This commit establishes the new monorepo architecture for the KROW Workforce platform. Key changes include: - Reorganized project into `frontend-web`, `mobile-apps`, `firebase`, `scripts`, and `secrets` directories. - Updated `Makefile` to support the new monorepo layout and automate Base44 export integration. - Fixed `scripts/prepare-export.js` for ES module compatibility and global component import resolution. - Created and updated `CONTRIBUTING.md` for developer onboarding. - Restructured, renamed, and translated all `docs/` files for clarity and consistency. - Implemented an interactive internal launchpad with diagram viewing capabilities. - Configured base Firebase project files (`firebase.json`, security rules). - Updated `README.md` to reflect the new project structure and documentation overview.
114 lines
5.1 KiB
JavaScript
114 lines
5.1 KiB
JavaScript
import React from "react";
|
|
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { FileText, Download, DollarSign, TrendingUp, Calendar, CheckCircle2 } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
export default function VendorInvoices() {
|
|
const invoices = [
|
|
{ id: "INV-V001", client: "Tech Corp", amount: 12400, status: "Paid", date: "2025-01-10", services: "Event Staffing - 12 staff x 8 hours" },
|
|
{ id: "INV-V002", client: "Premier Events", amount: 8950, status: "Pending", date: "2025-01-15", services: "Catering Staff - 8 staff x 6 hours" },
|
|
{ id: "INV-V003", client: "Corporate Solutions", amount: 15200, status: "Sent", date: "2025-01-18", services: "Full Service - 20 staff x 10 hours" },
|
|
];
|
|
|
|
const stats = {
|
|
totalRevenue: invoices.reduce((sum, inv) => sum + inv.amount, 0),
|
|
paid: invoices.filter(i => i.status === "Paid").reduce((sum, i) => sum + i.amount, 0),
|
|
pending: invoices.filter(i => i.status === "Pending" || i.status === "Sent").reduce((sum, i) => sum + i.amount, 0),
|
|
count: invoices.length,
|
|
};
|
|
|
|
const getStatusColor = (status) => {
|
|
const colors = {
|
|
'Paid': 'bg-green-100 text-green-700',
|
|
'Pending': 'bg-yellow-100 text-yellow-700',
|
|
'Sent': 'bg-blue-100 text-blue-700',
|
|
'Overdue': 'bg-red-100 text-red-700',
|
|
};
|
|
return colors[status] || 'bg-slate-100 text-slate-700';
|
|
};
|
|
|
|
return (
|
|
<div className="p-4 md:p-8 bg-slate-50 min-h-screen">
|
|
<div className="max-w-7xl mx-auto">
|
|
<div className="mb-6">
|
|
<h1 className="text-3xl font-bold text-[#1C323E]">Invoices</h1>
|
|
<p className="text-slate-500 mt-1">Track your billing and payments</p>
|
|
</div>
|
|
|
|
{/* Stats */}
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
|
<Card className="border-slate-200">
|
|
<CardContent className="p-6">
|
|
<DollarSign className="w-8 h-8 text-[#0A39DF] mb-2" />
|
|
<p className="text-sm text-slate-500">Total Revenue</p>
|
|
<p className="text-3xl font-bold text-[#1C323E]">${stats.totalRevenue.toLocaleString()}</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="border-slate-200">
|
|
<CardContent className="p-6">
|
|
<CheckCircle2 className="w-8 h-8 text-green-600 mb-2" />
|
|
<p className="text-sm text-slate-500">Paid</p>
|
|
<p className="text-3xl font-bold text-green-600">${stats.paid.toLocaleString()}</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="border-slate-200">
|
|
<CardContent className="p-6">
|
|
<TrendingUp className="w-8 h-8 text-yellow-600 mb-2" />
|
|
<p className="text-sm text-slate-500">Pending</p>
|
|
<p className="text-3xl font-bold text-yellow-600">${stats.pending.toLocaleString()}</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="border-slate-200">
|
|
<CardContent className="p-6">
|
|
<FileText className="w-8 h-8 text-blue-600 mb-2" />
|
|
<p className="text-sm text-slate-500">Total Invoices</p>
|
|
<p className="text-3xl font-bold text-blue-600">{stats.count}</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Invoices List */}
|
|
<Card className="border-slate-200">
|
|
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b">
|
|
<CardTitle>All Invoices</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="p-6">
|
|
<div className="space-y-4">
|
|
{invoices.map((invoice) => (
|
|
<div key={invoice.id} className="p-6 bg-white border-2 border-slate-200 rounded-xl hover:border-[#0A39DF] transition-all">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<h3 className="text-lg font-bold text-[#1C323E]">{invoice.id}</h3>
|
|
<Badge className={getStatusColor(invoice.status)}>
|
|
{invoice.status}
|
|
</Badge>
|
|
</div>
|
|
<p className="text-sm font-semibold text-slate-700">{invoice.client}</p>
|
|
<p className="text-sm text-slate-500 mt-1">{invoice.services}</p>
|
|
<div className="flex items-center gap-2 mt-2 text-xs text-slate-500">
|
|
<Calendar className="w-3 h-3" />
|
|
{invoice.date}
|
|
</div>
|
|
</div>
|
|
<div className="text-right">
|
|
<p className="text-3xl font-bold text-[#0A39DF] mb-3">${invoice.amount.toLocaleString()}</p>
|
|
<Button variant="outline" size="sm">
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Download
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |