import { useState } from 'react' import { Link, createFileRoute } from '@tanstack/react-router' import { useTranslation } from 'react-i18next' import { Alert, Badge, Button, EmptyState, LoadingBlock, PageHeader, Panel, Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, } from '@/ui' import { useMyDrafts, useMySchemaDrafts } from '@/api/queries' import { useWithdrawDraft } from '@/api/mutations' import type { DraftOperation, DraftStatus, SchemaDraft } from '@/api/client' import { UserCell } from '@/lib/useUserDisplay' export const Route = createFileRoute('/my-drafts')({ component: MyDraftsPage, }) const operationVariant = (op: DraftOperation): 'info' | 'success' | 'warning' => { if (op === 'CREATE') return 'success' if (op === 'CLOSE') return 'warning' return 'info' } const statusVariant = ( s: DraftStatus, ): 'warning' | 'success' | 'error' | 'neutral' => { if (s === 'PENDING') return 'warning' if (s === 'APPROVED') return 'success' if (s === 'REJECTED') return 'error' return 'neutral' } /** Mapping schema draft статусов на UI badge variant. */ const schemaStatusVariant = ( s: string, ): 'warning' | 'success' | 'error' | 'info' | 'neutral' => { if (s === 'review_pending') return 'warning' if (s === 'approved' || s === 'published') return 'success' if (s === 'rejected') return 'error' if (s === 'changes_requested') return 'info' return 'neutral' } /** * Approval Workflow v2 Phase 4: maker self-tracking. Maker видит свои * submissions всех статусов (PENDING/APPROVED/REJECTED/WITHDRAWN), sorted * submitted_at DESC. Polled каждые 30s — maker увидит когда reviewer * approve/reject. Withdraw кнопка для PENDING (только свои + maker-only * gate в backend). */ function MyDraftsPage() { const { t } = useTranslation() const drafts = useMyDrafts(0, 50) const schemaDrafts = useMySchemaDrafts(0, 50) const withdrawMut = useWithdrawDraft() const [busyId, setBusyId] = useState(undefined) const handleWithdraw = (id: string) => { if (!confirm(t('myDrafts.confirmWithdraw'))) return setBusyId(id) withdrawMut.mutate(id, { onSettled: () => setBusyId(undefined), }) } const recordTotal = drafts.data?.totalElements ?? 0 const schemaTotal = schemaDrafts.data?.totalElements ?? 0 const bothEmpty = !drafts.isLoading && !schemaDrafts.isLoading && recordTotal === 0 && schemaTotal === 0 return (
{(drafts.isLoading || schemaDrafts.isLoading) && ( )} {drafts.error && ( {String(drafts.error)} )} {schemaDrafts.error && ( {String(schemaDrafts.error)} )} {bothEmpty && } {schemaTotal > 0 && ( )} {drafts.data && drafts.data.totalElements > 0 && (

{t('myDrafts.records.title', { defaultValue: 'Записи' })}

{t('myDrafts.total', { count: drafts.data.totalElements })}

{t('myDrafts.col.bk')} {t('myDrafts.col.op')} {t('myDrafts.col.status')} {t('myDrafts.col.submitted')} {t('myDrafts.col.reviewed')} {t('myDrafts.col.reviewer')} {t('myDrafts.col.comment')} {t('myDrafts.col.actions')} {drafts.data.items.map((d) => ( {d.businessKey} {d.operation} {d.status} {new Date(d.submittedAt).toLocaleString()} {d.reviewedAt ? new Date(d.reviewedAt).toLocaleString() : '—'} {d.reviewerId ? ( ) : ( )} {d.reviewComment ?? d.makerComment ?? '—'} {d.status === 'PENDING' ? ( ) : ( )} ))}
)}
) } /** * Schema drafts maker self-tracking panel. Параллельно с record drafts * на той же странице — пользователь не должен помнить разные типы. * *

Status badge показывает schema state machine (draft / review_pending / * approved / rejected / changes_requested / withdrawn / published). * "Открыть" линкует на dictionary page где есть drawer с details + actions * (withdraw / re-submit для maker). */ function MySchemaDraftsPanel({ items, total }: { items: SchemaDraft[]; total: number }) { const { t } = useTranslation() return (

{t('myDrafts.schema.title', { defaultValue: 'Черновики схем' })}

{t('myDrafts.schema.total', { count: total, defaultValue: `${total} schema draft(s)`, })}

{t('myDrafts.schema.label', { defaultValue: 'Schema workflow' })}
{t('myDrafts.schema.col.dictionary', { defaultValue: 'Словарь' })} {t('myDrafts.schema.col.fromVersion', { defaultValue: 'От версии' })} {t('myDrafts.schema.col.status', { defaultValue: 'Статус' })} {t('myDrafts.schema.col.created', { defaultValue: 'Создан' })} {t('myDrafts.schema.col.submitted', { defaultValue: 'Отправлен' })} {t('myDrafts.schema.col.action', { defaultValue: 'Действие' })} {items.map((d) => ( {d.dictionaryName ?? '—'} v{d.branchedFromVersion} {d.status} {new Date(d.createdAt).toLocaleString()} {d.submittedAt ? new Date(d.submittedAt).toLocaleString() : '—'} {t('myDrafts.schema.open', { defaultValue: 'Открыть' })} → ))}
) }