"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import { ArrowLeft, Edit2, Save, X, User, Trash2, AlertTriangle, Shield, Plus, Check, X as XIcon, Briefcase, FileText, Upload, Loader2, Send } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select } from "@/components/ui/select"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { fetchEmployeeDetail, fetchDepartments, fetchManagerDropdown, updateEmployee, transferOwnership } from "@/lib/supabase/employees-actions"; import { fetchCustomRoles, assignRoleToEmployee, removeRoleFromEmployee, removeEmployee, fetchResignations, reviewResignation, canAccessPage, getUserPermissions } from "@/lib/supabase/rbac-actions"; import { fetchContractsForEmployee, createContract, sendContractForSignature, uploadContractFile, deleteContract } from "@/lib/supabase/contract-actions"; import { EMPLOYEE_STATUS_LABELS, EMPLOYMENT_TYPE_LABELS, PAY_FREQUENCY_LABELS, getInitials, type EmployeeWithRelations, type EmployeeStatus, type EmploymentType, type PayFrequency } from "@/lib/supabase/employees-types"; import PageSkeleton from "./PageSkeleton"; const AVATAR_COLORS = ["bg-teal-500", "bg-blue-500", "bg-purple-500", "bg-orange-500", "bg-pink-500"]; const STATUS_COLORS: Record = { active: "bg-emerald-100 text-emerald-700 border-emerald-200", on_leave: "bg-amber-100 text-amber-700 border-amber-200", terminated: "bg-red-100 text-red-700 border-red-200", }; const CONTRACT_STATUS_LABELS: Record = { draft: "Draft", sent: "Sent", signed: "Signed", declined: "Declined", }; const CONTRACT_STATUS_COLORS: Record = { draft: "bg-gray-100 text-gray-600 border-gray-200", sent: "bg-blue-100 text-blue-700 border-blue-200", signed: "bg-emerald-100 text-emerald-700 border-emerald-200", declined: "bg-red-100 text-red-700 border-red-200", }; function ComingSoon({ tab }: { tab: string }) { return (

{tab}

