folder in summary
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState, type FormEvent } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { EditIcon, IconX, CheckIcon, PlusIcon } from '../ui/icons';
|
||||
import SelectionAssignmentMenu, {
|
||||
SelectionAssignmentMenuItem,
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
} from '../utils/date';
|
||||
import { describeDocumentSummary, type DocumentSummaryRow } from './documentSummary';
|
||||
import { isPlainObject } from '../utils/typeGuards';
|
||||
import { useFolderManager } from '../folders/FolderManagerContext';
|
||||
|
||||
type Identifier = string | number;
|
||||
|
||||
@@ -31,6 +33,7 @@ interface DocumentLike {
|
||||
id?: Identifier;
|
||||
title?: string;
|
||||
issued_at?: string | null;
|
||||
folder_id?: string | null;
|
||||
current_version?: { version_number?: number } | null;
|
||||
tags?: TagEntry[];
|
||||
correspondents?: CorrespondentEntry[];
|
||||
@@ -71,6 +74,7 @@ export interface DocumentSummarySectionProps {
|
||||
onCorrespondentRemove?: (payload: { documentId: Identifier | undefined; correspondentId: Identifier | undefined }) => void;
|
||||
onUpdateTitle?: (docId: Identifier | undefined, title: string) => Promise<boolean> | boolean;
|
||||
onUpdateIssued?: (docId: Identifier | undefined, timestamp: number | null) => Promise<boolean> | boolean;
|
||||
onFolderNavigate?: (folderId: string | null) => void;
|
||||
layout?: 'default' | 'compact';
|
||||
}
|
||||
|
||||
@@ -456,8 +460,10 @@ const DocumentSummarySection: React.FC<DocumentSummarySectionProps> = ({
|
||||
onCorrespondentRemove,
|
||||
onUpdateTitle,
|
||||
onUpdateIssued,
|
||||
onFolderNavigate,
|
||||
layout = 'default',
|
||||
}) => {
|
||||
const folderManager = useFolderManager();
|
||||
const isCompactLayout = layout === 'compact';
|
||||
const summaryRows = useMemo(() => describeDocumentSummary(document), [document]);
|
||||
const issuedDateLabel = useMemo(
|
||||
@@ -499,6 +505,39 @@ const DocumentSummarySection: React.FC<DocumentSummarySectionProps> = ({
|
||||
return rows;
|
||||
}, [document?.current_version?.version_number]);
|
||||
|
||||
const resolvedFolderId = document?.folder_id ?? null;
|
||||
|
||||
const [folderName, setFolderName] = useState<string | null>(() => folderManager.getNameSync(resolvedFolderId));
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
const cached = folderManager.getNameSync(resolvedFolderId);
|
||||
setFolderName(cached);
|
||||
if (!cached && resolvedFolderId != null) {
|
||||
folderManager.resolveName(resolvedFolderId).then((name) => {
|
||||
if (active) {
|
||||
setFolderName(name);
|
||||
}
|
||||
}).catch(() => {});
|
||||
}
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [resolvedFolderId, folderManager]);
|
||||
|
||||
const folderHref = resolvedFolderId == null ? '/documents' : `/documents/folder/${resolvedFolderId}`;
|
||||
|
||||
const handleFolderClick = useCallback(
|
||||
(event: React.MouseEvent) => {
|
||||
if (!onFolderNavigate) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
onFolderNavigate(resolvedFolderId);
|
||||
},
|
||||
[onFolderNavigate, resolvedFolderId],
|
||||
);
|
||||
|
||||
const [titleDraft, setTitleDraft] = useState('');
|
||||
const [titleSaving, setTitleSaving] = useState(false);
|
||||
const [titleError, setTitleError] = useState(null);
|
||||
@@ -741,11 +780,22 @@ const DocumentSummarySection: React.FC<DocumentSummarySectionProps> = ({
|
||||
/>
|
||||
);
|
||||
|
||||
const folderValueContent = (
|
||||
<Link
|
||||
className="document-summary__folder-link"
|
||||
to={folderHref}
|
||||
onClick={handleFolderClick}
|
||||
>
|
||||
{folderName}
|
||||
</Link>
|
||||
);
|
||||
|
||||
const summaryRowOverrides = {
|
||||
title: { valueContent: titleMetaDisplay, error: titleError },
|
||||
issued: { valueContent: issuedDisplay, error: issuedError },
|
||||
tags: { valueContent: tagsValueContent },
|
||||
correspondents: { valueContent: correspondentsValueContent },
|
||||
folder: { valueContent: folderValueContent },
|
||||
} as Record<string, { valueContent?: React.ReactNode | null; error?: string | null }>;
|
||||
|
||||
const baseRows: MetaItem[] = [...summaryRows, ...extraSummaryRows].map((row) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { formatFileSize } from '../utils/format';
|
||||
import { formatDateTime as defaultFormatDateTime } from '../utils/date';
|
||||
import { DEFAULT_FOLDER_NAME } from '../app/appLayoutUtils';
|
||||
|
||||
interface DocumentPageMetadata {
|
||||
page_count?: number | string | null;
|
||||
@@ -24,11 +25,13 @@ export interface SummaryDocument {
|
||||
original_name?: string | null;
|
||||
filename?: string | null;
|
||||
content_type?: string | null;
|
||||
folder_id?: string | null;
|
||||
folder_name?: string;
|
||||
current_version?: DocumentVersion | null;
|
||||
created_at?: string | null;
|
||||
updated_at?: string | null;
|
||||
issued_at?: string | null;
|
||||
folder_path?: string | null;
|
||||
folder_path?: string;
|
||||
tags?: TagEntry[] | null;
|
||||
correspondents?: CorrespondentEntry[] | null;
|
||||
}
|
||||
@@ -37,7 +40,7 @@ interface DescribeSummaryOptions {
|
||||
formatDateTime?: typeof defaultFormatDateTime;
|
||||
}
|
||||
|
||||
export type DocumentSummaryRowType = 'text' | 'editable-title' | 'editable-issued' | 'tags' | 'correspondents';
|
||||
export type DocumentSummaryRowType = 'text' | 'editable-title' | 'editable-issued' | 'tags' | 'correspondents' | 'folder';
|
||||
|
||||
export interface DocumentSummaryRow {
|
||||
key: string;
|
||||
@@ -86,6 +89,7 @@ export const describeDocumentSummary = (document?: SummaryDocument | null, optio
|
||||
const metadata = doc.current_version?.metadata || null;
|
||||
const pageCount = coercePageCount(metadata);
|
||||
const pageCountLabel = Number.isFinite(pageCount) ? String(pageCount) : '—';
|
||||
const folderLabel = doc.folder_id == null ? DEFAULT_FOLDER_NAME : `Folder ${doc.folder_id}`;
|
||||
const tags = sanitizeArray<TagEntry>(doc.tags);
|
||||
const correspondents = sanitizeArray<CorrespondentEntry>(doc.correspondents);
|
||||
const tagLabels = tags.map((tag) => tag.label).filter(Boolean) as string[];
|
||||
@@ -99,6 +103,7 @@ export const describeDocumentSummary = (document?: SummaryDocument | null, optio
|
||||
{ key: 'issued', label: 'Issued', value: formatDateLabel(doc.issued_at), kind: 'editable-issued' },
|
||||
{ key: 'created', label: 'Created at', value: formatDateLabel(doc.created_at) },
|
||||
{ key: 'updated', label: 'Updated at', value: formatDateLabel(doc.updated_at) },
|
||||
{ key: 'folder', label: 'Folder', value: folderLabel, kind: 'folder' },
|
||||
{ key: 'size', label: 'Size', value: sizeLabel },
|
||||
{ key: 'content-type', label: 'Content type', value: doc.content_type || 'Unknown' },
|
||||
{ key: 'pages', label: 'Pages', value: pageCountLabel },
|
||||
|
||||
Reference in New Issue
Block a user