Skip to content

Commit 469d12b

Browse files
Merge pull request #244 from CivicDataLab/241-add-admin-members-page-in-org-dashboard
241 add admin members page in org dashboard
2 parents 3efc2c4 + 497cd47 commit 469d12b

File tree

5 files changed

+492
-4
lines changed

5 files changed

+492
-4
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
'use client';
2+
3+
import { useEffect, useState } from 'react';
4+
import { useParams } from 'next/navigation';
5+
import { graphql } from '@/gql';
6+
import {
7+
AddRemoveUserToOrganizationInput,
8+
AssignOrganizationRoleInput,
9+
} from '@/gql/generated/graphql';
10+
import { useMutation, useQuery } from '@tanstack/react-query';
11+
import { Button, Dialog, Label, Select, toast } from 'opub-ui';
12+
13+
import { GraphQL } from '@/lib/api';
14+
import { toTitleCase } from '@/lib/utils';
15+
import { FetchUsers } from '../usecases/edit/[id]/contributors/query';
16+
17+
const addUserDoc: any = graphql(`
18+
mutation addUserToOrganization($input: AddRemoveUserToOrganizationInput!) {
19+
addUserToOrganization(input: $input) {
20+
__typename
21+
... on TypeOrganizationMembership {
22+
role {
23+
name
24+
id
25+
}
26+
}
27+
}
28+
}
29+
`);
30+
const allRolesDoc: any = graphql(`
31+
query AllRolesDoc {
32+
roles {
33+
id
34+
name
35+
description
36+
}
37+
}
38+
`);
39+
40+
const updateUser: any = graphql(`
41+
mutation assignOrganizationRole($input: AssignOrganizationRoleInput!) {
42+
assignOrganizationRole(input: $input) {
43+
success
44+
message
45+
}
46+
}
47+
`);
48+
49+
const AddUser = ({
50+
setIsOpen,
51+
selectedUser,
52+
isOpen,
53+
isEdit,
54+
setRefetch,
55+
}: {
56+
setIsOpen: (isOpen: boolean) => void;
57+
selectedUser: any;
58+
isOpen: boolean;
59+
isEdit: boolean;
60+
setRefetch: (refetch: boolean) => void;
61+
}) => {
62+
const [searchValue, setSearchValue] = useState('');
63+
const params = useParams<{
64+
entityType: string;
65+
entitySlug: string;
66+
id: string;
67+
}>();
68+
69+
const Users: { data: any; isLoading: boolean; refetch: any } = useQuery(
70+
[`fetch_users_list`],
71+
() =>
72+
GraphQL(
73+
FetchUsers,
74+
{},
75+
{
76+
limit: 10,
77+
searchTerm: searchValue,
78+
}
79+
),
80+
{
81+
enabled: searchValue?.length > 0,
82+
keepPreviousData: true,
83+
}
84+
);
85+
86+
const RolesList: { data: any; isLoading: boolean; refetch: any } = useQuery(
87+
[`fetch_UseCaseData`],
88+
() =>
89+
GraphQL(
90+
allRolesDoc,
91+
{
92+
[params.entityType]: params.entitySlug,
93+
},
94+
[]
95+
)
96+
);
97+
98+
useEffect(() => {
99+
if (selectedUser) {
100+
setSearchValue(selectedUser.name || '');
101+
setFormData({
102+
userId: selectedUser.id || '',
103+
roleId: selectedUser.role?.id || '',
104+
});
105+
} else {
106+
setFormData({ userId: '', roleId: '' });
107+
setSearchValue('');
108+
}
109+
}, [selectedUser]);
110+
111+
const { mutate, isLoading: addUserLoading } = useMutation(
112+
(input: { input: AddRemoveUserToOrganizationInput }) =>
113+
GraphQL(
114+
addUserDoc,
115+
{
116+
[params.entityType]: params.entitySlug,
117+
},
118+
input
119+
),
120+
{
121+
onSuccess: (res: any) => {
122+
toast('User added successfully');
123+
// Optionally, reset form or perform other actions
124+
setIsOpen(false);
125+
setFormData({
126+
userId: '',
127+
roleId: '',
128+
});
129+
setRefetch(true);
130+
},
131+
onError: (err: any) => {
132+
toast('Failed to add user');
133+
},
134+
}
135+
);
136+
137+
const { mutate: updateMutate, isLoading: updateUserLoading } = useMutation(
138+
(input: { input: AssignOrganizationRoleInput }) =>
139+
GraphQL(updateUser, {
140+
[params.entityType]: params.entitySlug,
141+
}, input),
142+
{
143+
onSuccess: (res: any) => {
144+
toast('User updated successfully');
145+
// Optionally, reset form or perform other actions
146+
setIsOpen(false);
147+
setFormData({
148+
userId: '',
149+
roleId: '',
150+
});
151+
setRefetch(true);
152+
},
153+
onError: (err: any) => {
154+
toast('Failed to update user');
155+
},
156+
}
157+
);
158+
159+
const [formData, setFormData] = useState({
160+
userId: '',
161+
roleId: '',
162+
});
163+
const handleChange = (field: string, value: any) => {
164+
setFormData((prev) => ({
165+
...prev,
166+
[field]: value,
167+
}));
168+
};
169+
170+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
171+
172+
const filteredOptions = Users.data?.searchUsers;
173+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
174+
const value = e.target.value;
175+
setSearchValue(value);
176+
setIsDropdownOpen(true); // Keep dropdown open while typing
177+
Users.refetch(); // Refetch when search term changes
178+
};
179+
180+
const handleSelectOption = (option: any) => {
181+
handleChange('userId', option.id);
182+
setSearchValue(option.fullName);
183+
setIsDropdownOpen(false); // Close dropdown
184+
};
185+
186+
return (
187+
<div>
188+
<Dialog open={isOpen} onOpenChange={setIsOpen}>
189+
{isOpen && (
190+
<Dialog.Content
191+
title={isEdit ? 'Edit Admin / Member' : 'Add Admin / Member'}
192+
className="h-72 overflow-y-auto"
193+
>
194+
<div className="m-auto mb-6 flex flex-col gap-6">
195+
<div className="relative w-full">
196+
<Label>Select User</Label>
197+
<input
198+
type="text"
199+
id="combobox"
200+
disabled={isEdit}
201+
value={searchValue}
202+
autoComplete='off'
203+
onChange={handleInputChange}
204+
className="border border-gray-100 placeholder:text-sm mt-1 block w-full px-3 py-1"
205+
placeholder={'Select user'}
206+
/>
207+
{isDropdownOpen && filteredOptions?.length > 0 && (
208+
<div className="border border-gray-300 rounded-md shadow-lg absolute left-0 right-0 z-1 mt-2 max-h-60 overflow-y-auto rounded-2 bg-white px-1 py-2 shadow-basicXl">
209+
{filteredOptions.map((option: any) => (
210+
<div
211+
key={option.id}
212+
className="cursor-pointer rounded-2 px-4 py-2 hover:bg-baseGraySlateSolid3"
213+
onClick={() => handleSelectOption(option)}
214+
>
215+
{option.fullName}
216+
</div>
217+
))}
218+
</div>
219+
)}
220+
</div>
221+
<Select
222+
name=""
223+
value={formData.roleId}
224+
placeholder="Select a role"
225+
onChange={(e) => handleChange('roleId', e)}
226+
options={RolesList.data?.roles
227+
.filter((role: any) => role.name !== 'owner')
228+
.map((role: any) => ({
229+
label: toTitleCase(role.name),
230+
value: role.id,
231+
}))}
232+
label="Select a role"
233+
helpText={RolesList.data?.roles
234+
.filter((role: any) => role.id === formData.roleId)
235+
.map((role: any) => role.description)}
236+
/>
237+
</div>
238+
<div className="flex justify-center">
239+
<Button
240+
kind="primary"
241+
className="m-auto"
242+
onClick={() => {
243+
setIsOpen(false);
244+
isEdit ? updateMutate({ input: formData }) : mutate({ input: formData });
245+
}}
246+
>
247+
{isEdit ? 'Update' : 'Add'}
248+
</Button>
249+
</div>
250+
</Dialog.Content>
251+
)}
252+
</Dialog>
253+
</div>
254+
);
255+
};
256+
257+
export default AddUser;

0 commit comments

Comments
 (0)