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 / UserRoleTable.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
UserRoleTable.jsx
875 lines
1 import {
2 Pagination,
3 PaginationContainer,
4 PaginationNext,
5 PaginationPage,
6 PaginationPageGroup,
7 PaginationPrevious,
8 PaginationSeparator,
9 usePagination,
10 } from '@ajna/pagination';
11 import { LockIcon, SearchIcon } from '@chakra-ui/icons';
12 import {
13 Alert,
14 AlertIcon,
15 Box,
16 Button,
17 Checkbox,
18 Flex,
19 Heading,
20 IconButton,
21 Input,
22 InputGroup,
23 InputLeftElement,
24 Skeleton,
25 Stack,
26 Switch,
27 Table,
28 Tbody,
29 Td,
30 Text,
31 Th,
32 Thead,
33 Tooltip,
34 Tr,
35 useToast,
36 } from '@chakra-ui/react';
37 import { useMutation, useQuery } from '@tanstack/react-query';
38 import { __ } from '@wordpress/i18n';
39 import { Select } from 'chakra-react-select';
40 import { debounce } from 'lodash';
41 import { useEffect, useMemo, useState } from 'react';
42 import {
43 FaAngleDoubleLeft,
44 FaAngleDoubleRight,
45 FaAngleLeft,
46 FaAngleRight,
47 } from 'react-icons/fa';
48 import {
49 bulkAssignPermission,
50 bulkRemoveManager,
51 getManagers,
52 getWPRoles,
53 removeManager,
54 } from './RoleAndPermissionAPI';
55 import TrashUserRoleModel from './TrashUserRoleModel';
56 import UserDisplayModal from './UserDisplayModal';
57
58 const VISIBLE_PERM_COUNT = 4;
59
60 const PermTag = ({ children }) => (
61 <Text
62 as="span"
63 margin="0"
64 display="inline-flex"
65 alignItems="center"
66 fontSize="12px"
67 fontWeight="500"
68 bg="primary.25"
69 color="primary.500"
70 border="1px solid"
71 borderColor="primary.100"
72 padding="2px 10px"
73 borderRadius="full"
74 lineHeight="1.6"
75 >
76 {children}
77 </Text>
78 );
79
80 const PermissionCell = ({ permissionKeys, permissionLabels }) => {
81 const visible = permissionKeys.slice(0, VISIBLE_PERM_COUNT);
82 const hidden = permissionKeys.slice(VISIBLE_PERM_COUNT);
83
84 return (
85 <Flex gap="6px" flexWrap="wrap" alignItems="center">
86 {visible.map((perm, i) => (
87 <PermTag key={i}>{permissionLabels[perm]}</PermTag>
88 ))}
89 {hidden.length > 0 && (
90 <Tooltip
91 label={
92 <Stack gap="4px" py="2px">
93 {hidden.map((perm, i) => (
94 <Text key={i} fontSize="12px">
95 {permissionLabels[perm] || perm}
96 </Text>
97 ))}
98 </Stack>
99 }
100 placement="bottom-start"
101 hasArrow
102 bg="white"
103 color="gray.700"
104 >
105 <Text
106 as="span"
107 color="primary.400"
108 fontWeight="500"
109 fontSize="12px"
110 cursor="default"
111 _hover={{ textDecoration: 'underline' }}
112 >
113 +{hidden.length} more
114 </Text>
115 </Tooltip>
116 )}
117 </Flex>
118 );
119 };
120
121 const UserRoleTable = () => {
122 const [checkedItems, setCheckedItems] = useState({});
123 const [firstLoad, setFirstLoad] = useState(true);
124 const [selectedRows, setSelectedRows] = useState([]);
125 const [bulkDelete, setBulkDelete] = useState(false);
126 const [searchManager, setSearchManager] = useState('');
127 const toast = useToast();
128
129 const [totalManagers, setTotalManagers] = useState(0);
130
131 const outerLimit = 2;
132 const innerLimit = 2;
133
134 const {
135 pages,
136 pagesCount,
137 offset,
138 currentPage,
139 setCurrentPage,
140 isDisabled,
141 pageSize,
142 setPageSize,
143 } = usePagination({
144 total: totalManagers,
145 limits: { outer: outerLimit, inner: innerLimit },
146 initialState: { pageSize: 10, isDisabled: false, currentPage: 1 },
147 });
148
149 const managersQuery = useQuery({
150 queryKey: ['managers', offset, pageSize, searchManager],
151 queryFn: () => getManagers(offset, pageSize, searchManager),
152 keepPreviousData: true,
153 staleTime: 60 * 1000,
154 refetchOnWindowFocus: false,
155 onSuccess: (data) => {
156 setTotalManagers(data?.total ?? 0);
157 },
158 });
159
160 const managers = managersQuery.data?.managers ?? [];
161 const permissions = managersQuery.data?.permissions?.permissions ?? {};
162 const isLoading = managersQuery.isLoading || managersQuery.isFetching;
163
164 const wpRolesQuery = useQuery({
165 queryKey: ['wpRoles'],
166 queryFn: getWPRoles,
167 staleTime: 5 * 60 * 1000,
168 refetchOnWindowFocus: false,
169 });
170
171 const wpRoles = wpRolesQuery.data?.data?.roles ?? {};
172 const evfPermission = wpRolesQuery.data?.data?.permission?.permissions ?? [];
173
174 useEffect(() => {
175 if (wpRolesQuery.data?.data?.roles) {
176 const roles = wpRolesQuery.data.data.roles;
177 const initial = Object.keys(roles).reduce((acc, role) => {
178 acc[role] = roles[role].checked;
179 return acc;
180 }, {});
181 setCheckedItems(initial);
182 }
183 }, [wpRolesQuery.data]);
184
185 const deleteManagerMutation = useMutation({
186 mutationFn: removeManager,
187 onSuccess: (res) => {
188 if (res.success) {
189 toast({
190 title: res.message,
191 status: 'success',
192 duration: 3000,
193 isClosable: true,
194 });
195 managersQuery.refetch();
196 }
197 },
198 });
199
200 const bulkRemoveMutation = useMutation({
201 mutationFn: bulkRemoveManager,
202 onSuccess: (res) => {
203 if (res.success) {
204 toast({
205 title: res.message,
206 status: 'success',
207 duration: 3000,
208 isClosable: true,
209 });
210 setSelectedRows([]);
211 managersQuery.refetch();
212 } else {
213 toast({
214 title: res.message,
215 status: 'error',
216 duration: 3000,
217 isClosable: true,
218 });
219 }
220 },
221 });
222
223 const assignPermissionMutation = useMutation({
224 mutationFn: bulkAssignPermission,
225 onSuccess: (res) => {
226 if (res.success) {
227 toast({
228 title: res.message,
229 status: 'success',
230 duration: 3000,
231 isClosable: true,
232 });
233 } else {
234 toast({
235 title: res.message || 'Something went wrong',
236 status: 'error',
237 duration: 3000,
238 isClosable: true,
239 });
240 }
241 },
242 });
243
244 const handlePageChange = (nextPage) => {
245 setCurrentPage(nextPage);
246 };
247
248 const handlePageSizeChange = (selectedOption) => {
249 setPageSize(Number(selectedOption.value));
250 setCurrentPage(1);
251 };
252
253 const debounceSearch = debounce((val) => {
254 setCurrentPage(1);
255 setSearchManager(val);
256 }, 800);
257
258 const handleSelectAll = (checked) => {
259 setSelectedRows(checked ? managers.map((m) => m.id) : []);
260 };
261
262 const handleSelectRow = (id, checked) => {
263 setSelectedRows((prev) =>
264 checked ? [...prev, id] : prev.filter((rowId) => rowId !== id),
265 );
266 };
267
268 const isAllSelected =
269 managers.length > 0 && selectedRows.length === managers.length;
270 const isIndeterminate =
271 selectedRows.length > 0 && selectedRows.length < managers.length;
272
273 const checkedRoleKeys = useMemo(() => {
274 const keys = new Set();
275 Object.entries(firstLoad ? wpRoles : checkedItems).forEach(([key, val]) => {
276 const isChecked = firstLoad ? val?.checked : val;
277 if (isChecked) keys.add(key);
278 });
279 return keys;
280 }, [checkedItems, firstLoad, wpRoles]);
281
282 const isAdmin = (manager) => {
283 if (!manager.role_keys || !Array.isArray(manager.role_keys)) return false;
284 return manager.role_keys.includes('administrator');
285 };
286
287 const isRoleManaged = (manager) => {
288 if (isAdmin(manager)) return true;
289 if (!manager.role_keys || !Array.isArray(manager.role_keys)) return false;
290 return manager.role_keys.some((key) => checkedRoleKeys.has(key));
291 };
292
293 const handleIndividualCheck = (role, checked) => {
294 setFirstLoad(false);
295 const updated = { ...checkedItems, [role]: checked };
296 setCheckedItems(updated);
297 assignPermissionMutation.mutate(updated);
298 };
299
300 const handleBulkDelete = () => {
301 if (selectedRows.length === 0) {
302 return toast({
303 title: 'Please select user.',
304 status: 'error',
305 duration: 3000,
306 isClosable: true,
307 });
308 }
309 if (!bulkDelete) {
310 return toast({
311 title: 'Please choose bulk action.',
312 status: 'error',
313 duration: 3000,
314 isClosable: true,
315 });
316 }
317 bulkRemoveMutation.mutate(selectedRows);
318 };
319
320 return (
321 <Stack gap="20px">
322 <Flex justifyContent="space-between" alignItems="center">
323 <Flex alignItems="center" gap="16px">
324 <Heading
325 fontWeight="600"
326 fontSize="20px"
327 lineHeight="normal"
328 color="#383838"
329 margin="0"
330 >
331 {__('Role Based Access', 'everest-forms')}
332 </Heading>
333 <UserDisplayModal wp_roles={evfPermission} />
334 </Flex>
335
336 <InputGroup w="220px">
337 <InputLeftElement pointerEvents="none">
338 <SearchIcon color="gray.400" />
339 </InputLeftElement>
340 <Input
341 placeholder={__('Search...', 'everest-forms')}
342 _placeholder={{ color: '#383838' }}
343 borderColor="#e1e1e1"
344 focusBorderColor="primary.400"
345 borderRadius="4px"
346 fontSize="14px"
347 color="#383838"
348 onChange={(e) => debounceSearch(e.target.value)}
349 />
350 </InputGroup>
351 </Flex>
352
353 {wpRolesQuery.isLoading ? (
354 <Flex gap="12px">
355 {[80, 70, 90].map((w, i) => (
356 <Skeleton key={i} h="36px" w={`${w}px`} borderRadius="md" />
357 ))}
358 </Flex>
359 ) : (
360 <Flex gap="12px" flexWrap="wrap" alignItems="center">
361 {Object.entries(wpRoles).map(([roleKey, roleName]) => {
362 const isChecked = firstLoad
363 ? roleName.checked
364 : checkedItems[roleKey];
365 return (
366 <Flex
367 key={roleKey}
368 as="label"
369 alignItems="center"
370 gap="8px"
371 border="1px solid"
372 borderColor={isChecked ? 'primary.200' : 'gray.200'}
373 bg={isChecked ? 'primary.25' : 'white'}
374 borderRadius="md"
375 px="14px"
376 py="8px"
377 cursor="pointer"
378 transition="all 0.15s"
379 _hover={{ borderColor: 'primary.300' }}
380 >
381 <Switch
382 isChecked={!!isChecked}
383 onChange={(e) =>
384 handleIndividualCheck(roleKey, e.target.checked)
385 }
386 size="sm"
387 sx={{
388 '& .chakra-switch__track': { bg: 'gray.300' },
389 '& .chakra-switch__track[data-checked]': { bg: '#7545bb' },
390 }}
391 />
392 <Text fontSize="13px" fontWeight="500" color="#222222">
393 {roleName.name}
394 </Text>
395 </Flex>
396 );
397 })}
398 </Flex>
399 )}
400
401 {wpRolesQuery.isLoading ? (
402 <Skeleton h="48px" w="100%" borderRadius="md" />
403 ) : (
404 <Alert status="info" borderRadius="md" px="16px" py="12px" bg={"#f6f3fa"}>
405 <AlertIcon boxSize="16px" mt="1px" alignSelf="flex-start" color="#7545bb"/>
406 <Text
407 fontSize="13px"
408 lineHeight="1.5"
409 borderRadius="0"
410 color="#383838"
411 >
412 {checkedRoleKeys.size > 0 ? (
413 <>
414 <Text as="span" fontWeight="600">
415 {Object.entries(wpRoles)
416 .filter(([key]) => checkedRoleKeys.has(key))
417 .map(([, val]) => val.name)
418 .join(', ')}
419 </Text>{' '}
420 {checkedRoleKeys.size === 1
421 ? __('role has', 'everest-forms')
422 : __('roles have', 'everest-forms')}{' '}
423 {__('full Everest Forms access.', 'everest-forms')}
424 </>
425 ) : (
426 __(
427 'No roles are currently enabled. Enable a role above to grant all Everest Forms permissions to users with that role.',
428 'everest-forms',
429 )
430 )}
431 </Text>
432 </Alert>
433 )}
434
435 <Flex justifyContent="space-between" alignItems="center">
436 <Stack direction="row" gap="16px">
437 <Box minW="170px">
438 <Select
439 placeholder={__('Bulk Actions', 'everest-forms')}
440 options={[
441 { label: __('Delete', 'everest-forms'), value: 'delete' },
442 ]}
443 isClearable
444 isSearchable={false}
445 onChange={(opt) => setBulkDelete(opt?.value || '')}
446 chakraStyles={{
447 control: (provided) => ({
448 ...provided,
449 borderRadius: '4px',
450 borderColor: '#e1e1e1',
451 fontSize: '14px',
452 color: '#383838',
453 _hover: {
454 borderColor: 'primary.400',
455 },
456 }),
457 dropdownIndicator: (provided) => ({
458 ...provided,
459 bg: 'transparent',
460 }),
461 indicatorSeparator: (provided) => ({
462 ...provided,
463 display: 'none',
464 }),
465 placeholder: (provided) => ({
466 ...provided,
467 fontSize: '14px',
468 color: '#383838',
469 }),
470 singleValue: (provided) => ({
471 ...provided,
472 fontSize: '14px',
473 color: '#383838',
474 }),
475 option: (provided) => ({
476 ...provided,
477 fontSize: '13px',
478 }),
479 }}
480 />
481 </Box>
482 <Button
483 colorScheme="primary"
484 variant={'outline'}
485 onClick={handleBulkDelete}
486 isLoading={bulkRemoveMutation.isLoading}
487 >
488 <Text fontWeight="500" fontSize="13px" lineHeight="19.5px">
489 {__('Apply', 'everest-forms')}
490 </Text>
491 </Button>
492 </Stack>
493 </Flex>
494
495 <Box
496 border="1px solid"
497 borderColor="gray.200"
498 borderRadius="md"
499 overflow="hidden"
500 mt={8}
501 >
502 <Table fontSize="14px">
503 <Thead>
504 <Tr bg="white">
505 <Th textTransform="none" width="40px">
506 <Checkbox
507 isChecked={isAllSelected}
508 isIndeterminate={isIndeterminate}
509 onChange={(e) => handleSelectAll(e.target.checked)}
510 />
511 </Th>
512 <Th textTransform="none" width="220px">
513 <Text
514 fontWeight="600"
515 fontSize="14px"
516 lineHeight="24px"
517 color="#383838"
518 >
519 {__('Name', 'everest-forms')}
520 </Text>
521 </Th>
522 <Th textTransform="none">
523 <Text
524 fontWeight="600"
525 fontSize="14px"
526 lineHeight="24px"
527 color="#383838"
528 >
529 {__('Email', 'everest-forms')}
530 </Text>
531 </Th>
532 <Th textTransform="none">
533 <Text
534 fontWeight="600"
535 fontSize="14px"
536 lineHeight="24px"
537 color="#383838"
538 >
539 {__('Role', 'everest-forms')}
540 </Text>
541 </Th>
542 <Th textTransform="none">
543 <Text
544 fontWeight="600"
545 fontSize="14px"
546 lineHeight="24px"
547 color="#383838"
548 >
549 {__('Permission', 'everest-forms')}
550 </Text>
551 </Th>
552 </Tr>
553 </Thead>
554
555 <Tbody>
556 {isLoading ? (
557 Array.from({ length: 5 }).map((_, i) => (
558 <Tr
559 key={i}
560 bg={i % 2 === 0 ? 'white' : 'primary.15'}
561 height="56px"
562 >
563 <Td>
564 <Skeleton h="14px" w="14px" borderRadius="2px" />
565 </Td>
566 <Td>
567 <Stack gap="6px">
568 <Skeleton
569 h="10px"
570 w="70%"
571 maxW="110px"
572 borderRadius="sm"
573 />
574 <Skeleton h="8px" w="40%" maxW="50px" borderRadius="sm" />
575 </Stack>
576 </Td>
577 <Td>
578 <Skeleton h="10px" w="80%" maxW="170px" borderRadius="sm" />
579 </Td>
580 <Td>
581 <Skeleton h="10px" w="60%" maxW="70px" borderRadius="sm" />
582 </Td>
583 <Td>
584 <Flex gap="6px">
585 <Skeleton h="22px" w="90px" borderRadius="full" />
586 <Skeleton h="22px" w="70px" borderRadius="full" />
587 </Flex>
588 </Td>
589 </Tr>
590 ))
591 ) : totalManagers === 0 ? (
592 <Tr>
593 <Td colSpan="5" verticalAlign="top">
594 <Flex
595 justify="center"
596 align="center"
597 flexDirection="column"
598 py="40px"
599 >
600 <img
601 height="236px"
602 width="262px"
603 src={evf_roles_and_permission.not_found_image}
604 />
605 <Stack marginTop="16px" textAlign="center" gap={0}>
606 <Text
607 margin={0}
608 fontSize="lg"
609 color="#222222"
610 fontWeight={600}
611 >
612 {__("You don't have any Manager yet", 'everest-forms')}
613 </Text>
614 <Text
615 margin="8px 0 0 0"
616 fontSize="sm"
617 color="#6B6B6B"
618 fontWeight={400}
619 >
620 {__(
621 'Please create a manager and you are good to go.',
622 'everest-forms',
623 )}
624 </Text>
625 </Stack>
626 </Flex>
627 </Td>
628 </Tr>
629 ) : (
630 managers?.map((value, rowIndex) => {
631 const managed = isRoleManaged(value);
632 return (
633 <Tr
634 key={value.id}
635 role="group"
636 textAlign="left"
637 bg={rowIndex % 2 === 0 ? 'white' : 'primary.15'}
638 >
639 <Td verticalAlign="top" pt="14px">
640 <Checkbox
641 isChecked={selectedRows.includes(value.id)}
642 onChange={(e) =>
643 handleSelectRow(value.id, e.target.checked)
644 }
645 />
646 </Td>
647
648 <Td verticalAlign="top" fontSize="14px">
649 <Box>
650 <Text lineHeight="1.4">
651 {`${value.first_name} ${value.last_name}`}
652 </Text>
653 <Flex
654 alignItems="center"
655 gap="4px"
656 mt="2px"
657 visibility="hidden"
658 _groupHover={{ visibility: 'visible' }}
659 >
660 <Text
661 color="gray.500"
662 fontSize="xs"
663 userSelect="none"
664 >
665 ID: {value.id}
666 </Text>
667 {!managed && (
668 <>
669 <Text
670 color="gray.300"
671 fontSize="xs"
672 userSelect="none"
673 >
674 |
675 </Text>
676 <UserDisplayModal
677 wp_roles={permissions}
678 context="edit"
679 value={{
680 permission: value.permissions,
681 email: value.email,
682 }}
683 />
684 </>
685 )}
686
687 <Text
688 color="gray.300"
689 fontSize="xs"
690 userSelect="none"
691 >
692 |
693 </Text>
694 <TrashUserRoleModel
695 deleteManager={() =>
696 deleteManagerMutation.mutate(value.id)
697 }
698 />
699 </Flex>
700 </Box>
701 </Td>
702
703 <Td verticalAlign="top" fontSize="14px">
704 {value.email}
705 </Td>
706 <Td verticalAlign="top" fontSize="14px">
707 {value.roles}
708 </Td>
709 <Td verticalAlign="top">
710 {managed ? (
711 <Tooltip
712 label={
713 isAdmin(value)
714 ? __(
715 'Administrators have full access by default.',
716 'everest-forms',
717 )
718 : __(
719 'Permissions are managed via role-based access. Disable the role toggle above to edit individually.',
720 'everest-forms',
721 )
722 }
723 fontSize="xs"
724 placement="top"
725 hasArrow
726 bg={'white'}
727 color={'gray.700'}
728 >
729 <Flex
730 alignItems="center"
731 gap="6px"
732 cursor="help"
733 display="inline-flex"
734 >
735 <LockIcon color="gray.400" boxSize="10px" />
736 <Text
737 fontSize="12px"
738 fontWeight="500"
739 color="gray.500"
740 >
741 {isAdmin(value)
742 ? __('All permissions (admin)', 'everest-forms')
743 : __(
744 'All permissions (via role)',
745 'everest-forms',
746 )}
747 </Text>
748 </Flex>
749 </Tooltip>
750 ) : (
751 <PermissionCell
752 permissionKeys={value.permissions}
753 permissionLabels={permissions}
754 />
755 )}
756 </Td>
757 </Tr>
758 );
759 })
760 )}
761 </Tbody>
762 </Table>
763 </Box>
764
765 {/* ── Pagination ────────────────────────────────────── */}
766 {!isLoading && totalManagers > 10 && (
767 <Box borderTop="1px solid" borderColor="gray.200" px={2} py={2} mt={3}>
768 <Flex alignItems="center" justify="space-between">
769 <Text fontSize="sm" color="gray.500">
770 {__('Showing', 'everest-forms')}{' '}
771 {totalManagers === 0 ? 0 : (currentPage - 1) * pageSize + 1}-
772 {Math.min(currentPage * pageSize, totalManagers)}{' '}
773 {__('of', 'everest-forms')} {totalManagers}{' '}
774 {__('entries', 'everest-forms')}
775 </Text>
776
777 <Flex alignItems="center" gap="2px">
778 <IconButton
779 aria-label={__('First page', 'everest-forms')}
780 icon={<FaAngleDoubleLeft />}
781 variant="ghost"
782 colorScheme="gray"
783 size="sm"
784 fontSize="12px"
785 isDisabled={isDisabled || currentPage === 1}
786 onClick={() => handlePageChange(1)}
787 />
788
789 <Pagination
790 pagesCount={pagesCount}
791 currentPage={currentPage}
792 isDisabled={isDisabled}
793 onPageChange={handlePageChange}
794 >
795 <PaginationContainer gap="2px">
796 <PaginationPrevious
797 variant="ghost"
798 colorScheme="gray"
799 size="sm"
800 minW={8}
801 h={8}
802 fontSize="12px"
803 >
804 <FaAngleLeft />
805 </PaginationPrevious>
806
807 <PaginationPageGroup
808 align="center"
809 separator={
810 <PaginationSeparator
811 bg="transparent"
812 color="gray.400"
813 fontSize="sm"
814 w={8}
815 h={8}
816 jumpSize={11}
817 />
818 }
819 >
820 {pages?.map((page) => (
821 <PaginationPage
822 key={`pagination_page_${page}`}
823 page={page}
824 w={8}
825 h={8}
826 fontSize="sm"
827 fontWeight="400"
828 bg="transparent"
829 borderRadius="md"
830 color="gray.600"
831 _hover={{ bg: 'primary.15' }}
832 _current={{
833 bg: 'primary.400',
834 color: 'white',
835 fontWeight: '500',
836 borderRadius: 'md',
837 _hover: { bg: 'primary.500' },
838 }}
839 />
840 ))}
841 </PaginationPageGroup>
842
843 <PaginationNext
844 variant="ghost"
845 colorScheme="gray"
846 size="sm"
847 minW={8}
848 h={8}
849 fontSize="12px"
850 >
851 <FaAngleRight />
852 </PaginationNext>
853 </PaginationContainer>
854 </Pagination>
855
856 <IconButton
857 aria-label={__('Last page', 'everest-forms')}
858 icon={<FaAngleDoubleRight />}
859 variant="ghost"
860 colorScheme="gray"
861 size="sm"
862 fontSize="12px"
863 isDisabled={isDisabled || currentPage === pagesCount}
864 onClick={() => handlePageChange(pagesCount)}
865 />
866 </Flex>
867 </Flex>
868 </Box>
869 )}
870 </Stack>
871 );
872 };
873
874 export default UserRoleTable;
875