diff --git a/client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx b/client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx
index c9d0f2d..f5207f5 100644
--- a/client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx
+++ b/client/src/pages/admin-test-checklist/ui/AdminTestChecklistPage.tsx
@@ -1,17 +1,16 @@
-import { useMemo, useState } from 'react'
+import { useCallback, useMemo, useState } from 'react'
import Alert from '@mui/material/Alert'
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 IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import Table from '@mui/material/Table'
import TableBody from '@mui/material/TableBody'
@@ -19,7 +18,11 @@ 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 TextField from '@mui/material/TextField'
+import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
+import CheckCircleIcon from '@mui/icons-material/CheckCircle'
+import CancelIcon from '@mui/icons-material/Cancel'
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'
@@ -29,6 +32,13 @@ import {
updateTestChecklistItem,
} from '@/entities/test-checklist/api/test-checklist-api'
+type Status = 'passed' | 'failed' | 'unchecked'
+
+function statusFromResult(r: { passed: boolean; comment: string | null } | undefined): Status {
+ if (!r) return 'unchecked'
+ return r.passed ? 'passed' : 'failed'
+}
+
function formatDate(iso: string): string {
return new Date(iso).toLocaleString('ru-RU', {
day: '2-digit',
@@ -39,10 +49,30 @@ function formatDate(iso: string): string {
})
}
+function StatusIcon({ status, onClick }: { status: Status; onClick: () => void }) {
+ const icons = {
+ passed: ,
+ failed: ,
+ unchecked: ,
+ }
+
+ return (
+
+
+ {icons[status]}
+
+
+ )
+}
+
export function AdminTestChecklistPage() {
const queryClient = useQueryClient()
const [confirmOpen, setConfirmOpen] = useState(false)
const [expanded, setExpanded] = useState(false)
+ const [errorDialogOpen, setErrorDialogOpen] = useState(false)
+ const [errorItemKey, setErrorItemKey] = useState(null)
+ const [errorComment, setErrorComment] = useState('')
+ const [errorCommentError, setErrorCommentError] = useState(false)
const { data, isLoading, isError } = useQuery({
queryKey: ['admin', 'test-checklist'],
@@ -50,7 +80,8 @@ export function AdminTestChecklistPage() {
})
const updateMutation = useMutation({
- mutationFn: ({ itemKey, passed }: { itemKey: string; passed: boolean }) => updateTestChecklistItem(itemKey, passed),
+ mutationFn: ({ itemKey, passed, comment }: { itemKey: string; passed: boolean; comment?: string | null }) =>
+ updateTestChecklistItem(itemKey, passed, comment),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin', 'test-checklist'] })
},
@@ -79,6 +110,40 @@ export function AdminTestChecklistPage() {
const total = TEST_CHECKLIST_ITEMS.length
const passedCount = TEST_CHECKLIST_ITEMS.filter((i) => results[i.key]?.passed).length
+ const handleStatusClick = useCallback(
+ (itemKey: string) => {
+ const current = statusFromResult(results[itemKey])
+ if (current === 'failed') {
+ // Clicking on failed → reset to unchecked
+ updateMutation.mutate({ itemKey, passed: false, comment: null })
+ } else if (current === 'unchecked') {
+ // Clicking on unchecked → mark as passed
+ updateMutation.mutate({ itemKey, passed: true })
+ } else {
+ // Clicking on passed → open error dialog
+ setErrorItemKey(itemKey)
+ setErrorComment('')
+ setErrorCommentError(false)
+ setErrorDialogOpen(true)
+ }
+ },
+ [results, updateMutation],
+ )
+
+ const handleSaveError = () => {
+ if (!errorItemKey) return
+ if (!errorComment.trim()) {
+ setErrorCommentError(true)
+ return
+ }
+ updateMutation.mutate({ itemKey: errorItemKey, passed: false, comment: errorComment.trim() })
+ setErrorDialogOpen(false)
+ setErrorItemKey(null)
+ setErrorComment('')
+ }
+
+ const errorItem = errorItemKey ? TEST_CHECKLIST_ITEMS.find((i) => i.key === errorItemKey) : null
+
return (
@@ -121,26 +186,46 @@ export function AdminTestChecklistPage() {
-
+
Действие
Ожидаемый результат
+ Комментарий
Дата проверки
{items.map((item) => {
const r = results[item.key]
+ const status = statusFromResult(r)
return (
-
- updateMutation.mutate({ itemKey: item.key, passed: checked })}
- color="success"
- />
+
+ handleStatusClick(item.key)} />
{item.action}
{item.expectedResult}
+
+ {r?.comment ? (
+
+
+ {r.comment}
+
+
+ ) : (
+
+ —
+
+ )}
+
{r ? formatDate(r.checkedAt) : '—'}
@@ -158,7 +243,7 @@ export function AdminTestChecklistPage() {
+
+
)
}