@burdenoff/microfe-crewfoundry 2026.704.5 → 2026.704.7

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 (155) 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/HiringApplicationsPagePage.js +84 -75
  81. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  82. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
  83. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  84. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
  85. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  86. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
  87. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  88. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +252 -249
  89. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  90. package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
  91. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  92. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
  93. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  94. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
  95. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
  96. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
  97. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  98. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
  99. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  100. package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
  101. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  102. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
  103. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  104. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
  105. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  106. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +35 -31
  107. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  108. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
  109. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  110. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
  111. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  112. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +136 -133
  113. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  114. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
  115. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  116. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
  117. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  118. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
  119. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
  120. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  121. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  122. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  123. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  124. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  125. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +28 -25
  126. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
  127. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +290 -138
  128. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  129. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  130. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  131. package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
  132. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +65 -61
  133. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
  134. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  135. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  137. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  138. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +142 -76
  139. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  140. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  141. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  142. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
  143. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  144. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  145. package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
  146. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  147. package/dist/crewfoundry/utils/cn.js +10 -0
  148. package/dist/crewfoundry/utils/cn.js.map +1 -0
  149. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  150. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  151. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  152. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  153. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  154. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  155. package/package.json +1 -1
@@ -1,158 +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 } 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 y() {
8
- let y = s(), b = o(), { marketplaceServices: x } = e(), S = new URLSearchParams(b.search).get("id"), C = x.find((e) => e.id === S) ?? x[0];
9
- return C ? /* @__PURE__ */ l("div", {
10
- className: "space-y-6 p-6 max-w-4xl",
11
- children: [
12
- /* @__PURE__ */ l("div", {
13
- className: "flex items-center justify-between",
14
- children: [/* @__PURE__ */ l("div", { children: [
15
- /* @__PURE__ */ c("h1", {
16
- className: "text-2xl font-semibold",
17
- children: /* @__PURE__ */ c(h, { children: C.title })
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", {
33
+ className: "flex min-h-[60vh] items-center justify-center p-6",
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
+ })]
18
117
  }),
19
- /* @__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", {
20
123
  className: "text-sm text-text-secondary",
21
- children: ["by ", C.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
+ })]
22
170
  }),
23
- /* @__PURE__ */ c(v, {
24
- className: "mt-2",
25
- 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
+ }) })]
26
205
  })
27
- ] }), /* @__PURE__ */ l("div", {
28
- className: "flex gap-2",
29
- children: [/* @__PURE__ */ l(d, {
30
- variant: "outline",
31
- onClick: () => y("../marketplace/messaging-page"),
32
- children: [/* @__PURE__ */ c(r, { className: "h-4 w-4 mr-1" }), "Contact"]
33
- }), /* @__PURE__ */ c(d, {
34
- disabled: !0,
35
- title: "Hiring is coming soon",
36
- "aria-label": "Hire now — coming soon",
37
- children: "Hire Now · Coming soon"
38
- })]
39
- })]
40
- }),
41
- /* @__PURE__ */ c(_, {
42
- storageKey: "crewfoundry-service-details",
43
- steps: [
44
- {
45
- id: "contact",
46
- label: "Message the provider",
47
- description: "Ask questions before you commit to hiring.",
48
- icon: /* @__PURE__ */ c(r, { className: "h-4 w-4" }),
49
- onClick: () => y("../marketplace/messaging-page")
50
- },
51
- {
52
- id: "compare",
53
- label: "Compare other services",
54
- description: "Browse similar offerings on the marketplace.",
55
- icon: /* @__PURE__ */ c(a, { className: "h-4 w-4" }),
56
- onClick: () => y("../marketplace/marketplace-services-page")
57
- },
58
- {
59
- id: "bookings",
60
- label: "Manage your bookings",
61
- description: "Track engagements you have already arranged.",
62
- icon: /* @__PURE__ */ c(t, { className: "h-4 w-4" }),
63
- onClick: () => y("../marketplace/booking-management-page")
64
- }
65
206
  ]
66
- }),
67
- /* @__PURE__ */ l("div", {
68
- className: "grid gap-4 md:grid-cols-4",
69
- children: [
70
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
71
- 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",
72
216
  children: [
73
- /* @__PURE__ */ c(n, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
74
- /* @__PURE__ */ l("p", {
75
- className: "text-lg font-bold",
76
- children: ["$", C.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
+ })]
77
245
  }),
78
- /* @__PURE__ */ l("p", {
79
- className: "text-xs text-text-secondary",
80
- children: ["per ", C.priceType]
81
- })
82
- ]
83
- }) }),
84
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
85
- className: "p-4 text-center",
86
- children: [
87
- /* @__PURE__ */ c(i, { className: "h-5 w-5 mx-auto text-status-warning-text mb-1" }),
88
- /* @__PURE__ */ l("p", {
89
- className: "text-lg font-bold",
90
- children: [C.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
+ })]
91
263
  }),
92
- /* @__PURE__ */ l("p", {
93
- className: "text-xs text-text-secondary",
94
- children: [C.reviews, " reviews"]
95
- })
96
- ]
97
- }) }),
98
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
99
- className: "p-4 text-center",
100
- children: [
101
- /* @__PURE__ */ c(t, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
102
- /* @__PURE__ */ c("p", {
103
- className: "text-lg font-bold",
104
- children: C.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
+ })]
105
280
  }),
106
- /* @__PURE__ */ c("p", {
107
- className: "text-xs text-text-secondary",
108
- children: "Delivery"
109
- })
110
- ]
111
- }) }),
112
- /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(p, {
113
- className: "p-4 text-center",
114
- children: [
115
- /* @__PURE__ */ c(a, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
116
- /* @__PURE__ */ c("p", {
117
- className: "text-lg font-bold",
118
- children: C.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
+ })]
119
295
  }),
120
- /* @__PURE__ */ c("p", {
121
- className: "text-xs text-text-secondary",
122
- 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]
123
299
  })
124
300
  ]
125
- }) })
126
- ]
127
- }),
128
- /* @__PURE__ */ l(m, { children: [
129
- /* @__PURE__ */ c("div", {
130
- className: "mb-2 text-lg font-semibold",
131
- children: "About this Service"
132
- }),
133
- /* @__PURE__ */ c("p", {
134
- className: "text-sm text-text-secondary",
135
- children: C.description
136
- }),
137
- /* @__PURE__ */ c("div", {
138
- className: "flex flex-wrap gap-1 mt-3",
139
- children: C.skills.map((e) => /* @__PURE__ */ c(u, {
140
- variant: "outline",
141
- children: e
142
- }, e))
301
+ })]
143
302
  })
144
- ] })
145
- ]
146
- }) : /* @__PURE__ */ c("div", {
147
- className: "p-6",
148
- children: /* @__PURE__ */ c(g, {
149
- illustration: "empty-search",
150
- title: "Service not found",
151
- description: "This service is no longer available."
152
- })
303
+ })]
304
+ })]
153
305
  });
154
306
  }
155
307
  //#endregion
156
- export { y as MarketplaceServiceDetailsPagePage };
308
+ export { O as MarketplaceServiceDetailsPagePage };
157
309
 
158
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} 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 } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n const svc = marketplaceServices.find((s) => s.id === selectedId) ?? marketplaceServices[0];\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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"}