Coming soon

); } export default function EmployeesDetailPage({ employeeId, onBack, }: { employeeId: string; onBack: () => void; }) { const [employee, setEmployee] = useState(null); const [loading, setLoading] = useState(true); const [activeTab, setActiveTab] = useState("overview"); const [editing, setEditing] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [departments, setDepartments] = useState([]); const [managers, setManagers] = useState([]); const [canManage, setCanManage] = useState(false); const [currentOrgRole, setCurrentOrgRole] = useState("employee"); // Role management const [customRoles, setCustomRoles] = useState([]); const [employeeRoles, setEmployeeRoles] = useState([]); const [showRolePicker, setShowRolePicker] = useState(false); // Ownership transfer const [showTransferConfirm, setShowTransferConfirm] = useState(false); const [transferring, setTransferring] = useState(false); // Remove employee const [showRemoveConfirm, setShowRemoveConfirm] = useState(false); const [removing, setRemoving] = useState(false); // Contracts const [contracts, setContracts] = useState([]); const [loadingContracts, setLoadingContracts] = useState(false); const [showCreateContract, setShowCreateContract] = useState(false); const [contractTitle, setContractTitle] = useState(""); const [contractFile, setContractFile] = useState(null); const [creatingContract, setCreatingContract] = useState(false); const [sendingContract, setSendingContract] = useState(null); const fileInputRef = useRef(null); // Edit form state const [editFirstName, setEditFirstName] = useState(""); const [editLastName, setEditLastName] = useState(""); const [editEmail, setEditEmail] = useState(""); const [editPhone, setEditPhone] = useState(""); const [editJobTitle, setEditJobTitle] = useState(""); const [editDepartmentId, setEditDepartmentId] = useState(""); const [editStatus, setEditStatus] = useState("active"); const [editEmploymentType, setEditEmploymentType] = useState("full_time"); const [editPayFrequency, setEditPayFrequency] = useState("monthly"); const [editSalary, setEditSalary] = useState(""); const [editHourlyRate, setEditHourlyRate] = useState(""); const [editManagerId, setEditManagerId] = useState(""); useEffect(() => { let cancelled = false; Promise.all([ fetchEmployeeDetail(employeeId), fetchDepartments(), fetchManagerDropdown(), fetchCustomRoles().catch(() => []), canAccessPage("employees").catch(() => false), getUserPermissions().catch(() => ({ orgRole: "employee" })), ]) .then(([emp, depts, mgrs, roles, canM, perms]) => { if (!cancelled) { setEmployee(emp); setDepartments(depts); setManagers(mgrs); setCustomRoles(roles); setCanManage(canM); setCurrentOrgRole(perms.orgRole); if (emp) { setEditFirstName(emp.first_name); setEditLastName(emp.last_name); setEditEmail(emp.email); setEditPhone(emp.phone || ""); setEditJobTitle(emp.job_title || ""); setEditDepartmentId(emp.department_id || ""); setEditStatus(emp.status); setEditEmploymentType(emp.employment_type); setEditPayFrequency(emp.pay_frequency); setEditSalary(emp.salary ? String(emp.salary) : ""); setEditHourlyRate(emp.hourly_rate ? String(emp.hourly_rate) : ""); setEditManagerId(emp.manager_id || ""); setEmployeeRoles(emp.employee_roles || []); } } }) .catch(() => {}) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [employeeId]); // Load contracts when documents tab is active useEffect(() => { if (activeTab !== "documents" || !employee) return; let cancelled = false; setLoadingContracts(true); fetchContractsForEmployee(employee.id) .then((data) => { if (!cancelled) setContracts(data); }) .catch(() => {}) .finally(() => { if (!cancelled) setLoadingContracts(false); }); return () => { cancelled = true; }; }, [activeTab, employee]); const handleSave = useCallback(async () => { if (!employee) return; setSaving(true); setError(null); try { const result = await updateEmployee(employee.id, { first_name: editFirstName, last_name: editLastName, email: editEmail, phone: editPhone || undefined, job_title: editJobTitle || undefined, department_id: editDepartmentId || undefined, status: editStatus, employment_type: editEmploymentType, pay_frequency: editPayFrequency, salary: editSalary ? parseFloat(editSalary) : undefined, hourly_rate: editHourlyRate ? parseFloat(editHourlyRate) : undefined, manager_id: editManagerId || undefined, }); if (!result.success) { setError(result.error || "Failed to update"); return; } setEditing(false); const updated = await fetchEmployeeDetail(employeeId); setEmployee(updated); } catch (e: any) { setError(e.message || "An unexpected error occurred"); } finally { setSaving(false); } }, [employee, editFirstName, editLastName, editEmail, editPhone, editJobTitle, editDepartmentId, editStatus, editEmploymentType, editPayFrequency, editSalary, editHourlyRate, editManagerId, employeeId]); const handleCancel = useCallback(() => { if (!employee) return; setEditFirstName(employee.first_name); setEditLastName(employee.last_name); setEditEmail(employee.email); setEditPhone(employee.phone || ""); setEditJobTitle(employee.job_title || ""); setEditDepartmentId(employee.department_id || ""); setEditStatus(employee.status); setEditEmploymentType(employee.employment_type); setEditPayFrequency(employee.pay_frequency); setEditSalary(employee.salary ? String(employee.salary) : ""); setEditHourlyRate(employee.hourly_rate ? String(employee.hourly_rate) : ""); setEditManagerId(employee.manager_id || ""); setEditing(false); setError(null); }, [employee]); const handleAssignRole = async (roleId: string) => { if (!employee) return; const result = await assignRoleToEmployee(employee.id, roleId); if (result.success) { const roles = await fetchCustomRoles(); setCustomRoles(roles); const emp = await fetchEmployeeDetail(employeeId); if (emp) { setEmployee(emp); setEmployeeRoles(emp.employee_roles || []); } } setShowRolePicker(false); }; const handleRemoveRole = async (roleId: string) => { if (!employee) return; const result = await removeRoleFromEmployee(employee.id, roleId); if (result.success) { const emp = await fetchEmployeeDetail(employeeId); if (emp) { setEmployee(emp); setEmployeeRoles(emp.employee_roles || []); } } }; const handleTransferOwnership = async () => { if (!employee || !employee.user_id) return; setTransferring(true); try { const result = await transferOwnership(employee.user_id); if (result.success) { alert("Ownership transferred successfully. You are now an Admin."); onBack(); } else { setError(result.error || "Failed to transfer ownership"); } } catch (e: any) { setError(e.message); } finally { setTransferring(false); setShowTransferConfirm(false); } }; const handleRemoveEmployee = async () => { if (!employee) return; setRemoving(true); try { const result = await removeEmployee(employee.id); if (!result.success) { setError(result.error || "Failed to remove"); return; } onBack(); } catch (e: any) { setError(e.message || "An unexpected error occurred"); } finally { setRemoving(false); setShowRemoveConfirm(false); } }; const handleCreateContract = async () => { if (!employee || !contractTitle.trim()) return; setCreatingContract(true); setError(null); try { let templateUrl: string | undefined; if (contractFile) { const uploadResult = await uploadContractFile(contractFile); if (!uploadResult.success) { setError(uploadResult.error || "Failed to upload file"); return; } templateUrl = uploadResult.url; } const result = await createContract({ employee_id: employee.id, title: contractTitle.trim(), template_url: templateUrl }); if (!result.success) { setError(result.error || "Failed to create contract"); return; } // Send for signature if (result.id) { await sendContractForSignature(result.id); } setContractTitle(""); setContractFile(null); setShowCreateContract(false); const data = await fetchContractsForEmployee(employee.id); setContracts(data); } catch (e: any) { setError(e.message || "An unexpected error occurred"); } finally { setCreatingContract(false); } }; const handleSendContract = async (id: string) => { setSendingContract(id); try { const result = await sendContractForSignature(id); if (!result.success) { setError(result.error || "Failed to send"); return; } if (employee) { const data = await fetchContractsForEmployee(employee.id); setContracts(data); } } catch (e: any) { setError(e.message || "An unexpected error occurred"); } finally { setSendingContract(null); } }; const handleDeleteContract = async (id: string) => { const result = await deleteContract(id); if (!result.success) { setError(result.error || "Failed to delete"); return; } if (employee) { const data = await fetchContractsForEmployee(employee.id); setContracts(data); } }; if (loading) return ; if (!employee) return
Employee not found
; const displayPay = employee.salary ? `$${Number(employee.salary).toLocaleString()}/yr` : employee.hourly_rate ? `$${Number(employee.hourly_rate)}/hr` : "—"; const TABS = [ { key: "overview", label: "Overview" }, { key: "leave", label: "Leave" }, { key: "payroll", label: "Payroll" }, { key: "documents", label: "Documents" }, { key: "performance", label: "Performance" }, ]; const empRole = (employee as any).role || 'employee'; return (
{/* Header */}
{getInitials(employee.first_name, employee.last_name)}

{employee.first_name} {employee.last_name}

{employee.job_title || "No title"}{employee.department?.name ? ` · ${employee.department.name}` : ""}

{(employee as any).resignation_status === "submitted" && ( Resignation pending )} {(employee as any).resignation_status === "accepted" && ( Resignation accepted )}
{/* Remove button (admin only) */} {canManage && empRole !== 'owner' && ( )} {!editing ? ( ) : (
)}
{error && (
{error}
)} {/* Tabs */}
{TABS.map((tab) => ( ))}
{/* Tab Content */} {activeTab === "overview" && (
{/* Personal Details */}

Personal Details

{editing ? (
setEditFirstName(e.target.value)} className="mt-1" />
setEditLastName(e.target.value)} className="mt-1" />
setEditEmail(e.target.value)} className="mt-1" />
setEditPhone(e.target.value)} className="mt-1" />
) : (
First Name {employee.first_name}
Last Name {employee.last_name}
Email {employee.email}
Phone {employee.phone || "—"}
)}
{/* Employment Details */}

