Complete frontend implementation with: - Next.js 16 with App Router and TypeScript - Tailwind CSS v4 with custom violet theme - shadcn/ui components with Lucide React icons - Landing page with hero, services, pricing, testimonials, FAQ - Service selection page with toggle - Login/Register pages with social auth UI - Multi-step checkout flow - Client dashboard with stats, projects, support tickets - Billing page with subscription, payment methods, invoices - All mock data and TypeScript types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
'use client'
|
|
|
|
import { Download } from 'lucide-react'
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
import { Badge } from '@/components/ui/badge'
|
|
import { Button } from '@/components/ui/button'
|
|
import type { Invoice } from '@/lib/types'
|
|
|
|
interface InvoiceTableProps {
|
|
invoices: Invoice[]
|
|
}
|
|
|
|
const statusColors: Record<Invoice['status'], string> = {
|
|
paid: 'bg-emerald-500/10 text-emerald-400',
|
|
pending: 'bg-yellow-500/10 text-yellow-400',
|
|
refunded: 'bg-red-500/10 text-red-400',
|
|
cancelled: 'bg-gray-500/10 text-gray-400',
|
|
}
|
|
|
|
export function InvoiceTable({ invoices }: InvoiceTableProps) {
|
|
return (
|
|
<Card className="bg-card border-border">
|
|
<CardHeader>
|
|
<CardTitle>Invoice History</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full">
|
|
<thead>
|
|
<tr className="border-b border-border">
|
|
<th className="text-left py-3 px-4 text-sm font-semibold text-foreground">
|
|
Description
|
|
</th>
|
|
<th className="text-left py-3 px-4 text-sm font-semibold text-foreground">
|
|
Date
|
|
</th>
|
|
<th className="text-left py-3 px-4 text-sm font-semibold text-foreground">
|
|
Amount
|
|
</th>
|
|
<th className="text-left py-3 px-4 text-sm font-semibold text-foreground">
|
|
Status
|
|
</th>
|
|
<th className="text-right py-3 px-4 text-sm font-semibold text-foreground">
|
|
Download
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{invoices.map((invoice) => (
|
|
<tr key={invoice.id} className="border-b border-border hover:bg-white/5">
|
|
<td className="py-4 px-4">
|
|
<p className="font-medium text-foreground">{invoice.description}</p>
|
|
{invoice.projectId && (
|
|
<p className="text-xs text-muted-foreground mt-1">
|
|
Project: {invoice.projectId}
|
|
</p>
|
|
)}
|
|
</td>
|
|
<td className="py-4 px-4 text-sm text-muted-foreground">
|
|
{new Date(invoice.date).toLocaleDateString()}
|
|
</td>
|
|
<td className="py-4 px-4">
|
|
<p className="font-semibold text-foreground">
|
|
{invoice.total} {invoice.currency}
|
|
</p>
|
|
</td>
|
|
<td className="py-4 px-4">
|
|
<Badge className={statusColors[invoice.status]}>
|
|
{invoice.status}
|
|
</Badge>
|
|
</td>
|
|
<td className="py-4 px-4 text-right">
|
|
{invoice.downloadUrl && (
|
|
<Button variant="ghost" size="sm" asChild>
|
|
<a href={invoice.downloadUrl} download>
|
|
<Download className="w-4 h-4" />
|
|
</a>
|
|
</Button>
|
|
)}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|