2026-04-22 01:02:45 +06:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import { useState, use } from 'react';
|
|
|
|
|
import Link from 'next/link';
|
|
|
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
|
import {
|
|
|
|
|
User, Phone, Mail, MapPin, Calendar, Heart, Briefcase, Car, Navigation,
|
|
|
|
|
FileText, Clock, TrendingUp, CreditCard, Shield, Award, Star, Activity,
|
|
|
|
|
Eye, Edit, Trash2, ArrowLeft, PhoneCall, MessageCircle, CheckCircle, XCircle,
|
2026-04-26 14:56:12 +06:00
|
|
|
AlertTriangle, DollarSign as DollarSignIcon, Wallet, Bike as BikeIcon, Wrench, Ban, MoreHorizontal, Copy,
|
|
|
|
|
ExternalLink, Download, Upload, Bell, MessageSquare, Send, RefreshCcw, Image
|
2026-04-22 01:02:45 +06:00
|
|
|
} from 'lucide-react';
|
|
|
|
|
|
|
|
|
|
interface DrivingLicense {
|
|
|
|
|
number: string;
|
|
|
|
|
issueDate: string;
|
|
|
|
|
expiryDate: string;
|
|
|
|
|
class: string;
|
|
|
|
|
status: 'valid' | 'expired' | 'suspended';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface Document {
|
|
|
|
|
type: 'nid' | 'passport' | 'driving_license' | 'other';
|
|
|
|
|
number: string;
|
|
|
|
|
verified: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface Biker {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
email: string;
|
|
|
|
|
phone: string;
|
|
|
|
|
alternatePhone?: string;
|
|
|
|
|
status: 'active' | 'pending' | 'inactive' | 'blocked';
|
|
|
|
|
createdAt: string;
|
|
|
|
|
location: string;
|
|
|
|
|
address: string;
|
|
|
|
|
dateOfBirth: string;
|
|
|
|
|
gender: 'male' | 'female' | 'other';
|
|
|
|
|
bloodGroup: string;
|
|
|
|
|
occupation: string;
|
|
|
|
|
emergencyContact: string;
|
|
|
|
|
emergencyPhone: string;
|
|
|
|
|
emergencyRelation: string;
|
|
|
|
|
drivingLicense: DrivingLicense;
|
|
|
|
|
documents: Document[];
|
|
|
|
|
gpsDeviceId?: string;
|
|
|
|
|
gpsPhone?: string;
|
|
|
|
|
totalRides: number;
|
|
|
|
|
totalDistance: number;
|
|
|
|
|
totalRideHours: number;
|
|
|
|
|
totalSpent: number;
|
|
|
|
|
currentBike?: string;
|
|
|
|
|
bikePlate?: string;
|
|
|
|
|
depositPaid: number;
|
|
|
|
|
walletBalance: number;
|
|
|
|
|
rating: number;
|
|
|
|
|
totalRatings: number;
|
|
|
|
|
responseTime: number;
|
|
|
|
|
cancellationRate: number;
|
|
|
|
|
kycStatus: 'verified' | 'pending' | 'rejected';
|
|
|
|
|
membershipType: 'free' | 'basic' | 'premium' | 'vip';
|
|
|
|
|
insuranceStatus: 'active' | 'expired' | 'none';
|
|
|
|
|
insuranceExpiry?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
lastRideAt?: string;
|
|
|
|
|
firstRideAt?: string;
|
|
|
|
|
joinedFrom: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const mockBikers: Biker[] = [
|
|
|
|
|
{
|
|
|
|
|
id: 'B001', name: 'Rahim Ahmed', email: 'rahim@email.com', phone: '01712345678', alternatePhone: '01912345678',
|
|
|
|
|
status: 'active', createdAt: '2024-01-15', location: 'Gulshan, Dhaka',
|
|
|
|
|
address: 'House 12, Road 5, Gulshan 1, Dhaka 1212', dateOfBirth: '1995-03-15', gender: 'male', bloodGroup: 'O+',
|
|
|
|
|
occupation: 'Student', emergencyContact: 'Karim Ahmed', emergencyPhone: '01712345679', emergencyRelation: 'Brother',
|
|
|
|
|
drivingLicense: { number: 'DL2024001234', issueDate: '2023-01-15', expiryDate: '2033-01-14', class: 'M', status: 'valid' },
|
|
|
|
|
documents: [{ type: 'nid', number: '1234567890', verified: true }],
|
|
|
|
|
gpsDeviceId: 'GP-001234', gpsPhone: '01712345678',
|
|
|
|
|
totalRides: 156, totalDistance: 2340, totalRideHours: 468, totalSpent: 54500,
|
|
|
|
|
currentBike: 'Etron ET50', bikePlate: 'Dhaka Metro Cha-1234', depositPaid: 5000, walletBalance: 1250,
|
|
|
|
|
rating: 4.8, totalRatings: 156, responseTime: 2.5, cancellationRate: 2.1,
|
|
|
|
|
kycStatus: 'verified', membershipType: 'premium', insuranceStatus: 'active', insuranceExpiry: '2025-01-14',
|
|
|
|
|
notes: 'Reliable rider, frequently uses premium service', lastRideAt: '2024-03-21', firstRideAt: '2024-01-15', joinedFrom: 'App Store',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'B002', name: 'Karim Hasan', email: 'karim@email.com', phone: '01712345679',
|
|
|
|
|
status: 'active', createdAt: '2024-02-20', location: 'Banani, Dhaka',
|
|
|
|
|
address: 'House 5, Road 11, Banani, Dhaka 1213', dateOfBirth: '1990-07-22', gender: 'male', bloodGroup: 'B+',
|
|
|
|
|
occupation: 'Business', emergencyContact: 'Rahim Hasan', emergencyPhone: '01712345678', emergencyRelation: 'Friend',
|
|
|
|
|
drivingLicense: { number: 'DL2024005678', issueDate: '2023-06-20', expiryDate: '2033-06-19', class: 'M', status: 'valid' },
|
|
|
|
|
documents: [{ type: 'nid', number: '1234567891', verified: true }],
|
|
|
|
|
gpsDeviceId: 'GP-001235',
|
|
|
|
|
totalRides: 89, totalDistance: 1335, totalRideHours: 267, totalSpent: 31200,
|
|
|
|
|
currentBike: 'Yadea DT3', bikePlate: 'Dhaka Metro Cha-5678', depositPaid: 5000, walletBalance: 800,
|
|
|
|
|
rating: 4.5, totalRatings: 89, responseTime: 3.2, cancellationRate: 4.5,
|
|
|
|
|
kycStatus: 'verified', membershipType: 'basic', insuranceStatus: 'active', insuranceExpiry: '2025-02-19', joinedFrom: 'Website',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'B003', name: 'Jamal Mahmud', email: 'jamal@email.com', phone: '01712345680',
|
|
|
|
|
status: 'pending', createdAt: '2024-03-18', location: 'Uttara, Dhaka',
|
|
|
|
|
address: 'Sector 10, Uttara, Dhaka 1230', dateOfBirth: '1988-11-05', gender: 'male', bloodGroup: 'A+',
|
|
|
|
|
occupation: 'Job Holder', emergencyContact: 'Mahmud Ali', emergencyPhone: '01712345681', emergencyRelation: 'Father',
|
|
|
|
|
drivingLicense: { number: '', issueDate: '', expiryDate: '', class: 'M', status: 'valid' },
|
|
|
|
|
documents: [{ type: 'nid', number: '1234567892', verified: false }],
|
|
|
|
|
totalRides: 0, totalDistance: 0, totalRideHours: 0, totalSpent: 0,
|
|
|
|
|
depositPaid: 0, walletBalance: 0, rating: 0, totalRatings: 0, responseTime: 0, cancellationRate: 0,
|
|
|
|
|
kycStatus: 'pending', membershipType: 'free', insuranceStatus: 'none', joinedFrom: 'Referral',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'B004', name: 'Ali Rahman', email: 'ali@email.com', phone: '01712345681',
|
|
|
|
|
status: 'active', createdAt: '2023-12-01', location: 'Dhanmondi, Dhaka',
|
|
|
|
|
address: 'House 27, Road 8, Dhanmondi, Dhaka 1205', dateOfBirth: '1992-06-10', gender: 'male', bloodGroup: 'AB+',
|
|
|
|
|
occupation: 'Engineer', emergencyContact: 'Rahman Ali', emergencyPhone: '01712345682', emergencyRelation: 'Brother',
|
|
|
|
|
drivingLicense: { number: 'DL202301234', issueDate: '2023-05-10', expiryDate: '2033-05-09', class: 'M', status: 'valid' },
|
|
|
|
|
documents: [{ type: 'nid', number: '1234567893', verified: true }],
|
|
|
|
|
gpsDeviceId: 'GP-001236',
|
|
|
|
|
totalRides: 234, totalDistance: 3510, totalRideHours: 702, totalSpent: 81900,
|
|
|
|
|
currentBike: 'AIMA Lightning', bikePlate: 'Dhaka Metro Cha-9012', depositPaid: 5000, walletBalance: 2100,
|
|
|
|
|
rating: 4.9, totalRatings: 234, responseTime: 1.8, cancellationRate: 1.2,
|
|
|
|
|
kycStatus: 'verified', membershipType: 'vip', insuranceStatus: 'active', insuranceExpiry: '2024-12-01', joinedFrom: 'Facebook',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'B005', name: 'Mostafa Kamal', email: 'mostafa@email.com', phone: '01712345682',
|
|
|
|
|
status: 'inactive', createdAt: '2023-08-15', location: 'Mirpur, Dhaka',
|
|
|
|
|
address: 'Mirpur 1, Dhaka 1216', dateOfBirth: '1997-02-28', gender: 'male', bloodGroup: 'O-',
|
|
|
|
|
occupation: 'Teacher', emergencyContact: 'Kamal Mostafa', emergencyPhone: '01712345683', emergencyRelation: 'Father',
|
|
|
|
|
drivingLicense: { number: 'DL2022009876', issueDate: '2022-08-15', expiryDate: '2024-08-14', class: 'M', status: 'expired' },
|
|
|
|
|
documents: [{ type: 'nid', number: '1234567894', verified: true }],
|
|
|
|
|
totalRides: 45, totalDistance: 675, totalRideHours: 135, totalSpent: 15750,
|
|
|
|
|
depositPaid: 5000, walletBalance: 0, rating: 3.8, totalRatings: 45, responseTime: 4.5, cancellationRate: 8.9,
|
|
|
|
|
kycStatus: 'verified', membershipType: 'free', insuranceStatus: 'expired', insuranceExpiry: '2024-01-14', joinedFrom: 'App Store',
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const statusColors: Record<string, string> = {
|
|
|
|
|
active: 'bg-green-100 text-green-700',
|
|
|
|
|
pending: 'bg-amber-100 text-amber-700',
|
|
|
|
|
inactive: 'bg-slate-100 text-slate-500',
|
|
|
|
|
blocked: 'bg-red-100 text-red-700',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const kycColors: Record<string, string> = {
|
|
|
|
|
verified: 'bg-green-100 text-green-700',
|
|
|
|
|
pending: 'bg-amber-100 text-amber-700',
|
|
|
|
|
rejected: 'bg-red-100 text-red-700',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const membershipColors: Record<string, string> = {
|
|
|
|
|
free: 'bg-slate-100 text-slate-600',
|
|
|
|
|
basic: 'bg-blue-100 text-blue-700',
|
|
|
|
|
premium: 'bg-purple-100 text-purple-700',
|
|
|
|
|
vip: 'bg-amber-100 text-amber-700',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
interface PageProps {
|
|
|
|
|
params: Promise<{ id: string }>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function BikerDetailPage({ params }: PageProps) {
|
|
|
|
|
const resolvedParams = use(params);
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const [activeTab, setActiveTab] = useState('personal');
|
|
|
|
|
|
|
|
|
|
const biker = mockBikers.find(b => b.id === resolvedParams.id) || mockBikers[0];
|
|
|
|
|
|
|
|
|
|
const tabs = [
|
|
|
|
|
{ id: 'personal', label: 'Personal', icon: User },
|
|
|
|
|
{ id: 'license', label: 'License & GPS', icon: Car },
|
|
|
|
|
{ id: 'documents', label: 'Documents', icon: FileText },
|
2026-04-26 14:56:12 +06:00
|
|
|
{ id: 'rent', label: 'Rent History', icon: DollarSignIcon },
|
|
|
|
|
{ id: 'bike', label: 'Bike', icon: BikeIcon },
|
|
|
|
|
// { id: 'reviews', label: 'Reviews', icon: MessageCircle },
|
|
|
|
|
// { id: 'stats', label: 'Statistics', icon: TrendingUp },
|
2026-04-22 01:02:45 +06:00
|
|
|
{ id: 'account', label: 'Account', icon: CreditCard },
|
|
|
|
|
{ id: 'activity', label: 'Activity', icon: Activity },
|
|
|
|
|
];
|
|
|
|
|
|
2026-04-26 14:56:12 +06:00
|
|
|
const rentHistory = [
|
|
|
|
|
{ id: 'R001', date: '2024-03-21', amount: 50, status: 'paid', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
{ id: 'R002', date: '2024-03-20', amount: 50, status: 'paid', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
{ id: 'R003', date: '2024-03-19', amount: 50, status: 'paid', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
{ id: 'R004', date: '2024-03-18', amount: 50, status: 'paid', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
{ id: 'R005', date: '2024-03-17', amount: 50, status: 'paid', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
{ id: 'R006', date: '2024-03-16', amount: 50, status: 'paid', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
{ id: 'R007', date: '2024-03-15', amount: 50, status: 'paid', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
{ id: 'R008', date: '2024-03-14', amount: 0, status: 'pending', bikeId: 'EV001', plan: 'Single' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const rentedBikesHistory = [
|
|
|
|
|
{ id: 'RB001', bikeId: 'EV001', bikeName: 'AIMA Lightning', plate: 'Dhaka Metro Cha-9012', startDate: '2024-03-14', endDate: null, status: 'active', plan: 'Single', dailyRate: 50, totalDays: 8, totalRent: 400 },
|
|
|
|
|
{ id: 'RB002', bikeId: 'EV003', bikeName: 'Yadea DT3', plate: 'Dhaka Metro Cha-5678', startDate: '2024-02-01', endDate: '2024-03-13', status: 'returned', plan: 'Rent-to-Own', dailyRate: 45, totalDays: 42, totalRent: 1890 },
|
|
|
|
|
{ id: 'RB003', bikeId: 'EV005', bikeName: 'Etron ET50', plate: 'Dhaka Metro Cha-1234', startDate: '2024-01-10', endDate: '2024-01-31', status: 'returned', plan: 'Shared', dailyRate: 60, totalDays: 22, totalRent: 1320 },
|
|
|
|
|
];
|
|
|
|
|
|
2026-04-22 01:02:45 +06:00
|
|
|
return (
|
|
|
|
|
<div className="p-4 lg:p-6 min-h-screen">
|
|
|
|
|
<div className="flex items-center gap-3 mb-4">
|
|
|
|
|
<button onClick={() => router.back()} className="p-2 hover:bg-slate-100 rounded-lg lg:hidden">
|
|
|
|
|
<ArrowLeft className="w-5 h-5 text-slate-600" />
|
|
|
|
|
</button>
|
|
|
|
|
<Link href="/admin/bikers" className="p-2 hover:bg-slate-100 rounded-lg hidden lg:block">
|
|
|
|
|
<ArrowLeft className="w-5 h-5 text-slate-600" />
|
|
|
|
|
</Link>
|
|
|
|
|
<div className="flex-1">
|
|
|
|
|
<h1 className="text-xl lg:text-2xl font-extrabold text-slate-800">Biker Details</h1>
|
|
|
|
|
<p className="text-sm text-slate-500">View and manage biker profile</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<button className="p-2 border border-slate-200 rounded-lg hover:bg-slate-50">
|
|
|
|
|
<Bell className="w-5 h-5 text-slate-600" />
|
|
|
|
|
</button>
|
|
|
|
|
<button className="p-2 border border-slate-200 rounded-lg hover:bg-slate-50">
|
|
|
|
|
<MessageSquare className="w-5 h-5 text-slate-600" />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 overflow-hidden mb-4">
|
|
|
|
|
<div className="p-4 lg:p-6 flex flex-col lg:flex-row lg:items-center gap-4">
|
|
|
|
|
<div className="w-20 h-20 rounded-full bg-blue-100 flex items-center justify-center">
|
|
|
|
|
<span className="text-3xl font-bold text-blue-600">{biker.name.charAt(0)}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex-1">
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<h2 className="text-xl lg:text-2xl font-bold text-slate-800">{biker.name}</h2>
|
|
|
|
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${statusColors[biker.status]}`}>
|
|
|
|
|
{biker.status === 'active' && <Activity className="w-3 h-3" />}
|
|
|
|
|
{biker.status === 'pending' && <Clock className="w-3 h-3" />}
|
|
|
|
|
{biker.status === 'blocked' && <Ban className="w-3 h-3" />}
|
|
|
|
|
{biker.status}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-sm text-slate-500">ID: {biker.id} • {biker.location}</p>
|
|
|
|
|
<div className="flex flex-wrap items-center gap-2 mt-2">
|
|
|
|
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${kycColors[biker.kycStatus]}`}>
|
|
|
|
|
{biker.kycStatus === 'verified' && <CheckCircle className="w-3 h-3" />}
|
|
|
|
|
{biker.kycStatus === 'pending' && <Clock className="w-3 h-3" />}
|
|
|
|
|
KYC: {biker.kycStatus}
|
|
|
|
|
</span>
|
|
|
|
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${membershipColors[biker.membershipType]}`}>
|
|
|
|
|
<Award className="w-3 h-3" /> {biker.membershipType}
|
|
|
|
|
</span>
|
|
|
|
|
{biker.rating > 0 && (
|
|
|
|
|
<span className="inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full bg-amber-100 text-amber-700">
|
|
|
|
|
<Star className="w-3 h-3" /> {biker.rating} ({biker.totalRatings})
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex gap-2">
|
|
|
|
|
<button className="flex-1 lg:flex-none px-4 py-2 bg-blue-600 text-white rounded-lg font-semibold text-sm hover:bg-blue-700 flex items-center justify-center gap-2">
|
|
|
|
|
<PhoneCall className="w-4 h-4" />
|
|
|
|
|
<span className="hidden lg:inline">Call</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button className="flex-1 lg:flex-none px-4 py-2 bg-green-600 text-white rounded-lg font-semibold text-sm hover:bg-green-700 flex items-center justify-center gap-2">
|
|
|
|
|
<MessageCircle className="w-4 h-4" />
|
|
|
|
|
<span className="hidden lg:inline">Message</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="border-t border-slate-100 overflow-x-auto">
|
|
|
|
|
<nav className="flex whitespace-nowrap">
|
|
|
|
|
{tabs.map(tab => {
|
|
|
|
|
const Icon = tab.icon;
|
|
|
|
|
return (
|
|
|
|
|
<button
|
|
|
|
|
key={tab.id}
|
|
|
|
|
onClick={() => setActiveTab(tab.id)}
|
|
|
|
|
className={`px-4 py-3 text-sm font-medium whitespace-nowrap border-b-2 transition-colors ${activeTab === tab.id
|
|
|
|
|
? 'border-accent text-accent'
|
|
|
|
|
: 'border-transparent text-slate-500 hover:text-slate-700'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<Icon className="w-4 h-4 inline mr-1" />
|
|
|
|
|
{tab.label}
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</nav>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 overflow-hidden mb-4">
|
|
|
|
|
{activeTab === 'personal' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
|
|
|
|
<User className="w-5 h-5 text-accent" /> Personal Information
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
|
|
<InfoCard label="Full Name" value={biker.name} />
|
|
|
|
|
<InfoCard label="Email" value={biker.email} />
|
|
|
|
|
<InfoCard label="Phone" value={biker.phone} />
|
|
|
|
|
<InfoCard label="Alternate Phone" value={biker.alternatePhone || 'Not provided'} />
|
|
|
|
|
<InfoCard label="Date of Birth" value={biker.dateOfBirth} />
|
|
|
|
|
<InfoCard label="Gender" value={biker.gender} />
|
|
|
|
|
<InfoCard label="Blood Group" value={biker.bloodGroup} />
|
|
|
|
|
<InfoCard label="Occupation" value={biker.occupation} />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<p className="text-xs text-slate-500 mb-1">Address</p>
|
|
|
|
|
<p className="text-sm text-slate-700 bg-slate-50 p-3 rounded-lg">{biker.address}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
|
|
|
|
<PhoneCall className="w-5 h-5 text-accent" /> Emergency Contact
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="bg-slate-50 p-4 rounded-lg space-y-3">
|
|
|
|
|
<InfoCard label="Contact Name" value={biker.emergencyContact} />
|
|
|
|
|
<InfoCard label="Relation" value={biker.emergencyRelation} />
|
|
|
|
|
<InfoCard label="Phone" value={biker.emergencyPhone} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'license' && (
|
|
|
|
|
<div className="p-4 lg:p-6 space-y-6">
|
|
|
|
|
<div>
|
|
|
|
|
<h3 className="font-semibold text-slate-800 mb-3 flex items-center gap-2">
|
|
|
|
|
<Car className="w-5 h-5 text-accent" /> Driving License
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="grid grid-cols-2 lg:grid-cols-3 gap-4">
|
|
|
|
|
<InfoCard label="License Number" value={biker.drivingLicense.number || 'Not provided'} />
|
|
|
|
|
<InfoCard label="Class" value={biker.drivingLicense.class} />
|
|
|
|
|
<InfoCard label="Status" value={biker.drivingLicense.status} highlight={biker.drivingLicense.status === 'valid' ? 'green' : 'red'} />
|
|
|
|
|
<InfoCard label="Issue Date" value={biker.drivingLicense.issueDate || 'N/A'} />
|
|
|
|
|
<InfoCard label="Expiry Date" value={biker.drivingLicense.expiryDate || 'N/A'} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<h3 className="font-semibold text-slate-800 mb-3 flex items-center gap-2">
|
|
|
|
|
<Navigation className="w-5 h-5 text-accent" /> GPS Tracking Device
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
|
|
<InfoCard label="Device ID" value={biker.gpsDeviceId || 'Not assigned'} />
|
|
|
|
|
<InfoCard label="Linked Phone" value={biker.gpsPhone || 'Not linked'} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'documents' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 mb-3 flex items-center gap-2">
|
|
|
|
|
<FileText className="w-5 h-5 text-accent" /> Uploaded Documents
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
|
|
|
{biker.documents.map((doc, idx) => (
|
|
|
|
|
<div key={idx} className="p-4 border border-slate-200 rounded-lg">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-medium text-slate-700 uppercase">{doc.type}</p>
|
|
|
|
|
<p className="text-sm text-slate-500">Number: {doc.number || 'N/A'}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${doc.verified ? 'bg-green-100 text-green-700' : 'bg-amber-100 text-amber-700'
|
|
|
|
|
}`}>
|
|
|
|
|
{doc.verified ? <CheckCircle className="w-3 h-3" /> : <Clock className="w-3 h-3" />}
|
|
|
|
|
{doc.verified ? 'Verified' : 'Pending'}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'reviews' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 mb-3 flex items-center gap-2">
|
|
|
|
|
<Star className="w-5 h-5 text-amber-500" /> Biker Reviews
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
{[
|
|
|
|
|
{ rider: 'Tashrif', rating: 5, comment: 'Great service! Very polite and quick.', date: '2024-03-20', rideId: 'R001' },
|
|
|
|
|
{ rider: 'Mahir', rating: 4, comment: 'Good ride, arrived on time.', date: '2024-03-19', rideId: 'R002' },
|
|
|
|
|
{ rider: 'Raisa', rating: 5, comment: 'Excellent experience. Would recommend!', date: '2024-03-18', rideId: 'R003' },
|
|
|
|
|
{ rider: 'Anika', rating: 3, comment: 'Ride was okay but a bit slow.', date: '2024-03-17', rideId: 'R004' },
|
|
|
|
|
{ rider: 'Ovi', rating: 5, comment: 'Best biker ever! Helped with luggage.', date: '2024-03-16', rideId: 'R005' },
|
|
|
|
|
].map((review, idx) => (
|
|
|
|
|
<div key={idx} className="p-4 border border-slate-200 rounded-lg">
|
|
|
|
|
<div className="flex items-start justify-between mb-2">
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<div className="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center">
|
|
|
|
|
<span className="text-xs font-bold text-blue-600">{review.rider.charAt(0)}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<p className="text-sm font-medium text-slate-700">{review.rider}</p>
|
|
|
|
|
<p className="text-xs text-slate-400">Ride: {review.rideId}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<span className="flex items-center gap-1 text-amber-500 font-bold text-sm">
|
|
|
|
|
{Array.from({ length: review.rating }).map((_, i) => (
|
|
|
|
|
<Star key={i} className="w-4 h-4 fill-current" />
|
|
|
|
|
))}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-sm text-slate-600 mb-2">{review.comment}</p>
|
|
|
|
|
<p className="text-xs text-slate-400">{review.date}</p>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-04-26 14:56:12 +06:00
|
|
|
{activeTab === 'rent' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<div className="flex items-center justify-between mb-4">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
|
|
|
|
<DollarSignIcon className="w-5 h-5 text-accent" /> Daily Rent History
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="flex gap-2">
|
|
|
|
|
<button className="px-3 py-1.5 bg-green-600 text-white text-sm rounded-lg hover:bg-green-700 flex items-center gap-1">
|
|
|
|
|
<Download className="w-4 h-4" /> Export
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 mb-6">
|
|
|
|
|
<div className="bg-green-50 border border-green-200 rounded-lg p-3">
|
|
|
|
|
<p className="text-xs text-green-600 font-medium">Total Paid</p>
|
|
|
|
|
<p className="text-lg font-bold text-green-700">৳{rentHistory.filter(r => r.status === 'paid').reduce((sum, r) => sum + r.amount, 0)}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="bg-red-50 border border-red-200 rounded-lg p-3">
|
|
|
|
|
<p className="text-xs text-red-600 font-medium">Pending</p>
|
|
|
|
|
<p className="text-lg font-bold text-red-700">৳{rentHistory.filter(r => r.status === 'pending').reduce((sum, r) => sum + r.amount, 0)}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3">
|
|
|
|
|
<p className="text-xs text-blue-600 font-medium">Total Days</p>
|
|
|
|
|
<p className="text-lg font-bold text-blue-700">{rentHistory.length}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="bg-slate-50 border border-slate-200 rounded-lg p-3">
|
|
|
|
|
<p className="text-xs text-slate-600 font-medium">Current Plan</p>
|
|
|
|
|
<p className="text-lg font-bold text-slate-700">{biker.membershipType}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white border border-slate-200 rounded-lg overflow-hidden">
|
|
|
|
|
<table className="w-full">
|
|
|
|
|
<thead className="bg-slate-50">
|
|
|
|
|
<tr>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Date</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Bike ID</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Plan</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Amount</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Status</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Actions</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody className="divide-y divide-slate-100">
|
|
|
|
|
{rentHistory.map(rent => (
|
|
|
|
|
<tr key={rent.id} className="hover:bg-slate-50">
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rent.date}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rent.bikeId}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rent.plan}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm font-semibold text-slate-700">৳{rent.amount}</td>
|
|
|
|
|
<td className="px-4 py-3">
|
|
|
|
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${rent.status === 'paid'
|
|
|
|
|
? 'bg-green-100 text-green-700'
|
|
|
|
|
: 'bg-amber-100 text-amber-700'
|
|
|
|
|
}`}>
|
|
|
|
|
{rent.status === 'paid' && <CheckCircle className="w-3 h-3" />}
|
|
|
|
|
{rent.status === 'pending' && <Clock className="w-3 h-3" />}
|
|
|
|
|
{rent.status}
|
|
|
|
|
</span>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-4 py-3">
|
|
|
|
|
{rent.status === 'pending' ? (
|
|
|
|
|
<button className="px-3 py-1.5 bg-accent text-white text-xs rounded-lg hover:bg-accent-dark">
|
|
|
|
|
Collect
|
|
|
|
|
</button>
|
|
|
|
|
) : (
|
|
|
|
|
<span className="text-xs text-slate-400">-</span>
|
|
|
|
|
)}
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
))}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'bike' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<div className="flex items-center justify-between mb-4">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
|
|
|
|
<BikeIcon className="w-5 h-5 text-accent" /> Rented Bikes Details
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="flex gap-2">
|
|
|
|
|
<button className="px-3 py-1.5 bg-accent text-white text-sm rounded-lg hover:bg-accent-dark flex items-center gap-1">
|
|
|
|
|
<Edit className="w-4 h-4" /> Update
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white border border-slate-200 rounded-lg p-4 mb-6">
|
|
|
|
|
<div className="flex items-center gap-4">
|
|
|
|
|
<div className="w-16 h-16 rounded-lg bg-slate-100 flex items-center justify-center">
|
|
|
|
|
<BikeIcon className="w-8 h-8 text-slate-400" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-semibold text-slate-700">{biker.currentBike || 'No Bike Assigned'}</p>
|
|
|
|
|
<p className="text-sm text-slate-500">Plate: {biker.bikePlate || 'N/A'}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
|
|
|
|
<div className="bg-white border border-slate-200 rounded-lg p-4">
|
|
|
|
|
<h4 className="font-medium text-slate-700 mb-4">Mileage</h4>
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
<div>
|
|
|
|
|
<label className="text-sm text-slate-500 block mb-1">Current Odometer (km)</label>
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
|
|
|
|
|
placeholder="Enter current reading"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="text-sm text-slate-500 block mb-1">Last Updated</label>
|
|
|
|
|
<p className="text-sm text-slate-700">{biker.lastRideAt || 'N/A'}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="text-sm text-slate-500 block mb-1">Total Distance</label>
|
|
|
|
|
<p className="text-lg font-bold text-blue-600">{biker.totalDistance.toLocaleString()} km</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white border border-slate-200 rounded-lg p-4">
|
|
|
|
|
<h4 className="font-medium text-slate-700 mb-4">Battery Health</h4>
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
<div>
|
|
|
|
|
<label className="text-sm text-slate-500 block mb-1">Battery Percentage</label>
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
|
|
|
|
|
placeholder="0-100"
|
|
|
|
|
/>
|
|
|
|
|
<span className="text-slate-500">%</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="text-sm text-slate-500 block mb-1">Health Status</label>
|
|
|
|
|
<span className="inline-flex items-center gap-1 text-sm font-medium px-2.5 py-1 rounded-full bg-green-100 text-green-700">
|
|
|
|
|
<CheckCircle className="w-4 h-4" /> Good
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="text-sm text-slate-500 block mb-1">Estimated Range</label>
|
|
|
|
|
<p className="text-lg font-bold text-green-600">85 km</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white border border-slate-200 rounded-lg p-4 mb-6">
|
|
|
|
|
<h4 className="font-medium text-slate-700 mb-4">Bike Images</h4>
|
|
|
|
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
|
|
|
|
<div className="aspect-square bg-slate-100 rounded-lg flex flex-col items-center justify-center">
|
|
|
|
|
<Image className="w-8 h-8 text-slate-400 mb-2" />
|
|
|
|
|
<span className="text-xs text-slate-500">Front</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="aspect-square bg-slate-100 rounded-lg flex flex-col items-center justify-center">
|
|
|
|
|
<Image className="w-8 h-8 text-slate-400 mb-2" />
|
|
|
|
|
<span className="text-xs text-slate-500">Back</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="aspect-square bg-slate-100 rounded-lg flex flex-col items-center justify-center">
|
|
|
|
|
<Image className="w-8 h-8 text-slate-400 mb-2" />
|
|
|
|
|
<span className="text-xs text-slate-500">Left Side</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="aspect-square bg-slate-100 rounded-lg flex flex-col items-center justify-center">
|
|
|
|
|
<Image className="w-8 h-8 text-slate-400 mb-2" />
|
|
|
|
|
<span className="text-xs text-slate-500">Right Side</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button className="mt-4 px-4 py-2 border border-dashed border-slate-300 rounded-lg text-sm text-slate-500 hover:border-accent hover:text-accent w-full">
|
|
|
|
|
+ Upload Images
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white border border-slate-200 rounded-lg p-4">
|
|
|
|
|
<h4 className="font-medium text-slate-700 mb-4">Notes</h4>
|
|
|
|
|
<textarea
|
|
|
|
|
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
|
|
|
|
|
rows={4}
|
|
|
|
|
placeholder="Add notes about the bike condition, issues, etc..."
|
|
|
|
|
></textarea>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="mt-6">
|
|
|
|
|
<h4 className="font-semibold text-slate-800 mb-4 flex items-center gap-2">
|
|
|
|
|
<Clock className="w-5 h-5 text-accent" /> Rented Bikes History
|
|
|
|
|
</h4>
|
|
|
|
|
<div className="bg-white border border-slate-200 rounded-lg overflow-hidden">
|
|
|
|
|
<table className="w-full">
|
|
|
|
|
<thead className="bg-slate-50">
|
|
|
|
|
<tr>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Bike</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Plate</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Plan</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Start Date</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">End Date</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Days</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Total Rent</th>
|
|
|
|
|
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase">Status</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody className="divide-y divide-slate-100">
|
|
|
|
|
{rentedBikesHistory.map(rental => (
|
|
|
|
|
<tr key={rental.id} className="hover:bg-slate-50">
|
|
|
|
|
<td className="px-4 py-3">
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<BikeIcon className="w-4 h-4 text-slate-400" />
|
|
|
|
|
<div>
|
|
|
|
|
<p className="text-sm font-medium text-slate-700">{rental.bikeName}</p>
|
|
|
|
|
<p className="text-xs text-slate-400">{rental.bikeId}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rental.plate}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rental.plan}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rental.startDate}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rental.endDate || '-'}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm text-slate-600">{rental.totalDays}</td>
|
|
|
|
|
<td className="px-4 py-3 text-sm font-semibold text-green-600">৳{rental.totalRent}</td>
|
|
|
|
|
<td className="px-4 py-3">
|
|
|
|
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${rental.status === 'active'
|
|
|
|
|
? 'bg-green-100 text-green-700'
|
|
|
|
|
: 'bg-slate-100 text-slate-600'
|
|
|
|
|
}`}>
|
|
|
|
|
{rental.status === 'active' && <Activity className="w-3 h-3" />}
|
|
|
|
|
{rental.status === 'returned' && <CheckCircle className="w-3 h-3" />}
|
|
|
|
|
{rental.status === 'active' ? 'Active' : 'Returned'}
|
|
|
|
|
</span>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
))}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-04-22 01:02:45 +06:00
|
|
|
{activeTab === 'stats' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
|
|
|
|
<StatCard label="Total Rides" value={biker.totalRides.toString()} icon={BikeIcon} color="text-blue-600" />
|
|
|
|
|
<StatCard label="Distance" value={`${biker.totalDistance.toLocaleString()} km`} icon={Navigation} color="text-green-600" />
|
|
|
|
|
<StatCard label="Ride Hours" value={biker.totalRideHours.toString()} icon={Clock} color="text-purple-600" />
|
|
|
|
|
<StatCard label="Rating" value={`★ ${biker.rating}`} icon={Star} color="text-amber-600" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="grid grid-cols-2 lg:grid-cols-3 gap-4">
|
|
|
|
|
<InfoCard label="Avg Response Time" value={`${biker.responseTime} min`} />
|
|
|
|
|
<InfoCard label="Cancellation Rate" value={`${biker.cancellationRate}%`} highlight={biker.cancellationRate > 5 ? 'red' : ''} />
|
|
|
|
|
<InfoCard label="Current Bike" value={biker.currentBike || 'None'} />
|
|
|
|
|
<InfoCard label="Plate Number" value={biker.bikePlate || 'N/A'} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'account' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
|
|
|
|
<CreditCard className="w-5 h-5 text-accent" /> Financial
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
|
|
<InfoCard label="Total Spent" value={`৳${biker.totalSpent.toLocaleString()}`} highlight="green" />
|
|
|
|
|
<InfoCard label="Wallet Balance" value={`৳${biker.walletBalance}`} highlight="blue" />
|
|
|
|
|
<InfoCard label="Deposit Paid" value={`৳${biker.depositPaid}`} />
|
|
|
|
|
<InfoCard label="Membership" value={biker.membershipType} highlight={biker.membershipType === 'vip' ? 'amber' : ''} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
|
|
|
|
<Shield className="w-5 h-5 text-accent" /> Verification & Insurance
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
|
|
<InfoCard label="KYC Status" value={biker.kycStatus} highlight={biker.kycStatus === 'verified' ? 'green' : 'amber'} />
|
|
|
|
|
<InfoCard label="Insurance" value={biker.insuranceStatus} highlight={biker.insuranceStatus === 'active' ? 'green' : biker.insuranceStatus === 'expired' ? 'red' : ''} />
|
|
|
|
|
<InfoCard label="Insurance Expiry" value={biker.insuranceExpiry || 'N/A'} />
|
|
|
|
|
<InfoCard label="Joined From" value={biker.joinedFrom} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{activeTab === 'activity' && (
|
|
|
|
|
<div className="p-4 lg:p-6">
|
|
|
|
|
<h3 className="font-semibold text-slate-800 mb-3 flex items-center gap-2">
|
|
|
|
|
<Activity className="w-5 h-5 text-accent" /> Activity Log
|
|
|
|
|
</h3>
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
{[
|
|
|
|
|
{ action: 'Profile Updated', date: '2024-03-21', icon: Edit },
|
|
|
|
|
{ action: 'Ride Completed', date: '2024-03-21', icon: BikeIcon },
|
|
|
|
|
{ action: 'Wallet Top Up - ৳2000', date: '2024-03-20', icon: Wallet },
|
|
|
|
|
{ action: 'KYC Verified', date: '2024-01-15', icon: CheckCircle },
|
|
|
|
|
].map((log, idx) => {
|
|
|
|
|
const Icon = log.icon;
|
|
|
|
|
return (
|
|
|
|
|
<div key={idx} className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
|
|
|
<Icon className="w-5 h-5 text-slate-400" />
|
|
|
|
|
<div className="flex-1">
|
|
|
|
|
<p className="text-sm font-medium text-slate-700">{log.action}</p>
|
|
|
|
|
<p className="text-xs text-slate-400">{log.date}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* <div className="fixed bottom-0 left-0 right-0 p-4 bg-white border-t border-slate-200 lg:relative lg:bg-transparent lg:border-0 lg:p-0 z-50">
|
|
|
|
|
<div className="flex gap-2 max-w-2xl mx-auto">
|
|
|
|
|
<button className="flex-1 py-2 px-4 bg-accent text-white rounded-lg font-semibold text-sm flex items-center justify-center gap-2 hover:bg-accent-dark transition-colors">
|
|
|
|
|
<Edit className="w-4 h-4" />
|
|
|
|
|
<span>Edit Biker</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button className="flex-1 py-2 px-4 border border-red-200 text-red-600 rounded-lg font-semibold text-sm flex items-center justify-center gap-2 hover:bg-red-50 transition-colors">
|
|
|
|
|
<Trash2 className="w-4 h-4" />
|
|
|
|
|
<span>Delete</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div> */}
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function InfoCard({ label, value, highlight }: { label: string; value: string; highlight?: string }) {
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<p className="text-xs text-slate-500 mb-1">{label}</p>
|
|
|
|
|
<p className={`text-sm font-medium ${highlight === 'green' ? 'text-green-600' :
|
|
|
|
|
highlight === 'red' ? 'text-red-600' :
|
|
|
|
|
highlight === 'blue' ? 'text-blue-600' :
|
|
|
|
|
highlight === 'amber' ? 'text-amber-600' :
|
|
|
|
|
'text-slate-700'
|
|
|
|
|
}`}>{value}</p>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function StatCard({ label, value, icon: Icon, color }: { label: string; value: string; icon: any; color: string }) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="p-4 bg-slate-50 rounded-lg">
|
|
|
|
|
<Icon className={`w-5 h-5 ${color} mb-2`} />
|
|
|
|
|
<p className="text-lg font-bold text-slate-800">{value}</p>
|
|
|
|
|
<p className="text-xs text-slate-500">{label}</p>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|