import { Button } from '@/components/ui/button' import { Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, } from '@/components/ui/carousel' import { Dialog, DialogClose, DialogContent, DialogTrigger, } from '@/components/ui/dialog' import { ToastAction } from '@/components/ui/toast' import { useToast } from '@/components/ui/use-toast' import { randomId } from '@/lib/api' import { ExpenseFormValues } from '@/lib/schemas' import { formatFileSize } from '@/lib/utils' import { Loader2, Plus, Trash, X } from 'lucide-react' import { useLocale, useTranslations } from 'next-intl' import { getImageData, usePresignedUpload } from 'next-s3-upload' import Image from 'next/image' import { useEffect, useState } from 'react' type Props = { documents: ExpenseFormValues['documents'] updateDocuments: (documents: ExpenseFormValues['documents']) => void } const MAX_FILE_SIZE = 5 * 1024 ** 2 export function ExpenseDocumentsInput({ documents, updateDocuments }: Props) { const locale = useLocale() const t = useTranslations('ExpenseDocumentsInput') const [pending, setPending] = useState(false) const { FileInput, openFileDialog, uploadToS3 } = usePresignedUpload() // use presigned uploads to addtionally support providers other than AWS const { toast } = useToast() const handleFileChange = async (file: File) => { if (file.size > MAX_FILE_SIZE) { toast({ title: t('TooBigToast.title'), description: t('TooBigToast.description', { maxSize: formatFileSize(MAX_FILE_SIZE, locale), size: formatFileSize(file.size, locale), }), variant: 'destructive', }) return } const upload = async () => { try { setPending(true) const { width, height } = await getImageData(file) if (!width || !height) throw new Error('Cannot get image dimensions') const { url } = await uploadToS3(file) updateDocuments([...documents, { id: randomId(), url, width, height }]) } catch (err) { console.error(err) toast({ title: t('ErrorToast.title'), description: t('ErrorToast.description'), variant: 'destructive', action: ( upload()} > {t('ErrorToast.retry')} ), }) } finally { setPending(false) } } upload() } return (
{documents.map((doc) => ( { updateDocuments(documents.filter((d) => d.id !== document.id)) }} /> ))}
) } export function DocumentThumbnail({ document, documents, deleteDocument, }: { document: ExpenseFormValues['documents'][number] documents: ExpenseFormValues['documents'] deleteDocument: (document: ExpenseFormValues['documents'][number]) => void }) { const [open, setOpen] = useState(false) const [api, setApi] = useState() const [currentDocument, setCurrentDocument] = useState(null) useEffect(() => { if (!api) return api.on('slidesInView', () => { const index = api.slidesInView()[0] if (index !== undefined) { setCurrentDocument(index) } }) }, [api]) return (
{documents.map((document, index) => ( ))}
) }