122 lines
4.6 KiB
TypeScript
122 lines
4.6 KiB
TypeScript
'use client';
|
||
|
||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||
import { FileText } from 'lucide-react';
|
||
import { DocumentDialog } from '@/components/documents/document-dialog';
|
||
import { DocumentPhotosInline } from '@/components/documents/document-photo-gallery';
|
||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||
import { getDocumentType, indexDocumentsByType, parseAttachmentMeta, parseDocumentPhotos, parseMetadata, 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;
|
||
const photoKeys = parseDocumentPhotos(parseMetadata(document.metadataJson));
|
||
const attachmentMeta = parseAttachmentMeta(parseMetadata(document.metadataJson));
|
||
return (
|
||
<div key={document.id}>
|
||
<button
|
||
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>
|
||
{photoKeys.length > 0 && token ? (
|
||
<div className="mt-2 px-1">
|
||
<DocumentPhotosInline userId={targetUserId} token={token} storageKeys={photoKeys} attachmentMeta={attachmentMeta} />
|
||
</div>
|
||
) : null}
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
</DialogContent>
|
||
</Dialog>
|
||
|
||
{activeType ? (
|
||
<DocumentDialog
|
||
open={Boolean(activeType)}
|
||
onOpenChange={(nextOpen) => {
|
||
if (!nextOpen) {
|
||
setActiveType(null);
|
||
setSelectedDocument(null);
|
||
}
|
||
}}
|
||
documentType={activeType}
|
||
userId={targetUserId}
|
||
token={token}
|
||
existing={selectedDocument}
|
||
onSaved={loadDocuments}
|
||
readOnly
|
||
/>
|
||
) : null}
|
||
</>
|
||
);
|
||
}
|