Skip to content

Commit

Permalink
Merge pull request #7 from PropertyControl360/Dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
PropertyControl360 authored Aug 29, 2024
2 parents 8ea5a73 + b1c5099 commit 4e46aca
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 64 deletions.
11 changes: 10 additions & 1 deletion src/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,13 @@ export const toggleUserActiveStatus = async (userId: string) => {
console.error('Error toggling user active status', error);
throw error;
}
};
};
export const deleteUser = async (userId: string) => {
try {
const response = await axios.patch(`${endpoints.users}/${userId}/delete`);
return response.data;
} catch (error) {
console.error('Error toggling user active status', error);
throw error;
}
};
11 changes: 9 additions & 2 deletions src/sections/dashboard/components/app-user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Scrollbar from 'src/components/scrollbar';
import { TableHeadCustom } from 'src/components/table';
import CustomPopover, { usePopover } from 'src/components/custom-popover';
import { FormControlLabel, Switch } from '@mui/material';
import { toggleUserActiveStatus } from 'src/api/user';
import { deleteUser, toggleUserActiveStatus } from 'src/api/user';
import { paths } from 'src/routes/paths';

// ----------------------------------------------------------------------
Expand Down Expand Up @@ -110,9 +110,16 @@ function AppUserRow({ row , refetch}: AppUserRowProps) {
console.info('SHARE', row.id);
};

const handleDelete = () => {
const handleDelete = async() => {
popover.onClose();
console.info('DELETE', row.id);
try {
await deleteUser(row.id);
refetch()
}
catch (error) {
console.error('Failed to delete user', error)
}
};

const handleToggleActiveStatus = async (userId:string) => {
Expand Down
229 changes: 168 additions & 61 deletions src/sections/dashboard/components/error-log-table.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React, { useState, useMemo } from 'react';
import Box from '@mui/material/Box';
import Table from '@mui/material/Table';
import Button from '@mui/material/Button';
Expand All @@ -14,9 +15,14 @@ import { useLocation, useNavigate } from 'react-router-dom';
import Label from 'src/components/label';
import Iconify from 'src/components/iconify';
import Scrollbar from 'src/components/scrollbar';
import { TableHeadCustom } from 'src/components/table';
import CustomPopover, { usePopover } from 'src/components/custom-popover';
import { TableHeadCustom, TablePaginationCustom, TableEmptyRows, TableNoData, emptyRows } from 'src/components/table';
import { paths } from 'src/routes/paths';
import Stack from '@mui/material/Stack';
import FilledInput from '@mui/material/FilledInput';
import Chip from '@mui/material/Chip';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import { SelectChangeEvent } from '@mui/material';

// ----------------------------------------------------------------------

Expand All @@ -43,13 +49,122 @@ interface Props extends CardProps {
tableLabels: any;
}

enum Filter {
All = 'all',
RegisterError = 'registererror',
LoginError = 'loginerror',
EmailVerificationError = 'emailverificationerror',
PasswordResetError = 'passwordreseterror',
ReferralError = 'referralerror'
}

enum SortBy {
Newest = 'newest',
Oldest = 'oldest'
}
export const getLabelColor = (errorType: string) => {
switch (errorType.toLowerCase()) {
case 'registererror':
return 'warning';
case 'loginerror':
return 'error';
case 'emailverificationerror':
return 'info';
case 'passwordreseterror':
return 'error';
case 'referralerror':
return 'warning';
default:
return 'default';
}
};

export default function AppErrorLog({ title, subheader, tableData, tableLabels, ...other }: Props) {
const location = useLocation();
const navigate = useNavigate();

const [search, setSearch] = useState('');
const [filter, setFilter] = useState<Filter>(Filter.All);
const [sortBy, setSortBy] = useState<SortBy>(SortBy.Newest);
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);

// Filtered and sorted data
const filteredData = useMemo(() => {
let data = tableData;

// Filter by type
if (filter !== Filter.All) {
data = data.filter(row => row.errorType.toLowerCase() === filter);
}

// Filter by search term
if (search) {
data = data.filter(row =>
row.errorMessage.toLowerCase().includes(search.toLowerCase()) ||
(row.user?.firstName.toLowerCase().includes(search.toLowerCase()) ||
row.user?.lastName.toLowerCase().includes(search.toLowerCase()))
);
}

// Sort data
if (sortBy === SortBy.Newest) {
data = data.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
} else if (sortBy === SortBy.Oldest) {
data = data.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
}

return data;
}, [tableData, filter, search, sortBy]);

const dataInPage = filteredData.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
);

const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage);
};

const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};

const denseHeight = 56;
const emptyRowsCount = emptyRows(page, rowsPerPage, filteredData.length);
const notFound = !dataInPage.length;

