feat: manage invoice lifecycle

This commit is contained in:
2026-06-25 11:40:13 +01:00
parent 3373762d97
commit e1e2e94bf2
4 changed files with 426 additions and 13 deletions
@@ -1,6 +1,10 @@
<script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */
import ExternalLinkIcon from '@lucide/svelte/icons/external-link';
import { resolve } from '$app/paths';
import { Badge, type BadgeVariant } from '$lib/components/ui/badge/index.js';
import * as Table from '$lib/components/ui/table/index.js';
import type { PageData } from './$types';
let {
data,
formatValue,
@@ -8,12 +12,19 @@
formatMoney,
relationLabel
}: {
data: any;
formatValue: any;
formatDate: any;
formatMoney: any;
relationLabel: any;
data: Pick<PageData, 'records'>;
formatValue: (value: unknown) => string;
formatDate: (value: unknown) => string;
formatMoney: (value: unknown) => string;
relationLabel: (value: unknown, optionsKey: 'clients') => string;
} = $props();
function statusVariant(status: string): BadgeVariant {
if (status === 'paid') return 'default';
if (status === 'void') return 'destructive';
if (status === 'draft') return 'outline';
return 'secondary';
}
</script>
{#if data.records.length > 0}
@@ -23,6 +34,7 @@
<Table.Row>
<Table.Head>Invoice #</Table.Head>
<Table.Head>Client</Table.Head>
<Table.Head>Status</Table.Head>
<Table.Head>Issued</Table.Head>
<Table.Head>Due</Table.Head>
<Table.Head>Total</Table.Head>
@@ -31,8 +43,19 @@
<Table.Body>
{#each data.records as record (record.id)}
<Table.Row>
<Table.Cell class="font-medium">{formatValue(record.invoiceNumber)}</Table.Cell>
<Table.Cell class="font-medium"
><a
class="inline-flex items-center gap-2 underline-offset-4 hover:text-primary hover:underline"
href={resolve('/dashboard/invoices/[id]', { id: record.id })}
>{formatValue(record.invoiceNumber)}<ExternalLinkIcon class="size-3.5" /></a
></Table.Cell
>
<Table.Cell class="">{relationLabel(record.clientId, 'clients')}</Table.Cell>
<Table.Cell
><Badge variant={statusVariant(record.status)} class="capitalize"
>{formatValue(record.status)}</Badge
></Table.Cell
>
<Table.Cell class="">{formatDate(record.issueDate)}</Table.Cell>
<Table.Cell class="">{formatDate(record.dueDate)}</Table.Cell>
<Table.Cell class="">{formatMoney(record.totalGbp)}</Table.Cell>