unzip frontend

This commit is contained in:
2025-08-16 14:41:12 +02:00
parent b60af66732
commit 598774bca6
87 changed files with 9676 additions and 0 deletions
@@ -0,0 +1,272 @@
"use client"
import { useState } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Input } from "@/components/ui/input"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Search, ArrowUpRight, ArrowDownLeft, Calendar } from "lucide-react"
interface Transaction {
id: string
date: string
type: "receivable" | "payable" | "payment_received" | "payment_made"
entity: string
description: string
amount: number
status: "pending" | "completed" | "overdue"
reference?: string
}
// Mock transaction data
const mockTransactions: Transaction[] = [
{
id: "1",
date: "2024-01-15",
type: "receivable",
entity: "ABC Electronics",
description: "Invoice #INV-001 - Wireless Headphones",
amount: 2500,
status: "completed",
reference: "INV-001",
},
{
id: "2",
date: "2024-01-14",
type: "payment_received",
entity: "Tech Solutions Inc",
description: "Payment received for Invoice #INV-002",
amount: 1800,
status: "completed",
reference: "PAY-001",
},
{
id: "3",
date: "2024-01-13",
type: "payable",
entity: "Electronics Wholesale Co",
description: "Purchase Order #PO-001 - Components",
amount: 3200,
status: "pending",
reference: "PO-001",
},
{
id: "4",
date: "2024-01-12",
type: "payment_made",
entity: "Global Tech Supplies",
description: "Payment for Invoice #SUP-001",
amount: 1500,
status: "completed",
reference: "PAY-002",
},
{
id: "5",
date: "2024-01-11",
type: "receivable",
entity: "Mobile World",
description: "Invoice #INV-003 - Phone Cases",
amount: 950,
status: "overdue",
reference: "INV-003",
},
{
id: "6",
date: "2024-01-10",
type: "payable",
entity: "Premium Components Ltd",
description: "Purchase Order #PO-002 - Premium Parts",
amount: 4500,
status: "pending",
reference: "PO-002",
},
]
export function TransactionHistory() {
const [searchTerm, setSearchTerm] = useState("")
const [typeFilter, setTypeFilter] = useState<string>("all")
const [statusFilter, setStatusFilter] = useState<string>("all")
const filteredTransactions = mockTransactions.filter((transaction) => {
const matchesSearch =
transaction.entity.toLowerCase().includes(searchTerm.toLowerCase()) ||
transaction.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
(transaction.reference && transaction.reference.toLowerCase().includes(searchTerm.toLowerCase()))
const matchesType = typeFilter === "all" || transaction.type === typeFilter
const matchesStatus = statusFilter === "all" || transaction.status === statusFilter
return matchesSearch && matchesType && matchesStatus
})
const getTransactionIcon = (type: string) => {
switch (type) {
case "receivable":
case "payment_received":
return <ArrowUpRight className="h-4 w-4 text-green-600" />
case "payable":
case "payment_made":
return <ArrowDownLeft className="h-4 w-4 text-red-600" />
default:
return <Calendar className="h-4 w-4 text-muted-foreground" />
}
}
const getTransactionColor = (type: string) => {
switch (type) {
case "receivable":
case "payment_received":
return "text-green-600"
case "payable":
case "payment_made":
return "text-red-600"
default:
return "text-foreground"
}
}
const getStatusBadge = (status: string) => {
switch (status) {
case "completed":
return (
<Badge variant="default" className="text-xs">
Completed
</Badge>
)
case "pending":
return (
<Badge variant="secondary" className="text-xs">
Pending
</Badge>
)
case "overdue":
return (
<Badge variant="destructive" className="text-xs">
Overdue
</Badge>
)
default:
return (
<Badge variant="outline" className="text-xs">
{status}
</Badge>
)
}
}
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Calendar className="h-5 w-5" />
Transaction History
</CardTitle>
<CardDescription>Complete history of all credit-related transactions</CardDescription>
</CardHeader>
<CardContent>
{/* Filters */}
<div className="flex flex-col sm:flex-row gap-4 mb-6">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" />
<Input
placeholder="Search by entity, description, or reference..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10"
/>
</div>
<Select value={typeFilter} onValueChange={setTypeFilter}>
<SelectTrigger className="w-full sm:w-[180px]">
<SelectValue placeholder="Filter by type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Types</SelectItem>
<SelectItem value="receivable">Receivables</SelectItem>
<SelectItem value="payable">Payables</SelectItem>
<SelectItem value="payment_received">Payments Received</SelectItem>
<SelectItem value="payment_made">Payments Made</SelectItem>
</SelectContent>
</Select>
<Select value={statusFilter} onValueChange={setStatusFilter}>
<SelectTrigger className="w-full sm:w-[180px]">
<SelectValue placeholder="Filter by status" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Status</SelectItem>
<SelectItem value="completed">Completed</SelectItem>
<SelectItem value="pending">Pending</SelectItem>
<SelectItem value="overdue">Overdue</SelectItem>
</SelectContent>
</Select>
</div>
{/* Transaction Table */}
<div className="border rounded-lg overflow-hidden">
<Table>
<TableHeader>
<TableRow>
<TableHead>Date</TableHead>
<TableHead>Type</TableHead>
<TableHead>Entity</TableHead>
<TableHead>Description</TableHead>
<TableHead>Amount</TableHead>
<TableHead>Status</TableHead>
<TableHead>Reference</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredTransactions.length === 0 ? (
<TableRow>
<TableCell colSpan={7} className="text-center py-8 text-muted-foreground">
{searchTerm || typeFilter !== "all" || statusFilter !== "all"
? "No transactions found matching your filters."
: "No transactions recorded yet."}
</TableCell>
</TableRow>
) : (
filteredTransactions.map((transaction) => (
<TableRow key={transaction.id}>
<TableCell>
<div className="font-medium">{new Date(transaction.date).toLocaleDateString()}</div>
</TableCell>
<TableCell>
<div className="flex items-center gap-2">
{getTransactionIcon(transaction.type)}
<span className="capitalize text-sm">{transaction.type.replace("_", " ")}</span>
</div>
</TableCell>
<TableCell>
<div className="font-medium">{transaction.entity}</div>
</TableCell>
<TableCell>
<div className="max-w-[300px] truncate" title={transaction.description}>
{transaction.description}
</div>
</TableCell>
<TableCell>
<div className={`font-medium ${getTransactionColor(transaction.type)}`}>
{transaction.type.includes("receivable") || transaction.type.includes("payment_received")
? "+"
: "-"}
${transaction.amount.toLocaleString()}
</div>
</TableCell>
<TableCell>{getStatusBadge(transaction.status)}</TableCell>
<TableCell>
{transaction.reference && (
<code className="text-xs bg-muted px-2 py-1 rounded">{transaction.reference}</code>
)}
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
</CardContent>
</Card>
)
}