Employment Details

{editing ? (
setEditJobTitle(e.target.value)} className="mt-1" />
{(editEmploymentType === "full_time" || editEmploymentType === "part_time") && (
setEditSalary(e.target.value)} className="mt-1" placeholder="80000" />
)} {(editEmploymentType === "casual" || editEmploymentType === "contractor") && (
setEditHourlyRate(e.target.value)} className="mt-1" placeholder="35" />
)}
) : (
Job Title {employee.job_title || "—"}
Department {employee.department?.name || "—"}
Type {EMPLOYMENT_TYPE_LABELS[employee.employment_type]}
Pay {displayPay}
Frequency {PAY_FREQUENCY_LABELS[employee.pay_frequency]}
Manager {employee.manager ? `${employee.manager.first_name} ${employee.manager.last_name}` : "—"}
)}
{/* Roles */} {canManage && (

Roles & Permissions

{currentOrgRole === "owner" && employee.user_id && empRole !== "owner" && ( )}
{showRolePicker && (

Select a role to assign:

{customRoles.length === 0 ? (

No custom roles created yet.

) : ( customRoles.map((role: any) => { const isAssigned = employeeRoles.some((er: any) => er.role_id === role.id); return (
{role.name} Level {role.hierarchy_level}
{isAssigned ? ( Assigned ) : ( )}
); }) )}
)} {employeeRoles.length === 0 ? (

No custom roles assigned.

) : (
{employeeRoles.map((er: any) => (
{er.role?.name || "Unknown"} Level {er.role?.hierarchy_level || "?"}
))}
)}
)} {/* Resignation */} {((employee as any).resignation_status === "submitted" || (employee as any).resignation_status === "accepted") && (

Resignation {(employee as any).resignation_status === "submitted" ? "Submitted" : "Accepted"}

Last Day: {(employee as any).resignation_date ? new Date((employee as any).resignation_date + "T00:00:00").toLocaleDateString("en-AU", { day: "numeric", month: "long", year: "numeric" }) : "—"}

{(employee as any).resignation_reason &&

Reason: {(employee as any).resignation_reason}

}
)}
)} {activeTab === "leave" && } {activeTab === "payroll" && } {activeTab === "documents" && (

Contracts

{canManage && ( )}
{loadingContracts ? (
) : contracts.length === 0 ? (
No contracts yet.
) : (
{contracts.map((c: any) => ( ))}
Title Status Sent Signed Actions
{c.title} {CONTRACT_STATUS_LABELS[c.status] || c.status} {c.sent_at ? new Date(c.sent_at).toLocaleDateString("en-AU", { day: "numeric", month: "short", year: "numeric" }) : "—"} {c.signed_at ? new Date(c.signed_at).toLocaleDateString("en-AU", { day: "numeric", month: "short", year: "numeric" }) : "—"}
{(c.status === "draft" || c.status === "sent") && canManage && ( )} {c.status === "draft" && canManage && ( )}
)}
)} {activeTab === "performance" && } {/* Remove Employee Confirmation Modal */} {showRemoveConfirm && (
setShowRemoveConfirm(false)}>
e.stopPropagation()}>

