--- import DashboardLayout from '../../../layouts/DashboardLayout.astro'; import { Icon } from 'astro-icon/components'; import { db } from '../../../db'; import { invoices, invoiceItems, clients, members, organizations } from '../../../db/schema'; import { eq, and } from 'drizzle-orm'; const { id } = Astro.params; const user = Astro.locals.user; if (!user || !id) { return Astro.redirect('/dashboard/invoices'); } // Fetch invoice with related data const invoiceResult = await db.select({ invoice: invoices, client: clients, organization: organizations, }) .from(invoices) .leftJoin(clients, eq(invoices.clientId, clients.id)) .innerJoin(organizations, eq(invoices.organizationId, organizations.id)) .where(eq(invoices.id, id)) .get(); if (!invoiceResult) { return Astro.redirect('/404'); } const { invoice, client, organization } = invoiceResult; // Verify access const membership = await db.select() .from(members) .where(and( eq(members.userId, user.id), eq(members.organizationId, invoice.organizationId) )) .get(); if (!membership) { return Astro.redirect('/dashboard'); } // Fetch items const items = await db.select() .from(invoiceItems) .where(eq(invoiceItems.invoiceId, invoice.id)) .all(); const formatCurrency = (amount: number) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: invoice.currency, }).format(amount / 100); }; const isDraft = invoice.status === 'draft'; ---
{invoice.status}

{invoice.number}

{isDraft && (
)} {(invoice.status !== 'paid' && invoice.status !== 'void' && invoice.type === 'invoice') && (
)} {(invoice.status !== 'accepted' && invoice.status !== 'declined' && invoice.status !== 'void' && invoice.type === 'quote') && (
)} {(invoice.type === 'quote' && invoice.status === 'accepted') && (
)}

{organization.name}

{(organization.street || organization.city || organization.state || organization.zip || organization.country) && (
{organization.street &&
{organization.street}
} {(organization.city || organization.state || organization.zip) && (
{[organization.city, organization.state, organization.zip].filter(Boolean).join(', ')}
)} {organization.country &&
{organization.country}
}
)}
{invoice.type}
Number:
{invoice.number}
Date:
{invoice.issueDate.toLocaleDateString()}
Due Date:
{invoice.dueDate.toLocaleDateString()}
Bill To
{client ? (
{client.name}
{client.email &&
{client.email}
} {client.phone &&
{client.phone}
} {(client.street || client.city || client.state || client.zip || client.country) && (
{client.street &&
{client.street}
} {(client.city || client.state || client.zip) && (
{[client.city, client.state, client.zip].filter(Boolean).join(', ')}
)} {client.country &&
{client.country}
}
)}
) : (
Client deleted
)}
{isDraft && } {items.map(item => ( {isDraft && ( )} ))} {items.length === 0 && ( )}
Description Qty Price Amount
{item.description} {item.quantity} {formatCurrency(item.unitPrice)} {formatCurrency(item.amount)}
No items added yet.
{isDraft && (

Add Item

)}
Subtotal {formatCurrency(invoice.subtotal)}
{((invoice.taxRate ?? 0) > 0 || isDraft) && (
Tax ({invoice.taxRate ?? 0}%) {isDraft && ( )} {formatCurrency(invoice.taxAmount)}
)}
Total {formatCurrency(invoice.total)}
{invoice.notes && (
Notes
{invoice.notes}
)} {/* Edit Notes (Draft Only) - Simplistic approach */} {isDraft && !invoice.notes && ( )}