@burdenoff/microfe-crewfoundry 2026.1029.2 → 2026.1030.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/crewfoundry/components/EmployeeSkillsPanel.d.ts +12 -0
  2. package/dist/crewfoundry/components/EmployeeSkillsPanel.d.ts.map +1 -0
  3. package/dist/crewfoundry/components/EmployeeSkillsPanel.js +168 -0
  4. package/dist/crewfoundry/components/EmployeeSkillsPanel.js.map +1 -0
  5. package/dist/crewfoundry/lib/useFocusedRecordParam.d.ts +51 -0
  6. package/dist/crewfoundry/lib/useFocusedRecordParam.d.ts.map +1 -0
  7. package/dist/crewfoundry/lib/useFocusedRecordParam.js +38 -0
  8. package/dist/crewfoundry/lib/useFocusedRecordParam.js.map +1 -0
  9. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.d.ts.map +1 -1
  10. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +119 -112
  11. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
  12. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.d.ts.map +1 -1
  13. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +78 -71
  14. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  15. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.d.ts.map +1 -1
  16. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +88 -81
  17. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  18. package/dist/crewfoundry/pages/HiringCandidatesPagePage.d.ts.map +1 -1
  19. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +133 -126
  20. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  21. package/dist/crewfoundry/pages/HiringInterviewsPagePage.d.ts.map +1 -1
  22. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +150 -143
  23. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  24. package/dist/crewfoundry/pages/HrDepartmentsPagePage.d.ts.map +1 -1
  25. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +110 -103
  26. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  27. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.d.ts.map +1 -1
  28. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +124 -134
  29. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -1
  30. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.d.ts.map +1 -1
  31. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +173 -162
  32. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  33. package/dist/crewfoundry/pages/HrPayrollPagePage.d.ts.map +1 -1
  34. package/dist/crewfoundry/pages/HrPayrollPagePage.js +169 -158
  35. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  36. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.d.ts.map +1 -1
  37. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +179 -163
  38. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  39. package/dist/crewfoundry/store/crewfoundryStore.d.ts +22 -0
  40. package/dist/crewfoundry/store/crewfoundryStore.d.ts.map +1 -1
  41. package/dist/crewfoundry/store/crewfoundryStore.js +158 -129
  42. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  43. package/dist/utils/pageContext.d.ts +43 -4
  44. package/dist/utils/pageContext.d.ts.map +1 -1
  45. package/dist/utils/pageContext.js +10 -3
  46. package/dist/utils/pageContext.js.map +1 -1
  47. package/package.json +3 -2
