Fix invitation list connection
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { usePreloadedQuery, type PreloadedQuery } from "react-relay";
|
||||
import { graphql } from "relay-runtime";
|
||||
import { ConnectionHandler, graphql } from "relay-runtime";
|
||||
import { MemberList } from "./_components/MemberList";
|
||||
import type { MembersPageQuery } from "/__generated__/iam/MembersPageQuery.graphql";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
@@ -7,6 +7,7 @@ import { Button, Card, TabBadge, TabItem, Tabs } from "@probo/ui";
|
||||
import { useState } from "react";
|
||||
import { InvitationList } from "./_components/InvitationList";
|
||||
import { InviteUserDialog } from "./_components/InviteUserDialog";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
|
||||
export const membersPageQuery = graphql`
|
||||
query MembersPageQuery($organizationId: ID!) {
|
||||
@@ -37,6 +38,7 @@ export function MembersPage(props: {
|
||||
}) {
|
||||
const { queryRef } = props;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
|
||||
const [activeTab, setActiveTab] = useState<"memberships" | "invitations">(
|
||||
@@ -51,12 +53,23 @@ export function MembersPage(props: {
|
||||
throw new Error("node is of invalid type");
|
||||
}
|
||||
|
||||
const [invitationListConnectionId, setInvitationListConnectionId] = useState(
|
||||
ConnectionHandler.getConnectionID(
|
||||
organizationId,
|
||||
"InvitationListFragment_invitations",
|
||||
{ orderBy: { direction: "ASC", field: "CREATED_AT" } },
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-base font-medium">{__("Workspace members")}</h2>
|
||||
{organization.canInviteUser && (
|
||||
<InviteUserDialog viewerMembershipFKey={organization}>
|
||||
<InviteUserDialog
|
||||
connectionId={invitationListConnectionId}
|
||||
viewerMembershipFKey={organization}
|
||||
>
|
||||
<Button variant="secondary">{__("Invite member")}</Button>
|
||||
</InviteUserDialog>
|
||||
)}
|
||||
@@ -88,7 +101,10 @@ export function MembersPage(props: {
|
||||
{activeTab === "memberships" && <MemberList fKey={organization} />}
|
||||
|
||||
{activeTab === "invitations" && (
|
||||
<InvitationList fKey={organization} />
|
||||
<InvitationList
|
||||
fKey={organization}
|
||||
onConnectionIdChange={setInvitationListConnectionId}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { Tbody, Td, Th, Thead, Tr } from "@probo/ui";
|
||||
import { SortableTable, SortableTh } from "/components/SortableTable";
|
||||
import {
|
||||
SortableTable,
|
||||
SortableTh,
|
||||
type Order,
|
||||
} from "/components/SortableTable";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { graphql, usePaginationFragment } from "react-relay";
|
||||
import { ConnectionHandler, graphql, usePaginationFragment } from "react-relay";
|
||||
import { InvitationListItem } from "./InvitationListItem";
|
||||
import type { InvitationListFragment$key } from "/__generated__/iam/InvitationListFragment.graphql";
|
||||
import type { InvitationListFragment_RefetchQuery } from "/__generated__/iam/InvitationListFragment_RefetchQuery.graphql";
|
||||
import type { ComponentProps } from "react";
|
||||
import { type ComponentProps } from "react";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
|
||||
const fragment = graphql`
|
||||
fragment InvitationListFragment on Organization
|
||||
@@ -27,7 +32,10 @@ const fragment = graphql`
|
||||
before: $before
|
||||
orderBy: $order
|
||||
)
|
||||
@connection(key: "InvitationListFragment_invitations", filters: [])
|
||||
@connection(
|
||||
key: "InvitationListFragment_invitations"
|
||||
filters: ["orderBy"]
|
||||
)
|
||||
@required(action: THROW) {
|
||||
__id
|
||||
totalCount
|
||||
@@ -41,9 +49,13 @@ const fragment = graphql`
|
||||
}
|
||||
`;
|
||||
|
||||
export function InvitationList(props: { fKey: InvitationListFragment$key }) {
|
||||
const { fKey } = props;
|
||||
export function InvitationList(props: {
|
||||
fKey: InvitationListFragment$key;
|
||||
onConnectionIdChange: (connectionId: string) => void;
|
||||
}) {
|
||||
const { fKey, onConnectionIdChange } = props;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
|
||||
const invitationsPagination = usePaginationFragment<
|
||||
@@ -55,6 +67,16 @@ export function InvitationList(props: { fKey: InvitationListFragment$key }) {
|
||||
invitationsPagination.refetch({}, { fetchPolicy: "network-only" });
|
||||
};
|
||||
|
||||
const handleOrderChange = (order: Order) => {
|
||||
onConnectionIdChange(
|
||||
ConnectionHandler.getConnectionID(
|
||||
organizationId,
|
||||
"InvitationListFragment_invitations",
|
||||
{ orderBy: order },
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SortableTable
|
||||
{...invitationsPagination}
|
||||
@@ -67,12 +89,22 @@ export function InvitationList(props: { fKey: InvitationListFragment$key }) {
|
||||
>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<SortableTh field="FULL_NAME">{__("Name")}</SortableTh>
|
||||
<SortableTh field="EMAIL">{__("Email")}</SortableTh>
|
||||
<SortableTh field="ROLE">{__("Role")}</SortableTh>
|
||||
<SortableTh field="CREATED_AT">{__("Invited")}</SortableTh>
|
||||
<SortableTh field="FULL_NAME" onOrderChange={handleOrderChange}>
|
||||
{__("Name")}
|
||||
</SortableTh>
|
||||
<SortableTh field="EMAIL" onOrderChange={handleOrderChange}>
|
||||
{__("Email")}
|
||||
</SortableTh>
|
||||
<SortableTh field="ROLE" onOrderChange={handleOrderChange}>
|
||||
{__("Role")}
|
||||
</SortableTh>
|
||||
<SortableTh field="CREATED_AT" onOrderChange={handleOrderChange}>
|
||||
{__("Invited")}
|
||||
</SortableTh>
|
||||
<Th>{__("Status")}</Th>
|
||||
<SortableTh field="ACCEPTED_AT">{__("Accepted at")}</SortableTh>
|
||||
<SortableTh field="ACCEPTED_AT" onOrderChange={handleOrderChange}>
|
||||
{__("Accepted at")}
|
||||
</SortableTh>
|
||||
<Th></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from "@probo/ui";
|
||||
import { Controller } from "react-hook-form";
|
||||
import { useFragment } from "react-relay";
|
||||
import { ConnectionHandler, graphql } from "relay-runtime";
|
||||
import { graphql } from "relay-runtime";
|
||||
import z from "zod";
|
||||
import { useFormWithSchema } from "/hooks/useFormWithSchema";
|
||||
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
|
||||
@@ -59,11 +59,12 @@ const schema = z.object({
|
||||
});
|
||||
|
||||
type InviteUserDialogProps = PropsWithChildren<{
|
||||
connectionId: string;
|
||||
viewerMembershipFKey: InviteUserDialog_currentRoleFragment$key;
|
||||
}>;
|
||||
|
||||
export function InviteUserDialog(props: InviteUserDialogProps) {
|
||||
const { children, viewerMembershipFKey } = props;
|
||||
const { children, connectionId, viewerMembershipFKey } = props;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const { __ } = useTranslate();
|
||||
@@ -87,11 +88,6 @@ export function InviteUserDialog(props: InviteUserDialogProps) {
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit((data) => {
|
||||
const connectionId = ConnectionHandler.getConnectionID(
|
||||
organizationId,
|
||||
"InvitationListFragment_invitations",
|
||||
{},
|
||||
);
|
||||
inviteUser({
|
||||
variables: {
|
||||
input: {
|
||||
|
||||
Reference in New Issue
Block a user