From d54e270fb4129545089746f1a88d59b8727a5ebd Mon Sep 17 00:00:00 2001 From: sazzadulalambd Date: Thu, 14 May 2026 22:25:24 +0600 Subject: [PATCH] feat: update investor profile with rental history tab, withdrawal request modal, and refined financial dashboard metrics --- src/app/admin/investors/[id]/page.tsx | 875 ++++++++++++++++++++++---- src/data/mockData.ts | 47 +- 2 files changed, 798 insertions(+), 124 deletions(-) diff --git a/src/app/admin/investors/[id]/page.tsx b/src/app/admin/investors/[id]/page.tsx index 7748b27..a75f72f 100644 --- a/src/app/admin/investors/[id]/page.tsx +++ b/src/app/admin/investors/[id]/page.tsx @@ -3,7 +3,7 @@ import { useState } from 'react'; import Link from 'next/link'; import { useParams, useRouter } from 'next/navigation'; -import { investors as initialInvestors, bikes as initialBikes, transactions as initialTransactions } from '@/data/mockData'; +import { investors as initialInvestors, bikes as initialBikes, transactions as initialTransactions, rentalPayments as initialRentalPayments } from '@/data/mockData'; import type { Investor } from '@/data/mockData'; import toast from 'react-hot-toast'; import { @@ -11,7 +11,7 @@ import { User, FileText, CreditCard, DollarSign, Clock, ChevronDown, ExternalLink, Download, Upload, AlertTriangle, Shield, Star, CheckCircle, XCircle, Search, Filter, BookOpen, ArrowRight, Printer, UserCircle, Home, Briefcase, CreditCardIcon, Heart, PhoneCall, PhoneOutgoing, MessageSquare, Save, - ShieldCheck, Building2, Users, Check, AlertOctagon, Activity, Award, Camera + ShieldCheck, Building2, Users, Check, AlertOctagon, Activity, Award, Camera, History, Settings } from 'lucide-react'; const statusColors: Record = { @@ -107,6 +107,27 @@ export default function InvestorDetailPage() { const [newDoc, setNewDoc] = useState({ type: 'nid', number: '', url: '' }); const [editingMobileIndex, setEditingMobileIndex] = useState(null); const investorTransactions = initialTransactions.filter(t => t.investorId === investorId); + const investorRentalPayments = initialRentalPayments.filter(p => p.investorId === investorId).sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); + const [rentalPage, setRentalPage] = useState(1); + const [rentalPageSize] = useState(10); + const [rentalSortBy, setRentalSortBy] = useState('date'); + const [rentalSortOrder, setRentalSortOrder] = useState<'asc' | 'desc'>('desc'); + const [showWithdrawalModal, setShowWithdrawalModal] = useState(false); + const [showAutoWithdrawModal, setShowAutoWithdrawModal] = useState(false); + const [withdrawSelection, setWithdrawSelection] = useState({ + selectAll: true, + selectedPlans: [] as string[], + selectedBikes: [] as string[], + amount: 0, + paymentMethod: '', + accountId: '' + }); + const [autoWithdrawSettings, setAutoWithdrawSettings] = useState({ + enabled: false, + frequency: 'as_per_request' as 'as_per_request' | 'weekly' | 'monthly', + minAmount: 1000, + accountId: '' + }); const [newInvestment, setNewInvestment] = useState({ planName: '', planType: 'gold' as 'silver' | 'gold' | 'platinum' | 'diamond', @@ -177,7 +198,7 @@ export default function InvestorDetailPage() { paymentMethod: newInvestment.paymentMethod }; -setInvestorJournals([journalEntry, ...investorJournals]); + setInvestorJournals([journalEntry, ...investorJournals]); setLastCreatedInvestment({ id: invId, @@ -279,22 +300,23 @@ setInvestorJournals([journalEntry, ...investorJournals]);

Total Earnings

৳{investor.totalEarnings.toLocaleString()}

+
+

Total Withdrawn

+

৳{investor.totalWithdrawn.toLocaleString()}

+
-

ROI

-

{investor.roi}%

+

Current Balance

+

৳{(investor.totalEarnings - investor.totalWithdrawn - investor.pendingEarnings).toLocaleString()}

Active Bikes

{investor.activeBikes}

-

Pending Earning

+

Pending Request

৳{investor.pendingEarnings.toLocaleString()}

-
-

Withdrawn

-

৳{investor.totalWithdrawn.toLocaleString()}

-
+ @@ -325,7 +347,13 @@ setInvestorJournals([journalEntry, ...investorJournals]); onClick={() => setActiveTab('financial')} className={`px-4 py-3 text-sm font-medium whitespace-nowrap ${activeTab === 'financial' ? 'border-b-2 border-investor text-investor' : 'text-slate-500'}`} > - Financial + Account Info + + +
@@ -963,11 +992,10 @@ setInvestorJournals([journalEntry, ...investorJournals]);
- + planType === 'platinum' ? 'bg-purple-500' : 'bg-blue-500' + }`} /> {planType} Plan • {investment?.planName || 'Investment'}
@@ -993,10 +1021,9 @@ setInvestorJournals([journalEntry, ...investorJournals]);
Battery - 50 ? 'text-green-600' : + 50 ? 'text-green-600' : bike.batteryLevel > 20 ? 'text-amber-600' : 'text-red-600' - }`}>{bike.batteryLevel}% + }`}>{bike.batteryLevel}%
@@ -1035,7 +1062,7 @@ setInvestorJournals([journalEntry, ...investorJournals]); diamond: { bg: 'bg-blue-100', border: 'border-blue-300', icon: 'text-blue-500' }, }; const style = planConfig[inv.planType] || planConfig.gold; - + return (
@@ -1058,7 +1085,7 @@ setInvestorJournals([journalEntry, ...investorJournals]);

৳{inv.actualEarnings.toLocaleString()}

- +
Duration @@ -1084,7 +1111,9 @@ setInvestorJournals([journalEntry, ...investorJournals]); View - + + Statement +
@@ -1312,7 +1341,7 @@ setInvestorJournals([journalEntry, ...investorJournals]);

All Transactions

- + )} +
+
-
-

{tx.description}

-
-

{tx.createdAt}

- {tx.referenceNumber && ( - - )} +
+
+

+ {tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' || tx.type === 'referral_bonus' ? '+' : '-'}৳{tx.amount.toLocaleString()} +

+ + {tx.status} +
-
-

- {tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' || tx.type === 'referral_bonus' ? '+' : tx.type === 'withdrawal' || tx.type === 'penalty' || tx.type === 'adjustment' ? '-' : '+'}৳{tx.amount.toLocaleString()} -

- - {tx.status} - -
-
- ))} - {investorTransactions.length === 0 && ( -
- -

No transactions yet

-
- )} + ); + })} )} {activeTab === 'documents' && ( -
-
-

KYC Documents

-
-
+
{investor.kycDocuments?.map((doc, idx) => ( -
+
Pending Review )} -
))} + {(!investor.kycDocuments || investor.kycDocuments.length === 0) && (
@@ -1521,9 +1549,618 @@ setInvestorJournals([journalEntry, ...investorJournals]);
)} + + {activeTab === 'rentals' && ( +
+
+
+

Daily Rental History

+

Track daily rental payments for investor's bikes

+
+ +
+ +
+
+
+
+ +
+
+

Total Collected

+

৳{investorRentalPayments.filter(p => p.status === 'paid').reduce((sum, p) => sum + p.amount, 0).toLocaleString()}

+
+
+
+
+
+
+ +
+
+

Active Rentals

+

{new Set(investorRentalPayments.filter(p => p.status === 'paid').map(p => p.bikeId)).size}

+
+
+
+
+
+
+ +
+
+

Pending

+

৳{investorRentalPayments.filter(p => p.status === 'pending').reduce((sum, p) => sum + p.amount, 0).toLocaleString()}

+
+
+
+
+
+
+ +
+
+

Failed

+

৳{investorRentalPayments.filter(p => p.status === 'failed').reduce((sum, p) => sum + p.amount, 0).toLocaleString()}

+
+
+
+
+ +
+
+
+

Daily Payment Records

+ {investorRentalPayments.length} records +
+
+ + + +
+
+
+ + + + + + + + + + + + + + + {(() => { + const sortedPayments = [...investorRentalPayments].sort((a, b) => { + if (rentalSortBy === 'date') { + return rentalSortOrder === 'asc' + ? new Date(a.date).getTime() - new Date(b.date).getTime() + : new Date(b.date).getTime() - new Date(a.date).getTime(); + } else if (rentalSortBy === 'bike') { + return rentalSortOrder === 'asc' + ? a.bikeModel.localeCompare(b.bikeModel) + : b.bikeModel.localeCompare(a.bikeModel); + } else if (rentalSortBy === 'amount') { + return rentalSortOrder === 'asc' + ? a.amount - b.amount + : b.amount - a.amount; + } + return 0; + }); + const totalPages = Math.ceil(sortedPayments.length / rentalPageSize); + const paginatedPayments = sortedPayments.slice( + (rentalPage - 1) * rentalPageSize, + rentalPage * rentalPageSize + ); + return paginatedPayments.map((payment: any) => { + const planColors: Record = { + single: { label: 'Single Rent', bg: 'bg-green-100', color: 'text-green-700' }, + 'rent-to-own': { label: 'Rent to Own', bg: 'bg-blue-100', color: 'text-blue-700' }, + share_ev: { label: 'Share EV', bg: 'bg-purple-100', color: 'text-purple-700' }, + }; + const statusConfig: Record = { + paid: { label: 'Paid', bg: 'bg-green-100', color: 'text-green-700' }, + pending: { label: 'Pending', bg: 'bg-amber-100', color: 'text-amber-700' }, + failed: { label: 'Failed', bg: 'bg-red-100', color: 'text-red-700' }, + }; + const plan = planColors[payment.planType] || planColors.single; + const status = statusConfig[payment.status] || statusConfig.pending; + return ( + + + + + + + + + + + ); + }); + })()} + +
{ + if (rentalSortBy === 'date') { + setRentalSortOrder(rentalSortOrder === 'asc' ? 'desc' : 'asc'); + } else { + setRentalSortBy('date'); + setRentalSortOrder('desc'); + } + }} + className="px-4 py-3 text-left text-xs font-medium text-slate-500 uppercase cursor-pointer hover:bg-slate-100" + > +
+ Date + {rentalSortBy === 'date' && ( + {rentalSortOrder === 'asc' ? '↑' : '↓'} + )} +
+
{ + if (rentalSortBy === 'bike') { + setRentalSortOrder(rentalSortOrder === 'asc' ? 'desc' : 'asc'); + } else { + setRentalSortBy('bike'); + setRentalSortOrder('asc'); + } + }} + className="px-4 py-3 text-left text-xs font-medium text-slate-500 uppercase cursor-pointer hover:bg-slate-100" + > +
+ Bike + {rentalSortBy === 'bike' && ( + {rentalSortOrder === 'asc' ? '↑' : '↓'} + )} +
+
BikerPlanDuration { + if (rentalSortBy === 'amount') { + setRentalSortOrder(rentalSortOrder === 'asc' ? 'desc' : 'asc'); + } else { + setRentalSortBy('amount'); + setRentalSortOrder('desc'); + } + }} + className="px-4 py-3 text-left text-xs font-medium text-slate-500 uppercase cursor-pointer hover:bg-slate-100" + > +
+ Amount + {rentalSortBy === 'amount' && ( + {rentalSortOrder === 'asc' ? '↑' : '↓'} + )} +
+
MethodStatus
+
+

{payment.date}

+

{payment.transactionId || payment.id}

+
+
+
+ +
+

{payment.bikeModel}

+

{payment.plateNumber}

+
+
+
+
+ + {payment.bikerName} +
+
+ + {plan.label} + + + {payment.duration} + +

৳{payment.amount.toLocaleString()}

+
+ {payment.paymentMethod} + + + {status.label} + +
+ {investorRentalPayments.length === 0 && ( +
+ +

No rental payments found

+
+ )} +
+ {investorRentalPayments.length > rentalPageSize && ( +
+

+ Showing {((rentalPage - 1) * rentalPageSize) + 1} to {Math.min(rentalPage * rentalPageSize, investorRentalPayments.length)} of {investorRentalPayments.length} +

+
+ + {Array.from({ length: Math.ceil(investorRentalPayments.length / rentalPageSize) }, (_, i) => i + 1).map(page => ( + + ))} + +
+
+ )} +
+
+ )}
+ {showWithdrawalModal && ( +
+
+
+

+ Request Withdrawal +

+ +
+ +
+
+
+

Available Balance

+

৳{(investor.totalEarnings - investor.totalWithdrawn - investor.pendingEarnings).toLocaleString()}

+
+
+

Pending Request

+

৳{investor.pendingEarnings.toLocaleString()}

+
+
+

Total Withdrawn

+

৳{investor.totalWithdrawn.toLocaleString()}

+
+
+ +
+

Select Investment Plans & Bikes

+
+
+ { + setWithdrawSelection({ + ...withdrawSelection, + selectAll: e.target.checked, + selectedPlans: e.target.checked ? investor.investments?.map((inv: any) => inv.id) || [] : [], + selectedBikes: e.target.checked ? assignedBikes.map(b => b.id) : [] + }); + }} + className="w-4 h-4 text-investor rounded" + /> + +
+ +
+
+

Investment Plans

+
+
+ {investor.investments?.map((inv: any) => { + const planColors: Record = { + silver: 'bg-slate-100 text-slate-700', + gold: 'bg-amber-100 text-amber-700', + platinum: 'bg-purple-100 text-purple-700', + diamond: 'bg-blue-100 text-blue-700', + }; + const invBikes = assignedBikes.filter(b => b.investmentId === inv.id); + const invEarnings = invBikes.reduce((sum: number, b: any) => sum + (b.totalEarnings || 0), 0); + return ( +
+
+ { + const newPlans = e.target.checked + ? [...withdrawSelection.selectedPlans, inv.id] + : withdrawSelection.selectedPlans.filter((p: string) => p !== inv.id); + const newBikes = e.target.checked + ? [...new Set([...withdrawSelection.selectedBikes, ...invBikes.map((b: any) => b.id)])] + : withdrawSelection.selectedBikes.filter((b: string) => !invBikes.find((ib: any) => ib.id === b)); + setWithdrawSelection({ ...withdrawSelection, selectedPlans: newPlans, selectedBikes: newBikes }); + }} + className="w-4 h-4 text-investor rounded" + /> + +
+ {!withdrawSelection.selectAll && invBikes.length > 0 && ( +
+ {invBikes.map((bike: any) => ( +
+ { + const newBikes = e.target.checked + ? [...withdrawSelection.selectedBikes, bike.id] + : withdrawSelection.selectedBikes.filter((b: string) => b !== bike.id); + setWithdrawSelection({ ...withdrawSelection, selectedBikes: newBikes }); + }} + className="w-3 h-3 text-investor rounded" + /> + + ৳{bike.totalEarnings?.toLocaleString() || 0} +
+ ))} +
+ )} +
+ ); + })} +
+
+
+
+ +
+

Withdrawal Amount

+
+
+ Calculated Amount + + {withdrawSelection.selectAll ? 'All Selected' : `${withdrawSelection.selectedBikes.length} bikes`} + +
+

+ ৳{(withdrawSelection.selectAll + ? assignedBikes.reduce((sum: number, b: any) => sum + (b.totalEarnings || 0), 0) + : withdrawSelection.selectedBikes.reduce((sum: number, bikeId: string) => { + const bike = assignedBikes.find((b: any) => b.id === bikeId); + return sum + (bike?.totalEarnings || 0); + }, 0) + ).toLocaleString()} +

+

+ Based on {withdrawSelection.selectAll ? 'all' : withdrawSelection.selectedBikes.length} selected bike(s) earnings +

+
+
+ +
+

Payment Method

+
+ {investor.bankAccounts?.map((account: any) => ( +
setWithdrawSelection({ ...withdrawSelection, paymentMethod: 'bank', accountId: account.id })} + className={`p-4 rounded-lg border cursor-pointer transition-all ${withdrawSelection.accountId === account.id ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`} + > +
+
+ +
+
+

{account.bankName}

+ {account.isPrimary && Primary} +
+
+

{account.accountNumber}

+
+ ))} +
+ {investor.mobileBanking && ( +
setWithdrawSelection({ ...withdrawSelection, paymentMethod: 'mobile', accountId: 'mobile' })} + className={`mt-3 p-4 rounded-lg border cursor-pointer transition-all ${withdrawSelection.paymentMethod === 'mobile' ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`} + > +
+
+ +
+
+

{investor.mobileBanking}

+

{investor.mobileBankingNumber}

+
+
+
+ )} +
+
+ +
+ +
+ + +
+
+
+
+ )} + + {showAutoWithdrawModal && ( +
+
+
+

+ Auto-Withdraw Settings +

+ +
+ +
+
+
+

Enable Auto-Withdraw

+

Automatically withdraw earnings

+
+ +
+ + {autoWithdrawSettings.enabled && ( + <> +
+ +
+ {[ + { value: 'as_per_request', label: 'As Requested' }, + { value: 'weekly', label: 'Weekly' }, + { value: 'monthly', label: 'Monthly' } + ].map(opt => ( + + ))} +
+
+ +
+ +
+ + setAutoWithdrawSettings({ ...autoWithdrawSettings, minAmount: Number(e.target.value) })} + className="w-full pl-8 pr-4 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-investor" + /> +
+

Minimum balance required for auto-withdrawal

+
+ +
+ +
+ {investor.bankAccounts?.map((account: any) => ( +
setAutoWithdrawSettings({ ...autoWithdrawSettings, accountId: account.id })} + className={`p-3 rounded-lg border cursor-pointer flex items-center gap-3 ${autoWithdrawSettings.accountId === account.id ? 'border-investor bg-investor/5' : 'border-slate-200'}`} + > +
+ {autoWithdrawSettings.accountId === account.id &&
} +
+
+

{account.bankName}

+

{account.accountNumber}

+
+ {account.isPrimary && Primary} +
+ ))} + {investor.mobileBanking && ( +
setAutoWithdrawSettings({ ...autoWithdrawSettings, accountId: 'mobile' })} + className={`p-3 rounded-lg border cursor-pointer flex items-center gap-3 ${autoWithdrawSettings.accountId === 'mobile' ? 'border-investor bg-investor/5' : 'border-slate-200'}`} + > +
+ {autoWithdrawSettings.accountId === 'mobile' &&
} +
+
+

{investor.mobileBanking}

+

{investor.mobileBankingNumber}

+
+
+ )} +
+
+ + )} +
+ +
+ + +
+
+
+ )} + {showAssignBikeModal && (
diff --git a/src/data/mockData.ts b/src/data/mockData.ts index ee43a1b..fd3ae01 100644 --- a/src/data/mockData.ts +++ b/src/data/mockData.ts @@ -46,7 +46,9 @@ export interface BikeAssignment { export interface Rental { id: string; bikeId: string; + investorId: string; userId: string; + bikerName: string; type: 'single' | 'shared' | 'rent-to-own'; status: 'active' | 'pending' | 'completed' | 'disputed'; startDate: string; @@ -56,6 +58,24 @@ export interface Rental { totalPaid: number; } +export interface RentalPayment { + id: string; + rentalId: string; + bikeId: string; + investorId: string; + bikeModel: string; + plateNumber: string; + bikerId: string; + bikerName: string; + date: string; + amount: number; + duration: string; + planType: string; + status: 'paid' | 'pending' | 'failed'; + paymentMethod: 'cash' | 'mobile' | 'bank'; + transactionId?: string; +} + export interface Transaction { id: string; userId?: string; @@ -174,7 +194,7 @@ export const users: User[] = [ export const bikes: Bike[] = [ { - id: 'EV001', model: 'Etron ET50', brand: 'Etron', image: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400', plateNumber: 'Dhaka Metro Cha-1234', status: 'rented', batteryLevel: 78, location: 'Gulshan 1', assignedTo: 'u1', investorId: 'inv1', investmentId: 'ip1', rentalType: 'single_rent', purchasePrice: 85000, purchaseDate: '2024-01-15', currentRent: 350, totalEarnings: 14250, + id: 'EV001', model: 'Etron ET50', brand: 'Etron', image: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400', plateNumber: 'Dhaka Metro Cha-1234', status: 'rented', batteryLevel: 78, location: 'Gulshan 1', assignedTo: 'u1', investorId: 'inv1', investmentId: 'ip1', rentalType: 'single_rent', purchasePrice: 85000, purchaseDate: '2024-01-15', currentRent: 350, totalEarnings: 114250, assignmentHistory: [ { id: 'ash1', bikeId: 'EV001', bikerId: 'u3', bikerName: 'Rahim Khan', assignedAt: '2024-01-20 10:30:00', assignedBy: 'admin1', unassignedAt: '2024-02-15 14:20:00', unassignedBy: 'admin1', reason: 'Bike transfer to another biker', status: 'completed', notes: 'Initial assignment' }, { id: 'ash2', bikeId: 'EV001', bikerId: 'u1', bikerName: 'Karim Ahmed', assignedAt: '2024-02-15 15:00:00', assignedBy: 'admin1', status: 'active', notes: 'Reassigned after maintenance' } @@ -232,9 +252,26 @@ export const bikes: Bike[] = [ ]; export const rentals: Rental[] = [ - { id: 'r1', bikeId: 'b1', userId: 'u1', type: 'single', status: 'active', startDate: '2024-03-01', deposit: 5000, dailyRate: 350, totalPaid: 10500 }, - { id: 'r2', bikeId: 'b3', userId: 'u2', type: 'rent-to-own', status: 'active', startDate: '2024-02-15', deposit: 8000, dailyRate: 450, totalPaid: 18000 }, - { id: 'r3', bikeId: 'b2', userId: 'u1', type: 'single', status: 'completed', startDate: '2024-01-10', endDate: '2024-01-25', deposit: 5000, dailyRate: 350, totalPaid: 5250 }, + { id: 'r1', bikeId: 'EV001', investorId: 'inv1', userId: 'u1', bikerName: 'Karim Ahmed', type: 'single', status: 'active', startDate: '2024-03-01', deposit: 5000, dailyRate: 350, totalPaid: 10500 }, + { id: 'r2', bikeId: 'EV003', investorId: 'inv2', userId: 'u2', bikerName: 'Sofiq Rahman', type: 'rent-to-own', status: 'active', startDate: '2024-02-15', deposit: 8000, dailyRate: 450, totalPaid: 18000 }, + { id: 'r3', bikeId: 'EV002', investorId: 'inv1', userId: 'u1', bikerName: 'Karim Ahmed', type: 'single', status: 'completed', startDate: '2024-01-10', endDate: '2024-01-25', deposit: 5000, dailyRate: 350, totalPaid: 5250 }, +]; + +export const rentalPayments: RentalPayment[] = [ + { id: 'rp1', rentalId: 'r1', bikeId: 'EV001', investorId: 'inv1', bikeModel: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-25', amount: 350, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'mobile' }, + { id: 'rp2', rentalId: 'r1', bikeId: 'EV001', investorId: 'inv1', bikeModel: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-24', amount: 350, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'mobile' }, + { id: 'rp3', rentalId: 'r1', bikeId: 'EV001', investorId: 'inv1', bikeModel: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-23', amount: 350, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'cash' }, + { id: 'rp4', rentalId: 'r1', bikeId: 'EV001', investorId: 'inv1', bikeModel: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-22', amount: 350, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'mobile' }, + { id: 'rp5', rentalId: 'r1', bikeId: 'EV001', investorId: 'inv1', bikeModel: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-21', amount: 350, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'mobile' }, + { id: 'rp6', rentalId: 'r2', bikeId: 'EV002', investorId: 'inv1', bikeModel: 'Yadea DT3', plateNumber: 'Dhaka Metro Cha-5678', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-25', amount: 300, duration: '1 day', planType: 'single', status: 'pending', paymentMethod: 'mobile' }, + { id: 'rp7', rentalId: 'r2', bikeId: 'EV002', investorId: 'inv1', bikeModel: 'Yadea DT3', plateNumber: 'Dhaka Metro Cha-5678', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-24', amount: 300, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'cash' }, + { id: 'rp8', rentalId: 'r2', bikeId: 'EV002', investorId: 'inv1', bikeModel: 'Yadea DT3', plateNumber: 'Dhaka Metro Cha-5678', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-23', amount: 300, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'mobile' }, + { id: 'rp9', rentalId: 'r3', bikeId: 'EV003', investorId: 'inv2', bikeModel: 'AIMA Lightning', plateNumber: 'Dhaka Metro Cha-9012', bikerId: 'u2', bikerName: 'Sofiq Rahman', date: '2024-03-25', amount: 450, duration: '1 day', planType: 'rent-to-own', status: 'paid', paymentMethod: 'bank' }, + { id: 'rp10', rentalId: 'r3', bikeId: 'EV003', investorId: 'inv2', bikeModel: 'AIMA Lightning', plateNumber: 'Dhaka Metro Cha-9012', bikerId: 'u2', bikerName: 'Sofiq Rahman', date: '2024-03-24', amount: 450, duration: '1 day', planType: 'rent-to-own', status: 'paid', paymentMethod: 'mobile' }, + { id: 'rp11', rentalId: 'r3', bikeId: 'EV003', investorId: 'inv2', bikeModel: 'AIMA Lightning', plateNumber: 'Dhaka Metro Cha-9012', bikerId: 'u2', bikerName: 'Sofiq Rahman', date: '2024-03-23', amount: 450, duration: '1 day', planType: 'rent-to-own', status: 'paid', paymentMethod: 'bank' }, + { id: 'rp12', rentalId: 'r1', bikeId: 'EV001', investorId: 'inv1', bikeModel: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-20', amount: 350, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'cash' }, + { id: 'rp13', rentalId: 'r1', bikeId: 'EV001', investorId: 'inv1', bikeModel: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-19', amount: 350, duration: '1 day', planType: 'single', status: 'paid', paymentMethod: 'mobile' }, + { id: 'rp14', rentalId: 'r2', bikeId: 'EV002', investorId: 'inv1', bikeModel: 'Yadea DT3', plateNumber: 'Dhaka Metro Cha-5678', bikerId: 'u1', bikerName: 'Karim Ahmed', date: '2024-03-22', amount: 300, duration: '1 day', planType: 'single', status: 'failed', paymentMethod: 'mobile' }, ]; export const transactions: Transaction[] = [ @@ -326,7 +363,7 @@ export const investors: Investor[] = [ emergencyContactRelation: 'Wife', emergencyContactPhone: '01712345679', totalInvested: 150000, - totalEarnings: 14250, + totalEarnings: 114250, activeBikes: 2, withdrawalPending: 3000, totalWithdrawn: 45000,