PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 3.5.2
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v3.5.2
3.5.2 3.5.1 3.5.0 3.4.8 3.4.7 3.4.6 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5.1 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.10 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.6.1 1.6.7 1.7.0 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.2 1.7.2.1 1.7.2.2 1.7.3 1.7.4 1.7.5 1.7.5.1 1.7.5.2 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.8.0 1.8.0.1 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.0.1 1.9.1 1.9.2 1.9.3 1.9.4 1.9.4.1 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.0.1 2.0.1 2.0.2 2.0.3 2.0.3.1 2.0.4 2.0.4.1 2.0.5 2.0.6 2.0.7 2.0.8 2.0.8.1 2.0.9 3.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.3.1 3.0.4 3.0.4.1 3.0.4.2 3.0.5 3.0.5.1 3.0.5.2 3.0.6 3.0.6.1 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.0.9.1 3.0.9.2 3.0.9.3 3.0.9.4 3.0.9.5 3.1.0 3.1.1 3.1.2 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.4.0 3.4.1 3.4.2 3.4.2.1 3.4.3 3.4.4 3.4.5 trunk 1.0 1.0.1 1.0.2 1.0.3
everest-forms / src / rolesandpermission / components / UserDisplayModal.jsx
everest-forms / src / rolesandpermission / components Last commit date
RoleAndPermissionAPI.jsx 3 months ago TrashUserRoleModel.jsx 3 months ago UserDisplayModal.jsx 3 months ago UserRoleTable.jsx 2 months ago
UserDisplayModal.jsx
321 lines
1 import { AddIcon } from '@chakra-ui/icons';
2 import {
3 Alert,
4 Button,
5 Flex,
6 FormControl,
7 FormLabel,
8 Modal,
9 ModalBody,
10 ModalCloseButton,
11 ModalContent,
12 ModalHeader,
13 ModalOverlay,
14 Stack,
15 Text,
16 useDisclosure,
17 useToast,
18 } from '@chakra-ui/react';
19 import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
20 import { __ } from '@wordpress/i18n';
21 import { Select } from 'chakra-react-select';
22 import { debounce } from 'lodash';
23 import { useEffect, useMemo, useRef, useState } from 'react';
24 import { addManagerRole, getWPUsers } from './RoleAndPermissionAPI';
25
26 const selectChakraStyles = {
27 dropdownIndicator: (provided) => ({ ...provided, bg: 'transparent' }),
28 indicatorSeparator: (provided) => ({ ...provided, display: 'none' }),
29 option: (provided) => ({ ...provided, fontSize: '13px' }),
30 input: (base) => ({
31 ...base,
32 border: 'none',
33 outline: 'none',
34 boxShadow: 'none',
35 padding: 0,
36 margin: 0,
37 background: 'transparent',
38 height: 'auto',
39 minHeight: 0,
40 width: 0,
41 }),
42 };
43
44 const UserDisplayModal = ({ wp_roles, context = '', value = {} }) => {
45 const { isOpen, onOpen, onClose } = useDisclosure();
46 const queryClient = useQueryClient();
47 const [selectedUser, setSelectedUser] = useState(null);
48 const [permissions, setPermissions] = useState([]);
49 const [errors, setErrors] = useState([]);
50 const [isSubmitting, setIsSubmitting] = useState(false);
51 const [searchTerm, setSearchTerm] = useState('');
52 const toast = useToast();
53
54 const debouncedSetSearch = useRef(
55 debounce((val) => setSearchTerm(val), 400),
56 ).current;
57
58 useEffect(() => () => debouncedSetSearch.cancel(), [debouncedSetSearch]);
59
60 useEffect(() => {
61 if (!isOpen) return;
62 if (context === 'edit') {
63 setSelectedUser(
64 value.email ? { value: value.email, label: value.email } : null,
65 );
66 setPermissions(
67 Array.isArray(value.permission) ? [...value.permission] : [],
68 );
69 } else {
70 setSelectedUser(null);
71 setPermissions([]);
72 setSearchTerm('');
73 }
74 setErrors([]);
75 }, [isOpen]); // eslint-disable-line react-hooks/exhaustive-deps
76
77 const {
78 data: usersData,
79 fetchNextPage,
80 hasNextPage,
81 isFetchingNextPage,
82 isLoading: isUsersLoading,
83 } = useInfiniteQuery({
84 queryKey: ['wp-users', searchTerm],
85 queryFn: ({ pageParam = 1 }) =>
86 getWPUsers({ page: pageParam, search: searchTerm }),
87 getNextPageParam: (lastPage, allPages) =>
88 lastPage.has_more ? allPages.length + 1 : undefined,
89 enabled: isOpen && context !== 'edit',
90 staleTime: 30 * 1000,
91 keepPreviousData: true,
92 });
93
94 const userOptions = useMemo(
95 () => usersData?.pages.flatMap((page) => page.users) ?? [],
96 [usersData],
97 );
98
99 const handleInputChange = (val) => {
100 debouncedSetSearch(val);
101 };
102
103 const allPermissionOptions = useMemo(
104 () =>
105 Object.entries(wp_roles).map(([key, label]) => ({
106 label,
107 value: key,
108 })),
109 [wp_roles],
110 );
111
112 const handleMultiplePermission = (selectedOptions) => {
113 setPermissions(selectedOptions ? selectedOptions.map((o) => o.value) : []);
114 };
115
116 const handleAddManager = () => {
117 const email = selectedUser?.value;
118 setIsSubmitting(true);
119 addManagerRole(email, permissions)
120 .then((res) => {
121 setErrors([]);
122 if (!res.success) {
123 const errorList = Object.entries(res.message).map(
124 ([key, message]) => ({ key, message }),
125 );
126 setErrors(errorList);
127 } else {
128 onClose();
129 toast({
130 title: res.message,
131 status: 'success',
132 duration: 3000,
133 isClosable: true,
134 });
135
136 if (context === 'edit') {
137 queryClient.setQueriesData(
138 { queryKey: ['managers'] },
139 (oldData) => {
140 if (!oldData?.managers) return oldData;
141 return {
142 ...oldData,
143 managers: oldData.managers.map((m) =>
144 m.email === email
145 ? { ...m, permissions: [...permissions] }
146 : m,
147 ),
148 };
149 },
150 );
151 }
152
153 queryClient.invalidateQueries({ queryKey: ['managers'] });
154 }
155 })
156 .finally(() => setIsSubmitting(false));
157 };
158
159 const addButtonStyles = {
160 width: '113px',
161 height: '41px',
162 backgroundColor: '#7545BB',
163 padding: '10px 16px',
164 gap: '6px',
165 fontWeight: '500',
166 lineHeight: '21px',
167 fontSize: '14px',
168 color: '#FFFFFF',
169 };
170
171 return (
172 <>
173 {context === 'edit' ? (
174 <Button
175 variant="link"
176 color="gray.500"
177 fontWeight="400"
178 fontSize="13px"
179 minW="auto"
180 height="auto"
181 padding={0}
182 _hover={{ color: 'primary.400', textDecoration: 'none' }}
183 onClick={onOpen}
184 >
185 {__('Edit', 'everest-forms')}
186 </Button>
187 ) : (
188 <Button style={addButtonStyles} onClick={onOpen}>
189 <AddIcon
190 height="9.95px"
191 width="9.9px"
192 fontWeight="500"
193 color="#FFFFFF"
194 />{' '}
195 {__('Add User', 'everest-forms')}
196 </Button>
197 )}
198
199 <Modal isOpen={isOpen} onClose={onClose} isCentered size="lg">
200 <ModalOverlay />
201 <ModalContent p={2}>
202 <ModalHeader>
203 {context === 'edit'
204 ? __('Edit User', 'everest-forms')
205 : __('Add User', 'everest-forms')}
206 <Text mt={1} fontSize="sm" fontWeight="400" color="gray.500">
207 {__(
208 'View and manage the list of current managers, their assigned roles, and permissions.',
209 'everest-forms',
210 )}
211 </Text>
212 </ModalHeader>
213 <ModalCloseButton />
214
215 <ModalBody paddingTop="0">
216 <FormControl>
217 <Stack gap="28px">
218 <Stack>
219 <FormLabel display="flex" alignItems="center" fontSize="14px">
220 {__('User Email', 'everest-forms')}
221 </FormLabel>
222
223 <Select
224 placeholder={__('Select a user', 'everest-forms')}
225 options={context === 'edit' ? [] : userOptions}
226 value={selectedUser}
227 onChange={setSelectedUser}
228 onInputChange={
229 context === 'edit' ? undefined : handleInputChange
230 }
231 filterOption={() => true}
232 isLoading={
233 context !== 'edit' &&
234 (isUsersLoading || isFetchingNextPage)
235 }
236 isDisabled={context === 'edit'}
237 isClearable={context !== 'edit'}
238 isSearchable={false}
239 menuIsOpen={context === 'edit' ? false : undefined}
240 onMenuScrollToBottom={() => {
241 if (hasNextPage && !isFetchingNextPage) {
242 fetchNextPage();
243 }
244 }}
245 noOptionsMessage={() =>
246 isUsersLoading
247 ? __('Loading…', 'everest-forms')
248 : __('No users found', 'everest-forms')
249 }
250 loadingMessage={() => __('Loading…', 'everest-forms')}
251 chakraStyles={selectChakraStyles}
252 />
253
254 {errors.map((error, index) =>
255 error.key === 'user_email' ? (
256 <Alert borderRadius="4px" key={index} status="error">
257 {error.message}
258 </Alert>
259 ) : null,
260 )}
261 </Stack>
262
263 <Stack>
264 <FormLabel display="flex" alignItems="center" fontSize="14px">
265 {__('User Permission', 'everest-forms')}
266 </FormLabel>
267
268 <Select
269 isMulti
270 size="md"
271 placeholder={__('Select user permission', 'everest-forms')}
272 options={allPermissionOptions}
273 value={permissions.map((val) => ({
274 value: val,
275 label: wp_roles[val] || val,
276 }))}
277 onChange={handleMultiplePermission}
278 isClearable
279 isSearchable={false}
280 chakraStyles={selectChakraStyles}
281 />
282
283 {errors.map((error, index) =>
284 error.key === 'assigned_permission' ? (
285 <Alert borderRadius="4px" key={index} status="error">
286 {error.message}
287 </Alert>
288 ) : null,
289 )}
290 </Stack>
291 </Stack>
292
293 <Flex justifyContent="flex-end" mt="6" gap={3}>
294 <Button onClick={onClose} variant="outline">
295 {__('Back', 'everest-forms')}
296 </Button>
297 <Button
298 color="#FFFFFF"
299 backgroundColor="#7545BB"
300 padding="10px 16px"
301 borderRadius="4px"
302 border="1px solid #7545BB"
303 width="94px"
304 height="39px"
305 _hover={{ backgroundColor: '#7545BB' }}
306 onClick={handleAddManager}
307 isLoading={isSubmitting}
308 >
309 {__('Confirm', 'everest-forms')}
310 </Button>
311 </Flex>
312 </FormControl>
313 </ModalBody>
314 </ModalContent>
315 </Modal>
316 </>
317 );
318 };
319
320 export default UserDisplayModal;
321