first commit
This commit is contained in:
112
apps/frontend/components/documents/user-documents-dialog.tsx
Normal file
112
apps/frontend/components/documents/user-documents-dialog.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { FileText } from 'lucide-react';
|
||||
import { DocumentFormDialog } from '@/components/documents/document-form-dialog';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { getDocumentType, indexDocumentsByType, type DocumentTypeCode } from '@/lib/document-catalog';
|
||||
import { apiFetch, UserDocument } from '@/lib/api';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export function UserDocumentsDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
targetUserId,
|
||||
targetUserName,
|
||||
token
|
||||
}: {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
targetUserId: string;
|
||||
targetUserName: string;
|
||||
token: string | null;
|
||||
}) {
|
||||
const [documents, setDocuments] = useState<UserDocument[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [activeType, setActiveType] = useState<DocumentTypeCode | null>(null);
|
||||
const [selectedDocument, setSelectedDocument] = useState<UserDocument | null>(null);
|
||||
|
||||
const loadDocuments = useCallback(async () => {
|
||||
if (!token || !targetUserId) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await apiFetch<{ documents?: UserDocument[] }>(`/documents/users/${targetUserId}`, {}, token);
|
||||
setDocuments(response.documents ?? []);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [targetUserId, token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) void loadDocuments();
|
||||
}, [loadDocuments, open]);
|
||||
|
||||
const documentsByType = useMemo(() => indexDocumentsByType(documents), [documents]);
|
||||
|
||||
function openDocument(type: DocumentTypeCode) {
|
||||
setSelectedDocument(documentsByType.get(type) ?? null);
|
||||
setActiveType(type);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-h-[90vh] overflow-y-auto rounded-[28px] sm:max-w-[520px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Документы пользователя</DialogTitle>
|
||||
<p className="text-sm text-[#667085]">{targetUserName}</p>
|
||||
</DialogHeader>
|
||||
|
||||
{loading ? <p className="py-8 text-center text-sm text-[#667085]">Загрузка документов...</p> : null}
|
||||
|
||||
{!loading && documents.length === 0 ? (
|
||||
<p className="py-8 text-center text-sm text-[#667085]">У пользователя нет сохранённых документов</p>
|
||||
) : null}
|
||||
|
||||
<div className="space-y-2">
|
||||
{documents.map((document) => {
|
||||
const config = getDocumentType(document.type);
|
||||
if (!config) return null;
|
||||
const Icon = config.icon;
|
||||
return (
|
||||
<button
|
||||
key={document.id}
|
||||
type="button"
|
||||
onClick={() => openDocument(document.type as DocumentTypeCode)}
|
||||
className="flex w-full items-center gap-3 rounded-2xl bg-[#f4f5f8] px-4 py-3 text-left transition hover:bg-[#eceef4]"
|
||||
>
|
||||
<div className={cn('flex h-10 w-10 items-center justify-center rounded-xl', config.accent)}>
|
||||
<Icon className="h-5 w-5" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="font-medium">{config.label}</div>
|
||||
<div className="truncate text-sm text-[#667085]">{document.number}</div>
|
||||
</div>
|
||||
<FileText className="h-4 w-4 text-[#a8adbc]" />
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{activeType ? (
|
||||
<DocumentFormDialog
|
||||
open={Boolean(activeType)}
|
||||
onOpenChange={(nextOpen) => {
|
||||
if (!nextOpen) {
|
||||
setActiveType(null);
|
||||
setSelectedDocument(null);
|
||||
}
|
||||
}}
|
||||
documentType={activeType}
|
||||
userId={targetUserId}
|
||||
token={token}
|
||||
existing={selectedDocument}
|
||||
onSaved={loadDocuments}
|
||||
readOnly
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user