Skip to content

Commit 87d50f1

Browse files
chore(site): refactor groups to use react-query (coder#9701)
1 parent 161a3cf commit 87d50f1

File tree

10 files changed

+331
-668
lines changed

10 files changed

+331
-668
lines changed

site/src/api/api.ts

+18
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,24 @@ export const patchGroup = async (
969969
return response.data;
970970
};
971971

972+
export const addMember = async (groupId: string, userId: string) => {
973+
return patchGroup(groupId, {
974+
name: "",
975+
display_name: "",
976+
add_users: [userId],
977+
remove_users: [],
978+
});
979+
};
980+
981+
export const removeMember = async (groupId: string, userId: string) => {
982+
return patchGroup(groupId, {
983+
name: "",
984+
display_name: "",
985+
add_users: [],
986+
remove_users: [userId],
987+
});
988+
};
989+
972990
export const deleteGroup = async (groupId: string): Promise<void> => {
973991
await axios.delete(`/api/v2/groups/${groupId}`);
974992
};

site/src/api/queries/groups.ts

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { QueryClient } from "@tanstack/react-query";
2+
import * as API from "api/api";
3+
import { checkAuthorization } from "api/api";
4+
import {
5+
CreateGroupRequest,
6+
Group,
7+
PatchGroupRequest,
8+
} from "api/typesGenerated";
9+
10+
const GROUPS_QUERY_KEY = ["groups"];
11+
12+
const getGroupQueryKey = (groupId: string) => ["group", groupId];
13+
14+
export const groups = (organizationId: string) => {
15+
return {
16+
queryKey: GROUPS_QUERY_KEY,
17+
queryFn: () => API.getGroups(organizationId),
18+
};
19+
};
20+
21+
export const group = (groupId: string) => {
22+
return {
23+
queryKey: getGroupQueryKey(groupId),
24+
queryFn: () => API.getGroup(groupId),
25+
};
26+
};
27+
28+
export const groupPermissions = (groupId: string) => {
29+
return {
30+
queryKey: [...getGroupQueryKey(groupId), "permissions"],
31+
queryFn: () =>
32+
checkAuthorization({
33+
checks: {
34+
canUpdateGroup: {
35+
object: {
36+
resource_type: "group",
37+
resource_id: groupId,
38+
},
39+
action: "update",
40+
},
41+
},
42+
}),
43+
};
44+
};
45+
46+
export const createGroup = (queryClient: QueryClient) => {
47+
return {
48+
mutationFn: ({
49+
organizationId,
50+
...request
51+
}: CreateGroupRequest & { organizationId: string }) =>
52+
API.createGroup(organizationId, request),
53+
onSuccess: async () => {
54+
await queryClient.invalidateQueries(GROUPS_QUERY_KEY);
55+
},
56+
};
57+
};
58+
59+
export const patchGroup = (queryClient: QueryClient) => {
60+
return {
61+
mutationFn: ({
62+
groupId,
63+
...request
64+
}: PatchGroupRequest & { groupId: string }) =>
65+
API.patchGroup(groupId, request),
66+
onSuccess: async (updatedGroup: Group) =>
67+
invalidateGroup(queryClient, updatedGroup.id),
68+
};
69+
};
70+
71+
export const deleteGroup = (queryClient: QueryClient) => {
72+
return {
73+
mutationFn: API.deleteGroup,
74+
onSuccess: async (_: void, groupId: string) =>
75+
invalidateGroup(queryClient, groupId),
76+
};
77+
};
78+
79+
export const addMember = (queryClient: QueryClient) => {
80+
return {
81+
mutationFn: ({ groupId, userId }: { groupId: string; userId: string }) =>
82+
API.addMember(groupId, userId),
83+
onSuccess: async (updatedGroup: Group) =>
84+
invalidateGroup(queryClient, updatedGroup.id),
85+
};
86+
};
87+
88+
export const removeMember = (queryClient: QueryClient) => {
89+
return {
90+
mutationFn: ({ groupId, userId }: { groupId: string; userId: string }) =>
91+
API.removeMember(groupId, userId),
92+
onSuccess: async (updatedGroup: Group) =>
93+
invalidateGroup(queryClient, updatedGroup.id),
94+
};
95+
};
96+
97+
export const invalidateGroup = (queryClient: QueryClient, groupId: string) =>
98+
Promise.all([
99+
queryClient.invalidateQueries(GROUPS_QUERY_KEY),
100+
queryClient.invalidateQueries(getGroupQueryKey(groupId)),
101+
]);

site/src/pages/GroupsPage/CreateGroupPage.tsx

+11-19
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,33 @@
1-
import { useMachine } from "@xstate/react";
21
import { useOrganizationId } from "hooks/useOrganizationId";
32
import { FC } from "react";
43
import { Helmet } from "react-helmet-async";
54
import { useNavigate } from "react-router-dom";
65
import { pageTitle } from "utils/page";
7-
import { createGroupMachine } from "xServices/groups/createGroupXService";
86
import CreateGroupPageView from "./CreateGroupPageView";
7+
import { useMutation, useQueryClient } from "@tanstack/react-query";
8+
import { createGroup } from "api/queries/groups";
99

1010
export const CreateGroupPage: FC = () => {
11+
const queryClient = useQueryClient();
1112
const navigate = useNavigate();
1213
const organizationId = useOrganizationId();
13-
const [createState, sendCreateEvent] = useMachine(createGroupMachine, {
14-
context: {
15-
organizationId,
16-
},
17-
actions: {
18-
onCreate: (_, { data }) => {
19-
navigate(`/groups/${data.id}`);
20-
},
21-
},
22-
});
23-
const { error } = createState.context;
14+
const createGroupMutation = useMutation(createGroup(queryClient));
2415

2516
return (
2617
<>
2718
<Helmet>
2819
<title>{pageTitle("Create Group")}</title>
2920
</Helmet>
3021
<CreateGroupPageView
31-
onSubmit={(data) => {
32-
sendCreateEvent({
33-
type: "CREATE",
34-
data,
22+
onSubmit={async (data) => {
23+
const newGroup = await createGroupMutation.mutateAsync({
24+
organizationId,
25+
...data,
3526
});
27+
navigate(`/groups/${newGroup.id}`);
3628
}}
37-
formErrors={error}
38-
isLoading={createState.matches("creatingGroup")}
29+
formErrors={createGroupMutation.error}
30+
isLoading={createGroupMutation.isLoading}
3931
/>
4032
</>
4133
);

0 commit comments

Comments
 (0)