InvoiceManagement.tsx
Golden-Hour-backend-layer-2/pages/InvoiceManagement.tsx
import React, { useState, useRef } from 'react';
type InvoiceType = 'Company Invoices' | 'Customer Invoices' | 'Supplier Invoices' | 'Procurement Invoices' | 'Settings';
interface InvoiceRecord {
id: string;
entity: string;
amount: string;
date: string;
status: 'Paid' | 'Overdue' | 'Draft';
type: InvoiceType;
}
interface InvoiceManagementProps {
view?: InvoiceType;
}
const ScanModal: React.FC<{ isOpen: boolean; onClose: () => void }> = ({ isOpen, onClose }) => {
const [isScanning, setIsScanning] = useState(false);
const [scanProgress, setScanProgress] = useState(0);
const fileInputRef = useRef<HTMLInputElement>(null);
if (!isOpen) return null;
const handleFileSelect = () => {
setIsScanning(true);
let progress = 0;
const interval = setInterval(() => {
progress += 5;
setScanProgress(progress);
if (progress >= 100) {
clearInterval(interval);
setTimeout(() => {
setIsScanning(false);
setScanProgress(0);
onClose();
}, 1000);
}
}, 100);
};
return (
<div className="fixed inset-0 z-[100] flex items-center justify-center p-8 bg-slate-900/60 backdrop-blur-xl fade-in-section">
<div className="bg-white rounded-[3.5rem] gallery-shadow w-full max-w-xl border border-[#c5a059]/20 flex flex-col relative overflow-hidden">
<div className="absolute top-0 left-0 right-0 h-1.5 bg-[#c5a059]"></div>
<div className="p-16 text-center space-y-10">
<div className="mx-auto w-20 h-20 rounded-full border border-[#c5a059]/10 flex items-center justify-center relative">
<i className={`fa-solid ${isScanning ? 'fa-fingerprint animate-pulse text-[#c5a059]' : 'fa-file-invoice text-slate-200'} text-3xl`}></i>
</div>
<div>
<h3 className="font-serif italic text-4xl text-slate-900">Archive Scan Protocol</h3>
<p className="text-[9px] font-bold uppercase tracking-[0.4em] text-slate-400 mt-3">Registering Physical Assets to Ledger</p>
</div>
<div className="relative">
{isScanning ? (
<div className="space-y-6">
<div className="h-1 w-full bg-slate-100 rounded-full overflow-hidden relative">
<div className="absolute top-0 bottom-0 left-0 bg-[#c5a059] transition-all duration-300" style={{ width: `${scanProgress}%` }}></div>
</div>
<p className="text-[8px] font-black uppercase tracking-[0.3em] text-[#c5a059] animate-pulse italic font-serif">Harvesting OCR Data Points — {scanProgress}%</p>
</div>
) : (
<div
onClick={() => fileInputRef.current?.click()}
className="p-12 rounded-[2.5rem] bg-[#fdfcf9] border-2 border-dashed border-[#c5a059]/10 hover:border-[#c5a059]/40 transition-all cursor-pointer group"
>
<i className="fa-solid fa-cloud-arrow-up text-3xl text-slate-200 mb-6 group-hover:text-[#c5a059] transition-colors"></i>
<p className="text-[10px] font-bold uppercase tracking-[0.3em] text-slate-400">Upload or Capture Ledger Image</p>
<p className="text-[8px] font-serif italic text-slate-300 mt-3">Photographs, Scans, or Documents (PDF, JPG)</p>
<input ref={fileInputRef} type="file" className="hidden" onChange={handleFileSelect} />
</div>
)}
</div>
<div className="grid grid-cols-2 gap-4">
<button onClick={onClose} className="px-8 py-4 rounded-full text-[9px] font-black uppercase tracking-[0.3em] text-slate-300 hover:text-slate-900 transition-all">Abort Protocol</button>
<button disabled={isScanning} className="bg-black text-white px-8 py-4 rounded-full text-[9px] font-black uppercase tracking-[0.3em] hover:bg-[#c5a059] transition-all disabled:opacity-20">Manual Registry</button>
</div>
</div>
</div>
</div>
);
};
const InvoiceManagement: React.FC<InvoiceManagementProps> = ({ view = 'Customer Invoices' }) => {
const [isScanOpen, setIsScanOpen] = useState(false);
const invoices: InvoiceRecord[] = [
{ id: 'INV-GH-401', entity: 'Private Client: James Bond', amount: '€4,200', date: '2025-05-12', status: 'Paid', type: 'Customer Invoices' },
{ id: 'INV-GH-402', entity: 'EcoClean Provence Co.', amount: '€1,150', date: '2025-05-14', status: 'Overdue', type: 'Supplier Invoices' },
{ id: 'INV-GH-403', entity: 'Atelier Office Supplies', amount: '€450', date: '2025-05-15', status: 'Draft', type: 'Procurement Invoices' },
{ id: 'INV-GH-404', entity: 'Internal: Marketing Dept', amount: '€2,400', date: '2025-05-10', status: 'Paid', type: 'Company Invoices' },
];
const filteredInvoices = invoices.filter(inv => inv.type === view);
const viewMetadata: Record<InvoiceType, { title: string; sub: string }> = {
'Company Invoices': { title: 'Corporate Ledger', sub: 'Internal Asset & Expense Registry' },
'Customer Invoices': { title: 'Acquisition Archive', sub: 'Client Transactional Records' },
'Supplier Invoices': { title: 'Supply Chain Ledger', sub: 'Provisioning & Logistics Billing' },
'Procurement Invoices': { title: 'Procurement Dossier', sub: 'Atelier Acquisitions & Inventory' },
'Settings': { title: 'Fiscal Configuration', sub: 'Taxation & Registry Standards' }
};
const renderInvoiceTable = () => (
<div className="bg-white rounded-[2.5rem] border border-[#c5a059]/10 shadow-sm overflow-hidden fade-in-section">
<div className="overflow-x-auto">
<table className="w-full text-left">
<thead className="bg-[#fdfcf9] border-b border-[#c5a059]/5 text-[7px] font-bold uppercase tracking-widest text-slate-300 italic font-serif">
<tr>
<th className="px-10 py-6">Ref. Registry ID</th>
<th className="px-10 py-6">Identity / Entity</th>
<th className="px-10 py-6">Fiscal Value</th>
<th className="px-10 py-6">Date d'édition</th>
<th className="px-10 py-6">Current State</th>
<th className="px-10 py-6 text-center">Protocol</th>
</tr>
</thead>
<tbody className="divide-y divide-[#c5a059]/5">
{filteredInvoices.length > 0 ? filteredInvoices.map((inv) => (
<tr key={inv.id} className="hover:bg-[#fdfcf9]/50 group transition-all duration-700">
<td className="px-10 py-8 serif-numeral text-sm text-[#c5a059]">{inv.id}</td>
<td className="px-10 py-8">
<p className="font-serif italic text-lg text-slate-800 leading-tight">{inv.entity}</p>
</td>
<td className="px-10 py-8 font-serif italic text-xl text-slate-900 tracking-tighter">{inv.amount}</td>
<td className="px-10 py-8 text-[9px] font-bold uppercase tracking-widest text-slate-400 font-serif italic">{inv.date}</td>
<td className="px-10 py-8">
<span className={`text-[7px] font-black uppercase px-3 py-1 rounded-full border tracking-widest ${
inv.status === 'Paid' ? 'border-emerald-100 text-emerald-600 bg-emerald-50/5' :
inv.status === 'Overdue' ? 'border-rose-100 text-rose-600 bg-rose-50/5' : 'border-slate-100 text-slate-400'
}`}>
{inv.status}
</span>
</td>
<td className="px-10 py-8">
<div className="flex justify-center space-x-6 opacity-0 group-hover:opacity-100 transition-all duration-700">
<button className="text-slate-200 hover:text-[#c5a059] transition-all"><i className="fa-solid fa-eye text-xs"></i></button>
<button className="text-slate-200 hover:text-[#c5a059] transition-all"><i className="fa-solid fa-download text-xs"></i></button>
<button className="text-slate-200 hover:text-rose-600 transition-all"><i className="fa-solid fa-ellipsis-vertical text-xs"></i></button>
</div>
</td>
</tr>
)) : (
<tr>
<td colSpan={6} className="px-10 py-32 text-center text-slate-200 font-serif italic text-2xl opacity-40">
No records found in this category archive.
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
const renderSettingsView = () => (
<div className="grid grid-cols-1 md:grid-cols-2 gap-10 fade-in-section">
<div className="bg-white p-12 rounded-[2.5rem] border border-[#c5a059]/10 gallery-shadow">
<h3 className="font-serif italic text-3xl text-slate-900 mb-8">Statutory Logic</h3>
<div className="space-y-6">
<div className="p-6 rounded-2xl bg-[#fdfcf9] border border-[#c5a059]/5 flex justify-between items-center">
<div>
<p className="text-[10px] font-black uppercase tracking-widest text-slate-800">Standard VAT Protocol</p>
<p className="text-[8px] font-serif italic text-slate-400 mt-1">Applied to all customer transactions: 21%</p>
</div>
<button className="text-[8px] font-black text-[#c5a059] uppercase tracking-widest border border-[#c5a059]/10 px-4 py-2 rounded-full">Adjust</button>
</div>
<div className="p-6 rounded-2xl bg-[#fdfcf9] border border-[#c5a059]/5 flex justify-between items-center">
<div>
<p className="text-[10px] font-black uppercase tracking-widest text-slate-800">Currency Formatting</p>
<p className="text-[8px] font-serif italic text-slate-400 mt-1">EUR (€) - Postfix format</p>
</div>
<button className="text-[8px] font-black text-[#c5a059] uppercase tracking-widest border border-[#c5a059]/10 px-4 py-2 rounded-full">Change</button>
</div>
</div>
</div>
<div className="bg-[#1a1a1a] p-12 rounded-[2.5rem] gallery-shadow text-white relative overflow-hidden">
<div className="absolute top-0 right-0 w-32 h-32 bg-[#c5a059]/10 rounded-full blur-3xl -mr-16 -mt-16"></div>
<h3 className="font-serif italic text-3xl mb-8 relative z-10">Export Protocol</h3>
<p className="text-slate-400 text-sm italic font-serif leading-relaxed mb-10 relative z-10">
Configure the automated delivery of financial ledgers to your accounting bureau.
Supported formats: CSV, XML, PDF.
</p>
<button className="w-full py-5 bg-white text-black rounded-full text-[9px] font-black uppercase tracking-[0.4em] hover:bg-[#c5a059] hover:text-white transition-all">Setup Scheduled Export</button>
</div>
</div>
);
return (
<div className="relative pb-32">
<div className="space-y-16 fade-in-section">
{/* Dynamic Header */}
<div className="flex flex-col md:flex-row md:items-end justify-between border-b border-[#c5a059]/10 pb-12 gap-8">
<div>
<h2 className="text-4xl font-serif italic text-slate-900 tracking-tight">
{viewMetadata[view].title}
</h2>
<p className="text-[10px] font-black uppercase tracking-[0.5em] text-[#c5a059] mt-3 font-serif italic">
{viewMetadata[view].sub}
</p>
</div>
<div className="flex items-center space-x-6">
<button
onClick={() => setIsScanOpen(true)}
className="bg-[#fdfcf9] border border-[#c5a059]/20 text-[#c5a059] px-10 py-3.5 rounded-full text-[9px] font-black uppercase tracking-[0.3em] hover:bg-[#c5a059] hover:text-white transition-all shadow-xl hover:scale-105 active:scale-95 flex items-center"
>
<i className="fa-solid fa-maximize mr-4"></i> Register via Scan
</button>
<button className="bg-black text-white px-10 py-3.5 rounded-full text-[9px] font-black uppercase tracking-[0.3em] hover:bg-[#c5a059] transition-all shadow-xl">
<i className="fa-solid fa-plus mr-3"></i> Manual Registry
</button>
</div>
</div>
{/* Financial Analytics Summary */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-10">
{[
{ label: 'Cumulative Outstanding', value: '€12,450', sub: '08 Ledgers pending', color: 'text-slate-900' },
{ label: 'Secured This Cycle', value: '€84,200', sub: '142 Transactions verified', color: 'text-[#c5a059]' },
{ label: 'Total Overdue', value: '€1,150', sub: 'High Priority Protocol', color: 'text-rose-600' },
].map((stat, idx) => (
<div key={idx} className="bg-white p-10 rounded-[2.5rem] border border-[#c5a059]/10 gallery-shadow">
<span className="text-[8px] font-black uppercase tracking-[0.3em] text-slate-300 block mb-3">{stat.label}</span>
<h3 className={`font-serif italic text-4xl leading-none tracking-tighter ${stat.color}`}>{stat.value}</h3>
<p className="text-[8px] font-serif italic text-slate-400 mt-4 uppercase tracking-widest">{stat.sub}</p>
</div>
))}
</div>
{view === 'Settings' ? renderSettingsView() : renderInvoiceTable()}
</div>
<ScanModal isOpen={isScanOpen} onClose={() => setIsScanOpen(false)} />
{/* Persistent Protocol Bar */}
<div className="fixed bottom-12 left-1/2 -translate-x-1/2 bg-white/90 backdrop-blur-md border border-[#c5a059]/20 px-10 py-5 rounded-full gallery-shadow flex items-center space-x-12 z-50 transition-all hover:border-[#c5a059]/40 group">
<button className="flex items-center space-x-3 text-slate-400 hover:text-slate-900 transition-all">
<i className="fa-solid fa-print text-[9px] text-[#c5a059]"></i>
<span className="text-[8px] font-bold uppercase tracking-[0.3em]">Batch Print</span>
</button>
<div className="w-[0.5px] h-4 bg-[#c5a059]/20"></div>
<button className="flex items-center space-x-3 text-slate-400 hover:text-slate-900 transition-all">
<i className="fa-solid fa-magnifying-glass text-[9px] text-[#c5a059]"></i>
<span className="text-[8px] font-bold uppercase tracking-[0.3em]">Audit Query</span>
</button>
</div>
</div>
);
};
export default InvoiceManagement;
Articles liés
App.tsx
App.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/App.tsx).
Lire l'article →Header.tsx
Header.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/components/Header.tsx).
Lire l'article →Sidebar.tsx
Sidebar.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/components/Sidebar.tsx).
Lire l'article →index.tsx
index.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/index.tsx).
Lire l'article →ContentManagement.tsx
ContentManagement.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/pages/ContentManagement.tsx).
Lire l'article →CustomerManagement.tsx
CustomerManagement.tsx — typescript source code from the Golden-Hour-backend-layer-2 learning materials (Golden-Hour-backend-layer-2/pages/CustomerManagement.tsx).
Lire l'article →