@burdenoff/microfe-crewfoundry 2026.704.6 → 2026.707.1

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 (150) hide show
  1. package/dist/crewfoundry/CrewFoundryRoutes.js +51 -43
  2. package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
  3. package/dist/crewfoundry/components/forms/formValues.js +5 -2
  4. package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
  5. package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
  6. package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
  7. package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
  8. package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
  9. package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
  10. package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
  11. package/dist/crewfoundry/components/viz/BarChart.js +83 -0
  12. package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
  13. package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
  14. package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
  15. package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
  16. package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
  17. package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
  18. package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
  19. package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
  20. package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
  21. package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
  22. package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
  23. package/dist/crewfoundry/components/viz/LineChart.js +123 -0
  24. package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
  25. package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
  26. package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
  27. package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
  28. package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
  29. package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
  30. package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
  31. package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
  32. package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
  33. package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
  34. package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
  35. package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
  36. package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
  37. package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
  38. package/dist/crewfoundry/components/viz/StatCard.js +60 -0
  39. package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
  40. package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
  41. package/dist/crewfoundry/components/viz/Timeline.js +66 -0
  42. package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
  43. package/dist/crewfoundry/components/viz/index.js +23 -0
  44. package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
  45. package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
  46. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
  47. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
  48. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
  49. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
  50. package/dist/crewfoundry/components/viz/lib/format.js +21 -0
  51. package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
  52. package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
  53. package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
  54. package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
  55. package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
  56. package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
  57. package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
  58. package/dist/crewfoundry/lib/analytics.js +323 -0
  59. package/dist/crewfoundry/lib/analytics.js.map +1 -0
  60. package/dist/crewfoundry/lib/companyFinance.js +16 -0
  61. package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
  62. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
  63. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  64. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
  65. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
  66. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
  67. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
  68. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
  69. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
  70. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
  71. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
  72. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
  73. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
  74. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
  75. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  76. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
  77. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  78. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
  79. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
  80. package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js +0 -41
  81. package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
  82. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
  83. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  84. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
  85. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  86. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
  87. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  88. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
  89. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  90. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +269 -270
  91. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  92. package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
  93. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  94. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
  95. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  96. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
  97. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
  98. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
  99. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  100. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
  101. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  102. package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
  103. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  104. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
  105. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  106. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
  107. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  108. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +1 -1
  109. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  110. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
  111. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  112. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
  113. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  114. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +134 -135
  115. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  116. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
  117. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  118. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
  119. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  120. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
  121. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  122. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  123. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  124. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  125. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  126. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +289 -140
  127. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  128. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  129. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  130. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  131. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  132. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  133. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  134. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +140 -78
  135. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  137. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  138. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  139. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  140. package/dist/crewfoundry/store/crewfoundryStore.js +142 -184
  141. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  142. package/dist/crewfoundry/utils/cn.js +10 -0
  143. package/dist/crewfoundry/utils/cn.js.map +1 -0
  144. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  145. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  146. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  147. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  148. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  149. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  150. package/package.json +1 -1
@@ -1,13 +1,19 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
2
  import { formatEnumLabel as t } from "../utils/formatEnumLabel.js";
3
- import { FormModal as n, useFormModal as r } from "../components/forms/FormModal.js";
4
- import { useState as i } from "react";
5
- import { Building2 as a, DollarSign as o, FolderKanban as s, Pencil as c, Plus as l, Search as u, Trash2 as d } from "lucide-react";
6
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
7
- import { AlertDialog as m, AlertDialogAction as h, AlertDialogCancel as g, AlertDialogContent as _, AlertDialogDescription as v, AlertDialogFooter as ee, AlertDialogHeader as te, AlertDialogTitle as ne, AlertDialogTrigger as re, Badge as ie, Button as y, Card as b, CardContent as x, CardHeader as S, CardTitle as C, GlassCard as w, GradientText as T, IllustratedEmptyState as E, Input as D, PagePurpose as O, Pagination as k, ResponsiveTable as A, Select as j, SelectContent as M, SelectItem as N, SelectTrigger as P, SelectValue as F } from "@burdenoff/fe-libs/ui";
8
- import { usePagination as I } from "@burdenoff/fe-libs/shared/hooks";
3
+ import { StatCard as n } from "../components/viz/StatCard.js";
4
+ import { AvatarStack as r } from "../components/viz/AvatarStack.js";
5
+ import { SegmentedTabs as ee } from "../components/viz/SegmentedTabs.js";
6
+ import "../components/viz/index.js";
7
+ import { FormModal as te, useFormModal as i } from "../components/forms/FormModal.js";
8
+ import { thisQuarterRevenue as a, totalContractValue as o } from "../lib/companyFinance.js";
9
+ import { useState as s } from "react";
10
+ import { MoreHorizontal as c, Pencil as l, Plus as u, Search as ne, Trash2 as re } from "lucide-react";
11
+ import { useNavigate as ie } from "react-router-dom";
12
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
13
+ import { AlertDialog as ae, AlertDialogAction as oe, AlertDialogCancel as se, AlertDialogContent as ce, AlertDialogDescription as le, AlertDialogFooter as p, AlertDialogHeader as m, AlertDialogTitle as h, Badge as g, Button as _, Card as v, CardContent as y, CardHeader as b, CardTitle as x, DropdownMenu as S, DropdownMenuContent as C, DropdownMenuItem as w, DropdownMenuSeparator as T, DropdownMenuTrigger as E, GradientText as D, IllustratedEmptyState as O, Input as k, PagePurpose as A, Pagination as j, ResponsiveTable as M, Select as N, SelectContent as P, SelectItem as F, SelectTrigger as I, SelectValue as ue } from "@burdenoff/fe-libs/ui";
14
+ import { usePagination as L } from "@burdenoff/fe-libs/shared/hooks";
9
15
  //#region src/crewfoundry/pages/CompanyClientManagementPagePage.tsx
