From 6bed4b4709487b4b535cd278541df56f79dab75a Mon Sep 17 00:00:00 2001 From: Atridad Lahiji Date: Tue, 20 Jan 2026 01:06:06 -0700 Subject: [PATCH] Last fix for the night... --- src/pages/dashboard/invoices/index.astro | 150 +++++++++++++++++++++-- 1 file changed, 141 insertions(+), 9 deletions(-) diff --git a/src/pages/dashboard/invoices/index.astro b/src/pages/dashboard/invoices/index.astro index ccffc33..077aae0 100644 --- a/src/pages/dashboard/invoices/index.astro +++ b/src/pages/dashboard/invoices/index.astro @@ -3,7 +3,7 @@ import DashboardLayout from '../../../layouts/DashboardLayout.astro'; import { Icon } from 'astro-icon/components'; import { db } from '../../../db'; import { invoices, clients, members } from '../../../db/schema'; -import { eq, desc, and } from 'drizzle-orm'; +import { eq, desc, and, gte, lte, sql } from 'drizzle-orm'; const user = Astro.locals.user; if (!user) return Astro.redirect('/login'); @@ -25,17 +25,71 @@ const userMembership = currentTeamId const currentTeamIdResolved = userMembership.organizationId; -// Fetch invoices and quotes -const allInvoices = await db.select({ +// Get filter parameters +const currentYear = new Date().getFullYear(); +const selectedYear = Astro.url.searchParams.get('year') ? parseInt(Astro.url.searchParams.get('year')!) : currentYear; +const selectedType = Astro.url.searchParams.get('type') || 'all'; +const selectedStatus = Astro.url.searchParams.get('status') || 'all'; +const sortBy = Astro.url.searchParams.get('sort') || 'date-desc'; + +// Fetch all invoices for the organization (for year dropdown) +const allInvoicesRaw = await db.select({ invoice: invoices, client: clients, }) .from(invoices) .leftJoin(clients, eq(invoices.clientId, clients.id)) .where(eq(invoices.organizationId, currentTeamIdResolved)) - .orderBy(desc(invoices.issueDate)) .all(); +// Get unique years from invoices +const availableYears = [...new Set(allInvoicesRaw.map(i => i.invoice.issueDate.getFullYear()))].sort((a, b) => b - a); + +// Filter by year +const yearStart = new Date(selectedYear, 0, 1); +const yearEnd = new Date(selectedYear, 11, 31, 23, 59, 59); + +let filteredInvoices = allInvoicesRaw.filter(i => { + const issueDate = i.invoice.issueDate; + return issueDate >= yearStart && issueDate <= yearEnd; +}); + +// Filter by type +if (selectedType !== 'all') { + filteredInvoices = filteredInvoices.filter(i => i.invoice.type === selectedType); +} + +// Filter by status +if (selectedStatus !== 'all') { + filteredInvoices = filteredInvoices.filter(i => i.invoice.status === selectedStatus); +} + +// Sort invoices +const allInvoices = filteredInvoices.sort((a, b) => { + switch (sortBy) { + case 'date-desc': + return b.invoice.issueDate.getTime() - a.invoice.issueDate.getTime(); + case 'date-asc': + return a.invoice.issueDate.getTime() - b.invoice.issueDate.getTime(); + case 'amount-desc': + return b.invoice.total - a.invoice.total; + case 'amount-asc': + return a.invoice.total - b.invoice.total; + case 'number-desc': + return b.invoice.number.localeCompare(a.invoice.number); + case 'number-asc': + return a.invoice.number.localeCompare(b.invoice.number); + default: + return b.invoice.issueDate.getTime() - a.invoice.issueDate.getTime(); + } +}); + +// Calculate stats for the selected year +const yearInvoices = allInvoicesRaw.filter(i => { + const issueDate = i.invoice.issueDate; + return issueDate >= yearStart && issueDate <= yearEnd; +}); + const formatCurrency = (amount: number, currency: string) => { return new Intl.NumberFormat('en-US', { style: 'currency', @@ -75,8 +129,8 @@ const getStatusColor = (status: string) => {
Total Invoices
-
{allInvoices.filter(i => i.invoice.type === 'invoice').length}
-
All time
+
{yearInvoices.filter(i => i.invoice.type === 'invoice').length}
+
{selectedYear}
@@ -86,7 +140,7 @@ const getStatusColor = (status: string) => {
Open Quotes
-
{allInvoices.filter(i => i.invoice.type === 'quote' && i.invoice.status === 'sent').length}
+
{yearInvoices.filter(i => i.invoice.type === 'quote' && i.invoice.status === 'sent').length}
Waiting for approval
@@ -98,17 +152,95 @@ const getStatusColor = (status: string) => {
Total Revenue
- {formatCurrency(allInvoices + {formatCurrency(yearInvoices .filter(i => i.invoice.type === 'invoice' && i.invoice.status === 'paid') .reduce((acc, curr) => acc + curr.invoice.total, 0), 'USD')}
-
Paid invoices
+
Paid invoices ({selectedYear})
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + {(selectedYear !== currentYear || selectedType !== 'all' || selectedStatus !== 'all' || sortBy !== 'date-desc') && ( + + )} +
+
+
+
+

+ Showing {allInvoices.length} + {allInvoices.length === 1 ? 'result' : 'results'} + {selectedYear && ` for ${selectedYear}`} +

+