uchill/front_minimal/src/sections/children/view/children-view.jsx

245 lines
8.4 KiB
JavaScript

'use client';
import { useRouter } from 'src/routes/hooks';
import { useState, useEffect, useCallback } from 'react';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Alert from '@mui/material/Alert';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import CircularProgress from '@mui/material/CircularProgress';
import InputAdornment from '@mui/material/InputAdornment';
import { paths } from 'src/routes/paths';
import axios from 'src/utils/axios';
import { DashboardContent } from 'src/layouts/dashboard';
import { Iconify } from 'src/components/iconify';
import { CustomBreadcrumbs } from 'src/components/custom-breadcrumbs';
// ----------------------------------------------------------------------
async function getChildren() {
const res = await axios.get('/parent/dashboard/');
const raw = res.data?.children ?? [];
return raw.map((item) => {
const c = item.child ?? item;
const [first_name = '', ...rest] = (c.name || '').split(' ');
return { id: c.id, first_name, last_name: rest.join(' '), email: c.email };
});
}
// ----------------------------------------------------------------------
function AddChildDialog({ open, onClose, onSuccess }) {
const [code, setCode] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleClose = () => {
setCode('');
setError('');
onClose();
};
const handleSubmit = async () => {
const trimmed = code.trim().toUpperCase();
if (!trimmed) { setError('Введите код'); return; }
if (trimmed.length !== 8) { setError('Код должен содержать ровно 8 символов'); return; }
try {
setLoading(true);
setError('');
await axios.post('/manage/parents/add_child/', { universal_code: trimmed });
handleClose();
onSuccess();
} catch (e) {
const msg = e?.response?.data?.error
|| e?.response?.data?.detail
|| e?.message
|| 'Ошибка при добавлении';
setError(msg);
} finally {
setLoading(false);
}
};
return (
<Dialog open={open} onClose={handleClose} maxWidth="xs" fullWidth>
<DialogTitle>Добавить ребёнка по коду</DialogTitle>
<DialogContent>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
Введите 8-значный код из профиля ребёнка. Код содержит буквы и цифры.
</Typography>
<TextField
autoFocus
fullWidth
label="Код ребёнка"
placeholder="Например: 8XW4EIVL"
value={code}
onChange={(e) => {
setCode(e.target.value.toUpperCase());
setError('');
}}
onKeyDown={(e) => e.key === 'Enter' && handleSubmit()}
inputProps={{ maxLength: 8, style: { letterSpacing: 4, fontWeight: 600, fontSize: 18 } }}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Iconify icon="solar:key-bold" width={20} />
</InputAdornment>
),
}}
error={!!error}
helperText={error || ' '}
/>
</DialogContent>
<DialogActions sx={{ px: 3, pb: 2 }}>
<Button onClick={handleClose} color="inherit" disabled={loading}>
Отмена
</Button>
<Button
variant="contained"
onClick={handleSubmit}
disabled={loading || code.trim().length !== 8}
startIcon={loading ? <CircularProgress size={16} /> : <Iconify icon="solar:user-plus-bold" width={18} />}
>
Добавить
</Button>
</DialogActions>
</Dialog>
);
}
// ----------------------------------------------------------------------
export function ChildrenView() {
const router = useRouter();
const [children, setChildren] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [addOpen, setAddOpen] = useState(false);
const load = useCallback(async () => {
try {
setLoading(true);
setError(null);
const list = await getChildren();
setChildren(list);
} catch (e) {
setError(e?.response?.data?.detail || e?.message || 'Ошибка загрузки');
} finally {
setLoading(false);
}
}, []);
useEffect(() => { load(); }, [load]);
return (
<DashboardContent>
<CustomBreadcrumbs
heading="Мои дети"
links={[{ name: 'Главная', href: paths.dashboard.root }, { name: 'Мои дети' }]}
action={
<Button
variant="contained"
startIcon={<Iconify icon="solar:user-plus-bold" width={18} />}
onClick={() => setAddOpen(true)}
>
Добавить ребёнка
</Button>
}
sx={{ mb: 3 }}
/>
{error && (
<Alert severity="error" sx={{ mb: 3 }}>
{error}
</Alert>
)}
{loading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
<CircularProgress />
</Box>
) : children.length === 0 ? (
<Box sx={{ textAlign: 'center', py: 8 }}>
<Iconify icon="eva:people-outline" width={64} color="text.disabled" />
<Typography variant="body1" color="text.secondary" sx={{ mt: 2 }}>
Нет привязанных детей
</Typography>
<Button
variant="outlined"
sx={{ mt: 2 }}
startIcon={<Iconify icon="solar:user-plus-bold" width={18} />}
onClick={() => setAddOpen(true)}
>
Добавить ребёнка по коду
</Button>
</Box>
) : (
<Grid container spacing={2}>
{children.map((child) => {
const name = `${child.first_name || ''} ${child.last_name || ''}`.trim() || child.email;
return (
<Grid key={child.id} item xs={12} sm={6} md={4}>
<Card variant="outlined">
<CardContent>
<Stack direction="row" spacing={2} alignItems="center">
<Avatar sx={{ width: 48, height: 48, bgcolor: 'primary.lighter', color: 'primary.main' }}>
{name[0]?.toUpperCase()}
</Avatar>
<Box>
<Typography variant="subtitle1">{name}</Typography>
<Typography variant="body2" color="text.secondary">
{child.email}
</Typography>
</Box>
</Stack>
</CardContent>
<CardActions sx={{ px: 2, pb: 2 }}>
<Button
variant="contained"
fullWidth
startIcon={<Iconify icon="solar:chart-square-bold" />}
onClick={() => {
localStorage.setItem('selected_child', JSON.stringify({ id: child.id, name }));
window.dispatchEvent(new Event('child-changed'));
router.push(paths.dashboard.root);
}}
>
Дашборд
</Button>
</CardActions>
</Card>
</Grid>
);
})}
</Grid>
)}
<AddChildDialog
open={addOpen}
onClose={() => setAddOpen(false)}
onSuccess={() => {
load();
window.dispatchEvent(new Event('child-changed'));
}}
/>
</DashboardContent>
);
}