@burdenoff/microfe-buildmyiq 2026.705.13 → 2026.706.10
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/buildmyiq/BuildmyiqRoot.d.ts.map +1 -1
- package/dist/buildmyiq/BuildmyiqRoot.js +57 -49
- package/dist/buildmyiq/BuildmyiqRoot.js.map +1 -1
- package/dist/buildmyiq/BuildmyiqRoutes.d.ts.map +1 -1
- package/dist/buildmyiq/BuildmyiqRoutes.js +15 -11
- package/dist/buildmyiq/BuildmyiqRoutes.js.map +1 -1
- package/dist/buildmyiq/components/Avatar.d.ts +15 -0
- package/dist/buildmyiq/components/Avatar.d.ts.map +1 -0
- package/dist/buildmyiq/components/Avatar.js +42 -0
- package/dist/buildmyiq/components/Avatar.js.map +1 -0
- package/dist/buildmyiq/components/Viz.d.ts +25 -0
- package/dist/buildmyiq/components/Viz.d.ts.map +1 -0
- package/dist/buildmyiq/components/Viz.js +78 -0
- package/dist/buildmyiq/components/Viz.js.map +1 -0
- package/dist/buildmyiq/components/index.d.ts +2 -0
- package/dist/buildmyiq/components/index.d.ts.map +1 -1
- package/dist/buildmyiq/components/index.js +2 -0
- package/dist/buildmyiq/pages/DashboardPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/DashboardPage.js +200 -98
- package/dist/buildmyiq/pages/DashboardPage.js.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js +262 -241
- package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/assessments/AssessmentsPage.js +142 -115
- package/dist/buildmyiq/pages/assessments/AssessmentsPage.js.map +1 -1
- package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.js +220 -156
- package/dist/buildmyiq/pages/assessments/TakeAssessmentPage.js.map +1 -1
- package/dist/buildmyiq/pages/authoring/AuthoringPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/authoring/AuthoringPage.js +51 -46
- package/dist/buildmyiq/pages/authoring/AuthoringPage.js.map +1 -1
- package/dist/buildmyiq/pages/authoring/CourseBuilderPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js +581 -448
- package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js.map +1 -1
- package/dist/buildmyiq/pages/catalog/CatalogPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/catalog/CatalogPage.js +52 -42
- package/dist/buildmyiq/pages/catalog/CatalogPage.js.map +1 -1
- package/dist/buildmyiq/pages/catalog/CourseDetailPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/catalog/CourseDetailPage.js +422 -301
- package/dist/buildmyiq/pages/catalog/CourseDetailPage.js.map +1 -1
- package/dist/buildmyiq/pages/certificates/CertificatesPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/certificates/CertificatesPage.js +237 -151
- package/dist/buildmyiq/pages/certificates/CertificatesPage.js.map +1 -1
- package/dist/buildmyiq/pages/cohorts/CohortsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/cohorts/CohortsPage.js +219 -138
- package/dist/buildmyiq/pages/cohorts/CohortsPage.js.map +1 -1
- package/dist/buildmyiq/pages/insights/InsightsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/insights/InsightsPage.js +276 -152
- package/dist/buildmyiq/pages/insights/InsightsPage.js.map +1 -1
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.js +237 -174
- package/dist/buildmyiq/pages/learning/LessonPlayerPage.js.map +1 -1
- package/dist/buildmyiq/pages/learning/MyLearningPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/learning/MyLearningPage.js +307 -169
- package/dist/buildmyiq/pages/learning/MyLearningPage.js.map +1 -1
- package/dist/buildmyiq/pages/paths/PathsPage.d.ts +4 -0
- package/dist/buildmyiq/pages/paths/PathsPage.d.ts.map +1 -0
- package/dist/buildmyiq/pages/paths/PathsPage.js +187 -0
- package/dist/buildmyiq/pages/paths/PathsPage.js.map +1 -0
- package/dist/buildmyiq/pages/skills/SkillsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/skills/SkillsPage.js +233 -140
- package/dist/buildmyiq/pages/skills/SkillsPage.js.map +1 -1
- package/dist/buildmyiq/pages/submissions/SubmissionsPage.d.ts.map +1 -1
- package/dist/buildmyiq/pages/submissions/SubmissionsPage.js +379 -275
- package/dist/buildmyiq/pages/submissions/SubmissionsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,230 +1,323 @@
|
|
|
1
1
|
import { PageLayout as e } from "../../components/PageLayout.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { useBuiCreateSkill as l, useBuiSkills as u } from "../../hooks/useBuildmyiqApi.js";
|
|
2
|
+
import { formatEnumLabel as t, formatRelativeTime as n } from "../../utils/formatters.js";
|
|
3
|
+
import { EmptyState as r } from "../../components/EmptyState.js";
|
|
4
|
+
import { ErrorView as i, LoadingView as a } from "../../components/StateViews.js";
|
|
5
|
+
import { FilterTabs as o } from "../../components/FilterTabs.js";
|
|
6
|
+
import { ProgressRing as s } from "../../components/Viz.js";
|
|
7
|
+
import { useBuiCreateSkill as c, useBuiSkills as l } from "../../hooks/useBuildmyiqApi.js";
|
|
9
8
|
import "../../hooks/index.js";
|
|
10
9
|
import "../../components/index.js";
|
|
11
|
-
import { SKILL_CATEGORIES as
|
|
12
|
-
import { useMemo as
|
|
13
|
-
import {
|
|
14
|
-
import { jsx as
|
|
15
|
-
import { Button as
|
|
10
|
+
import { SKILL_CATEGORIES as u } from "../../types/index.js";
|
|
11
|
+
import { useMemo as d, useState as f } from "react";
|
|
12
|
+
import { BarChart3 as p, Brain as m, Briefcase as h, Code2 as g, Languages as _, Palette as v, Plus as y, Sparkles as b, Users as x } from "lucide-react";
|
|
13
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
14
|
+
import { Button as w, GlassCard as T, Input as E, Label as D, ResponsiveDialog as O, ResponsiveDialogContent as k, ResponsiveDialogDescription as ee, ResponsiveDialogFooter as A, ResponsiveDialogHeader as j, ResponsiveDialogTitle as M, Select as N, SelectContent as P, SelectItem as F, SelectTrigger as I, SelectValue as L, Textarea as R } from "@burdenoff/fe-libs/ui";
|
|
16
15
|
//#region src/buildmyiq/pages/skills/SkillsPage.tsx
|
|
17
|
-
var
|
|
16
|
+
var z = [{
|
|
18
17
|
value: "ALL",
|
|
19
18
|
label: "All"
|
|
20
|
-
}, ...
|
|
19
|
+
}, ...u.map((e) => ({
|
|
21
20
|
value: e,
|
|
22
|
-
label:
|
|
23
|
-
}))],
|
|
21
|
+
label: t(e)
|
|
22
|
+
}))], B = {
|
|
23
|
+
TECHNICAL: {
|
|
24
|
+
icon: g,
|
|
25
|
+
color: "var(--color-accent-teal)"
|
|
26
|
+
},
|
|
27
|
+
BUSINESS: {
|
|
28
|
+
icon: h,
|
|
29
|
+
color: "var(--color-accent-blue)"
|
|
30
|
+
},
|
|
31
|
+
CREATIVE: {
|
|
32
|
+
icon: v,
|
|
33
|
+
color: "var(--color-status-warning-text)"
|
|
34
|
+
},
|
|
35
|
+
COGNITIVE: {
|
|
36
|
+
icon: m,
|
|
37
|
+
color: "var(--color-accent-purple)"
|
|
38
|
+
},
|
|
39
|
+
SOCIAL: {
|
|
40
|
+
icon: x,
|
|
41
|
+
color: "var(--color-status-success-text)"
|
|
42
|
+
},
|
|
43
|
+
LANGUAGE: {
|
|
44
|
+
icon: _,
|
|
45
|
+
color: "var(--color-accent-indigo)"
|
|
46
|
+
}
|
|
47
|
+
}, V = {
|
|
24
48
|
name: "",
|
|
25
49
|
category: "TECHNICAL",
|
|
26
50
|
description: ""
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
className: "
|
|
35
|
-
children:
|
|
36
|
-
}), /* @__PURE__ */ v(i, {
|
|
37
|
-
status: e.category,
|
|
38
|
-
className: "shrink-0"
|
|
39
|
-
})]
|
|
40
|
-
}),
|
|
41
|
-
e.description ? /* @__PURE__ */ v("p", {
|
|
42
|
-
className: "line-clamp-3 text-sm text-text-secondary",
|
|
43
|
-
children: e.description
|
|
44
|
-
}) : /* @__PURE__ */ v("p", {
|
|
45
|
-
className: "text-sm italic text-text-secondary/70",
|
|
46
|
-
children: "No description provided."
|
|
47
|
-
}),
|
|
48
|
-
/* @__PURE__ */ y("div", {
|
|
49
|
-
className: "mt-auto flex items-center justify-between gap-3 pt-2",
|
|
50
|
-
children: [/* @__PURE__ */ y("span", {
|
|
51
|
-
className: e.isActive ? "inline-flex items-center gap-1.5 text-xs font-medium text-status-success-text" : "inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary",
|
|
52
|
-
children: [/* @__PURE__ */ v("span", {
|
|
51
|
+
}, H = ({ skill: e }) => {
|
|
52
|
+
let r = B[e.category], i = r.icon;
|
|
53
|
+
return /* @__PURE__ */ C(T, {
|
|
54
|
+
treatment: "plain",
|
|
55
|
+
className: "flex flex-col gap-3 p-5",
|
|
56
|
+
children: [
|
|
57
|
+
/* @__PURE__ */ C("div", {
|
|
58
|
+
className: "flex items-start gap-3",
|
|
59
|
+
children: [/* @__PURE__ */ S("span", {
|
|
53
60
|
"aria-hidden": "true",
|
|
54
|
-
className:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-xl",
|
|
62
|
+
style: {
|
|
63
|
+
backgroundColor: `color-mix(in srgb, ${r.color} 15%, transparent)`,
|
|
64
|
+
color: r.color
|
|
65
|
+
},
|
|
66
|
+
children: /* @__PURE__ */ S(i, { className: "h-5 w-5" })
|
|
67
|
+
}), /* @__PURE__ */ C("div", {
|
|
68
|
+
className: "flex min-w-0 flex-1 items-start justify-between gap-2",
|
|
69
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
70
|
+
className: "min-w-0 break-words font-semibold leading-snug text-text-primary",
|
|
71
|
+
children: e.name
|
|
72
|
+
}), /* @__PURE__ */ S("span", {
|
|
73
|
+
className: "inline-flex shrink-0 items-center rounded-full border px-2.5 py-0.5 text-xs font-medium",
|
|
74
|
+
style: {
|
|
75
|
+
color: r.color,
|
|
76
|
+
borderColor: `color-mix(in srgb, ${r.color} 40%, transparent)`
|
|
77
|
+
},
|
|
78
|
+
children: t(e.category)
|
|
79
|
+
})]
|
|
80
|
+
})]
|
|
81
|
+
}),
|
|
82
|
+
e.description ? /* @__PURE__ */ S("p", {
|
|
83
|
+
className: "line-clamp-3 text-sm text-text-secondary",
|
|
84
|
+
children: e.description
|
|
85
|
+
}) : /* @__PURE__ */ S("p", {
|
|
86
|
+
className: "text-sm italic text-text-secondary/70",
|
|
87
|
+
children: "No description provided."
|
|
88
|
+
}),
|
|
89
|
+
/* @__PURE__ */ C("div", {
|
|
90
|
+
className: "mt-auto flex items-center justify-between gap-3 border-t border-border-seam/60 pt-3",
|
|
91
|
+
children: [/* @__PURE__ */ C("span", {
|
|
92
|
+
className: e.isActive ? "inline-flex items-center gap-1.5 text-xs font-medium text-status-success-text" : "inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary",
|
|
93
|
+
children: [/* @__PURE__ */ S("span", {
|
|
94
|
+
"aria-hidden": "true",
|
|
95
|
+
className: e.isActive ? "size-1.5 rounded-full bg-status-success-text" : "size-1.5 rounded-full bg-text-secondary"
|
|
96
|
+
}), e.isActive ? "Active" : "Inactive"]
|
|
97
|
+
}), /* @__PURE__ */ C("span", {
|
|
98
|
+
className: "text-xs text-text-tertiary",
|
|
99
|
+
children: ["Added ", n(e.createdAt)]
|
|
100
|
+
})]
|
|
101
|
+
})
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
}, U = () => {
|
|
105
|
+
let [n, m] = f("ALL"), [h, g] = f(!1), [_, v] = f(V), [x, B] = f(null), { data: U, isLoading: W, isError: G, refetch: K } = l(n === "ALL" ? void 0 : n), q = c(), J = d(() => U ?? [], [U]), Y = d(() => {
|
|
106
|
+
let e = J.length, t = J.filter((e) => e.isActive).length, n = e > 0 ? Math.round(t / e * 100) : 0;
|
|
65
107
|
return {
|
|
66
108
|
total: e,
|
|
67
109
|
active: t,
|
|
68
|
-
inactive: e - t
|
|
110
|
+
inactive: e - t,
|
|
111
|
+
activeRatio: n
|
|
69
112
|
};
|
|
70
|
-
}, [
|
|
71
|
-
V
|
|
113
|
+
}, [J]), X = n === "ALL" ? "Skills" : `${t(n)} skills`, Z = !W && !G && Y.total > 0, Q = () => {
|
|
114
|
+
v(V), B(null);
|
|
72
115
|
}, $ = () => {
|
|
73
|
-
|
|
116
|
+
g(!1), Q();
|
|
74
117
|
};
|
|
75
|
-
return /* @__PURE__ */
|
|
118
|
+
return /* @__PURE__ */ C(e, {
|
|
76
119
|
title: "Skills",
|
|
77
120
|
description: "The competency taxonomy your courses map to — organised by category.",
|
|
78
121
|
titleGradient: !0,
|
|
79
122
|
aurora: !0,
|
|
80
|
-
actions: /* @__PURE__ */
|
|
81
|
-
onClick: () =>
|
|
82
|
-
children: [/* @__PURE__ */
|
|
123
|
+
actions: /* @__PURE__ */ C(w, {
|
|
124
|
+
onClick: () => g(!0),
|
|
125
|
+
children: [/* @__PURE__ */ S(y, { className: "mr-1.5 h-4 w-4" }), " New skill"]
|
|
83
126
|
}),
|
|
84
|
-
children: [/* @__PURE__ */
|
|
127
|
+
children: [/* @__PURE__ */ C("div", {
|
|
85
128
|
className: "flex flex-col gap-6",
|
|
86
129
|
children: [
|
|
87
|
-
/* @__PURE__ */
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
130
|
+
Z && /* @__PURE__ */ C(T, {
|
|
131
|
+
treatment: "glass",
|
|
132
|
+
glow: !0,
|
|
133
|
+
className: "flex flex-col gap-4 p-5 sm:flex-row sm:items-center sm:justify-between",
|
|
134
|
+
children: [/* @__PURE__ */ C("div", {
|
|
135
|
+
className: "flex flex-wrap items-center gap-x-6 gap-y-3",
|
|
136
|
+
children: [
|
|
137
|
+
/* @__PURE__ */ C("div", {
|
|
138
|
+
className: "flex items-center gap-3",
|
|
139
|
+
children: [/* @__PURE__ */ S("span", {
|
|
140
|
+
className: "flex h-11 w-11 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-[var(--color-accent-primary)]",
|
|
141
|
+
children: /* @__PURE__ */ S(p, { className: "h-5 w-5" })
|
|
142
|
+
}), /* @__PURE__ */ C("span", {
|
|
143
|
+
className: "flex items-baseline gap-1.5",
|
|
144
|
+
children: [/* @__PURE__ */ S("span", {
|
|
145
|
+
className: "text-2xl font-bold tabular-nums text-text-primary",
|
|
146
|
+
children: Y.total
|
|
147
|
+
}), /* @__PURE__ */ S("span", {
|
|
148
|
+
className: "text-sm text-text-secondary",
|
|
149
|
+
children: X
|
|
150
|
+
})]
|
|
151
|
+
})]
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ S("span", {
|
|
154
|
+
"aria-hidden": "true",
|
|
155
|
+
className: "hidden h-8 w-px bg-border-seam sm:block"
|
|
156
|
+
}),
|
|
157
|
+
/* @__PURE__ */ C("span", {
|
|
158
|
+
className: "inline-flex items-center gap-2 text-sm",
|
|
159
|
+
children: [
|
|
160
|
+
/* @__PURE__ */ S("span", { className: "size-2 rounded-full bg-status-success-text" }),
|
|
161
|
+
/* @__PURE__ */ S("span", {
|
|
162
|
+
className: "text-lg font-semibold tabular-nums text-text-primary",
|
|
163
|
+
children: Y.active
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ S("span", {
|
|
166
|
+
className: "text-text-secondary",
|
|
167
|
+
children: "Active"
|
|
168
|
+
})
|
|
169
|
+
]
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ C("span", {
|
|
172
|
+
className: "inline-flex items-center gap-2 text-sm",
|
|
173
|
+
children: [
|
|
174
|
+
/* @__PURE__ */ S("span", { className: "size-2 rounded-full bg-text-tertiary" }),
|
|
175
|
+
/* @__PURE__ */ S("span", {
|
|
176
|
+
className: "text-lg font-semibold tabular-nums text-text-primary",
|
|
177
|
+
children: Y.inactive
|
|
178
|
+
}),
|
|
179
|
+
/* @__PURE__ */ S("span", {
|
|
180
|
+
className: "text-text-secondary",
|
|
181
|
+
children: "Inactive"
|
|
182
|
+
})
|
|
183
|
+
]
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
}), /* @__PURE__ */ C("div", {
|
|
187
|
+
className: "flex items-center gap-3 self-start sm:self-auto",
|
|
188
|
+
children: [/* @__PURE__ */ S(s, {
|
|
189
|
+
value: Y.activeRatio,
|
|
190
|
+
size: 52,
|
|
191
|
+
stroke: 5
|
|
192
|
+
}), /* @__PURE__ */ C("span", {
|
|
193
|
+
className: "text-xs leading-tight text-text-secondary",
|
|
194
|
+
children: [
|
|
195
|
+
"of the taxonomy",
|
|
196
|
+
/* @__PURE__ */ S("br", {}),
|
|
197
|
+
"is active"
|
|
198
|
+
]
|
|
199
|
+
})]
|
|
200
|
+
})]
|
|
108
201
|
}),
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
options:
|
|
111
|
-
value:
|
|
112
|
-
onChange:
|
|
202
|
+
/* @__PURE__ */ S(o, {
|
|
203
|
+
options: z,
|
|
204
|
+
value: n,
|
|
205
|
+
onChange: m
|
|
113
206
|
}),
|
|
114
|
-
|
|
207
|
+
W ? /* @__PURE__ */ S(a, { label: "Loading skills…" }) : G ? /* @__PURE__ */ S(i, {
|
|
115
208
|
title: "Couldn't load skills",
|
|
116
209
|
message: "The skills taxonomy failed to load.",
|
|
117
|
-
onRetry: () =>
|
|
118
|
-
}) :
|
|
210
|
+
onRetry: () => K()
|
|
211
|
+
}) : J.length === 0 ? /* @__PURE__ */ S(r, {
|
|
119
212
|
illustration: "empty-data",
|
|
120
|
-
icon: /* @__PURE__ */
|
|
121
|
-
title:
|
|
122
|
-
description:
|
|
123
|
-
action: /* @__PURE__ */
|
|
124
|
-
onClick: () =>
|
|
125
|
-
children: [/* @__PURE__ */
|
|
213
|
+
icon: /* @__PURE__ */ S(b, { className: "h-10 w-10" }),
|
|
214
|
+
title: n === "ALL" ? "No skills yet" : "No skills in this category",
|
|
215
|
+
description: n === "ALL" ? "Define the competencies your courses build. Skills let you organise the catalog and target learning outcomes." : "No skills are tagged with this category yet. Add one, or switch categories.",
|
|
216
|
+
action: /* @__PURE__ */ C(w, {
|
|
217
|
+
onClick: () => g(!0),
|
|
218
|
+
children: [/* @__PURE__ */ S(y, { className: "mr-1.5 h-4 w-4" }), " New skill"]
|
|
126
219
|
})
|
|
127
|
-
}) : /* @__PURE__ */
|
|
128
|
-
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3
|
|
129
|
-
children:
|
|
220
|
+
}) : /* @__PURE__ */ S("div", {
|
|
221
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
222
|
+
children: J.map((e) => /* @__PURE__ */ S(H, { skill: e }, e.id))
|
|
130
223
|
})
|
|
131
224
|
]
|
|
132
|
-
}), /* @__PURE__ */
|
|
133
|
-
open:
|
|
225
|
+
}), /* @__PURE__ */ S(O, {
|
|
226
|
+
open: h,
|
|
134
227
|
onOpenChange: (e) => {
|
|
135
|
-
e ?
|
|
228
|
+
e ? g(!0) : $();
|
|
136
229
|
},
|
|
137
|
-
children: /* @__PURE__ */
|
|
138
|
-
/* @__PURE__ */
|
|
139
|
-
/* @__PURE__ */
|
|
230
|
+
children: /* @__PURE__ */ C(k, { children: [
|
|
231
|
+
/* @__PURE__ */ C(j, { children: [/* @__PURE__ */ S(M, { children: "New skill" }), /* @__PURE__ */ S(ee, { children: "Add a competency to the taxonomy. Courses can then be mapped to it." })] }),
|
|
232
|
+
/* @__PURE__ */ C("div", {
|
|
140
233
|
className: "grid gap-4 py-2",
|
|
141
234
|
children: [
|
|
142
|
-
/* @__PURE__ */
|
|
235
|
+
/* @__PURE__ */ C("div", {
|
|
143
236
|
className: "grid gap-1.5",
|
|
144
|
-
children: [/* @__PURE__ */
|
|
237
|
+
children: [/* @__PURE__ */ S(D, {
|
|
145
238
|
htmlFor: "skill-name",
|
|
146
239
|
children: "Name *"
|
|
147
|
-
}), /* @__PURE__ */
|
|
240
|
+
}), /* @__PURE__ */ S(E, {
|
|
148
241
|
id: "skill-name",
|
|
149
|
-
value:
|
|
150
|
-
onChange: (e) =>
|
|
151
|
-
...
|
|
242
|
+
value: _.name,
|
|
243
|
+
onChange: (e) => v({
|
|
244
|
+
..._,
|
|
152
245
|
name: e.target.value
|
|
153
246
|
}),
|
|
154
247
|
placeholder: "e.g. Data Visualisation"
|
|
155
248
|
})]
|
|
156
249
|
}),
|
|
157
|
-
/* @__PURE__ */
|
|
250
|
+
/* @__PURE__ */ C("div", {
|
|
158
251
|
className: "grid gap-1.5",
|
|
159
|
-
children: [/* @__PURE__ */
|
|
252
|
+
children: [/* @__PURE__ */ S(D, {
|
|
160
253
|
htmlFor: "skill-category",
|
|
161
254
|
children: "Category"
|
|
162
|
-
}), /* @__PURE__ */
|
|
163
|
-
value:
|
|
164
|
-
onValueChange: (e) =>
|
|
165
|
-
...
|
|
255
|
+
}), /* @__PURE__ */ C(N, {
|
|
256
|
+
value: _.category,
|
|
257
|
+
onValueChange: (e) => v({
|
|
258
|
+
..._,
|
|
166
259
|
category: e
|
|
167
260
|
}),
|
|
168
|
-
children: [/* @__PURE__ */
|
|
261
|
+
children: [/* @__PURE__ */ S(I, {
|
|
169
262
|
id: "skill-category",
|
|
170
|
-
children: /* @__PURE__ */
|
|
171
|
-
}), /* @__PURE__ */
|
|
263
|
+
children: /* @__PURE__ */ S(L, {})
|
|
264
|
+
}), /* @__PURE__ */ S(P, { children: u.map((e) => /* @__PURE__ */ S(F, {
|
|
172
265
|
value: e,
|
|
173
|
-
children:
|
|
266
|
+
children: t(e)
|
|
174
267
|
}, e)) })]
|
|
175
268
|
})]
|
|
176
269
|
}),
|
|
177
|
-
/* @__PURE__ */
|
|
270
|
+
/* @__PURE__ */ C("div", {
|
|
178
271
|
className: "grid gap-1.5",
|
|
179
|
-
children: [/* @__PURE__ */
|
|
272
|
+
children: [/* @__PURE__ */ S(D, {
|
|
180
273
|
htmlFor: "skill-description",
|
|
181
274
|
children: "Description"
|
|
182
|
-
}), /* @__PURE__ */
|
|
275
|
+
}), /* @__PURE__ */ S(R, {
|
|
183
276
|
id: "skill-description",
|
|
184
|
-
value:
|
|
185
|
-
onChange: (e) =>
|
|
186
|
-
...
|
|
277
|
+
value: _.description,
|
|
278
|
+
onChange: (e) => v({
|
|
279
|
+
..._,
|
|
187
280
|
description: e.target.value
|
|
188
281
|
}),
|
|
189
282
|
placeholder: "Optional — what this competency covers and how it's assessed.",
|
|
190
283
|
rows: 3
|
|
191
284
|
})]
|
|
192
285
|
}),
|
|
193
|
-
|
|
286
|
+
x && /* @__PURE__ */ S("p", {
|
|
194
287
|
className: "text-sm text-status-error-text",
|
|
195
|
-
children:
|
|
288
|
+
children: x
|
|
196
289
|
})
|
|
197
290
|
]
|
|
198
291
|
}),
|
|
199
|
-
/* @__PURE__ */
|
|
292
|
+
/* @__PURE__ */ C(A, { children: [/* @__PURE__ */ S(w, {
|
|
200
293
|
variant: "outline",
|
|
201
294
|
onClick: $,
|
|
202
295
|
children: "Cancel"
|
|
203
|
-
}), /* @__PURE__ */
|
|
296
|
+
}), /* @__PURE__ */ S(w, {
|
|
204
297
|
onClick: async () => {
|
|
205
|
-
let e =
|
|
298
|
+
let e = _.name.trim();
|
|
206
299
|
if (!e) {
|
|
207
|
-
|
|
300
|
+
B("A skill name is required.");
|
|
208
301
|
return;
|
|
209
302
|
}
|
|
210
303
|
try {
|
|
211
|
-
await
|
|
304
|
+
await q.mutateAsync({
|
|
212
305
|
name: e,
|
|
213
|
-
category:
|
|
214
|
-
description:
|
|
306
|
+
category: _.category,
|
|
307
|
+
description: _.description.trim() || void 0
|
|
215
308
|
}), $();
|
|
216
309
|
} catch (e) {
|
|
217
|
-
|
|
310
|
+
B(e instanceof Error ? e.message : "Failed to create skill.");
|
|
218
311
|
}
|
|
219
312
|
},
|
|
220
|
-
disabled:
|
|
221
|
-
children:
|
|
313
|
+
disabled: q.isPending,
|
|
314
|
+
children: q.isPending ? "Creating…" : "Create skill"
|
|
222
315
|
})] })
|
|
223
316
|
] })
|
|
224
317
|
})]
|
|
225
318
|
});
|
|
226
319
|
};
|
|
227
320
|
//#endregion
|
|
228
|
-
export {
|
|
321
|
+
export { U as SkillsPage };
|
|
229
322
|
|
|
230
323
|
//# sourceMappingURL=SkillsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkillsPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/skills/SkillsPage.tsx"],"sourcesContent":["/**\n * SkillsPage — the workspace skills taxonomy.\n * @module buildmyiq/pages/skills\n *\n * The competency vocabulary that courses map to (`BuiCourse.skillId → BuiSkill`).\n * Reads the taxonomy via `useBuiSkills(category?)` — the category filter is applied\n * server-side — and writes new competencies via `useBuiCreateSkill`. A small KPI\n * summary (total / active / inactive) is derived from the loaded list, so it is\n * honest for whichever category is currently in view. Every tile renders REAL\n * `bui*` data; the empty state is honest.\n */\n\nimport { useMemo, useState } from 'react';\nimport type { FC } from 'react';\nimport { Plus, Sparkles, CheckCircle2, CircleSlash } from 'lucide-react';\nimport {\n Button,\n GlassCard,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n StatusBadge,\n FilterTabs,\n EmptyState,\n LoadingView,\n ErrorView,\n type FilterOption,\n} from '../../components';\nimport { useBuiSkills, useBuiCreateSkill } from '../../hooks';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport { SKILL_CATEGORIES } from '../../types';\nimport type { BuiSkill, BuiSkillCategory } from '../../types';\n\ntype CategoryFilter = BuiSkillCategory | 'ALL';\n\nconst CATEGORY_FILTERS: FilterOption<CategoryFilter>[] = [\n { value: 'ALL', label: 'All' },\n ...SKILL_CATEGORIES.map((c) => ({ value: c, label: formatEnumLabel(c) })),\n];\n\ninterface CreateFormState {\n name: string;\n category: BuiSkillCategory;\n description: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n name: '',\n category: 'TECHNICAL',\n description: '',\n};\n\n/** A single competency tile — name, category badge, description, active state. */\nconst SkillTile: FC<{ skill: BuiSkill }> = ({ skill }) => (\n <GlassCard treatment=\"plain\" className=\"flex flex-col gap-3 p-5\">\n <div className=\"flex items-start justify-between gap-3\">\n <h3 className=\"min-w-0 break-words font-semibold text-text-primary\">{skill.name}</h3>\n <StatusBadge status={skill.category} className=\"shrink-0\" />\n </div>\n\n {skill.description ? (\n <p className=\"line-clamp-3 text-sm text-text-secondary\">{skill.description}</p>\n ) : (\n <p className=\"text-sm italic text-text-secondary/70\">No description provided.</p>\n )}\n\n <div className=\"mt-auto flex items-center justify-between gap-3 pt-2\">\n <span\n className={\n skill.isActive\n ? 'inline-flex items-center gap-1.5 text-xs font-medium text-status-success-text'\n : 'inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary'\n }\n >\n <span\n aria-hidden=\"true\"\n className={\n skill.isActive\n ? 'size-1.5 rounded-full bg-status-success-text'\n : 'size-1.5 rounded-full bg-text-secondary'\n }\n />\n {skill.isActive ? 'Active' : 'Inactive'}\n </span>\n <span className=\"text-xs text-text-secondary\">\n Added {formatRelativeTime(skill.createdAt)}\n </span>\n </div>\n </GlassCard>\n);\n\nexport const SkillsPage: FC = () => {\n const [category, setCategory] = useState<CategoryFilter>('ALL');\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useBuiSkills(\n category === 'ALL' ? undefined : category\n );\n const createSkill = useBuiCreateSkill();\n\n const skills = useMemo<BuiSkill[]>(() => data ?? [], [data]);\n\n // KPIs are derived from the loaded (optionally category-filtered) list.\n const summary = useMemo(() => {\n const total = skills.length;\n const active = skills.filter((s) => s.isActive).length;\n return { total, active, inactive: total - active };\n }, [skills]);\n\n const scopeLabel = category === 'ALL' ? '' : ` · ${formatEnumLabel(category)}`;\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const closeDialog = () => {\n setDialogOpen(false);\n resetForm();\n };\n\n const handleCreate = async () => {\n const name = form.name.trim();\n if (!name) {\n setFormError('A skill name is required.');\n return;\n }\n try {\n await createSkill.mutateAsync({\n name,\n category: form.category,\n description: form.description.trim() || undefined,\n });\n closeDialog();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create skill.');\n }\n };\n\n return (\n <PageLayout\n title=\"Skills\"\n description=\"The competency taxonomy your courses map to — organised by category.\"\n titleGradient\n aurora\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New skill\n </Button>\n }\n >\n <div className=\"flex flex-col gap-6\">\n {/* KPI row — scoped to the loaded list. */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<Sparkles className=\"h-5 w-5\" />}\n value={summary.total}\n label={`Skills${scopeLabel}`}\n featured\n />\n <MetricsCard\n icon={<CheckCircle2 className=\"h-5 w-5\" />}\n value={summary.active}\n label=\"Active\"\n accent=\"success\"\n />\n <MetricsCard\n icon={<CircleSlash className=\"h-5 w-5\" />}\n value={summary.inactive}\n label=\"Inactive\"\n />\n </div>\n\n <FilterTabs options={CATEGORY_FILTERS} value={category} onChange={setCategory} />\n\n {isLoading ? (\n <LoadingView label=\"Loading skills…\" />\n ) : isError ? (\n <ErrorView\n title=\"Couldn't load skills\"\n message=\"The skills taxonomy failed to load.\"\n onRetry={() => refetch()}\n />\n ) : skills.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title={category === 'ALL' ? 'No skills yet' : 'No skills in this category'}\n description={\n category === 'ALL'\n ? 'Define the competencies your courses build. Skills let you organise the catalog and target learning outcomes.'\n : 'No skills are tagged with this category yet. Add one, or switch categories.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New skill\n </Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\">\n {skills.map((skill) => (\n <SkillTile key={skill.id} skill={skill} />\n ))}\n </div>\n )}\n </div>\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n if (open) setDialogOpen(true);\n else closeDialog();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New skill</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Add a competency to the taxonomy. Courses can then be mapped to it.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"skill-name\">Name *</Label>\n <Input\n id=\"skill-name\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n placeholder=\"e.g. Data Visualisation\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"skill-category\">Category</Label>\n <Select\n value={form.category}\n onValueChange={(v) => setForm({ ...form, category: v as BuiSkillCategory })}\n >\n <SelectTrigger id=\"skill-category\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SKILL_CATEGORIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"skill-description\">Description</Label>\n <Textarea\n id=\"skill-description\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Optional — what this competency covers and how it's assessed.\"\n rows={3}\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={closeDialog}>\n Cancel\n </Button>\n <Button onClick={handleCreate} disabled={createSkill.isPending}>\n {createSkill.isPending ? 'Creating…' : 'Create skill'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SkillsPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/skills/SkillsPage.tsx"],"sourcesContent":["/**\n * SkillsPage — the workspace skills taxonomy.\n * @module buildmyiq/pages/skills\n *\n * The competency vocabulary that courses map to (`BuiCourse.skillId → BuiSkill`).\n * Reads the taxonomy via `useBuiSkills(category?)` — the category filter is applied\n * server-side — and writes new competencies via `useBuiCreateSkill`. A small KPI\n * summary (total / active / inactive) is derived from the loaded list, so it is\n * honest for whichever category is currently in view. Every tile renders REAL\n * `bui*` data; the empty state is honest.\n */\n\nimport { useMemo, useState } from 'react';\nimport type { FC } from 'react';\nimport type { LucideIcon } from 'lucide-react';\nimport {\n Plus,\n Sparkles,\n BarChart3,\n Code2,\n Briefcase,\n Palette,\n Brain,\n Users,\n Languages,\n} from 'lucide-react';\nimport {\n Button,\n GlassCard,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n ProgressRing,\n FilterTabs,\n EmptyState,\n LoadingView,\n ErrorView,\n type FilterOption,\n} from '../../components';\nimport { useBuiSkills, useBuiCreateSkill } from '../../hooks';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport { SKILL_CATEGORIES } from '../../types';\nimport type { BuiSkill, BuiSkillCategory } from '../../types';\n\ntype CategoryFilter = BuiSkillCategory | 'ALL';\n\nconst CATEGORY_FILTERS: FilterOption<CategoryFilter>[] = [\n { value: 'ALL', label: 'All' },\n ...SKILL_CATEGORIES.map((c) => ({ value: c, label: formatEnumLabel(c) })),\n];\n\n/**\n * Per-category icon + semantic-token colour. Distinct hues drawn ONLY from the\n * Boff UI 2.0 accent/status palette (theme-safe in light + dark, no raw colours).\n */\nconst CATEGORY_VISUAL: Record<BuiSkillCategory, { icon: LucideIcon; color: string }> = {\n TECHNICAL: { icon: Code2, color: 'var(--color-accent-teal)' },\n BUSINESS: { icon: Briefcase, color: 'var(--color-accent-blue)' },\n CREATIVE: { icon: Palette, color: 'var(--color-status-warning-text)' },\n COGNITIVE: { icon: Brain, color: 'var(--color-accent-purple)' },\n SOCIAL: { icon: Users, color: 'var(--color-status-success-text)' },\n LANGUAGE: { icon: Languages, color: 'var(--color-accent-indigo)' },\n};\n\ninterface CreateFormState {\n name: string;\n category: BuiSkillCategory;\n description: string;\n}\n\nconst EMPTY_FORM: CreateFormState = {\n name: '',\n category: 'TECHNICAL',\n description: '',\n};\n\n/** A single competency tile — category-coloured icon, badge, description, state. */\nconst SkillTile: FC<{ skill: BuiSkill }> = ({ skill }) => {\n const visual = CATEGORY_VISUAL[skill.category];\n const Icon = visual.icon;\n return (\n <GlassCard treatment=\"plain\" className=\"flex flex-col gap-3 p-5\">\n <div className=\"flex items-start gap-3\">\n <span\n aria-hidden=\"true\"\n className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl\"\n style={{\n backgroundColor: `color-mix(in srgb, ${visual.color} 15%, transparent)`,\n color: visual.color,\n }}\n >\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"flex min-w-0 flex-1 items-start justify-between gap-2\">\n <h3 className=\"min-w-0 break-words font-semibold leading-snug text-text-primary\">\n {skill.name}\n </h3>\n <span\n className=\"inline-flex shrink-0 items-center rounded-full border px-2.5 py-0.5 text-xs font-medium\"\n style={{\n color: visual.color,\n borderColor: `color-mix(in srgb, ${visual.color} 40%, transparent)`,\n }}\n >\n {formatEnumLabel(skill.category)}\n </span>\n </div>\n </div>\n\n {skill.description ? (\n <p className=\"line-clamp-3 text-sm text-text-secondary\">{skill.description}</p>\n ) : (\n <p className=\"text-sm italic text-text-secondary/70\">No description provided.</p>\n )}\n\n <div className=\"mt-auto flex items-center justify-between gap-3 border-t border-border-seam/60 pt-3\">\n <span\n className={\n skill.isActive\n ? 'inline-flex items-center gap-1.5 text-xs font-medium text-status-success-text'\n : 'inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary'\n }\n >\n <span\n aria-hidden=\"true\"\n className={\n skill.isActive\n ? 'size-1.5 rounded-full bg-status-success-text'\n : 'size-1.5 rounded-full bg-text-secondary'\n }\n />\n {skill.isActive ? 'Active' : 'Inactive'}\n </span>\n <span className=\"text-xs text-text-tertiary\">Added {formatRelativeTime(skill.createdAt)}</span>\n </div>\n </GlassCard>\n );\n};\n\nexport const SkillsPage: FC = () => {\n const [category, setCategory] = useState<CategoryFilter>('ALL');\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<CreateFormState>(EMPTY_FORM);\n const [formError, setFormError] = useState<string | null>(null);\n\n const { data, isLoading, isError, refetch } = useBuiSkills(\n category === 'ALL' ? undefined : category\n );\n const createSkill = useBuiCreateSkill();\n\n const skills = useMemo<BuiSkill[]>(() => data ?? [], [data]);\n\n // KPIs are derived from the loaded (optionally category-filtered) list.\n const summary = useMemo(() => {\n const total = skills.length;\n const active = skills.filter((s) => s.isActive).length;\n const activeRatio = total > 0 ? Math.round((active / total) * 100) : 0;\n return { total, active, inactive: total - active, activeRatio };\n }, [skills]);\n\n const scopeLabel = category === 'ALL' ? 'Skills' : `${formatEnumLabel(category)} skills`;\n const showSummary = !isLoading && !isError && summary.total > 0;\n\n const resetForm = () => {\n setForm(EMPTY_FORM);\n setFormError(null);\n };\n\n const closeDialog = () => {\n setDialogOpen(false);\n resetForm();\n };\n\n const handleCreate = async () => {\n const name = form.name.trim();\n if (!name) {\n setFormError('A skill name is required.');\n return;\n }\n try {\n await createSkill.mutateAsync({\n name,\n category: form.category,\n description: form.description.trim() || undefined,\n });\n closeDialog();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to create skill.');\n }\n };\n\n return (\n <PageLayout\n title=\"Skills\"\n description=\"The competency taxonomy your courses map to — organised by category.\"\n titleGradient\n aurora\n actions={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New skill\n </Button>\n }\n >\n <div className=\"flex flex-col gap-6\">\n {/* Summary strip — scoped to the loaded list. */}\n {showSummary && (\n <GlassCard\n treatment=\"glass\"\n glow\n className=\"flex flex-col gap-4 p-5 sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"flex flex-wrap items-center gap-x-6 gap-y-3\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex h-11 w-11 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-[var(--color-accent-primary)]\">\n <BarChart3 className=\"h-5 w-5\" />\n </span>\n <span className=\"flex items-baseline gap-1.5\">\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {summary.total}\n </span>\n <span className=\"text-sm text-text-secondary\">{scopeLabel}</span>\n </span>\n </div>\n <span aria-hidden=\"true\" className=\"hidden h-8 w-px bg-border-seam sm:block\" />\n <span className=\"inline-flex items-center gap-2 text-sm\">\n <span className=\"size-2 rounded-full bg-status-success-text\" />\n <span className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {summary.active}\n </span>\n <span className=\"text-text-secondary\">Active</span>\n </span>\n <span className=\"inline-flex items-center gap-2 text-sm\">\n <span className=\"size-2 rounded-full bg-text-tertiary\" />\n <span className=\"text-lg font-semibold tabular-nums text-text-primary\">\n {summary.inactive}\n </span>\n <span className=\"text-text-secondary\">Inactive</span>\n </span>\n </div>\n <div className=\"flex items-center gap-3 self-start sm:self-auto\">\n <ProgressRing value={summary.activeRatio} size={52} stroke={5} />\n <span className=\"text-xs leading-tight text-text-secondary\">\n of the taxonomy\n <br />\n is active\n </span>\n </div>\n </GlassCard>\n )}\n\n <FilterTabs options={CATEGORY_FILTERS} value={category} onChange={setCategory} />\n\n {isLoading ? (\n <LoadingView label=\"Loading skills…\" />\n ) : isError ? (\n <ErrorView\n title=\"Couldn't load skills\"\n message=\"The skills taxonomy failed to load.\"\n onRetry={() => refetch()}\n />\n ) : skills.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Sparkles className=\"h-10 w-10\" />}\n title={category === 'ALL' ? 'No skills yet' : 'No skills in this category'}\n description={\n category === 'ALL'\n ? 'Define the competencies your courses build. Skills let you organise the catalog and target learning outcomes.'\n : 'No skills are tagged with this category yet. Add one, or switch categories.'\n }\n action={\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> New skill\n </Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {skills.map((skill) => (\n <SkillTile key={skill.id} skill={skill} />\n ))}\n </div>\n )}\n </div>\n\n <ResponsiveDialog\n open={dialogOpen}\n onOpenChange={(open) => {\n if (open) setDialogOpen(true);\n else closeDialog();\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New skill</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Add a competency to the taxonomy. Courses can then be mapped to it.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"grid gap-4 py-2\">\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"skill-name\">Name *</Label>\n <Input\n id=\"skill-name\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n placeholder=\"e.g. Data Visualisation\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"skill-category\">Category</Label>\n <Select\n value={form.category}\n onValueChange={(v) => setForm({ ...form, category: v as BuiSkillCategory })}\n >\n <SelectTrigger id=\"skill-category\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SKILL_CATEGORIES.map((c) => (\n <SelectItem key={c} value={c}>\n {formatEnumLabel(c)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"skill-description\">Description</Label>\n <Textarea\n id=\"skill-description\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n placeholder=\"Optional — what this competency covers and how it's assessed.\"\n rows={3}\n />\n </div>\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={closeDialog}>\n Cancel\n </Button>\n <Button onClick={handleCreate} disabled={createSkill.isPending}>\n {createSkill.isPending ? 'Creating…' : 'Create skill'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubmissionsPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/submissions/SubmissionsPage.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SubmissionsPage.d.ts","sourceRoot":"","sources":["../../../../src/buildmyiq/pages/submissions/SubmissionsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,EAAE,EAAa,MAAM,OAAO,CAAC;AA4H3C,eAAO,MAAM,eAAe,EAAE,EAgc7B,CAAC"}
|