import React, { useState, useEffect } from 'react'; import Toast from '../Components/Toast'; import { Shield, ChevronLeft, Save, Plus, Trash2 } from 'lucide-react'; export default function StaffAdd() { const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [branches, setBranches] = useState([]); const [toast, setToast] = useState(null); const isReceptionist = window.__APP_DATA__?.role === 'receptionist'; const receptionistBranchId = window.__APP_DATA__?.branch?.id; const basePath = isReceptionist ? '/receptionist' : '/owner'; const today = new Date().toISOString().split("T")[0]; const [formData, setFormData] = useState({ full_name: '', email: '', phone: '', role: 'Trainer', branch_id: isReceptionist ? (receptionistBranchId?.toString() || '') : '', joining_date: today, status: 'Active', salary_type: 'Fixed', salary_amount: '', cycle_effective_date: today, advance_enabled: false, advance_amount: '', advance_months: '', advance_repayment_mode: 'Full Next Month', commission_enabled: false, commission_amount: '', commission_member_count: '', emirates_id: '', emirates_id_expiry: '', emirates_id_reminder_days: 30, salary_reminder_enabled: true, document_expiry_enabled: true, family_members: [{ name: '', relation: '', contact: '' }], documents: [{ name: '', document_number: '', expiry_date: '', reminder_days: 30, file: null }] }); useEffect(() => { const fetchBranches = async () => { try { const response = await fetch('/api/branches'); const data = await response.json(); setBranches(data); } catch (error) { console.error('Error fetching branches:', error); } finally { setLoading(false); } }; fetchBranches(); }, []); const handleChange = (e) => { const { name, value, type, checked } = e.target; setFormData({ ...formData, [name]: type === 'checkbox' ? checked : value }); }; const handleDocumentChange = (index, e) => { const { name, value, files } = e.target; const newDocs = [...formData.documents]; if (name === 'file') { newDocs[index][name] = files[0]; } else { newDocs[index][name] = value; } setFormData({ ...formData, documents: newDocs }); }; const addDocumentRow = () => { setFormData({ ...formData, documents: [...formData.documents, { name: '', document_number: '', expiry_date: '', reminder_days: 30, file: null }] }); }; const removeDocumentRow = (index) => { const newDocs = formData.documents.filter((_, i) => i !== index); setFormData({ ...formData, documents: newDocs }); }; const handleFamilyMemberChange = (index, e) => { const { name, value } = e.target; const newMembers = [...formData.family_members]; newMembers[index][name] = value; setFormData({ ...formData, family_members: newMembers }); }; const addFamilyMemberRow = () => { setFormData({ ...formData, family_members: [...formData.family_members, { name: '', relation: '', contact: '' }] }); }; const removeFamilyMemberRow = (index) => { const newMembers = formData.family_members.filter((_, i) => i !== index); setFormData({ ...formData, family_members: newMembers }); }; const handleSave = async (e) => { if (e) e.preventDefault(); // Comprehensive Validations const errors = []; if (!formData.full_name.trim()) errors.push('Full Name is required.'); if (!formData.email.trim()) errors.push('Email is required.'); else if (!/\S+@\S+\.\S+/.test(formData.email)) errors.push('Invalid Email format.'); if (!formData.phone.trim()) errors.push('Phone number is required.'); else if (!/^(\+91|91|0)?[6-9]\d{9}$|^(\+971|971|0)?5[024568]\d{7}$/.test(formData.phone.replace(/[\s-]/g, ''))) { errors.push('Invalid Phone format. Only Indian (+91) and UAE (+971) numbers are allowed.'); } if (!formData.branch_id) errors.push('Please select a Branch.'); if (!formData.joining_date) errors.push('Joining Date is required.'); if (!formData.role) errors.push('Please select a Role.'); if (!formData.salary_amount || parseFloat(formData.salary_amount) <= 0) { errors.push('Please enter a valid Salary Amount.'); } // Branch Start Date Validation - REMOVED AS PER USER REQUEST /* const selectedBranch = branches.find(b => b.id == formData.branch_id); if (selectedBranch && formData.joining_date && selectedBranch.operational_start_date) { if (formData.joining_date < selectedBranch.operational_start_date) { errors.push(`Joining date (${formData.joining_date}) cannot be before branch start date (${selectedBranch.operational_start_date}).`); } } */ if (formData.advance_enabled) { if (!formData.advance_amount || parseFloat(formData.advance_amount) <= 0) errors.push('Please enter a valid Advance Amount.'); if (formData.advance_repayment_mode === 'Divide by Months' && (!formData.advance_months || parseInt(formData.advance_months) <= 0)) { errors.push('Please enter a valid number of months for repayment.'); } } if (formData.commission_enabled) { if (!formData.commission_amount || parseFloat(formData.commission_amount) <= 0) errors.push('Please enter a valid Commission Amount.'); if (!formData.commission_member_count || parseInt(formData.commission_member_count) <= 0) errors.push('Please enter a valid Member Count for commission.'); } // Family Details Validation formData.family_members.forEach((member, idx) => { if (member.name || member.relation || member.contact) { if (!member.name) errors.push(`Family Member ${idx + 1}: Name is required.`); if (!member.relation) errors.push(`Family Member ${idx + 1}: Relation is required.`); if (!member.contact) errors.push(`Family Member ${idx + 1}: Contact is required.`); else if (!/^(\+91|91|0)?[6-9]\d{9}$|^(\+971|971|0)?5[024568]\d{7}$/.test(member.contact.replace(/[\s-]/g, ''))) { errors.push(`Family Member ${idx + 1}: Invalid Contact format. Only Indian (+91) and UAE (+971) numbers are allowed.`); } } }); // Document Validations (Check if any document rows have partial data) formData.documents.forEach((doc, idx) => { if (doc.name || doc.document_number || doc.expiry_date || doc.file) { if (!doc.name) errors.push(`Document ${idx + 1}: Name is required.`); if (!doc.document_number) errors.push(`Document ${idx + 1}: Document Number is required.`); if (!doc.expiry_date) errors.push(`Document ${idx + 1}: Expiry Date is required.`); } }); if (errors.length > 0) { setToast({ message: 'Validation Errors:\n• ' + errors.join('\n• '), type: 'error' }); return; } setSaving(true); const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); const data = new FormData(); // ... (rest of the method remains similar but with the validation above) Object.keys(formData).forEach(key => { if (key === 'documents') { formData.documents.forEach((doc, index) => { data.append(`documents[${index}][name]`, doc.name); data.append(`documents[${index}][document_number]`, doc.document_number); data.append(`documents[${index}][expiry_date]`, doc.expiry_date); data.append(`documents[${index}][reminder_days]`, doc.reminder_days); if (doc.file) { data.append(`documents[${index}][file]`, doc.file); } }); } else if (key === 'family_members') { formData.family_members.forEach((member, index) => { data.append(`family_members[${index}][name]`, member.name); data.append(`family_members[${index}][relation]`, member.relation); data.append(`family_members[${index}][contact]`, member.contact); }); } else { let value = formData[key]; if (typeof value === 'boolean') { value = value ? '1' : '0'; } data.append(key, value); } }); try { const response = await fetch('/api/staff', { method: 'POST', headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': csrfToken }, body: data }); if (response.ok) { setToast({ message: 'Staff member added successfully!', type: 'success' }); setTimeout(() => window.location.href = `${basePath}/staff`, 1500); } else { const errorData = await response.json().catch(() => ({})); if (errorData.errors) { const message = Object.entries(errorData.errors) .map(([field, msgs]) => `${field.replace('_', ' ')}: ${msgs.join(', ')}`) .join('\n'); setToast({ message: 'Validation Error:\n' + message, type: 'error' }); } else { setToast({ message: 'Error saving staff member: ' + (errorData.message || response.statusText), type: 'error' }); } } } catch (error) { console.error('API Error:', error); setToast({ message: 'Failed to save staff member.', type: 'error' }); } finally { setSaving(false); } }; if (loading) return
Loading form...
; return (
{toast && setToast(null)} />}
{/* Top Actions */}
{/* Card 1: Basic Details */}

Basic Details

{!isReceptionist && (
)}
{/* Salary Details */}

Salary Details

{/* Salary Advance */}

Salary Advance

{!formData.advance_enabled ? (
) : (
Advance Configuration Active
{formData.advance_repayment_mode === 'Divide by Months' && (

Monthly Deduction

AED {((parseFloat(formData.advance_amount) || 0) / (parseInt(formData.advance_months) || 1)).toFixed(2)}

)}
)}
{/* Commission Card */}
Commission Settings
Enable per-person commission
{formData.commission_enabled && (

Total Commission

AED {((parseFloat(formData.commission_member_count) || 0) * (parseFloat(formData.commission_amount) || 0)).toFixed(2)}

* This amount will be added to the monthly settlement automatically.
)}
{/* Documentation Card */}
Documentation
{formData.documents.map((doc, index) => (
{formData.documents.length > 1 && ( )}
handleDocumentChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 transition-all font-medium" placeholder="Ex: Visa, Emirates ID, Passport" />
handleDocumentChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 transition-all font-medium" placeholder="Number / ID" />
handleDocumentChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 transition-all font-medium" />
handleDocumentChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-blue-500 transition-all font-medium" placeholder="30" />
handleDocumentChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-2.5 text-xs focus:ring-2 focus:ring-blue-500 transition-all font-medium file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-xs file:font-black file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100" />
))}
{/* Family Members Card */}
Family Members
{formData.family_members.map((member, index) => (
{formData.family_members.length > 1 && ( )}
handleFamilyMemberChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-emerald-500 transition-all font-medium" placeholder="e.g. Jane Doe" />
handleFamilyMemberChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-emerald-500 transition-all font-medium" placeholder="e.g. Spouse" />
handleFamilyMemberChange(index, e)} className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-emerald-500 transition-all font-medium" placeholder="05XXXXXXXX" />
))}
); }