return (
<Card {...other}>
<CardHeader title={title} subheader={subheader} sx={{ mb: 3 }} />


<Divider />

{/* Filter and Search Area */}
<Box sx={{ p: 2 }}>
<Stack flexDirection="row" justifyContent="space-between" alignItems="center" flexWrap="wrap" spacing={1.5}>

<Stack flexDirection="row" spacing={1.25}>
<Chip label="Show All" variant={filter === Filter.All ? 'filled' : 'outlined'} color="primary" onClick={() => setFilter(Filter.All)} />
<Chip label="Register Error" variant={filter === Filter.RegisterError ? 'filled' : 'outlined'} color={getLabelColor("registererror")} onClick={() => setFilter(Filter.RegisterError)} />
<Chip label="Login Error" variant={filter === Filter.LoginError ? 'filled' : 'outlined'} color={getLabelColor("loginerror")} onClick={() => setFilter(Filter.LoginError)} />
<Chip label="Email Verification Error" variant={filter === Filter.EmailVerificationError ? 'filled' : 'outlined'} color={getLabelColor("emailverificationerror")} onClick={() => setFilter(Filter.EmailVerificationError)} />
<Chip label="Password Reset Error" variant={filter === Filter.PasswordResetError ? 'filled' : 'outlined'} color={getLabelColor("passwordreseterror")} onClick={() => setFilter(Filter.PasswordResetError)} />
<Chip label="Referral Error" variant={filter === Filter.ReferralError ? 'filled' : 'outlined'} color={getLabelColor("referralerror")} onClick={() => setFilter(Filter.ReferralError)} />
</Stack>
<Stack flexDirection="row" alignItems="center" spacing={1}>
<Typography fontSize={14} fontWeight={400} color="text.secondary">Sort by</Typography>
<FormControl variant="standard" sx={{ minWidth: 120 }}>
<Select value={sortBy} onChange={(e: SelectChangeEvent) => setSortBy(e.target.value as SortBy)} sx={{ color: 'primary.main' }}>
<MenuItem value={SortBy.Newest}>Newest</MenuItem>
<MenuItem value={SortBy.Oldest}>Oldest</MenuItem>
</Select>
</FormControl>
</Stack>
</Stack>
</Box>

<Divider />

<TableContainer sx={{ overflow: 'unset' }}>
Expand All @@ -58,27 +173,41 @@ export default function AppErrorLog({ title, subheader, tableData, tableLabels,
<TableHeadCustom headLabel={tableLabels} />

<TableBody>
{tableData.map((row) => (
{dataInPage.map((row) => (
<AppErrorLogRow key={row.id} row={row} />
))}

<TableEmptyRows height={denseHeight} emptyRows={emptyRowsCount} />

<TableNoData notFound={notFound} />
</TableBody>
</Table>
</Scrollbar>
</TableContainer>

<Divider sx={{ borderStyle: 'dashed' }} />

{location.pathname === paths.dashboard.root && <Box sx={{ p: 2, textAlign: 'right' }}>
<Button
size="small"
color="inherit"
endIcon={<Iconify icon="eva:arrow-ios-forward-fill" width={18} sx={{ ml: -0.5 }} />}
onClick={() => navigate(paths.dashboard.errorLogs.root)}
>
View All
</Button>
</Box>
}
{location.pathname === paths.dashboard.root && (
<Box sx={{ p: 2, textAlign: 'right' }}>
<Button
size="small"
color="inherit"
endIcon={<Iconify icon="eva:arrow-ios-forward-fill" width={18} sx={{ ml: -0.5 }} />}
onClick={() => navigate(paths.dashboard.errorLogs.root)}
>
View All
</Button>
</Box>
)}

{/* Pagination */}
<TablePaginationCustom
count={filteredData.length}
page={page}
rowsPerPage={rowsPerPage}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Card>
);
}
Expand All @@ -90,10 +219,6 @@ type AppErrorLogRowProps = {
};

function AppErrorLogRow({ row }: AppErrorLogRowProps) {
const popover = usePopover();



const formatDate = (date: string) => {
const options = {
day: '2-digit',
Expand All @@ -105,49 +230,31 @@ function AppErrorLogRow({ row }: AppErrorLogRowProps) {
return new Date(date).toLocaleDateString('en-GB', options);
};

const getLabelColor = (errorType: string) => {
switch (errorType.toLowerCase()) {
case 'registererror':
return 'warning';
case 'loginerror':
return 'error';
case 'emailverificationerror':
return 'info';
case 'passwordreseterror':
return 'error';
case 'referralerror':
return 'warning';
default:
return 'default';
}
};


return (
<>
<TableRow hover>
<TableCell>
<Typography variant="body2" color="text.primary">
{row.user ? `${row.user.firstName} ${row.user.lastName}` : 'N/A'}
</Typography>
<Typography variant="caption" color="text.secondary">
{row.user?.email || 'No Email'}
</Typography>
</TableCell>
<TableCell>
<Typography variant="body2" color="text.primary">
{row.errorMessage}
</Typography>
</TableCell>
<TableCell>
<Label color={getLabelColor(row.errorType)}>{row.errorType}</Label>
</TableCell>
<TableCell>
<Typography variant="body2" color="text.primary">
{formatDate(row.createdAt)}
</Typography>
</TableCell>
</TableRow>

</>
<TableRow hover>
<TableCell>
<Typography variant="body2" color="text.primary">
{row.user ? `${row.user.firstName} ${row.user.lastName}` : 'N/A'}
</Typography>
<Typography variant="caption" color="text.secondary">
{row.user?.email || 'No Email'}
</Typography>
</TableCell>
<TableCell>
<Typography variant="body2" color="text.primary">
{row.errorMessage}
</Typography>
</TableCell>
<TableCell>
<Label color={getLabelColor(row.errorType)}>{row.errorType}</Label>
</TableCell>
<TableCell>
<Typography variant="body2" color="text.primary">
{formatDate(row.createdAt)}
</Typography>
</TableCell>
</TableRow>
);
}

0 comments on commit 4e46aca

Please sign in to comment.