Refactor Financials page: Add Settlements Table, Transaction Details, and Visual Upgrades
This commit is contained in:
120
src/data/mockFinancialData.ts
Normal file
120
src/data/mockFinancialData.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
|
||||
export interface Settlement {
|
||||
id: string;
|
||||
partnerName: string;
|
||||
eventName: string;
|
||||
amount: number;
|
||||
dueDate: string;
|
||||
status: 'Ready' | 'On Hold' | 'Overdue';
|
||||
}
|
||||
|
||||
export interface Transaction {
|
||||
id: string;
|
||||
title: string;
|
||||
partner: string;
|
||||
amount: number;
|
||||
date: string; // ISO string
|
||||
type: 'in' | 'out';
|
||||
method: 'Stripe' | 'Bank Transfer' | 'Razorpay';
|
||||
fees: number;
|
||||
net: number;
|
||||
status: 'Completed' | 'Pending' | 'Failed';
|
||||
}
|
||||
|
||||
export const mockSettlements: Settlement[] = [
|
||||
{
|
||||
id: 's1',
|
||||
partnerName: 'Neon Arena',
|
||||
eventName: 'Summer Music Festival',
|
||||
amount: 125000,
|
||||
dueDate: '2026-02-05',
|
||||
status: 'Ready',
|
||||
},
|
||||
{
|
||||
id: 's2',
|
||||
partnerName: 'TopTier Promoters',
|
||||
eventName: 'Comedy Night',
|
||||
amount: 45000,
|
||||
dueDate: '2026-02-06',
|
||||
status: 'On Hold',
|
||||
},
|
||||
{
|
||||
id: 's3',
|
||||
partnerName: 'TechFlow Solutions',
|
||||
eventName: 'Tech Summit 2026',
|
||||
amount: 85000,
|
||||
dueDate: '2026-02-02', // Past date
|
||||
status: 'Overdue',
|
||||
},
|
||||
{
|
||||
id: 's4',
|
||||
partnerName: 'Global Sponsors Inc',
|
||||
eventName: 'Corporate Gala',
|
||||
amount: 250000,
|
||||
dueDate: '2026-02-10',
|
||||
status: 'Ready',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTransactions: Transaction[] = [
|
||||
{
|
||||
id: 't1',
|
||||
title: 'Ticket Sales - Summer Fest',
|
||||
partner: 'Neon Arena',
|
||||
amount: 25000,
|
||||
date: new Date().toISOString(),
|
||||
type: 'in',
|
||||
method: 'Razorpay',
|
||||
fees: 1250,
|
||||
net: 23750,
|
||||
status: 'Completed',
|
||||
},
|
||||
{
|
||||
id: 't2',
|
||||
title: 'Payout - Neon Arena',
|
||||
partner: 'Neon Arena',
|
||||
amount: 15000,
|
||||
date: new Date().toISOString(),
|
||||
type: 'out',
|
||||
method: 'Bank Transfer',
|
||||
fees: 0,
|
||||
net: 15000,
|
||||
status: 'Completed',
|
||||
},
|
||||
{
|
||||
id: 't3',
|
||||
title: 'Ticket Sales - Comedy Night',
|
||||
partner: 'TopTier Promoters',
|
||||
amount: 4500,
|
||||
date: new Date(Date.now() - 86400000).toISOString(), // Yesterday
|
||||
type: 'in',
|
||||
method: 'Stripe',
|
||||
fees: 225,
|
||||
net: 4275,
|
||||
status: 'Completed',
|
||||
},
|
||||
{
|
||||
id: 't4',
|
||||
title: 'Refund - User #442',
|
||||
partner: 'Neon Arena',
|
||||
amount: 1500,
|
||||
date: new Date(Date.now() - 86400000).toISOString(),
|
||||
type: 'out',
|
||||
method: 'Razorpay',
|
||||
fees: 0,
|
||||
net: 1500,
|
||||
status: 'Completed',
|
||||
},
|
||||
{
|
||||
id: 't5',
|
||||
title: 'Ticket Sales - Tech Summit',
|
||||
partner: 'TechFlow Solutions',
|
||||
amount: 12000,
|
||||
date: '2026-02-01T10:00:00Z',
|
||||
type: 'in',
|
||||
method: 'Razorpay',
|
||||
fees: 600,
|
||||
net: 11400,
|
||||
status: 'Completed',
|
||||
},
|
||||
];
|
||||
116
src/features/financials/components/SettlementTable.tsx
Normal file
116
src/features/financials/components/SettlementTable.tsx
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { format } from "date-fns";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow
|
||||
} from "@/components/ui/table";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { mockSettlements, Settlement } from "@/data/mockFinancialData";
|
||||
import { ArrowUpRight } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export function SettlementTable() {
|
||||
const [selected, setSelected] = useState<string[]>([]);
|
||||
|
||||
const handleSelectAll = (checked: boolean) => {
|
||||
if (checked) {
|
||||
setSelected(mockSettlements.map(s => s.id));
|
||||
} else {
|
||||
setSelected([]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectOne = (id: string, checked: boolean) => {
|
||||
if (checked) {
|
||||
setSelected(prev => [...prev, id]);
|
||||
} else {
|
||||
setSelected(prev => prev.filter(item => item !== id));
|
||||
}
|
||||
};
|
||||
|
||||
const handleReleasePayout = () => {
|
||||
toast.success(`Processing payouts for ${selected.length} partners`);
|
||||
setSelected([]);
|
||||
};
|
||||
|
||||
const getStatusBadge = (status: Settlement['status']) => {
|
||||
switch (status) {
|
||||
case 'Ready':
|
||||
return <Badge className="bg-success/15 text-success hover:bg-success/25 border-none">Ready</Badge>;
|
||||
case 'On Hold':
|
||||
return <Badge className="bg-warning/15 text-warning hover:bg-warning/25 border-none">On Hold</Badge>;
|
||||
case 'Overdue':
|
||||
return <Badge className="bg-error/15 text-error hover:bg-error/25 border-none">Overdue</Badge>;
|
||||
default: return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="neu-card p-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-foreground">Due for Settlement</h2>
|
||||
<p className="text-sm text-muted-foreground">Manage pending partner payouts</p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleReleasePayout}
|
||||
disabled={selected.length === 0}
|
||||
className="bg-primary hover:bg-primary/90 text-white"
|
||||
>
|
||||
Release Payout ({selected.length})
|
||||
<ArrowUpRight className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border border-border/50">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="hover:bg-transparent">
|
||||
<TableHead className="w-[50px]">
|
||||
<Checkbox
|
||||
checked={selected.length === mockSettlements.length && mockSettlements.length > 0}
|
||||
onCheckedChange={(checked) => handleSelectAll(checked as boolean)}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead>Partner Name</TableHead>
|
||||
<TableHead>Event</TableHead>
|
||||
<TableHead>Unsettled Amount</TableHead>
|
||||
<TableHead>Due Date</TableHead>
|
||||
<TableHead className="text-right">Status</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{mockSettlements.map((settlement) => (
|
||||
<TableRow key={settlement.id} className="hover:bg-secondary/20">
|
||||
<TableCell>
|
||||
<Checkbox
|
||||
checked={selected.includes(settlement.id)}
|
||||
onCheckedChange={(checked) => handleSelectOne(settlement.id, checked as boolean)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">{settlement.partnerName}</TableCell>
|
||||
<TableCell className="text-muted-foreground">{settlement.eventName}</TableCell>
|
||||
<TableCell className="font-semibold">
|
||||
{settlement.amount.toLocaleString('en-IN', { style: 'currency', currency: 'INR' })}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{format(new Date(settlement.dueDate), 'MMM dd, yyyy')}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{getStatusBadge(settlement.status)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from "@/components/ui/sheet";
|
||||
import { Transaction } from "@/data/mockFinancialData";
|
||||
import { AlertCircle, CheckCircle2, XCircle } from "lucide-react";
|
||||
|
||||
interface TransactionDetailsSheetProps {
|
||||
transaction: Transaction | null;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export function TransactionDetailsSheet({ transaction, open, onOpenChange }: TransactionDetailsSheetProps) {
|
||||
if (!transaction) return null;
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||
<SheetContent>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Transaction Details</SheetTitle>
|
||||
<SheetDescription>
|
||||
ID: {transaction.id}
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
|
||||
<div className="mt-8 space-y-6">
|
||||
<div className="flex items-center justify-between p-4 bg-secondary/30 rounded-xl">
|
||||
<div className="flex items-center gap-3">
|
||||
{transaction.status === 'Completed' ? (
|
||||
<CheckCircle2 className="h-8 w-8 text-success" />
|
||||
) : transaction.status === 'Failed' ? (
|
||||
<XCircle className="h-8 w-8 text-error" />
|
||||
) : (
|
||||
<AlertCircle className="h-8 w-8 text-warning" />
|
||||
)}
|
||||
<div>
|
||||
<p className="font-bold text-lg">{transaction.amount.toLocaleString('en-IN', { style: 'currency', currency: 'INR' })}</p>
|
||||
<p className="text-sm text-muted-foreground">{transaction.status}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-sm font-medium">{new Date(transaction.date).toLocaleDateString()}</p>
|
||||
<p className="text-xs text-muted-foreground">{new Date(transaction.date).toLocaleTimeString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">Breakdown</h3>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-foreground">Gross Amount</span>
|
||||
<span className="font-medium">{transaction.amount.toLocaleString('en-IN', { style: 'currency', currency: 'INR' })}</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-muted-foreground">
|
||||
<span>Platform Fees (5%)</span>
|
||||
<span>- {transaction.fees.toLocaleString('en-IN', { style: 'currency', currency: 'INR' })}</span>
|
||||
</div>
|
||||
<div className="h-px bg-border my-2" />
|
||||
<div className="flex justify-between text-lg font-bold">
|
||||
<span>Net Settlement</span>
|
||||
<span className="text-success">{transaction.net.toLocaleString('en-IN', { style: 'currency', currency: 'INR' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">Metadata</h3>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p className="text-xs text-muted-foreground">Partner</p>
|
||||
<p className="font-medium">{transaction.partner}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-muted-foreground">Method</p>
|
||||
<p className="font-medium">{transaction.method}</p>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<p className="text-xs text-muted-foreground">Description</p>
|
||||
<p className="font-medium">{transaction.title}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
114
src/features/financials/components/TransactionList.tsx
Normal file
114
src/features/financials/components/TransactionList.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { format, isToday, isYesterday } from "date-fns";
|
||||
import { mockTransactions, Transaction } from "@/data/mockFinancialData";
|
||||
import { TransactionDetailsSheet } from "./TransactionDetailsSheet";
|
||||
import { ArrowUpRight, ArrowDownRight, CreditCard, Landmark, Wallet } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function TransactionList() {
|
||||
const [selectedTx, setSelectedTx] = useState<Transaction | null>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
// Group transactions by date
|
||||
const groupedTransactions = mockTransactions.reduce((groups, tx) => {
|
||||
const date = new Date(tx.date);
|
||||
let key = format(date, 'yyyy-MM-dd');
|
||||
if (isToday(date)) key = 'Today';
|
||||
else if (isYesterday(date)) key = 'Yesterday';
|
||||
else key = format(date, 'MMMM dd, yyyy');
|
||||
|
||||
if (!groups[key]) {
|
||||
groups[key] = [];
|
||||
}
|
||||
groups[key].push(tx);
|
||||
return groups;
|
||||
}, {} as Record<string, Transaction[]>);
|
||||
|
||||
const handleRowClick = (tx: Transaction) => {
|
||||
setSelectedTx(tx);
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const getMethodIcon = (method: Transaction['method']) => {
|
||||
switch (method) {
|
||||
case 'Stripe': return <CreditCard className="h-4 w-4" />;
|
||||
case 'Bank Transfer': return <Landmark className="h-4 w-4" />;
|
||||
case 'Razorpay': return <Wallet className="h-4 w-4" />;
|
||||
default: return <Wallet className="h-4 w-4" />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="neu-card p-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-lg font-bold text-foreground">Recent Transactions</h2>
|
||||
<button className="text-sm font-medium text-accent hover:underline">
|
||||
View All
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
{Object.entries(groupedTransactions).map(([date, transactions]) => (
|
||||
<div key={date}>
|
||||
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-3 px-2">
|
||||
{date}
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{transactions.map((tx) => (
|
||||
<div
|
||||
key={tx.id}
|
||||
onClick={() => handleRowClick(tx)}
|
||||
className={cn(
|
||||
"flex items-center justify-between p-3 rounded-lg cursor-pointer transition-all",
|
||||
"hover:bg-secondary/50 border border-transparent hover:border-border/50",
|
||||
tx.type === 'out' ? "bg-error/5 hover:bg-error/10" : "bg-card"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={cn(
|
||||
"h-10 w-10 rounded-full flex items-center justify-center shrink-0",
|
||||
tx.type === 'in' ? "bg-success/10 text-success" : "bg-error/10 text-error"
|
||||
)}>
|
||||
{tx.type === 'in' ? <ArrowUpRight className="h-5 w-5" /> : <ArrowDownRight className="h-5 w-5" />}
|
||||
</div>
|
||||
|
||||
<div className="min-w-[120px]">
|
||||
<p className="font-medium text-sm text-foreground">{tx.title}</p>
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground mt-0.5">
|
||||
<span className="flex items-center gap-1">
|
||||
{getMethodIcon(tx.method)}
|
||||
{tx.method}
|
||||
</span>
|
||||
<span>•</span>
|
||||
<span>{format(new Date(tx.date), 'hh:mm a')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-right">
|
||||
<p className={cn(
|
||||
"font-bold text-sm",
|
||||
tx.type === 'in' ? "text-success" : "text-error"
|
||||
)}>
|
||||
{tx.type === 'in' ? '+' : '-'}{tx.amount.toLocaleString('en-IN', { style: 'currency', currency: 'INR' })}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{tx.status}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<TransactionDetailsSheet
|
||||
transaction={selectedTx}
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +1,23 @@
|
||||
import { IndianRupee, TrendingUp, Wallet, ArrowUpRight, ArrowDownRight } from 'lucide-react';
|
||||
|
||||
import { IndianRupee, TrendingUp, Wallet } from 'lucide-react';
|
||||
import { AppLayout } from '@/components/layout/AppLayout';
|
||||
import { formatCurrency, mockRevenueData } from '@/data/mockData';
|
||||
import { SettlementTable } from '@/features/financials/components/SettlementTable';
|
||||
import { TransactionList } from '@/features/financials/components/TransactionList';
|
||||
|
||||
export default function Financials() {
|
||||
const totalRevenue = mockRevenueData.reduce((sum, d) => sum + d.revenue, 0);
|
||||
const totalPayouts = mockRevenueData.reduce((sum, d) => sum + d.payouts, 0);
|
||||
const platformFee = totalRevenue - totalPayouts;
|
||||
// Calculating platform fee (approx 10% of revenue for mock)
|
||||
const platformEarnings = totalRevenue * 0.12;
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
title="Financials"
|
||||
<AppLayout
|
||||
title="Financials & Settlements"
|
||||
description="Track revenue, payouts, and platform earnings."
|
||||
>
|
||||
{/* Financial Overview */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
||||
{/* Financial Overview Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||
<div className="neu-card p-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="h-12 w-12 rounded-xl bg-success/10 flex items-center justify-center">
|
||||
@@ -21,10 +25,11 @@ export default function Financials() {
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-bold text-foreground">{formatCurrency(totalRevenue)}</p>
|
||||
<p className="text-sm text-muted-foreground">Total Revenue (7d)</p>
|
||||
<p className="text-sm text-muted-foreground">Total Revenue (All Time)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="neu-card p-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="h-12 w-12 rounded-xl bg-accent/10 flex items-center justify-center">
|
||||
@@ -32,82 +37,52 @@ export default function Financials() {
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-bold text-foreground">{formatCurrency(totalPayouts)}</p>
|
||||
<p className="text-sm text-muted-foreground">Partner Payouts (7d)</p>
|
||||
<p className="text-sm text-muted-foreground">Partner Payouts (Processed)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="neu-card p-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="h-12 w-12 rounded-xl bg-royal-blue/10 flex items-center justify-center">
|
||||
<TrendingUp className="h-6 w-6 text-royal-blue" />
|
||||
|
||||
{/* Premium Platform Earnings Card */}
|
||||
<div className="relative overflow-hidden rounded-xl border border-yellow-500/20 bg-gradient-to-br from-yellow-500/10 to-orange-500/10 p-6 shadow-neu">
|
||||
<div className="flex items-center gap-4 relative z-10">
|
||||
<div className="h-12 w-12 rounded-xl bg-yellow-500/20 flex items-center justify-center border border-yellow-500/30">
|
||||
<TrendingUp className="h-6 w-6 text-yellow-600 dark:text-yellow-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-bold text-foreground">{formatCurrency(platformFee)}</p>
|
||||
<p className="text-sm text-muted-foreground">Platform Earnings (7d)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="neu-card p-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="h-12 w-12 rounded-xl bg-warning/10 flex items-center justify-center">
|
||||
<Wallet className="h-6 w-6 text-warning" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-2xl font-bold text-foreground">{formatCurrency(845000)}</p>
|
||||
<p className="text-sm text-muted-foreground">Pending Payouts</p>
|
||||
<p className="text-2xl font-bold text-foreground">{formatCurrency(platformEarnings)}</p>
|
||||
<p className="text-sm text-yellow-700/80 dark:text-yellow-400/80 font-medium">Net Platform Earnings</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* Decorative background glow */}
|
||||
<div className="absolute -right-6 -top-6 h-24 w-24 bg-yellow-500/20 blur-2xl rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Transaction History */}
|
||||
<div className="neu-card p-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-lg font-bold text-foreground">Recent Transactions</h2>
|
||||
<button className="text-sm font-medium text-accent hover:underline">
|
||||
View All
|
||||
</button>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Main Section: Payouts Command Center (2/3 width) */}
|
||||
<div className="lg:col-span-2 space-y-8">
|
||||
<SettlementTable />
|
||||
|
||||
{/* Detailed Transaction List */}
|
||||
<TransactionList />
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{ id: '1', type: 'in', title: 'Mumbai Music Festival', partner: 'Music Nights', amount: 489000, date: new Date() },
|
||||
{ id: '2', type: 'out', title: 'Partner Payout', partner: 'TechConf India', amount: 245000, date: new Date(Date.now() - 1000 * 60 * 60 * 2) },
|
||||
{ id: '3', type: 'in', title: 'Tech Summit 2024', partner: 'TechConf India', amount: 156000, date: new Date(Date.now() - 1000 * 60 * 60 * 5) },
|
||||
{ id: '4', type: 'out', title: 'Partner Payout', partner: 'Music Nights', amount: 180000, date: new Date(Date.now() - 1000 * 60 * 60 * 8) },
|
||||
{ id: '5', type: 'in', title: 'Night Club Party', partner: 'Music Nights', amount: 24000, date: new Date(Date.now() - 1000 * 60 * 60 * 12) },
|
||||
].map((tx) => (
|
||||
<div key={tx.id} className="flex items-center justify-between p-4 rounded-xl bg-secondary/30 hover:bg-secondary/50 transition-colors">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`h-10 w-10 rounded-xl flex items-center justify-center ${
|
||||
tx.type === 'in' ? 'bg-success/10' : 'bg-error/10'
|
||||
}`}>
|
||||
{tx.type === 'in' ? (
|
||||
<ArrowUpRight className="h-5 w-5 text-success" />
|
||||
) : (
|
||||
<ArrowDownRight className="h-5 w-5 text-error" />
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-foreground">{tx.title}</p>
|
||||
<p className="text-sm text-muted-foreground">{tx.partner}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className={`font-bold ${tx.type === 'in' ? 'text-success' : 'text-error'}`}>
|
||||
{tx.type === 'in' ? '+' : '-'}{formatCurrency(tx.amount)}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{tx.date.toLocaleDateString('en-IN', {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
{/* Sidebar Section: Summary or Quick Actions (1/3 width) */}
|
||||
<div className="space-y-6">
|
||||
{/* Could add mini charts or notifications here */}
|
||||
<div className="neu-card p-6">
|
||||
<h3 className="font-semibold mb-4">Quick Actions</h3>
|
||||
<div className="space-y-2">
|
||||
<button className="w-full text-left px-4 py-3 rounded-lg bg-secondary/50 hover:bg-secondary transition-colors text-sm font-medium flex items-center justify-between group">
|
||||
Download Monthly Report
|
||||
<IndianRupee className="h-4 w-4 text-muted-foreground group-hover:text-foreground" />
|
||||
</button>
|
||||
<button className="w-full text-left px-4 py-3 rounded-lg bg-secondary/50 hover:bg-secondary transition-colors text-sm font-medium flex items-center justify-between group">
|
||||
Update Tax Settings
|
||||
<Wallet className="h-4 w-4 text-muted-foreground group-hover:text-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
|
||||
Reference in New Issue
Block a user