@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,161 +1,310 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
- import { Clock as t, DollarSign as n, MessageSquare as r, Star as i, Users as a } from "lucide-react";
3
- import { useLocation as o, useNavigate as s } from "react-router-dom";
4
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
5
- import { Badge as u, Button as d, Card as f, CardContent as p, EmphasisPanel as m, GradientText as h, IllustratedEmptyState as g, NextSteps as _, PagePurpose as v, Spinner as y } from "@burdenoff/fe-libs/ui";
2
+ import { getInitials as t } from "../components/viz/lib/format.js";
3
+ import { RatingStars as n } from "../components/viz/RatingStars.js";
4
+ import "../components/viz/index.js";
5
+ import { useMemo as r, useState as i } from "react";
6
+ import { CalendarDays as a, CheckCircle2 as o, Clock3 as s, MessageSquare as c, PauseCircle as l, Star as u } from "lucide-react";
7
+ import { useLocation as d, useNavigate as f } from "react-router-dom";
8
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
9
+ import { Badge as h, Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b, EmphasisPanel as x, GradientText as S, IllustratedEmptyState as C, Input as w, PagePurpose as T, Spinner as E } from "@burdenoff/fe-libs/ui";
6
10
  //#region src/crewfoundry/pages/MarketplaceServiceDetailsPagePage.tsx
