2026-03-17 04:50:00 +05:30

1137 lines
77 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import Toast from '../Components/Toast';
import {
ChevronLeft,
Edit2,
Mail,
Phone,
Shield,
Calendar,
MapPin,
Building,
Plus,
Minus,
Wallet,
FileText,
Users,
Bell,
Eye,
Save,
X,
Clock,
Heart
} from 'lucide-react';
export default function StaffView({ id }) {
const isReceptionist = window.__APP_DATA__?.role === 'receptionist';
const basePath = isReceptionist ? '/receptionist' : '/owner';
const [staff, setStaff] = useState(null);
const [payments, setPayments] = useState([]);
const [loading, setLoading] = useState(true);
const [history, setHistory] = useState([]);
const [showHistory, setShowHistory] = useState(false);
const [loadingHistory, setLoadingHistory] = useState(false);
const [toast, setToast] = useState(null);
const [isPaymentModalOpen, setIsPaymentModalOpen] = useState(false);
const [newPayment, setNewPayment] = useState({
amount: '',
payment_date: new Date().toISOString().split('T')[0],
payment_type: 'Salary',
status: 'Paid',
remarks: ''
});
const [personCount, setPersonCount] = useState(1); // For commission mockup
const [isSettleModalOpen, setIsSettleModalOpen] = useState(false);
const [settlementData, setSettlementData] = useState(null);
const [settling, setSettling] = useState(false);
const [payrollStatus, setPayrollStatus] = useState([]);
const [loadingPayroll, setLoadingPayroll] = useState(false);
const [advanceHistory, setAdvanceHistory] = useState([]);
const [loadingAdvanceHistory, setLoadingAdvanceHistory] = useState(false);
const [isAdvanceHistoryModalOpen, setIsAdvanceHistoryModalOpen] = useState(false);
const [isPaymentHistoryModalOpen, setIsPaymentHistoryModalOpen] = useState(false);
useEffect(() => {
fetchStaff();
fetchPayments();
fetchPayrollStatus();
fetchAdvanceHistory();
}, [id]);
const fetchPayments = async () => {
try {
const response = await fetch(`/api/staff/${id}/payments`);
const data = await response.json();
setPayments(data);
} catch (error) {
console.error('Error fetching payments:', error);
}
};
const handleAddPayment = async (e) => {
e.preventDefault();
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
try {
const response = await fetch(`/api/staff/${id}/payments`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify(newPayment)
});
if (response.ok) {
setToast({ message: 'Payment recorded successfully!', type: 'success' });
setIsPaymentModalOpen(false);
fetchPayments();
setNewPayment({
amount: '',
payment_date: new Date().toISOString().split('T')[0],
payment_type: 'Salary',
status: 'Paid',
remarks: ''
});
}
} catch (error) {
setToast({ message: 'Failed to record payment.', type: 'error' });
}
};
const fetchStaff = async () => {
try {
const response = await fetch(`/api/staff/${id}`);
const data = await response.json();
setStaff(data);
} catch (error) {
console.error('Error fetching staff:', error);
setToast({ message: 'Failed to load staff details.', type: 'error' });
} finally {
setLoading(false);
}
};
const handleToggleStatus = async () => {
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
const newStatus = staff.status === 'Active' ? 'Inactive' : 'Active';
try {
const response = await fetch(`/api/staff/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ ...staff, status: newStatus })
});
if (response.ok) {
setStaff({ ...staff, status: newStatus });
setToast({ message: `Staff marked as ${newStatus}`, type: 'success' });
}
} catch (error) {
setToast({ message: 'Failed to update status.', type: 'error' });
}
};
const fetchHistory = async () => {
setLoadingHistory(true);
setShowHistory(true);
try {
const res = await fetch(`/api/staff/${id}/commission-history`);
const data = await res.json();
setHistory(data);
} catch (error) {
console.error('Error fetching history:', error);
} finally {
setLoadingHistory(false);
}
};
const fetchPayrollStatus = async () => {
setLoadingPayroll(true);
try {
const res = await fetch(`/api/staff/${id}/payroll-status`);
const data = await res.json();
setPayrollStatus(data);
} catch (error) {
console.error('Error fetching payroll status:', error);
} finally {
setLoadingPayroll(false);
}
};
const fetchAdvanceHistory = async () => {
setLoadingAdvanceHistory(true);
try {
const res = await fetch(`/api/staff/${id}/advance-history`);
const data = await res.json();
setAdvanceHistory(data);
} catch (error) {
console.error('Error fetching advance history:', error);
} finally {
setLoadingAdvanceHistory(false);
}
};
const fetchSettlement = async (monthKey = null) => {
try {
const url = monthKey
? `/api/staff/${id}/settlement?month=${monthKey}`
: `/api/staff/${id}/settlement`;
const res = await fetch(url);
const data = await res.json();
if (data.can_settle === false) {
setToast({ message: data.message, type: 'info' });
return;
}
setSettlementData(data);
setIsSettleModalOpen(true);
} catch (error) {
setToast({ message: 'Failed to fetch settlement details.', type: 'error' });
}
};
const handleSettle = async () => {
setSettling(true);
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
try {
const res = await fetch(`/api/staff/${id}/settle`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({
settlement_month: settlementData.settlement_month
})
});
if (res.ok) {
setToast({ message: 'Salary settled successfully!', type: 'success' });
setIsSettleModalOpen(false);
fetchStaff();
fetchPayments();
fetchPayrollStatus();
} else {
const err = await res.json();
setToast({ message: err.message || 'Failed to settle salary.', type: 'error' });
}
} catch (error) {
setToast({ message: 'Failed to settle salary.', type: 'error' });
} finally {
setSettling(false);
}
};
const handleGetAdvance = async () => {
// Redirect to edit with advance enabled or just update here
window.location.href = `${basePath}/staff/edit/${id}?get_advance=true`;
};
if (loading) return <div className="p-12 text-center text-gray-400 font-medium">Loading profile...</div>;
if (!staff) return <div className="p-12 text-center text-red-500 font-bold font-mono uppercase tracking-widest text-xl">Staff Member Not Found!</div>;
const initials = staff.full_name?.split(' ').map(n => n[0]).join('').toUpperCase() || 'ST';
return (
<>
{toast && <Toast message={toast.message} type={toast.type} onClose={() => setToast(null)} />}
<main className="p-8 max-w-7xl mx-auto space-y-6">
{/* Back Link */}
<button onClick={() => window.location.href = `${basePath}/staff`} className="flex items-center gap-2 text-sm font-bold text-gray-500 hover:text-gray-900 transition-colors">
<ChevronLeft size={18} />
<span>Back to Staff List</span>
</button>
{/* Profile Header Card */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm p-8 flex items-center justify-between">
<div className="flex items-center gap-6">
<div className="w-20 h-20 bg-amber-400 rounded-full flex items-center justify-center text-white text-2xl font-bold border-4 border-amber-50 shadow-inner">
{initials}
</div>
<div className="space-y-2">
<div className="flex items-center gap-4">
<h1 className="text-2xl font-black text-gray-900 tracking-tight">{staff.full_name}</h1>
<div className={`flex items-center gap-1.5 px-2.5 py-0.5 rounded-full ${staff.status === 'Active' ? 'bg-emerald-50 text-emerald-600 border-emerald-100' : 'bg-red-50 text-red-600 border-red-100'} border text-[10px] font-black uppercase tracking-wider`}>
<div className={`w-1 h-1 rounded-full ${staff.status === 'Active' ? 'bg-emerald-500' : 'bg-red-500'}`}></div>
{staff.status}
</div>
</div>
<div className="flex items-center gap-6 text-gray-500 text-xs font-bold">
<div className="flex items-center gap-1.5">
<Mail size={14} className="text-gray-400" />
<span>{staff.email}</span>
</div>
<div className="flex items-center gap-1.5">
<Phone size={14} className="text-gray-400" />
<span>{staff.phone || 'N/A'}</span>
</div>
<div className="flex items-center gap-1.5">
<Shield size={14} className="text-gray-400" />
<span>{staff.designation || 'N/A'}</span>
</div>
</div>
</div>
</div>
<button
onClick={() => window.location.href = `${basePath}/staff/edit/${staff.id}`}
className="flex items-center gap-2 px-5 py-2.5 bg-red-500 text-white rounded-xl font-bold text-sm hover:bg-red-600 transition-all shadow-lg shadow-red-100"
>
<Edit2 size={16} />
<span>Edit Profile</span>
</button>
</div>
{/* Basic Details Card */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden">
<div className="px-8 py-5 border-b border-gray-50 flex items-center gap-3 bg-gray-50/10">
<Users size={18} className="text-gray-900" />
<h2 className="text-base font-black text-gray-900 uppercase tracking-wider">Basic Details</h2>
</div>
<div className="p-8 grid grid-cols-4 gap-8">
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Staff ID</p>
<p className="text-sm font-bold text-gray-900">{staff.staff_id_code || 'N/A'}</p>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Name</p>
<p className="text-sm font-bold text-gray-900">{staff.full_name}</p>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Contact Number</p>
<div className="flex items-center gap-2 text-sm font-bold text-gray-900">
<Phone size={12} className="text-gray-300" />
<span>{staff.phone || 'N/A'}</span>
</div>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Email</p>
<div className="flex items-center gap-2 text-sm font-bold text-gray-900">
<Mail size={12} className="text-gray-300" />
<span>{staff.email}</span>
</div>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Branch</p>
<div className="flex items-center gap-2 text-sm font-bold text-gray-900">
<MapPin size={12} className="text-gray-300" />
<span>{staff.branch?.name || 'UNDEF'}</span>
</div>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Designation</p>
<div className="flex items-center gap-2 text-sm font-bold text-gray-900">
<Building size={12} className="text-gray-300" />
<span>{staff.designation || 'N/A'}</span>
</div>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Joining Date</p>
<p className="text-sm font-bold text-gray-900">{staff.joining_date || 'N/A'}</p>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Status</p>
<div className={`inline-block px-2.5 py-0.5 rounded-full ${staff.status === 'Active' ? 'bg-emerald-50 text-emerald-600 border-emerald-100' : 'bg-red-50 text-red-600 border-red-100'} border text-[10px] font-black uppercase tracking-wider`}>
{staff.status}
</div>
</div>
</div>
</div>
{/* Salary Details Section */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden">
<div className="px-8 py-5 border-b border-gray-50 flex items-center justify-between bg-gray-50/10">
<div className="flex items-center gap-3">
<Wallet size={18} className="text-emerald-500" />
<h2 className="text-base font-black text-gray-900 uppercase tracking-wider">Salary Details</h2>
</div>
<div className="flex items-center gap-3">
</div>
</div>
<div className="p-8 flex gap-8">
{/* Current Salary Box */}
<div className="w-1/3 space-y-4">
<div className="bg-emerald-50/30 rounded-2xl p-6 border border-emerald-50 relative overflow-hidden group">
<p className="text-emerald-600 text-[10px] font-black uppercase tracking-widest mb-4">Current Salary</p>
<div className="flex items-baseline gap-1.5 mb-6">
<span className="text-4xl font-black text-emerald-700">{(staff.salary_amount || 0).toLocaleString()}</span>
<span className="text-emerald-500 font-bold text-xs">AED</span>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between text-[10px]">
<span className="text-emerald-600/60 font-bold uppercase tracking-widest">Type:</span>
<span className="text-emerald-700 font-black">{staff.salary_type || 'Monthly'}</span>
</div>
<div className="flex items-center justify-between text-[10px]">
<span className="text-emerald-600/60 font-bold uppercase tracking-widest">Cycle:</span>
<span className="text-emerald-700 font-black">{staff.salary_cycle || 'Monthly'}</span>
</div>
</div>
</div>
{/* Advance Card */}
<div className="bg-orange-50/30 rounded-2xl p-6 border border-orange-50 relative overflow-hidden group">
<div className="flex items-center justify-between mb-4">
<p className="text-orange-600 text-[10px] font-black uppercase tracking-widest">Salary Advance</p>
{!staff.advance_enabled && (
<button
onClick={handleGetAdvance}
className="px-2.5 py-1 bg-white text-orange-600 rounded-lg text-[10px] font-black border border-orange-100 hover:bg-orange-50 transition-all shadow-sm"
>
GET ADVANCE
</button>
)}
</div>
{(() => {
const activeAdvance = advanceHistory.find(h => h.status === 'Pending');
if (activeAdvance) {
return (
<>
<div className="flex items-baseline gap-1.5 mb-6">
<span className="text-2xl font-black text-orange-700">{(parseFloat(activeAdvance.advance_amount) || 0).toLocaleString()}</span>
<span className="text-orange-500 font-bold text-[10px]">AED</span>
</div>
<div className="flex items-center justify-between p-2.5 bg-white/50 rounded-xl border border-orange-50">
<div className="text-[8px] font-black text-orange-400 uppercase tracking-widest">Mode</div>
<div className="text-[9px] font-black text-orange-700 uppercase tracking-wider">{staff.advance_repayment_mode}</div>
</div>
</>
);
} else {
return (
<div className="py-2 text-center text-orange-300">
<p className="text-[10px] font-bold italic">No active advance</p>
</div>
);
}
})()}
{advanceHistory.length > 0 && (
<div className="mt-4 p-3 bg-white/50 rounded-xl border border-orange-100 flex items-center justify-between">
<div>
<p className="text-[8px] font-black text-orange-400 uppercase tracking-widest leading-none mb-1">Total Balance Due</p>
<p className="text-sm font-black text-orange-700">
{advanceHistory
.filter(h => h.status === 'Pending')
.reduce((sum, h) => sum + (parseFloat(h.advance_amount) - parseFloat(h.paid_amount || 0)), 0)
.toLocaleString()} AED
</p>
</div>
<div className="text-right">
<p className="text-[8px] font-black text-emerald-500 uppercase tracking-widest leading-none mb-1">Total Paid</p>
<p className="text-sm font-black text-emerald-600">
{advanceHistory.reduce((sum, h) => sum + (parseFloat(h.paid_amount || 0)), 0).toLocaleString()} AED
</p>
</div>
</div>
)}
{advanceHistory.length > 0 && (
<div className="mt-6 pt-6 border-t border-orange-50/50 space-y-3">
<div className="flex items-center justify-between mb-2">
<p className="text-[9px] font-black text-orange-400 uppercase tracking-widest">Monthly Repayment Schedule</p>
{advanceHistory.flatMap(h => h.installment_schedule || []).length > 3 && (
<button
onClick={() => setIsAdvanceHistoryModalOpen(true)}
className="text-[8px] font-black text-orange-600 hover:underline uppercase tracking-widest"
>
View Full History
</button>
)}
</div>
<div className="space-y-2">
{advanceHistory.flatMap(h => h.installment_schedule || [])
.slice(0, 3)
.map((item, idx) => (
<div key={idx} className={`p-2 rounded-xl border flex items-center justify-between transition-all ${item.status === 'Paid' ? 'bg-emerald-50/30 border-emerald-100 opacity-60' : 'bg-white border-orange-100 shadow-sm'}`}>
<div>
<p className="text-[10px] font-black text-gray-900">{item.month}</p>
<p className="text-[8px] text-gray-400 font-medium">AED {item.amount.toLocaleString()}</p>
</div>
<div className="text-right">
<span className={`px-2 py-0.5 rounded-full text-[8px] font-black uppercase tracking-widest ${item.status === 'Paid' ? 'bg-emerald-100 text-emerald-600' : 'bg-orange-50 text-orange-600'}`}>
{item.status}
</span>
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>
{/* Monthly Payroll Status Table */}
<div className="flex-1 space-y-8">
<div>
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-black text-gray-900 uppercase tracking-wider">Monthly Payroll Status</h3>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-emerald-500"></div>
<span className="text-[10px] font-bold text-gray-400">Paid</span>
<div className="w-2 h-2 rounded-full bg-orange-500 ml-2"></div>
<span className="text-[10px] font-bold text-gray-400">Unpaid</span>
</div>
</div>
<div className="border border-gray-50 rounded-2xl overflow-hidden bg-white shadow-sm">
<table className="w-full">
<thead className="bg-gray-50/50">
<tr>
<th className="px-6 py-3 text-left text-[10px] font-bold text-gray-400 uppercase tracking-widest">Month</th>
<th className="px-6 py-3 text-left text-[10px] font-bold text-gray-400 uppercase tracking-widest">Status</th>
<th className="px-6 py-3 text-left text-[10px] font-bold text-gray-400 uppercase tracking-widest">Net Amount</th>
<th className="px-6 py-3 text-right text-[10px] font-bold text-gray-400 uppercase tracking-widest">Action</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-50">
{payrollStatus.length > 0 ? (
payrollStatus.map((p) => (
<tr key={p.month_key} className="hover:bg-gray-50/50 transition-colors">
<td className="px-6 py-4 text-xs font-bold text-gray-900">{p.month}</td>
<td className="px-6 py-4">
<span className={`px-2 py-0.5 rounded-full text-[10px] font-black uppercase tracking-wider ${
p.status === 'Paid' ? 'bg-emerald-50 text-emerald-600' : 'bg-orange-50 text-orange-600'
}`}>
{p.status}
</span>
</td>
<td className="px-6 py-4 text-xs font-black text-gray-600">
{p.amount ? `${parseFloat(p.amount).toLocaleString()} AED` : '-'}
</td>
<td className="px-6 py-4 text-right">
{p.can_settle ? (
<button
onClick={() => fetchSettlement(p.month_key)}
className="px-3 py-1 bg-emerald-500 text-white rounded-lg text-[10px] font-black hover:scale-105 active:scale-95 transition-all shadow-md shadow-emerald-100 uppercase tracking-widest"
>
Settle
</button>
) : (
<span className="text-[10px] font-black text-emerald-500 uppercase tracking-widest">COMPLETED</span>
)}
</td>
</tr>
))
) : (
<tr>
<td colSpan="4" className="px-6 py-8 text-center text-xs font-bold text-gray-400 italic">
No months yet to settle. Next settlement will be available after 1st of next month.
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
{/* Transaction History Table */}
<div>
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-black text-gray-900 uppercase tracking-wider">Transaction History</h3>
{payments.length > 3 && (
<button
onClick={() => setIsPaymentHistoryModalOpen(true)}
className="text-[10px] font-bold text-blue-600 hover:underline uppercase tracking-wider"
>
View Full History
</button>
)}
</div>
<div className="border border-gray-50 rounded-2xl overflow-hidden bg-white shadow-sm opacity-80">
<table className="w-full">
<thead className="bg-gray-50/50">
<tr>
<th className="px-6 py-3 text-left text-[10px] font-bold text-gray-400 uppercase tracking-widest">Date</th>
<th className="px-6 py-3 text-left text-[10px] font-bold text-gray-400 uppercase tracking-widest">Type</th>
<th className="px-6 py-3 text-left text-[10px] font-bold text-gray-400 uppercase tracking-widest">Amount</th>
<th className="px-6 py-3 text-left text-[10px] font-bold text-gray-400 uppercase tracking-widest">Status</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-50">
{payments.length > 0 ? (
payments.slice(0, 3).map((p) => (
<tr key={p.id}>
<td className="px-6 py-4 text-xs font-bold text-gray-900">{p.payment_date}</td>
<td className="px-6 py-4 text-xs font-semibold text-gray-500">{p.payment_type}</td>
<td className="px-6 py-4 text-xs font-black text-emerald-600">{(parseFloat(p.amount) || 0).toLocaleString()} AED</td>
<td className="px-6 py-4">
<span className="px-2 py-0.5 bg-emerald-50 text-emerald-600 rounded-full text-[10px] font-black uppercase tracking-wider">{p.status}</span>
</td>
</tr>
))
) : (
<tr>
<td colSpan="4" className="px-6 py-8 text-center text-xs font-bold text-gray-400 italic">
No transactions recorded yet.
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{/* Member Commission Section */}
<div className="bg-[#FAF9FF] rounded-2xl border border-purple-100 shadow-sm p-8 group transition-all hover:bg-white hover:border-purple-200">
<div className="flex items-center justify-between mb-8">
<div className="flex items-center gap-3">
<div className="p-2 bg-purple-100/50 rounded-xl text-purple-600">
<Users size={18} />
</div>
<h2 className="text-base font-black text-purple-900 uppercase tracking-wider">Member Commission</h2>
</div>
<div className="flex items-center gap-4">
<button
onClick={() => window.location.href = `${basePath}/staff/edit/${id}`}
className="text-[10px] font-black text-gray-400 uppercase tracking-widest flex items-center gap-1.5 hover:text-purple-600 transition-all border border-transparent hover:border-purple-100 px-2 py-1 rounded-lg"
>
<Edit2 size={12} />
Edit Settings
</button>
<button
onClick={fetchHistory}
className="text-[10px] font-black text-purple-500 uppercase tracking-widest flex items-center gap-1.5 px-3 py-1.5 bg-purple-50 rounded-lg hover:bg-purple-100 transition-all"
>
<Eye size={12} />
PT History
</button>
</div>
</div>
<div className="grid grid-cols-2 gap-20">
<div className="space-y-6">
<div>
<p className="text-[10px] font-bold text-purple-400 uppercase tracking-widest mb-1.5">Amount Per Person</p>
<div className="flex items-baseline gap-1.5">
<span className="text-4xl font-black text-purple-900">{staff.commission_amount || 0}</span>
<span className="text-purple-400 font-bold text-sm">AED</span>
</div>
</div>
<div className="pt-6 border-t border-purple-50">
<p className="text-[10px] font-bold text-purple-400 uppercase tracking-widest mb-1">Total Monthly Estimate</p>
<p className="text-2xl font-black text-purple-600">{(staff.commission_amount * (staff.commission_member_count || 0)).toLocaleString()} AED</p>
</div>
</div>
<div className="flex flex-col justify-center items-center gap-3 bg-white/50 border border-purple-50 rounded-2xl p-6">
<p className="text-[10px] font-black text-purple-400 uppercase tracking-widest">Active Member Count</p>
<div className="flex items-center gap-8">
<span className="text-5xl font-black text-purple-900 text-center">{staff.commission_member_count || 0}</span>
</div>
<p className="text-[9px] text-purple-300 font-bold uppercase tracking-wider">Updated Monthly</p>
</div>
</div>
</div>
{/* Bottom Row: Docs, Family, Notifications */}
<div className="grid grid-cols-2 gap-8">
{/* Documentation Card */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden">
<div className="px-8 py-5 border-b border-gray-50 flex items-center justify-between bg-gray-50/10">
<div className="flex items-center gap-3">
<FileText size={18} className="text-blue-500" />
<h2 className="text-base font-black text-gray-900 uppercase tracking-wider">Documentation</h2>
</div>
<span className="px-2.5 py-0.5 bg-blue-50 text-blue-600 rounded-full text-[10px] font-bold border border-blue-100">VERIFIED</span>
</div>
<div className="p-8 space-y-4">
{staff.documents && staff.documents.length > 0 ? (
staff.documents.map((doc, index) => (
<div key={index} className="group p-4 bg-gray-50/50 rounded-2xl border border-gray-100 flex items-center justify-between hover:bg-white hover:shadow-sm transition-all">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-blue-50 rounded-xl flex items-center justify-center text-blue-500">
<FileText size={20} />
</div>
<div>
<p className="text-xs font-black text-gray-900 mb-1 leading-none uppercase tracking-tight">{doc.name}</p>
<p className="text-[10px] font-bold text-gray-400 mb-1.5">{doc.document_number || 'No Number'}</p>
<div className="flex items-center gap-2">
<p className="text-[10px] font-bold text-orange-400 flex items-center gap-1.5">
<Clock size={10} />
Expiry: {doc.expiry_date || 'N/A'}
</p>
</div>
</div>
</div>
{doc.path && (
<a
href={`/storage/${doc.path}`}
target="_blank"
rel="noopener noreferrer"
className="p-2 bg-blue-50 text-blue-600 rounded-lg hover:bg-blue-100 transition-all border border-blue-100"
>
<Eye size={16} />
</a>
)}
</div>
))
) : (
<p className="text-center py-6 text-gray-400 text-xs italic font-bold uppercase tracking-widest opacity-50">No documents</p>
)}
</div>
</div>
{/* Family Members Card */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden">
<div className="px-8 py-5 border-b border-gray-50 flex items-center justify-between bg-gray-50/10">
<div className="flex items-center gap-3">
<Heart size={18} className="text-rose-500" />
<h2 className="text-base font-black text-gray-900 uppercase tracking-wider">Family Details</h2>
</div>
</div>
<div className="p-8 space-y-4">
{staff.family_members && staff.family_members.length > 0 ? (
staff.family_members.map((member, index) => (
<div key={index} className="p-5 rounded-2xl bg-rose-50/30 border border-rose-50 flex flex-col gap-4">
<div className="flex items-center justify-between">
<div>
<p className="text-[10px] font-black text-rose-400 uppercase tracking-widest mb-1">Family Member {index + 1}</p>
<p className="text-sm font-black text-gray-900">{member.name}</p>
</div>
<div className="px-3 py-1 bg-white rounded-full border border-rose-100 text-[10px] font-black text-rose-500 uppercase">
{member.relation}
</div>
</div>
<div className="flex items-center gap-2 text-xs font-bold text-gray-600 bg-white/50 p-2.5 rounded-xl border border-rose-50">
<Phone size={14} className="text-rose-300" />
<span>{member.contact}</span>
</div>
</div>
))
) : staff.family_member_name ? (
<div className="p-5 rounded-2xl bg-rose-50/30 border border-rose-50 flex flex-col gap-4">
<div className="flex items-center justify-between">
<div>
<p className="text-[10px] font-black text-rose-400 uppercase tracking-widest mb-1">Emergency Contact</p>
<p className="text-sm font-black text-gray-900">{staff.family_member_name}</p>
</div>
<div className="px-3 py-1 bg-white rounded-full border border-rose-100 text-[10px] font-black text-rose-500 uppercase">
{staff.family_member_relation}
</div>
</div>
<div className="flex items-center gap-2 text-xs font-bold text-gray-600 bg-white/50 p-2.5 rounded-xl border border-rose-50">
<Phone size={14} className="text-rose-300" />
<span>{staff.family_member_contact}</span>
</div>
</div>
) : (
<p className="text-center py-6 text-gray-400 text-xs italic font-bold uppercase tracking-widest opacity-50">Not Provided</p>
)}
</div>
</div>
</div>
{/* Payment Modal */}
{isPaymentModalOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm">
<div className="bg-white rounded-[2.5rem] w-full max-w-md shadow-2xl border border-gray-100 overflow-hidden animate-in fade-in zoom-in duration-200">
<div className="p-8 border-b border-gray-50 flex items-center justify-between bg-[#F9FAFB]/50">
<div>
<h3 className="text-xl font-black text-[#111827]">Record Payment</h3>
<p className="text-xs text-gray-500 font-bold uppercase tracking-widest mt-1">Staff Transaction</p>
</div>
<button onClick={() => setIsPaymentModalOpen(false)} className="p-2 hover:bg-gray-100 rounded-full transition-colors text-gray-400">
<Minus size={20} />
</button>
</div>
<form onSubmit={handleAddPayment} className="p-8 space-y-6">
<div className="space-y-4">
<div>
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] mb-2 block">Payment Type</label>
<select
className="w-full px-4 py-3 bg-gray-50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 transition-all text-sm font-bold"
value={newPayment.payment_type}
onChange={(e) => setNewPayment({...newPayment, payment_type: e.target.value})}
>
<option>Salary</option>
<option>Advance</option>
<option>Commission</option>
<option>Bonus</option>
</select>
</div>
<div>
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] mb-2 block">Amount (AED)</label>
<input
type="number"
required
className="w-full px-4 py-3 bg-gray-50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 transition-all text-sm font-bold"
placeholder="Enter amount"
value={newPayment.amount}
onChange={(e) => setNewPayment({...newPayment, amount: e.target.value})}
/>
</div>
<div>
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] mb-2 block">Date</label>
<input
type="date"
required
className="w-full px-4 py-3 bg-gray-50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 transition-all text-sm font-bold"
value={newPayment.payment_date}
onChange={(e) => setNewPayment({...newPayment, payment_date: e.target.value})}
/>
</div>
<div>
<label className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em] mb-2 block">Remarks</label>
<textarea
className="w-full px-4 py-3 bg-gray-50 border border-gray-100 rounded-2xl outline-none focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 transition-all text-sm font-medium resize-none h-24"
placeholder="Optional notes..."
value={newPayment.remarks}
onChange={(e) => setNewPayment({...newPayment, remarks: e.target.value})}
/>
</div>
</div>
<div className="flex gap-3 pt-4">
<button
type="button"
onClick={() => setIsPaymentModalOpen(false)}
className="flex-1 px-6 py-4 bg-gray-100 text-gray-600 rounded-2xl font-black text-sm hover:bg-gray-200 transition-all"
>
CANCEL
</button>
<button
type="submit"
className="flex-2 px-8 py-4 bg-emerald-600 text-white rounded-2xl font-black text-sm hover:scale-[1.02] active:scale-[0.98] transition-all shadow-xl shadow-emerald-100 flex items-center justify-center gap-2"
>
<Save size={18} />
RECORD PAYMENT
</button>
</div>
</form>
</div>
</div>
)}
{/* PT History Modal */}
{showHistory && (
<div className="fixed inset-0 z-[60] flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm animate-in fade-in duration-200">
<div className="bg-white rounded-[2.5rem] w-full max-w-2xl max-h-[85vh] overflow-hidden flex flex-col shadow-2xl animate-in zoom-in-95 duration-200">
<div className="p-8 flex items-center justify-between border-b border-gray-100">
<div>
<h3 className="text-xl font-bold text-gray-900">Commission History</h3>
<p className="text-sm text-gray-400 font-medium">Past member counts and commissions</p>
</div>
<button
onClick={() => setShowHistory(false)}
className="w-10 h-10 flex items-center justify-center rounded-full hover:bg-gray-100 text-gray-400 hover:text-gray-900 transition-all"
>
<X size={20} />
</button>
</div>
<div className="flex-1 overflow-auto p-8">
{loadingHistory ? (
<div className="text-center py-10 font-medium text-gray-400">Loading history...</div>
) : history.length > 0 ? (
<div className="overflow-hidden border border-gray-100 rounded-2xl">
<table className="w-full text-left border-collapse">
<thead>
<tr className="bg-gray-50/50">
<th className="px-6 py-4 text-[10px] font-bold text-gray-400 uppercase tracking-wider">Month</th>
<th className="px-6 py-4 text-[10px] font-bold text-gray-400 uppercase tracking-wider text-center">Members</th>
<th className="px-6 py-4 text-[10px] font-bold text-gray-400 uppercase tracking-wider text-right">Per Head</th>
<th className="px-6 py-4 text-[10px] font-bold text-gray-400 uppercase tracking-wider text-right">Total</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-50">
{history.map((row) => (
<tr key={row.id} className="hover:bg-gray-50/30 transition-colors">
<td className="px-6 py-4">
<span className="text-sm font-bold text-gray-900 capitalize">
{new Date(row.effective_month + "-01").toLocaleString('default', { month: 'long', year: 'numeric' })}
</span>
</td>
<td className="px-6 py-4 text-center">
<span className="px-3 py-1 bg-purple-50 text-purple-600 text-xs font-black rounded-lg">
{row.member_count}
</span>
</td>
<td className="px-6 py-4 text-right text-sm font-semibold text-gray-500">
AED {row.amount_per_head}
</td>
<td className="px-6 py-4 text-right">
<span className="text-sm font-bold text-emerald-600">AED {row.total_amount}</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className="text-center py-20 bg-gray-50 rounded-3xl border-2 border-dashed border-gray-100">
<p className="text-gray-400 font-medium">No history found for this staff member.</p>
</div>
)}
</div>
<div className="p-8 border-t border-gray-100 bg-gray-50/30 flex justify-end">
<button
onClick={() => setShowHistory(false)}
className="px-8 py-3 bg-gray-900 text-white rounded-xl text-sm font-bold hover:bg-black transition-all shadow-lg shadow-gray-200"
>
Close History
</button>
</div>
</div>
</div>
)}
{/* Settle Salary Modal */}
{isSettleModalOpen && settlementData && (
<div className="fixed inset-0 z-[70] flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm animate-in fade-in duration-300">
<div className="bg-white rounded-[2.5rem] w-full max-w-lg shadow-2xl border border-gray-100 overflow-hidden animate-in zoom-in-95 duration-200">
<div className="p-10 border-b border-gray-50 flex items-center justify-between">
<div>
<h3 className="text-2xl font-black text-gray-900 leading-none">Settle Salary Next Month</h3>
<div className="mt-4 flex gap-8">
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">STAFF</p>
<p className="text-sm font-bold text-gray-900">{settlementData.staff_name}</p>
</div>
<div>
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Settlement Period</p>
<p className="text-sm font-bold text-gray-900">{settlementData.period}</p>
<p className="text-[10px] text-gray-400 italic font-medium">Cycle: {settlementData.cycle_range}</p>
</div>
</div>
</div>
<button onClick={() => setIsSettleModalOpen(false)} className="w-10 h-10 flex items-center justify-center rounded-full hover:bg-gray-100 text-gray-400 transition-colors">
<X size={24} />
</button>
</div>
<div className="p-10 space-y-8">
<div className="bg-gray-50/50 rounded-[2.5rem] border border-gray-100 overflow-hidden">
<div className="px-8 py-4 border-b border-gray-100 flex items-center justify-between">
<p className="text-[10px] font-black text-gray-400 uppercase tracking-[0.2em]">BILL BREAKDOWN</p>
<div className="text-[9px] font-bold text-gray-400 uppercase">
Formula: <span className="text-emerald-500">Salary</span> + <span className="text-purple-500">Comm.</span> - <span className="text-orange-500">Adv.</span>
</div>
</div>
<div className="p-8 space-y-4">
{/* Base Salary */}
<div className="flex items-center justify-between group">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-emerald-50 rounded-2xl flex items-center justify-center text-emerald-500 shadow-sm border border-emerald-100">
<Wallet size={18} />
</div>
<div>
<span className="text-sm font-bold text-gray-700 block">Base Salary ({settlementData.salary_type})</span>
{settlementData.is_prorated && (
<span className="text-[10px] text-orange-500 font-bold italic">
Prorated: {settlementData.working_days} Days / {settlementData.total_days} Cycle Days
</span>
)}
</div>
</div>
<div className="text-right">
<span className="text-base font-black text-gray-900 block">{(settlementData.prorated_base || settlementData.base_salary || 0).toLocaleString()} AED</span>
{settlementData.is_prorated && (
<span className="text-[10px] text-gray-400 line-through">{(settlementData.base_salary || 0).toLocaleString()} AED</span>
)}
</div>
</div>
{/* Commission */}
<div className="flex items-center justify-between group">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-purple-50 rounded-2xl flex items-center justify-center text-purple-500 shadow-sm border border-purple-100">
<Users size={18} />
</div>
<div>
<p className="text-sm font-bold text-gray-700">Member Commission</p>
<p className="text-[10px] font-bold text-purple-400 tracking-wider">
{settlementData.commission_count} members × {settlementData.commission_amount} AED
</p>
</div>
</div>
<span className="text-base font-black text-purple-600">+ {(settlementData.total_commission || 0).toLocaleString()} AED</span>
</div>
{/* Advance Deduction */}
<div className="flex items-center justify-between group">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-orange-50 rounded-2xl flex items-center justify-center text-orange-500 shadow-sm border border-orange-100">
<Minus size={18} />
</div>
<div>
<p className="text-sm font-bold text-gray-700">Advance Deduction</p>
<p className="text-[10px] font-bold text-orange-400 tracking-wider">
Remaining: {(settlementData.remaining_advance || 0).toLocaleString()} AED
</p>
</div>
</div>
<span className="text-base font-black text-orange-600">- {(settlementData.advance_deduction || 0).toLocaleString()} AED</span>
</div>
<div className="mt-4 pt-6 border-t-2 border-dashed border-gray-100">
<div className="bg-emerald-50/50 p-6 rounded-[2rem] border border-emerald-100/50 flex items-center justify-between group hover:scale-[1.02] transition-transform">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-emerald-500 rounded-2xl flex items-center justify-center text-white shadow-xl shadow-emerald-100">
<FileText size={24} />
</div>
<span className="text-lg font-black text-emerald-900">Net Payable</span>
</div>
<span className="text-3xl font-black text-emerald-600">{(settlementData.net_payable || 0).toLocaleString()} AED</span>
</div>
</div>
</div>
</div>
<div className="flex gap-4">
<button
onClick={() => setIsSettleModalOpen(false)}
className="flex-1 px-8 py-4 bg-gray-100 text-gray-600 rounded-2xl font-black text-sm hover:bg-gray-200 transition-all uppercase tracking-widest"
>
Cancel
</button>
<button
onClick={handleSettle}
disabled={settling}
className="flex-[2] px-8 py-4 bg-emerald-500 text-white rounded-2xl font-black text-sm hover:scale-[1.02] active:scale-[0.98] transition-all shadow-xl shadow-emerald-100 flex items-center justify-center gap-3 uppercase tracking-widest disabled:opacity-50"
>
{settling ? 'Processing...' : (
<>
<Save size={20} />
Settle for {settlementData.period}
</>
)}
</button>
</div>
</div>
</div>
</div>
)}
{/* Full Advance History Modal */}
{isAdvanceHistoryModalOpen && (
<div className="fixed inset-0 z-[80] flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm animate-in fade-in duration-300">
<div className="bg-white rounded-[2.5rem] w-full max-w-2xl max-h-[85vh] overflow-hidden flex flex-col shadow-2xl animate-in zoom-in-95 duration-200">
<div className="p-8 flex items-center justify-between border-b border-gray-100">
<div>
<h3 className="text-xl font-black text-gray-900 uppercase tracking-tight">Full Advance History</h3>
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-1">Repayment Schedule & Status</p>
</div>
<button onClick={() => setIsAdvanceHistoryModalOpen(false)} className="w-10 h-10 flex items-center justify-center rounded-full hover:bg-gray-100 text-gray-400 transition-all">
<X size={20} />
</button>
</div>
<div className="flex-1 overflow-auto p-8">
<div className="space-y-4">
{advanceHistory.map((h, hIdx) => (
<div key={hIdx} className="space-y-3">
<div className="flex items-center justify-between px-2">
<p className="text-[10px] font-black text-orange-500 uppercase tracking-widest">
Advance taken on {new Date(h.created_at).toLocaleDateString()} {parseFloat(h.advance_amount).toLocaleString()} AED
</p>
<span className={`px-2 py-0.5 rounded-full text-[8px] font-black uppercase tracking-widest ${h.status === 'Closed' ? 'bg-gray-100 text-gray-400' : 'bg-orange-50 text-orange-600'}`}>
{h.status}
</span>
</div>
<div className="grid grid-cols-2 gap-3">
{(h.installment_schedule || []).map((item, iIdx) => (
<div key={iIdx} className={`p-4 rounded-2xl border flex items-center justify-between transition-all ${item.status === 'Paid' ? 'bg-emerald-50/30 border-emerald-50 opacity-60' : 'bg-gray-50/50 border-gray-100 shadow-sm'}`}>
<div>
<p className="text-sm font-black text-gray-900">{item.month}</p>
<div className="flex items-center gap-3">
<p className="text-[10px] text-gray-400 font-bold uppercase tracking-wider">Amount: AED {item.amount.toLocaleString()}</p>
{item.status !== 'Paid' && (
<p className="text-[10px] text-orange-500 font-black uppercase tracking-wider">Pending: AED {item.amount.toLocaleString()}</p>
)}
</div>
</div>
<div className={`px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-widest ${item.status === 'Paid' ? 'bg-emerald-100 text-emerald-600' : 'bg-white text-orange-600 border border-orange-100'}`}>
{item.status}
</div>
</div>
))}
</div>
{hIdx < advanceHistory.length - 1 && <div className="h-px bg-gray-100 my-6" />}
</div>
))}
</div>
</div>
<div className="p-8 border-t border-gray-100 bg-gray-50/30 flex justify-end">
<button
onClick={() => setIsAdvanceHistoryModalOpen(false)}
className="px-8 py-3 bg-gray-900 text-white rounded-xl text-sm font-bold hover:bg-black transition-all shadow-lg shadow-gray-200"
>
Close History
</button>
</div>
</div>
</div>
)}
{/* Full Transaction History Modal */}
{isPaymentHistoryModalOpen && (
<div className="fixed inset-0 z-[80] flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm animate-in fade-in duration-300">
<div className="bg-white rounded-[2.5rem] w-full max-w-3xl max-h-[85vh] overflow-hidden flex flex-col shadow-2xl animate-in zoom-in-95 duration-200">
<div className="p-8 flex items-center justify-between border-b border-gray-100 bg-[#F9FAFB]/50">
<div>
<h3 className="text-xl font-black text-gray-900 uppercase tracking-tight">Full Transaction History</h3>
<p className="text-xs text-gray-400 font-bold uppercase tracking-widest mt-1">Salary, Advance & Others</p>
</div>
<button onClick={() => setIsPaymentHistoryModalOpen(false)} className="w-10 h-10 flex items-center justify-center rounded-full hover:bg-gray-100 text-gray-400 transition-all">
<X size={20} />
</button>
</div>
<div className="flex-1 overflow-auto p-8">
<div className="border border-gray-100 rounded-2xl overflow-hidden bg-white shadow-sm">
<table className="w-full">
<thead className="bg-gray-50/50">
<tr>
<th className="px-6 py-4 text-left text-[10px] font-black text-gray-400 uppercase tracking-widest">Date</th>
<th className="px-6 py-4 text-left text-[10px] font-black text-gray-400 uppercase tracking-widest">Type</th>
<th className="px-6 py-4 text-left text-[10px] font-black text-gray-400 uppercase tracking-widest">Amount</th>
<th className="px-6 py-4 text-left text-[10px] font-black text-gray-400 uppercase tracking-widest">Status</th>
<th className="px-6 py-4 text-left text-[10px] font-black text-gray-400 uppercase tracking-widest">Remarks</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-50">
{payments.map((p) => (
<tr key={p.id} className="hover:bg-gray-50/30 transition-colors">
<td className="px-6 py-4 text-xs font-bold text-gray-900">{p.payment_date}</td>
<td className="px-6 py-4 text-xs font-semibold text-gray-500">{p.payment_type}</td>
<td className="px-6 py-4 text-xs font-black text-emerald-600">{(parseFloat(p.amount) || 0).toLocaleString()} AED</td>
<td className="px-6 py-4">
<span className="px-2 py-0.5 bg-emerald-50 text-emerald-600 rounded-full text-[10px] font-black uppercase tracking-wider">{p.status}</span>
</td>
<td className="px-6 py-4 text-[10px] font-medium text-gray-400 italic max-w-[150px] truncate">{p.remarks || '-'}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="p-8 border-t border-gray-100 bg-gray-50/30 flex justify-end">
<button
onClick={() => setIsPaymentHistoryModalOpen(false)}
className="px-8 py-3 bg-gray-900 text-white rounded-xl text-sm font-bold hover:bg-black transition-all shadow-lg shadow-gray-200"
>
Close History
</button>
</div>
</div>
</div>
)}
</main>
</>
);
}