From 69f7e4f9e8b8c828c7f1cbf56ee65c02c99a9178 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 24 May 2026 16:27:14 +0500 Subject: [PATCH] feat: add admin test checklist page --- .../src/pages/admin-test-checklist/index.ts | 1 + .../ui/AdminTestChecklistPage.tsx | 156 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 client/src/pages/admin-test-checklist/index.ts create mode 100644 client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx diff --git a/client/src/pages/admin-test-checklist/index.ts b/client/src/pages/admin-test-checklist/index.ts new file mode 100644 index 0000000..1108b62 --- /dev/null +++ b/client/src/pages/admin-test-checklist/index.ts @@ -0,0 +1 @@ +export { AdminTestChecklistPage } from './ui/AdminTestChecklistPage' diff --git a/client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx b/client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx new file mode 100644 index 0000000..d658675 --- /dev/null +++ b/client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx @@ -0,0 +1,156 @@ +import { useMemo, useState } from 'react' +import Accordion from '@mui/material/Accordion' +import AccordionDetails from '@mui/material/AccordionDetails' +import AccordionSummary from '@mui/material/AccordionSummary' +import Box from '@mui/material/Box' +import Button from '@mui/material/Button' +import Checkbox from '@mui/material/Checkbox' +import CircularProgress from '@mui/material/CircularProgress' +import Dialog from '@mui/material/Dialog' +import DialogActions from '@mui/material/DialogActions' +import DialogContent from '@mui/material/DialogContent' +import DialogContentText from '@mui/material/DialogContentText' +import DialogTitle from '@mui/material/DialogTitle' +import Stack from '@mui/material/Stack' +import Table from '@mui/material/Table' +import TableBody from '@mui/material/TableBody' +import TableCell from '@mui/material/TableCell' +import TableContainer from '@mui/material/TableContainer' +import TableHead from '@mui/material/TableHead' +import TableRow from '@mui/material/TableRow' +import Typography from '@mui/material/Typography' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { TEST_CHECKLIST_ITEMS } from '@shared/constants/test-checklist-items' +import { fetchTestChecklistResults, resetTestChecklist, updateTestChecklistItem } from '@/entities/test-checklist/api/test-checklist-api' + +function formatDate(iso: string): string { + return new Date(iso).toLocaleString('ru-RU', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }) +} + +export function AdminTestChecklistPage() { + const queryClient = useQueryClient() + const [confirmOpen, setConfirmOpen] = useState(false) + const [expanded, setExpanded] = useState(false) + + const { data, isLoading } = useQuery({ + queryKey: ['admin', 'test-checklist'], + queryFn: fetchTestChecklistResults, + }) + + const updateMutation = useMutation({ + mutationFn: ({ itemKey, passed }: { itemKey: string; passed: boolean }) => updateTestChecklistItem(itemKey, passed), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['admin', 'test-checklist'] }) + }, + }) + + const resetMutation = useMutation({ + mutationFn: resetTestChecklist, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['admin', 'test-checklist'] }) + setConfirmOpen(false) + }, + }) + + const sections = useMemo(() => { + const map = new Map() + for (const item of TEST_CHECKLIST_ITEMS) { + const existing = map.get(item.section) || [] + existing.push(item) + map.set(item.section, existing) + } + return Array.from(map.entries()) + }, []) + + const results = data?.results ?? {} + + const total = TEST_CHECKLIST_ITEMS.length + const passedCount = TEST_CHECKLIST_ITEMS.filter((i) => results[i.key]?.passed).length + + return ( + + + + + Тест-чеклист + + + Пройдено: {passedCount} из {total} + + + + + + {isLoading ? ( + + + + ) : ( + sections.map(([section, items]) => ( + setExpanded(isExpanded ? section : false)}> + }> + {section} + + + + + + + + Действие + Ожидаемый результат + Дата проверки + + + + {items.map((item) => { + const r = results[item.key] + return ( + + + updateMutation.mutate({ itemKey: item.key, passed: checked })} + color="success" + /> + + {item.action} + {item.expectedResult} + + {r ? formatDate(r.checkedAt) : '—'} + + + ) + })} + +
+
+
+
+ )) + )} + + setConfirmOpen(false)}> + Сбросить все проверки? + + Все отметки будут удалены. Это действие нельзя отменить. + + + + + + +
+ ) +}