7
- function b() {
8
- let b = s(), x = o(), { marketplaceServices: S, initialized: C } = e(), w = new URLSearchParams(x.search).get("id"), T = S.find((e) => e.id === w) ?? S[0];
9
- return !C && !T ? /* @__PURE__ */ c("div", {
11
+ function D(e) {
12
+ switch (e) {
13
+ case "active": return {
14
+ label: "Available for new projects",
15
+ icon: o,
16
+ className: "text-status-success-text"
17
+ };
18
+ case "pending": return {
19
+ label: "Pending review",
20
+ icon: s,
21
+ className: "text-status-warning-text"
22
+ };
23
+ default: return {
24
+ label: "Not currently available",
25
+ icon: l,
26
+ className: "text-text-secondary"
27
+ };
28
+ }
29
+ }
30
+ function O() {
31
+ let o = f(), l = d(), { marketplaceServices: O, initialized: k } = e(), A = new URLSearchParams(l.search).get("id"), j = O.find((e) => e.id === A) ?? O[0], M = r(() => j ? O.filter((e) => e.provider === j.provider) : [], [O, j]), [N, P] = i(null), F = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), [I, L] = i(F);
32
+ if (!k && !j) return /* @__PURE__ */ p("div", {
10
33
  className: "flex min-h-[60vh] items-center justify-center p-6",
11
- children: /* @__PURE__ */ c(y, { size: "lg" })
12
- }) : T ? /* @__PURE__ */ l("div", {
13
- className: "space-y-6 p-6 max-w-4xl",
14
- children: [
15
- /* @__PURE__ */ l("div", {
16
- className: "flex items-center justify-between",
17
- children: [/* @__PURE__ */ l("div", { children: [
18
- /* @__PURE__ */ c("h1", {
19
- className: "text-2xl font-semibold",
20
- children: /* @__PURE__ */ c(h, { children: T.title })
34
+ children: /* @__PURE__ */ p(E, { size: "lg" })
35
+ });
36
+ if (!j) return /* @__PURE__ */ p("div", {
37
+ className: "p-6",
38
+ children: /* @__PURE__ */ p(C, {
39
+ illustration: "empty-search",
40
+ title: "Service not found",
41
+ description: "This service is no longer available."
42
+ })
43
+ });
44
+ let R = M.find((e) => e.id === N) ?? j, z = D(j.status), B = z.icon;
45
+ return /* @__PURE__ */ m("div", {
46
+ className: "space-y-6 p-6",
47
+ children: [/* @__PURE__ */ m("div", {
48
+ className: "text-xs text-text-secondary",
49
+ children: [
50
+ /* @__PURE__ */ p("button", {
51
+ type: "button",
52
+ className: "hover:text-text-primary",
53
+ onClick: () => o("../marketplace/marketplace-page"),
54
+ children: "Marketplace"
55
+ }),
56
+ /* @__PURE__ */ p("span", {
57
+ className: "mx-1",
58
+ children: "/"
59
+ }),
60
+ /* @__PURE__ */ p("span", {
61
+ className: "text-text-primary",
62
+ children: j.title
63
+ })
64
+ ]
65
+ }), /* @__PURE__ */ m("div", {
66
+ className: "grid gap-6 lg:grid-cols-3",
67
+ children: [/* @__PURE__ */ m("div", {
68
+ className: "space-y-6 lg:col-span-2",
69
+ children: [
70
+ /* @__PURE__ */ m("div", {
71
+ className: "flex flex-col gap-4 sm:flex-row sm:items-start",
72
+ children: [/* @__PURE__ */ p("span", {
73
+ className: "flex h-20 w-20 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-2xl font-semibold text-action-primary-text",
74
+ "aria-hidden": "true",
75
+ children: t(j.provider)
76
+ }), /* @__PURE__ */ m("div", {
77
+ className: "min-w-0 flex-1 space-y-2",
78
+ children: [
79
+ /* @__PURE__ */ p("h1", {
80
+ className: "text-2xl font-semibold",
81
+ children: /* @__PURE__ */ p(S, { children: j.provider })
82
+ }),
83
+ /* @__PURE__ */ p("p", {
84
+ className: "text-sm text-text-secondary",
85
+ children: j.title
86
+ }),
87
+ /* @__PURE__ */ m("div", {
88
+ className: "flex flex-wrap items-center gap-3",
89
+ children: [
90
+ /* @__PURE__ */ p(n, {
91
+ value: j.rating,
92
+ count: j.reviews,
93
+ showValue: !0,
94
+ size: 16
95
+ }),
96
+ /* @__PURE__ */ m("span", {
97
+ className: "flex items-center gap-1 text-xs text-text-secondary",
98
+ children: [/* @__PURE__ */ p(s, { className: "h-3 w-3" }), j.deliveryTime]
99
+ }),
100
+ /* @__PURE__ */ p(h, {
101
+ variant: "outline",
102
+ className: "text-[10px]",
103
+ children: j.category
104
+ })
105
+ ]
106
+ }),
107
+ /* @__PURE__ */ p("div", {
108
+ className: "flex flex-wrap gap-1.5 pt-1",
109
+ children: j.skills.map((e) => /* @__PURE__ */ p(h, {
110
+ variant: "secondary",
111
+ className: "text-xs",
112
+ children: e
113
+ }, e))
114
+ })
115
+ ]
116
+ })]
21
117
  }),
22
- /* @__PURE__ */ l("p", {
118
+ /* @__PURE__ */ p(T, { children: "See exactly what this service includes, what it costs, and how others rated it — use the booking panel to pick a package and request an engagement." }),
119
+ /* @__PURE__ */ m(x, { children: [/* @__PURE__ */ p("div", {
120
+ className: "mb-2 text-lg font-semibold",
121
+ children: "About this service"
122
+ }), /* @__PURE__ */ p("p", {
23
123
  className: "text-sm text-text-secondary",
24
- children: ["by ", T.provider]
124
+ children: j.description
125
+ })] }),
126
+ /* @__PURE__ */ m("div", {
127
+ className: "space-y-3",
128
+ children: [/* @__PURE__ */ p("h2", {
129
+ className: "text-lg font-semibold",
130
+ children: "Services offered"
131
+ }), /* @__PURE__ */ p("div", {
132
+ className: "grid gap-3 sm:grid-cols-2 xl:grid-cols-3",
133
+ children: M.map((e) => {
134
+ let t = e.id === R.id;
135
+ return /* @__PURE__ */ m("button", {
136
+ type: "button",
137
+ onClick: () => P(e.id),
138
+ "aria-pressed": t,
139
+ className: `flex flex-col rounded-lg border p-4 text-left transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] ${t ? "border-action-primary-bg bg-action-primary-bg/5" : "border-border-subtle hover:bg-bg-sunken/50"}`,
140
+ children: [
141
+ /* @__PURE__ */ m("div", {
142
+ className: "flex items-start justify-between gap-2",
143
+ children: [/* @__PURE__ */ p("p", {
144
+ className: "text-sm font-semibold",
145
+ children: e.title
146
+ }), /* @__PURE__ */ p("span", {
147
+ className: "whitespace-nowrap text-[11px] text-text-secondary",
148
+ children: e.deliveryTime
149
+ })]
150
+ }),
151
+ /* @__PURE__ */ m("p", {
152
+ className: "mt-1 text-xl font-bold tabular-nums",
153
+ children: [
154
+ "$",
155
+ e.price.toLocaleString(),
156
+ /* @__PURE__ */ m("span", {
157
+ className: "text-xs font-normal text-text-secondary",
158
+ children: ["/", e.priceType]
159
+ })
160
+ ]
161
+ }),
162
+ /* @__PURE__ */ p("p", {
163
+ className: "mt-2 line-clamp-3 text-xs text-text-secondary",
164
+ children: e.description
165
+ })
166
+ ]
167
+ }, e.id);
168
+ })
169
+ })]
25
170
  }),
26
- /* @__PURE__ */ c(v, {
27
- className: "mt-2",
28
- children: "See exactly what this service includes, what it costs, and how others rated it — use it to compare offerings and hire the right provider for your project."
171
+ /* @__PURE__ */ m("div", {
172
+ className: "space-y-3",
173
+ children: [/* @__PURE__ */ p("h2", {
174
+ className: "text-lg font-semibold",
175
+ children: "Reviews"
176
+ }), /* @__PURE__ */ p(_, { children: /* @__PURE__ */ m(v, {
177
+ className: "flex flex-col items-center gap-2 p-6 text-center",
178
+ children: [/* @__PURE__ */ m("div", {
179
+ className: "flex items-center gap-2",
180
+ children: [
181
+ /* @__PURE__ */ p(u, {
182
+ className: "h-6 w-6 text-status-warning-text",
183
+ fill: "currentColor"
184
+ }),
185
+ /* @__PURE__ */ p("span", {
186
+ className: "text-2xl font-bold tabular-nums",
187
+ children: j.rating.toFixed(1)
188
+ }),
189
+ /* @__PURE__ */ p("span", {
190
+ className: "text-sm text-text-secondary",
191
+ children: "/ 5"
192
+ })
193
+ ]
194
+ }), /* @__PURE__ */ m("p", {
195
+ className: "text-sm text-text-secondary",
196
+ children: [
197
+ "Based on ",
198
+ j.reviews.toLocaleString(),
199
+ " ",
200
+ j.reviews === 1 ? "review" : "reviews",
201
+ ". Individual review notes aren't published for this listing yet."
202
+ ]
203
+ })]
204
+ }) })]
29
205
  })
30
- ] }), /* @__PURE__ */ l("div", {
31
- className: "flex gap-2",
32
- children: [/* @__PURE__ */ l(d, {
33
- variant: "outline",
34
- onClick: () => b("../marketplace/messaging-page"),
35
- children: [/* @__PURE__ */ c(r, { className: "h-4 w-4 mr-1" }), "Contact"]
36
- }), /* @__PURE__ */ c(d, {
37
- disabled: !0,
38
- title: "Hiring is coming soon",
39
- "aria-label": "Hire now — coming soon",
40
- children: "Hire Now · Coming soon"
41
- })]
42
- })]
43
- }),
44
- /* @__PURE__ */ c(_, {
45
- storageKey: "crewfoundry-service-details",
46
- steps: [
47
- {
48
- id: "contact",
49
- label: "Message the provider",
50
- description: "Ask questions before you commit to hiring.",
51
- icon: /* @__PURE__ */ c(r, { className: "h-4 w-4" }),
52
- onClick: () => b("../marketplace/messaging-page")
53
- },
54
- {
55
- id: "compare",
56
- label: "Compare other services",
57
- description: "Browse similar offerings on the marketplace.",
58
- icon: /* @__PURE__ */ c(a, { className: "h-4 w-4" }),
59
- onClick: () => b("../marketplace/marketplace-services-page")
60
- },
61
- {
62
- id: "bookings",
63
- label: "Manage your bookings",
64
- description: "Track engagements you have already arranged.",
65
- icon: /* @__PURE__ */ c(t, { className: "h-4 w-4" }),
66
- onClick: () => b("../marketplace/booking-management-page")
67
- }
68
206
  ]
69
- }),
70
- /* @__PURE__ */ l("div", {
71
- className: "grid gap-4 md:grid-cols-4",
72
- children: [
73
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
74
- className: "p-4 text-center",
207
+ }), /* @__PURE__ */ p("div", {
208
+ className: "lg:col-span-1",
209
+ children: /* @__PURE__ */ m(_, {
210
+ className: "lg:sticky lg:top-6",
211
+ children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, {
212
+ className: "text-lg",
213
+ children: "Book this service"
214
+ }) }), /* @__PURE__ */ m(v, {
215
+ className: "space-y-5",
75
216
  children: [
76
- /* @__PURE__ */ c(n, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
77
- /* @__PURE__ */ l("p", {
78
- className: "text-lg font-bold",
79
- children: ["$", T.price.toLocaleString()]
217
+ /* @__PURE__ */ m("fieldset", {
218
+ className: "space-y-2",
219
+ children: [/* @__PURE__ */ p("legend", {
220
+ className: "mb-1 text-sm font-medium",
221
+ children: "Package"
222
+ }), M.map((e) => {
223
+ let t = e.id === R.id;
224
+ return /* @__PURE__ */ m("button", {
225
+ type: "button",
226
+ onClick: () => P(e.id),
227
+ "aria-pressed": t,
228
+ className: `flex w-full items-center justify-between gap-3 rounded-lg border px-3 py-2.5 text-left transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] ${t ? "border-action-primary-bg bg-action-primary-bg/5" : "border-border-subtle hover:bg-bg-sunken/50"}`,
229
+ children: [/* @__PURE__ */ m("span", {
230
+ className: "flex items-center gap-2 min-w-0",
231
+ children: [/* @__PURE__ */ p("span", {
232
+ className: `flex h-4 w-4 shrink-0 items-center justify-center rounded-full border ${t ? "border-action-primary-bg" : "border-border-strong"}`,
233
+ "aria-hidden": "true",
234
+ children: t ? /* @__PURE__ */ p("span", { className: "h-2 w-2 rounded-full bg-action-primary-bg" }) : null
235
+ }), /* @__PURE__ */ p("span", {
236
+ className: "truncate text-sm",
237
+ children: e.title
238
+ })]
239
+ }), /* @__PURE__ */ m("span", {
240
+ className: "whitespace-nowrap text-sm font-semibold tabular-nums",
241
+ children: ["$", e.price.toLocaleString()]
242
+ })]
243
+ }, e.id);
244
+ })]
80
245
  }),
81
- /* @__PURE__ */ l("p", {
82
- className: "text-xs text-text-secondary",
83
- children: ["per ", T.priceType]
84
- })
85
- ]
86
- }) }),
87
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
88
- className: "p-4 text-center",
89
- children: [
90
- /* @__PURE__ */ c(i, { className: "h-5 w-5 mx-auto text-status-warning-text mb-1" }),
91
- /* @__PURE__ */ l("p", {
92
- className: "text-lg font-bold",
93
- children: [T.rating, "/5"]
246
+ /* @__PURE__ */ m("div", {
247
+ className: "space-y-1.5",
248
+ children: [/* @__PURE__ */ p("label", {
249
+ htmlFor: "booking-date",
250
+ className: "text-sm font-medium",
251
+ children: "Date"
252
+ }), /* @__PURE__ */ m("div", {
253
+ className: "relative",
254
+ children: [/* @__PURE__ */ p(a, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ p(w, {
255
+ id: "booking-date",
256
+ type: "date",
257
+ min: F,
258
+ value: I,
259
+ onChange: (e) => L(e.target.value),
260
+ className: "pl-9"
261
+ })]
262
+ })]
94
263
  }),
95
- /* @__PURE__ */ l("p", {
96
- className: "text-xs text-text-secondary",
97
- children: [T.reviews, " reviews"]
98
- })
99
- ]
100
- }) }),
101
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
102
- className: "p-4 text-center",
103
- children: [
104
- /* @__PURE__ */ c(t, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
105
- /* @__PURE__ */ c("p", {
106
- className: "text-lg font-bold",
107
- children: T.deliveryTime
264
+ /* @__PURE__ */ m("div", {
265
+ className: "flex items-center justify-between border-t border-border-subtle pt-3",
266
+ children: [/* @__PURE__ */ p("span", {
267
+ className: "text-sm font-medium",
268
+ children: "Total price"
269
+ }), /* @__PURE__ */ m("span", {
270
+ className: "text-lg font-bold tabular-nums",
271
+ children: [
272
+ "$",
273
+ R.price.toLocaleString(),
274
+ /* @__PURE__ */ m("span", {
275
+ className: "text-xs font-normal text-text-secondary",
276
+ children: ["/", R.priceType]
277
+ })
278
+ ]
279
+ })]
108
280
  }),
109
- /* @__PURE__ */ c("p", {
110
- className: "text-xs text-text-secondary",
111
- children: "Delivery"
112
- })
113
- ]
114
- }) }),
115
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
116
- className: "p-4 text-center",
117
- children: [
118
- /* @__PURE__ */ c(a, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
119
- /* @__PURE__ */ c("p", {
120
- className: "text-lg font-bold",
121
- children: T.category
281
+ /* @__PURE__ */ m("div", {
282
+ className: "space-y-2",
283
+ children: [/* @__PURE__ */ p(g, {
284
+ className: "w-full",
285
+ disabled: !0,
286
+ title: "Booking is coming soon",
287
+ "aria-label": "Book now — coming soon",
288
+ children: "Book Now · Coming soon"
289
+ }), /* @__PURE__ */ m(g, {
290
+ variant: "outline",
291
+ className: "w-full",
292
+ onClick: () => o("../marketplace/messaging-page"),
293
+ children: [/* @__PURE__ */ p(c, { className: "mr-1 h-4 w-4" }), "Message"]
294
+ })]
122
295
  }),
123
- /* @__PURE__ */ c("p", {
124
- className: "text-xs text-text-secondary",
125
- children: "Category"
296
+ /* @__PURE__ */ m("p", {
297
+ className: `flex items-center justify-center gap-1.5 text-xs ${z.className}`,
298
+ children: [/* @__PURE__ */ p(B, { className: "h-3.5 w-3.5" }), z.label]
126
299
  })
127
300
  ]
128
- }) })
129
- ]
130
- }),
131
- /* @__PURE__ */ l(m, { children: [
132
- /* @__PURE__ */ c("div", {
133
- className: "mb-2 text-lg font-semibold",
134
- children: "About this Service"
135
- }),
136
- /* @__PURE__ */ c("p", {
137
- className: "text-sm text-text-secondary",
138
- children: T.description
139
- }),
140
- /* @__PURE__ */ c("div", {
141
- className: "flex flex-wrap gap-1 mt-3",
142
- children: T.skills.map((e) => /* @__PURE__ */ c(u, {
143
- variant: "outline",
144
- children: e
145
- }, e))
301
+ })]
146
302
  })
147
- ] })
148
- ]
149
- }) : /* @__PURE__ */ c("div", {
150
- className: "p-6",
151
- children: /* @__PURE__ */ c(g, {
152
- illustration: "empty-search",
153
- title: "Service not found",
154
- description: "This service is no longer available."
155
- })
303
+ })]
304
+ })]
156
305
  });
157
306
  }
158
307
  //#endregion
159
- export { b as MarketplaceServiceDetailsPagePage };
308
+ export { O as MarketplaceServiceDetailsPagePage };
160
309
 
161
310
  //# sourceMappingURL=MarketplaceServiceDetailsPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplaceServiceDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceServiceDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Spinner,\n} from '@burdenoff/fe-libs/ui';\nimport { Clock, DollarSign, MessageSquare, Star, Users } from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function MarketplaceServiceDetailsPagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices, initialized } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n const svc = marketplaceServices.find((s) => s.id === selectedId) ?? marketplaceServices[0];\n if (!initialized && !svc) {\n return (\n <div className=\"flex min-h-[60vh] items-center justify-center p-6\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n if (!svc)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Service not found\"\n description=\"This service is no longer available.\"\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{svc.title}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">by {svc.provider}</p>\n <PagePurpose className=\"mt-2\">\n See exactly what this service includes, what it costs, and how others rated it — use it\n to compare offerings and hire the right provider for your project.\n </PagePurpose>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" onClick={() => navigate('../marketplace/messaging-page')}>\n <MessageSquare className=\"h-4 w-4 mr-1\" />\n Contact\n </Button>\n {/* No hire/engagement mutation exists yet, so this stays an honest\n disabled control rather than a silently-dead primary CTA. */}\n <Button disabled title=\"Hiring is coming soon\" aria-label=\"Hire now — coming soon\">\n Hire Now · Coming soon\n </Button>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-service-details\"\n steps={[\n {\n id: 'contact',\n label: 'Message the provider',\n description: 'Ask questions before you commit to hiring.',\n icon: <MessageSquare className=\"h-4 w-4\" />,\n onClick: () => navigate('../marketplace/messaging-page'),\n },\n {\n id: 'compare',\n label: 'Compare other services',\n description: 'Browse similar offerings on the marketplace.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../marketplace/marketplace-services-page'),\n },\n {\n id: 'bookings',\n label: 'Manage your bookings',\n description: 'Track engagements you have already arranged.',\n icon: <Clock className=\"h-4 w-4\" />,\n onClick: () => navigate('../marketplace/booking-management-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">${svc.price.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">per {svc.priceType}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Star className=\"h-5 w-5 mx-auto text-status-warning-text mb-1\" />\n <p className=\"text-lg font-bold\">{svc.rating}/5</p>\n <p className=\"text-xs text-text-secondary\">{svc.reviews} reviews</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Clock className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{svc.deliveryTime}</p>\n <p className=\"text-xs text-text-secondary\">Delivery</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{svc.category}</p>\n <p className=\"text-xs text-text-secondary\">Category</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"mb-2 text-lg font-semibold\">About this Service</div>\n <p className=\"text-sm text-text-secondary\">{svc.description}</p>\n <div className=\"flex flex-wrap gap-1 mt-3\">\n {svc.skills.map((s) => (\n <Badge key={s} variant=\"outline\">\n {s}\n </Badge>\n ))}\n </div>\n </EmphasisPanel>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MarketplaceServiceDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceServiceDetailsPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Spinner,\n} from '@burdenoff/fe-libs/ui';\nimport {\n CalendarDays,\n CheckCircle2,\n Clock3,\n MessageSquare,\n PauseCircle,\n Star,\n} from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type MarketplaceService } from '../store/crewfoundryStore';\nimport { RatingStars, getInitials } from '../components/viz';\n\n/** Honest availability derived from the real service `status` enum (never \"Booked\"). */\nfunction availabilityOf(status: MarketplaceService['status']): {\n label: string;\n icon: typeof CheckCircle2;\n className: string;\n} {\n switch (status) {\n case 'active':\n return {\n label: 'Available for new projects',\n icon: CheckCircle2,\n className: 'text-status-success-text',\n };\n case 'pending':\n return { label: 'Pending review', icon: Clock3, className: 'text-status-warning-text' };\n default:\n return { label: 'Not currently available', icon: PauseCircle, className: 'text-text-secondary' };\n }\n}\n\nexport function MarketplaceServiceDetailsPagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices, initialized } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n const svc = marketplaceServices.find((s) => s.id === selectedId) ?? marketplaceServices[0];\n\n // Real \"packages\": every service this same provider actually offers. The\n // backend exposes a single price per service (no synthetic tiers), so each\n // package is a genuine listing — the viewed service is pre-selected.\n const providerPackages = useMemo(\n () =>\n svc\n ? marketplaceServices.filter((s) => s.provider === svc.provider)\n : ([] as MarketplaceService[]),\n [marketplaceServices, svc]\n );\n\n const [selectedPackageId, setSelectedPackageId] = useState<string | null>(null);\n const today = new Date().toISOString().slice(0, 10);\n const [bookingDate, setBookingDate] = useState(today);\n\n if (!initialized && !svc) {\n return (\n <div className=\"flex min-h-[60vh] items-center justify-center p-6\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n if (!svc) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Service not found\"\n description=\"This service is no longer available.\"\n />\n </div>\n );\n }\n\n const selectedPackage = providerPackages.find((p) => p.id === selectedPackageId) ?? svc;\n const availability = availabilityOf(svc.status);\n const AvailabilityIcon = availability.icon;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"text-xs text-text-secondary\">\n <button\n type=\"button\"\n className=\"hover:text-text-primary\"\n onClick={() => navigate('../marketplace/marketplace-page')}\n >\n Marketplace\n </button>\n <span className=\"mx-1\">/</span>\n <span className=\"text-text-primary\">{svc.title}</span>\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* ── Left: provider + service detail ─────────────────────────── */}\n <div className=\"space-y-6 lg:col-span-2\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start\">\n <span\n className=\"flex h-20 w-20 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-2xl font-semibold text-action-primary-text\"\n aria-hidden=\"true\"\n >\n {getInitials(svc.provider)}\n </span>\n <div className=\"min-w-0 flex-1 space-y-2\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{svc.provider}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{svc.title}</p>\n <div className=\"flex flex-wrap items-center gap-3\">\n <RatingStars value={svc.rating} count={svc.reviews} showValue size={16} />\n <span className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Clock3 className=\"h-3 w-3\" />\n {svc.deliveryTime}\n </span>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {svc.category}\n </Badge>\n </div>\n <div className=\"flex flex-wrap gap-1.5 pt-1\">\n {svc.skills.map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-xs\">\n {skill}\n </Badge>\n ))}\n </div>\n </div>\n </div>\n\n <PagePurpose>\n See exactly what this service includes, what it costs, and how others rated it — use the\n booking panel to pick a package and request an engagement.\n </PagePurpose>\n\n <EmphasisPanel>\n <div className=\"mb-2 text-lg font-semibold\">About this service</div>\n <p className=\"text-sm text-text-secondary\">{svc.description}</p>\n </EmphasisPanel>\n\n {/* Services offered — real listings from this provider */}\n <div className=\"space-y-3\">\n <h2 className=\"text-lg font-semibold\">Services offered</h2>\n <div className=\"grid gap-3 sm:grid-cols-2 xl:grid-cols-3\">\n {providerPackages.map((pkg) => {\n const active = pkg.id === selectedPackage.id;\n return (\n <button\n key={pkg.id}\n type=\"button\"\n onClick={() => setSelectedPackageId(pkg.id)}\n aria-pressed={active}\n className={`flex flex-col rounded-lg border p-4 text-left transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] ${\n active\n ? 'border-action-primary-bg bg-action-primary-bg/5'\n : 'border-border-subtle hover:bg-bg-sunken/50'\n }`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"text-sm font-semibold\">{pkg.title}</p>\n <span className=\"whitespace-nowrap text-[11px] text-text-secondary\">\n {pkg.deliveryTime}\n </span>\n </div>\n <p className=\"mt-1 text-xl font-bold tabular-nums\">\n ${pkg.price.toLocaleString()}\n <span className=\"text-xs font-normal text-text-secondary\">/{pkg.priceType}</span>\n </p>\n <p className=\"mt-2 line-clamp-3 text-xs text-text-secondary\">{pkg.description}</p>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Reviews — backend stores only an aggregate rating + count, not\n individual review bodies, so we report that honestly rather than\n inventing reviewer cards. */}\n <div className=\"space-y-3\">\n <h2 className=\"text-lg font-semibold\">Reviews</h2>\n <Card>\n <CardContent className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <div className=\"flex items-center gap-2\">\n <Star className=\"h-6 w-6 text-status-warning-text\" fill=\"currentColor\" />\n <span className=\"text-2xl font-bold tabular-nums\">{svc.rating.toFixed(1)}</span>\n <span className=\"text-sm text-text-secondary\">/ 5</span>\n </div>\n <p className=\"text-sm text-text-secondary\">\n Based on {svc.reviews.toLocaleString()}{' '}\n {svc.reviews === 1 ? 'review' : 'reviews'}. Individual review notes aren&apos;t\n published for this listing yet.\n </p>\n </CardContent>\n </Card>\n </div>\n </div>\n\n {/* ── Right: sticky booking panel ─────────────────────────────── */}\n <div className=\"lg:col-span-1\">\n <Card className=\"lg:sticky lg:top-6\">\n <CardHeader>\n <CardTitle className=\"text-lg\">Book this service</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-5\">\n <fieldset className=\"space-y-2\">\n <legend className=\"mb-1 text-sm font-medium\">Package</legend>\n {providerPackages.map((pkg) => {\n const active = pkg.id === selectedPackage.id;\n return (\n <button\n key={pkg.id}\n type=\"button\"\n onClick={() => setSelectedPackageId(pkg.id)}\n aria-pressed={active}\n className={`flex w-full items-center justify-between gap-3 rounded-lg border px-3 py-2.5 text-left transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] ${\n active\n ? 'border-action-primary-bg bg-action-primary-bg/5'\n : 'border-border-subtle hover:bg-bg-sunken/50'\n }`}\n >\n <span className=\"flex items-center gap-2 min-w-0\">\n <span\n className={`flex h-4 w-4 shrink-0 items-center justify-center rounded-full border ${\n active ? 'border-action-primary-bg' : 'border-border-strong'\n }`}\n aria-hidden=\"true\"\n >\n {active ? (\n <span className=\"h-2 w-2 rounded-full bg-action-primary-bg\" />\n ) : null}\n </span>\n <span className=\"truncate text-sm\">{pkg.title}</span>\n </span>\n <span className=\"whitespace-nowrap text-sm font-semibold tabular-nums\">\n ${pkg.price.toLocaleString()}\n </span>\n </button>\n );\n })}\n </fieldset>\n\n <div className=\"space-y-1.5\">\n <label htmlFor=\"booking-date\" className=\"text-sm font-medium\">\n Date\n </label>\n <div className=\"relative\">\n <CalendarDays className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n id=\"booking-date\"\n type=\"date\"\n min={today}\n value={bookingDate}\n onChange={(event) => setBookingDate(event.target.value)}\n className=\"pl-9\"\n />\n </div>\n </div>\n\n <div className=\"flex items-center justify-between border-t border-border-subtle pt-3\">\n <span className=\"text-sm font-medium\">Total price</span>\n <span className=\"text-lg font-bold tabular-nums\">\n ${selectedPackage.price.toLocaleString()}\n <span className=\"text-xs font-normal text-text-secondary\">\n /{selectedPackage.priceType}\n </span>\n </span>\n </div>\n\n <div className=\"space-y-2\">\n {/* No createCrewBooking mutation exists in the backend yet, so\n Book Now stays an honest disabled control — the panel is\n fully interactive but does not fake a booking. */}\n <Button\n className=\"w-full\"\n disabled\n title=\"Booking is coming soon\"\n aria-label=\"Book now — coming soon\"\n >\n Book Now · Coming soon\n </Button>\n <Button\n variant=\"outline\"\n className=\"w-full\"\n onClick={() => navigate('../marketplace/messaging-page')}\n >\n <MessageSquare className=\"mr-1 h-4 w-4\" />\n Message\n </Button>\n </div>\n\n <p className={`flex items-center justify-center gap-1.5 text-xs ${availability.className}`}>\n <AvailabilityIcon className=\"h-3.5 w-3.5\" />\n {availability.label}\n </p>\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}