openreader/src/components/DocumentList.tsx
Richard Roberson d025227518 More refactors
2025-01-29 22:04:11 -07:00

157 lines
6.5 KiB
TypeScript

import { usePDF } from '@/contexts/PDFContext';
import Link from 'next/link';
import { Button, Dialog } from '@headlessui/react';
import { Transition, TransitionChild, DialogPanel, DialogTitle } from '@headlessui/react';
import { Fragment, useState } from 'react';
export function DocumentList() {
const { documents, removeDocument, isDocsLoading } = usePDF();
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [documentToDelete, setDocumentToDelete] = useState<{ id: string; name: string } | null>(null);
const handleDelete = async () => {
if (documentToDelete) {
try {
await removeDocument(documentToDelete.id);
setIsDeleteDialogOpen(false);
setDocumentToDelete(null);
} catch (err) {
console.error('Failed to remove document:', err);
}
}
};
if (isDocsLoading) {
return (
<div className="w-full text-center text-muted">
Loading documents...
</div>
);
}
if (documents.length === 0) {
return (
<div className="w-full text-center text-muted">
No documents uploaded yet
</div>
);
}
return (
<div className="w-full mx-auto">
<h2 className="text-xl font-semibold mb-4 text-foreground">Your Documents</h2>
<div className="bg-background rounded-lg shadow p-2 space-y-2">
{documents.map((doc) => (
<Transition
key={doc.id}
show={true}
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<div
className="flex items-center justify-between hover:bg-base p-1 rounded-lg transition-colors"
>
<Link
href={`/pdf/${encodeURIComponent(doc.id)}`}
className="flex items-center space-x-4 flex-1 min-w-0"
>
<div className="flex-shrink-0">
<svg className="w-6 h-6 sm:w-8 sm:h-8 text-accent" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
</div>
<div className="flex-1 min-w-0 transform transition-transform duration-200 ease-in-out hover:scale-[1.02]">
<p className="text-sm sm:text-md text-foreground font-medium truncate">{doc.name}</p>
<p className="text-xs sm:text-sm text-muted truncate">
{(doc.size / 1024 / 1024).toFixed(2)} MB
</p>
</div>
</Link>
<Button
onClick={() => {
setDocumentToDelete({ id: doc.id, name: doc.name });
setIsDeleteDialogOpen(true);
}}
className="ml-4 p-2 text-muted hover:text-red-500 rounded-lg hover:bg-red-50 transition-colors"
aria-label="Delete document"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
</Button>
</div>
</Transition>
))}
</div>
<Transition appear show={isDeleteDialogOpen} as={Fragment}>
<Dialog
as="div"
className="relative z-50"
onClose={() => setIsDeleteDialogOpen(false)}
>
<TransitionChild
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black bg-opacity-25" />
</TransitionChild>
<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<TransitionChild
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<DialogPanel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-background p-6 text-left align-middle shadow-xl transition-all">
<DialogTitle
as="h3"
className="text-lg font-medium leading-6 text-foreground"
>
Delete Document
</DialogTitle>
<div className="mt-2">
<p className="text-sm text-muted">
Are you sure you want to delete <span className='font-bold'>{documentToDelete?.name}</span>? This action cannot be undone.
</p>
</div>
<div className="mt-4 flex justify-end space-x-3">
<Button
type="button"
className="inline-flex justify-center rounded-md border border-transparent bg-base px-4 py-2 text-sm font-medium text-foreground hover:bg-base/80 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2"
onClick={() => setIsDeleteDialogOpen(false)}
>
Cancel
</Button>
<Button
type="button"
className="inline-flex justify-center rounded-md border border-transparent bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2"
onClick={handleDelete}
>
Delete
</Button>
</div>
</DialogPanel>
</TransitionChild>
</div>
</div>
</Dialog>
</Transition>
</div>
);
}