feat: add category-based filtering and enhanced dashboard stats for damage and maintenance records
This commit is contained in:
@@ -3,8 +3,8 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
AlertTriangle, Search, Plus, X, Check, Clock, Bike, User, Phone,
|
AlertTriangle, Search, Plus, X, Check, Clock, Bike, User, Phone,
|
||||||
MapPin, FileText, Image, DollarSign, Wrench, Battery, Key,
|
MapPin, FileText, Image, DollarSign, Wrench, Battery, Key,
|
||||||
CheckCircle, XCircle, ChevronDown, ChevronUp, Download, Eye, Edit,
|
CheckCircle, XCircle, ChevronDown, ChevronUp, Download, Eye, Edit,
|
||||||
MessageSquare, Filter, Calendar, Save, Printer, Send
|
MessageSquare, Filter, Calendar, Save, Printer, Send
|
||||||
@@ -24,31 +24,31 @@ interface MaintenanceRecord {
|
|||||||
severity: DamageSeverity;
|
severity: DamageSeverity;
|
||||||
status: MaintenanceStatus;
|
status: MaintenanceStatus;
|
||||||
paymentStatus: PaymentStatus;
|
paymentStatus: PaymentStatus;
|
||||||
|
|
||||||
bikeId: string;
|
bikeId: string;
|
||||||
bikeModel: string;
|
bikeModel: string;
|
||||||
bikePlate: string;
|
bikePlate: string;
|
||||||
batteryId?: string;
|
batteryId?: string;
|
||||||
|
|
||||||
reporterId: string;
|
reporterId: string;
|
||||||
reporterName: string;
|
reporterName: string;
|
||||||
reporterPhone: string;
|
reporterPhone: string;
|
||||||
reporterRole: 'biker' | 'staff' | 'hub';
|
reporterRole: 'biker' | 'staff' | 'hub';
|
||||||
|
|
||||||
description: string;
|
description: string;
|
||||||
location: string;
|
location: string;
|
||||||
|
|
||||||
estimatedCost: number;
|
estimatedCost: number;
|
||||||
actualCost?: number;
|
actualCost?: number;
|
||||||
partsUsed?: string[];
|
partsUsed?: string[];
|
||||||
|
|
||||||
images: { id: string; name: string; url: string; uploadedAt: string }[];
|
images: { id: string; name: string; url: string; uploadedAt: string }[];
|
||||||
bills?: { id: string; name: string; url: string }[];
|
bills?: { id: string; name: string; url: string }[];
|
||||||
|
|
||||||
assignedTo?: string;
|
assignedTo?: string;
|
||||||
notes: string[];
|
notes: string[];
|
||||||
resolvedAt?: string;
|
resolvedAt?: string;
|
||||||
|
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
createdBy: string;
|
createdBy: string;
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,8 @@ const typeIcons: Record<string, any> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function MaintenancePage() {
|
export default function MaintenancePage() {
|
||||||
const [activeTab, setActiveTab] = useState<'all' | MaintenanceType>('all');
|
const [mainCategory, setMainCategory] = useState<'damage' | 'maintenance'>('damage');
|
||||||
|
const [targetType, setTargetType] = useState<'all' | 'battery' | 'fleet'>('all');
|
||||||
const [records, setRecords] = useState<MaintenanceRecord[]>(mockMaintenance);
|
const [records, setRecords] = useState<MaintenanceRecord[]>(mockMaintenance);
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [statusFilter, setStatusFilter] = useState('all');
|
const [statusFilter, setStatusFilter] = useState('all');
|
||||||
@@ -259,20 +260,36 @@ export default function MaintenancePage() {
|
|||||||
const [expandedNotes, setExpandedNotes] = useState<string[]>([]);
|
const [expandedNotes, setExpandedNotes] = useState<string[]>([]);
|
||||||
const [newNoteText, setNewNoteText] = useState('');
|
const [newNoteText, setNewNoteText] = useState('');
|
||||||
const [editForm, setEditForm] = useState<Partial<MaintenanceRecord>>({});
|
const [editForm, setEditForm] = useState<Partial<MaintenanceRecord>>({});
|
||||||
|
const [reportType, setReportType] = useState<'damage' | 'maintenance'>('damage');
|
||||||
|
|
||||||
const filteredRecords = records.filter(r => {
|
const filteredRecords = records.filter(r => {
|
||||||
const matchesTab = activeTab === 'all' || r.type === activeTab;
|
const isDamage = r.type === 'damage';
|
||||||
const matchesSearch = !searchQuery ||
|
const matchesCategory = mainCategory === 'damage' ? isDamage : !isDamage;
|
||||||
|
const matchesTarget = targetType === 'all' ||
|
||||||
|
(targetType === 'battery' && r.batteryId) ||
|
||||||
|
(targetType === 'fleet' && r.bikeId && !r.batteryId);
|
||||||
|
const matchesSearch = !searchQuery ||
|
||||||
r.bikeId.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
r.bikeId.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
r.bikeModel.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
r.bikeModel.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
r.bikePlate.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
r.bikePlate.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
r.reporterName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
r.reporterName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
r.id.toLowerCase().includes(searchQuery.toLowerCase());
|
r.id.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
(r.batteryId && r.batteryId.toLowerCase().includes(searchQuery.toLowerCase()));
|
||||||
const matchesStatus = statusFilter === 'all' || r.status === statusFilter;
|
const matchesStatus = statusFilter === 'all' || r.status === statusFilter;
|
||||||
return matchesTab && matchesSearch && matchesStatus;
|
return matchesCategory && matchesTarget && matchesSearch && matchesStatus;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const damageRecords = records.filter(r => r.type === 'damage');
|
||||||
|
const maintenanceRecords = records.filter(r => r.type !== 'damage');
|
||||||
const stats = {
|
const stats = {
|
||||||
|
damageCount: damageRecords.length,
|
||||||
|
maintenanceCount: maintenanceRecords.length,
|
||||||
|
batteryDamage: damageRecords.filter(r => r.batteryId).length,
|
||||||
|
fleetDamage: damageRecords.filter(r => r.bikeId && !r.batteryId).length,
|
||||||
|
batteryMaintenance: maintenanceRecords.filter(r => r.batteryId).length,
|
||||||
|
fleetMaintenance: maintenanceRecords.filter(r => r.bikeId && !r.batteryId).length,
|
||||||
|
pendingMaintenance: maintenanceRecords.filter(r => r.status === 'reported' || r.status === 'in_progress').length,
|
||||||
|
completedMaintenance: maintenanceRecords.filter(r => r.status === 'completed').length,
|
||||||
critical: records.filter(r => r.severity === 'critical' && r.status !== 'completed').length,
|
critical: records.filter(r => r.severity === 'critical' && r.status !== 'completed').length,
|
||||||
inProgress: records.filter(r => r.status === 'in_progress' || r.status === 'parts_ordered').length,
|
inProgress: records.filter(r => r.status === 'in_progress' || r.status === 'parts_ordered').length,
|
||||||
completed: records.filter(r => r.status === 'completed').length,
|
completed: records.filter(r => r.status === 'completed').length,
|
||||||
@@ -281,15 +298,15 @@ export default function MaintenancePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleNotes = (id: string) => {
|
const toggleNotes = (id: string) => {
|
||||||
setExpandedNotes(prev =>
|
setExpandedNotes(prev =>
|
||||||
prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id]
|
prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddNote = () => {
|
const handleAddNote = () => {
|
||||||
if (!selectedRecord || !newNoteText.trim()) return;
|
if (!selectedRecord || !newNoteText.trim()) return;
|
||||||
setRecords(prev => prev.map(r =>
|
setRecords(prev => prev.map(r =>
|
||||||
r.id === selectedRecord.id
|
r.id === selectedRecord.id
|
||||||
? { ...r, notes: [...r.notes, newNoteText] }
|
? { ...r, notes: [...r.notes, newNoteText] }
|
||||||
: r
|
: r
|
||||||
));
|
));
|
||||||
@@ -299,8 +316,8 @@ export default function MaintenancePage() {
|
|||||||
|
|
||||||
const handleCompleteRecord = () => {
|
const handleCompleteRecord = () => {
|
||||||
if (!selectedRecord) return;
|
if (!selectedRecord) return;
|
||||||
setRecords(prev => prev.map(r =>
|
setRecords(prev => prev.map(r =>
|
||||||
r.id === selectedRecord.id
|
r.id === selectedRecord.id
|
||||||
? { ...r, status: 'completed', resolvedAt: new Date().toISOString().split('T')[0] }
|
? { ...r, status: 'completed', resolvedAt: new Date().toISOString().split('T')[0] }
|
||||||
: r
|
: r
|
||||||
));
|
));
|
||||||
@@ -311,9 +328,9 @@ export default function MaintenancePage() {
|
|||||||
const handlePayment = (source: 'biker' | 'company') => {
|
const handlePayment = (source: 'biker' | 'company') => {
|
||||||
if (!selectedRecord) return;
|
if (!selectedRecord) return;
|
||||||
const cost = selectedRecord.actualCost || selectedRecord.estimatedCost;
|
const cost = selectedRecord.actualCost || selectedRecord.estimatedCost;
|
||||||
|
|
||||||
setRecords(prev => prev.map(r =>
|
setRecords(prev => prev.map(r =>
|
||||||
r.id === selectedRecord.id
|
r.id === selectedRecord.id
|
||||||
? { ...r, paymentStatus: 'paid' }
|
? { ...r, paymentStatus: 'paid' }
|
||||||
: r
|
: r
|
||||||
));
|
));
|
||||||
@@ -347,22 +364,22 @@ export default function MaintenancePage() {
|
|||||||
import('jspdf').then(jsPDF => {
|
import('jspdf').then(jsPDF => {
|
||||||
const doc = new jsPDF.default();
|
const doc = new jsPDF.default();
|
||||||
const cost = selectedRecord.actualCost || selectedRecord.estimatedCost;
|
const cost = selectedRecord.actualCost || selectedRecord.estimatedCost;
|
||||||
|
|
||||||
doc.setFontSize(18);
|
doc.setFontSize(18);
|
||||||
doc.setTextColor(6, 95, 70);
|
doc.setTextColor(6, 95, 70);
|
||||||
doc.text('JAIBEN Mobility Ltd', 20, 20);
|
doc.text('JAIBEN Mobility Ltd', 20, 20);
|
||||||
|
|
||||||
doc.setFontSize(14);
|
doc.setFontSize(14);
|
||||||
doc.setTextColor(0);
|
doc.setTextColor(0);
|
||||||
doc.text('Maintenance Invoice', 20, 32);
|
doc.text('Maintenance Invoice', 20, 32);
|
||||||
|
|
||||||
doc.setFontSize(10);
|
doc.setFontSize(10);
|
||||||
doc.setTextColor(100);
|
doc.setTextColor(100);
|
||||||
doc.text(`Invoice No: INV-${selectedRecord.id}`, 20, 42);
|
doc.text(`Invoice No: INV-${selectedRecord.id}`, 20, 42);
|
||||||
doc.text(`Date: ${selectedRecord.date}`, 20, 48);
|
doc.text(`Date: ${selectedRecord.date}`, 20, 48);
|
||||||
doc.text(`Issue Type: ${selectedRecord.type}`, 20, 54);
|
doc.text(`Issue Type: ${selectedRecord.type}`, 20, 54);
|
||||||
doc.text(`Severity: ${selectedRecord.severity}`, 20, 60);
|
doc.text(`Severity: ${selectedRecord.severity}`, 20, 60);
|
||||||
|
|
||||||
doc.setFontSize(11);
|
doc.setFontSize(11);
|
||||||
doc.setTextColor(0);
|
doc.setTextColor(0);
|
||||||
doc.text('Bike Details', 20, 72);
|
doc.text('Bike Details', 20, 72);
|
||||||
@@ -371,27 +388,27 @@ export default function MaintenancePage() {
|
|||||||
doc.text(`Model: ${selectedRecord.bikeModel}`, 20, 84);
|
doc.text(`Model: ${selectedRecord.bikeModel}`, 20, 84);
|
||||||
doc.text(`License Plate: ${selectedRecord.bikePlate}`, 20, 90);
|
doc.text(`License Plate: ${selectedRecord.bikePlate}`, 20, 90);
|
||||||
if (selectedRecord.batteryId) doc.text(`Battery ID: ${selectedRecord.batteryId}`, 20, 96);
|
if (selectedRecord.batteryId) doc.text(`Battery ID: ${selectedRecord.batteryId}`, 20, 96);
|
||||||
|
|
||||||
doc.setFontSize(11);
|
doc.setFontSize(11);
|
||||||
doc.text('Description', 20, 108);
|
doc.text('Description', 20, 108);
|
||||||
doc.setFontSize(10);
|
doc.setFontSize(10);
|
||||||
const descLines = doc.splitTextToSize(selectedRecord.description, 170);
|
const descLines = doc.splitTextToSize(selectedRecord.description, 170);
|
||||||
doc.text(descLines, 20, 114);
|
doc.text(descLines, 20, 114);
|
||||||
|
|
||||||
doc.setFontSize(11);
|
doc.setFontSize(11);
|
||||||
doc.text('Cost Breakdown', 20, 130);
|
doc.text('Cost Breakdown', 20, 130);
|
||||||
doc.setFontSize(10);
|
doc.setFontSize(10);
|
||||||
doc.text(`Estimated Cost: ৳${selectedRecord.estimatedCost}`, 20, 136);
|
doc.text(`Estimated Cost: ৳${selectedRecord.estimatedCost}`, 20, 136);
|
||||||
if (selectedRecord.actualCost) doc.text(`Actual Cost: ৳${selectedRecord.actualCost}`, 20, 142);
|
if (selectedRecord.actualCost) doc.text(`Actual Cost: ৳${selectedRecord.actualCost}`, 20, 142);
|
||||||
|
|
||||||
doc.setFontSize(12);
|
doc.setFontSize(12);
|
||||||
doc.setTextColor(6, 95, 70);
|
doc.setTextColor(6, 95, 70);
|
||||||
doc.text(`Total: ৳${cost}`, 20, 152);
|
doc.text(`Total: ৳${cost}`, 20, 152);
|
||||||
|
|
||||||
doc.setFontSize(9);
|
doc.setFontSize(9);
|
||||||
doc.setTextColor(150);
|
doc.setTextColor(150);
|
||||||
doc.text('Generated from JAIBEN Maintenance System', 20, 280);
|
doc.text('Generated from JAIBEN Maintenance System', 20, 280);
|
||||||
|
|
||||||
doc.save(`maintenance-invoice-${selectedRecord.id}.pdf`);
|
doc.save(`maintenance-invoice-${selectedRecord.id}.pdf`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -404,7 +421,7 @@ export default function MaintenancePage() {
|
|||||||
<p className="text-sm text-slate-500 mt-1">Track bike damage, repairs, and service records</p>
|
<p className="text-sm text-slate-500 mt-1">Track bike damage, repairs, and service records</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowNewModal(true)}
|
onClick={() => setShowNewModal(true)}
|
||||||
className="py-2 px-4 bg-accent text-white rounded-lg text-sm font-medium hover:bg-accent-dark flex items-center gap-2"
|
className="py-2 px-4 bg-accent text-white rounded-lg text-sm font-medium hover:bg-accent-dark flex items-center gap-2"
|
||||||
>
|
>
|
||||||
@@ -413,26 +430,26 @@ export default function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-5 gap-4 mb-6">
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||||
<div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
<div className="bg-white rounded-xl p-5 shadow-sm border border-red-100">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-12 h-12 rounded-xl bg-red-50 flex items-center justify-center">
|
<div className="w-12 h-12 rounded-xl bg-red-50 flex items-center justify-center">
|
||||||
<AlertTriangle className="w-6 h-6 text-red-600" />
|
<AlertTriangle className="w-6 h-6 text-red-600" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-2xl font-extrabold text-slate-800">{stats.critical}</p>
|
<p className="text-2xl font-extrabold text-slate-800">{stats.damageCount}</p>
|
||||||
<p className="text-sm text-slate-500">Critical</p>
|
<p className="text-sm text-slate-500">Total Damage</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
<div className="bg-white rounded-xl p-5 shadow-sm border border-blue-100">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-12 h-12 rounded-xl bg-blue-50 flex items-center justify-center">
|
<div className="w-12 h-12 rounded-xl bg-blue-50 flex items-center justify-center">
|
||||||
<Wrench className="w-6 h-6 text-blue-600" />
|
<Wrench className="w-6 h-6 text-blue-600" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-2xl font-extrabold text-slate-800">{stats.inProgress}</p>
|
<p className="text-2xl font-extrabold text-slate-800">{stats.maintenanceCount}</p>
|
||||||
<p className="text-sm text-slate-500">In Progress</p>
|
<p className="text-sm text-slate-500">Total Maintenance</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -458,7 +475,7 @@ export default function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
{/* <div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-12 h-12 rounded-xl bg-purple-50 flex items-center justify-center">
|
<div className="w-12 h-12 rounded-xl bg-purple-50 flex items-center justify-center">
|
||||||
<DollarSign className="w-6 h-6 text-purple-600" />
|
<DollarSign className="w-6 h-6 text-purple-600" />
|
||||||
@@ -468,43 +485,145 @@ export default function MaintenancePage() {
|
|||||||
<p className="text-sm text-slate-500">Total Cost</p>
|
<p className="text-sm text-slate-500">Total Cost</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{mainCategory === 'damage' && (
|
||||||
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||||
|
<div className="bg-red-50 rounded-xl p-4 border border-red-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center">
|
||||||
|
<AlertTriangle className="w-5 h-5 text-red-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.damageCount}</p>
|
||||||
|
<p className="text-sm text-slate-500">Total Damage</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-green-50 rounded-xl p-4 border border-green-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-green-100 flex items-center justify-center">
|
||||||
|
<Battery className="w-5 h-5 text-green-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.batteryDamage}</p>
|
||||||
|
<p className="text-sm text-slate-500">Battery Damage</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-purple-50 rounded-xl p-4 border border-purple-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-purple-100 flex items-center justify-center">
|
||||||
|
<Bike className="w-5 h-5 text-purple-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.fleetDamage}</p>
|
||||||
|
<p className="text-sm text-slate-500">Fleet Damage</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-orange-50 rounded-xl p-4 border border-orange-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-orange-100 flex items-center justify-center">
|
||||||
|
<Clock className="w-5 h-5 text-orange-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.critical}</p>
|
||||||
|
<p className="text-sm text-slate-500">Critical Damage</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{mainCategory === 'maintenance' && (
|
||||||
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||||
|
<div className="bg-blue-50 rounded-xl p-4 border border-blue-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-blue-100 flex items-center justify-center">
|
||||||
|
<Wrench className="w-5 h-5 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.maintenanceCount}</p>
|
||||||
|
<p className="text-sm text-slate-500">Total Maintenance</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-green-50 rounded-xl p-4 border border-green-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-green-100 flex items-center justify-center">
|
||||||
|
<Battery className="w-5 h-5 text-green-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.batteryMaintenance}</p>
|
||||||
|
<p className="text-sm text-slate-500">Battery Maintenance</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-purple-50 rounded-xl p-4 border border-purple-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-purple-100 flex items-center justify-center">
|
||||||
|
<Bike className="w-5 h-5 text-purple-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.fleetMaintenance}</p>
|
||||||
|
<p className="text-sm text-slate-500">Fleet Maintenance</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-orange-50 rounded-xl p-4 border border-orange-100 flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-lg bg-orange-100 flex items-center justify-center">
|
||||||
|
<Clock className="w-5 h-5 text-orange-600" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg font-bold text-slate-800">{stats.pendingMaintenance}</p>
|
||||||
|
<p className="text-sm text-slate-500">Pending Maintenance</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-100 mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 mb-6">
|
||||||
<div className="p-4 border-b border-slate-100">
|
<div className="p-4 border-b border-slate-100">
|
||||||
<div className="flex flex-col lg:flex-row lg:items-center gap-4">
|
<div className="flex flex-col lg:flex-row lg:items-center gap-4">
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-3">
|
||||||
<button
|
<div className="flex items-center gap-1 bg-slate-100 p-1 rounded-lg">
|
||||||
onClick={() => setActiveTab('all')}
|
<button
|
||||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium ${activeTab === 'all' ? 'bg-slate-800 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
onClick={() => setMainCategory('damage')}
|
||||||
>
|
className={`px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 ${mainCategory === 'damage' ? 'bg-red-600 text-white shadow-sm' : 'text-slate-600 hover:bg-white hover:shadow-sm'}`}
|
||||||
All
|
>
|
||||||
</button>
|
<AlertTriangle className="w-4 h-4" /> Damage
|
||||||
<button
|
</button>
|
||||||
onClick={() => setActiveTab('damage')}
|
<button
|
||||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium flex items-center gap-1 ${activeTab === 'damage' ? 'bg-slate-800 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
onClick={() => setMainCategory('maintenance')}
|
||||||
>
|
className={`px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 ${mainCategory === 'maintenance' ? 'bg-blue-600 text-white shadow-sm' : 'text-slate-600 hover:bg-white hover:shadow-sm'}`}
|
||||||
<AlertTriangle className="w-4 h-4" /> Damage
|
>
|
||||||
</button>
|
<Wrench className="w-4 h-4" /> Maintenance
|
||||||
<button
|
</button>
|
||||||
onClick={() => setActiveTab('repair')}
|
</div>
|
||||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium flex items-center gap-1 ${activeTab === 'repair' ? 'bg-slate-800 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
<div className="flex items-center gap-1">
|
||||||
>
|
<button
|
||||||
<Wrench className="w-4 h-4" /> Repair
|
onClick={() => setTargetType('all')}
|
||||||
</button>
|
className={`px-3 py-1.5 rounded-lg text-sm font-medium ${targetType === 'all' ? 'bg-slate-800 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
||||||
<button
|
>
|
||||||
onClick={() => setActiveTab('service')}
|
All
|
||||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium flex items-center gap-1 ${activeTab === 'service' ? 'bg-slate-800 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
</button>
|
||||||
>
|
<button
|
||||||
<Wrench className="w-4 h-4" /> Service
|
onClick={() => setTargetType('battery')}
|
||||||
</button>
|
className={`px-3 py-1.5 rounded-lg text-sm font-medium flex items-center gap-1 ${targetType === 'battery' ? 'bg-green-600 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
||||||
<button
|
>
|
||||||
onClick={() => setActiveTab('battery_swap')}
|
<Battery className="w-4 h-4" /> Battery
|
||||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium flex items-center gap-1 ${activeTab === 'battery_swap' ? 'bg-slate-800 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
</button>
|
||||||
>
|
<button
|
||||||
<Battery className="w-4 h-4" /> Battery
|
onClick={() => setTargetType('fleet')}
|
||||||
</button>
|
className={`px-3 py-1.5 rounded-lg text-sm font-medium flex items-center gap-1 ${targetType === 'fleet' ? 'bg-purple-600 text-white' : 'border border-slate-200 text-slate-600 hover:bg-slate-50'}`}
|
||||||
|
>
|
||||||
|
<Bike className="w-4 h-4" /> Fleet
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -546,6 +665,16 @@ export default function MaintenancePage() {
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<p className="font-semibold text-slate-800">{record.id}</p>
|
<p className="font-semibold text-slate-800">{record.id}</p>
|
||||||
|
{record.batteryId && (
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full bg-green-100 text-green-700">
|
||||||
|
<Battery className="w-3 h-3" /> Battery
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{!record.batteryId && record.bikeId && (
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full bg-purple-100 text-purple-700">
|
||||||
|
<Bike className="w-3 h-3" /> Fleet
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full ${severityColors[record.severity]}`}>
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full ${severityColors[record.severity]}`}>
|
||||||
{record.severity}
|
{record.severity}
|
||||||
</span>
|
</span>
|
||||||
@@ -557,7 +686,7 @@ export default function MaintenancePage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<p className="text-sm text-slate-700">{record.description}</p>
|
<p className="text-sm text-slate-700">{record.description}</p>
|
||||||
<div className="flex flex-wrap gap-4 text-sm text-slate-500 mt-1">
|
<div className="flex flex-wrap gap-4 text-sm text-slate-500 mt-1">
|
||||||
@@ -573,7 +702,7 @@ export default function MaintenancePage() {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{record.notes.length > 0 && (
|
{record.notes.length > 0 && (
|
||||||
<button
|
<button
|
||||||
onClick={() => toggleNotes(record.id)}
|
onClick={() => toggleNotes(record.id)}
|
||||||
className="flex items-center gap-1 text-purple-600"
|
className="flex items-center gap-1 text-purple-600"
|
||||||
>
|
>
|
||||||
@@ -582,7 +711,7 @@ export default function MaintenancePage() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{expandedNotes.includes(record.id) && record.notes.length > 0 && (
|
{expandedNotes.includes(record.id) && record.notes.length > 0 && (
|
||||||
<div className="mt-2 p-3 bg-purple-50 rounded-lg space-y-1">
|
<div className="mt-2 p-3 bg-purple-50 rounded-lg space-y-1">
|
||||||
{record.notes.map((note, idx) => (
|
{record.notes.map((note, idx) => (
|
||||||
@@ -591,7 +720,7 @@ export default function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<p className="text-sm font-medium text-slate-700">৳{record.actualCost || record.estimatedCost}</p>
|
<p className="text-sm font-medium text-slate-700">৳{record.actualCost || record.estimatedCost}</p>
|
||||||
@@ -605,9 +734,9 @@ export default function MaintenancePage() {
|
|||||||
{record.status === 'cancelled' && <XCircle className="w-3 h-3" />}
|
{record.status === 'cancelled' && <XCircle className="w-3 h-3" />}
|
||||||
{record.status.replace('_', ' ')}
|
{record.status.replace('_', ' ')}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<button
|
<button
|
||||||
onClick={(e) => { e.preventDefault(); setSelectedRecord(record); setShowDetailsModal(true); }}
|
onClick={(e) => { e.preventDefault(); setSelectedRecord(record); setShowDetailsModal(true); }}
|
||||||
className="p-2 hover:bg-slate-100 rounded-lg text-slate-500"
|
className="p-2 hover:bg-slate-100 rounded-lg text-slate-500"
|
||||||
title="View Details"
|
title="View Details"
|
||||||
@@ -620,7 +749,7 @@ export default function MaintenancePage() {
|
|||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{filteredRecords.length === 0 && (
|
{filteredRecords.length === 0 && (
|
||||||
<div className="p-12 text-center">
|
<div className="p-12 text-center">
|
||||||
<Wrench className="w-12 h-12 text-slate-300 mx-auto mb-4" />
|
<Wrench className="w-12 h-12 text-slate-300 mx-auto mb-4" />
|
||||||
@@ -737,13 +866,13 @@ export default function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="p-4 border-t border-slate-100 flex justify-between">
|
<div className="p-4 border-t border-slate-100 flex justify-between">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => { setShowDetailsModal(false); setShowEditModal(true); }}
|
onClick={() => { setShowDetailsModal(false); setShowEditModal(true); }}
|
||||||
className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50 flex items-center gap-2"
|
className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50 flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<Edit className="w-4 h-4" /> Edit Record
|
<Edit className="w-4 h-4" /> Edit Record
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setShowDetailsModal(false); setShowAddNoteModal(true); }}
|
onClick={() => { setShowDetailsModal(false); setShowAddNoteModal(true); }}
|
||||||
className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50 flex items-center gap-2"
|
className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50 flex items-center gap-2"
|
||||||
>
|
>
|
||||||
@@ -752,7 +881,7 @@ export default function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{selectedRecord.status !== 'completed' && (
|
{selectedRecord.status !== 'completed' && (
|
||||||
<button
|
<button
|
||||||
onClick={handleCompleteRecord}
|
onClick={handleCompleteRecord}
|
||||||
className="px-4 py-2 bg-green-600 text-white rounded-lg text-sm hover:bg-green-700 flex items-center gap-2"
|
className="px-4 py-2 bg-green-600 text-white rounded-lg text-sm hover:bg-green-700 flex items-center gap-2"
|
||||||
>
|
>
|
||||||
@@ -760,7 +889,7 @@ export default function MaintenancePage() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{selectedRecord.status === 'completed' && selectedRecord.paymentStatus !== 'paid' && (
|
{selectedRecord.status === 'completed' && selectedRecord.paymentStatus !== 'paid' && (
|
||||||
<button
|
<button
|
||||||
onClick={() => { setShowDetailsModal(false); setShowPaymentModal(true); }}
|
onClick={() => { setShowDetailsModal(false); setShowPaymentModal(true); }}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700 flex items-center gap-2"
|
className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700 flex items-center gap-2"
|
||||||
>
|
>
|
||||||
@@ -768,7 +897,7 @@ export default function MaintenancePage() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{selectedRecord.paymentStatus === 'paid' && (
|
{selectedRecord.paymentStatus === 'paid' && (
|
||||||
<button
|
<button
|
||||||
onClick={handleGenerateInvoice}
|
onClick={handleGenerateInvoice}
|
||||||
className="px-4 py-2 bg-purple-600 text-white rounded-lg text-sm hover:bg-purple-700 flex items-center gap-2"
|
className="px-4 py-2 bg-purple-600 text-white rounded-lg text-sm hover:bg-purple-700 flex items-center gap-2"
|
||||||
>
|
>
|
||||||
@@ -794,10 +923,32 @@ export default function MaintenancePage() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 overflow-y-auto max-h-[70vh] space-y-4">
|
<div className="p-4 overflow-y-auto max-h-[70vh] space-y-4">
|
||||||
|
<div>
|
||||||
|
<label className="text-sm font-semibold text-slate-700 mb-2 block">Select Target *</label>
|
||||||
|
<div className="grid grid-cols-2 gap-3 mb-4">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="p-4 border-2 rounded-xl flex flex-col items-center gap-2 hover:border-green-500 hover:bg-green-50 transition-colors"
|
||||||
|
>
|
||||||
|
<Battery className="w-8 h-8 text-green-600" />
|
||||||
|
<span className="font-medium text-slate-700">Battery</span>
|
||||||
|
<span className="text-xs text-slate-500">For battery issues</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="p-4 border-2 rounded-xl flex flex-col items-center gap-2 hover:border-purple-500 hover:bg-purple-50 transition-colors"
|
||||||
|
>
|
||||||
|
<Bike className="w-8 h-8 text-purple-600" />
|
||||||
|
<span className="font-medium text-slate-700">Fleet (Bike)</span>
|
||||||
|
<span className="text-xs text-slate-500">For bike issues</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs font-medium text-slate-600 mb-1 block">Issue Type *</label>
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Category *</label>
|
||||||
<select className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
<select className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="">Select Category</option>
|
||||||
<option value="damage">Damage</option>
|
<option value="damage">Damage</option>
|
||||||
<option value="repair">Repair</option>
|
<option value="repair">Repair</option>
|
||||||
<option value="service">Service</option>
|
<option value="service">Service</option>
|
||||||
@@ -815,32 +966,45 @@ export default function MaintenancePage() {
|
|||||||
<option value="cosmetic">Cosmetic</option>
|
<option value="cosmetic">Cosmetic</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label className="text-xs font-medium text-slate-600 mb-1 block">Bike ID *</label>
|
|
||||||
<input type="text" placeholder="EV-XXX" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs font-medium text-slate-600 mb-1 block">Battery ID</label>
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Battery ID</label>
|
||||||
<input type="text" placeholder="BAT-XXX" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
<input type="text" placeholder="BAT-XXX" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Bike ID</label>
|
||||||
|
<input type="text" placeholder="EV-XXX" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Reporter Name *</label>
|
||||||
|
<input type="text" placeholder="Enter name" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Reporter Phone *</label>
|
||||||
|
<input type="tel" placeholder="01XXXXXXXXX" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs font-medium text-slate-600 mb-1 block">Description *</label>
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Description *</label>
|
||||||
<textarea rows={3} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Describe the issue..." />
|
<textarea rows={3} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Describe the issue in detail..." />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<label className="text-xs font-medium text-slate-600 mb-1 block">Location *</label>
|
<div>
|
||||||
<input type="text" placeholder="Where did the issue occur?" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Location / Hub *</label>
|
||||||
</div>
|
<input type="text" placeholder="e.g., Gulshan Hub" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
<div>
|
</div>
|
||||||
<label className="text-xs font-medium text-slate-600 mb-1 block">Estimated Cost</label>
|
<div>
|
||||||
<input type="number" placeholder="0" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Estimated Cost (৳)</label>
|
||||||
|
<input type="number" placeholder="0" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs font-medium text-slate-600 mb-1 block">Upload Images</label>
|
<label className="text-xs font-medium text-slate-600 mb-1 block">Upload Images</label>
|
||||||
<div className="border-2 border-dashed border-slate-200 rounded-lg p-6 text-center">
|
<div className="border-2 border-dashed border-slate-200 rounded-lg p-6 text-center hover:border-accent cursor-pointer">
|
||||||
<Image className="w-8 h-8 text-slate-300 mx-auto mb-2" />
|
<Image className="w-8 h-8 text-slate-300 mx-auto mb-2" />
|
||||||
<p className="text-sm text-slate-500">Drag and drop or click to upload</p>
|
<p className="text-sm text-slate-500">Click to upload images</p>
|
||||||
|
<p className="text-xs text-slate-400">JPG, PNG up to 5MB</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -881,7 +1045,7 @@ export default function MaintenancePage() {
|
|||||||
<button onClick={() => setShowAddNoteModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50">
|
<button onClick={() => setShowAddNoteModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50">
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleAddNote}
|
onClick={handleAddNote}
|
||||||
disabled={!newNoteText.trim()}
|
disabled={!newNoteText.trim()}
|
||||||
className="px-4 py-2 bg-accent text-white rounded-lg text-sm hover:bg-accent-dark disabled:opacity-50"
|
className="px-4 py-2 bg-accent text-white rounded-lg text-sm hover:bg-accent-dark disabled:opacity-50"
|
||||||
@@ -914,7 +1078,7 @@ export default function MaintenancePage() {
|
|||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-slate-600 mb-2 block">Payment Source</label>
|
<label className="text-sm font-medium text-slate-600 mb-2 block">Payment Source</label>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => handlePayment('company')}
|
onClick={() => handlePayment('company')}
|
||||||
className="w-full p-4 border-2 border-slate-200 rounded-lg text-left hover:border-accent hover:bg-accent-light/30 transition-colors"
|
className="w-full p-4 border-2 border-slate-200 rounded-lg text-left hover:border-accent hover:bg-accent-light/30 transition-colors"
|
||||||
>
|
>
|
||||||
@@ -928,7 +1092,7 @@ export default function MaintenancePage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handlePayment('biker')}
|
onClick={() => handlePayment('biker')}
|
||||||
className="w-full p-4 border-2 border-slate-200 rounded-lg text-left hover:border-accent hover:bg-accent-light/30 transition-colors"
|
className="w-full p-4 border-2 border-slate-200 rounded-lg text-left hover:border-accent hover:bg-accent-light/30 transition-colors"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user