template tutoring-admin-dashboard v1
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded';
|
||||
import MarkEmailReadRoundedIcon from '@mui/icons-material/MarkEmailReadRounded';
|
||||
import Box from '@mui/material/Box';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { deleteEnquiry, listEnquiries, patchEnquiry } from '../../services/content';
|
||||
import { SEED, type Enquiry } from '../../services/mockData';
|
||||
|
||||
export function EnquiriesPanel() {
|
||||
const [rows, setRows] = useState<Enquiry[]>([]);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
|
||||
const load = () => {
|
||||
listEnquiries()
|
||||
.then((d) => {
|
||||
setRows(d);
|
||||
setLoaded(true);
|
||||
})
|
||||
.catch(() => {
|
||||
// Preview / offline: show the seed so the panel isn't empty.
|
||||
setRows(SEED.enquiries);
|
||||
setLoaded(true);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(load, []);
|
||||
|
||||
const toggleRead = async (e: Enquiry) => {
|
||||
setRows((rs) => rs.map((r) => (r.id === e.id ? { ...r, is_read: !r.is_read } : r)));
|
||||
try {
|
||||
await patchEnquiry(e.id, !e.is_read);
|
||||
} catch {
|
||||
/* optimistic */
|
||||
}
|
||||
};
|
||||
|
||||
const remove = async (e: Enquiry) => {
|
||||
setRows((rs) => rs.filter((r) => r.id !== e.id));
|
||||
try {
|
||||
await deleteEnquiry(e.id);
|
||||
} catch {
|
||||
/* optimistic */
|
||||
}
|
||||
};
|
||||
|
||||
const unread = rows.filter((r) => !r.is_read).length;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, mb: 2 }}>
|
||||
<Typography variant="h5">Enquiries</Typography>
|
||||
{unread > 0 && <Chip label={`${unread} unread`} color="secondary" size="small" />}
|
||||
</Box>
|
||||
|
||||
<Stack spacing={1.5}>
|
||||
{loaded && rows.length === 0 && (
|
||||
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
||||
No enquiries yet. Messages from your contact form will appear here.
|
||||
</Typography>
|
||||
)}
|
||||
{rows.map((e) => (
|
||||
<Card key={e.id} sx={{ borderColor: e.is_read ? 'divider' : 'secondary.main' }}>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 1 }}>
|
||||
<Box sx={{ minWidth: 0 }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
|
||||
{e.name}
|
||||
{!e.is_read && (
|
||||
<Chip label="New" color="secondary" size="small" sx={{ ml: 1, height: 20 }} />
|
||||
)}
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
||||
{[e.email, e.phone].filter(Boolean).join(' · ')}
|
||||
{e.subject_interest ? ` · Interested in ${e.subject_interest}` : ''}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 0.5, flexShrink: 0 }}>
|
||||
<Tooltip title={e.is_read ? 'Mark as unread' : 'Mark as read'}>
|
||||
<IconButton onClick={() => toggleRead(e)} color={e.is_read ? 'default' : 'primary'}>
|
||||
<MarkEmailReadRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete">
|
||||
<IconButton color="error" onClick={() => remove(e)}>
|
||||
<DeleteRoundedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
<Typography variant="body1" sx={{ mt: 1.5 }}>
|
||||
{e.message}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: 'text.secondary', mt: 1, display: 'block' }}>
|
||||
{new Date(e.created_at).toLocaleString()}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user