@burdenoff/microfe-crewfoundry 2026.704.2 → 2026.704.4
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/pages/AdminAdminPagePage.js +76 -75
- package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +118 -117
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +115 -114
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +105 -104
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js +52 -51
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +94 -93
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js +97 -96
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +68 -67
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js +96 -95
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +153 -152
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js +107 -106
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +77 -76
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +80 -79
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +102 -101
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +126 -125
- package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +64 -63
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +96 -95
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +127 -126
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js +118 -117
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +123 -122
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +77 -76
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +49 -48
- package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +62 -61
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +72 -71
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +70 -69
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +57 -56
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js +58 -57
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js +122 -121
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +70 -69
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +41 -40
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js +65 -64
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +75 -74
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +60 -59
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js +53 -52
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js +37 -36
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +126 -125
- package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +62 -61
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js +50 -49
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +72 -71
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +40 -39
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js +130 -129
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +60 -59
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/store/crewfoundryStore.js +177 -146
- package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
- package/dist/crewfoundry/utils/formatEnumLabel.js +8 -0
- package/dist/crewfoundry/utils/formatEnumLabel.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,114 +1,115 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { formatEnumLabel as t } from "../utils/formatEnumLabel.js";
|
|
3
|
+
import { useState as n } from "react";
|
|
4
|
+
import { BookOpen as r, CheckCircle as i, Clock as a, Star as o, Users as s } from "lucide-react";
|
|
5
|
+
import { useSearchParams as c } from "react-router-dom";
|
|
6
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
7
|
+
import { Badge as d, Button as f, Card as p, CardContent as m, EmphasisPanel as h, GradientText as g, IllustratedEmptyState as _, PagePurpose as v } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { useGlobalUi as y } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
8
9
|
//#region src/crewfoundry/pages/LearningLearningPathDetailPagePage.tsx
|
|
9
|
-
function
|
|
10
|
-
let [
|
|
11
|
-
if (!
|
|
10
|
+
function b() {
|
|
11
|
+
let [b] = c(), { learningPaths: x, courses: S, enrollCourse: C } = e(), { showToast: w } = y(), [T, E] = n(!1), D = b.get("id"), O = D ? x.find((e) => e.id === D) : x[0];
|
|
12
|
+
if (!O) return /* @__PURE__ */ l("div", {
|
|
12
13
|
className: "p-6",
|
|
13
|
-
children: /* @__PURE__ */
|
|
14
|
+
children: /* @__PURE__ */ l(_, {
|
|
14
15
|
illustration: "empty-search",
|
|
15
16
|
title: "No learning path found",
|
|
16
17
|
description: "This learning path is no longer available."
|
|
17
18
|
})
|
|
18
19
|
});
|
|
19
|
-
let
|
|
20
|
-
return /* @__PURE__ */
|
|
20
|
+
let k = S.filter((e) => O.courses.includes(e.id));
|
|
21
|
+
return /* @__PURE__ */ u("div", {
|
|
21
22
|
className: "space-y-6 p-6 max-w-4xl",
|
|
22
23
|
children: [
|
|
23
|
-
/* @__PURE__ */
|
|
24
|
+
/* @__PURE__ */ u("div", {
|
|
24
25
|
className: "flex items-center justify-between",
|
|
25
|
-
children: [/* @__PURE__ */
|
|
26
|
-
/* @__PURE__ */
|
|
26
|
+
children: [/* @__PURE__ */ u("div", { children: [
|
|
27
|
+
/* @__PURE__ */ l("h1", {
|
|
27
28
|
className: "text-2xl font-semibold",
|
|
28
|
-
children: /* @__PURE__ */
|
|
29
|
+
children: /* @__PURE__ */ l(g, { children: O.title })
|
|
29
30
|
}),
|
|
30
|
-
/* @__PURE__ */
|
|
31
|
+
/* @__PURE__ */ l("p", {
|
|
31
32
|
className: "text-sm text-text-secondary",
|
|
32
|
-
children:
|
|
33
|
+
children: O.description
|
|
33
34
|
}),
|
|
34
|
-
/* @__PURE__ */
|
|
35
|
+
/* @__PURE__ */ l(v, {
|
|
35
36
|
className: "mt-1",
|
|
36
37
|
children: "Follow a single learning path end-to-end — see its courses, your progress, and what to complete next to finish the journey."
|
|
37
38
|
})
|
|
38
|
-
] }), /* @__PURE__ */
|
|
39
|
+
] }), /* @__PURE__ */ l(f, {
|
|
39
40
|
onClick: async () => {
|
|
40
|
-
if (
|
|
41
|
-
|
|
41
|
+
if (k.length === 0) {
|
|
42
|
+
w("No courses in this path yet", "warning");
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
+
E(!0);
|
|
45
46
|
try {
|
|
46
|
-
for (let e of
|
|
47
|
-
|
|
47
|
+
for (let e of k) await C(e.id);
|
|
48
|
+
w(`Enrolled in ${k.length} course${k.length > 1 ? "s" : ""}`, "success");
|
|
48
49
|
} catch (e) {
|
|
49
|
-
|
|
50
|
+
w(e instanceof Error ? e.message : "Unable to enroll in path", "error");
|
|
50
51
|
} finally {
|
|
51
|
-
|
|
52
|
+
E(!1);
|
|
52
53
|
}
|
|
53
54
|
},
|
|
54
|
-
disabled:
|
|
55
|
-
children:
|
|
55
|
+
disabled: T,
|
|
56
|
+
children: T ? "Enrolling…" : "Enroll Now"
|
|
56
57
|
})]
|
|
57
58
|
}),
|
|
58
|
-
/* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ u("div", {
|
|
59
60
|
className: "grid gap-4 md:grid-cols-4",
|
|
60
61
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ l(p, { children: /* @__PURE__ */ u(m, {
|
|
62
63
|
className: "p-4 text-center",
|
|
63
64
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
65
|
-
/* @__PURE__ */
|
|
65
|
+
/* @__PURE__ */ l(r, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
66
|
+
/* @__PURE__ */ l("p", {
|
|
66
67
|
className: "text-lg font-bold",
|
|
67
|
-
children:
|
|
68
|
+
children: O.courses.length
|
|
68
69
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
70
|
+
/* @__PURE__ */ l("p", {
|
|
70
71
|
className: "text-xs text-text-secondary",
|
|
71
72
|
children: "Courses"
|
|
72
73
|
})
|
|
73
74
|
]
|
|
74
75
|
}) }),
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
+
/* @__PURE__ */ l(p, { children: /* @__PURE__ */ u(m, {
|
|
76
77
|
className: "p-4 text-center",
|
|
77
78
|
children: [
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
/* @__PURE__ */
|
|
79
|
+
/* @__PURE__ */ l(a, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
80
|
+
/* @__PURE__ */ l("p", {
|
|
80
81
|
className: "text-lg font-bold",
|
|
81
|
-
children:
|
|
82
|
+
children: O.duration
|
|
82
83
|
}),
|
|
83
|
-
/* @__PURE__ */
|
|
84
|
+
/* @__PURE__ */ l("p", {
|
|
84
85
|
className: "text-xs text-text-secondary",
|
|
85
86
|
children: "Duration"
|
|
86
87
|
})
|
|
87
88
|
]
|
|
88
89
|
}) }),
|
|
89
|
-
/* @__PURE__ */
|
|
90
|
+
/* @__PURE__ */ l(p, { children: /* @__PURE__ */ u(m, {
|
|
90
91
|
className: "p-4 text-center",
|
|
91
92
|
children: [
|
|
92
|
-
/* @__PURE__ */
|
|
93
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ l(s, { className: "h-5 w-5 mx-auto text-text-secondary mb-1" }),
|
|
94
|
+
/* @__PURE__ */ l("p", {
|
|
94
95
|
className: "text-lg font-bold",
|
|
95
|
-
children:
|
|
96
|
+
children: O.enrolled
|
|
96
97
|
}),
|
|
97
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ l("p", {
|
|
98
99
|
className: "text-xs text-text-secondary",
|
|
99
100
|
children: "Enrolled"
|
|
100
101
|
})
|
|
101
102
|
]
|
|
102
103
|
}) }),
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
+
/* @__PURE__ */ l(p, { children: /* @__PURE__ */ u(m, {
|
|
104
105
|
className: "p-4 text-center",
|
|
105
106
|
children: [
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
-
/* @__PURE__ */
|
|
107
|
+
/* @__PURE__ */ l(i, { className: "h-5 w-5 mx-auto text-status-success-text mb-1" }),
|
|
108
|
+
/* @__PURE__ */ u("p", {
|
|
108
109
|
className: "text-lg font-bold",
|
|
109
|
-
children: [
|
|
110
|
+
children: [O.completionRate, "%"]
|
|
110
111
|
}),
|
|
111
|
-
/* @__PURE__ */
|
|
112
|
+
/* @__PURE__ */ l("p", {
|
|
112
113
|
className: "text-xs text-text-secondary",
|
|
113
114
|
children: "Completion"
|
|
114
115
|
})
|
|
@@ -116,38 +117,38 @@ function y() {
|
|
|
116
117
|
}) })
|
|
117
118
|
]
|
|
118
119
|
}),
|
|
119
|
-
/* @__PURE__ */
|
|
120
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ u(h, { children: [
|
|
121
|
+
/* @__PURE__ */ l("div", {
|
|
121
122
|
className: "text-lg font-semibold",
|
|
122
123
|
children: "Courses in this Path"
|
|
123
124
|
}),
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ u("p", {
|
|
125
126
|
className: "mb-4 text-sm text-text-secondary",
|
|
126
127
|
children: [
|
|
127
|
-
|
|
128
|
+
k.length,
|
|
128
129
|
" courses · ",
|
|
129
|
-
|
|
130
|
+
O.level
|
|
130
131
|
]
|
|
131
132
|
}),
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ l("div", {
|
|
133
134
|
className: "space-y-3",
|
|
134
|
-
children:
|
|
135
|
+
children: k.length === 0 ? /* @__PURE__ */ l(_, {
|
|
135
136
|
illustration: "empty-generic",
|
|
136
137
|
title: "No courses in this path yet",
|
|
137
138
|
description: "Courses added to this path will appear here in order."
|
|
138
|
-
}) :
|
|
139
|
+
}) : k.map((e, n) => /* @__PURE__ */ u("div", {
|
|
139
140
|
className: "flex items-center gap-3 rounded border p-4",
|
|
140
141
|
children: [
|
|
141
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ l("div", {
|
|
142
143
|
className: "flex-shrink-0 w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center text-sm font-bold",
|
|
143
|
-
children:
|
|
144
|
+
children: n + 1
|
|
144
145
|
}),
|
|
145
|
-
/* @__PURE__ */
|
|
146
|
+
/* @__PURE__ */ u("div", {
|
|
146
147
|
className: "flex-1",
|
|
147
|
-
children: [/* @__PURE__ */
|
|
148
|
+
children: [/* @__PURE__ */ l("p", {
|
|
148
149
|
className: "text-sm font-medium",
|
|
149
150
|
children: e.title
|
|
150
|
-
}), /* @__PURE__ */
|
|
151
|
+
}), /* @__PURE__ */ u("p", {
|
|
151
152
|
className: "text-xs text-text-secondary",
|
|
152
153
|
children: [
|
|
153
154
|
e.instructor,
|
|
@@ -159,18 +160,18 @@ function y() {
|
|
|
159
160
|
]
|
|
160
161
|
})]
|
|
161
162
|
}),
|
|
162
|
-
/* @__PURE__ */
|
|
163
|
+
/* @__PURE__ */ u("div", {
|
|
163
164
|
className: "flex items-center gap-2",
|
|
164
|
-
children: [/* @__PURE__ */
|
|
165
|
+
children: [/* @__PURE__ */ u("div", {
|
|
165
166
|
className: "flex items-center gap-1",
|
|
166
|
-
children: [/* @__PURE__ */
|
|
167
|
+
children: [/* @__PURE__ */ l(o, { className: "h-3 w-3 text-status-warning-text" }), /* @__PURE__ */ l("span", {
|
|
167
168
|
className: "text-sm",
|
|
168
169
|
children: e.rating
|
|
169
170
|
})]
|
|
170
|
-
}), /* @__PURE__ */
|
|
171
|
+
}), /* @__PURE__ */ l(d, {
|
|
171
172
|
variant: e.level === "beginner" ? "secondary" : e.level === "intermediate" ? "default" : "destructive",
|
|
172
173
|
className: "text-[10px]",
|
|
173
|
-
children: e.level
|
|
174
|
+
children: t(e.level)
|
|
174
175
|
})]
|
|
175
176
|
})
|
|
176
177
|
]
|
|
@@ -181,6 +182,6 @@ function y() {
|
|
|
181
182
|
});
|
|
182
183
|
}
|
|
183
184
|
//#endregion
|
|
184
|
-
export {
|
|
185
|
+
export { b as LearningLearningPathDetailPagePage };
|
|
185
186
|
|
|
186
187
|
//# sourceMappingURL=LearningLearningPathDetailPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LearningLearningPathDetailPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningLearningPathDetailPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { BookOpen, CheckCircle, Clock, Star, Users } from 'lucide-react';\nimport { useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function LearningLearningPathDetailPagePage() {\n const [searchParams] = useSearchParams();\n const { learningPaths, courses, enrollCourse } = useCrewFoundryStore();\n const { showToast } = useGlobalUi();\n const [enrolling, setEnrolling] = useState(false);\n const pathId = searchParams.get('id');\n const path = pathId ? learningPaths.find((p) => p.id === pathId) : learningPaths[0];\n if (!path)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No learning path found\"\n description=\"This learning path is no longer available.\"\n />\n </div>\n );\n const pathCourses = courses.filter((c) => path.courses.includes(c.id));\n\n const handleEnroll = async () => {\n if (pathCourses.length === 0) {\n showToast('No courses in this path yet', 'warning');\n return;\n }\n setEnrolling(true);\n try {\n for (const course of pathCourses) {\n await enrollCourse(course.id);\n }\n showToast(\n `Enrolled in ${pathCourses.length} course${pathCourses.length > 1 ? 's' : ''}`,\n 'success'\n );\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to enroll in path', 'error');\n } finally {\n setEnrolling(false);\n }\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>{path.title}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{path.description}</p>\n <PagePurpose className=\"mt-1\">\n Follow a single learning path end-to-end — see its courses, your progress, and what to\n complete next to finish the journey.\n </PagePurpose>\n </div>\n <Button onClick={handleEnroll} disabled={enrolling}>\n {enrolling ? 'Enrolling…' : 'Enroll Now'}\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <BookOpen className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{path.courses.length}</p>\n <p className=\"text-xs text-text-secondary\">Courses</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\">{path.duration}</p>\n <p className=\"text-xs text-text-secondary\">Duration</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\">{path.enrolled}</p>\n <p className=\"text-xs text-text-secondary\">Enrolled</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <CheckCircle className=\"h-5 w-5 mx-auto text-status-success-text mb-1\" />\n <p className=\"text-lg font-bold\">{path.completionRate}%</p>\n <p className=\"text-xs text-text-secondary\">Completion</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"text-lg font-semibold\">Courses in this Path</div>\n <p className=\"mb-4 text-sm text-text-secondary\">\n {pathCourses.length} courses · {path.level}\n </p>\n <div className=\"space-y-3\">\n {pathCourses.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No courses in this path yet\"\n description=\"Courses added to this path will appear here in order.\"\n />\n ) : (\n pathCourses.map((course, idx) => (\n <div key={course.id} className=\"flex items-center gap-3 rounded border p-4\">\n <div className=\"flex-shrink-0 w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center text-sm font-bold\">\n {idx + 1}\n </div>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium\">{course.title}</p>\n <p className=\"text-xs text-text-secondary\">\n {course.instructor} · {course.duration} · {course.modules} modules\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n <span className=\"text-sm\">{course.rating}</span>\n </div>\n <Badge\n variant={\n course.level === 'beginner'\n ? 'secondary'\n : course.level === 'intermediate'\n ? 'default'\n : 'destructive'\n }\n className=\"text-[10px]\"\n >\n {course.level}\n </Badge>\n </div>\n </div>\n ))\n )}\n </div>\n </EmphasisPanel>\n </div>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"LearningLearningPathDetailPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningLearningPathDetailPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { BookOpen, CheckCircle, Clock, Star, Users } from 'lucide-react';\nimport { useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useGlobalUi } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nexport function LearningLearningPathDetailPagePage() {\n const [searchParams] = useSearchParams();\n const { learningPaths, courses, enrollCourse } = useCrewFoundryStore();\n const { showToast } = useGlobalUi();\n const [enrolling, setEnrolling] = useState(false);\n const pathId = searchParams.get('id');\n const path = pathId ? learningPaths.find((p) => p.id === pathId) : learningPaths[0];\n if (!path)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No learning path found\"\n description=\"This learning path is no longer available.\"\n />\n </div>\n );\n const pathCourses = courses.filter((c) => path.courses.includes(c.id));\n\n const handleEnroll = async () => {\n if (pathCourses.length === 0) {\n showToast('No courses in this path yet', 'warning');\n return;\n }\n setEnrolling(true);\n try {\n for (const course of pathCourses) {\n await enrollCourse(course.id);\n }\n showToast(\n `Enrolled in ${pathCourses.length} course${pathCourses.length > 1 ? 's' : ''}`,\n 'success'\n );\n } catch (error) {\n showToast(error instanceof Error ? error.message : 'Unable to enroll in path', 'error');\n } finally {\n setEnrolling(false);\n }\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>{path.title}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{path.description}</p>\n <PagePurpose className=\"mt-1\">\n Follow a single learning path end-to-end — see its courses, your progress, and what to\n complete next to finish the journey.\n </PagePurpose>\n </div>\n <Button onClick={handleEnroll} disabled={enrolling}>\n {enrolling ? 'Enrolling…' : 'Enroll Now'}\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <BookOpen className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{path.courses.length}</p>\n <p className=\"text-xs text-text-secondary\">Courses</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\">{path.duration}</p>\n <p className=\"text-xs text-text-secondary\">Duration</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\">{path.enrolled}</p>\n <p className=\"text-xs text-text-secondary\">Enrolled</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <CheckCircle className=\"h-5 w-5 mx-auto text-status-success-text mb-1\" />\n <p className=\"text-lg font-bold\">{path.completionRate}%</p>\n <p className=\"text-xs text-text-secondary\">Completion</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"text-lg font-semibold\">Courses in this Path</div>\n <p className=\"mb-4 text-sm text-text-secondary\">\n {pathCourses.length} courses · {path.level}\n </p>\n <div className=\"space-y-3\">\n {pathCourses.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No courses in this path yet\"\n description=\"Courses added to this path will appear here in order.\"\n />\n ) : (\n pathCourses.map((course, idx) => (\n <div key={course.id} className=\"flex items-center gap-3 rounded border p-4\">\n <div className=\"flex-shrink-0 w-8 h-8 rounded-full bg-action-primary-bg/10 flex items-center justify-center text-sm font-bold\">\n {idx + 1}\n </div>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium\">{course.title}</p>\n <p className=\"text-xs text-text-secondary\">\n {course.instructor} · {course.duration} · {course.modules} modules\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n <span className=\"text-sm\">{course.rating}</span>\n </div>\n <Badge\n variant={\n course.level === 'beginner'\n ? 'secondary'\n : course.level === 'intermediate'\n ? 'default'\n : 'destructive'\n }\n className=\"text-[10px]\"\n >\n {formatEnumLabel(course.level)}\n </Badge>\n </div>\n </div>\n ))\n )}\n </div>\n </EmphasisPanel>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { formatEnumLabel as t } from "../utils/formatEnumLabel.js";
|
|
3
|
+
import { FormModal as n, useFormModal as r } from "../components/forms/FormModal.js";
|
|
4
|
+
import { BookOpen as i, GraduationCap as a, Plus as o } from "lucide-react";
|
|
5
|
+
import { useNavigate as s } from "react-router-dom";
|
|
6
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
|
+
import { Badge as u, Button as d, CardContent as f, CardDescription as p, CardHeader as m, CardTitle as h, GlassCard as g, GradientText as _, IllustratedEmptyState as v, PagePurpose as y, Pagination as b } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { usePagination as x } from "@burdenoff/fe-libs/shared/hooks";
|
|
8
9
|
//#region src/crewfoundry/pages/LearningLearningPathsPagePage.tsx
|
|
9
|
-
var
|
|
10
|
+
var S = [
|
|
10
11
|
{
|
|
11
12
|
name: "title",
|
|
12
13
|
label: "Path Title",
|
|
@@ -49,90 +50,90 @@ var x = [
|
|
|
49
50
|
]
|
|
50
51
|
}
|
|
51
52
|
];
|
|
52
|
-
function
|
|
53
|
-
let { learningPaths:
|
|
54
|
-
return /* @__PURE__ */
|
|
53
|
+
function C() {
|
|
54
|
+
let { learningPaths: C, courses: w, addLearningPath: T } = e(), E = s(), D = r(), { page: O, pageSize: k, offset: A, setPage: j } = x({ initialPageSize: 9 }), M = C.slice(A, A + k), N = (e) => E(`../../learning/learning-path-detail-page?id=${encodeURIComponent(e)}`);
|
|
55
|
+
return /* @__PURE__ */ l("div", {
|
|
55
56
|
className: "space-y-6 p-6",
|
|
56
57
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
+
/* @__PURE__ */ l("div", {
|
|
58
59
|
className: "flex flex-wrap items-start justify-between gap-3",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
60
|
-
/* @__PURE__ */
|
|
60
|
+
children: [/* @__PURE__ */ l("div", { children: [
|
|
61
|
+
/* @__PURE__ */ c("h1", {
|
|
61
62
|
className: "text-2xl font-semibold",
|
|
62
|
-
children: /* @__PURE__ */
|
|
63
|
+
children: /* @__PURE__ */ c(_, { children: "Learning Paths" })
|
|
63
64
|
}),
|
|
64
|
-
/* @__PURE__ */
|
|
65
|
+
/* @__PURE__ */ c("p", {
|
|
65
66
|
className: "text-sm text-text-secondary",
|
|
66
67
|
children: "Structured learning journeys for career growth"
|
|
67
68
|
}),
|
|
68
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ c(y, {
|
|
69
70
|
className: "mt-1",
|
|
70
71
|
children: "Structured learning journeys that string courses together — follow a path to build toward a role or skill set step by step."
|
|
71
72
|
})
|
|
72
|
-
] }), /* @__PURE__ */
|
|
73
|
-
onClick: () =>
|
|
74
|
-
children: [/* @__PURE__ */
|
|
73
|
+
] }), /* @__PURE__ */ l(d, {
|
|
74
|
+
onClick: () => D.openModal(),
|
|
75
|
+
children: [/* @__PURE__ */ c(o, { className: "mr-1 h-4 w-4" }), "Create Path"]
|
|
75
76
|
})]
|
|
76
77
|
}),
|
|
77
|
-
/* @__PURE__ */
|
|
78
|
+
/* @__PURE__ */ c("div", {
|
|
78
79
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
|
|
79
|
-
children:
|
|
80
|
+
children: C.length === 0 ? /* @__PURE__ */ c("div", {
|
|
80
81
|
className: "col-span-full",
|
|
81
|
-
children: /* @__PURE__ */
|
|
82
|
+
children: /* @__PURE__ */ c(v, {
|
|
82
83
|
illustration: "empty-generic",
|
|
83
84
|
title: "No learning paths yet",
|
|
84
85
|
description: "Learning paths will appear here once they are created."
|
|
85
86
|
})
|
|
86
|
-
}) :
|
|
87
|
-
let
|
|
88
|
-
return /* @__PURE__ */
|
|
89
|
-
treatment:
|
|
90
|
-
glow:
|
|
87
|
+
}) : M.map((e, n) => {
|
|
88
|
+
let r = w.filter((t) => e.courses.includes(t.id));
|
|
89
|
+
return /* @__PURE__ */ l(g, {
|
|
90
|
+
treatment: n === 0 ? "glass" : "plain",
|
|
91
|
+
glow: n === 0,
|
|
91
92
|
role: "button",
|
|
92
93
|
tabIndex: 0,
|
|
93
94
|
"aria-label": `View ${e.title}`,
|
|
94
|
-
onClick: () =>
|
|
95
|
+
onClick: () => N(e.id),
|
|
95
96
|
onKeyDown: (t) => {
|
|
96
|
-
(t.key === "Enter" || t.key === " ") && (t.preventDefault(),
|
|
97
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), N(e.id));
|
|
97
98
|
},
|
|
98
99
|
className: "hover:shadow-md transition-shadow cursor-pointer focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]",
|
|
99
|
-
children: [/* @__PURE__ */
|
|
100
|
+
children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ c(h, {
|
|
100
101
|
className: "text-lg",
|
|
101
102
|
children: e.title
|
|
102
|
-
}), /* @__PURE__ */
|
|
103
|
+
}), /* @__PURE__ */ c(p, { children: e.description })] }), /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l("div", {
|
|
103
104
|
className: "space-y-3",
|
|
104
105
|
children: [
|
|
105
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ l("div", {
|
|
106
107
|
className: "flex items-center justify-between text-sm text-text-secondary",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ l("span", {
|
|
108
109
|
className: "flex items-center gap-1",
|
|
109
110
|
children: [
|
|
110
|
-
/* @__PURE__ */
|
|
111
|
+
/* @__PURE__ */ c(i, { className: "h-3 w-3" }),
|
|
111
112
|
e.courses.length,
|
|
112
113
|
" courses"
|
|
113
114
|
]
|
|
114
|
-
}), /* @__PURE__ */
|
|
115
|
+
}), /* @__PURE__ */ c("span", { children: e.duration })]
|
|
115
116
|
}),
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ c(u, {
|
|
117
118
|
variant: "outline",
|
|
118
119
|
className: "text-[10px]",
|
|
119
|
-
children: e.level
|
|
120
|
+
children: t(e.level)
|
|
120
121
|
}),
|
|
121
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ c("div", {
|
|
122
123
|
className: "space-y-1 mt-2",
|
|
123
|
-
children:
|
|
124
|
+
children: r.map((e) => /* @__PURE__ */ l("div", {
|
|
124
125
|
className: "flex items-center gap-2 text-xs text-text-secondary",
|
|
125
|
-
children: [/* @__PURE__ */
|
|
126
|
+
children: [/* @__PURE__ */ c(a, { className: "h-3 w-3" }), e.title]
|
|
126
127
|
}, e.id))
|
|
127
128
|
}),
|
|
128
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ l("div", {
|
|
129
130
|
className: "pt-2 border-t",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
131
|
+
children: [/* @__PURE__ */ l("div", {
|
|
131
132
|
className: "flex justify-between text-xs mb-1",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
133
|
-
}), /* @__PURE__ */
|
|
133
|
+
children: [/* @__PURE__ */ l("span", { children: [e.enrolled, " enrolled"] }), /* @__PURE__ */ l("span", { children: [e.completionRate, "%"] })]
|
|
134
|
+
}), /* @__PURE__ */ c("div", {
|
|
134
135
|
className: "h-2 bg-bg-sunken rounded overflow-hidden",
|
|
135
|
-
children: /* @__PURE__ */
|
|
136
|
+
children: /* @__PURE__ */ c("div", {
|
|
136
137
|
className: "h-2 bg-action-primary-bg rounded",
|
|
137
138
|
style: { width: `${e.completionRate}%` }
|
|
138
139
|
})
|
|
@@ -143,21 +144,21 @@ function S() {
|
|
|
143
144
|
}, e.id);
|
|
144
145
|
})
|
|
145
146
|
}),
|
|
146
|
-
|
|
147
|
-
page:
|
|
148
|
-
pageSize:
|
|
149
|
-
totalItems:
|
|
150
|
-
onPageChange:
|
|
147
|
+
C.length > k && /* @__PURE__ */ c(b, {
|
|
148
|
+
page: O,
|
|
149
|
+
pageSize: k,
|
|
150
|
+
totalItems: C.length,
|
|
151
|
+
onPageChange: j
|
|
151
152
|
}),
|
|
152
|
-
/* @__PURE__ */
|
|
153
|
-
open:
|
|
154
|
-
onOpenChange:
|
|
153
|
+
/* @__PURE__ */ c(n, {
|
|
154
|
+
open: D.open,
|
|
155
|
+
onOpenChange: D.onOpenChange,
|
|
155
156
|
title: "Create Learning Path",
|
|
156
157
|
description: "Group courses into a structured journey. You can add courses after creating the path.",
|
|
157
|
-
fields:
|
|
158
|
+
fields: S,
|
|
158
159
|
submitLabel: "Create Path",
|
|
159
160
|
onSubmit: async (e) => {
|
|
160
|
-
await
|
|
161
|
+
await T({
|
|
161
162
|
id: `path-${Date.now()}`,
|
|
162
163
|
title: String(e.title ?? ""),
|
|
163
164
|
description: String(e.description ?? ""),
|
|
@@ -173,6 +174,6 @@ function S() {
|
|
|
173
174
|
});
|
|
174
175
|
}
|
|
175
176
|
//#endregion
|
|
176
|
-
export {
|
|
177
|
+
export { C as LearningLearningPathsPagePage };
|
|
177
178
|
|
|
178
179
|
//# sourceMappingURL=LearningLearningPathsPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LearningLearningPathsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningLearningPathsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { BookOpen, GraduationCap, Plus } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type LearningPath } from '../store/crewfoundryStore';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\n\nconst PATH_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Path Title', type: 'text', required: true, colSpan: 2 },\n { name: 'description', label: 'Description', type: 'textarea', required: true, colSpan: 2 },\n {\n name: 'duration',\n label: 'Duration',\n type: 'text',\n required: true,\n placeholder: 'e.g. 3 months',\n },\n {\n name: 'level',\n label: 'Level',\n type: 'select',\n required: true,\n options: [\n { label: 'Beginner', value: 'beginner' },\n { label: 'Intermediate', value: 'intermediate' },\n { label: 'Advanced', value: 'advanced' },\n ],\n },\n];\n\nexport function LearningLearningPathsPagePage() {\n const { learningPaths, courses, addLearningPath } = useCrewFoundryStore();\n const navigate = useNavigate();\n const createModal = useFormModal();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n const pagedPaths = learningPaths.slice(offset, offset + pageSize);\n const openPath = (id: string) =>\n navigate(`../../learning/learning-path-detail-page?id=${encodeURIComponent(id)}`);\n\n const handleCreate = async (values: FormValues) => {\n const path: LearningPath = {\n id: `path-${Date.now()}`,\n title: String(values.title ?? ''),\n description: String(values.description ?? ''),\n courses: [],\n duration: String(values.duration ?? ''),\n level: String(values.level ?? 'beginner'),\n enrolled: 0,\n completionRate: 0,\n };\n await addLearningPath(path);\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Learning Paths</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Structured learning journeys for career growth\n </p>\n <PagePurpose className=\"mt-1\">\n Structured learning journeys that string courses together — follow a path to build\n toward a role or skill set step by step.\n </PagePurpose>\n </div>\n <Button onClick={() => createModal.openModal()}>\n <Plus className=\"mr-1 h-4 w-4\" />\n Create Path\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {learningPaths.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No learning paths yet\"\n description=\"Learning paths will appear here once they are created.\"\n />\n </div>\n ) : (\n pagedPaths.map((path, _idx) => {\n const pathCourses = courses.filter((c) => path.courses.includes(c.id));\n return (\n <GlassCard\n key={path.id}\n treatment={_idx === 0 ? 'glass' : 'plain'}\n glow={_idx === 0}\n role=\"button\"\n tabIndex={0}\n aria-label={`View ${path.title}`}\n onClick={() => openPath(path.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openPath(path.id);\n }\n }}\n className=\"hover:shadow-md transition-shadow cursor-pointer focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]\"\n >\n <CardHeader>\n <CardTitle className=\"text-lg\">{path.title}</CardTitle>\n <CardDescription>{path.description}</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <BookOpen className=\"h-3 w-3\" />\n {path.courses.length} courses\n </span>\n <span>{path.duration}</span>\n </div>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {path.level}\n </Badge>\n <div className=\"space-y-1 mt-2\">\n {pathCourses.map((c) => (\n <div\n key={c.id}\n className=\"flex items-center gap-2 text-xs text-text-secondary\"\n >\n <GraduationCap className=\"h-3 w-3\" />\n {c.title}\n </div>\n ))}\n </div>\n <div className=\"pt-2 border-t\">\n <div className=\"flex justify-between text-xs mb-1\">\n <span>{path.enrolled} enrolled</span>\n <span>{path.completionRate}%</span>\n </div>\n <div className=\"h-2 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-2 bg-action-primary-bg rounded\"\n style={{ width: `${path.completionRate}%` }}\n />\n </div>\n </div>\n </div>\n </CardContent>\n </GlassCard>\n );\n })\n )}\n </div>\n\n {learningPaths.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={learningPaths.length}\n onPageChange={setPage}\n />\n )}\n\n <FormModal\n open={createModal.open}\n onOpenChange={createModal.onOpenChange}\n title=\"Create Learning Path\"\n description=\"Group courses into a structured journey. You can add courses after creating the path.\"\n fields={PATH_FIELDS}\n submitLabel=\"Create Path\"\n onSubmit={handleCreate}\n />\n </div>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"LearningLearningPathsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/LearningLearningPathsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { BookOpen, GraduationCap, Plus } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type LearningPath } from '../store/crewfoundryStore';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nconst PATH_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Path Title', type: 'text', required: true, colSpan: 2 },\n { name: 'description', label: 'Description', type: 'textarea', required: true, colSpan: 2 },\n {\n name: 'duration',\n label: 'Duration',\n type: 'text',\n required: true,\n placeholder: 'e.g. 3 months',\n },\n {\n name: 'level',\n label: 'Level',\n type: 'select',\n required: true,\n options: [\n { label: 'Beginner', value: 'beginner' },\n { label: 'Intermediate', value: 'intermediate' },\n { label: 'Advanced', value: 'advanced' },\n ],\n },\n];\n\nexport function LearningLearningPathsPagePage() {\n const { learningPaths, courses, addLearningPath } = useCrewFoundryStore();\n const navigate = useNavigate();\n const createModal = useFormModal();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n const pagedPaths = learningPaths.slice(offset, offset + pageSize);\n const openPath = (id: string) =>\n navigate(`../../learning/learning-path-detail-page?id=${encodeURIComponent(id)}`);\n\n const handleCreate = async (values: FormValues) => {\n const path: LearningPath = {\n id: `path-${Date.now()}`,\n title: String(values.title ?? ''),\n description: String(values.description ?? ''),\n courses: [],\n duration: String(values.duration ?? ''),\n level: String(values.level ?? 'beginner'),\n enrolled: 0,\n completionRate: 0,\n };\n await addLearningPath(path);\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Learning Paths</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Structured learning journeys for career growth\n </p>\n <PagePurpose className=\"mt-1\">\n Structured learning journeys that string courses together — follow a path to build\n toward a role or skill set step by step.\n </PagePurpose>\n </div>\n <Button onClick={() => createModal.openModal()}>\n <Plus className=\"mr-1 h-4 w-4\" />\n Create Path\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {learningPaths.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No learning paths yet\"\n description=\"Learning paths will appear here once they are created.\"\n />\n </div>\n ) : (\n pagedPaths.map((path, _idx) => {\n const pathCourses = courses.filter((c) => path.courses.includes(c.id));\n return (\n <GlassCard\n key={path.id}\n treatment={_idx === 0 ? 'glass' : 'plain'}\n glow={_idx === 0}\n role=\"button\"\n tabIndex={0}\n aria-label={`View ${path.title}`}\n onClick={() => openPath(path.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openPath(path.id);\n }\n }}\n className=\"hover:shadow-md transition-shadow cursor-pointer focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus)]\"\n >\n <CardHeader>\n <CardTitle className=\"text-lg\">{path.title}</CardTitle>\n <CardDescription>{path.description}</CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <BookOpen className=\"h-3 w-3\" />\n {path.courses.length} courses\n </span>\n <span>{path.duration}</span>\n </div>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {formatEnumLabel(path.level)}\n </Badge>\n <div className=\"space-y-1 mt-2\">\n {pathCourses.map((c) => (\n <div\n key={c.id}\n className=\"flex items-center gap-2 text-xs text-text-secondary\"\n >\n <GraduationCap className=\"h-3 w-3\" />\n {c.title}\n </div>\n ))}\n </div>\n <div className=\"pt-2 border-t\">\n <div className=\"flex justify-between text-xs mb-1\">\n <span>{path.enrolled} enrolled</span>\n <span>{path.completionRate}%</span>\n </div>\n <div className=\"h-2 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-2 bg-action-primary-bg rounded\"\n style={{ width: `${path.completionRate}%` }}\n />\n </div>\n </div>\n </div>\n </CardContent>\n </GlassCard>\n );\n })\n )}\n </div>\n\n {learningPaths.length > pageSize && (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={learningPaths.length}\n onPageChange={setPage}\n />\n )}\n\n <FormModal\n open={createModal.open}\n onOpenChange={createModal.onOpenChange}\n title=\"Create Learning Path\"\n description=\"Group courses into a structured journey. You can add courses after creating the path.\"\n fields={PATH_FIELDS}\n submitLabel=\"Create Path\"\n onSubmit={handleCreate}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|