ui-nyla/src/components/UiComponents/Messages/MessageParts/DocumentItem.tsx

131 lines
4 KiB
TypeScript

import React, { useMemo } from 'react';
import { MessageDocument, Message } from '../MessagesTypes';
import { formatFileSize } from '../MessageUtils';
import { ViewActionButton, DeleteActionButton, RemoveActionButton } from '../../../FormGenerator/ActionButtons';
import { WorkflowFile } from '../../../../hooks/usePlayground';
import styles from '../Messages.module.css';
export interface DocumentItemProps {
document: MessageDocument;
message: Message;
className?: string;
onFileDelete?: (file: WorkflowFile) => Promise<void>;
onFileRemove?: (file: WorkflowFile) => Promise<void>;
onFileView?: (file: WorkflowFile) => Promise<void>;
deletingFiles?: Set<string>;
previewingFiles?: Set<string>;
removingFiles?: Set<string>;
workflowId?: string;
}
/**
* Renders a single document attachment with action buttons
*/
export const DocumentItem: React.FC<DocumentItemProps> = ({
document,
message: _message,
className,
onFileDelete,
onFileRemove,
onFileView,
deletingFiles = new Set(),
previewingFiles = new Set(),
removingFiles = new Set(),
workflowId: _workflowId
}) => {
// Convert MessageDocument to WorkflowFile format for compatibility with action buttons
const workflowFile: WorkflowFile = useMemo(() => ({
id: document.id,
fileId: document.fileId,
fileName: document.fileName,
fileSize: document.fileSize,
mimeType: document.mimeType,
messageId: document.messageId,
source: 'user_uploaded' // Default to user_uploaded, can be enhanced later
}), [document]);
const isDeleting = deletingFiles.has(document.fileId);
const isPreviewing = previewingFiles.has(document.fileId);
const isRemoving = removingFiles.has(document.fileId);
// Create hookData object for action buttons
const hookData = useMemo(() => ({
handleDelete: async (_fileId: string) => {
if (onFileDelete) {
await onFileDelete(workflowFile);
return true;
}
return false;
},
removeOptimistically: () => {
// Handled by parent component
},
refetch: async () => {
// Refetch handled by parent
},
deletingItems: deletingFiles,
previewingFiles: previewingFiles,
removingItems: removingFiles
}), [onFileDelete, workflowFile, deletingFiles, previewingFiles, removingFiles]);
const handleView = async () => {
if (onFileView) {
await onFileView(workflowFile);
}
};
const handleRemove = async () => {
if (onFileRemove) {
await onFileRemove(workflowFile);
}
};
return (
<div className={`${styles.documentItem} ${className || ''}`}>
<div className={styles.documentIcon}>📎</div>
<div className={styles.documentInfo}>
<div className={styles.documentName}>{document.fileName}</div>
<div className={styles.documentMeta}>
{formatFileSize(document.fileSize)} {document.mimeType}
</div>
</div>
{(onFileView || onFileDelete || onFileRemove) && (
<div style={{ display: 'flex', gap: '4px', flexShrink: 0 }}>
{onFileView && (
<ViewActionButton
row={workflowFile}
onView={handleView}
disabled={isDeleting || isRemoving}
loading={isPreviewing}
hookData={hookData}
idField="fileId"
nameField="fileName"
typeField="mimeType"
/>
)}
{onFileRemove && (
<RemoveActionButton
row={workflowFile}
onRemove={handleRemove}
disabled={isDeleting}
loading={isRemoving}
hookData={hookData}
idField="fileId"
loadingStateName="removingItems"
/>
)}
{onFileDelete && (
<DeleteActionButton
row={workflowFile}
hookData={hookData}
idField="fileId"
operationName="handleDelete"
loadingStateName="deletingItems"
/>
)}
</div>
)}
</div>
);
};