feat: add employee management module with roster, search, and filtering to hub details page
This commit is contained in:
@@ -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<RentalInfo[]>(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<Employee[]>(mockHubEmployees);
|
||||
const [employeeSearch, setEmployeeSearch] = useState('');
|
||||
const [roleFilter, setRoleFilter] = useState<string>('All');
|
||||
const [statusFilter, setStatusFilter] = useState<string>('All');
|
||||
const [addEmployeeModal, setAddEmployeeModal] = useState(false);
|
||||
const [editingEmployee, setEditingEmployee] = useState<Employee | null>(null);
|
||||
const [employeeForm, setEmployeeForm] = useState<Omit<Employee, 'id'>>({
|
||||
name: '',
|
||||
role: 'Staff',
|
||||
email: '',
|
||||
phone: '',
|
||||
status: 'Active',
|
||||
joiningDate: new Date().toISOString().split('T')[0],
|
||||
shift: 'Full-time'
|
||||
});
|
||||
const [deleteEmployeeModal, setDeleteEmployeeModal] = useState<Employee | null>(null);
|
||||
const [assignModal, setAssignModal] = useState<BatteryInfo | null>(null);
|
||||
const [selectedBike, setSelectedBike] = useState('');
|
||||
const [addBikeModal, setAddBikeModal] = useState(false);
|
||||
@@ -191,6 +272,15 @@ export default function HubDetailPage() {
|
||||
>
|
||||
Overview
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('employees')}
|
||||
className={`py-4 text-sm font-medium border-b-2 transition-colors ${activeTab === 'employees'
|
||||
? 'border-accent text-accent'
|
||||
: 'border-transparent text-slate-500 hover:text-slate-700'
|
||||
}`}
|
||||
>
|
||||
Employees ({employees.length})
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('bikes')}
|
||||
className={`py-4 text-sm font-medium border-b-2 transition-colors ${activeTab === 'bikes'
|
||||
@@ -376,6 +466,194 @@ export default function HubDetailPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'employees' && (
|
||||
<div>
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6">
|
||||
<div>
|
||||
<h3 className="font-bold text-slate-800 text-lg">Hub Employees ({employees.length})</h3>
|
||||
<p className="text-sm text-slate-500 mt-0.5">Manage and track hub operational personnel and roles</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditingEmployee(null);
|
||||
setEmployeeForm({
|
||||
name: '',
|
||||
role: 'Staff',
|
||||
email: '',
|
||||
phone: '',
|
||||
status: 'Active',
|
||||
joiningDate: new Date().toISOString().split('T')[0],
|
||||
shift: 'Full-time'
|
||||
});
|
||||
setAddEmployeeModal(true);
|
||||
}}
|
||||
className="px-4 py-2 bg-accent text-white rounded-lg text-sm font-medium flex items-center gap-2 hover:opacity-90 transition-all shadow-sm self-start md:self-auto"
|
||||
>
|
||||
<UserPlus className="w-4 h-4" /> Add Employee
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Search & Filter Toolbar */}
|
||||
<div className="bg-slate-50 p-4 rounded-xl border border-slate-100 flex flex-col md:flex-row gap-3 mb-6">
|
||||
<div className="flex-1 relative">
|
||||
<Search className="absolute left-3 top-2.5 w-4 h-4 text-slate-400" />
|
||||
<input
|
||||
type="text"
|
||||
value={employeeSearch}
|
||||
onChange={(e) => 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"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<select
|
||||
value={roleFilter}
|
||||
onChange={(e) => setRoleFilter(e.target.value)}
|
||||
className="py-2 px-3 border border-slate-200 rounded-lg text-sm text-slate-600 bg-white focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent transition-all"
|
||||
>
|
||||
<option value="All">All Roles</option>
|
||||
<option value="Manager">Managers</option>
|
||||
<option value="Accountant">Accountants</option>
|
||||
<option value="Staff">Operations Staff</option>
|
||||
<option value="Technician">Technicians</option>
|
||||
<option value="Support">Support Staff</option>
|
||||
</select>
|
||||
<select
|
||||
value={statusFilter}
|
||||
onChange={(e) => setStatusFilter(e.target.value)}
|
||||
className="py-2 px-3 border border-slate-200 rounded-lg text-sm text-slate-600 bg-white focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent transition-all"
|
||||
>
|
||||
<option value="All">All Statuses</option>
|
||||
<option value="Active">Active / On Duty</option>
|
||||
<option value="On Leave">On Leave</option>
|
||||
<option value="Inactive">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 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 ? (
|
||||
<div className="text-center py-12 bg-slate-50 rounded-xl border border-slate-100">
|
||||
<Users className="w-12 h-12 text-slate-300 mx-auto mb-3" />
|
||||
<p className="text-slate-500 text-sm">No employees match your search or filter criteria.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{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<string, { badge: string; circle: string; text: string }> = {
|
||||
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 (
|
||||
<div key={emp.id} className="bg-white rounded-xl border border-slate-100 shadow-sm overflow-hidden hover:shadow-md transition-all flex flex-col justify-between">
|
||||
<div className="p-5">
|
||||
<div className="flex items-start justify-between gap-3 mb-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`w-12 h-12 rounded-full flex items-center justify-center font-bold text-lg ${style.circle}`}>
|
||||
{emp.name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase()}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold text-slate-800 hover:text-accent transition-colors">{emp.name}</h4>
|
||||
<span className="text-xs text-slate-400 font-mono">{emp.id}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span className={`inline-flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full border ${style.badge}`}>
|
||||
{emp.role}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2.5 my-4 border-t border-b border-slate-50 py-3">
|
||||
<div className="flex items-center gap-2 text-sm text-slate-600">
|
||||
<Mail className="w-4 h-4 text-slate-400 flex-shrink-0" />
|
||||
<a href={`mailto:${emp.email}`} className="truncate hover:text-accent hover:underline">{emp.email}</a>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm text-slate-600">
|
||||
<Phone className="w-4 h-4 text-slate-400 flex-shrink-0" />
|
||||
<a href={`tel:${emp.phone}`} className="hover:text-accent hover:underline">{emp.phone}</a>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm text-slate-600">
|
||||
<Clock className="w-4 h-4 text-slate-400 flex-shrink-0" />
|
||||
<span>Shift: <span className="font-medium text-slate-700">{emp.shift}</span></span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm text-slate-600">
|
||||
<Calendar className="w-4 h-4 text-slate-400 flex-shrink-0" />
|
||||
<span>Joined: <span className="font-medium text-slate-700">{emp.joiningDate}</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="px-5 pb-5 pt-1 border-t border-slate-50 flex items-center justify-between bg-slate-50/50">
|
||||
<span className={`inline-flex items-center gap-1.5 text-xs font-semibold px-2.5 py-1 rounded-full ${
|
||||
emp.status === 'Active' ? 'bg-green-100 text-green-700' :
|
||||
emp.status === 'On Leave' ? 'bg-amber-100 text-amber-700' :
|
||||
'bg-slate-200 text-slate-600'
|
||||
}`}>
|
||||
<span className={`w-1.5 h-1.5 rounded-full ${
|
||||
emp.status === 'Active' ? 'bg-green-500' :
|
||||
emp.status === 'On Leave' ? 'bg-amber-500' :
|
||||
'bg-slate-500'
|
||||
}`} />
|
||||
{emp.status}
|
||||
</span>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditingEmployee(emp);
|
||||
setEmployeeForm({
|
||||
name: emp.name,
|
||||
role: emp.role,
|
||||
email: emp.email,
|
||||
phone: emp.phone,
|
||||
status: emp.status,
|
||||
joiningDate: emp.joiningDate,
|
||||
shift: emp.shift
|
||||
});
|
||||
setAddEmployeeModal(true);
|
||||
}}
|
||||
className="px-2.5 py-1.5 text-xs font-semibold text-blue-600 hover:text-blue-700 bg-white border border-blue-100 hover:border-blue-200 rounded-lg hover:shadow-sm transition-all"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setDeleteEmployeeModal(emp)}
|
||||
className="px-2.5 py-1.5 text-xs font-semibold text-red-600 hover:text-red-700 bg-white border border-red-100 hover:border-red-200 rounded-lg hover:shadow-sm transition-all"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'bikes' && (
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
@@ -745,6 +1023,175 @@ export default function HubDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{addEmployeeModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden">
|
||||
<div className="p-4 border-b border-slate-100 flex justify-between items-center bg-slate-50">
|
||||
<h3 className="font-bold text-slate-800">{editingEmployee ? 'Edit Employee Details' : 'Register New Employee'}</h3>
|
||||
<button onClick={() => { setAddEmployeeModal(false); setEditingEmployee(null); }} className="text-slate-400 hover:text-slate-600">
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-4 space-y-4 max-h-[80vh] overflow-y-auto">
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wider block mb-1">Full Name</label>
|
||||
<input
|
||||
type="text"
|
||||
value={employeeForm.name}
|
||||
onChange={(e) => 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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wider block mb-1">Role</label>
|
||||
<select
|
||||
value={employeeForm.role}
|
||||
onChange={(e) => setEmployeeForm(f => ({ ...f, role: e.target.value as any }))}
|
||||
className="w-full px-3 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"
|
||||
>
|
||||
<option value="Manager">Manager</option>
|
||||
<option value="Accountant">Accountant</option>
|
||||
<option value="Staff">Operations Staff</option>
|
||||
<option value="Technician">Technician</option>
|
||||
<option value="Support">Support Staff</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wider block mb-1">Shift</label>
|
||||
<select
|
||||
value={employeeForm.shift}
|
||||
onChange={(e) => setEmployeeForm(f => ({ ...f, shift: e.target.value as any }))}
|
||||
className="w-full px-3 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"
|
||||
>
|
||||
<option value="Full-time">Full-time</option>
|
||||
<option value="Morning">Morning</option>
|
||||
<option value="Evening">Evening</option>
|
||||
<option value="Night">Night</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wider block mb-1">Email Address</label>
|
||||
<input
|
||||
type="email"
|
||||
value={employeeForm.email}
|
||||
onChange={(e) => 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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wider block mb-1">Phone Number</label>
|
||||
<input
|
||||
type="text"
|
||||
value={employeeForm.phone}
|
||||
onChange={(e) => 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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wider block mb-1">Status</label>
|
||||
<select
|
||||
value={employeeForm.status}
|
||||
onChange={(e) => setEmployeeForm(f => ({ ...f, status: e.target.value as any }))}
|
||||
className="w-full px-3 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"
|
||||
>
|
||||
<option value="Active">Active / On Duty</option>
|
||||
<option value="On Leave">On Leave</option>
|
||||
<option value="Inactive">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wider block mb-1">Joining Date</label>
|
||||
<input
|
||||
type="date"
|
||||
value={employeeForm.joiningDate}
|
||||
onChange={(e) => 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"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 border-t border-slate-100 flex justify-end gap-2 bg-slate-50">
|
||||
<button
|
||||
onClick={() => { setAddEmployeeModal(false); setEditingEmployee(null); }}
|
||||
className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm font-semibold hover:bg-slate-100 transition-all"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (editingEmployee) {
|
||||
setEmployees(prev => prev.map(emp => emp.id === editingEmployee.id ? { ...emp, ...employeeForm } : emp));
|
||||
} else {
|
||||
const nextIdNum = employees.length > 0
|
||||
? Math.max(...employees.map(e => parseInt(e.id.split('-')[1]) || 0)) + 1
|
||||
: 1;
|
||||
const nextIdStr = `EMP-${nextIdNum.toString().padStart(3, '0')}`;
|
||||
const newEmployee: Employee = {
|
||||
id: nextIdStr,
|
||||
...employeeForm
|
||||
};
|
||||
setEmployees(prev => [...prev, newEmployee]);
|
||||
}
|
||||
setAddEmployeeModal(false);
|
||||
setEditingEmployee(null);
|
||||
}}
|
||||
disabled={!employeeForm.name || !employeeForm.email || !employeeForm.phone}
|
||||
className="px-4 py-2 bg-accent text-white rounded-lg text-sm font-semibold hover:opacity-90 disabled:opacity-50 transition-all"
|
||||
>
|
||||
{editingEmployee ? 'Save Changes' : 'Register Employee'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{deleteEmployeeModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-sm overflow-hidden">
|
||||
<div className="p-6 text-center">
|
||||
<div className="w-12 h-12 bg-red-50 border border-red-200 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<AlertTriangle className="w-6 h-6 text-red-600" />
|
||||
</div>
|
||||
<h3 className="font-bold text-slate-800 text-lg mb-2">Remove Employee</h3>
|
||||
<p className="text-sm text-slate-500">
|
||||
Are you sure you want to remove <span className="font-semibold text-slate-700">{deleteEmployeeModal.name}</span> from Gulshan Head Office's operational roster?
|
||||
</p>
|
||||
<div className="mt-3 bg-slate-50 p-3 rounded-lg border border-slate-100 text-left">
|
||||
<p className="text-xs text-slate-400 font-mono">ID: {deleteEmployeeModal.id}</p>
|
||||
<p className="text-xs font-semibold text-slate-700 capitalize mt-1">Role: {deleteEmployeeModal.role}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 border-t border-slate-100 flex justify-end gap-2 bg-slate-50">
|
||||
<button
|
||||
onClick={() => setDeleteEmployeeModal(null)}
|
||||
className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm font-semibold hover:bg-slate-100 transition-all"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setEmployees(prev => prev.filter(emp => emp.id !== deleteEmployeeModal.id));
|
||||
setDeleteEmployeeModal(null);
|
||||
}}
|
||||
className="px-4 py-2 bg-red-600 text-white rounded-lg text-sm font-semibold hover:bg-red-700 transition-all"
|
||||
>
|
||||
Confirm Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1960,7 +1960,7 @@ export default function InvestorDetailPage() {
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="font-semibold text-slate-800">EV Investment Plans</h3>
|
||||
<h3 className="font-semibold text-slate-800">Investment Plans</h3>
|
||||
<p className="text-sm text-slate-500">Manage investment portfolios for this investor</p>
|
||||
</div>
|
||||
<button onClick={() => setShowCreateInvestmentModal(true)} className="py-2 px-4 bg-investor text-white rounded-lg text-sm font-medium hover:bg-investor-dark flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user