gitscope
https://dev.kronoz.win/r/marzneshin.git
app/dashboard/src/pages/hosts/users/table/index.tsx · v0.1.0
Source
1 6aab6f0 Mrdn 2y ago
2 6aab6f0 Mrdn 2y ago import {
3 6aab6f0 Mrdn 2y ago Accordion,
4 6aab6f0 Mrdn 2y ago AccordionButton,
5 6aab6f0 Mrdn 2y ago AccordionItem,
6 6aab6f0 Mrdn 2y ago AccordionPanel,
7 6aab6f0 Mrdn 2y ago Box,
8 6aab6f0 Mrdn 2y ago HStack,
9 6aab6f0 Mrdn 2y ago IconButton,
10 6aab6f0 Mrdn 2y ago Table,
11 6aab6f0 Mrdn 2y ago TableProps,
12 6aab6f0 Mrdn 2y ago Tbody,
13 6aab6f0 Mrdn 2y ago Td,
14 6aab6f0 Mrdn 2y ago Text,
15 6aab6f0 Mrdn 2y ago Th,
16 6aab6f0 Mrdn 2y ago Thead,
17 6aab6f0 Mrdn 2y ago Tooltip,
18 6aab6f0 Mrdn 2y ago Tr,
19 6aab6f0 Mrdn 2y ago useBreakpointValue,
20 6aab6f0 Mrdn 2y ago VStack,
21 6aab6f0 Mrdn 2y ago } from '@chakra-ui/react';
22 6aab6f0 Mrdn 2y ago import classNames from 'classnames';
23 6aab6f0 Mrdn 2y ago import { statusColors } from 'constants/Settings';
24 6aab6f0 Mrdn 2y ago import { FC, Fragment, useState } from 'react';
25 6aab6f0 Mrdn 2y ago import { useTranslation } from 'react-i18next';
26 6aab6f0 Mrdn 2y ago import { OnlineBadge } from 'components/online-badge';
27 6aab6f0 Mrdn 2y ago import { OnlineStatus } from 'components/online-status';
28 6aab6f0 Mrdn 2y ago import { StatusBadge } from 'components/status-badge';
29 6aab6f0 Mrdn 2y ago import {
30 6aab6f0 Mrdn 2y ago Pagination,
31 6aab6f0 Mrdn 2y ago EmptySection,
32 6aab6f0 Mrdn 2y ago AccordionArrowIcon,
33 6aab6f0 Mrdn 2y ago handleSort,
34 6aab6f0 Mrdn 2y ago EditIcon,
35 6aab6f0 Mrdn 2y ago StatusSortSelect,
36 6aab6f0 Mrdn 2y ago Sort,
37 6aab6f0 Mrdn 2y ago } from 'components/table';
38 6aab6f0 Mrdn 2y ago import { UsageSlider, UsageSliderCompact } from './usage-slider';
39 6aab6f0 Mrdn 2y ago import { useUsers } from 'stores';
40 6aab6f0 Mrdn 2y ago import { ActionButtons } from './action-buttons';
41 6aab6f0 Mrdn 2y ago import { pageSizeManagers } from 'utils/userPreferenceStorage';
42 6aab6f0 Mrdn 2y ago
43 6aab6f0 Mrdn 2y ago type ExpandedIndex = number | number[];
44 6aab6f0 Mrdn 2y ago
45 6aab6f0 Mrdn 2y ago type UsersTableProps = {} & TableProps;
46 6aab6f0 Mrdn 2y ago
47 6aab6f0 Mrdn 2y ago export const UsersTable: FC<UsersTableProps> = (props) => {
48 6aab6f0 Mrdn 2y ago const {
49 6aab6f0 Mrdn 2y ago usersFilters: filters,
50 6aab6f0 Mrdn 2y ago users: { users },
51 6aab6f0 Mrdn 2y ago users: { total },
52 6aab6f0 Mrdn 2y ago onEditingUser,
53 6aab6f0 Mrdn 2y ago onCreateUser,
54 6aab6f0 Mrdn 2y ago onFilterChange,
55 6aab6f0 Mrdn 2y ago } = useUsers();
56 6aab6f0 Mrdn 2y ago
57 6aab6f0 Mrdn 2y ago const { t } = useTranslation();
58 6aab6f0 Mrdn 2y ago const [selectedRow, setSelectedRow] = useState<ExpandedIndex | undefined>(
59 6aab6f0 Mrdn 2y ago undefined
60 6aab6f0 Mrdn 2y ago );
61 6aab6f0 Mrdn 2y ago const useTable = useBreakpointValue({ base: false, md: true });
62 6aab6f0 Mrdn 2y ago
63 6aab6f0 Mrdn 2y ago const isFiltered = users.length !== total;
64 6aab6f0 Mrdn 2y ago
65 6aab6f0 Mrdn 2y ago const handleStatusFilter = (e: any) => {
66 6aab6f0 Mrdn 2y ago onFilterChange({
67 6aab6f0 Mrdn 2y ago status: e.target.value.length > 0 ? e.target.value : undefined,
68 6aab6f0 Mrdn 2y ago });
69 6aab6f0 Mrdn 2y ago };
70 6aab6f0 Mrdn 2y ago
71 6aab6f0 Mrdn 2y ago const toggleAccordion = (index: number) => {
72 6aab6f0 Mrdn 2y ago setSelectedRow(index === selectedRow ? undefined : index);
73 6aab6f0 Mrdn 2y ago };
74 6aab6f0 Mrdn 2y ago return (
75 6aab6f0 Mrdn 2y ago <Box id="users-table" overflowX={{ base: 'unset', md: 'unset' }}>
76 6aab6f0 Mrdn 2y ago <Accordion
77 6aab6f0 Mrdn 2y ago allowMultiple
78 6aab6f0 Mrdn 2y ago display={{ base: 'block', md: 'none' }}
79 6aab6f0 Mrdn 2y ago index={selectedRow}
80 6aab6f0 Mrdn 2y ago >
81 6aab6f0 Mrdn 2y ago <Table orientation="vertical" zIndex="docked" {...props}>
82 6aab6f0 Mrdn 2y ago <Thead zIndex="docked" position="relative">
83 6aab6f0 Mrdn 2y ago <Tr>
84 6aab6f0 Mrdn 2y ago <Th
85 6aab6f0 Mrdn 2y ago position="sticky"
86 6aab6f0 Mrdn 2y ago minW="120px"
87 6aab6f0 Mrdn 2y ago pl={4}
88 6aab6f0 Mrdn 2y ago pr={4}
89 6aab6f0 Mrdn 2y ago cursor={'pointer'}
90 6aab6f0 Mrdn 2y ago onClick={handleSort.bind(null, filters, 'username', onFilterChange)}
91 6aab6f0 Mrdn 2y ago >
92 6aab6f0 Mrdn 2y ago <HStack>
93 6aab6f0 Mrdn 2y ago <span>{t('users')}</span>
94 6aab6f0 Mrdn 2y ago <Sort sort={filters.sort} column="username" />
95 6aab6f0 Mrdn 2y ago </HStack>
96 6aab6f0 Mrdn 2y ago </Th>
97 6aab6f0 Mrdn 2y ago <Th
98 6aab6f0 Mrdn 2y ago position="sticky"
99 6aab6f0 Mrdn 2y ago minW="50px"
100 6aab6f0 Mrdn 2y ago pl={0}
101 6aab6f0 Mrdn 2y ago pr={0}
102 6aab6f0 Mrdn 2y ago w="140px"
103 6aab6f0 Mrdn 2y ago cursor={'pointer'}
104 6aab6f0 Mrdn 2y ago >
105 6aab6f0 Mrdn 2y ago <HStack spacing={0} position="relative">
106 6aab6f0 Mrdn 2y ago <Text
107 6aab6f0 Mrdn 2y ago position="absolute"
108 6aab6f0 Mrdn 2y ago _dark={{
109 6aab6f0 Mrdn 2y ago bg: 'gray.750',
110 6aab6f0 Mrdn 2y ago }}
111 6aab6f0 Mrdn 2y ago _light={{
112 6aab6f0 Mrdn 2y ago bg: '#F9FAFB',
113 6aab6f0 Mrdn 2y ago }}
114 6aab6f0 Mrdn 2y ago userSelect="none"
115 6aab6f0 Mrdn 2y ago pointerEvents="none"
116 6aab6f0 Mrdn 2y ago zIndex={1}
117 6aab6f0 Mrdn 2y ago w="100%"
118 6aab6f0 Mrdn 2y ago >
119 6aab6f0 Mrdn 2y ago {t('usersTable.status')}
120 6aab6f0 Mrdn 2y ago {filters.status ? ': ' + filters.status : ''}
121 6aab6f0 Mrdn 2y ago </Text>
122 6aab6f0 Mrdn 2y ago <StatusSortSelect filters={filters} handleStatusFilter={handleStatusFilter} options={['active', 'disabled', 'limited', 'expired', 'on_hold']} />
123 6aab6f0 Mrdn 2y ago </HStack>
124 6aab6f0 Mrdn 2y ago </Th>
125 6aab6f0 Mrdn 2y ago <Th
126 6aab6f0 Mrdn 2y ago position="sticky"
127 6aab6f0 Mrdn 2y ago minW="100px"
128 6aab6f0 Mrdn 2y ago cursor={'pointer'}
129 6aab6f0 Mrdn 2y ago pr={0}
130 6aab6f0 Mrdn 2y ago onClick={handleSort.bind(null, filters, 'used_traffic', onFilterChange)}
131 6aab6f0 Mrdn 2y ago >
132 6aab6f0 Mrdn 2y ago <HStack>
133 6aab6f0 Mrdn 2y ago <span>{t('usersTable.dataUsage')}</span>
134 6aab6f0 Mrdn 2y ago <Sort sort={filters.sort} column="used_traffic" />
135 6aab6f0 Mrdn 2y ago </HStack>
136 6aab6f0 Mrdn 2y ago </Th>
137 6aab6f0 Mrdn 2y ago <Th
138 6aab6f0 Mrdn 2y ago position="sticky"
139 6aab6f0 Mrdn 2y ago minW="32px"
140 6aab6f0 Mrdn 2y ago w="32px"
141 6aab6f0 Mrdn 2y ago p={0}
142 6aab6f0 Mrdn 2y ago cursor={'pointer'}
143 6aab6f0 Mrdn 2y ago ></Th>
144 6aab6f0 Mrdn 2y ago </Tr>
145 6aab6f0 Mrdn 2y ago </Thead>
146 6aab6f0 Mrdn 2y ago <Tbody>
147 6aab6f0 Mrdn 2y ago {!useTable &&
148 6aab6f0 Mrdn 2y ago users?.map((user, i) => {
149 6aab6f0 Mrdn 2y ago return (
150 6aab6f0 Mrdn 2y ago <Fragment key={user.username}>
151 6aab6f0 Mrdn 2y ago <Tr
152 6aab6f0 Mrdn 2y ago onClick={toggleAccordion.bind(null, i)}
153 6aab6f0 Mrdn 2y ago cursor="pointer"
154 6aab6f0 Mrdn 2y ago >
155 6aab6f0 Mrdn 2y ago <Td borderBottom={0} minW="100px" pl={4} pr={4}>
156 6aab6f0 Mrdn 2y ago <div className="flex-status">
157 6aab6f0 Mrdn 2y ago <OnlineBadge lastOnline={user.online_at} />
158 6aab6f0 Mrdn 2y ago {user.username}
159 6aab6f0 Mrdn 2y ago </div>
160 6aab6f0 Mrdn 2y ago </Td>
161 6aab6f0 Mrdn 2y ago <Td borderBottom={0} minW="50px" pl={0} pr={0}>
162 6aab6f0 Mrdn 2y ago <StatusBadge
163 6aab6f0 Mrdn 2y ago compact
164 6aab6f0 Mrdn 2y ago showDetail={false}
165 6aab6f0 Mrdn 2y ago expiryDate={user.expire}
166 6aab6f0 Mrdn 2y ago status={user.status}
167 6aab6f0 Mrdn 2y ago />
168 6aab6f0 Mrdn 2y ago </Td>
169 6aab6f0 Mrdn 2y ago <Td borderBottom={0} minW="100px" pr={0}>
170 6aab6f0 Mrdn 2y ago <UsageSliderCompact
171 6aab6f0 Mrdn 2y ago totalUsedTraffic={user.lifetime_used_traffic}
172 6aab6f0 Mrdn 2y ago dataLimitResetStrategy={
173 6aab6f0 Mrdn 2y ago user.data_limit_reset_strategy
174 6aab6f0 Mrdn 2y ago }
175 6aab6f0 Mrdn 2y ago used={user.used_traffic}
176 6aab6f0 Mrdn 2y ago total={user.data_limit}
177 6aab6f0 Mrdn 2y ago colorScheme={statusColors[user.status].bandWidthColor}
178 6aab6f0 Mrdn 2y ago />
179 6aab6f0 Mrdn 2y ago </Td>
180 6aab6f0 Mrdn 2y ago <Td p={0} borderBottom={0} w="32px" minW="32px">
181 6aab6f0 Mrdn 2y ago <AccordionArrowIcon
182 6aab6f0 Mrdn 2y ago color="gray.600"
183 6aab6f0 Mrdn 2y ago _dark={{
184 6aab6f0 Mrdn 2y ago color: 'gray.400',
185 6aab6f0 Mrdn 2y ago }}
186 6aab6f0 Mrdn 2y ago transition="transform .2s ease-out"
187 6aab6f0 Mrdn 2y ago transform={
188 6aab6f0 Mrdn 2y ago selectedRow === i ? 'rotate(180deg)' : '0deg'
189 6aab6f0 Mrdn 2y ago }
190 6aab6f0 Mrdn 2y ago />
191 6aab6f0 Mrdn 2y ago </Td>
192 6aab6f0 Mrdn 2y ago </Tr>
193 6aab6f0 Mrdn 2y ago <Tr
194 6aab6f0 Mrdn 2y ago className="collapsible"
195 6aab6f0 Mrdn 2y ago onClick={toggleAccordion.bind(null, i)}
196 6aab6f0 Mrdn 2y ago >
197 6aab6f0 Mrdn 2y ago <Td p={0} colSpan={4}>
198 6aab6f0 Mrdn 2y ago <AccordionItem border={0}>
199 6aab6f0 Mrdn 2y ago <AccordionButton display="none"></AccordionButton>
200 6aab6f0 Mrdn 2y ago <AccordionPanel
201 6aab6f0 Mrdn 2y ago border={0}
202 6aab6f0 Mrdn 2y ago cursor="pointer"
203 6aab6f0 Mrdn 2y ago px={6}
204 6aab6f0 Mrdn 2y ago py={3}
205 6aab6f0 Mrdn 2y ago >
206 6aab6f0 Mrdn 2y ago <VStack justifyContent="space-between" spacing="4">
207 6aab6f0 Mrdn 2y ago <VStack
208 6aab6f0 Mrdn 2y ago alignItems="flex-start"
209 6aab6f0 Mrdn 2y ago w="full"
210 6aab6f0 Mrdn 2y ago spacing={-1}
211 6aab6f0 Mrdn 2y ago >
212 6aab6f0 Mrdn 2y ago <Text
213 6aab6f0 Mrdn 2y ago textTransform="capitalize"
214 6aab6f0 Mrdn 2y ago fontSize="xs"
215 6aab6f0 Mrdn 2y ago fontWeight="bold"
216 6aab6f0 Mrdn 2y ago color="gray.600"
217 6aab6f0 Mrdn 2y ago _dark={{
218 6aab6f0 Mrdn 2y ago color: 'gray.400',
219 6aab6f0 Mrdn 2y ago }}
220 6aab6f0 Mrdn 2y ago >
221 6aab6f0 Mrdn 2y ago {t('usersTable.dataUsage')}
222 6aab6f0 Mrdn 2y ago </Text>
223 6aab6f0 Mrdn 2y ago <Box width="full" minW="230px">
224 6aab6f0 Mrdn 2y ago <UsageSlider
225 6aab6f0 Mrdn 2y ago totalUsedTraffic={
226 6aab6f0 Mrdn 2y ago user.lifetime_used_traffic
227 6aab6f0 Mrdn 2y ago }
228 6aab6f0 Mrdn 2y ago dataLimitResetStrategy={
229 6aab6f0 Mrdn 2y ago user.data_limit_reset_strategy
230 6aab6f0 Mrdn 2y ago }
231 6aab6f0 Mrdn 2y ago used={user.used_traffic}
232 6aab6f0 Mrdn 2y ago total={user.data_limit}
233 6aab6f0 Mrdn 2y ago colorScheme={
234 6aab6f0 Mrdn 2y ago statusColors[user.status].bandWidthColor
235 6aab6f0 Mrdn 2y ago }
236 6aab6f0 Mrdn 2y ago />
237 6aab6f0 Mrdn 2y ago </Box>
238 6aab6f0 Mrdn 2y ago </VStack>
239 6aab6f0 Mrdn 2y ago <HStack w="full" justifyContent="space-between">
240 6aab6f0 Mrdn 2y ago <Box width="full">
241 6aab6f0 Mrdn 2y ago <StatusBadge
242 6aab6f0 Mrdn 2y ago compact
243 6aab6f0 Mrdn 2y ago expiryDate={user.expire}
244 6aab6f0 Mrdn 2y ago status={user.status}
245 6aab6f0 Mrdn 2y ago />
246 6aab6f0 Mrdn 2y ago <OnlineStatus lastOnline={user.online_at} />
247 6aab6f0 Mrdn 2y ago </Box>
248 6aab6f0 Mrdn 2y ago <HStack>
249 6aab6f0 Mrdn 2y ago <ActionButtons user={user} />
250 6aab6f0 Mrdn 2y ago <Tooltip
251 6aab6f0 Mrdn 2y ago label={t('userDialog.editUser')}
252 6aab6f0 Mrdn 2y ago placement="top"
253 6aab6f0 Mrdn 2y ago >
254 6aab6f0 Mrdn 2y ago <IconButton
255 6aab6f0 Mrdn 2y ago p="0 !important"
256 6aab6f0 Mrdn 2y ago aria-label="Edit user"
257 6aab6f0 Mrdn 2y ago bg="transparent"
258 6aab6f0 Mrdn 2y ago _dark={{
259 6aab6f0 Mrdn 2y ago _hover: {
260 6aab6f0 Mrdn 2y ago bg: 'gray.700',
261 6aab6f0 Mrdn 2y ago },
262 6aab6f0 Mrdn 2y ago }}
263 6aab6f0 Mrdn 2y ago size={{
264 6aab6f0 Mrdn 2y ago base: 'sm',
265 6aab6f0 Mrdn 2y ago md: 'md',
266 6aab6f0 Mrdn 2y ago }}
267 6aab6f0 Mrdn 2y ago onClick={(e) => {
268 6aab6f0 Mrdn 2y ago e.stopPropagation();
269 6aab6f0 Mrdn 2y ago onEditingUser(user);
270 6aab6f0 Mrdn 2y ago }}
271 6aab6f0 Mrdn 2y ago >
272 6aab6f0 Mrdn 2y ago <EditIcon />
273 6aab6f0 Mrdn 2y ago </IconButton>
274 6aab6f0 Mrdn 2y ago </Tooltip>
275 6aab6f0 Mrdn 2y ago </HStack>
276 6aab6f0 Mrdn 2y ago </HStack>
277 6aab6f0 Mrdn 2y ago </VStack>
278 6aab6f0 Mrdn 2y ago </AccordionPanel>
279 6aab6f0 Mrdn 2y ago </AccordionItem>
280 6aab6f0 Mrdn 2y ago </Td>
281 6aab6f0 Mrdn 2y ago </Tr>
282 6aab6f0 Mrdn 2y ago </Fragment>
283 6aab6f0 Mrdn 2y ago );
284 6aab6f0 Mrdn 2y ago })}
285 6aab6f0 Mrdn 2y ago </Tbody>
286 6aab6f0 Mrdn 2y ago </Table>
287 6aab6f0 Mrdn 2y ago </Accordion>
288 6aab6f0 Mrdn 2y ago <Table
289 6aab6f0 Mrdn 2y ago orientation="vertical"
290 6aab6f0 Mrdn 2y ago display={{ base: 'none', md: 'table' }}
291 6aab6f0 Mrdn 2y ago {...props}
292 6aab6f0 Mrdn 2y ago >
293 6aab6f0 Mrdn 2y ago <Thead zIndex="docked" position="relative">
294 6aab6f0 Mrdn 2y ago <Tr>
295 6aab6f0 Mrdn 2y ago <Th
296 6aab6f0 Mrdn 2y ago position="sticky"
297 6aab6f0 Mrdn 2y ago minW="140px"
298 6aab6f0 Mrdn 2y ago cursor={'pointer'}
299 6aab6f0 Mrdn 2y ago onClick={handleSort.bind(null, filters, 'username', onFilterChange)}
300 6aab6f0 Mrdn 2y ago >
301 6aab6f0 Mrdn 2y ago <HStack>
302 6aab6f0 Mrdn 2y ago <span>{t('username')}</span>
303 6aab6f0 Mrdn 2y ago <Sort sort={filters.sort} column="username" />
304 6aab6f0 Mrdn 2y ago </HStack>
305 6aab6f0 Mrdn 2y ago </Th>
306 6aab6f0 Mrdn 2y ago <Th
307 6aab6f0 Mrdn 2y ago position="sticky"
308 6aab6f0 Mrdn 2y ago width="400px"
309 6aab6f0 Mrdn 2y ago minW="150px"
310 6aab6f0 Mrdn 2y ago cursor={'pointer'}
311 6aab6f0 Mrdn 2y ago >
312 6aab6f0 Mrdn 2y ago <HStack spacing={0} position="relative">
313 6aab6f0 Mrdn 2y ago <Text
314 6aab6f0 Mrdn 2y ago position="absolute"
315 6aab6f0 Mrdn 2y ago _dark={{
316 6aab6f0 Mrdn 2y ago bg: 'gray.750',
317 6aab6f0 Mrdn 2y ago }}
318 6aab6f0 Mrdn 2y ago _light={{
319 6aab6f0 Mrdn 2y ago bg: '#F9FAFB',
320 6aab6f0 Mrdn 2y ago }}
321 6aab6f0 Mrdn 2y ago userSelect="none"
322 6aab6f0 Mrdn 2y ago pointerEvents="none"
323 6aab6f0 Mrdn 2y ago zIndex={1}
324 6aab6f0 Mrdn 2y ago w="100%"
325 6aab6f0 Mrdn 2y ago >
326 6aab6f0 Mrdn 2y ago {t('usersTable.status')}
327 6aab6f0 Mrdn 2y ago {filters.status ? ': ' + filters.status : ''}
328 6aab6f0 Mrdn 2y ago </Text>
329 6aab6f0 Mrdn 2y ago <StatusSortSelect filters={filters} handleStatusFilter={handleStatusFilter} options={['active', 'disabled', 'limited', 'expired', 'on_hold']} />
330 6aab6f0 Mrdn 2y ago </HStack>
331 6aab6f0 Mrdn 2y ago </Th>
332 6aab6f0 Mrdn 2y ago <Th
333 6aab6f0 Mrdn 2y ago position="sticky"
334 6aab6f0 Mrdn 2y ago width="350px"
335 6aab6f0 Mrdn 2y ago minW="230px"
336 6aab6f0 Mrdn 2y ago cursor={'pointer'}
337 6aab6f0 Mrdn 2y ago onClick={handleSort.bind(null, filters, 'used_traffic', onFilterChange)}
338 6aab6f0 Mrdn 2y ago >
339 6aab6f0 Mrdn 2y ago <HStack>
340 6aab6f0 Mrdn 2y ago <span>{t('usersTable.dataUsage')}</span>
341 6aab6f0 Mrdn 2y ago <Sort sort={filters.sort} column="used_traffic" />
342 6aab6f0 Mrdn 2y ago </HStack>
343 6aab6f0 Mrdn 2y ago </Th>
344 6aab6f0 Mrdn 2y ago <Th
345 6aab6f0 Mrdn 2y ago position="sticky"
346 6aab6f0 Mrdn 2y ago width="200px"
347 6aab6f0 Mrdn 2y ago minW="180px"
348 6aab6f0 Mrdn 2y ago />
349 6aab6f0 Mrdn 2y ago </Tr>
350 6aab6f0 Mrdn 2y ago </Thead>
351 6aab6f0 Mrdn 2y ago <Tbody>
352 6aab6f0 Mrdn 2y ago {useTable &&
353 6aab6f0 Mrdn 2y ago users?.map((user, i) => {
354 6aab6f0 Mrdn 2y ago return (
355 6aab6f0 Mrdn 2y ago <Tr
356 6aab6f0 Mrdn 2y ago key={user.username}
357 6aab6f0 Mrdn 2y ago className={classNames('interactive', {
358 6aab6f0 Mrdn 2y ago 'last-row': i === users.length - 1,
359 6aab6f0 Mrdn 2y ago })}
360 6aab6f0 Mrdn 2y ago onClick={() => onEditingUser(user)}
361 6aab6f0 Mrdn 2y ago >
362 6aab6f0 Mrdn 2y ago <Td minW="140px">
363 6aab6f0 Mrdn 2y ago <div className="flex-status">
364 6aab6f0 Mrdn 2y ago <OnlineBadge lastOnline={user.online_at} />
365 6aab6f0 Mrdn 2y ago {user.username}
366 6aab6f0 Mrdn 2y ago <OnlineStatus lastOnline={user.online_at} />
367 6aab6f0 Mrdn 2y ago </div>
368 6aab6f0 Mrdn 2y ago </Td>
369 6aab6f0 Mrdn 2y ago <Td width="400px" minW="150px">
370 6aab6f0 Mrdn 2y ago <StatusBadge
371 6aab6f0 Mrdn 2y ago expiryDate={user.expire}
372 6aab6f0 Mrdn 2y ago status={user.status}
373 6aab6f0 Mrdn 2y ago />
374 6aab6f0 Mrdn 2y ago </Td>
375 6aab6f0 Mrdn 2y ago <Td width="350px" minW="230px">
376 6aab6f0 Mrdn 2y ago <UsageSlider
377 6aab6f0 Mrdn 2y ago totalUsedTraffic={user.lifetime_used_traffic}
378 6aab6f0 Mrdn 2y ago dataLimitResetStrategy={user.data_limit_reset_strategy}
379 6aab6f0 Mrdn 2y ago used={user.used_traffic}
380 6aab6f0 Mrdn 2y ago total={user.data_limit}
381 6aab6f0 Mrdn 2y ago colorScheme={statusColors[user.status].bandWidthColor}
382 6aab6f0 Mrdn 2y ago />
383 6aab6f0 Mrdn 2y ago </Td>
384 6aab6f0 Mrdn 2y ago <Td width="200px" minW="180px">
385 6aab6f0 Mrdn 2y ago <ActionButtons user={user} />
386 6aab6f0 Mrdn 2y ago </Td>
387 6aab6f0 Mrdn 2y ago </Tr>
388 6aab6f0 Mrdn 2y ago );
389 6aab6f0 Mrdn 2y ago })}
390 6aab6f0 Mrdn 2y ago {users.length == 0 && (
391 6aab6f0 Mrdn 2y ago <Tr>
392 6aab6f0 Mrdn 2y ago <Td colSpan={4}>
393 6aab6f0 Mrdn 2y ago <EmptySection
394 6aab6f0 Mrdn 2y ago isFiltered={isFiltered}
395 6aab6f0 Mrdn 2y ago noObjectT="usersTable.noUser"
396 6aab6f0 Mrdn 2y ago noObjectMatchedT='usersTable.noUserMatched'
397 6aab6f0 Mrdn 2y ago createObjectT="createUser"
398 6aab6f0 Mrdn 2y ago onCreateObject={onCreateUser}
399 6aab6f0 Mrdn 2y ago />
400 6aab6f0 Mrdn 2y ago </Td>
401 6aab6f0 Mrdn 2y ago </Tr>
402 6aab6f0 Mrdn 2y ago )}
403 6aab6f0 Mrdn 2y ago </Tbody>
404 6aab6f0 Mrdn 2y ago </Table>
405 6aab6f0 Mrdn 2y ago <Pagination filters={filters} total={total} onFilterChange={onFilterChange} pageSizeManager={pageSizeManagers.users} />
406 6aab6f0 Mrdn 2y ago </Box>
407 6aab6f0 Mrdn 2y ago );
408 6aab6f0 Mrdn 2y ago };