diff --git a/app/(dashboard)/invoices/[id]/page.tsx b/app/(dashboard)/invoices/[id]/page.tsx index 700ed5b8..12732b22 100644 --- a/app/(dashboard)/invoices/[id]/page.tsx +++ b/app/(dashboard)/invoices/[id]/page.tsx @@ -32,6 +32,14 @@ import { Trash2, } from 'lucide-react' import PaymentBookingDialog from '@/components/invoices/PaymentBookingDialog' +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' import type { Invoice, InvoiceItem, Customer, InvoiceStatus, InvoiceReminder, InvoiceDocumentType } from '@/types' const statusConfig: Record = { @@ -72,6 +80,8 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st const [isUpdating, setIsUpdating] = useState(false) const [isDownloading, setIsDownloading] = useState(false) const [isSendingEmail, setIsSendingEmail] = useState(false) + const [showDeleteDialog, setShowDeleteDialog] = useState(false) + const [isDeleting, setIsDeleting] = useState(false) useEffect(() => { fetchInvoice() @@ -326,6 +336,39 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st setIsDownloading(false) } + async function deleteInvoice() { + if (!invoice) return + + setIsDeleting(true) + + try { + const response = await fetch(`/api/invoices/${invoice.id}`, { + method: 'DELETE', + }) + + if (!response.ok) { + const data = await response.json() + throw new Error(data.error || 'Kunde inte ta bort fakturan') + } + + toast({ + title: 'Faktura borttagen', + description: `Utkast ${invoice.invoice_number} har tagits bort`, + }) + + router.push('/invoices') + } catch (error) { + toast({ + title: 'Kunde inte ta bort fakturan', + description: error instanceof Error ? error.message : 'Försök igen.', + variant: 'destructive', + }) + } + + setIsDeleting(false) + setShowDeleteDialog(false) + } + if (isLoading) { return (
@@ -885,8 +928,8 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st
+ {/* Delete confirmation dialog */} + + + + Ta bort fakturautkast + + Är du säker på att du vill ta bort utkast {invoice.invoice_number}? Detta kan inte ångras. + + + + + + + + + } +) { + const { id } = await params + const supabase = await createClient() + + const { data: { user } } = await supabase.auth.getUser() + + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + + // Fetch invoice to verify ownership and status + const { data: invoice, error: fetchError } = await supabase + .from('invoices') + .select('id, status, user_id') + .eq('id', id) + .eq('user_id', user.id) + .single() + + if (fetchError || !invoice) { + return NextResponse.json({ error: 'Invoice not found' }, { status: 404 }) + } + + if (invoice.status !== 'draft') { + return NextResponse.json( + { error: 'Endast utkast kan tas bort. Bokförda fakturor måste krediteras istället.' }, + { status: 400 } + ) + } + + // Delete items first (FK constraint), then the invoice + const { error: itemsError } = await supabase + .from('invoice_items') + .delete() + .eq('invoice_id', id) + + if (itemsError) { + return NextResponse.json({ error: itemsError.message }, { status: 500 }) + } + + const { error: deleteError } = await supabase + .from('invoices') + .delete() + .eq('id', id) + .eq('user_id', user.id) + + if (deleteError) { + return NextResponse.json({ error: deleteError.message }, { status: 500 }) + } + + return NextResponse.json({ data: { deleted: true } }) +} diff --git a/app/globals.css b/app/globals.css index d3771a0a..47b38e34 100644 --- a/app/globals.css +++ b/app/globals.css @@ -105,7 +105,7 @@ --success-foreground: 0 0% 100%; --warning: 38 50% 55%; - --warning-foreground: 0 0% 9%; + --warning-foreground: 38 50% 90%; --warm-accent: 38 42% 58%;