@burdenoff/microfe-crewfoundry 2026.704.6 → 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.
- package/dist/crewfoundry/CrewFoundryRoutes.js +51 -43
- package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
- package/dist/crewfoundry/components/forms/formValues.js +5 -2
- package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
- package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
- package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
- package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
- package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
- package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
- package/dist/crewfoundry/components/viz/BarChart.js +83 -0
- package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
- package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
- package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
- package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
- package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
- package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
- package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
- package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
- package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
- package/dist/crewfoundry/components/viz/LineChart.js +123 -0
- package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
- package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
- package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
- package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
- package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
- package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
- package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
- package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
- package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
- package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
- package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
- package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
- package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
- package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
- package/dist/crewfoundry/components/viz/StatCard.js +60 -0
- package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
- package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
- package/dist/crewfoundry/components/viz/Timeline.js +66 -0
- package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
- package/dist/crewfoundry/components/viz/index.js +23 -0
- package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
- package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
- package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
- package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/format.js +21 -0
- package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
- package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
- package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
- package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
- package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
- package/dist/crewfoundry/lib/analytics.js +323 -0
- package/dist/crewfoundry/lib/analytics.js.map +1 -0
- package/dist/crewfoundry/lib/companyFinance.js +16 -0
- package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +269 -270
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
- package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +134 -135
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +289 -140
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
- package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +140 -78
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/crewfoundry/utils/cn.js +10 -0
- package/dist/crewfoundry/utils/cn.js.map +1 -0
- package/dist/crewfoundry/utils/courseProgress.js +46 -0
- package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
- package/dist/node_modules/clsx/dist/clsx.js +18 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,172 +1,261 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { getInitials as t } from "../components/viz/lib/format.js";
|
|
3
|
+
import { RatingStars as n } from "../components/viz/RatingStars.js";
|
|
4
|
+
import { SegmentedTabs as r } from "../components/viz/SegmentedTabs.js";
|
|
5
|
+
import "../components/viz/index.js";
|
|
6
|
+
import { useEffect as i, useMemo as a, useState as o } from "react";
|
|
7
|
+
import { CheckCircle2 as s, Clock3 as c, PauseCircle as l, Search as u, ShoppingBag as d, Star as f, Users as p } from "lucide-react";
|
|
8
|
+
import { useNavigate as m } from "react-router-dom";
|
|
9
|
+
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
10
|
+
import { Button as _, CardContent as v, CardHeader as y, CardTitle as b, GlassCard as x, GradientText as S, IllustratedEmptyState as C, Input as w, PagePurpose as T, Pagination as E } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
import { usePagination as D } from "@burdenoff/fe-libs/shared/hooks";
|
|
12
|
+
import { useI18n as O } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
9
13
|
//#region src/crewfoundry/pages/MarketplaceMarketplacePagePage.tsx
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
function k(e) {
|
|
15
|
+
switch (e) {
|
|
16
|
+
case "active": return {
|
|
17
|
+
label: "Available",
|
|
18
|
+
icon: s,
|
|
19
|
+
className: "bg-status-success-bg text-status-success-text"
|
|
20
|
+
};
|
|
21
|
+
case "pending": return {
|
|
22
|
+
label: "Pending",
|
|
23
|
+
icon: c,
|
|
24
|
+
className: "bg-status-warning-bg text-status-warning-text"
|
|
25
|
+
};
|
|
26
|
+
default: return {
|
|
27
|
+
label: "Unavailable",
|
|
28
|
+
icon: l,
|
|
29
|
+
className: "bg-bg-sunken text-text-secondary"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function A() {
|
|
34
|
+
let { t: s } = O(), l = m(), { marketplaceServices: A } = e(), j = (e, t) => {
|
|
35
|
+
let n = s(e);
|
|
13
36
|
return n === e ? t : n;
|
|
14
|
-
}, { page:
|
|
15
|
-
|
|
37
|
+
}, { page: M, pageSize: N, offset: P, setPage: F } = D({ initialPageSize: 9 }), [I, L] = o(""), [R, z] = o("all"), B = a(() => {
|
|
38
|
+
let e = /* @__PURE__ */ new Map();
|
|
39
|
+
for (let t of A) e.set(t.category, (e.get(t.category) ?? 0) + 1);
|
|
40
|
+
let t = [{
|
|
41
|
+
id: "all",
|
|
42
|
+
label: "All",
|
|
43
|
+
count: A.length
|
|
44
|
+
}];
|
|
45
|
+
for (let [n, r] of [...e.entries()].sort((e, t) => e[0].localeCompare(t[0]))) t.push({
|
|
46
|
+
id: n,
|
|
47
|
+
label: n,
|
|
48
|
+
count: r
|
|
49
|
+
});
|
|
50
|
+
return t;
|
|
51
|
+
}, [A]), V = a(() => {
|
|
52
|
+
let e = I.trim().toLowerCase();
|
|
53
|
+
return A.filter((t) => R !== "all" && t.category !== R ? !1 : e ? `${t.title} ${t.provider} ${t.category} ${t.skills.join(" ")}`.toLowerCase().includes(e) : !0);
|
|
54
|
+
}, [
|
|
55
|
+
A,
|
|
56
|
+
I,
|
|
57
|
+
R
|
|
58
|
+
]);
|
|
59
|
+
i(() => {
|
|
60
|
+
F(1);
|
|
61
|
+
}, [
|
|
62
|
+
I,
|
|
63
|
+
R,
|
|
64
|
+
F
|
|
65
|
+
]);
|
|
66
|
+
let H = A.length > 0 ? (A.reduce((e, t) => e + t.rating, 0) / A.length).toFixed(1) : "0.0", U = A.reduce((e, t) => e + t.reviews, 0), W = V.slice(P, P + N), G = (e) => l(`../marketplace/service-details-page?id=${e}`);
|
|
67
|
+
return /* @__PURE__ */ g("div", {
|
|
16
68
|
className: "space-y-6 p-6",
|
|
17
69
|
children: [
|
|
18
|
-
/* @__PURE__ */
|
|
19
|
-
/* @__PURE__ */
|
|
70
|
+
/* @__PURE__ */ g("div", { children: [
|
|
71
|
+
/* @__PURE__ */ h("h1", {
|
|
20
72
|
className: "text-2xl font-semibold",
|
|
21
|
-
children: /* @__PURE__ */
|
|
73
|
+
children: /* @__PURE__ */ h(S, { children: j("crewfoundry.marketplace.title", "Talent Marketplace") })
|
|
22
74
|
}),
|
|
23
|
-
/* @__PURE__ */
|
|
75
|
+
/* @__PURE__ */ h("p", {
|
|
24
76
|
className: "text-sm text-text-secondary",
|
|
25
|
-
children:
|
|
77
|
+
children: j("crewfoundry.marketplace.subtitle", "Book vetted specialists and services")
|
|
26
78
|
}),
|
|
27
|
-
/* @__PURE__ */
|
|
79
|
+
/* @__PURE__ */ h(T, {
|
|
28
80
|
className: "mt-1",
|
|
29
|
-
children: "Discover freelancers and services for your projects —
|
|
81
|
+
children: "Discover freelancers and services for your projects — search, filter by category, and hire the right talent on demand."
|
|
30
82
|
})
|
|
31
83
|
] }),
|
|
32
|
-
/* @__PURE__ */
|
|
84
|
+
/* @__PURE__ */ g("div", {
|
|
33
85
|
className: "grid gap-4 md:grid-cols-3",
|
|
34
86
|
children: [
|
|
35
|
-
/* @__PURE__ */
|
|
87
|
+
/* @__PURE__ */ g(x, {
|
|
36
88
|
treatment: "glass",
|
|
37
89
|
glow: !0,
|
|
38
90
|
className: "border-border-seam",
|
|
39
|
-
children: [/* @__PURE__ */
|
|
91
|
+
children: [/* @__PURE__ */ g(y, {
|
|
40
92
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
41
|
-
children: [/* @__PURE__ */
|
|
93
|
+
children: [/* @__PURE__ */ h(b, {
|
|
42
94
|
className: "text-sm font-medium",
|
|
43
|
-
children:
|
|
44
|
-
}), /* @__PURE__ */
|
|
45
|
-
}), /* @__PURE__ */
|
|
95
|
+
children: j("crewfoundry.marketplace.stats.services", "Services")
|
|
96
|
+
}), /* @__PURE__ */ h(d, { className: "h-4 w-4 text-text-secondary" })]
|
|
97
|
+
}), /* @__PURE__ */ h(v, { children: /* @__PURE__ */ h("div", {
|
|
46
98
|
className: "text-2xl font-bold tabular-nums",
|
|
47
|
-
children:
|
|
99
|
+
children: A.length
|
|
48
100
|
}) })]
|
|
49
101
|
}),
|
|
50
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ g(x, {
|
|
51
103
|
treatment: "metric",
|
|
52
104
|
className: "border-border-seam",
|
|
53
|
-
children: [/* @__PURE__ */
|
|
105
|
+
children: [/* @__PURE__ */ g(y, {
|
|
54
106
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
55
|
-
children: [/* @__PURE__ */
|
|
107
|
+
children: [/* @__PURE__ */ h(b, {
|
|
56
108
|
className: "text-sm font-medium",
|
|
57
|
-
children:
|
|
58
|
-
}), /* @__PURE__ */
|
|
59
|
-
}), /* @__PURE__ */
|
|
109
|
+
children: j("crewfoundry.marketplace.stats.avgRating", "Avg Rating")
|
|
110
|
+
}), /* @__PURE__ */ h(f, { className: "h-4 w-4 text-status-warning-text" })]
|
|
111
|
+
}), /* @__PURE__ */ h(v, { children: /* @__PURE__ */ h("div", {
|
|
60
112
|
className: "text-2xl font-bold tabular-nums",
|
|
61
|
-
children:
|
|
113
|
+
children: H
|
|
62
114
|
}) })]
|
|
63
115
|
}),
|
|
64
|
-
/* @__PURE__ */
|
|
116
|
+
/* @__PURE__ */ g(x, {
|
|
65
117
|
treatment: "metric",
|
|
66
118
|
className: "border-border-seam",
|
|
67
|
-
children: [/* @__PURE__ */
|
|
119
|
+
children: [/* @__PURE__ */ g(y, {
|
|
68
120
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
121
|
+
children: [/* @__PURE__ */ h(b, {
|
|
70
122
|
className: "text-sm font-medium",
|
|
71
|
-
children:
|
|
72
|
-
}), /* @__PURE__ */
|
|
73
|
-
}), /* @__PURE__ */
|
|
123
|
+
children: j("crewfoundry.marketplace.stats.totalReviews", "Total Reviews")
|
|
124
|
+
}), /* @__PURE__ */ h(p, { className: "h-4 w-4 text-text-secondary" })]
|
|
125
|
+
}), /* @__PURE__ */ h(v, { children: /* @__PURE__ */ h("div", {
|
|
74
126
|
className: "text-2xl font-bold tabular-nums",
|
|
75
|
-
children:
|
|
127
|
+
children: U
|
|
76
128
|
}) })]
|
|
77
129
|
})
|
|
78
130
|
]
|
|
79
131
|
}),
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
-
className: "
|
|
82
|
-
children:
|
|
132
|
+
/* @__PURE__ */ g("div", {
|
|
133
|
+
className: "flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between",
|
|
134
|
+
children: [/* @__PURE__ */ g("div", {
|
|
135
|
+
className: "relative w-full max-w-sm",
|
|
136
|
+
children: [/* @__PURE__ */ h(u, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ h(w, {
|
|
137
|
+
placeholder: "Search services, providers, skills…",
|
|
138
|
+
className: "pl-9",
|
|
139
|
+
value: I,
|
|
140
|
+
onChange: (e) => L(e.target.value),
|
|
141
|
+
"aria-label": "Search marketplace services"
|
|
142
|
+
})]
|
|
143
|
+
}), /* @__PURE__ */ h("div", {
|
|
144
|
+
className: "-mx-1 overflow-x-auto px-1 pb-1",
|
|
145
|
+
children: /* @__PURE__ */ h(r, {
|
|
146
|
+
tabs: B,
|
|
147
|
+
value: R,
|
|
148
|
+
onChange: z,
|
|
149
|
+
"aria-label": "Filter services by category"
|
|
150
|
+
})
|
|
151
|
+
})]
|
|
83
152
|
}),
|
|
84
|
-
/* @__PURE__ */
|
|
153
|
+
W.length === 0 ? /* @__PURE__ */ h(C, {
|
|
154
|
+
illustration: "empty-search",
|
|
155
|
+
title: "No services found",
|
|
156
|
+
description: "Try a different search term or category to find the help you need."
|
|
157
|
+
}) : /* @__PURE__ */ h("div", {
|
|
85
158
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
|
|
86
|
-
children:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
className: "text-[10px]",
|
|
101
|
-
children: e.category
|
|
102
|
-
}), /* @__PURE__ */ o(c, {
|
|
103
|
-
variant: e.status === "active" ? "default" : "secondary",
|
|
104
|
-
className: "text-[10px]",
|
|
105
|
-
children: t(e.status)
|
|
106
|
-
})]
|
|
107
|
-
}),
|
|
108
|
-
/* @__PURE__ */ o(p, {
|
|
109
|
-
className: "text-base mt-2",
|
|
110
|
-
children: e.title
|
|
111
|
-
}),
|
|
112
|
-
/* @__PURE__ */ o(d, { children: e.provider })
|
|
113
|
-
] }), /* @__PURE__ */ s(u, { children: [
|
|
114
|
-
/* @__PURE__ */ o("p", {
|
|
115
|
-
className: "text-sm text-text-secondary mb-3",
|
|
116
|
-
children: e.description
|
|
117
|
-
}),
|
|
118
|
-
/* @__PURE__ */ o("div", {
|
|
119
|
-
className: "flex flex-wrap gap-1 mb-3",
|
|
120
|
-
children: e.skills.map((e) => /* @__PURE__ */ o(c, {
|
|
121
|
-
variant: "outline",
|
|
122
|
-
className: "text-[9px]",
|
|
123
|
-
children: e
|
|
124
|
-
}, e))
|
|
125
|
-
}),
|
|
126
|
-
/* @__PURE__ */ s("div", {
|
|
127
|
-
className: "flex items-center justify-between text-sm",
|
|
128
|
-
children: [/* @__PURE__ */ s("span", {
|
|
129
|
-
className: "font-bold",
|
|
130
|
-
children: [
|
|
131
|
-
"$",
|
|
132
|
-
e.price.toLocaleString(),
|
|
133
|
-
/* @__PURE__ */ s("span", {
|
|
134
|
-
className: "text-xs font-normal text-text-secondary",
|
|
135
|
-
children: ["/", e.priceType]
|
|
136
|
-
})
|
|
137
|
-
]
|
|
138
|
-
}), /* @__PURE__ */ s("span", {
|
|
139
|
-
className: "flex items-center gap-1",
|
|
140
|
-
children: [
|
|
141
|
-
/* @__PURE__ */ o(r, { className: "h-3 w-3 text-status-warning-text" }),
|
|
142
|
-
e.rating,
|
|
143
|
-
" (",
|
|
144
|
-
e.reviews,
|
|
145
|
-
")"
|
|
146
|
-
]
|
|
147
|
-
})]
|
|
148
|
-
}),
|
|
149
|
-
/* @__PURE__ */ s("p", {
|
|
150
|
-
className: "text-xs text-text-secondary mt-1",
|
|
159
|
+
children: W.map((e) => {
|
|
160
|
+
let r = k(e.status), i = r.icon;
|
|
161
|
+
return /* @__PURE__ */ h(x, {
|
|
162
|
+
treatment: "glass",
|
|
163
|
+
role: "button",
|
|
164
|
+
tabIndex: 0,
|
|
165
|
+
"aria-label": `View and book ${e.title} by ${e.provider}`,
|
|
166
|
+
onClick: () => G(e.id),
|
|
167
|
+
onKeyDown: (t) => {
|
|
168
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), G(e.id));
|
|
169
|
+
},
|
|
170
|
+
className: "cursor-pointer border-border-seam transition-shadow hover:shadow-elevation-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
171
|
+
children: /* @__PURE__ */ g(v, {
|
|
172
|
+
className: "flex h-full flex-col gap-3 p-4",
|
|
151
173
|
children: [
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
174
|
+
/* @__PURE__ */ g("div", {
|
|
175
|
+
className: "flex items-start justify-between gap-2",
|
|
176
|
+
children: [/* @__PURE__ */ g("div", {
|
|
177
|
+
className: "flex items-center gap-2.5",
|
|
178
|
+
children: [/* @__PURE__ */ h("span", {
|
|
179
|
+
className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-sm font-semibold text-action-primary-text",
|
|
180
|
+
"aria-hidden": "true",
|
|
181
|
+
children: t(e.provider)
|
|
182
|
+
}), /* @__PURE__ */ g("div", {
|
|
183
|
+
className: "min-w-0",
|
|
184
|
+
children: [/* @__PURE__ */ h("p", {
|
|
185
|
+
className: "truncate text-sm font-semibold",
|
|
186
|
+
children: e.provider
|
|
187
|
+
}), /* @__PURE__ */ h("span", {
|
|
188
|
+
className: "inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-[10px] text-text-secondary",
|
|
189
|
+
children: e.category
|
|
190
|
+
})]
|
|
191
|
+
})]
|
|
192
|
+
}), /* @__PURE__ */ g("div", {
|
|
193
|
+
className: "shrink-0 text-right",
|
|
194
|
+
children: [/* @__PURE__ */ g("p", {
|
|
195
|
+
className: "text-base font-bold tabular-nums",
|
|
196
|
+
children: ["$", e.price.toLocaleString()]
|
|
197
|
+
}), /* @__PURE__ */ g("p", {
|
|
198
|
+
className: "text-[10px] text-text-secondary",
|
|
199
|
+
children: ["/", e.priceType]
|
|
200
|
+
})]
|
|
201
|
+
})]
|
|
202
|
+
}),
|
|
203
|
+
/* @__PURE__ */ h("p", {
|
|
204
|
+
className: "text-sm font-medium",
|
|
205
|
+
children: e.title
|
|
206
|
+
}),
|
|
207
|
+
/* @__PURE__ */ g("div", {
|
|
208
|
+
className: "flex flex-wrap items-center gap-2",
|
|
209
|
+
children: [/* @__PURE__ */ h(n, {
|
|
210
|
+
value: e.rating,
|
|
211
|
+
count: e.reviews,
|
|
212
|
+
showValue: !0,
|
|
213
|
+
size: 14
|
|
214
|
+
}), /* @__PURE__ */ g("span", {
|
|
215
|
+
className: `inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium ${r.className}`,
|
|
216
|
+
children: [/* @__PURE__ */ h(i, { className: "h-3 w-3" }), r.label]
|
|
217
|
+
})]
|
|
218
|
+
}),
|
|
219
|
+
/* @__PURE__ */ h("p", {
|
|
220
|
+
className: "line-clamp-2 text-xs text-text-secondary",
|
|
221
|
+
children: e.description
|
|
222
|
+
}),
|
|
223
|
+
/* @__PURE__ */ h("div", {
|
|
224
|
+
className: "flex flex-wrap gap-1",
|
|
225
|
+
children: e.skills.slice(0, 4).map((e) => /* @__PURE__ */ h("span", {
|
|
226
|
+
className: "rounded-full bg-bg-sunken px-2 py-0.5 text-[10px] text-text-secondary",
|
|
227
|
+
children: e
|
|
228
|
+
}, e))
|
|
229
|
+
}),
|
|
230
|
+
/* @__PURE__ */ h("div", {
|
|
231
|
+
className: "mt-auto flex items-center justify-between pt-1 text-[11px] text-text-secondary",
|
|
232
|
+
children: /* @__PURE__ */ g("span", {
|
|
233
|
+
className: "flex items-center gap-1",
|
|
234
|
+
children: [/* @__PURE__ */ h(c, { className: "h-3 w-3" }), e.deliveryTime]
|
|
235
|
+
})
|
|
236
|
+
}),
|
|
237
|
+
/* @__PURE__ */ h(_, {
|
|
238
|
+
className: "w-full",
|
|
239
|
+
onClick: (t) => {
|
|
240
|
+
t.stopPropagation(), G(e.id);
|
|
241
|
+
},
|
|
242
|
+
children: j("crewfoundry.marketplace.card.book", "View & Book")
|
|
243
|
+
})
|
|
155
244
|
]
|
|
156
245
|
})
|
|
157
|
-
|
|
158
|
-
}
|
|
246
|
+
}, e.id);
|
|
247
|
+
})
|
|
159
248
|
}),
|
|
160
|
-
/* @__PURE__ */
|
|
161
|
-
page:
|
|
162
|
-
pageSize:
|
|
163
|
-
totalItems:
|
|
164
|
-
onPageChange:
|
|
165
|
-
})
|
|
249
|
+
V.length > N ? /* @__PURE__ */ h(E, {
|
|
250
|
+
page: M,
|
|
251
|
+
pageSize: N,
|
|
252
|
+
totalItems: V.length,
|
|
253
|
+
onPageChange: F
|
|
254
|
+
}) : null
|
|
166
255
|
]
|
|
167
256
|
});
|
|
168
257
|
}
|
|
169
258
|
//#endregion
|
|
170
|
-
export {
|
|
259
|
+
export { A as MarketplaceMarketplacePagePage };
|
|
171
260
|
|
|
172
261
|
//# sourceMappingURL=MarketplaceMarketplacePagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceMarketplacePagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMarketplacePagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { ShoppingBag, Star, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nexport function MarketplaceMarketplacePagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { marketplaceServices } = useCrewFoundryStore();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n const avgRating =\n marketplaceServices.length > 0\n ? (\n marketplaceServices.reduce((s, m) => s + m.rating, 0) / marketplaceServices.length\n ).toFixed(1)\n : '0.0';\n const pagedServices = marketplaceServices.slice(offset, offset + pageSize);\n const openService = (id: string) => navigate(`../marketplace/service-details-page?id=${id}`);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>\n {t('crewfoundry.marketplace.title', 'HR Services Marketplace')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t('crewfoundry.marketplace.subtitle', 'Find and hire professional HR service providers')}\n </p>\n <PagePurpose className=\"mt-1\">\n Discover freelancers and services for your projects — browse the marketplace to find and\n hire the right talent on demand.\n </PagePurpose>\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\">\n {t('crewfoundry.marketplace.stats.services', 'Services')}\n </CardTitle>\n <ShoppingBag className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{marketplaceServices.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\">\n {t('crewfoundry.marketplace.stats.avgRating', 'Avg Rating')}\n </CardTitle>\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}</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\">\n {t('crewfoundry.marketplace.stats.totalReviews', 'Total Reviews')}\n </CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {marketplaceServices.reduce((s, m) => s + m.reviews, 0)}\n </div>\n </CardContent>\n </GlassCard>\n </div>\n <h2 className=\"text-lg font-medium\">\n {t('crewfoundry.marketplace.featured.title', 'Featured Services')}\n </h2>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {pagedServices.map((svc) => (\n <Card\n key={svc.id}\n role=\"button\"\n tabIndex={0}\n aria-label={`View details for ${svc.title}`}\n onClick={() => openService(svc.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n openService(svc.id);\n }\n }}\n className=\"hover:shadow-md transition-shadow cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg\"\n >\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {svc.category}\n </Badge>\n <Badge\n variant={svc.status === 'active' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {formatEnumLabel(svc.status)}\n </Badge>\n </div>\n <CardTitle className=\"text-base mt-2\">{svc.title}</CardTitle>\n <CardDescription>{svc.provider}</CardDescription>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary mb-3\">{svc.description}</p>\n <div className=\"flex flex-wrap gap-1 mb-3\">\n {svc.skills.map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-[9px]\">\n {s}\n </Badge>\n ))}\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-bold\">\n ${svc.price.toLocaleString()}\n <span className=\"text-xs font-normal text-text-secondary\">/{svc.priceType}</span>\n </span>\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {svc.rating} ({svc.reviews})\n </span>\n </div>\n <p className=\"text-xs text-text-secondary mt-1\">\n {t('crewfoundry.marketplace.card.delivery', 'Delivery')}: {svc.deliveryTime}\n </p>\n </CardContent>\n </Card>\n ))}\n </div>\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={marketplaceServices.length}\n onPageChange={setPage}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MarketplaceMarketplacePagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMarketplacePagePage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport {\n Button,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { CheckCircle2, Clock3, PauseCircle, Search, ShoppingBag, Star, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type MarketplaceService } from '../store/crewfoundryStore';\nimport { RatingStars, SegmentedTabs, getInitials, type SegmentedTab } 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',\n icon: CheckCircle2,\n className: 'bg-status-success-bg text-status-success-text',\n };\n case 'pending':\n return {\n label: 'Pending',\n icon: Clock3,\n className: 'bg-status-warning-bg text-status-warning-text',\n };\n default:\n return {\n label: 'Unavailable',\n icon: PauseCircle,\n className: 'bg-bg-sunken text-text-secondary',\n };\n }\n}\n\nexport function MarketplaceMarketplacePagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { marketplaceServices } = useCrewFoundryStore();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n const [search, setSearch] = useState('');\n const [category, setCategory] = useState('all');\n\n const categoryTabs = useMemo<SegmentedTab[]>(() => {\n const counts = new Map<string, number>();\n for (const svc of marketplaceServices) {\n counts.set(svc.category, (counts.get(svc.category) ?? 0) + 1);\n }\n const tabs: SegmentedTab[] = [{ id: 'all', label: 'All', count: marketplaceServices.length }];\n for (const [name, count] of [...counts.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {\n tabs.push({ id: name, label: name, count });\n }\n return tabs;\n }, [marketplaceServices]);\n\n const filtered = useMemo(() => {\n const query = search.trim().toLowerCase();\n return marketplaceServices.filter((svc) => {\n if (category !== 'all' && svc.category !== category) {\n return false;\n }\n if (!query) {\n return true;\n }\n return `${svc.title} ${svc.provider} ${svc.category} ${svc.skills.join(' ')}`\n .toLowerCase()\n .includes(query);\n });\n }, [marketplaceServices, search, category]);\n\n useEffect(() => {\n setPage(1);\n }, [search, category, setPage]);\n\n const avgRating =\n marketplaceServices.length > 0\n ? (\n marketplaceServices.reduce((s, m) => s + m.rating, 0) / marketplaceServices.length\n ).toFixed(1)\n : '0.0';\n const totalReviews = marketplaceServices.reduce((s, m) => s + m.reviews, 0);\n const pagedServices = filtered.slice(offset, offset + pageSize);\n const openService = (id: string) => navigate(`../marketplace/service-details-page?id=${id}`);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{t('crewfoundry.marketplace.title', 'Talent Marketplace')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t('crewfoundry.marketplace.subtitle', 'Book vetted specialists and services')}\n </p>\n <PagePurpose className=\"mt-1\">\n Discover freelancers and services for your projects — search, filter by category, and hire\n the right talent on demand.\n </PagePurpose>\n </div>\n\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\">\n {t('crewfoundry.marketplace.stats.services', 'Services')}\n </CardTitle>\n <ShoppingBag className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{marketplaceServices.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\">\n {t('crewfoundry.marketplace.stats.avgRating', 'Avg Rating')}\n </CardTitle>\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}</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\">\n {t('crewfoundry.marketplace.stats.totalReviews', 'Total Reviews')}\n </CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{totalReviews}</div>\n </CardContent>\n </GlassCard>\n </div>\n\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"relative w-full max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search services, providers, skills…\"\n className=\"pl-9\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n aria-label=\"Search marketplace services\"\n />\n </div>\n <div className=\"-mx-1 overflow-x-auto px-1 pb-1\">\n <SegmentedTabs\n tabs={categoryTabs}\n value={category}\n onChange={setCategory}\n aria-label=\"Filter services by category\"\n />\n </div>\n </div>\n\n {pagedServices.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No services found\"\n description=\"Try a different search term or category to find the help you need.\"\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {pagedServices.map((svc) => {\n const availability = availabilityOf(svc.status);\n const AvailabilityIcon = availability.icon;\n return (\n <GlassCard\n key={svc.id}\n treatment=\"glass\"\n role=\"button\"\n tabIndex={0}\n aria-label={`View and book ${svc.title} by ${svc.provider}`}\n onClick={() => openService(svc.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n openService(svc.id);\n }\n }}\n className=\"cursor-pointer border-border-seam transition-shadow hover:shadow-elevation-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <CardContent className=\"flex h-full flex-col gap-3 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2.5\">\n <span\n className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-sm font-semibold text-action-primary-text\"\n aria-hidden=\"true\"\n >\n {getInitials(svc.provider)}\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold\">{svc.provider}</p>\n <span className=\"inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-[10px] text-text-secondary\">\n {svc.category}\n </span>\n </div>\n </div>\n <div className=\"shrink-0 text-right\">\n <p className=\"text-base font-bold tabular-nums\">${svc.price.toLocaleString()}</p>\n <p className=\"text-[10px] text-text-secondary\">/{svc.priceType}</p>\n </div>\n </div>\n\n <p className=\"text-sm font-medium\">{svc.title}</p>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <RatingStars value={svc.rating} count={svc.reviews} showValue size={14} />\n <span\n className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium ${availability.className}`}\n >\n <AvailabilityIcon className=\"h-3 w-3\" />\n {availability.label}\n </span>\n </div>\n\n <p className=\"line-clamp-2 text-xs text-text-secondary\">{svc.description}</p>\n\n <div className=\"flex flex-wrap gap-1\">\n {svc.skills.slice(0, 4).map((skill) => (\n <span\n key={skill}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-[10px] text-text-secondary\"\n >\n {skill}\n </span>\n ))}\n </div>\n\n <div className=\"mt-auto flex items-center justify-between pt-1 text-[11px] text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Clock3 className=\"h-3 w-3\" />\n {svc.deliveryTime}\n </span>\n </div>\n\n <Button\n className=\"w-full\"\n onClick={(event) => {\n event.stopPropagation();\n openService(svc.id);\n }}\n >\n {t('crewfoundry.marketplace.card.book', 'View & Book')}\n </Button>\n </CardContent>\n </GlassCard>\n );\n })}\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 ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|