init students,
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import RouterLink from 'next/link';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import LinearProgress from '@mui/material/LinearProgress';
|
||||
import Link from '@mui/material/Link';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { CheckCircle as CheckCircleIcon } from '@phosphor-icons/react/dist/ssr/CheckCircle';
|
||||
import { Clock as ClockIcon } from '@phosphor-icons/react/dist/ssr/Clock';
|
||||
import { Images as ImagesIcon } from '@phosphor-icons/react/dist/ssr/Images';
|
||||
import { Minus as MinusIcon } from '@phosphor-icons/react/dist/ssr/Minus';
|
||||
import { PencilSimple as PencilSimpleIcon } from '@phosphor-icons/react/dist/ssr/PencilSimple';
|
||||
import { TrashSimple as TrashSimpleIcon } from '@phosphor-icons/react/dist/ssr/TrashSimple';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { paths } from '@/paths';
|
||||
import { dayjs } from '@/lib/dayjs';
|
||||
import { DataTable } from '@/components/core/data-table';
|
||||
import type { ColumnDef } from '@/components/core/data-table';
|
||||
|
||||
import ConfirmDeleteModal from './confirm-delete-modal';
|
||||
import { useCustomersSelection } from './customers-selection-context';
|
||||
import type { Customer } from './type.d';
|
||||
|
||||
function columns(handleDeleteClick: (testId: string) => void): ColumnDef<Customer>[] {
|
||||
return [
|
||||
{
|
||||
formatter: (row): React.JSX.Element => (
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={1}
|
||||
sx={{ alignItems: 'center' }}
|
||||
>
|
||||
<Avatar src={row.avatar} />{' '}
|
||||
<div>
|
||||
<Link
|
||||
color="inherit"
|
||||
component={RouterLink}
|
||||
href={paths.dashboard.customers.details(row.id)}
|
||||
sx={{ whiteSpace: 'nowrap' }}
|
||||
variant="subtitle2"
|
||||
>
|
||||
{row.name}
|
||||
</Link>
|
||||
<Typography
|
||||
color="text.secondary"
|
||||
variant="body2"
|
||||
>
|
||||
{row.email}
|
||||
</Typography>
|
||||
</div>
|
||||
</Stack>
|
||||
),
|
||||
name: 'Name',
|
||||
width: '250px',
|
||||
},
|
||||
{
|
||||
formatter: (row): React.JSX.Element => (
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={2}
|
||||
sx={{ alignItems: 'center' }}
|
||||
>
|
||||
<LinearProgress
|
||||
sx={{ flex: '1 1 auto' }}
|
||||
value={row.quota}
|
||||
variant="determinate"
|
||||
/>
|
||||
<Typography
|
||||
color="text.secondary"
|
||||
variant="body2"
|
||||
>
|
||||
{new Intl.NumberFormat('en-US', { style: 'percent', maximumFractionDigits: 2 }).format(row.quota / 100)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
),
|
||||
name: 'Quota',
|
||||
width: '150px',
|
||||
},
|
||||
{ field: 'phone', name: 'Phone number', width: '150px' },
|
||||
|
||||
{
|
||||
formatter: (row): React.JSX.Element => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
|
||||
const mapping = {
|
||||
active: {
|
||||
label: 'Active',
|
||||
icon: (
|
||||
<CheckCircleIcon
|
||||
color="var(--mui-palette-success-main)"
|
||||
weight="fill"
|
||||
/>
|
||||
),
|
||||
},
|
||||
blocked: { label: 'Blocked', icon: <MinusIcon color="var(--mui-palette-error-main)" /> },
|
||||
pending: {
|
||||
label: 'Pending',
|
||||
icon: (
|
||||
<ClockIcon
|
||||
color="var(--mui-palette-warning-main)"
|
||||
weight="fill"
|
||||
/>
|
||||
),
|
||||
},
|
||||
} as const;
|
||||
const { label, icon } = mapping[row.status] ?? { label: 'Unknown', icon: null };
|
||||
|
||||
return (
|
||||
<Chip
|
||||
icon={icon}
|
||||
label={label}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
);
|
||||
},
|
||||
name: 'Status',
|
||||
width: '150px',
|
||||
},
|
||||
{
|
||||
formatter(row) {
|
||||
return dayjs(row.createdAt).format('MMM D, YYYY');
|
||||
},
|
||||
name: 'Created at',
|
||||
width: '150px',
|
||||
},
|
||||
{
|
||||
formatter: (row): React.JSX.Element => (
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={1}
|
||||
>
|
||||
<LoadingButton
|
||||
//
|
||||
color="secondary"
|
||||
component={RouterLink}
|
||||
href={paths.dashboard.customers.details(row.id)}
|
||||
>
|
||||
<PencilSimpleIcon size={24} />
|
||||
</LoadingButton>
|
||||
<LoadingButton
|
||||
color="error"
|
||||
// TODO: originally it is row.isEmpty
|
||||
disabled={false}
|
||||
onClick={() => {
|
||||
handleDeleteClick(row.id);
|
||||
}}
|
||||
>
|
||||
<TrashSimpleIcon size={24} />
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
),
|
||||
name: 'Actions',
|
||||
hideName: true,
|
||||
align: 'right',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export interface CustomersTableProps {
|
||||
rows: Customer[];
|
||||
reloadRows: () => void;
|
||||
}
|
||||
|
||||
export function CustomersTable({ rows, reloadRows }: CustomersTableProps): React.JSX.Element {
|
||||
const { t } = useTranslation(['customers']);
|
||||
const { deselectAll, deselectOne, selectAll, selectOne, selected } = useCustomersSelection();
|
||||
|
||||
const [idToDelete, setIdToDelete] = React.useState('');
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
function handleDeleteClick(testId: string): void {
|
||||
setOpen(true);
|
||||
setIdToDelete(testId);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ConfirmDeleteModal
|
||||
idToDelete={idToDelete}
|
||||
open={open}
|
||||
reloadRows={reloadRows}
|
||||
setOpen={setOpen}
|
||||
/>
|
||||
<DataTable<Customer>
|
||||
columns={columns(handleDeleteClick)}
|
||||
onDeselectAll={deselectAll}
|
||||
onDeselectOne={(_, row) => {
|
||||
deselectOne(row.id);
|
||||
}}
|
||||
onSelectAll={selectAll}
|
||||
onSelectOne={(_, row) => {
|
||||
selectOne(row.id);
|
||||
}}
|
||||
rows={rows}
|
||||
selectable
|
||||
selected={selected}
|
||||
/>
|
||||
{!rows.length ? (
|
||||
<Box sx={{ p: 3 }}>
|
||||
<Typography
|
||||
color="text.secondary"
|
||||
sx={{ textAlign: 'center' }}
|
||||
variant="body2"
|
||||
>
|
||||
{/* TODO: update this */}
|
||||
{t('no-record-found')}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user