2026-03-13 10:08:46 +05:30

636 lines
40 KiB
JavaScript

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 [roles, setRoles] = 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 fetchData = async () => {
try {
const [bRes, rRes] = await Promise.all([
fetch('/api/branches?status=Active'),
fetch('/api/masters/staff_role')
]);
const bData = await bRes.json();
const rData = await rRes.json();
setBranches(bData);
const activeRoles = rData.filter(r => r.status === 'Active');
setRoles(activeRoles);
if (activeRoles.length > 0) {
setFormData(prev => ({ ...prev, role: prev.role || activeRoles[0].name }));
}
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
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 (!doc.file) errors.push(`Document ${idx + 1}: Please upload a file.`);
}
});
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(/_/g, ' ')}: ${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 <div className="p-10 text-center font-medium text-gray-400">Loading form...</div>;
return (
<div className="pb-20">
{toast && <Toast message={toast.message} type={toast.type} onClose={() => setToast(null)} />}
<main className="p-8 max-w-5xl mx-auto space-y-8">
{/* Top Actions */}
<div className="flex items-center justify-between">
<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>
<button
onClick={handleSave}
disabled={saving}
className="flex items-center gap-2 px-6 py-2.5 bg-red-500 text-white rounded-xl font-bold text-sm hover:hover:scale-[1.02] active:scale-[0.98] transition-all shadow-lg shadow-red-100 disabled:opacity-50"
>
<Save size={18} />
<span>{saving ? 'Adding...' : 'Create Staff Member'}</span>
</button>
</div>
<form onSubmit={handleSave} className="grid grid-cols-1 gap-8">
{/* Card 1: Basic Details */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden">
<div className="p-6 border-b border-gray-50 bg-gray-50/30">
<h3 className="text-lg font-bold text-gray-900">Basic Details</h3>
</div>
<div className="p-8 grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Full Name *</label>
<input type="text" name="full_name" value={formData.full_name} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium" placeholder="Ex: Alex Johnson" />
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Email *</label>
<input type="text" name="email" value={formData.email} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium" placeholder="Ex: alex@gym.com" />
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Phone (India/UAE) *</label>
<input type="text" name="phone" value={formData.phone} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium" placeholder="Ex: +91 98765 43210 or +971 50 123 4567" />
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Role *</label>
<select name="role" value={formData.role} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium appearance-none">
{roles.length === 0 && <option value="">No roles configured</option>}
{roles.map(r => (
<option key={r.id} value={r.name}>{r.name}</option>
))}
</select>
</div>
{!isReceptionist && (
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Branch *</label>
<select name="branch_id" value={formData.branch_id} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium appearance-none">
<option value="">Select Branch...</option>
{branches.map(branch => (
<option key={branch.id} value={branch.id}>{branch.name}</option>
))}
</select>
</div>
)}
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Joining Date *</label>
<input type="date" name="joining_date" value={formData.joining_date} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium" />
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Status</label>
<select name="status" value={formData.status} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium appearance-none">
<option value="Active">Active</option>
<option value="Inactive">Inactive</option>
</select>
</div>
</div>
</div>
{/* Salary Details */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden">
<div className="p-6 border-b border-gray-50 bg-gray-50/30">
<h3 className="text-lg font-bold text-gray-900">Salary Details</h3>
</div>
<div className="p-8 grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Salary Type</label>
<select name="salary_type" value={formData.salary_type} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium appearance-none">
<option value="Monthly">Monthly</option>
<option value="Daily">Daily</option>
<option value="Weekly">Weekly</option>
</select>
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Amount (AED) *</label>
<input type="number" name="salary_amount" value={formData.salary_amount} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium" placeholder="0.00" />
</div>
</div>
</div>
{/* Salary Advance */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden">
<div className="p-6 border-b border-gray-50 bg-gray-50/30">
<h3 className="text-lg font-bold text-gray-900">Salary Advance</h3>
</div>
<div className="p-8 space-y-6">
{!formData.advance_enabled ? (
<div className="py-8 text-center bg-gray-50 rounded-2xl border-2 border-dashed border-gray-100">
<button
type="button"
onClick={() => setFormData({...formData, advance_enabled: true})}
className="px-6 py-2.5 bg-white border border-gray-200 text-gray-700 rounded-xl text-sm font-bold hover:bg-gray-50 transition-all shadow-sm flex items-center gap-2 mx-auto"
>
Get Advance
</button>
</div>
) : (
<div className="animate-in slide-in-from-top-2 duration-300 space-y-6">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-orange-500 shadow-[0_0_10px_rgba(249,115,22,0.5)]" />
<span className="text-[#344054] font-bold text-sm">Advance Configuration Active</span>
</div>
<button
type="button"
onClick={() => setFormData({...formData, advance_enabled: false, advance_amount: '', advance_months: ''})}
className="text-xs font-bold text-red-500 hover:text-red-600 transition-colors uppercase tracking-widest"
>
Remove Advance
</button>
</div>
<div className="grid grid-cols-2 gap-6 pt-4">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Advance Amount (AED)</label>
<input type="number" name="advance_amount" value={formData.advance_amount} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium" placeholder="e.g. 3000" />
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Repayment Mode</label>
<div className="flex gap-2">
<button
type="button"
onClick={() => setFormData({...formData, advance_repayment_mode: 'Full Next Month'})}
className={`flex-1 py-3 text-sm font-bold rounded-xl border transition-all ${formData.advance_repayment_mode === 'Full Next Month' ? 'border-orange-500 bg-orange-50/50 text-orange-600' : 'border-gray-200 text-gray-500 bg-white'}`}
>
Full Next Month
</button>
<button
type="button"
onClick={() => setFormData({...formData, advance_repayment_mode: 'Divide by Months'})}
className={`flex-1 py-3 text-sm font-bold rounded-xl border transition-all ${formData.advance_repayment_mode === 'Divide by Months' ? 'border-orange-500 bg-orange-50/50 text-orange-600' : 'border-gray-200 text-gray-500 bg-white'}`}
>
Divide by Months
</button>
</div>
</div>
</div>
{formData.advance_repayment_mode === 'Divide by Months' && (
<div className="grid grid-cols-2 gap-6 p-6 bg-gray-50 rounded-2xl border border-gray-100 animate-in zoom-in-95 duration-200">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Number of Months</label>
<input
type="number"
name="advance_months"
value={formData.advance_months}
onChange={handleChange}
className="w-full bg-white border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-red-500 transition-all font-medium"
placeholder="e.g. 3"
/>
</div>
<div className="flex flex-col justify-center">
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Monthly Deduction</p>
<p className="text-xl font-black text-orange-600">
AED {((parseFloat(formData.advance_amount) || 0) / (parseInt(formData.advance_months) || 1)).toFixed(2)}
</p>
</div>
</div>
)}
</div>
)}
</div>
</div>
{/* Commission Card */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden text-purple-600">
<div className="p-6 border-b border-gray-50 bg-gray-50/30 font-bold">
Commission Settings
</div>
<div className="p-8 space-y-6">
<div className="flex items-center gap-3">
<input
type="checkbox"
name="commission_enabled"
checked={formData.commission_enabled}
onChange={handleChange}
className="w-5 h-5 rounded border-gray-300 text-purple-600 focus:ring-purple-500 cursor-pointer"
/>
<span className="text-[#344054] font-medium text-sm">Enable per-person commission</span>
</div>
{formData.commission_enabled && (
<div className="animate-in slide-in-from-top-2 duration-300 space-y-6">
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Number of Members</label>
<input type="number" name="commission_member_count" value={formData.commission_member_count} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-purple-500 transition-all font-medium" placeholder="Ex: 15" />
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Amount per Person (AED)</label>
<input type="number" name="commission_amount" value={formData.commission_amount} onChange={handleChange} className="w-full bg-gray-50 border-none rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-purple-500 transition-all font-medium" placeholder="e.g. 195" />
</div>
</div>
<div className="grid grid-cols-2 gap-6 p-6 bg-purple-50 rounded-2xl border border-purple-100 animate-in zoom-in-95 duration-200">
<div>
<p className="text-[10px] font-bold text-purple-400 uppercase tracking-widest mb-1">Total Commission</p>
<p className="text-2xl font-black text-purple-600">
AED {((parseFloat(formData.commission_member_count) || 0) * (parseFloat(formData.commission_amount) || 0)).toFixed(2)}
</p>
</div>
<div className="flex items-center text-[10px] text-purple-400 font-medium leading-relaxed italic">
* This amount will be added to the monthly settlement automatically.
</div>
</div>
</div>
)}
</div>
</div>
<div className="grid grid-cols-2 gap-8">
{/* Documentation Card */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden text-blue-600">
<div className="p-6 border-b border-gray-50 bg-gray-50/30 flex items-center justify-between font-bold">
<span>Documentation</span>
<button
type="button"
onClick={addDocumentRow}
className="flex items-center gap-2 px-3 py-1.5 bg-blue-50 text-blue-600 rounded-lg text-xs hover:bg-blue-100 transition-all border border-blue-100"
>
<Plus size={14} />
<span>Add Document</span>
</button>
</div>
<div className="p-8 space-y-8">
{formData.documents.map((doc, index) => (
<div key={index} className="relative p-6 bg-gray-50 rounded-2xl border border-gray-100 animate-in slide-in-from-top-2 duration-300">
{formData.documents.length > 1 && (
<button
type="button"
onClick={() => removeDocumentRow(index)}
className="absolute top-4 right-4 text-red-400 hover:text-red-600 transition-colors"
>
<Trash2 size={18} />
</button>
)}
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Document Name</label>
<input
type="text"
name="name"
value={doc.name}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Document Number</label>
<input
type="text"
name="document_number"
value={doc.document_number}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Expiry Date</label>
<input
type="date"
name="expiry_date"
value={doc.expiry_date}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Days Before</label>
<input
type="number"
name="reminder_days"
value={doc.reminder_days}
onChange={(e) => 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"
/>
</div>
<div className="col-span-2">
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Upload Document</label>
<input
type="file"
name="file"
onChange={(e) => 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"
/>
</div>
</div>
</div>
))}
</div>
</div>
{/* Family Members Card */}
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm overflow-hidden text-emerald-600">
<div className="p-6 border-b border-gray-50 bg-gray-50/30 flex items-center justify-between font-bold">
<span>Family Members</span>
<button
type="button"
onClick={addFamilyMemberRow}
className="flex items-center gap-2 px-3 py-1.5 bg-emerald-50 text-emerald-600 rounded-lg text-xs hover:bg-emerald-100 transition-all border border-emerald-100"
>
<Plus size={14} />
<span>Add Member</span>
</button>
</div>
<div className="p-8 space-y-6">
{formData.family_members.map((member, index) => (
<div key={index} className="relative p-6 bg-gray-50 rounded-2xl border border-gray-100 animate-in slide-in-from-top-2 duration-300">
{formData.family_members.length > 1 && (
<button
type="button"
onClick={() => removeFamilyMemberRow(index)}
className="absolute top-4 right-4 text-red-400 hover:text-red-600 transition-colors"
>
<Trash2 size={18} />
</button>
)}
<div className="space-y-4">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Member Name</label>
<input
type="text"
name="name"
value={member.name}
onChange={(e) => 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"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Relation</label>
<input
type="text"
name="relation"
value={member.relation}
onChange={(e) => 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"
/>
</div>
<div>
<label className="block text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">Contact Number</label>
<input
type="text"
name="contact"
value={member.contact}
onChange={(e) => 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"
/>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</form>
</main>
</div>
);
}