Compare commits

...

2 Commits

2 changed files with 152 additions and 105 deletions

View File

@@ -272,27 +272,52 @@ export default function RentalsPage() {
const [editPermission, setEditPermission] = useState(false); const [editPermission, setEditPermission] = useState(false);
const [lockPermission, setLockPermission] = useState(false); const [lockPermission, setLockPermission] = useState(false);
const [unlockPermission, setUnlockPermission] = useState(false); const [unlockPermission, setUnlockPermission] = useState(false);
const [planConditions, setPlanConditions] = useState<{
single: { name: string; deposit: number; dailyRate: number; weeklyRate: number; monthlyRate: number; contractMonths: number[]; evModels: string[] }[];
shared: { name: string; deposit: number; dailyRate: number; weeklyRate: number; monthlyRate: number; contractMonths: number[]; evModels: string[] }[];
'rent-to-own': { name: string; deposit: number; dailyRate: number; weeklyRate: number; monthlyRate: number; contractMonths: number[]; evModels: string[] }[];
}>({
single: [
{ name: 'Single Rent - Premium', deposit: 25000, dailyRate: 400, weeklyRate: 2800, monthlyRate: 12000, contractMonths: [1, 3, 6, 12], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
{ name: 'Single Rent - Standard', deposit: 20000, dailyRate: 300, weeklyRate: 2100, monthlyRate: 9000, contractMonths: [1, 3, 6, 12], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
{ name: 'Single Rent - Economy', deposit: 15000, dailyRate: 250, weeklyRate: 1750, monthlyRate: 7500, contractMonths: [1, 3, 6, 12], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
],
shared: [
{ name: 'Share an EV - Premium', deposit: 20000, dailyRate: 300, weeklyRate: 2100, monthlyRate: 8400, contractMonths: [1, 3, 6, 12], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
{ name: 'Share an EV - Standard', deposit: 15000, dailyRate: 200, weeklyRate: 1400, monthlyRate: 5600, contractMonths: [1, 3, 6, 12], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
{ name: 'Share an EV - Economy', deposit: 12000, dailyRate: 150, weeklyRate: 1050, monthlyRate: 4200, contractMonths: [1, 3, 6, 12], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
],
'rent-to-own': [
{ name: 'Rent to Own - Premium', deposit: 25000, dailyRate: 350, weeklyRate: 2450, monthlyRate: 10500, contractMonths: [12, 18, 24, 36], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
{ name: 'Rent to Own - Standard', deposit: 18000, dailyRate: 250, weeklyRate: 1750, monthlyRate: 7000, contractMonths: [12, 18, 24, 36], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
{ name: 'Rent to Own - Economy', deposit: 15000, dailyRate: 200, weeklyRate: 1400, monthlyRate: 6000, contractMonths: [12, 18, 24, 36], evModels: ['Yadea G5', 'Yadea C1S', 'Himiwa 400', 'Himiwa 500', 'Himiwa 600', 'TVS iQube', 'Bexly 1S', 'Bexly 3S', 'Bexly 5E', 'Bolan E-Bike', 'Nova E-Bike', 'Super Eco', 'Other'] },
],
});
const [createStep, setCreateStep] = useState(1); const [createStep, setCreateStep] = useState(1);
const [newRental, setNewRental] = useState<{ const [newRental, setNewRental] = useState<{
userId: string; userId: string;
type: RentalType; type: RentalType;
condition: 'Premium' | 'Standard' | 'Economy'; planConditionName: string;
evModel: string;
subscriptionType: 'daily' | 'weekly' | 'monthly'; subscriptionType: 'daily' | 'weekly' | 'monthly';
contractMonths: number; contractMonths: number;
bikeId: string; bikeId: string;
startDate: string; startDate: string;
hubId: string; hubId: string;
depositAmount: number;
depositPaymentMethod: PaymentMethod; depositPaymentMethod: PaymentMethod;
}>({ }>({
userId: '', userId: '',
type: 'single', type: 'single',
condition: 'Standard', planConditionName: '',
evModel: '',
subscriptionType: 'daily', subscriptionType: 'daily',
contractMonths: 0, contractMonths: 0,
bikeId: '', bikeId: '',
startDate: new Date().toISOString().split('T')[0], startDate: new Date().toISOString().split('T')[0],
hubId: '', hubId: '',
depositAmount: 0,
depositPaymentMethod: 'cash', depositPaymentMethod: 'cash',
}); });
@@ -306,6 +331,8 @@ export default function RentalsPage() {
setUnlockPermission(canRentalUnlock()); setUnlockPermission(canRentalUnlock());
}, []); }, []);
const getStatusBadge = (status: RentalStatus) => { const getStatusBadge = (status: RentalStatus) => {
const styles: Record<RentalStatus, string> = { const styles: Record<RentalStatus, string> = {
active: 'bg-green-100 text-green-700', active: 'bg-green-100 text-green-700',
@@ -393,7 +420,7 @@ export default function RentalsPage() {
const eligibleUsers = mockUsers.filter(u => u.kycStatus === 'approved' && !u.hasActiveRental); const eligibleUsers = mockUsers.filter(u => u.kycStatus === 'approved' && !u.hasActiveRental);
const availableBikes = mockBikes.filter(b => b.status === 'available'); const availableBikes = mockBikes.filter(b => b.status === 'available');
const selectedSettings = rentalSettings[newRental.type]?.[newRental.condition] || rentalSettings.single.Standard; const selectedPlan = planConditions[newRental.type]?.find(p => p.name === newRental.planConditionName) || planConditions[newRental.type]?.[0];
const stats = { const stats = {
active: rentals.filter(r => r.status === 'active').length, active: rentals.filter(r => r.status === 'active').length,
@@ -411,7 +438,7 @@ export default function RentalsPage() {
const bike = mockBikes.find(b => b.id === newRental.bikeId); const bike = mockBikes.find(b => b.id === newRental.bikeId);
const user = mockUsers.find(u => u.id === newRental.userId); const user = mockUsers.find(u => u.id === newRental.userId);
const hub = mockHubs.find(h => h.id === newRental.hubId); const hub = mockHubs.find(h => h.id === newRental.hubId);
const settings = rentalSettings[newRental.type]?.[newRental.condition]; const settings = planConditions[newRental.type]?.find(p => p.name === newRental.planConditionName) || planConditions[newRental.type]?.[0];
const rental: Rental = { const rental: Rental = {
id: `RNT-${String(rentals.length + 1).padStart(3, '0')}`, id: `RNT-${String(rentals.length + 1).padStart(3, '0')}`,
@@ -454,12 +481,14 @@ export default function RentalsPage() {
setNewRental({ setNewRental({
userId: '', userId: '',
type: 'single', type: 'single',
condition: 'Standard', planConditionName: planConditions.single[1]?.name || '',
subscriptionType: 'daily', subscriptionType: 'daily',
contractMonths: 0, contractMonths: 0,
bikeId: '', bikeId: '',
evModel: '',
startDate: new Date().toISOString().split('T')[0], startDate: new Date().toISOString().split('T')[0],
hubId: '', hubId: '',
depositAmount: 0,
depositPaymentMethod: 'cash', depositPaymentMethod: 'cash',
}); });
}; };
@@ -673,7 +702,7 @@ export default function RentalsPage() {
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4"> <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto"> <div className="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto">
<div className="p-4 border-b border-slate-100 flex justify-between items-center"> <div className="p-4 border-b border-slate-100 flex justify-between items-center">
<h3 className="font-semibold text-slate-800">Create New Rental - Step {createStep} of 5</h3> <h3 className="font-semibold text-slate-800">Create New Rental - Step {createStep} of 4</h3>
<button onClick={() => { setShowCreateModal(false); setCreateStep(1); }} className="text-slate-400 hover:text-slate-600"> <button onClick={() => { setShowCreateModal(false); setCreateStep(1); }} className="text-slate-400 hover:text-slate-600">
<X className="w-5 h-5" /> <X className="w-5 h-5" />
</button> </button>
@@ -681,20 +710,34 @@ export default function RentalsPage() {
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{createStep === 1 && ( {createStep === 1 && (
<div className="space-y-4">
<h4 className="font-medium text-slate-700 mb-3">Step 1: Start Date & Hub</h4>
<div className="grid grid-cols-2 gap-3">
<div> <div>
<h4 className="font-medium text-slate-700 mb-3">Step 1: Select User</h4> <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-1.5 block">Start Date</label>
<p className="text-sm text-slate-500 mb-3">Only KYC-approved users without active rentals are shown.</p> <input type="date" value={newRental.startDate} onChange={(e) => setNewRental({ ...newRental, startDate: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
<select </div>
value={newRental.userId} <div>
onChange={(e) => setNewRental({ ...newRental, userId: e.target.value })} <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-1.5 block">Hub</label>
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" <select value={newRental.hubId} onChange={(e) => setNewRental({ ...newRental, hubId: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
> <option value="">Select Hub...</option>
{mockHubs.map(hub => (
<option key={hub.id} value={hub.id}>{hub.name}</option>
))}
</select>
</div>
</div>
<div>
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-1.5 block">Select User</label>
<p className="text-xs text-slate-400 mb-2">Only KYC-approved users without active rentals are shown.</p>
<select value={newRental.userId} onChange={(e) => setNewRental({ ...newRental, userId: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
<option value="">Select User...</option> <option value="">Select User...</option>
{eligibleUsers.map(user => ( {eligibleUsers.map(user => (
<option key={user.id} value={user.id}>{user.name} ({user.phone})</option> <option key={user.id} value={user.id}>{user.name} ({user.phone})</option>
))} ))}
</select> </select>
</div> </div>
</div>
)} )}
{createStep === 2 && ( {createStep === 2 && (
@@ -703,7 +746,7 @@ export default function RentalsPage() {
<label className="text-sm text-slate-600">Rental Type</label> <label className="text-sm text-slate-600">Rental Type</label>
<select <select
value={newRental.type} value={newRental.type}
onChange={(e) => setNewRental({ ...newRental, type: e.target.value as RentalType, condition: 'Standard', subscriptionType: 'daily' })} onChange={(e) => setNewRental({ ...newRental, type: e.target.value as RentalType, planConditionName: planConditions[e.target.value as RentalType]?.[1]?.name || planConditions[e.target.value as RentalType]?.[0]?.name || '', subscriptionType: 'daily', contractMonths: 0 })}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1"
> >
<option value="single">Single Rent</option> <option value="single">Single Rent</option>
@@ -712,25 +755,33 @@ export default function RentalsPage() {
</select> </select>
</div> </div>
<div> <div>
<label className="text-sm text-slate-600">Condition</label> <label className="text-sm text-slate-600">Plan Condition</label>
<div className="grid grid-cols-3 gap-2 mt-1"> <select
{(['Premium', 'Standard', 'Economy'] as const).map(cond => ( value={newRental.planConditionName}
<button onChange={(e) => setNewRental(prev => {
key={cond} const selectedPlan = planConditions[prev.type]?.find(p => p.name === e.target.value);
type="button" return { ...prev, planConditionName: e.target.value, depositAmount: selectedPlan?.deposit || prev.depositAmount, contractMonths: 0, subscriptionType: 'daily' };
onClick={() => setNewRental({ ...newRental, condition: cond })} })}
className={`py-2 px-3 rounded-lg text-sm border ${ className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1"
newRental.condition === cond
? cond === 'Premium' ? 'bg-purple-100 border-purple-300 text-purple-700'
: cond === 'Standard' ? 'bg-blue-100 border-blue-300 text-blue-700'
: 'bg-amber-100 border-amber-300 text-amber-700'
: 'border-slate-200 text-slate-600 hover:bg-slate-50'
}`}
> >
{cond} <option value="">Select Plan...</option>
</button> {planConditions[newRental.type]?.map(plan => (
<option key={plan.name} value={plan.name}>{plan.name}</option>
))} ))}
</select>
</div> </div>
<div>
<label className="text-sm text-slate-600">EV Model</label>
<select
value={newRental.evModel}
onChange={(e) => setNewRental({ ...newRental, evModel: e.target.value })}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1"
>
<option value="">Select EV Model...</option>
{selectedPlan?.evModels.map(model => (
<option key={model} value={model}>{model}</option>
))}
</select>
</div> </div>
<div> <div>
<label className="text-sm text-slate-600">Contract Duration</label> <label className="text-sm text-slate-600">Contract Duration</label>
@@ -740,7 +791,7 @@ export default function RentalsPage() {
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1"
> >
<option value={0}>Daily Basis</option> <option value={0}>Daily Basis</option>
{selectedSettings.contractMonths.map(m => ( {selectedPlan?.contractMonths.map(m => (
<option key={m} value={m}>{m} Months</option> <option key={m} value={m}>{m} Months</option>
))} ))}
</select> </select>
@@ -770,11 +821,11 @@ export default function RentalsPage() {
</div> </div>
<div className="bg-emerald-50 p-3 rounded-lg border border-emerald-100"> <div className="bg-emerald-50 p-3 rounded-lg border border-emerald-100">
<div className="flex items-center justify-between mb-1"> <div className="flex items-center justify-between mb-1">
<span className="text-xs text-emerald-600 font-medium uppercase tracking-wide">{newRental.condition} - {newRental.type === 'single' ? 'Single Rent' : newRental.type === 'shared' ? 'Share EV' : 'Rent to Own'}</span> <span className="text-xs text-emerald-600 font-medium uppercase tracking-wide">{newRental.planConditionName}</span>
</div> </div>
<p className="text-sm text-slate-600">Deposit: <span className="font-semibold text-slate-800">{selectedSettings.deposit.toLocaleString()}</span></p> <p className="text-sm text-slate-600">Deposit: <span className="font-semibold text-slate-800">{selectedPlan?.deposit.toLocaleString()}</span></p>
<p className="text-sm text-slate-600"> <p className="text-sm text-slate-600">
Rate: <span className="font-semibold text-slate-800">{newRental.subscriptionType === 'daily' ? selectedSettings.dailyRate : newRental.subscriptionType === 'weekly' ? selectedSettings.weeklyRate : selectedSettings.monthlyRate}</span> Rate: <span className="font-semibold text-slate-800">{newRental.subscriptionType === 'daily' ? selectedPlan?.dailyRate : newRental.subscriptionType === 'weekly' ? selectedPlan?.weeklyRate : selectedPlan?.monthlyRate}</span>
<span className="text-slate-500">/{newRental.subscriptionType === 'daily' ? 'day' : newRental.subscriptionType === 'weekly' ? 'week' : 'month'}</span> <span className="text-slate-500">/{newRental.subscriptionType === 'daily' ? 'day' : newRental.subscriptionType === 'weekly' ? 'week' : 'month'}</span>
</p> </p>
</div> </div>
@@ -805,44 +856,26 @@ export default function RentalsPage() {
</div> </div>
)} )}
{createStep === 4 && ( {createStep === 4 && (
<div className="space-y-4"> <div className="space-y-4">
<h4 className="font-medium text-slate-700 mb-3">Step 4: Start Date & Hub</h4> <h4 className="font-medium text-slate-700 mb-3">Step 4: Deposit Payment</h4>
<div>
<label className="text-sm text-slate-600">Start Date</label>
<input
type="date"
value={newRental.startDate}
onChange={(e) => setNewRental({ ...newRental, startDate: e.target.value })}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1"
/>
</div>
<div>
<label className="text-sm text-slate-600">Hub</label>
<select
value={newRental.hubId}
onChange={(e) => setNewRental({ ...newRental, hubId: e.target.value })}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1"
>
<option value="">Select Hub...</option>
{mockHubs.map(hub => (
<option key={hub.id} value={hub.id}>{hub.name}</option>
))}
</select>
</div>
</div>
)}
{createStep === 5 && (
<div className="space-y-4">
<h4 className="font-medium text-slate-700 mb-3">Step 5: Deposit Payment</h4>
<div className="bg-slate-50 p-3 rounded-lg"> <div className="bg-slate-50 p-3 rounded-lg">
<p className="text-sm text-slate-600">Deposit Amount: {selectedSettings.deposit.toLocaleString()}</p> <p className="text-sm text-slate-600">Deposit Amount: {selectedPlan?.deposit.toLocaleString()}</p>
<p className="text-sm text-slate-600">User: {selectedUser?.name}</p> <p className="text-sm text-slate-600">User: {selectedUser?.name}</p>
<p className="text-sm text-slate-600">Bike: {selectedBike?.model} ({selectedBike?.plate})</p> <p className="text-sm text-slate-600">Bike: {selectedBike?.model} ({selectedBike?.plate})</p>
<p className="text-sm text-slate-600">Hub: {mockHubs.find(h => h.id === newRental.hubId)?.name}</p> <p className="text-sm text-slate-600">Hub: {mockHubs.find(h => h.id === newRental.hubId)?.name}</p>
</div> </div>
{selectedSettings.deposit > 0 && ( <div className="grid grid-cols-2 gap-4">
{/* <div>
<label className="text-sm text-slate-600 mb-1 block">Deposit Amount (৳)</label>
<input
type="number"
value={newRental.depositAmount}
onChange={(e) => setNewRental({ ...newRental, depositAmount: Number(e.target.value) })}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
/>
</div> */}
<div> <div>
<label className="text-sm text-slate-600 mb-2 block">Payment Method</label> <label className="text-sm text-slate-600 mb-2 block">Payment Method</label>
<div className="flex gap-2"> <div className="flex gap-2">
@@ -864,34 +897,49 @@ export default function RentalsPage() {
))} ))}
</div> </div>
</div> </div>
)} </div>
{selectedSettings.deposit > 0 && ( {newRental.depositAmount > 0 && (
<div className="bg-blue-50 p-3 rounded-lg"> <div className="bg-white border border-slate-200 rounded-lg overflow-hidden">
<p className="text-sm font-medium text-blue-700 mb-2">Journal Preview</p> <div className="bg-slate-100 px-4 py-2 border-b border-slate-200">
<p className="text-sm font-semibold text-slate-700">Proforma Invoice</p>
</div>
<div className="p-3 space-y-1 text-xs">
<div className="flex justify-between"><span className="text-slate-500">Invoice No:</span><span className="text-slate-700">PI-{Date.now().toString().slice(-8)}</span></div>
<div className="flex justify-between"><span className="text-slate-500">Date:</span><span className="text-slate-700">{new Date().toLocaleDateString()}</span></div>
<div className="flex justify-between"><span className="text-slate-500">Customer:</span><span className="text-slate-700">{selectedUser?.name}</span></div>
<div className="flex justify-between"><span className="text-slate-500">Bike:</span><span className="text-slate-700">{selectedBike?.model} ({selectedBike?.plate})</span></div>
</div>
<table className="w-full text-xs"> <table className="w-full text-xs">
<thead className="bg-blue-100"> <thead className="bg-slate-50 border-t border-slate-200">
<tr> <tr>
<th className="px-2 py-1 text-left">Account</th> <th className="px-3 py-2 text-left text-slate-500 font-medium">Description</th>
<th className="px-2 py-1 text-right">Debit</th> <th className="px-3 py-2 text-right text-slate-500 font-medium">Debit ()</th>
<th className="px-2 py-1 text-right">Credit</th> <th className="px-3 py-2 text-right text-slate-500 font-medium">Credit ()</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr className="border-t border-slate-100">
<td className="px-2 py-1"> <td className="px-3 py-2">
{newRental.depositPaymentMethod === 'cash' && '1000 - Cash'} {newRental.depositPaymentMethod === 'cash' && '1000 - Cash'}
{newRental.depositPaymentMethod === 'bank' && '1100 - Bank'} {newRental.depositPaymentMethod === 'bank' && '1100 - Bank'}
{newRental.depositPaymentMethod === 'wallet' && '1200 - Biker Wallet'} {newRental.depositPaymentMethod === 'wallet' && '1200 - Biker Wallet'}
</td> </td>
<td className="px-2 py-1 text-right">{selectedSettings.deposit}</td> <td className="px-3 py-2 text-right">{newRental.depositAmount.toLocaleString()}</td>
<td className="px-2 py-1 text-right">-</td> <td className="px-3 py-2 text-right">-</td>
</tr> </tr>
<tr> <tr className="border-t border-slate-100">
<td className="px-2 py-1">2100 - Deposit Received</td> <td className="px-3 py-2">2100 - Deposit Received</td>
<td className="px-2 py-1 text-right">-</td> <td className="px-3 py-2 text-right">-</td>
<td className="px-2 py-1 text-right">{selectedSettings.deposit}</td> <td className="px-3 py-2 text-right">{newRental.depositAmount.toLocaleString()}</td>
</tr> </tr>
</tbody> </tbody>
<tfoot className="bg-slate-50 border-t border-slate-200">
<tr>
<td className="px-3 py-2 font-semibold text-slate-700">Total</td>
<td className="px-3 py-2 text-right font-semibold">{newRental.depositAmount.toLocaleString()}</td>
<td className="px-3 py-2 text-right font-semibold">{newRental.depositAmount.toLocaleString()}</td>
</tr>
</tfoot>
</table> </table>
</div> </div>
)} )}
@@ -911,13 +959,12 @@ export default function RentalsPage() {
)} )}
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
{createStep < 5 ? ( {createStep < 4 ? (
<button <button
onClick={() => setCreateStep(createStep + 1)} onClick={() => setCreateStep(createStep + 1)}
disabled={ disabled={
(createStep === 1 && !newRental.userId) || (createStep === 1 && !newRental.userId) ||
(createStep === 3 && !newRental.bikeId) || (createStep === 3 && !newRental.bikeId)
(createStep === 4 && !newRental.hubId)
} }
className="px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm disabled:opacity-50 flex items-center gap-2" className="px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm disabled:opacity-50 flex items-center gap-2"
> >
@@ -925,7 +972,7 @@ export default function RentalsPage() {
</button> </button>
) : ( ) : (
<> <>
{selectedSettings.deposit > 0 && ( {newRental.depositAmount > 0 && (
<button className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm flex items-center gap-2"> <button className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm flex items-center gap-2">
<Printer className="w-4 h-4" /> Print Invoice <Printer className="w-4 h-4" /> Print Invoice
</button> </button>

View File

@@ -2461,8 +2461,8 @@ export default function CompanySettingsPage() {
<div className="p-5 space-y-5"> <div className="p-5 space-y-5">
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-3 gap-4">
<div> <div>
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Name</label> <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Condition</label>
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Name" /> <input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Condition" />
</div> </div>
<div> <div>
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label> <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label>
@@ -2600,8 +2600,8 @@ export default function CompanySettingsPage() {
<div className="p-5 space-y-5"> <div className="p-5 space-y-5">
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-3 gap-4">
<div> <div>
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Name</label> <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Condition</label>
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Name" /> <input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Condition" />
</div> </div>
<div> <div>
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label> <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label>
@@ -2739,8 +2739,8 @@ export default function CompanySettingsPage() {
<div className="p-5 space-y-5"> <div className="p-5 space-y-5">
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-3 gap-4">
<div> <div>
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Name</label> <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Condition</label>
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Name" /> <input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Condition" />
</div> </div>
<div> <div>
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label> <label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label>
@@ -2891,7 +2891,7 @@ export default function CompanySettingsPage() {
<div className="p-4"> <div className="p-4">
<div className="grid lg:grid-cols-3 gap-4"> <div className="grid lg:grid-cols-3 gap-4">
<div> <div>
<label className="text-sm text-slate-600">Plan Name</label> <label className="text-sm text-slate-600">Plan Condition</label>
<input type="text" value={newInvestName} onChange={(e) => setNewInvestName(e.target.value)} placeholder="e.g., 1 Bike Plan" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" /> <input type="text" value={newInvestName} onChange={(e) => setNewInvestName(e.target.value)} placeholder="e.g., 1 Bike Plan" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div> </div>
<div> <div>
@@ -2986,7 +2986,7 @@ export default function CompanySettingsPage() {
<div className="p-4"> <div className="p-4">
<div className="grid lg:grid-cols-3 gap-4"> <div className="grid lg:grid-cols-3 gap-4">
<div> <div>
<label className="text-sm text-slate-600">Plan Name</label> <label className="text-sm text-slate-600">Plan Condition</label>
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" /> <input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div> </div>
<div> <div>
@@ -3101,7 +3101,7 @@ export default function CompanySettingsPage() {
<div className="p-4"> <div className="p-4">
<div className="grid lg:grid-cols-3 gap-4"> <div className="grid lg:grid-cols-3 gap-4">
<div> <div>
<label className="text-sm text-slate-600">Plan Name</label> <label className="text-sm text-slate-600">Plan Condition</label>
<input type="text" value={newSwapName} onChange={(e) => setNewSwapName(e.target.value)} placeholder="e.g., Standard Station" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" /> <input type="text" value={newSwapName} onChange={(e) => setNewSwapName(e.target.value)} placeholder="e.g., Standard Station" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div> </div>
<div> <div>
@@ -3168,7 +3168,7 @@ export default function CompanySettingsPage() {
<div className="p-4"> <div className="p-4">
<div className="grid lg:grid-cols-3 gap-4"> <div className="grid lg:grid-cols-3 gap-4">
<div> <div>
<label className="text-sm text-slate-600">Plan Name</label> <label className="text-sm text-slate-600">Plan Condition</label>
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, swapStation: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" /> <input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, swapStation: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div> </div>
<div> <div>
@@ -3255,7 +3255,7 @@ export default function CompanySettingsPage() {
<div className="p-4"> <div className="p-4">
<div className="grid lg:grid-cols-3 gap-4"> <div className="grid lg:grid-cols-3 gap-4">
<div> <div>
<label className="text-sm text-slate-600">Plan Name</label> <label className="text-sm text-slate-600">Plan Condition</label>
<input type="text" value={newRiderName} onChange={(e) => setNewRiderName(e.target.value)} placeholder="e.g., Premium Rider Plan" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" /> <input type="text" value={newRiderName} onChange={(e) => setNewRiderName(e.target.value)} placeholder="e.g., Premium Rider Plan" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div> </div>
<div> <div>
@@ -3334,7 +3334,7 @@ export default function CompanySettingsPage() {
<div className="p-4"> <div className="p-4">
<div className="grid lg:grid-cols-3 gap-4"> <div className="grid lg:grid-cols-3 gap-4">
<div> <div>
<label className="text-sm text-slate-600">Plan Name</label> <label className="text-sm text-slate-600">Plan Condition</label>
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.riderRequest]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, riderRequest: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" /> <input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.riderRequest]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, riderRequest: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div> </div>
<div> <div>