'use client' import { CategoryIcon } from '@/app/groups/[groupId]/expenses/category-icon' import { ReceiptExtractedInfo, extractExpenseInformationFromImage, } from '@/app/groups/[groupId]/expenses/create-from-receipt-button-actions' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog' import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle, DrawerTrigger, } from '@/components/ui/drawer' import { ToastAction } from '@/components/ui/toast' import { useToast } from '@/components/ui/use-toast' import { useMediaQuery } from '@/lib/hooks' import { formatCurrency, formatExpenseDate } from '@/lib/utils' import { Category } from '@prisma/client' import { ChevronRight, FileQuestion, Loader2, Receipt } from 'lucide-react' import { getImageData, usePresignedUpload } from 'next-s3-upload' import Image from 'next/image' import { useRouter } from 'next/navigation' import { PropsWithChildren, ReactNode, useState } from 'react' type Props = { groupId: string groupCurrency: string categories: Category[] } export function CreateFromReceiptButton({ groupId, groupCurrency, categories, }: Props) { const [pending, setPending] = useState(false) const { uploadToS3, FileInput, openFileDialog } = usePresignedUpload() const { toast } = useToast() const router = useRouter() const [receiptInfo, setReceiptInfo] = useState< | null | (ReceiptExtractedInfo & { url: string; width?: number; height?: number }) >(null) const isDesktop = useMediaQuery('(min-width: 640px)') const handleFileChange = async (file: File) => { const upload = async () => { try { setPending(true) console.log('Uploading image…') let { url } = await uploadToS3(file) console.log('Extracting information from receipt…') const { amount, categoryId, date, title } = await extractExpenseInformationFromImage(url) const { width, height } = await getImageData(file) setReceiptInfo({ amount, categoryId, date, title, url, width, height }) } catch (err) { console.error(err) toast({ title: 'Error while uploading document', description: 'Something wrong happened when uploading the document. Please retry later or select a different file.', variant: 'destructive', action: ( upload()}> Retry ), }) } finally { setPending(false) } } upload() } const receiptInfoCategory = (receiptInfo?.categoryId && categories.find((c) => String(c.id) === receiptInfo.categoryId)) || null const DialogOrDrawer = isDesktop ? CreateFromReceiptDialog : CreateFromReceiptDrawer return ( } title={ <> Create from receipt Beta } description={<>Extract the expense information from a receipt photo.} >

Upload the photo of a receipt, and we’ll scan it to extract the expense information if we can.

Title:
{receiptInfo ? receiptInfo.title ?? : '…'}
Category:
{receiptInfo ? ( receiptInfoCategory ? (
{receiptInfoCategory.grouping} {receiptInfoCategory.name}
) : ( ) ) : ( '' || '…' )}
Amount:
{receiptInfo ? ( receiptInfo.amount ? ( <>{formatCurrency(groupCurrency, receiptInfo.amount)} ) : ( ) ) : ( '…' )}
Date:
{receiptInfo ? ( receiptInfo.date ? ( formatExpenseDate( new Date(`${receiptInfo?.date}T12:00:00.000Z`), ) ) : ( ) ) : ( '…' )}

You’ll be able to edit the expense information next.

) } function Unknown() { return (
Unknown
) } function CreateFromReceiptDialog({ trigger, title, description, children, }: PropsWithChildren<{ trigger: ReactNode title: ReactNode description: ReactNode }>) { return ( {trigger} {title} {description} {children} ) } function CreateFromReceiptDrawer({ trigger, title, description, children, }: PropsWithChildren<{ trigger: ReactNode title: ReactNode description: ReactNode }>) { return ( {trigger} {title} {description}
{children}
) }