@@ -1 +1 @@
1
- {"version":3,"file":"HrDepartmentsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HrDepartmentsPagePage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Building2, DollarSign, MapPin, Network, Pencil, Plus, Trash2, Users } from 'lucide-react';\nimport { useCrewFoundryStore, type Department, type Employee } from '../store/crewfoundryStore';\nimport { AvatarStack, OrgTree, StatCard, type OrgNode } from '../components/viz';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getText, newClientId } from '../components/forms/formValues';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nconst fullName = (employee: Employee): string =>\n `${employee.firstName} ${employee.lastName}`.trim();\n\nconst DEPARTMENT_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Department name', type: 'text', required: true, colSpan: 2 },\n { name: 'headName', label: 'Department head', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n { name: 'budget', label: 'Annual budget', type: 'number', required: true },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Restructuring', value: 'restructuring' },\n ],\n },\n];\n\nconst toFormValues = (department: Department): FormValues => ({\n name: department.name,\n headName: department.headName,\n location: department.location,\n budget: department.budget,\n status: department.status,\n});\n\nexport function HrDepartmentsPagePage() {\n const { departments, employees, teams, addDepartment, updateDepartment, removeDepartment } =\n useCrewFoundryStore();\n const form = useFormModal<Department>();\n const [deleting, setDeleting] = useState<Department | null>(null);\n\n const totalBudget = departments.reduce((s, d) => s + d.budget, 0);\n const totalHeadcount = departments.reduce((s, d) => s + d.employeeCount, 0);\n\n const editing = form.context;\n\n // Resolve a department's head to a real employee (by id first, then by name) so\n // we can show a real avatar rather than a text-only name.\n const headOf = useCallback(\n (department: Department): Employee | undefined =>\n employees.find((e) => e.id === department.headId) ||\n employees.find((e) => fullName(e) === department.headName),\n [employees]\n );\n\n // Org structure: a real hierarchy derived from the roster + departments + teams.\n // Root = a top-of-org employee (CEO / founder / chief with no manager) when one\n // exists, else a generic company node. Each department hangs off the root with\n // its head; each department's children are its real teams (or a sample of its\n // real employees when the department has no teams).\n const orgRoot = useMemo<OrgNode | null>(() => {\n if (departments.length === 0) {\n return null;\n }\n const topLeader = employees.find(\n (e) => !e.managerId && /chief|ceo|founder|president|head of company/i.test(e.position)\n );\n\n const deptNodes: OrgNode[] = departments.map((department) => {\n const head = headOf(department);\n const deptTeams = teams.filter((team) => team.department === department.name);\n let children: OrgNode[];\n if (deptTeams.length > 0) {\n children = deptTeams.slice(0, 4).map((team) => ({\n id: team.id,\n name: team.name,\n role: `${team.memberCount} member${team.memberCount === 1 ? '' : 's'}`,\n }));\n } else {\n children = employees\n .filter((e) => e.department === department.name && e.id !== head?.id)\n .slice(0, 3)\n .map((e) => ({ id: e.id, name: fullName(e), role: e.position, avatarUrl: e.avatar }));\n }\n return {\n id: department.id,\n name: department.name,\n role: department.headName ? `${department.headName}, Head` : 'Department',\n avatarUrl: head?.avatar,\n children,\n };\n });\n\n return {\n id: topLeader?.id ?? 'org-root',\n name: topLeader ? fullName(topLeader) : 'Organization',\n role: topLeader?.position ?? 'Company',\n avatarUrl: topLeader?.avatar,\n children: deptNodes,\n };\n }, [departments, employees, teams, headOf]);\n\n const handleSubmit = async (values: FormValues) => {\n const payload: Department = {\n id: editing?.id ?? newClientId(),\n name: getText(values, 'name'),\n headId: editing?.headId ?? '',\n headName: getText(values, 'headName'),\n employeeCount: editing?.employeeCount ?? 0,\n budget: getNumber(values, 'budget'),\n location: getText(values, 'location'),\n status: getText(values, 'status') as Department['status'],\n };\n if (editing) {\n await updateDepartment(editing.id, payload);\n } else {\n await addDepartment(payload);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Departments</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Organizational structure and department management\n </p>\n <PagePurpose className=\"mt-1\">\n Organize your company into departments — set up structure, assign heads, and see how\n headcount is distributed across the org.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => form.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Department\n </Button>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <StatCard\n label=\"Total Departments\"\n value={departments.length}\n icon={<Building2 className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Total Headcount\"\n value={totalHeadcount}\n icon={<Users className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Total Budget\"\n value={`$${(totalBudget / 1000000).toFixed(1)}M`}\n icon={<DollarSign className=\"h-4 w-4\" />}\n />\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {departments.map((dept) => {\n const deptEmps = employees.filter((e) => e.department === dept.name);\n const headcount = dept.employeeCount || deptEmps.length;\n const avgSalary =\n deptEmps.length > 0\n ? Math.round(deptEmps.reduce((s, e) => s + e.salary, 0) / deptEmps.length)\n : 0;\n const avgPerfValue =\n deptEmps.length > 0\n ? deptEmps.reduce((s, e) => s + e.performanceScore, 0) / deptEmps.length\n : 0;\n // Progress bar = real average performance for the department, on a 0–100\n // scale (score out of 5). A clearly-labeled, computed metric — no fabrication.\n const perfPct = Math.round((avgPerfValue / 5) * 100);\n const head = headOf(dept);\n const perfTone =\n perfPct >= 80\n ? 'bg-status-success-text'\n : perfPct >= 60\n ? 'bg-status-warning-text'\n : 'bg-status-error-text';\n\n return (\n <GlassCard key={dept.id} treatment=\"glass\" className=\"border-border-seam\">\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"truncate text-lg\">{dept.name}</CardTitle>\n <div className=\"mt-2 flex items-center gap-2\">\n <AvatarStack\n people={[{ name: dept.headName || 'Unassigned', avatarUrl: head?.avatar }]}\n size={28}\n />\n <span className=\"truncate text-sm text-text-secondary\">\n <span className=\"font-medium text-text-primary\">{dept.headName}</span>\n {dept.headName ? ', Head' : 'No head assigned'}\n </span>\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n <Badge variant={dept.status === 'active' ? 'default' : 'secondary'}>\n {formatEnumLabel(dept.status)}\n </Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Edit ${dept.name}`}\n onClick={() => form.openModal(dept)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Delete ${dept.name}`}\n onClick={() => setDeleting(dept)}\n >\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-end justify-between gap-3\">\n <div>\n <p className=\"text-3xl font-bold leading-none tabular-nums\">{headcount}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">Employees</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-lg font-semibold tabular-nums\">\n ${(dept.budget / 1000000).toFixed(1)}M\n </p>\n <p className=\"text-xs text-text-secondary\">Annual budget</p>\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>Avg performance</span>\n <span className=\"font-medium text-text-primary tabular-nums\">{perfPct}%</span>\n </div>\n <div className=\"h-2 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className={`h-2 rounded-full ${perfTone}`}\n style={{ width: `${perfPct}%` }}\n />\n </div>\n </div>\n\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" />\n {dept.location}\n </span>\n <span>\n Cost/Head:{' '}\n {headcount > 0 ? `$${Math.round(dept.budget / headcount / 1000)}K` : '—'}\n </span>\n </div>\n {avgSalary > 0 && (\n <p className=\"text-xs text-text-secondary\">\n Avg salary{' '}\n <span className=\"font-medium text-text-primary\">\n ${avgSalary.toLocaleString()}\n </span>\n </p>\n )}\n </CardContent>\n </GlassCard>\n );\n })}\n </div>\n\n {orgRoot && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-lg\">\n <Network className=\"h-4 w-4 text-text-secondary\" />\n Org structure\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"overflow-x-auto pb-2\">\n <div className=\"min-w-fit\">\n <OrgTree root={orgRoot} />\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <FormModal\n open={form.open}\n onOpenChange={form.onOpenChange}\n title={editing ? 'Edit department' : 'Add department'}\n description={\n editing\n ? 'Update this department’s details.'\n : 'Create a new department in your organization.'\n }\n fields={DEPARTMENT_FIELDS}\n initialValues={editing ? toFormValues(editing) : undefined}\n submitLabel={editing ? 'Save changes' : 'Add department'}\n onSubmit={handleSubmit}\n />\n\n <ConfirmDialog\n open={deleting !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleting(null);\n }\n }}\n title=\"Delete department?\"\n description={\n deleting ? `${deleting.name} will be removed. This cannot be undone.` : undefined\n }\n confirmLabel=\"Delete\"\n destructive\n onConfirm={async () => {\n if (deleting) {\n await removeDepartment(deleting.id);\n setDeleting(null);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAyBA,IAAM,KAAY,MAChB,GAAG,EAAS,UAAU,GAAG,EAAS,WAAW,MAAM,EAE/C,IAAmC;CACvC;EAAE,MAAM;EAAQ,OAAO;EAAmB,MAAM;EAAQ,UAAU;EAAM,SAAS;EAAG;CACpF;EAAE,MAAM;EAAY,OAAO;EAAmB,MAAM;EAAQ,UAAU;EAAM;CAC5E;EAAE,MAAM;EAAY,OAAO;EAAY,MAAM;EAAQ,UAAU;EAAM;CACrE;EAAE,MAAM;EAAU,OAAO;EAAiB,MAAM;EAAU,UAAU;EAAM;CAC1E;EACE,MAAM;EACN,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS,CACP;GAAE,OAAO;GAAU,OAAO;GAAU,EACpC;GAAE,OAAO;GAAiB,OAAO;GAAiB,CACnD;EACF;CACF,EAEK,KAAgB,OAAwC;CAC5D,MAAM,EAAW;CACjB,UAAU,EAAW;CACrB,UAAU,EAAW;CACrB,QAAQ,EAAW;CACnB,QAAQ,EAAW;CACpB;AAED,SAAgB,IAAwB;CACtC,IAAM,EAAE,gBAAa,cAAW,UAAO,kBAAe,qBAAkB,wBACtE,GAAqB,EACjB,IAAO,GAA0B,EACjC,CAAC,GAAU,KAAe,EAA4B,KAAK,EAE3D,IAAc,EAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,QAAQ,EAAE,EAC3D,IAAiB,EAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,eAAe,EAAE,EAErE,IAAU,EAAK,SAIf,IAAS,GACZ,MACC,EAAU,MAAM,MAAM,EAAE,OAAO,EAAW,OAAO,IACjD,EAAU,MAAM,MAAM,EAAS,EAAE,KAAK,EAAW,SAAS,EAC5D,CAAC,EAAU,CACZ,EAOK,IAAU,QAA8B;AAC5C,MAAI,EAAY,WAAW,EACzB,QAAO;EAET,IAAM,IAAY,EAAU,MACzB,MAAM,CAAC,EAAE,aAAa,+CAA+C,KAAK,EAAE,SAAS,CACvF,EAEK,IAAuB,EAAY,KAAK,MAAe;GAC3D,IAAM,IAAO,EAAO,EAAW,EACzB,IAAY,EAAM,QAAQ,MAAS,EAAK,eAAe,EAAW,KAAK,EACzE;AAaJ,UAZA,AAOE,IAPE,EAAU,SAAS,IACV,EAAU,MAAM,GAAG,EAAE,CAAC,KAAK,OAAU;IAC9C,IAAI,EAAK;IACT,MAAM,EAAK;IACX,MAAM,GAAG,EAAK,YAAY,SAAS,EAAK,gBAAgB,IAAI,KAAK;IAClE,EAAE,GAEQ,EACR,QAAQ,MAAM,EAAE,eAAe,EAAW,QAAQ,EAAE,OAAO,GAAM,GAAG,CACpE,MAAM,GAAG,EAAE,CACX,KAAK,OAAO;IAAE,IAAI,EAAE;IAAI,MAAM,EAAS,EAAE;IAAE,MAAM,EAAE;IAAU,WAAW,EAAE;IAAQ,EAAE,EAElF;IACL,IAAI,EAAW;IACf,MAAM,EAAW;IACjB,MAAM,EAAW,WAAW,GAAG,EAAW,SAAS,UAAU;IAC7D,WAAW,GAAM;IACjB;IACD;IACD;AAEF,SAAO;GACL,IAAI,GAAW,MAAM;GACrB,MAAM,IAAY,EAAS,EAAU,GAAG;GACxC,MAAM,GAAW,YAAY;GAC7B,WAAW,GAAW;GACtB,UAAU;GACX;IACA;EAAC;EAAa;EAAW;EAAO;EAAO,CAAC;AAoB3C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,MAAD;MAAI,WAAU;gBACZ,kBAAC,GAAD,EAAA,UAAc,eAA0B,CAAA;MACrC,CAAA;KACL,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAEvC,CAAA;KACJ,kBAAC,GAAD;MAAa,WAAU;gBAAO;MAGhB,CAAA;KACV,EAAA,CAAA,EACN,kBAAC,GAAD;KAAQ,MAAK;KAAK,eAAe,EAAK,WAAW;eAAjD,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,iBAE1B;OACL;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAY;MACnB,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;MACvC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO;MACP,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,KAAK,IAAc,KAAS,QAAQ,EAAE,CAAC;MAC9C,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,CAAA;KACE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAY,KAAK,MAAS;KACzB,IAAM,IAAW,EAAU,QAAQ,MAAM,EAAE,eAAe,EAAK,KAAK,EAC9D,IAAY,EAAK,iBAAiB,EAAS,QAC3C,IACJ,EAAS,SAAS,IACd,KAAK,MAAM,EAAS,QAAQ,GAAG,MAAM,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAS,OAAO,GACxE,GACA,IACJ,EAAS,SAAS,IACd,EAAS,QAAQ,GAAG,MAAM,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAS,SAChE,GAGA,IAAU,KAAK,MAAO,IAAe,IAAK,IAAI,EAC9C,IAAO,EAAO,EAAK,EACnB,IACJ,KAAW,KACP,2BACA,KAAW,KACT,2BACA;AAER,YACE,kBAAC,GAAD;MAAyB,WAAU;MAAQ,WAAU;gBAArD,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAW,WAAU;mBAAoB,EAAK;SAAiB,CAAA,EAC/D,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UACE,QAAQ,CAAC;WAAE,MAAM,EAAK,YAAY;WAAc,WAAW,GAAM;WAAQ,CAAC;UAC1E,MAAM;UACN,CAAA,EACF,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAiC,EAAK;WAAgB,CAAA,EACrE,EAAK,WAAW,WAAW,mBACvB;YACH;WACF;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,GAAD;UAAO,SAAS,EAAK,WAAW,WAAW,YAAY;oBACpD,EAAgB,EAAK,OAAO;UACvB,CAAA;SACR,kBAAC,GAAD;UACE,SAAQ;UACR,MAAK;UACL,WAAU;UACV,cAAY,QAAQ,EAAK;UACzB,eAAe,EAAK,UAAU,EAAK;oBAEnC,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;UACvB,CAAA;SACT,kBAAC,GAAD;UACE,SAAQ;UACR,MAAK;UACL,WAAU;UACV,cAAY,UAAU,EAAK;UAC3B,eAAe,EAAY,EAAK;oBAEhC,kBAAC,GAAD,EAAQ,WAAU,kCAAmC,CAAA;UAC9C,CAAA;SACL;UACF;UACK,CAAA,EACb,kBAAC,GAAD;OAAa,WAAU;iBAAvB;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAgD;UAAc,CAAA,EAC3E,kBAAC,KAAD;UAAG,WAAU;oBAAmC;UAAa,CAAA,CACzD,EAAA,CAAA,EACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAb;YAAkD;aAC7C,EAAK,SAAS,KAAS,QAAQ,EAAE;YAAC;YACnC;cACJ,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAiB,CAAA,CACxD;YACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD,EAAA,UAAM,mBAAsB,CAAA,EAC5B,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAA8D,GAAQ,IAAQ;aAC1E;aACN,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,OAAD;WACE,WAAW,oBAAoB;WAC/B,OAAO,EAAE,OAAO,GAAG,EAAQ,IAAI;WAC/B,CAAA;UACE,CAAA,CACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAC7B,EAAK,SACD;aACP,kBAAC,QAAD,EAAA,UAAA;UAAM;UACO;UACV,IAAY,IAAI,IAAI,KAAK,MAAM,EAAK,SAAS,IAAY,IAAK,CAAC,KAAK;UAChE,EAAA,CAAA,CACH;;QACL,IAAY,KACX,kBAAC,KAAD;SAAG,WAAU;mBAAb;UAA2C;UAC9B;UACX,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAAgD,KAC5C,EAAU,gBAAgB,CACvB;;UACL;;QAEM;SACJ;QAvFI,EAAK,GAuFT;MAEd;IACE,CAAA;GAEL,KACC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,GAAD,EAAS,WAAU,+BAAgC,CAAA,EAAA,gBAEzC;OACD,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAS,MAAM,GAAW,CAAA;KACtB,CAAA;IACF,CAAA,EACM,CAAA,CACT,EAAA,CAAA;GAGT,kBAAC,GAAD;IACE,MAAM,EAAK;IACX,cAAc,EAAK;IACnB,OAAO,IAAU,oBAAoB;IACrC,aACE,IACI,sCACA;IAEN,QAAQ;IACR,eAAe,IAAU,EAAa,EAAQ,GAAG,KAAA;IACjD,aAAa,IAAU,iBAAiB;IACxC,UA3Me,OAAO,MAAuB;KACjD,IAAM,IAAsB;MAC1B,IAAI,GAAS,MAAM,GAAa;MAChC,MAAM,EAAQ,GAAQ,OAAO;MAC7B,QAAQ,GAAS,UAAU;MAC3B,UAAU,EAAQ,GAAQ,WAAW;MACrC,eAAe,GAAS,iBAAiB;MACzC,QAAQ,EAAU,GAAQ,SAAS;MACnC,UAAU,EAAQ,GAAQ,WAAW;MACrC,QAAQ,EAAQ,GAAQ,SAAS;MAClC;AACD,KAAI,IACF,MAAM,EAAiB,EAAQ,IAAI,EAAQ,GAE3C,MAAM,EAAc,EAAQ;;IA8L1B,CAAA;GAEF,kBAAC,GAAD;IACE,MAAM,MAAa;IACnB,eAAe,MAAS;AACtB,KAAK,KACH,EAAY,KAAK;;IAGrB,OAAM;IACN,aACE,IAAW,GAAG,EAAS,KAAK,4CAA4C,KAAA;IAE1E,cAAa;IACb,aAAA;IACA,WAAW,YAAY;AACrB,KAAI,MACF,MAAM,EAAiB,EAAS,GAAG,EACnC,EAAY,KAAK;;IAGrB,CAAA;GACE"}
1
+ {"version":3,"file":"HrDepartmentsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/HrDepartmentsPagePage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Building2, DollarSign, MapPin, Network, Pencil, Plus, Trash2, Users } from 'lucide-react';\nimport { useCrewFoundryStore, type Department, type Employee } from '../store/crewfoundryStore';\nimport { AvatarStack, OrgTree, StatCard, type OrgNode } from '../components/viz';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { ConfirmDialog } from '../components/forms/ConfirmDialog';\nimport { getNumber, getText, newClientId } from '../components/forms/formValues';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { useFocusedRecordParam } from '../lib/useFocusedRecordParam';\n\nconst fullName = (employee: Employee): string =>\n `${employee.firstName} ${employee.lastName}`.trim();\n\nconst DEPARTMENT_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Department name', type: 'text', required: true, colSpan: 2 },\n { name: 'headName', label: 'Department head', type: 'text', required: true },\n { name: 'location', label: 'Location', type: 'text', required: true },\n { name: 'budget', label: 'Annual budget', type: 'number', required: true },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n required: true,\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Restructuring', value: 'restructuring' },\n ],\n },\n];\n\nconst toFormValues = (department: Department): FormValues => ({\n name: department.name,\n headName: department.headName,\n location: department.location,\n budget: department.budget,\n status: department.status,\n});\n\nexport function HrDepartmentsPagePage() {\n const { departments, employees, teams, addDepartment, updateDepartment, removeDepartment } =\n useCrewFoundryStore();\n const form = useFormModal<Department>();\n // The department open in the edit dialog is \"this department\" for the assistant.\n useFocusedRecordParam({\n records: departments,\n activeId: form.open ? (form.context?.id ?? null) : null,\n onRestore: form.openModal,\n });\n const [deleting, setDeleting] = useState<Department | null>(null);\n\n const totalBudget = departments.reduce((s, d) => s + d.budget, 0);\n const totalHeadcount = departments.reduce((s, d) => s + d.employeeCount, 0);\n\n const editing = form.context;\n\n // Resolve a department's head to a real employee (by id first, then by name) so\n // we can show a real avatar rather than a text-only name.\n const headOf = useCallback(\n (department: Department): Employee | undefined =>\n employees.find((e) => e.id === department.headId) ||\n employees.find((e) => fullName(e) === department.headName),\n [employees]\n );\n\n // Org structure: a real hierarchy derived from the roster + departments + teams.\n // Root = a top-of-org employee (CEO / founder / chief with no manager) when one\n // exists, else a generic company node. Each department hangs off the root with\n // its head; each department's children are its real teams (or a sample of its\n // real employees when the department has no teams).\n const orgRoot = useMemo<OrgNode | null>(() => {\n if (departments.length === 0) {\n return null;\n }\n const topLeader = employees.find(\n (e) => !e.managerId && /chief|ceo|founder|president|head of company/i.test(e.position)\n );\n\n const deptNodes: OrgNode[] = departments.map((department) => {\n const head = headOf(department);\n const deptTeams = teams.filter((team) => team.department === department.name);\n let children: OrgNode[];\n if (deptTeams.length > 0) {\n children = deptTeams.slice(0, 4).map((team) => ({\n id: team.id,\n name: team.name,\n role: `${team.memberCount} member${team.memberCount === 1 ? '' : 's'}`,\n }));\n } else {\n children = employees\n .filter((e) => e.department === department.name && e.id !== head?.id)\n .slice(0, 3)\n .map((e) => ({ id: e.id, name: fullName(e), role: e.position, avatarUrl: e.avatar }));\n }\n return {\n id: department.id,\n name: department.name,\n role: department.headName ? `${department.headName}, Head` : 'Department',\n avatarUrl: head?.avatar,\n children,\n };\n });\n\n return {\n id: topLeader?.id ?? 'org-root',\n name: topLeader ? fullName(topLeader) : 'Organization',\n role: topLeader?.position ?? 'Company',\n avatarUrl: topLeader?.avatar,\n children: deptNodes,\n };\n }, [departments, employees, teams, headOf]);\n\n const handleSubmit = async (values: FormValues) => {\n const payload: Department = {\n id: editing?.id ?? newClientId(),\n name: getText(values, 'name'),\n headId: editing?.headId ?? '',\n headName: getText(values, 'headName'),\n employeeCount: editing?.employeeCount ?? 0,\n budget: getNumber(values, 'budget'),\n location: getText(values, 'location'),\n status: getText(values, 'status') as Department['status'],\n };\n if (editing) {\n await updateDepartment(editing.id, payload);\n } else {\n await addDepartment(payload);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Departments</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Organizational structure and department management\n </p>\n <PagePurpose className=\"mt-1\">\n Organize your company into departments — set up structure, assign heads, and see how\n headcount is distributed across the org.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => form.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Department\n </Button>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <StatCard\n label=\"Total Departments\"\n value={departments.length}\n icon={<Building2 className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Total Headcount\"\n value={totalHeadcount}\n icon={<Users className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Total Budget\"\n value={`$${(totalBudget / 1000000).toFixed(1)}M`}\n icon={<DollarSign className=\"h-4 w-4\" />}\n />\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {departments.map((dept) => {\n const deptEmps = employees.filter((e) => e.department === dept.name);\n const headcount = dept.employeeCount || deptEmps.length;\n const avgSalary =\n deptEmps.length > 0\n ? Math.round(deptEmps.reduce((s, e) => s + e.salary, 0) / deptEmps.length)\n : 0;\n const avgPerfValue =\n deptEmps.length > 0\n ? deptEmps.reduce((s, e) => s + e.performanceScore, 0) / deptEmps.length\n : 0;\n // Progress bar = real average performance for the department, on a 0–100\n // scale (score out of 5). A clearly-labeled, computed metric — no fabrication.\n const perfPct = Math.round((avgPerfValue / 5) * 100);\n const head = headOf(dept);\n const perfTone =\n perfPct >= 80\n ? 'bg-status-success-text'\n : perfPct >= 60\n ? 'bg-status-warning-text'\n : 'bg-status-error-text';\n\n return (\n <GlassCard key={dept.id} treatment=\"glass\" className=\"border-border-seam\">\n <CardHeader>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <CardTitle className=\"truncate text-lg\">{dept.name}</CardTitle>\n <div className=\"mt-2 flex items-center gap-2\">\n <AvatarStack\n people={[{ name: dept.headName || 'Unassigned', avatarUrl: head?.avatar }]}\n size={28}\n />\n <span className=\"truncate text-sm text-text-secondary\">\n <span className=\"font-medium text-text-primary\">{dept.headName}</span>\n {dept.headName ? ', Head' : 'No head assigned'}\n </span>\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n <Badge variant={dept.status === 'active' ? 'default' : 'secondary'}>\n {formatEnumLabel(dept.status)}\n </Badge>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Edit ${dept.name}`}\n onClick={() => form.openModal(dept)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-8 p-0\"\n aria-label={`Delete ${dept.name}`}\n onClick={() => setDeleting(dept)}\n >\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-end justify-between gap-3\">\n <div>\n <p className=\"text-3xl font-bold leading-none tabular-nums\">{headcount}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">Employees</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-lg font-semibold tabular-nums\">\n ${(dept.budget / 1000000).toFixed(1)}M\n </p>\n <p className=\"text-xs text-text-secondary\">Annual budget</p>\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>Avg performance</span>\n <span className=\"font-medium text-text-primary tabular-nums\">{perfPct}%</span>\n </div>\n <div className=\"h-2 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className={`h-2 rounded-full ${perfTone}`}\n style={{ width: `${perfPct}%` }}\n />\n </div>\n </div>\n\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" />\n {dept.location}\n </span>\n <span>\n Cost/Head:{' '}\n {headcount > 0 ? `$${Math.round(dept.budget / headcount / 1000)}K` : '—'}\n </span>\n </div>\n {avgSalary > 0 && (\n <p className=\"text-xs text-text-secondary\">\n Avg salary{' '}\n <span className=\"font-medium text-text-primary\">\n ${avgSalary.toLocaleString()}\n </span>\n </p>\n )}\n </CardContent>\n </GlassCard>\n );\n })}\n </div>\n\n {orgRoot && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-lg\">\n <Network className=\"h-4 w-4 text-text-secondary\" />\n Org structure\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"overflow-x-auto pb-2\">\n <div className=\"min-w-fit\">\n <OrgTree root={orgRoot} />\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n <FormModal\n open={form.open}\n onOpenChange={form.onOpenChange}\n title={editing ? 'Edit department' : 'Add department'}\n description={\n editing\n ? 'Update this department’s details.'\n : 'Create a new department in your organization.'\n }\n fields={DEPARTMENT_FIELDS}\n initialValues={editing ? toFormValues(editing) : undefined}\n submitLabel={editing ? 'Save changes' : 'Add department'}\n onSubmit={handleSubmit}\n />\n\n <ConfirmDialog\n open={deleting !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleting(null);\n }\n }}\n title=\"Delete department?\"\n description={\n deleting ? `${deleting.name} will be removed. This cannot be undone.` : undefined\n }\n confirmLabel=\"Delete\"\n destructive\n onConfirm={async () => {\n if (deleting) {\n await removeDepartment(deleting.id);\n setDeleting(null);\n }\n }}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,IAAM,KAAY,MAChB,GAAG,EAAS,UAAU,GAAG,EAAS,WAAW,MAAM,EAE/C,IAAmC;CACvC;EAAE,MAAM;EAAQ,OAAO;EAAmB,MAAM;EAAQ,UAAU;EAAM,SAAS;EAAG;CACpF;EAAE,MAAM;EAAY,OAAO;EAAmB,MAAM;EAAQ,UAAU;EAAM;CAC5E;EAAE,MAAM;EAAY,OAAO;EAAY,MAAM;EAAQ,UAAU;EAAM;CACrE;EAAE,MAAM;EAAU,OAAO;EAAiB,MAAM;EAAU,UAAU;EAAM;CAC1E;EACE,MAAM;EACN,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS,CACP;GAAE,OAAO;GAAU,OAAO;GAAU,EACpC;GAAE,OAAO;GAAiB,OAAO;GAAiB,CACnD;EACF;CACF,EAEK,KAAgB,OAAwC;CAC5D,MAAM,EAAW;CACjB,UAAU,EAAW;CACrB,UAAU,EAAW;CACrB,QAAQ,EAAW;CACnB,QAAQ,EAAW;CACpB;AAED,SAAgB,IAAwB;CACtC,IAAM,EAAE,gBAAa,cAAW,UAAO,kBAAe,qBAAkB,wBACtE,GAAqB,EACjB,IAAO,GAA0B;AAEvC,GAAsB;EACpB,SAAS;EACT,UAAU,EAAK,OAAQ,EAAK,SAAS,MAAM,OAAQ;EACnD,WAAW,EAAK;EACjB,CAAC;CACF,IAAM,CAAC,GAAU,KAAe,EAA4B,KAAK,EAE3D,IAAc,EAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,QAAQ,EAAE,EAC3D,IAAiB,EAAY,QAAQ,GAAG,MAAM,IAAI,EAAE,eAAe,EAAE,EAErE,IAAU,EAAK,SAIf,IAAS,GACZ,MACC,EAAU,MAAM,MAAM,EAAE,OAAO,EAAW,OAAO,IACjD,EAAU,MAAM,MAAM,EAAS,EAAE,KAAK,EAAW,SAAS,EAC5D,CAAC,EAAU,CACZ,EAOK,IAAU,QAA8B;AAC5C,MAAI,EAAY,WAAW,EACzB,QAAO;EAET,IAAM,IAAY,EAAU,MACzB,MAAM,CAAC,EAAE,aAAa,+CAA+C,KAAK,EAAE,SAAS,CACvF,EAEK,IAAuB,EAAY,KAAK,MAAe;GAC3D,IAAM,IAAO,EAAO,EAAW,EACzB,IAAY,EAAM,QAAQ,MAAS,EAAK,eAAe,EAAW,KAAK,EACzE;AAaJ,UAZA,AAOE,IAPE,EAAU,SAAS,IACV,EAAU,MAAM,GAAG,EAAE,CAAC,KAAK,OAAU;IAC9C,IAAI,EAAK;IACT,MAAM,EAAK;IACX,MAAM,GAAG,EAAK,YAAY,SAAS,EAAK,gBAAgB,IAAI,KAAK;IAClE,EAAE,GAEQ,EACR,QAAQ,MAAM,EAAE,eAAe,EAAW,QAAQ,EAAE,OAAO,GAAM,GAAG,CACpE,MAAM,GAAG,EAAE,CACX,KAAK,OAAO;IAAE,IAAI,EAAE;IAAI,MAAM,EAAS,EAAE;IAAE,MAAM,EAAE;IAAU,WAAW,EAAE;IAAQ,EAAE,EAElF;IACL,IAAI,EAAW;IACf,MAAM,EAAW;IACjB,MAAM,EAAW,WAAW,GAAG,EAAW,SAAS,UAAU;IAC7D,WAAW,GAAM;IACjB;IACD;IACD;AAEF,SAAO;GACL,IAAI,GAAW,MAAM;GACrB,MAAM,IAAY,EAAS,EAAU,GAAG;GACxC,MAAM,GAAW,YAAY;GAC7B,WAAW,GAAW;GACtB,UAAU;GACX;IACA;EAAC;EAAa;EAAW;EAAO;EAAO,CAAC;AAoB3C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,MAAD;MAAI,WAAU;gBACZ,kBAAC,GAAD,EAAA,UAAc,eAA0B,CAAA;MACrC,CAAA;KACL,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAEvC,CAAA;KACJ,kBAAC,GAAD;MAAa,WAAU;gBAAO;MAGhB,CAAA;KACV,EAAA,CAAA,EACN,kBAAC,GAAD;KAAQ,MAAK;KAAK,eAAe,EAAK,WAAW;eAAjD,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,iBAE1B;OACL;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAY;MACnB,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;MACvC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO;MACP,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,KAAK,IAAc,KAAS,QAAQ,EAAE,CAAC;MAC9C,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,CAAA;KACE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAY,KAAK,MAAS;KACzB,IAAM,IAAW,EAAU,QAAQ,MAAM,EAAE,eAAe,EAAK,KAAK,EAC9D,IAAY,EAAK,iBAAiB,EAAS,QAC3C,IACJ,EAAS,SAAS,IACd,KAAK,MAAM,EAAS,QAAQ,GAAG,MAAM,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAS,OAAO,GACxE,GACA,IACJ,EAAS,SAAS,IACd,EAAS,QAAQ,GAAG,MAAM,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAS,SAChE,GAGA,IAAU,KAAK,MAAO,IAAe,IAAK,IAAI,EAC9C,IAAO,EAAO,EAAK,EACnB,IACJ,KAAW,KACP,2BACA,KAAW,KACT,2BACA;AAER,YACE,kBAAC,GAAD;MAAyB,WAAU;MAAQ,WAAU;gBAArD,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAW,WAAU;mBAAoB,EAAK;SAAiB,CAAA,EAC/D,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UACE,QAAQ,CAAC;WAAE,MAAM,EAAK,YAAY;WAAc,WAAW,GAAM;WAAQ,CAAC;UAC1E,MAAM;UACN,CAAA,EACF,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAiC,EAAK;WAAgB,CAAA,EACrE,EAAK,WAAW,WAAW,mBACvB;YACH;WACF;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,GAAD;UAAO,SAAS,EAAK,WAAW,WAAW,YAAY;oBACpD,EAAgB,EAAK,OAAO;UACvB,CAAA;SACR,kBAAC,GAAD;UACE,SAAQ;UACR,MAAK;UACL,WAAU;UACV,cAAY,QAAQ,EAAK;UACzB,eAAe,EAAK,UAAU,EAAK;oBAEnC,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;UACvB,CAAA;SACT,kBAAC,GAAD;UACE,SAAQ;UACR,MAAK;UACL,WAAU;UACV,cAAY,UAAU,EAAK;UAC3B,eAAe,EAAY,EAAK;oBAEhC,kBAAC,GAAD,EAAQ,WAAU,kCAAmC,CAAA;UAC9C,CAAA;SACL;UACF;UACK,CAAA,EACb,kBAAC,GAAD;OAAa,WAAU;iBAAvB;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAgD;UAAc,CAAA,EAC3E,kBAAC,KAAD;UAAG,WAAU;oBAAmC;UAAa,CAAA,CACzD,EAAA,CAAA,EACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAb;YAAkD;aAC7C,EAAK,SAAS,KAAS,QAAQ,EAAE;YAAC;YACnC;cACJ,kBAAC,KAAD;WAAG,WAAU;qBAA8B;WAAiB,CAAA,CACxD;YACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD,EAAA,UAAM,mBAAsB,CAAA,EAC5B,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAA8D,GAAQ,IAAQ;aAC1E;aACN,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,OAAD;WACE,WAAW,oBAAoB;WAC/B,OAAO,EAAE,OAAO,GAAG,EAAQ,IAAI;WAC/B,CAAA;UACE,CAAA,CACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CACE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAC7B,EAAK,SACD;aACP,kBAAC,QAAD,EAAA,UAAA;UAAM;UACO;UACV,IAAY,IAAI,IAAI,KAAK,MAAM,EAAK,SAAS,IAAY,IAAK,CAAC,KAAK;UAChE,EAAA,CAAA,CACH;;QACL,IAAY,KACX,kBAAC,KAAD;SAAG,WAAU;mBAAb;UAA2C;UAC9B;UACX,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAAgD,KAC5C,EAAU,gBAAgB,CACvB;;UACL;;QAEM;SACJ;QAvFI,EAAK,GAuFT;MAEd;IACE,CAAA;GAEL,KACC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACE,kBAAC,GAAD,EAAS,WAAU,+BAAgC,CAAA,EAAA,gBAEzC;OACD,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAS,MAAM,GAAW,CAAA;KACtB,CAAA;IACF,CAAA,EACM,CAAA,CACT,EAAA,CAAA;GAGT,kBAAC,GAAD;IACE,MAAM,EAAK;IACX,cAAc,EAAK;IACnB,OAAO,IAAU,oBAAoB;IACrC,aACE,IACI,sCACA;IAEN,QAAQ;IACR,eAAe,IAAU,EAAa,EAAQ,GAAG,KAAA;IACjD,aAAa,IAAU,iBAAiB;IACxC,UA3Me,OAAO,MAAuB;KACjD,IAAM,IAAsB;MAC1B,IAAI,GAAS,MAAM,GAAa;MAChC,MAAM,EAAQ,GAAQ,OAAO;MAC7B,QAAQ,GAAS,UAAU;MAC3B,UAAU,EAAQ,GAAQ,WAAW;MACrC,eAAe,GAAS,iBAAiB;MACzC,QAAQ,EAAU,GAAQ,SAAS;MACnC,UAAU,EAAQ,GAAQ,WAAW;MACrC,QAAQ,EAAQ,GAAQ,SAAS;MAClC;AACD,KAAI,IACF,MAAM,EAAiB,EAAQ,IAAI,EAAQ,GAE3C,MAAM,EAAc,EAAQ;;IA8L1B,CAAA;GAEF,kBAAC,GAAD;IACE,MAAM,MAAa;IACnB,eAAe,MAAS;AACtB,KAAK,KACH,EAAY,KAAK;;IAGrB,OAAM;IACN,aACE,IAAW,GAAG,EAAS,KAAK,4CAA4C,KAAA;IAE1E,cAAa;IACb,aAAA;IACA,WAAW,YAAY;AACrB,KAAI,MACF,MAAM,EAAiB,EAAS,GAAG,EACnC,EAAY,KAAK;;IAGrB,CAAA;GACE"}
@@ -1 +1 @@
1
- {"version":3,"file":"HrEmployeeProfilePagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/HrEmployeeProfilePagePage.tsx"],"names":[],"mappings":"AA+MA,wBAAgB,yBAAyB,gCAqVxC"}
1
+ {"version":3,"file":"HrEmployeeProfilePagePage.d.ts","sourceRoot":"","sources":["../../../src/crewfoundry/pages/HrEmployeeProfilePagePage.tsx"],"names":[],"mappings":"AAgNA,wBAAgB,yBAAyB,gCAqUxC"}
@@ -7,14 +7,15 @@ import { SegmentedTabs as a } from "../components/viz/SegmentedTabs.js";
7
7
  import "../components/viz/index.js";
8
8
  import { ConfirmDialog as o } from "../components/forms/ConfirmDialog.js";
9
9
  import { AttachDocumentDialog as s } from "../components/forms/AttachDocumentDialog.js";
10
- import { useEffect as ee, useRef as te, useState as c } from "react";
11
- import { ArrowLeft as l, BadgeCheck as ne, CalendarDays as re, FileText as ie, Mail as ae, MapPin as u, Phone as oe, Plus as d, Trash2 as f } from "lucide-react";
12
- import { useNavigate as p, useSearchParams as se } from "react-router";
13
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
14
- import { Badge as g, Button as _, Card as v, CardContent as y, CardHeader as b, CardTitle as x, GlassCard as S, GradientText as ce, IllustratedEmptyState as C, PagePurpose as w, Spinner as T } from "@burdenoff/fe-libs/ui";
15
- import { useGlobalUi as E } from "@burdenoff/fe-libs/shared/providers/shell";
10
+ import { EmployeeSkillsPanel as c } from "../components/EmployeeSkillsPanel.js";
11
+ import { useEffect as l, useRef as ee, useState as u } from "react";
12
+ import { ArrowLeft as d, BadgeCheck as f, CalendarDays as p, FileText as te, Mail as ne, MapPin as re, Phone as ie, Plus as m, Trash2 as ae } from "lucide-react";
13
+ import { useNavigate as h, useSearchParams as g } from "react-router";
14
+ import { jsx as _, jsxs as v } from "react/jsx-runtime";
15
+ import { Badge as y, Button as b, Card as x, CardContent as S, CardHeader as C, CardTitle as w, GlassCard as oe, GradientText as se, IllustratedEmptyState as T, PagePurpose as ce, Spinner as le } from "@burdenoff/fe-libs/ui";
16
+ import { useGlobalUi as ue } from "@burdenoff/fe-libs/shared/providers/shell";
16
17
  //#region src/crewfoundry/pages/HrEmployeeProfilePagePage.tsx
17
- var D = [
18
+ var de = [
18
19
  {
19
20
  id: "overview",
20
21
  label: "Overview"
@@ -35,7 +36,7 @@ var D = [
35
36
  id: "activity",
36
37
  label: "Activity"
37
38
  }
38
- ], O = [
39
+ ], E = [
39
40
  {
40
41
  min: 0,
41
42
  max: 6e4
@@ -61,11 +62,11 @@ var D = [
61
62
  max: Infinity
62
63
  }
63
64
  ];
64
- function le(e) {
65
- let t = O.findIndex((t) => e >= t.min && e < t.max), n = t === -1 ? O.length - 1 : t, r = O[n], i = `$${Math.round(r.min / 1e3)}k`, a = r.max === Infinity ? "+" : `–$${Math.round(r.max / 1e3)}k`;
65
+ function fe(e) {
66
+ let t = E.findIndex((t) => e >= t.min && e < t.max), n = t === -1 ? E.length - 1 : t, r = E[n], i = `$${Math.round(r.min / 1e3)}k`, a = r.max === Infinity ? "+" : `–$${Math.round(r.max / 1e3)}k`;
66
67
  return `Band ${n + 1} · ${i}${a}`;
67
68
  }
68
- function ue(e) {
69
+ function D(e) {
69
70
  let t = new Date(e);
70
71
  if (Number.isNaN(t.getTime())) return "—";
71
72
  let n = /* @__PURE__ */ new Date(), r = (n.getFullYear() - t.getFullYear()) * 12 + (n.getMonth() - t.getMonth());
@@ -73,37 +74,37 @@ function ue(e) {
73
74
  let i = Math.floor(r / 12), a = r % 12, o = [];
74
75
  return i > 0 && o.push(`${i} year${i === 1 ? "" : "s"}`), o.push(`${a} month${a === 1 ? "" : "s"}`), o.join(", ");
75
76
  }
76
- function k(e) {
77
+ function O(e) {
77
78
  return e >= 4.5 ? "Excellent" : e >= 3.5 ? "Strong" : e >= 2.5 ? "Meets expectations" : "Needs improvement";
78
79
  }
79
- function A(e) {
80
+ function k(e) {
80
81
  return e === "active" ? "default" : e === "on_leave" ? "secondary" : "destructive";
81
82
  }
82
- function j({ icon: e, children: t }) {
83
- return /* @__PURE__ */ h("span", {
83
+ function A({ icon: e, children: t }) {
84
+ return /* @__PURE__ */ v("span", {
84
85
  className: "inline-flex items-center gap-1.5 rounded-full border border-border-subtle bg-bg-surface px-3 py-1 text-xs text-text-secondary",
85
- children: [/* @__PURE__ */ m("span", {
86
+ children: [/* @__PURE__ */ _("span", {
86
87
  className: "text-text-muted",
87
88
  children: e
88
- }), /* @__PURE__ */ m("span", {
89
+ }), /* @__PURE__ */ _("span", {
89
90
  className: "truncate",
90
91
  children: t
91
92
  })]
92
93
  });
93
94
  }
94
- function M({ label: e, children: t }) {
95
- return /* @__PURE__ */ h("div", {
95
+ function j({ label: e, children: t }) {
96
+ return /* @__PURE__ */ v("div", {
96
97
  className: "flex items-start justify-between gap-4 py-2 text-sm",
97
- children: [/* @__PURE__ */ m("span", {
98
+ children: [/* @__PURE__ */ _("span", {
98
99
  className: "text-text-secondary",
99
100
  children: e
100
- }), /* @__PURE__ */ m("span", {
101
+ }), /* @__PURE__ */ _("span", {
101
102
  className: "text-right font-medium text-text-primary",
102
103
  children: t
103
104
  })]
104
105
  });
105
106
  }
106
- function N(e, n, r, i, a) {
107
+ function M(e, n, r, i, a) {
107
108
  let o = [], s = (e) => {
108
109
  let t = new Date(e).getTime();
109
110
  return Number.isNaN(t) ? 0 : t;
@@ -153,73 +154,73 @@ function N(e, n, r, i, a) {
153
154
  });
154
155
  return o.sort((e, t) => t.ts - e.ts).slice(0, 14).map((e) => e.item);
155
156
  }
156
- function P() {
157
- let O = p(), [P] = se(), F = e((e) => e.employees), I = e((e) => e.timeEntries), L = e((e) => e.leaveRequests), R = e((e) => e.payrollRecords), z = e((e) => e.projects), B = e((e) => e.initialized), V = e((e) => e.employeeDocuments), H = e((e) => e.fetchEmployeeDocuments), de = e((e) => e.uploadEmployeeDocument), fe = e((e) => e.detachEmployeeDocument), { showToast: U } = E(), [W, pe] = c("overview"), [me, G] = c(!1), [K, q] = c(null), J = te(null), he = P.get("id"), Y = F.find((e) => e.id === he);
158
- if (ee(() => {
159
- W === "documents" && Y && J.current !== Y.id && (J.current = Y.id, H(Y.id).catch((e) => {
160
- U(e instanceof Error ? e.message : "Unable to load documents", "error");
157
+ function N() {
158
+ let E = h(), [N] = g(), P = e((e) => e.employees), F = e((e) => e.timeEntries), I = e((e) => e.leaveRequests), L = e((e) => e.payrollRecords), R = e((e) => e.projects), z = e((e) => e.initialized), B = e((e) => e.employeeDocuments), V = e((e) => e.fetchEmployeeDocuments), pe = e((e) => e.uploadEmployeeDocument), me = e((e) => e.detachEmployeeDocument), { showToast: H } = ue(), [U, he] = u("overview"), [W, G] = u(!1), [K, q] = u(null), J = ee(null), ge = N.get("id"), Y = P.find((e) => e.id === ge);
159
+ if (l(() => {
160
+ U === "documents" && Y && J.current !== Y.id && (J.current = Y.id, V(Y.id).catch((e) => {
161
+ H(e instanceof Error ? e.message : "Unable to load documents", "error");
161
162
  }));
162
163
  }, [
163
- W,
164
+ U,
164
165
  Y,
165
- H,
166
- U
167
- ]), !B && !Y) return /* @__PURE__ */ m("div", {
166
+ V,
167
+ H
168
+ ]), !z && !Y) return /* @__PURE__ */ _("div", {
168
169
  className: "flex min-h-[60vh] items-center justify-center p-6",
169
- children: /* @__PURE__ */ m(T, { size: "lg" })
170
+ children: /* @__PURE__ */ _(le, { size: "lg" })
170
171
  });
171
- if (!Y) return /* @__PURE__ */ h("div", {
172
+ if (!Y) return /* @__PURE__ */ v("div", {
172
173
  className: "space-y-4 p-6",
173
- children: [/* @__PURE__ */ h(_, {
174
+ children: [/* @__PURE__ */ v(b, {
174
175
  variant: "ghost",
175
176
  size: "sm",
176
- onClick: () => O("../hr/employees-page"),
177
- children: [/* @__PURE__ */ m(l, { className: "mr-1 h-4 w-4" }), "Back to directory"]
178
- }), /* @__PURE__ */ m(C, {
177
+ onClick: () => E("../hr/employees-page"),
178
+ children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Back to directory"]
179
+ }), /* @__PURE__ */ _(T, {
179
180
  illustration: "empty-search",
180
181
  title: "Employee not found",
181
182
  description: "This profile is no longer available or the link is out of date."
182
183
  })]
183
184
  });
184
- let X = Y.managerId ? F.find((e) => e.id === Y.managerId) : void 0, Z = X ? `${X.firstName} ${X.lastName}` : Y.managerId ? "Assigned" : "No manager", Q = `${Y.firstName} ${Y.lastName}`, $ = N(Y, I, L, R, z);
185
- return /* @__PURE__ */ h("div", {
185
+ let X = Y.managerId ? P.find((e) => e.id === Y.managerId) : void 0, Z = X ? `${X.firstName} ${X.lastName}` : Y.managerId ? "Assigned" : "No manager", Q = `${Y.firstName} ${Y.lastName}`, $ = M(Y, F, I, L, R);
186
+ return /* @__PURE__ */ v("div", {
186
187
  className: "space-y-6 p-6",
187
188
  children: [
188
- /* @__PURE__ */ h(_, {
189
+ /* @__PURE__ */ v(b, {
189
190
  variant: "ghost",
190
191
  size: "sm",
191
- onClick: () => O("../hr/employees-page"),
192
- children: [/* @__PURE__ */ m(l, { className: "mr-1 h-4 w-4" }), "Back to directory"]
192
+ onClick: () => E("../hr/employees-page"),
193
+ children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Back to directory"]
193
194
  }),
194
- /* @__PURE__ */ m(S, {
195
+ /* @__PURE__ */ _(oe, {
195
196
  treatment: "glass",
196
197
  glow: !0,
197
198
  className: "border-border-seam",
198
- children: /* @__PURE__ */ m(y, {
199
+ children: /* @__PURE__ */ _(S, {
199
200
  className: "p-6",
200
- children: /* @__PURE__ */ h("div", {
201
+ children: /* @__PURE__ */ v("div", {
201
202
  className: "flex flex-col gap-5 sm:flex-row sm:items-start",
202
- children: [/* @__PURE__ */ m(i, {
203
+ children: [/* @__PURE__ */ _(i, {
203
204
  people: [{
204
205
  name: Q,
205
206
  avatarUrl: Y.avatar
206
207
  }],
207
208
  max: 1,
208
209
  size: 72
209
- }), /* @__PURE__ */ h("div", {
210
+ }), /* @__PURE__ */ v("div", {
210
211
  className: "flex-1 space-y-3",
211
212
  children: [
212
- /* @__PURE__ */ h("div", {
213
+ /* @__PURE__ */ v("div", {
213
214
  className: "flex flex-wrap items-center gap-3",
214
- children: [/* @__PURE__ */ m("h1", {
215
+ children: [/* @__PURE__ */ _("h1", {
215
216
  className: "text-2xl font-semibold",
216
- children: /* @__PURE__ */ m(ce, { children: Q })
217
- }), /* @__PURE__ */ m(g, {
218
- variant: A(Y.status),
217
+ children: /* @__PURE__ */ _(se, { children: Q })
218
+ }), /* @__PURE__ */ _(y, {
219
+ variant: k(Y.status),
219
220
  children: t(Y.status)
220
221
  })]
221
222
  }),
222
- /* @__PURE__ */ h("p", {
223
+ /* @__PURE__ */ v("p", {
223
224
  className: "text-sm text-text-secondary",
224
225
  children: [
225
226
  Y.position,
@@ -227,23 +228,23 @@ function P() {
227
228
  Y.department
228
229
  ]
229
230
  }),
230
- /* @__PURE__ */ h("div", {
231
+ /* @__PURE__ */ v("div", {
231
232
  className: "flex flex-wrap gap-2",
232
233
  children: [
233
- /* @__PURE__ */ m(j, {
234
- icon: /* @__PURE__ */ m(ae, { className: "h-3.5 w-3.5" }),
234
+ /* @__PURE__ */ _(A, {
235
+ icon: /* @__PURE__ */ _(ne, { className: "h-3.5 w-3.5" }),
235
236
  children: Y.email
236
237
  }),
237
- /* @__PURE__ */ m(j, {
238
- icon: /* @__PURE__ */ m(oe, { className: "h-3.5 w-3.5" }),
238
+ /* @__PURE__ */ _(A, {
239
+ icon: /* @__PURE__ */ _(ie, { className: "h-3.5 w-3.5" }),
239
240
  children: Y.phone
240
241
  }),
241
- /* @__PURE__ */ m(j, {
242
- icon: /* @__PURE__ */ m(u, { className: "h-3.5 w-3.5" }),
242
+ /* @__PURE__ */ _(A, {
243
+ icon: /* @__PURE__ */ _(re, { className: "h-3.5 w-3.5" }),
243
244
  children: Y.location
244
245
  }),
245
- /* @__PURE__ */ h(j, {
246
- icon: /* @__PURE__ */ m(re, { className: "h-3.5 w-3.5" }),
246
+ /* @__PURE__ */ v(A, {
247
+ icon: /* @__PURE__ */ _(p, { className: "h-3.5 w-3.5" }),
247
248
  children: ["Joined ", Y.startDate]
248
249
  })
249
250
  ]
@@ -253,26 +254,26 @@ function P() {
253
254
  })
254
255
  })
255
256
  }),
256
- /* @__PURE__ */ m(w, { children: "A single view of one team member — their role, tenure, performance, and recent activity — so managers and partners have the full context in one place." }),
257
- /* @__PURE__ */ m(a, {
258
- tabs: D,
259
- value: W,
260
- onChange: (e) => pe(e),
257
+ /* @__PURE__ */ _(ce, { children: "A single view of one team member — their role, tenure, performance, and recent activity — so managers and partners have the full context in one place." }),
258
+ /* @__PURE__ */ _(a, {
259
+ tabs: de,
260
+ value: U,
261
+ onChange: (e) => he(e),
261
262
  "aria-label": "Employee profile sections"
262
263
  }),
263
- W === "overview" ? /* @__PURE__ */ h("div", {
264
+ U === "overview" ? /* @__PURE__ */ v("div", {
264
265
  className: "grid gap-4 lg:grid-cols-2",
265
- children: [/* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ m(x, {
266
+ children: [/* @__PURE__ */ v(x, { children: [/* @__PURE__ */ _(C, { children: /* @__PURE__ */ _(w, {
266
267
  className: "text-base",
267
268
  children: "Details"
268
- }) }), /* @__PURE__ */ h(y, {
269
+ }) }), /* @__PURE__ */ v(S, {
269
270
  className: "divide-y divide-border-subtle pt-0",
270
271
  children: [
271
- /* @__PURE__ */ m(M, {
272
+ /* @__PURE__ */ _(j, {
272
273
  label: "Manager",
273
- children: /* @__PURE__ */ h("span", {
274
+ children: /* @__PURE__ */ v("span", {
274
275
  className: "inline-flex items-center gap-2",
275
- children: [X ? /* @__PURE__ */ m(i, {
276
+ children: [X ? /* @__PURE__ */ _(i, {
276
277
  people: [{
277
278
  name: Z,
278
279
  avatarUrl: X.avatar
@@ -282,42 +283,42 @@ function P() {
282
283
  }) : null, Z]
283
284
  })
284
285
  }),
285
- /* @__PURE__ */ m(M, {
286
+ /* @__PURE__ */ _(j, {
286
287
  label: "Employment type",
287
288
  children: t(Y.type)
288
289
  }),
289
- /* @__PURE__ */ m(M, {
290
+ /* @__PURE__ */ _(j, {
290
291
  label: "Salary band",
291
- children: le(Y.salary)
292
+ children: fe(Y.salary)
292
293
  }),
293
- /* @__PURE__ */ m(M, {
294
+ /* @__PURE__ */ _(j, {
294
295
  label: "Tenure",
295
- children: ue(Y.startDate)
296
+ children: D(Y.startDate)
296
297
  }),
297
- /* @__PURE__ */ m(M, {
298
+ /* @__PURE__ */ _(j, {
298
299
  label: "Employee ID",
299
- children: /* @__PURE__ */ m("span", {
300
+ children: /* @__PURE__ */ _("span", {
300
301
  className: "break-all font-mono text-xs",
301
302
  children: Y.id
302
303
  })
303
304
  })
304
305
  ]
305
- })] }), /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ m(x, {
306
+ })] }), /* @__PURE__ */ v(x, { children: [/* @__PURE__ */ _(C, { children: /* @__PURE__ */ _(w, {
306
307
  className: "text-base",
307
308
  children: "Performance"
308
- }) }), /* @__PURE__ */ h(y, {
309
+ }) }), /* @__PURE__ */ v(S, {
309
310
  className: "flex items-center gap-6 pt-0",
310
- children: [/* @__PURE__ */ m(n, {
311
+ children: [/* @__PURE__ */ _(n, {
311
312
  value: Y.performanceScore,
312
313
  max: 5,
313
314
  label: Y.performanceScore.toFixed(1),
314
315
  caption: "/ 5"
315
- }), /* @__PURE__ */ h("div", {
316
+ }), /* @__PURE__ */ v("div", {
316
317
  className: "space-y-1",
317
- children: [/* @__PURE__ */ m("p", {
318
+ children: [/* @__PURE__ */ _("p", {
318
319
  className: "text-lg font-semibold text-text-primary",
319
- children: k(Y.performanceScore)
320
- }), /* @__PURE__ */ h("p", {
320
+ children: O(Y.performanceScore)
321
+ }), /* @__PURE__ */ v("p", {
321
322
  className: "text-sm text-text-secondary",
322
323
  children: [
323
324
  "Latest review score of ",
@@ -328,48 +329,37 @@ function P() {
328
329
  })]
329
330
  })] })]
330
331
  }) : null,
331
- W === "skills" ? /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ m(x, {
332
+ U === "skills" ? /* @__PURE__ */ v(x, { children: [/* @__PURE__ */ _(C, { children: /* @__PURE__ */ _(w, {
332
333
  className: "text-base",
333
334
  children: "Skills"
334
- }) }), /* @__PURE__ */ m(y, {
335
+ }) }), /* @__PURE__ */ _(S, {
335
336
  className: "pt-0",
336
- children: Y.skills.length > 0 ? /* @__PURE__ */ m("div", {
337
- className: "flex flex-wrap gap-2",
338
- children: Y.skills.map((e) => /* @__PURE__ */ m(g, {
339
- variant: "secondary",
340
- className: "text-xs",
341
- children: e
342
- }, e))
343
- }) : /* @__PURE__ */ m(C, {
344
- illustration: "empty-data",
345
- title: "No skills recorded",
346
- description: "This team member has no skills captured yet. Add skills from the employee directory to surface them here."
347
- })
337
+ children: /* @__PURE__ */ _(c, { employeeId: Y.id })
348
338
  })] }) : null,
349
- W === "documents" ? /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ h(b, {
339
+ U === "documents" ? /* @__PURE__ */ v(x, { children: [/* @__PURE__ */ v(C, {
350
340
  className: "flex flex-row items-center justify-between",
351
- children: [/* @__PURE__ */ m(x, {
341
+ children: [/* @__PURE__ */ _(w, {
352
342
  className: "text-base",
353
343
  children: "Documents"
354
- }), /* @__PURE__ */ h(_, {
344
+ }), /* @__PURE__ */ v(b, {
355
345
  size: "sm",
356
346
  onClick: () => G(!0),
357
- children: [/* @__PURE__ */ m(d, { className: "mr-1.5 h-3.5 w-3.5" }), "Attach document"]
347
+ children: [/* @__PURE__ */ _(m, { className: "mr-1.5 h-3.5 w-3.5" }), "Attach document"]
358
348
  })]
359
- }), /* @__PURE__ */ m(y, {
349
+ }), /* @__PURE__ */ _(S, {
360
350
  className: "pt-0",
361
- children: V.length > 0 ? /* @__PURE__ */ m("div", {
351
+ children: B.length > 0 ? /* @__PURE__ */ _("div", {
362
352
  className: "space-y-2",
363
- children: V.map((e) => /* @__PURE__ */ h("div", {
353
+ children: B.map((e) => /* @__PURE__ */ v("div", {
364
354
  className: "flex items-center justify-between gap-3 rounded-input border border-border-subtle bg-bg-surface px-3 py-2.5",
365
- children: [/* @__PURE__ */ h("div", {
355
+ children: [/* @__PURE__ */ v("div", {
366
356
  className: "flex min-w-0 items-center gap-3",
367
- children: [/* @__PURE__ */ m(ie, { className: "h-4 w-4 shrink-0 text-text-muted" }), /* @__PURE__ */ h("div", {
357
+ children: [/* @__PURE__ */ _(te, { className: "h-4 w-4 shrink-0 text-text-muted" }), /* @__PURE__ */ v("div", {
368
358
  className: "min-w-0",
369
- children: [/* @__PURE__ */ m("p", {
359
+ children: [/* @__PURE__ */ _("p", {
370
360
  className: "truncate text-sm font-medium text-text-primary",
371
361
  children: e.title
372
- }), /* @__PURE__ */ h("p", {
362
+ }), /* @__PURE__ */ v("p", {
373
363
  className: "text-xs text-text-muted",
374
364
  children: [
375
365
  e.category ? `${e.category} · ` : "",
@@ -378,45 +368,45 @@ function P() {
378
368
  ]
379
369
  })]
380
370
  })]
381
- }), /* @__PURE__ */ m("button", {
371
+ }), /* @__PURE__ */ _("button", {
382
372
  type: "button",
383
373
  "aria-label": `Remove document "${e.title}"`,
384
374
  className: "shrink-0 text-text-muted hover:text-status-error-fg",
385
375
  onClick: () => q(e.id),
386
- children: /* @__PURE__ */ m(f, { className: "h-4 w-4" })
376
+ children: /* @__PURE__ */ _(ae, { className: "h-4 w-4" })
387
377
  })]
388
378
  }, e.id))
389
- }) : /* @__PURE__ */ m(C, {
379
+ }) : /* @__PURE__ */ _(T, {
390
380
  illustration: "empty-data",
391
381
  title: "No documents attached",
392
382
  description: "Offer letters, contracts, and compliance documents attached to this profile will appear here.",
393
- action: /* @__PURE__ */ h(_, {
383
+ action: /* @__PURE__ */ v(b, {
394
384
  size: "sm",
395
385
  onClick: () => G(!0),
396
- children: [/* @__PURE__ */ m(d, { className: "mr-1.5 h-3.5 w-3.5" }), "Attach document"]
386
+ children: [/* @__PURE__ */ _(m, { className: "mr-1.5 h-3.5 w-3.5" }), "Attach document"]
397
387
  })
398
388
  })
399
389
  })] }) : null,
400
- W === "performance" ? /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ m(x, {
390
+ U === "performance" ? /* @__PURE__ */ v(x, { children: [/* @__PURE__ */ _(C, { children: /* @__PURE__ */ _(w, {
401
391
  className: "text-base",
402
392
  children: "Performance"
403
- }) }), /* @__PURE__ */ h(y, {
393
+ }) }), /* @__PURE__ */ v(S, {
404
394
  className: "flex flex-col items-center gap-6 pt-0 sm:flex-row sm:items-center",
405
- children: [/* @__PURE__ */ m(n, {
395
+ children: [/* @__PURE__ */ _(n, {
406
396
  value: Y.performanceScore,
407
397
  max: 5,
408
398
  size: 160,
409
399
  label: Y.performanceScore.toFixed(1),
410
400
  caption: "/ 5"
411
- }), /* @__PURE__ */ h("div", {
401
+ }), /* @__PURE__ */ v("div", {
412
402
  className: "flex-1 space-y-2",
413
403
  children: [
414
- /* @__PURE__ */ h(g, {
404
+ /* @__PURE__ */ v(y, {
415
405
  variant: "secondary",
416
406
  className: "gap-1",
417
- children: [/* @__PURE__ */ m(ne, { className: "h-3.5 w-3.5" }), k(Y.performanceScore)]
407
+ children: [/* @__PURE__ */ _(f, { className: "h-3.5 w-3.5" }), O(Y.performanceScore)]
418
408
  }),
419
- /* @__PURE__ */ h("p", {
409
+ /* @__PURE__ */ v("p", {
420
410
  className: "text-sm text-text-secondary",
421
411
  children: [
422
412
  Q,
@@ -425,35 +415,35 @@ function P() {
425
415
  " out of 5."
426
416
  ]
427
417
  }),
428
- /* @__PURE__ */ m("p", {
418
+ /* @__PURE__ */ _("p", {
429
419
  className: "text-xs text-text-muted",
430
420
  children: "Goal, peer, and manager sub-scores will appear here once captured on the review record."
431
421
  })
432
422
  ]
433
423
  })]
434
424
  })] }) : null,
435
- W === "activity" ? /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ m(b, { children: /* @__PURE__ */ m(x, {
425
+ U === "activity" ? /* @__PURE__ */ v(x, { children: [/* @__PURE__ */ _(C, { children: /* @__PURE__ */ _(w, {
436
426
  className: "text-base",
437
427
  children: "Recent activity"
438
- }) }), /* @__PURE__ */ m(y, {
428
+ }) }), /* @__PURE__ */ _(S, {
439
429
  className: "pt-0",
440
- children: $.length > 0 ? /* @__PURE__ */ m(r, { items: $ }) : /* @__PURE__ */ m(C, {
430
+ children: $.length > 0 ? /* @__PURE__ */ _(r, { items: $ }) : /* @__PURE__ */ _(T, {
441
431
  illustration: "empty-data",
442
432
  title: "No activity yet",
443
433
  description: "Time logs, leave, payroll, and project assignments for this employee will show up here."
444
434
  })
445
435
  })] }) : null,
446
- /* @__PURE__ */ m(s, {
447
- open: me,
436
+ /* @__PURE__ */ _(s, {
437
+ open: W,
448
438
  onOpenChange: G,
449
- onUpload: ({ file: e, title: t, category: n }) => de({
439
+ onUpload: ({ file: e, title: t, category: n }) => pe({
450
440
  employeeId: Y.id,
451
441
  file: e,
452
442
  title: t,
453
443
  category: n
454
444
  })
455
445
  }),
456
- /* @__PURE__ */ m(o, {
446
+ /* @__PURE__ */ _(o, {
457
447
  open: K !== null,
458
448
  onOpenChange: (e) => {
459
449
  e || q(null);
@@ -463,13 +453,13 @@ function P() {
463
453
  confirmLabel: "Remove",
464
454
  destructive: !0,
465
455
  onConfirm: async () => {
466
- K && (await fe(K), q(null));
456
+ K && (await me(K), q(null));
467
457
  }
468
458
  })
469
459
  ]
470
460
  });
471
461
  }
472
462
  //#endregion
473
- export { P as HrEmployeeProfilePagePage };
463
+ export { N as HrEmployeeProfilePagePage };
474
464
 
475
465
  //# sourceMappingURL=HrEmployeeProfilePagePage.js.map