diff --git a/src/app/admin/hub/[id]/page.tsx b/src/app/admin/hub/[id]/page.tsx index 731bd9f..46913ef 100644 --- a/src/app/admin/hub/[id]/page.tsx +++ b/src/app/admin/hub/[id]/page.tsx @@ -4,7 +4,8 @@ import { useState, useEffect } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { ArrowLeft, MapPin, Phone, Clock, Bike, Plus, X, Edit, Save, Trash2, - Navigation, User, Wallet, DollarSign, CheckCircle, AlertTriangle, Battery + Navigation, User, Wallet, DollarSign, CheckCircle, AlertTriangle, Battery, + Mail, Calendar, Briefcase, Users, Search, UserPlus } from 'lucide-react'; interface Hub { @@ -90,6 +91,70 @@ const mockHubRentals: RentalInfo[] = [ { id: 'RNT-003', userName: 'Jamal Uddin', bike: 'AIMA EM5', plate: 'Dhaka Metro Ko-1234', startDate: '2024-02-01', type: 'shared', status: 'pending', dailyRate: 150, totalPaid: 450 }, ]; +interface Employee { + id: string; + name: string; + role: 'Manager' | 'Accountant' | 'Staff' | 'Technician' | 'Support'; + email: string; + phone: string; + status: 'Active' | 'On Leave' | 'Inactive'; + joiningDate: string; + shift: 'Morning' | 'Evening' | 'Night' | 'Full-time'; +} + +const mockHubEmployees: Employee[] = [ + { + id: 'EMP-001', + name: 'Arif Rahman', + role: 'Manager', + email: 'arif.rahman@jaiben.com', + phone: '+8801711223344', + status: 'Active', + joiningDate: '2023-01-10', + shift: 'Full-time', + }, + { + id: 'EMP-002', + name: 'Tasmia Chowdhury', + role: 'Accountant', + email: 'tasmia.c@jaiben.com', + phone: '+8801722334455', + status: 'Active', + joiningDate: '2023-03-15', + shift: 'Morning', + }, + { + id: 'EMP-003', + name: 'Kamrul Islam', + role: 'Staff', + email: 'kamrul.i@jaiben.com', + phone: '+8801733445566', + status: 'Active', + joiningDate: '2023-06-20', + shift: 'Evening', + }, + { + id: 'EMP-004', + name: 'Mizanur Rahman', + role: 'Technician', + email: 'mizan.r@jaiben.com', + phone: '+8801744556677', + status: 'Active', + joiningDate: '2023-08-01', + shift: 'Morning', + }, + { + id: 'EMP-005', + name: 'Sujon Ali', + role: 'Support', + email: 'sujon.a@jaiben.com', + phone: '+8801755667788', + status: 'On Leave', + joiningDate: '2023-11-15', + shift: 'Night', + }, +]; + export default function HubDetailPage() { const params = useParams(); const router = useRouter(); @@ -101,7 +166,23 @@ export default function HubDetailPage() { const [rentals, setRentals] = useState(mockHubRentals); const [editMode, setEditMode] = useState(false); const [editForm, setEditForm] = useState(hub); - const [activeTab, setActiveTab] = useState<'overview' | 'bikes' | 'batteries' | 'rentals'>('overview'); + const [activeTab, setActiveTab] = useState<'overview' | 'employees' | 'bikes' | 'batteries' | 'rentals'>('overview'); + const [employees, setEmployees] = useState(mockHubEmployees); + const [employeeSearch, setEmployeeSearch] = useState(''); + const [roleFilter, setRoleFilter] = useState('All'); + const [statusFilter, setStatusFilter] = useState('All'); + const [addEmployeeModal, setAddEmployeeModal] = useState(false); + const [editingEmployee, setEditingEmployee] = useState(null); + const [employeeForm, setEmployeeForm] = useState>({ + name: '', + role: 'Staff', + email: '', + phone: '', + status: 'Active', + joiningDate: new Date().toISOString().split('T')[0], + shift: 'Full-time' + }); + const [deleteEmployeeModal, setDeleteEmployeeModal] = useState(null); const [assignModal, setAssignModal] = useState(null); const [selectedBike, setSelectedBike] = useState(''); const [addBikeModal, setAddBikeModal] = useState(false); @@ -191,6 +272,15 @@ export default function HubDetailPage() { > Overview + + + + {/* Search & Filter Toolbar */} +
+
+ + setEmployeeSearch(e.target.value)} + placeholder="Search by name, email, phone or ID..." + className="w-full pl-9 pr-4 py-2 border border-slate-200 rounded-lg text-sm bg-white focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent transition-all" + /> +
+
+ + +
+
+ + {/* Roster Cards Grid */} + {employees.filter(emp => { + const matchesSearch = + emp.name.toLowerCase().includes(employeeSearch.toLowerCase()) || + emp.email.toLowerCase().includes(employeeSearch.toLowerCase()) || + emp.phone.includes(employeeSearch) || + emp.id.toLowerCase().includes(employeeSearch.toLowerCase()); + const matchesRole = roleFilter === 'All' || emp.role === roleFilter; + const matchesStatus = statusFilter === 'All' || emp.status === statusFilter; + return matchesSearch && matchesRole && matchesStatus; + }).length === 0 ? ( +
+ +

No employees match your search or filter criteria.

+
+ ) : ( +
+ {employees.filter(emp => { + const matchesSearch = + emp.name.toLowerCase().includes(employeeSearch.toLowerCase()) || + emp.email.toLowerCase().includes(employeeSearch.toLowerCase()) || + emp.phone.includes(employeeSearch) || + emp.id.toLowerCase().includes(employeeSearch.toLowerCase()); + const matchesRole = roleFilter === 'All' || emp.role === roleFilter; + const matchesStatus = statusFilter === 'All' || emp.status === statusFilter; + return matchesSearch && matchesRole && matchesStatus; + }).map(emp => { + const roleConfig: Record = { + Manager: { badge: 'bg-emerald-100 text-emerald-800 border-emerald-200', circle: 'bg-emerald-50 text-emerald-600', text: 'text-emerald-700' }, + Accountant: { badge: 'bg-blue-100 text-blue-800 border-blue-200', circle: 'bg-blue-50 text-blue-600', text: 'text-blue-700' }, + Staff: { badge: 'bg-purple-100 text-purple-800 border-purple-200', circle: 'bg-purple-50 text-purple-600', text: 'text-purple-700' }, + Technician: { badge: 'bg-amber-100 text-amber-800 border-amber-200', circle: 'bg-amber-50 text-amber-600', text: 'text-amber-700' }, + Support: { badge: 'bg-orange-100 text-orange-800 border-orange-200', circle: 'bg-orange-50 text-orange-600', text: 'text-orange-700' }, + }; + const style = roleConfig[emp.role] || roleConfig.Staff; + + return ( +
+
+
+
+
+ {emp.name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase()} +
+
+

{emp.name}

+ {emp.id} +
+
+ + {emp.role} + +
+ +
+
+ + {emp.email} +
+
+ + {emp.phone} +
+
+ + Shift: {emp.shift} +
+
+ + Joined: {emp.joiningDate} +
+
+
+ +
+ + + {emp.status} + + +
+ + +
+
+
+ ); + })} +
+ )} + + )} + {activeTab === 'bikes' && (
@@ -745,6 +1023,175 @@ export default function HubDetailPage() {
)} + + {addEmployeeModal && ( +
+
+
+

{editingEmployee ? 'Edit Employee Details' : 'Register New Employee'}

+ +
+
+
+ + setEmployeeForm(f => ({ ...f, name: e.target.value }))} + placeholder="e.g. Arif Rahman" + className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent transition-all" + /> +
+ +
+
+ + +
+
+ + +
+
+ +
+ + setEmployeeForm(f => ({ ...f, email: e.target.value }))} + placeholder="e.g. arif.rahman@jaiben.com" + className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent transition-all" + /> +
+ +
+ + setEmployeeForm(f => ({ ...f, phone: e.target.value }))} + placeholder="e.g. +8801711223344" + className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent transition-all" + /> +
+ +
+
+ + +
+
+ + setEmployeeForm(f => ({ ...f, joiningDate: e.target.value }))} + className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent transition-all" + /> +
+
+
+
+ + +
+
+
+ )} + + {deleteEmployeeModal && ( +
+
+
+
+ +
+

Remove Employee

+

+ Are you sure you want to remove {deleteEmployeeModal.name} from Gulshan Head Office's operational roster? +

+
+

ID: {deleteEmployeeModal.id}

+

Role: {deleteEmployeeModal.role}

+
+
+
+ + +
+
+
+ )} ); } \ No newline at end of file diff --git a/src/app/admin/investors/[id]/page.tsx b/src/app/admin/investors/[id]/page.tsx index 347a6e8..0c735a6 100644 --- a/src/app/admin/investors/[id]/page.tsx +++ b/src/app/admin/investors/[id]/page.tsx @@ -1960,7 +1960,7 @@ export default function InvestorDetailPage() {
-

EV Investment Plans

+

Investment Plans

Manage investment portfolios for this investor