10
- var L = [
16
+ var R = [
11
17
  {
12
18
  name: "name",
13
19
  label: "Client name",
@@ -68,7 +74,7 @@ var L = [
68
74
  label: "Client since",
69
75
  type: "date"
70
76
  }
71
- ], ae = (e) => ({
77
+ ], z = (e) => ({
72
78
  name: e.name,
73
79
  industry: e.industry,
74
80
  contactPerson: e.contactPerson,
@@ -78,7 +84,7 @@ var L = [
78
84
  revenue: e.revenue,
79
85
  projects: e.projects,
80
86
  since: e.since ? e.since.slice(0, 10) : ""
81
- }), R = (e, t) => ({
87
+ }), B = (e, t) => ({
82
88
  id: t?.id ?? crypto.randomUUID(),
83
89
  name: String(e.name ?? ""),
84
90
  industry: String(e.industry ?? ""),
@@ -89,182 +95,169 @@ var L = [
89
95
  revenue: typeof e.revenue == "number" ? e.revenue : Number(e.revenue) || 0,
90
96
  projects: typeof e.projects == "number" ? e.projects : Number(e.projects) || 0,
91
97
  since: String(e.since ?? "")
92
- }), z = (e) => e === "active" ? "default" : e === "prospect" ? "secondary" : "destructive";
93
- function B() {
94
- let { clients: B, addClient: V, updateClient: H, removeClient: U } = e(), W = r(), [G, K] = i(""), [q, J] = i("all"), { page: oe, pageSize: Y, offset: X, setPage: Z } = I({ initialPageSize: 25 }), Q = B.reduce((e, t) => e + t.revenue, 0), se = B.filter((e) => e.status === "active"), $ = B.filter((e) => {
95
- let t = `${e.name} ${e.industry} ${e.contactPerson} ${e.email}`.toLowerCase().includes(G.toLowerCase()), n = q === "all" || e.status === q;
98
+ }), V = (e) => e === "active" ? "default" : e === "prospect" ? "secondary" : "destructive", H = (e) => e >= 1e6 ? `$${(e / 1e6).toFixed(1)}M` : e >= 1e3 ? `$${Math.round(e / 1e3)}k` : `$${Math.round(e)}`;
99
+ function U() {
100
+ let { clients: U, vendors: W, invoices: de, addClient: fe, updateClient: pe, removeClient: me } = e(), he = ie(), G = i(), [K, ge] = s(""), [q, _e] = s("all"), [J, Y] = s(null), { page: ve, pageSize: X, offset: Z, setPage: Q } = L({ initialPageSize: 25 }), ye = U.filter((e) => e.status === "active"), be = o(U, W), xe = a(de), $ = U.filter((e) => {
101
+ let t = `${e.name} ${e.industry} ${e.contactPerson} ${e.email}`.toLowerCase().includes(K.toLowerCase()), n = q === "all" || e.status === q;
96
102
  return t && n;
97
- }), ce = $.slice(X, X + Y);
98
- return /* @__PURE__ */ p("div", {
103
+ }), Se = $.slice(Z, Z + X);
104
+ return /* @__PURE__ */ f("div", {
99
105
  className: "space-y-6 p-6",
100
106
  children: [
101
- /* @__PURE__ */ p("div", {
107
+ /* @__PURE__ */ f("div", {
102
108
  className: "flex items-center justify-between",
103
- children: [/* @__PURE__ */ p("div", { children: [
104
- /* @__PURE__ */ f("h1", {
109
+ children: [/* @__PURE__ */ f("div", { children: [
110
+ /* @__PURE__ */ d("h1", {
105
111
  className: "text-2xl font-semibold",
106
- children: /* @__PURE__ */ f(T, { children: "Client Management" })
112
+ children: /* @__PURE__ */ d(D, { children: "Clients & Vendors" })
107
113
  }),
108
- /* @__PURE__ */ p("p", {
114
+ /* @__PURE__ */ f("p", {
109
115
  className: "text-sm text-text-secondary",
110
116
  children: [
111
- B.length,
112
- " clients · $",
113
- (Q / 1e6).toFixed(1),
114
- "M revenue"
117
+ U.length,
118
+ " clients · ",
119
+ W.length,
120
+ " vendors"
115
121
  ]
116
122
  }),
117
- /* @__PURE__ */ f(O, {
123
+ /* @__PURE__ */ d(A, {
118
124
  className: "mt-1",
119
125
  children: "Keep track of the clients you work with — their contacts, status, and engagements — so account relationships never slip through the cracks."
120
126
  })
121
- ] }), /* @__PURE__ */ p(y, {
127
+ ] }), /* @__PURE__ */ f(_, {
122
128
  size: "sm",
123
- onClick: () => W.openModal(),
124
- children: [/* @__PURE__ */ f(l, { className: "h-4 w-4 mr-1" }), "Add Client"]
129
+ onClick: () => G.openModal(),
130
+ children: [/* @__PURE__ */ d(u, { className: "h-4 w-4 mr-1" }), "Add Client"]
125
131
  })]
126
132
  }),
127
- /* @__PURE__ */ p("div", {
128
- className: "grid gap-4 md:grid-cols-3",
133
+ /* @__PURE__ */ d(ee, {
134
+ "aria-label": "Clients and vendors",
135
+ variant: "underline",
136
+ value: "clients",
137
+ onChange: (e) => {
138
+ e === "vendors" && he("../company/vendor-management-page");
139
+ },
140
+ tabs: [{
141
+ id: "clients",
142
+ label: "Clients",
143
+ count: U.length
144
+ }, {
145
+ id: "vendors",
146
+ label: "Vendors",
147
+ count: W.length
148
+ }]
149
+ }),
150
+ /* @__PURE__ */ f("div", {
151
+ className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-4",
129
152
  children: [
130
- /* @__PURE__ */ p(w, {
131
- treatment: "glass",
132
- glow: !0,
133
- className: "border-border-seam",
134
- children: [/* @__PURE__ */ p(S, {
135
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
136
- children: [/* @__PURE__ */ f(C, {
137
- className: "text-sm font-medium",
138
- children: "Active Clients"
139
- }), /* @__PURE__ */ f(a, { className: "h-4 w-4 text-text-secondary" })]
140
- }), /* @__PURE__ */ f(x, { children: /* @__PURE__ */ f("div", {
141
- className: "text-2xl font-bold tabular-nums",
142
- children: se.length
143
- }) })]
153
+ /* @__PURE__ */ d(n, {
154
+ label: "Active Clients",
155
+ value: ye.length
156
+ }),
157
+ /* @__PURE__ */ d(n, {
158
+ label: "Vendors",
159
+ value: W.length
144
160
  }),
145
- /* @__PURE__ */ p(w, {
146
- treatment: "metric",
147
- className: "border-border-seam",
148
- children: [/* @__PURE__ */ p(S, {
149
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
150
- children: [/* @__PURE__ */ f(C, {
151
- className: "text-sm font-medium",
152
- children: "Total Revenue"
153
- }), /* @__PURE__ */ f(o, { className: "h-4 w-4 text-text-secondary" })]
154
- }), /* @__PURE__ */ f(x, { children: /* @__PURE__ */ p("div", {
155
- className: "text-2xl font-bold tabular-nums",
156
- children: [
157
- "$",
158
- (Q / 1e6).toFixed(1),
159
- "M"
160
- ]
161
- }) })]
161
+ /* @__PURE__ */ d(n, {
162
+ label: "Total Contract Value",
163
+ value: H(be)
162
164
  }),
163
- /* @__PURE__ */ p(w, {
164
- treatment: "metric",
165
- className: "border-border-seam",
166
- children: [/* @__PURE__ */ p(S, {
167
- className: "flex flex-row items-center justify-between space-y-0 pb-2",
168
- children: [/* @__PURE__ */ f(C, {
169
- className: "text-sm font-medium",
170
- children: "Total Projects"
171
- }), /* @__PURE__ */ f(s, { className: "h-4 w-4 text-text-secondary" })]
172
- }), /* @__PURE__ */ f(x, { children: /* @__PURE__ */ f("div", {
173
- className: "text-2xl font-bold tabular-nums",
174
- children: B.reduce((e, t) => e + t.projects, 0)
175
- }) })]
165
+ /* @__PURE__ */ d(n, {
166
+ label: "This Quarter",
167
+ value: H(xe)
176
168
  })
177
169
  ]
178
170
  }),
179
- /* @__PURE__ */ p(b, { children: [/* @__PURE__ */ f(S, { children: /* @__PURE__ */ f(C, { children: "Client Portfolio" }) }), /* @__PURE__ */ p(x, {
171
+ /* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(b, { children: /* @__PURE__ */ d(x, { children: "Client Portfolio" }) }), /* @__PURE__ */ f(y, {
180
172
  className: "space-y-4",
181
173
  children: [
182
- /* @__PURE__ */ p("div", {
174
+ /* @__PURE__ */ f("div", {
183
175
  className: "flex flex-col gap-2 sm:flex-row sm:items-center",
184
- children: [/* @__PURE__ */ p("div", {
176
+ children: [/* @__PURE__ */ f("div", {
185
177
  className: "relative flex-1",
186
- children: [/* @__PURE__ */ f(u, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ f(D, {
178
+ children: [/* @__PURE__ */ d(ne, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ d(k, {
187
179
  placeholder: "Search clients...",
188
180
  className: "pl-9",
189
- value: G,
181
+ value: K,
190
182
  onChange: (e) => {
191
- K(e.target.value), Z(1);
183
+ ge(e.target.value), Q(1);
192
184
  }
193
185
  })]
194
- }), /* @__PURE__ */ p(j, {
186
+ }), /* @__PURE__ */ f(N, {
195
187
  value: q,
196
188
  onValueChange: (e) => {
197
- J(e), Z(1);
189
+ _e(e), Q(1);
198
190
  },
199
- children: [/* @__PURE__ */ f(P, {
191
+ children: [/* @__PURE__ */ d(I, {
200
192
  className: "w-full sm:w-40",
201
193
  "aria-label": "Filter by status",
202
- children: /* @__PURE__ */ f(F, {})
203
- }), /* @__PURE__ */ p(M, { children: [
204
- /* @__PURE__ */ f(N, {
194
+ children: /* @__PURE__ */ d(ue, {})
195
+ }), /* @__PURE__ */ f(P, { children: [
196
+ /* @__PURE__ */ d(F, {
205
197
  value: "all",
206
198
  children: "All statuses"
207
199
  }),
208
- /* @__PURE__ */ f(N, {
200
+ /* @__PURE__ */ d(F, {
209
201
  value: "active",
210
202
  children: "Active"
211
203
  }),
212
- /* @__PURE__ */ f(N, {
204
+ /* @__PURE__ */ d(F, {
213
205
  value: "prospect",
214
206
  children: "Prospect"
215
207
  }),
216
- /* @__PURE__ */ f(N, {
208
+ /* @__PURE__ */ d(F, {
217
209
  value: "churned",
218
210
  children: "Churned"
219
211
  })
220
212
  ] })]
221
213
  })]
222
214
  }),
223
- /* @__PURE__ */ f(A, {
224
- data: ce,
215
+ /* @__PURE__ */ d(M, {
216
+ data: Se,
225
217
  rowKey: (e) => e.id,
226
218
  columns: [
227
219
  {
228
220
  key: "name",
229
221
  header: "Client",
230
222
  priority: "primary",
231
- cell: (e) => /* @__PURE__ */ f("span", {
232
- className: "font-medium",
233
- children: e.name
234
- })
235
- },
236
- {
237
- key: "industry",
238
- header: "Industry",
239
- priority: "secondary",
240
- cell: (e) => /* @__PURE__ */ f("span", {
241
- className: "text-text-secondary",
242
- children: e.industry
223
+ cell: (e) => /* @__PURE__ */ f("div", {
224
+ className: "flex items-center gap-3",
225
+ children: [/* @__PURE__ */ d(r, {
226
+ people: [{ name: e.name }],
227
+ size: 36
228
+ }), /* @__PURE__ */ f("div", {
229
+ className: "min-w-0",
230
+ children: [/* @__PURE__ */ d("p", {
231
+ className: "truncate font-medium",
232
+ children: e.name
233
+ }), /* @__PURE__ */ d("p", {
234
+ className: "truncate text-xs text-text-secondary",
235
+ children: e.industry || "—"
236
+ })]
237
+ })]
243
238
  })
244
239
  },
245
240
  {
246
241
  key: "contact",
247
- header: "Contact",
242
+ header: "Primary Contact",
248
243
  priority: "secondary",
249
- cell: (e) => /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("p", {
244
+ cell: (e) => /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
250
245
  className: "text-xs",
251
- children: e.contactPerson
252
- }), /* @__PURE__ */ f("p", {
246
+ children: e.contactPerson || "—"
247
+ }), /* @__PURE__ */ d("p", {
253
248
  className: "text-xs text-text-secondary",
254
249
  children: e.email
255
250
  })] })
256
251
  },
257
252
  {
258
- key: "revenue",
259
- header: "Revenue",
253
+ key: "status",
254
+ header: "Status",
260
255
  priority: "secondary",
261
- headerClassName: "text-right",
262
- cellClassName: "text-right",
263
- cell: (e) => /* @__PURE__ */ p("span", { children: [
264
- "$",
265
- (e.revenue / 1e3).toFixed(0),
266
- "K"
267
- ] })
256
+ cell: (e) => /* @__PURE__ */ d(g, {
257
+ variant: V(e.status),
258
+ className: "text-[10px]",
259
+ children: t(e.status)
260
+ })
268
261
  },
269
262
  {
270
263
  key: "projects",
@@ -272,83 +265,92 @@ function B() {
272
265
  priority: "hidden-on-mobile",
273
266
  headerClassName: "text-right",
274
267
  cellClassName: "text-right",
275
- cell: (e) => /* @__PURE__ */ f("span", { children: e.projects })
276
- },
277
- {
278
- key: "since",
279
- header: "Since",
280
- priority: "hidden-on-mobile",
281
- cell: (e) => /* @__PURE__ */ f("span", {
282
- className: "text-text-secondary",
283
- children: e.since
268
+ cell: (e) => /* @__PURE__ */ d("span", {
269
+ className: "tabular-nums",
270
+ children: e.projects
284
271
  })
285
272
  },
286
273
  {
287
- key: "status",
288
- header: "Status",
274
+ key: "revenue",
275
+ header: "Value",
289
276
  priority: "secondary",
290
- cell: (e) => /* @__PURE__ */ f(ie, {
291
- variant: z(e.status),
292
- className: "text-[10px]",
293
- children: t(e.status)
277
+ headerClassName: "text-right",
278
+ cellClassName: "text-right",
279
+ cell: (e) => /* @__PURE__ */ f("span", {
280
+ className: "tabular-nums",
281
+ children: ["$", e.revenue.toLocaleString()]
294
282
  })
295
283
  }
296
284
  ],
297
- emptyState: /* @__PURE__ */ f(E, {
285
+ emptyState: /* @__PURE__ */ d(O, {
298
286
  illustration: "empty-search",
299
287
  title: "No clients match",
300
288
  description: "Try a different search term or status filter."
301
289
  }),
302
- rowActions: (e) => /* @__PURE__ */ p("div", {
303
- className: "flex items-center justify-end gap-1",
304
- children: [/* @__PURE__ */ f(y, {
305
- variant: "ghost",
306
- size: "icon",
307
- "aria-label": `Edit ${e.name}`,
308
- onClick: () => W.openModal(e),
309
- children: /* @__PURE__ */ f(c, { className: "h-4 w-4" })
310
- }), /* @__PURE__ */ p(m, { children: [/* @__PURE__ */ f(re, {
290
+ rowActions: (e) => /* @__PURE__ */ d("div", {
291
+ className: "flex items-center justify-end",
292
+ children: /* @__PURE__ */ f(S, { children: [/* @__PURE__ */ d(E, {
311
293
  asChild: !0,
312
- children: /* @__PURE__ */ f(y, {
294
+ children: /* @__PURE__ */ d(_, {
313
295
  variant: "ghost",
314
296
  size: "icon",
315
- "aria-label": `Delete ${e.name}`,
316
- children: /* @__PURE__ */ f(d, { className: "h-4 w-4 text-status-error-text" })
297
+ className: "h-8 w-8",
298
+ "aria-label": `More actions for ${e.name}`,
299
+ children: /* @__PURE__ */ d(c, { className: "h-4 w-4" })
317
300
  })
318
- }), /* @__PURE__ */ p(_, { children: [/* @__PURE__ */ p(te, { children: [/* @__PURE__ */ f(ne, { children: "Delete client?" }), /* @__PURE__ */ p(v, { children: [
319
- "This removes “",
320
- e.name,
321
- "” from your client portfolio. This action cannot be undone."
322
- ] })] }), /* @__PURE__ */ p(ee, { children: [/* @__PURE__ */ f(g, { children: "Cancel" }), /* @__PURE__ */ f(h, {
323
- onClick: () => void U(e.id),
324
- children: "Delete"
325
- })] })] })] })]
301
+ }), /* @__PURE__ */ f(C, {
302
+ align: "end",
303
+ children: [
304
+ /* @__PURE__ */ f(w, {
305
+ onSelect: () => G.openModal(e),
306
+ children: [/* @__PURE__ */ d(l, { className: "mr-2 h-4 w-4" }), "Edit"]
307
+ }),
308
+ /* @__PURE__ */ d(T, {}),
309
+ /* @__PURE__ */ f(w, {
310
+ className: "text-status-error-text",
311
+ onSelect: () => Y(e),
312
+ children: [/* @__PURE__ */ d(re, { className: "mr-2 h-4 w-4" }), "Delete"]
313
+ })
314
+ ]
315
+ })] })
326
316
  })
327
317
  }),
328
- $.length > Y && /* @__PURE__ */ f(k, {
329
- page: oe,
330
- pageSize: Y,
318
+ $.length > X && /* @__PURE__ */ d(j, {
319
+ page: ve,
320
+ pageSize: X,
331
321
  totalItems: $.length,
332
- onPageChange: Z
322
+ onPageChange: Q
333
323
  })
334
324
  ]
335
325
  })] }),
336
- /* @__PURE__ */ f(n, {
337
- open: W.open,
338
- onOpenChange: W.onOpenChange,
339
- title: W.context ? "Edit client" : "Add client",
326
+ /* @__PURE__ */ d(te, {
327
+ open: G.open,
328
+ onOpenChange: G.onOpenChange,
329
+ title: G.context ? "Edit client" : "Add client",
340
330
  description: "Track the client relationship, contacts, and engagement value.",
341
- fields: L,
342
- initialValues: W.context ? ae(W.context) : void 0,
343
- submitLabel: W.context ? "Save changes" : "Add client",
331
+ fields: R,
332
+ initialValues: G.context ? z(G.context) : void 0,
333
+ submitLabel: G.context ? "Save changes" : "Add client",
344
334
  onSubmit: async (e) => {
345
- W.context ? await H(W.context.id, R(e, W.context)) : await V(R(e));
335
+ G.context ? await pe(G.context.id, B(e, G.context)) : await fe(B(e));
346
336
  }
337
+ }),
338
+ /* @__PURE__ */ d(ae, {
339
+ open: J !== null,
340
+ onOpenChange: (e) => {
341
+ e || Y(null);
342
+ },
343
+ children: /* @__PURE__ */ f(ce, { children: [/* @__PURE__ */ f(m, { children: [/* @__PURE__ */ d(h, { children: "Delete client?" }), /* @__PURE__ */ d(le, { children: J ? `This removes “${J.name}” from your client portfolio. This action cannot be undone.` : "" })] }), /* @__PURE__ */ f(p, { children: [/* @__PURE__ */ d(se, { children: "Cancel" }), /* @__PURE__ */ d(oe, {
344
+ onClick: (e) => {
345
+ e.preventDefault(), J && me(J.id), Y(null);
346
+ },
347
+ children: "Delete"
348
+ })] })] })
347
349
  })
348
350
  ]
349
351
  });
350
352
  }
351
353
  //#endregion
352
- export { B as CompanyClientManagementPagePage };
354
+ export { U as CompanyClientManagementPagePage };
353
355
 
354
356
  //# sourceMappingURL=CompanyClientManagementPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CompanyClientManagementPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/CompanyClientManagementPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Building2, DollarSign, FolderKanban, Pencil, Plus, Search, Trash2 } from 'lucide-react';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { useCrewFoundryStore, type Client } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nconst CLIENT_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Client name', type: 'text', required: true },\n { name: 'industry', label: 'Industry', type: 'text' },\n { name: 'contactPerson', label: 'Contact person', type: 'text' },\n { name: 'email', label: 'Contact email', type: 'email' },\n { name: 'phone', label: 'Phone', type: 'text' },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Prospect', value: 'prospect' },\n { label: 'Churned', value: 'churned' },\n ],\n },\n { name: 'revenue', label: 'Revenue (USD)', type: 'number' },\n { name: 'projects', label: 'Projects', type: 'number' },\n { name: 'since', label: 'Client since', type: 'date' },\n];\n\nconst toInitialValues = (client: Client): FormValues => ({\n name: client.name,\n industry: client.industry,\n contactPerson: client.contactPerson,\n email: client.email,\n phone: client.phone,\n status: client.status,\n revenue: client.revenue,\n projects: client.projects,\n since: client.since ? client.since.slice(0, 10) : '',\n});\n\nconst valuesToClient = (values: FormValues, base?: Client): Client => ({\n id: base?.id ?? crypto.randomUUID(),\n name: String(values.name ?? ''),\n industry: String(values.industry ?? ''),\n contactPerson: String(values.contactPerson ?? ''),\n email: String(values.email ?? ''),\n phone: String(values.phone ?? ''),\n status: (values.status as Client['status']) || 'prospect',\n revenue: typeof values.revenue === 'number' ? values.revenue : Number(values.revenue) || 0,\n projects: typeof values.projects === 'number' ? values.projects : Number(values.projects) || 0,\n since: String(values.since ?? ''),\n});\n\nconst statusVariant = (status: Client['status']) =>\n status === 'active' ? 'default' : status === 'prospect' ? 'secondary' : 'destructive';\n\nexport function CompanyClientManagementPagePage() {\n const { clients, addClient, updateClient, removeClient } = useCrewFoundryStore();\n const modal = useFormModal<Client>();\n const [search, setSearch] = useState('');\n const [filterStatus, setFilterStatus] = useState<string>('all');\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 25 });\n\n const totalRevenue = clients.reduce((s, c) => s + c.revenue, 0);\n const activeClients = clients.filter((c) => c.status === 'active');\n\n const filtered = clients.filter((c) => {\n const matchSearch = `${c.name} ${c.industry} ${c.contactPerson} ${c.email}`\n .toLowerCase()\n .includes(search.toLowerCase());\n const matchStatus = filterStatus === 'all' || c.status === filterStatus;\n return matchSearch && matchStatus;\n });\n const paged = filtered.slice(offset, offset + pageSize);\n\n const handleSubmit = async (values: FormValues) => {\n if (modal.context) {\n await updateClient(modal.context.id, valuesToClient(values, modal.context));\n } else {\n await addClient(valuesToClient(values));\n }\n };\n\n const columns: ResponsiveTableColumn<Client>[] = [\n {\n key: 'name',\n header: 'Client',\n priority: 'primary',\n cell: (c) => <span className=\"font-medium\">{c.name}</span>,\n },\n {\n key: 'industry',\n header: 'Industry',\n priority: 'secondary',\n cell: (c) => <span className=\"text-text-secondary\">{c.industry}</span>,\n },\n {\n key: 'contact',\n header: 'Contact',\n priority: 'secondary',\n cell: (c) => (\n <div>\n <p className=\"text-xs\">{c.contactPerson}</p>\n <p className=\"text-xs text-text-secondary\">{c.email}</p>\n </div>\n ),\n },\n {\n key: 'revenue',\n header: 'Revenue',\n priority: 'secondary',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (c) => <span>${(c.revenue / 1000).toFixed(0)}K</span>,\n },\n {\n key: 'projects',\n header: 'Projects',\n priority: 'hidden-on-mobile',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (c) => <span>{c.projects}</span>,\n },\n {\n key: 'since',\n header: 'Since',\n priority: 'hidden-on-mobile',\n cell: (c) => <span className=\"text-text-secondary\">{c.since}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'secondary',\n cell: (c) => (\n <Badge variant={statusVariant(c.status)} className=\"text-[10px]\">\n {formatEnumLabel(c.status)}\n </Badge>\n ),\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>Client Management</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {clients.length} clients · ${(totalRevenue / 1000000).toFixed(1)}M revenue\n </p>\n <PagePurpose className=\"mt-1\">\n Keep track of the clients you work with — their contacts, status, and engagements — so\n account relationships never slip through the cracks.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => modal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Client\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-3\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Active Clients</CardTitle>\n <Building2 className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{activeClients.length}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Revenue</CardTitle>\n <DollarSign className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n ${(totalRevenue / 1000000).toFixed(1)}M\n </div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">Total Projects</CardTitle>\n <FolderKanban className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {clients.reduce((s, c) => s + c.projects, 0)}\n </div>\n </CardContent>\n </GlassCard>\n </div>\n <Card>\n <CardHeader>\n <CardTitle>Client Portfolio</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search clients...\"\n className=\"pl-9\"\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n setPage(1);\n }}\n />\n </div>\n <Select\n value={filterStatus}\n onValueChange={(value) => {\n setFilterStatus(value);\n setPage(1);\n }}\n >\n <SelectTrigger className=\"w-full sm:w-40\" aria-label=\"Filter by status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n <SelectItem value=\"active\">Active</SelectItem>\n <SelectItem value=\"prospect\">Prospect</SelectItem>\n <SelectItem value=\"churned\">Churned</SelectItem>\n </SelectContent>\n </Select>\n </div>\n <ResponsiveTable\n data={paged}\n rowKey={(c) => c.id}\n columns={columns}\n emptyState={\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No clients match\"\n description=\"Try a different search term or status filter.\"\n />\n }\n rowActions={(c) => (\n <div className=\"flex items-center justify-end gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={`Edit ${c.name}`}\n onClick={() => modal.openModal(c)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={`Delete ${c.name}`}>\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete client?</AlertDialogTitle>\n <AlertDialogDescription>\n This removes “{c.name}” from your client portfolio. This action cannot be\n undone.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction onClick={() => void removeClient(c.id)}>\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n )}\n />\n {filtered.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n )}\n </CardContent>\n </Card>\n\n <FormModal\n open={modal.open}\n onOpenChange={modal.onOpenChange}\n title={modal.context ? 'Edit client' : 'Add client'}\n description=\"Track the client relationship, contacts, and engagement value.\"\n fields={CLIENT_FIELDS}\n initialValues={modal.context ? toInitialValues(modal.context) : undefined}\n submitLabel={modal.context ? 'Save changes' : 'Add client'}\n onSubmit={handleSubmit}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompanyClientManagementPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/CompanyClientManagementPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { MoreHorizontal, Pencil, Plus, Search, Trash2 } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { useCrewFoundryStore, type Client } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\nimport { AvatarStack, SegmentedTabs, StatCard } from '../components/viz';\nimport { thisQuarterRevenue, totalContractValue } from '../lib/companyFinance';\n\nconst CLIENT_FIELDS: FieldConfig[] = [\n { name: 'name', label: 'Client name', type: 'text', required: true },\n { name: 'industry', label: 'Industry', type: 'text' },\n { name: 'contactPerson', label: 'Contact person', type: 'text' },\n { name: 'email', label: 'Contact email', type: 'email' },\n { name: 'phone', label: 'Phone', type: 'text' },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Prospect', value: 'prospect' },\n { label: 'Churned', value: 'churned' },\n ],\n },\n { name: 'revenue', label: 'Revenue (USD)', type: 'number' },\n { name: 'projects', label: 'Projects', type: 'number' },\n { name: 'since', label: 'Client since', type: 'date' },\n];\n\nconst toInitialValues = (client: Client): FormValues => ({\n name: client.name,\n industry: client.industry,\n contactPerson: client.contactPerson,\n email: client.email,\n phone: client.phone,\n status: client.status,\n revenue: client.revenue,\n projects: client.projects,\n since: client.since ? client.since.slice(0, 10) : '',\n});\n\nconst valuesToClient = (values: FormValues, base?: Client): Client => ({\n id: base?.id ?? crypto.randomUUID(),\n name: String(values.name ?? ''),\n industry: String(values.industry ?? ''),\n contactPerson: String(values.contactPerson ?? ''),\n email: String(values.email ?? ''),\n phone: String(values.phone ?? ''),\n status: (values.status as Client['status']) || 'prospect',\n revenue: typeof values.revenue === 'number' ? values.revenue : Number(values.revenue) || 0,\n projects: typeof values.projects === 'number' ? values.projects : Number(values.projects) || 0,\n since: String(values.since ?? ''),\n});\n\nconst statusVariant = (status: Client['status']) =>\n status === 'active' ? 'default' : status === 'prospect' ? 'secondary' : 'destructive';\n\nconst compactMoney = (value: number): string => {\n if (value >= 1_000_000) {\n return `$${(value / 1_000_000).toFixed(1)}M`;\n }\n if (value >= 1_000) {\n return `$${Math.round(value / 1_000)}k`;\n }\n return `$${Math.round(value)}`;\n};\n\nexport function CompanyClientManagementPagePage() {\n const { clients, vendors, invoices, addClient, updateClient, removeClient } = useCrewFoundryStore();\n const navigate = useNavigate();\n const modal = useFormModal<Client>();\n const [search, setSearch] = useState('');\n const [filterStatus, setFilterStatus] = useState<string>('all');\n const [deleteTarget, setDeleteTarget] = useState<Client | null>(null);\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 25 });\n\n const activeClients = clients.filter((c) => c.status === 'active');\n const contractValue = totalContractValue(clients, vendors);\n const quarterRevenue = thisQuarterRevenue(invoices);\n\n const filtered = clients.filter((c) => {\n const matchSearch = `${c.name} ${c.industry} ${c.contactPerson} ${c.email}`\n .toLowerCase()\n .includes(search.toLowerCase());\n const matchStatus = filterStatus === 'all' || c.status === filterStatus;\n return matchSearch && matchStatus;\n });\n const paged = filtered.slice(offset, offset + pageSize);\n\n const handleSubmit = async (values: FormValues) => {\n if (modal.context) {\n await updateClient(modal.context.id, valuesToClient(values, modal.context));\n } else {\n await addClient(valuesToClient(values));\n }\n };\n\n const columns: ResponsiveTableColumn<Client>[] = [\n {\n key: 'name',\n header: 'Client',\n priority: 'primary',\n cell: (c) => (\n <div className=\"flex items-center gap-3\">\n <AvatarStack people={[{ name: c.name }]} size={36} />\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{c.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">{c.industry || '—'}</p>\n </div>\n </div>\n ),\n },\n {\n key: 'contact',\n header: 'Primary Contact',\n priority: 'secondary',\n cell: (c) => (\n <div>\n <p className=\"text-xs\">{c.contactPerson || '—'}</p>\n <p className=\"text-xs text-text-secondary\">{c.email}</p>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'secondary',\n cell: (c) => (\n <Badge variant={statusVariant(c.status)} className=\"text-[10px]\">\n {formatEnumLabel(c.status)}\n </Badge>\n ),\n },\n {\n key: 'projects',\n header: 'Projects',\n priority: 'hidden-on-mobile',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (c) => <span className=\"tabular-nums\">{c.projects}</span>,\n },\n {\n key: 'revenue',\n header: 'Value',\n priority: 'secondary',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (c) => <span className=\"tabular-nums\">${c.revenue.toLocaleString()}</span>,\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>Clients &amp; Vendors</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {clients.length} clients · {vendors.length} vendors\n </p>\n <PagePurpose className=\"mt-1\">\n Keep track of the clients you work with — their contacts, status, and engagements — so\n account relationships never slip through the cracks.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => modal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add Client\n </Button>\n </div>\n\n <SegmentedTabs\n aria-label=\"Clients and vendors\"\n variant=\"underline\"\n value=\"clients\"\n onChange={(id) => {\n if (id === 'vendors') {\n navigate('../company/vendor-management-page');\n }\n }}\n tabs={[\n { id: 'clients', label: 'Clients', count: clients.length },\n { id: 'vendors', label: 'Vendors', count: vendors.length },\n ]}\n />\n\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <StatCard label=\"Active Clients\" value={activeClients.length} />\n <StatCard label=\"Vendors\" value={vendors.length} />\n <StatCard label=\"Total Contract Value\" value={compactMoney(contractValue)} />\n <StatCard label=\"This Quarter\" value={compactMoney(quarterRevenue)} />\n </div>\n\n <Card>\n <CardHeader>\n <CardTitle>Client Portfolio</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search clients...\"\n className=\"pl-9\"\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n setPage(1);\n }}\n />\n </div>\n <Select\n value={filterStatus}\n onValueChange={(value) => {\n setFilterStatus(value);\n setPage(1);\n }}\n >\n <SelectTrigger className=\"w-full sm:w-40\" aria-label=\"Filter by status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n <SelectItem value=\"active\">Active</SelectItem>\n <SelectItem value=\"prospect\">Prospect</SelectItem>\n <SelectItem value=\"churned\">Churned</SelectItem>\n </SelectContent>\n </Select>\n </div>\n <ResponsiveTable\n data={paged}\n rowKey={(c) => c.id}\n columns={columns}\n emptyState={\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No clients match\"\n description=\"Try a different search term or status filter.\"\n />\n }\n rowActions={(c) => (\n <div className=\"flex items-center justify-end\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n aria-label={`More actions for ${c.name}`}\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onSelect={() => modal.openModal(c)}>\n <Pencil className=\"mr-2 h-4 w-4\" />\n Edit\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"text-status-error-text\"\n onSelect={() => setDeleteTarget(c)}\n >\n <Trash2 className=\"mr-2 h-4 w-4\" />\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )}\n />\n {filtered.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n )}\n </CardContent>\n </Card>\n\n <FormModal\n open={modal.open}\n onOpenChange={modal.onOpenChange}\n title={modal.context ? 'Edit client' : 'Add client'}\n description=\"Track the client relationship, contacts, and engagement value.\"\n fields={CLIENT_FIELDS}\n initialValues={modal.context ? toInitialValues(modal.context) : undefined}\n submitLabel={modal.context ? 'Save changes' : 'Add client'}\n onSubmit={handleSubmit}\n />\n\n <AlertDialog\n open={deleteTarget !== null}\n onOpenChange={(open) => {\n if (!open) {\n setDeleteTarget(null);\n }\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete client?</AlertDialogTitle>\n <AlertDialogDescription>\n {deleteTarget\n ? `This removes “${deleteTarget.name}” from your client portfolio. This action cannot be undone.`\n : ''}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={(event) => {\n event.preventDefault();\n if (deleteTarget) {\n void removeClient(deleteTarget.id);\n }\n setDeleteTarget(null);\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n"],"mappings":"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"}