Remove Employee

Are you sure you want to remove {employee.first_name} {employee.last_name} from the organisation? This action cannot be undone.

)} {/* Transfer Ownership Confirmation Modal */} {showTransferConfirm && (
setShowTransferConfirm(false)}>
e.stopPropagation()}>

Transfer Organisation Ownership

Are you sure you want to transfer ownership of this organisation to {employee.first_name} {employee.last_name}?

You will lose owner privileges and become an Admin. This action is significant and should be done with caution.

)} {/* Create Contract Modal */} {showCreateContract && (
setShowCreateContract(false)}>
e.stopPropagation()}>

Create Contract

setContractTitle(e.target.value)} className="mt-1" placeholder="e.g. Employment Agreement" />
fileInputRef.current?.click()} className="mt-1 border-2 border-dashed border-gray-200 rounded-lg p-4 flex items-center gap-3 cursor-pointer hover:border-[#1D9E75] hover:bg-[#E1F5EE]/30 transition-colors" >

{contractFile ? contractFile.name : "Click to upload contract PDF"}

{contractFile && (

{(contractFile.size / 1024).toFixed(1)} KB

)}
{ const file = e.target.files?.[0]; if (file) setContractFile(file); }} className="hidden" />
)}
); } function StatusBadge({ status }: { status: EmployeeStatus }) { return ( {EMPLOYEE_STATUS_LABELS[status]} ); }