@burdenoff/microfe-technospam 2026.704.2 → 2026.705.2
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/technospam/api/technospamApi.js +233 -150
- package/dist/technospam/api/technospamApi.js.map +1 -1
- package/dist/technospam/components/LoadMore.js +18 -2
- package/dist/technospam/components/LoadMore.js.map +1 -0
- package/dist/technospam/components/MediaCover.js +57 -0
- package/dist/technospam/components/MediaCover.js.map +1 -0
- package/dist/technospam/components/PageLayout.js +1 -1
- package/dist/technospam/components/PageLayout.js.map +1 -1
- package/dist/technospam/components/StatCard.js +19 -11
- package/dist/technospam/components/StatCard.js.map +1 -1
- package/dist/technospam/components/StatusBadge.js +1 -1
- package/dist/technospam/components/StatusBadge.js.map +1 -1
- package/dist/technospam/components/index.js +1 -0
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js +748 -352
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +167 -127
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +178 -125
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +89 -93
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +295 -141
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +86 -86
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesMyLearningPagePage.js +122 -88
- package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
- package/dist/technospam/pages/DashboardDashboardPagePage.js +232 -199
- package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +128 -106
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +89 -73
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +171 -115
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +214 -151
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js +241 -116
- package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { useTechnoSpamNavigate as e } from "../providers/TechnoSpamProvider.js";
|
|
2
2
|
import { PageLayout as t } from "../components/PageLayout.js";
|
|
3
3
|
import { StatCard as n } from "../components/StatCard.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { MediaCover as r, topicIcon as i } from "../components/MediaCover.js";
|
|
5
|
+
import { formatDuration as a } from "../utils/format.js";
|
|
6
|
+
import { StatusBadge as o } from "../components/StatusBadge.js";
|
|
7
|
+
import { LoadMore as s } from "../components/LoadMore.js";
|
|
8
|
+
import { EmptyView as c, ErrorView as l, LoadingGrid as u } from "../components/StateViews.js";
|
|
7
9
|
import "../components/index.js";
|
|
8
|
-
import { useCoursesQuery as
|
|
9
|
-
import { useMemo as
|
|
10
|
-
import { BookOpen as
|
|
11
|
-
import { jsx as
|
|
12
|
-
import { Badge as
|
|
10
|
+
import { pageArg as d, useCoursesQuery as f, usePageLimit as p } from "../api/technospamApi.js";
|
|
11
|
+
import { useMemo as m, useState as h } from "react";
|
|
12
|
+
import { BookOpen as g, Clock as _, GraduationCap as v, Layers as y, Search as b, Sparkles as x } from "lucide-react";
|
|
13
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
14
|
+
import { Badge as w, Button as T, GlassCard as E, Input as D, Tabs as O, TabsList as k, TabsTrigger as A } from "@burdenoff/fe-libs/ui";
|
|
13
15
|
//#region src/technospam/pages/CoursesCoursesPagePage.tsx
|
|
14
|
-
var
|
|
16
|
+
var j = [
|
|
15
17
|
{
|
|
16
18
|
value: "ALL",
|
|
17
19
|
label: "All levels"
|
|
@@ -33,63 +35,51 @@ var E = [
|
|
|
33
35
|
label: "Expert"
|
|
34
36
|
}
|
|
35
37
|
];
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"from-accent-teal/25 to-accent-primary/15",
|
|
40
|
-
"from-status-success-bg-subtle to-accent-wash",
|
|
41
|
-
"from-accent-wash to-bg-sunken"
|
|
42
|
-
], n = 0;
|
|
43
|
-
for (let t = 0; t < e.length; t += 1) n = n * 31 + e.charCodeAt(t) >>> 0;
|
|
44
|
-
return t[n % t.length];
|
|
45
|
-
}
|
|
46
|
-
function O({ course: e, onOpen: t }) {
|
|
47
|
-
return /* @__PURE__ */ v(x, {
|
|
48
|
-
className: "group flex cursor-pointer flex-col overflow-hidden transition-shadow hover:shadow-md",
|
|
38
|
+
function M({ course: e, onOpen: t }) {
|
|
39
|
+
return /* @__PURE__ */ C(E, {
|
|
40
|
+
className: "group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg",
|
|
49
41
|
onClick: t,
|
|
50
|
-
children: [/* @__PURE__ */
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
size: 20
|
|
55
|
-
}), /* @__PURE__ */ _(i, {
|
|
42
|
+
children: [/* @__PURE__ */ S(r, {
|
|
43
|
+
seed: `${e.topic ?? ""} ${e.title}`,
|
|
44
|
+
icon: i(e.topic ?? e.title),
|
|
45
|
+
children: /* @__PURE__ */ S(o, {
|
|
56
46
|
status: e.level,
|
|
57
47
|
kind: "level"
|
|
58
|
-
})
|
|
59
|
-
}), /* @__PURE__ */
|
|
48
|
+
})
|
|
49
|
+
}), /* @__PURE__ */ C("div", {
|
|
60
50
|
className: "flex flex-1 flex-col gap-3 p-4",
|
|
61
51
|
children: [
|
|
62
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ C("div", {
|
|
63
53
|
className: "min-w-0",
|
|
64
|
-
children: [/* @__PURE__ */
|
|
54
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
65
55
|
className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
|
|
66
56
|
children: e.title
|
|
67
|
-
}), e.summary ? /* @__PURE__ */
|
|
57
|
+
}), e.summary ? /* @__PURE__ */ S("p", {
|
|
68
58
|
className: "mt-1 line-clamp-2 text-sm text-text-secondary",
|
|
69
59
|
children: e.summary
|
|
70
60
|
}) : null]
|
|
71
61
|
}),
|
|
72
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ C("div", {
|
|
73
63
|
className: "mt-auto flex flex-wrap items-center gap-3 text-xs text-text-muted",
|
|
74
|
-
children: [e.topic ? /* @__PURE__ */
|
|
64
|
+
children: [e.topic ? /* @__PURE__ */ C("span", {
|
|
75
65
|
className: "inline-flex items-center gap-1",
|
|
76
66
|
children: [
|
|
77
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ S(y, { size: 13 }),
|
|
78
68
|
" ",
|
|
79
69
|
e.topic
|
|
80
70
|
]
|
|
81
|
-
}) : null, /* @__PURE__ */
|
|
71
|
+
}) : null, /* @__PURE__ */ C("span", {
|
|
82
72
|
className: "inline-flex items-center gap-1",
|
|
83
73
|
children: [
|
|
84
|
-
/* @__PURE__ */ _
|
|
74
|
+
/* @__PURE__ */ S(_, { size: 13 }),
|
|
85
75
|
" ",
|
|
86
|
-
|
|
76
|
+
a(e.estimatedMinutes)
|
|
87
77
|
]
|
|
88
78
|
})]
|
|
89
79
|
}),
|
|
90
|
-
e.tags.length ? /* @__PURE__ */
|
|
80
|
+
e.tags.length ? /* @__PURE__ */ S("div", {
|
|
91
81
|
className: "flex flex-wrap gap-1.5",
|
|
92
|
-
children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */
|
|
82
|
+
children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */ S(w, {
|
|
93
83
|
variant: "secondary",
|
|
94
84
|
className: "text-[11px]",
|
|
95
85
|
children: e
|
|
@@ -99,89 +89,99 @@ function O({ course: e, onOpen: t }) {
|
|
|
99
89
|
})]
|
|
100
90
|
});
|
|
101
91
|
}
|
|
102
|
-
function
|
|
103
|
-
let
|
|
92
|
+
function N() {
|
|
93
|
+
let r = e(), [i, o] = h("ALL"), [y, w] = h(""), { limit: E, more: N } = p(), { data: P, loading: F, error: I } = f({
|
|
104
94
|
status: "PUBLISHED",
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
95
|
+
pagination: d(E),
|
|
96
|
+
...i === "ALL" ? {} : { level: i }
|
|
97
|
+
}), L = P?.tecListCourses.items ?? [], R = P?.tecListCourses.pageInfo.hasMore ?? !1, z = m(() => {
|
|
98
|
+
let e = y.trim().toLowerCase();
|
|
99
|
+
return e ? L.filter((t) => t.title.toLowerCase().includes(e) || (t.topic ?? "").toLowerCase().includes(e) || t.tags.some((t) => t.toLowerCase().includes(e))) : L;
|
|
100
|
+
}, [L, y]);
|
|
101
|
+
return /* @__PURE__ */ C(t, {
|
|
111
102
|
hero: !0,
|
|
112
103
|
title: "Course Catalog",
|
|
113
|
-
description: "Learn technology by doing —
|
|
114
|
-
actions: /* @__PURE__ */
|
|
104
|
+
description: "Learn technology by doing — practical, project-based courses across the stack.",
|
|
105
|
+
actions: /* @__PURE__ */ C(T, {
|
|
115
106
|
variant: "outline",
|
|
116
|
-
onClick: () =>
|
|
117
|
-
children: [/* @__PURE__ */
|
|
107
|
+
onClick: () => r("/courses/my-learning-page"),
|
|
108
|
+
children: [/* @__PURE__ */ S(v, { size: 16 }), " My Learning"]
|
|
118
109
|
}),
|
|
119
110
|
children: [
|
|
120
|
-
/* @__PURE__ */
|
|
111
|
+
/* @__PURE__ */ C("div", {
|
|
121
112
|
className: "mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
122
113
|
children: [
|
|
123
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ S(n, {
|
|
124
115
|
label: "Courses",
|
|
125
|
-
value:
|
|
126
|
-
icon:
|
|
116
|
+
value: L.length,
|
|
117
|
+
icon: g,
|
|
118
|
+
tone: "blue"
|
|
127
119
|
}),
|
|
128
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ S(n, {
|
|
129
121
|
label: "Beginner-friendly",
|
|
130
|
-
value:
|
|
131
|
-
icon:
|
|
122
|
+
value: L.filter((e) => e.level === "BEGINNER").length,
|
|
123
|
+
icon: x,
|
|
124
|
+
tone: "green"
|
|
132
125
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
126
|
+
/* @__PURE__ */ S(n, {
|
|
134
127
|
label: "Advanced+",
|
|
135
|
-
value:
|
|
136
|
-
icon:
|
|
128
|
+
value: L.filter((e) => e.level === "ADVANCED" || e.level === "EXPERT").length,
|
|
129
|
+
icon: v,
|
|
130
|
+
tone: "purple"
|
|
137
131
|
}),
|
|
138
|
-
/* @__PURE__ */
|
|
132
|
+
/* @__PURE__ */ S(n, {
|
|
139
133
|
label: "Total content",
|
|
140
|
-
value:
|
|
141
|
-
icon:
|
|
134
|
+
value: a(L.reduce((e, t) => e + t.estimatedMinutes, 0)),
|
|
135
|
+
icon: _,
|
|
136
|
+
tone: "teal"
|
|
142
137
|
})
|
|
143
138
|
]
|
|
144
139
|
}),
|
|
145
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ C("div", {
|
|
146
141
|
className: "mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
147
|
-
children: [/* @__PURE__ */
|
|
148
|
-
value:
|
|
149
|
-
onValueChange: (e) =>
|
|
150
|
-
children: /* @__PURE__ */
|
|
142
|
+
children: [/* @__PURE__ */ S(O, {
|
|
143
|
+
value: i,
|
|
144
|
+
onValueChange: (e) => o(e),
|
|
145
|
+
children: /* @__PURE__ */ S(k, { children: j.map((e) => /* @__PURE__ */ S(A, {
|
|
151
146
|
value: e.value,
|
|
152
147
|
children: e.label
|
|
153
148
|
}, e.value)) })
|
|
154
|
-
}), /* @__PURE__ */
|
|
149
|
+
}), /* @__PURE__ */ C("div", {
|
|
155
150
|
className: "relative w-full sm:w-72",
|
|
156
|
-
children: [/* @__PURE__ */
|
|
151
|
+
children: [/* @__PURE__ */ S(b, {
|
|
157
152
|
className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted",
|
|
158
153
|
size: 16
|
|
159
|
-
}), /* @__PURE__ */
|
|
154
|
+
}), /* @__PURE__ */ S(D, {
|
|
160
155
|
className: "pl-9",
|
|
161
156
|
placeholder: "Search courses…",
|
|
162
|
-
value:
|
|
163
|
-
onChange: (e) =>
|
|
157
|
+
value: y,
|
|
158
|
+
onChange: (e) => w(e.target.value)
|
|
164
159
|
})]
|
|
165
160
|
})]
|
|
166
161
|
}),
|
|
167
|
-
|
|
162
|
+
F && !L.length ? /* @__PURE__ */ S(u, {}) : I ? /* @__PURE__ */ S(l, {
|
|
168
163
|
title: "Couldn't load courses",
|
|
169
|
-
error:
|
|
170
|
-
}) :
|
|
171
|
-
icon: /* @__PURE__ */
|
|
172
|
-
title:
|
|
173
|
-
description:
|
|
174
|
-
}) : /* @__PURE__ */
|
|
164
|
+
error: I
|
|
165
|
+
}) : z.length === 0 ? /* @__PURE__ */ S(c, {
|
|
166
|
+
icon: /* @__PURE__ */ S(g, { size: 26 }),
|
|
167
|
+
title: y || i !== "ALL" ? "No matching courses" : "No courses published yet",
|
|
168
|
+
description: y || i !== "ALL" ? "Try a different search or level filter." : "Published courses will appear here. Check back soon — TechnoSpam is pre-launch."
|
|
169
|
+
}) : /* @__PURE__ */ S("div", {
|
|
175
170
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
176
|
-
children:
|
|
171
|
+
children: z.map((e) => /* @__PURE__ */ S(M, {
|
|
177
172
|
course: e,
|
|
178
|
-
onOpen: () =>
|
|
173
|
+
onOpen: () => r(`/courses/course-details-page?id=${e.id}`)
|
|
179
174
|
}, e.id))
|
|
175
|
+
}),
|
|
176
|
+
/* @__PURE__ */ S(s, {
|
|
177
|
+
hasMore: R,
|
|
178
|
+
loading: F,
|
|
179
|
+
onClick: N
|
|
180
180
|
})
|
|
181
181
|
]
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
//#endregion
|
|
185
|
-
export {
|
|
185
|
+
export { N as CoursesCoursesPagePage };
|
|
186
186
|
|
|
187
187
|
//# sourceMappingURL=CoursesCoursesPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CoursesCoursesPagePage.js","names":[],"sources":["../../../src/technospam/pages/CoursesCoursesPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { BookOpen, Clock, GraduationCap, Layers, Search, Sparkles } from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Input,\n Tabs,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingGrid,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport { useCoursesQuery, type TecCourse, type TecCourseLevel } from '../api/technospamApi';\nimport { formatDuration } from '../utils/format';\n\nconst LEVELS: Array<{ value: 'ALL' | TecCourseLevel; label: string }> = [\n { value: 'ALL', label: 'All levels' },\n { value: 'BEGINNER', label: 'Beginner' },\n { value: 'INTERMEDIATE', label: 'Intermediate' },\n { value: 'ADVANCED', label: 'Advanced' },\n { value: 'EXPERT', label: 'Expert' },\n];\n\n/** Deterministic token-based cover gradient keyed off the course topic/level. */\nfunction coverGradient(seed: string): string {\n const gradients = [\n 'from-accent-primary/25 to-accent-teal/20',\n 'from-accent-teal/25 to-accent-primary/15',\n 'from-status-success-bg-subtle to-accent-wash',\n 'from-accent-wash to-bg-sunken',\n ];\n let hash = 0;\n for (let i = 0; i < seed.length; i += 1) hash = (hash * 31 + seed.charCodeAt(i)) >>> 0;\n return gradients[hash % gradients.length]!;\n}\n\nfunction CourseCard({ course, onOpen }: { course: TecCourse; onOpen: () => void }) {\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col overflow-hidden transition-shadow hover:shadow-md\"\n onClick={onOpen}\n >\n <div\n className={`relative flex h-28 items-end bg-gradient-to-br ${coverGradient(\n course.topic ?? course.level\n )} p-4`}\n >\n <BookOpen className=\"absolute right-3 top-3 text-text-muted/60\" size={20} />\n <StatusBadge status={course.level} kind=\"level\" />\n </div>\n <div className=\"flex flex-1 flex-col gap-3 p-4\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n {course.title}\n </h3>\n {course.summary ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{course.summary}</p>\n ) : null}\n </div>\n <div className=\"mt-auto flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n {course.topic ? (\n <span className=\"inline-flex items-center gap-1\">\n <Layers size={13} /> {course.topic}\n </span>\n ) : null}\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={13} /> {formatDuration(course.estimatedMinutes)}\n </span>\n </div>\n {course.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {course.tags.slice(0, 3).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function CoursesCoursesPagePage() {\n const navigate = useTechnoSpamNavigate();\n const [level, setLevel] = useState<'ALL' | TecCourseLevel>('ALL');\n const [search, setSearch] = useState('');\n\n const { data, loading, error } = useCoursesQuery({\n status: 'PUBLISHED',\n ...(level !== 'ALL' ? { level } : {}),\n });\n\n const courses = data?.tecListCourses.items ?? [];\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return courses;\n return courses.filter(\n (c) =>\n c.title.toLowerCase().includes(q) ||\n (c.topic ?? '').toLowerCase().includes(q) ||\n c.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [courses, search]);\n\n return (\n <PageLayout\n hero\n title=\"Course Catalog\"\n description=\"Learn technology by doing — runnable, project-based courses across the stack.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/courses/my-learning-page')}>\n <GraduationCap size={16} /> My Learning\n </Button>\n }\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Courses\" value={courses.length} icon={BookOpen} />\n <StatCard\n label=\"Beginner-friendly\"\n value={courses.filter((c) => c.level === 'BEGINNER').length}\n icon={Sparkles}\n />\n <StatCard\n label=\"Advanced+\"\n value={courses.filter((c) => c.level === 'ADVANCED' || c.level === 'EXPERT').length}\n icon={GraduationCap}\n />\n <StatCard\n label=\"Total content\"\n value={formatDuration(courses.reduce((s, c) => s + c.estimatedMinutes, 0))}\n icon={Clock}\n />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <Tabs value={level} onValueChange={(v) => setLevel(v as 'ALL' | TecCourseLevel)}>\n <TabsList>\n {LEVELS.map((l) => (\n <TabsTrigger key={l.value} value={l.value}>\n {l.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n <div className=\"relative w-full sm:w-72\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted\"\n size={16}\n />\n <Input\n className=\"pl-9\"\n placeholder=\"Search courses…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n </div>\n\n {loading && !courses.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load courses\" error={error} />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<BookOpen size={26} />}\n title={search || level !== 'ALL' ? 'No matching courses' : 'No courses published yet'}\n description={\n search || level !== 'ALL'\n ? 'Try a different search or level filter.'\n : 'Published courses will appear here. Check back soon — TechnoSpam is pre-launch.'\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((course) => (\n <CourseCard\n key={course.id}\n course={course}\n onOpen={() => navigate(`/courses/course-details-page?id=${course.id}`)}\n />\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CoursesCoursesPagePage.js","names":[],"sources":["../../../src/technospam/pages/CoursesCoursesPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { BookOpen, Clock, GraduationCap, Layers, Search, Sparkles } from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Input,\n Tabs,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n MediaCover,\n PageLayout,\n StatCard,\n StatusBadge,\n topicIcon,\n} from '../components';\nimport { useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useCoursesQuery,\n usePageLimit,\n type TecCourse,\n type TecCourseLevel,\n} from '../api/technospamApi';\nimport { formatDuration } from '../utils/format';\n\nconst LEVELS: Array<{ value: 'ALL' | TecCourseLevel; label: string }> = [\n { value: 'ALL', label: 'All levels' },\n { value: 'BEGINNER', label: 'Beginner' },\n { value: 'INTERMEDIATE', label: 'Intermediate' },\n { value: 'ADVANCED', label: 'Advanced' },\n { value: 'EXPERT', label: 'Expert' },\n];\n\nfunction CourseCard({ course, onOpen }: { course: TecCourse; onOpen: () => void }) {\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\"\n onClick={onOpen}\n >\n <MediaCover\n seed={`${course.topic ?? ''} ${course.title}`}\n icon={topicIcon(course.topic ?? course.title)}\n >\n <StatusBadge status={course.level} kind=\"level\" />\n </MediaCover>\n <div className=\"flex flex-1 flex-col gap-3 p-4\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n {course.title}\n </h3>\n {course.summary ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{course.summary}</p>\n ) : null}\n </div>\n <div className=\"mt-auto flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n {course.topic ? (\n <span className=\"inline-flex items-center gap-1\">\n <Layers size={13} /> {course.topic}\n </span>\n ) : null}\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={13} /> {formatDuration(course.estimatedMinutes)}\n </span>\n </div>\n {course.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {course.tags.slice(0, 3).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function CoursesCoursesPagePage() {\n const navigate = useTechnoSpamNavigate();\n const [level, setLevel] = useState<'ALL' | TecCourseLevel>('ALL');\n const [search, setSearch] = useState('');\n\n const { limit, more } = usePageLimit();\n const { data, loading, error } = useCoursesQuery({\n status: 'PUBLISHED',\n pagination: pageArg(limit),\n ...(level !== 'ALL' ? { level } : {}),\n });\n\n const courses = data?.tecListCourses.items ?? [];\n const hasMore = data?.tecListCourses.pageInfo.hasMore ?? false;\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return courses;\n return courses.filter(\n (c) =>\n c.title.toLowerCase().includes(q) ||\n (c.topic ?? '').toLowerCase().includes(q) ||\n c.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [courses, search]);\n\n return (\n <PageLayout\n hero\n title=\"Course Catalog\"\n description=\"Learn technology by doing — practical, project-based courses across the stack.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/courses/my-learning-page')}>\n <GraduationCap size={16} /> My Learning\n </Button>\n }\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Courses\" value={courses.length} icon={BookOpen} tone=\"blue\" />\n <StatCard\n label=\"Beginner-friendly\"\n value={courses.filter((c) => c.level === 'BEGINNER').length}\n icon={Sparkles}\n tone=\"green\"\n />\n <StatCard\n label=\"Advanced+\"\n value={courses.filter((c) => c.level === 'ADVANCED' || c.level === 'EXPERT').length}\n icon={GraduationCap}\n tone=\"purple\"\n />\n <StatCard\n label=\"Total content\"\n value={formatDuration(courses.reduce((s, c) => s + c.estimatedMinutes, 0))}\n icon={Clock}\n tone=\"teal\"\n />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <Tabs value={level} onValueChange={(v) => setLevel(v as 'ALL' | TecCourseLevel)}>\n <TabsList>\n {LEVELS.map((l) => (\n <TabsTrigger key={l.value} value={l.value}>\n {l.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n <div className=\"relative w-full sm:w-72\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted\"\n size={16}\n />\n <Input\n className=\"pl-9\"\n placeholder=\"Search courses…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n </div>\n\n {loading && !courses.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load courses\" error={error} />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<BookOpen size={26} />}\n title={search || level !== 'ALL' ? 'No matching courses' : 'No courses published yet'}\n description={\n search || level !== 'ALL'\n ? 'Try a different search or level filter.'\n : 'Published courses will appear here. Check back soon — TechnoSpam is pre-launch.'\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((course) => (\n <CourseCard\n key={course.id}\n course={course}\n onOpen={() => navigate(`/courses/course-details-page?id=${course.id}`)}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,149 +1,183 @@
|
|
|
1
1
|
import { useTechnoSpam as e, useTechnoSpamNavigate as t } from "../providers/TechnoSpamProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { cn as n } from "../utils/cn.js";
|
|
3
|
+
import { PageLayout as r } from "../components/PageLayout.js";
|
|
4
|
+
import { StatCard as i } from "../components/StatCard.js";
|
|
5
|
+
import { coverGradient as a, topicIcon as o } from "../components/MediaCover.js";
|
|
6
|
+
import { formatDate as s, relativeTime as c } from "../utils/format.js";
|
|
7
|
+
import { StatusBadge as l } from "../components/StatusBadge.js";
|
|
8
|
+
import { EmptyView as u, ErrorView as d, LoadingRows as f } from "../components/StateViews.js";
|
|
7
9
|
import "../components/index.js";
|
|
8
|
-
import { useCertificatesQuery as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { useCertificatesQuery as p, useEnrollmentsQuery as m } from "../api/technospamApi.js";
|
|
11
|
+
import { createElement as h } from "react";
|
|
12
|
+
import { Award as g, BookOpen as _, GraduationCap as v, PlayCircle as y, ShieldCheck as b } from "lucide-react";
|
|
13
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
14
|
+
import { Button as C, GlassCard as w } from "@burdenoff/fe-libs/ui";
|
|
12
15
|
//#region src/technospam/pages/CoursesMyLearningPagePage.tsx
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
function T({ e, onOpen: t }) {
|
|
17
|
+
let r = `${e.course?.topic ?? ""} ${e.course?.title ?? "Course"}`;
|
|
18
|
+
return /* @__PURE__ */ S(w, {
|
|
19
|
+
className: "group flex cursor-pointer flex-col gap-3 p-4 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md sm:flex-row sm:items-center sm:gap-4",
|
|
16
20
|
onClick: t,
|
|
17
21
|
children: [
|
|
18
|
-
/* @__PURE__ */
|
|
19
|
-
className: "flex h-
|
|
20
|
-
children:
|
|
22
|
+
/* @__PURE__ */ x("span", {
|
|
23
|
+
className: n("flex h-12 w-12 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br text-white shadow-sm transition-transform duration-200 group-hover:scale-105", a(r)),
|
|
24
|
+
children: h(o(r), { size: 20 })
|
|
21
25
|
}),
|
|
22
|
-
/* @__PURE__ */
|
|
26
|
+
/* @__PURE__ */ S("div", {
|
|
23
27
|
className: "min-w-0 flex-1",
|
|
24
28
|
children: [
|
|
25
|
-
/* @__PURE__ */
|
|
26
|
-
className: "flex items-center gap-2",
|
|
27
|
-
children: [/* @__PURE__ */
|
|
28
|
-
className: "truncate text-sm font-semibold text-text-primary",
|
|
29
|
+
/* @__PURE__ */ S("div", {
|
|
30
|
+
className: "flex flex-wrap items-center gap-2",
|
|
31
|
+
children: [/* @__PURE__ */ x("span", {
|
|
32
|
+
className: "truncate text-sm font-semibold text-text-primary group-hover:text-accent-primary",
|
|
29
33
|
children: e.course?.title ?? "Course"
|
|
30
|
-
}), /* @__PURE__ */
|
|
34
|
+
}), /* @__PURE__ */ x(l, { status: e.status })]
|
|
31
35
|
}),
|
|
32
|
-
/* @__PURE__ */
|
|
33
|
-
className: "mt-1 flex items-center gap-2 text-xs text-text-muted",
|
|
36
|
+
/* @__PURE__ */ S("div", {
|
|
37
|
+
className: "mt-1 flex flex-wrap items-center gap-2 text-xs text-text-muted",
|
|
34
38
|
children: [
|
|
35
|
-
/* @__PURE__ */
|
|
36
|
-
/* @__PURE__ */
|
|
37
|
-
|
|
39
|
+
/* @__PURE__ */ S("span", { children: [e.lessonsCompleted, " lessons done"] }),
|
|
40
|
+
/* @__PURE__ */ x("span", {
|
|
41
|
+
"aria-hidden": !0,
|
|
42
|
+
children: "·"
|
|
43
|
+
}),
|
|
44
|
+
/* @__PURE__ */ S("span", { children: ["Active ", c(e.lastActiveAt ?? e.startedAt)] })
|
|
38
45
|
]
|
|
39
46
|
}),
|
|
40
|
-
/* @__PURE__ */
|
|
47
|
+
/* @__PURE__ */ x("div", {
|
|
41
48
|
className: "mt-2 h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken",
|
|
42
|
-
children: /* @__PURE__ */
|
|
43
|
-
className: "h-full rounded-full bg-accent-primary",
|
|
49
|
+
children: /* @__PURE__ */ x("div", {
|
|
50
|
+
className: "h-full rounded-full bg-gradient-to-r from-accent-primary via-accent-indigo to-accent-purple transition-all duration-500",
|
|
44
51
|
style: { width: `${e.progressPct}%` }
|
|
45
52
|
})
|
|
46
53
|
})
|
|
47
54
|
]
|
|
48
55
|
}),
|
|
49
|
-
/* @__PURE__ */
|
|
50
|
-
className: "
|
|
51
|
-
children: [/* @__PURE__ */
|
|
52
|
-
className: "text-lg font-semibold text-text-primary",
|
|
56
|
+
/* @__PURE__ */ S("div", {
|
|
57
|
+
className: "flex items-center justify-between gap-3 sm:flex-col sm:items-end sm:justify-center",
|
|
58
|
+
children: [/* @__PURE__ */ S("div", {
|
|
59
|
+
className: "text-lg font-semibold tabular-nums text-text-primary",
|
|
53
60
|
children: [e.progressPct, "%"]
|
|
54
|
-
}), /* @__PURE__ */
|
|
61
|
+
}), /* @__PURE__ */ S(C, {
|
|
55
62
|
variant: "ghost",
|
|
56
63
|
size: "sm",
|
|
57
|
-
|
|
64
|
+
onClick: (e) => {
|
|
65
|
+
e.stopPropagation(), t();
|
|
66
|
+
},
|
|
67
|
+
children: [/* @__PURE__ */ x(y, { size: 15 }), " Resume"]
|
|
58
68
|
})]
|
|
59
69
|
})
|
|
60
70
|
]
|
|
61
71
|
});
|
|
62
72
|
}
|
|
63
|
-
function
|
|
64
|
-
let
|
|
65
|
-
return /* @__PURE__ */
|
|
73
|
+
function E() {
|
|
74
|
+
let n = t(), { currentUser: a } = e(), o = a?.id, { data: c, loading: h, error: E } = m(o ? { learnerId: o } : {}), { data: D } = p(o ? { learnerId: o } : {}), O = c?.tecListEnrollments.items ?? [], k = D?.tecListCertificates ?? [], A = O.filter((e) => e.status === "COMPLETED").length, j = O.filter((e) => e.status === "IN_PROGRESS" || e.status === "ENROLLED").length;
|
|
75
|
+
return /* @__PURE__ */ S(r, {
|
|
66
76
|
hero: !0,
|
|
67
77
|
title: "My Learning",
|
|
68
78
|
description: "Track your enrolled courses, progress, and earned certificates.",
|
|
69
|
-
actions: /* @__PURE__ */
|
|
79
|
+
actions: /* @__PURE__ */ S(C, {
|
|
70
80
|
variant: "outline",
|
|
71
|
-
onClick: () =>
|
|
72
|
-
children: [/* @__PURE__ */
|
|
81
|
+
onClick: () => n("/courses/courses-page"),
|
|
82
|
+
children: [/* @__PURE__ */ x(_, { size: 16 }), " Browse catalog"]
|
|
73
83
|
}),
|
|
74
84
|
children: [
|
|
75
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ S("div", {
|
|
76
86
|
className: "mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
77
87
|
children: [
|
|
78
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ x(i, {
|
|
79
89
|
label: "Enrolled",
|
|
80
|
-
value:
|
|
81
|
-
|
|
90
|
+
value: O.length,
|
|
91
|
+
hint: "Courses you've enrolled in",
|
|
92
|
+
icon: _,
|
|
93
|
+
tone: "blue"
|
|
82
94
|
}),
|
|
83
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ x(i, {
|
|
84
96
|
label: "In progress",
|
|
85
|
-
value:
|
|
86
|
-
|
|
97
|
+
value: j,
|
|
98
|
+
hint: "Courses in progress",
|
|
99
|
+
icon: y,
|
|
100
|
+
tone: "indigo"
|
|
87
101
|
}),
|
|
88
|
-
/* @__PURE__ */
|
|
102
|
+
/* @__PURE__ */ x(i, {
|
|
89
103
|
label: "Completed",
|
|
90
|
-
value:
|
|
91
|
-
|
|
104
|
+
value: A,
|
|
105
|
+
hint: "Courses completed",
|
|
106
|
+
icon: v,
|
|
107
|
+
tone: "green"
|
|
92
108
|
}),
|
|
93
|
-
/* @__PURE__ */
|
|
109
|
+
/* @__PURE__ */ x(i, {
|
|
94
110
|
label: "Certificates",
|
|
95
|
-
value:
|
|
96
|
-
|
|
111
|
+
value: k.length,
|
|
112
|
+
hint: "Certificates earned",
|
|
113
|
+
icon: g,
|
|
114
|
+
tone: "purple"
|
|
97
115
|
})
|
|
98
116
|
]
|
|
99
117
|
}),
|
|
100
|
-
|
|
118
|
+
h && !O.length ? /* @__PURE__ */ x(f, {
|
|
101
119
|
count: 3,
|
|
102
120
|
height: "h-24"
|
|
103
|
-
}) :
|
|
121
|
+
}) : E ? /* @__PURE__ */ x(d, {
|
|
104
122
|
title: "Couldn't load your learning",
|
|
105
|
-
error:
|
|
106
|
-
}) :
|
|
107
|
-
icon: /* @__PURE__ */
|
|
123
|
+
error: E
|
|
124
|
+
}) : O.length === 0 ? /* @__PURE__ */ x(u, {
|
|
125
|
+
icon: /* @__PURE__ */ x(_, { size: 26 }),
|
|
108
126
|
title: "You haven't enrolled yet",
|
|
109
127
|
description: "Browse the catalog and enroll in a course to start building skill by doing.",
|
|
110
|
-
action: /* @__PURE__ */
|
|
111
|
-
onClick: () =>
|
|
128
|
+
action: /* @__PURE__ */ x(C, {
|
|
129
|
+
onClick: () => n("/courses/courses-page"),
|
|
112
130
|
children: "Browse courses"
|
|
113
131
|
})
|
|
114
|
-
}) : /* @__PURE__ */
|
|
132
|
+
}) : /* @__PURE__ */ x("div", {
|
|
115
133
|
className: "space-y-3",
|
|
116
|
-
children:
|
|
134
|
+
children: O.map((e) => /* @__PURE__ */ x(T, {
|
|
117
135
|
e,
|
|
118
|
-
onOpen: () =>
|
|
136
|
+
onOpen: () => n(`/courses/course-details-page?id=${e.courseId}`)
|
|
119
137
|
}, e.id))
|
|
120
138
|
}),
|
|
121
|
-
|
|
139
|
+
k.length > 0 ? /* @__PURE__ */ S("div", {
|
|
122
140
|
className: "mt-8",
|
|
123
|
-
children: [/* @__PURE__ */
|
|
124
|
-
className: "mb-3 text-base font-semibold text-text-primary",
|
|
125
|
-
children:
|
|
126
|
-
|
|
141
|
+
children: [/* @__PURE__ */ S("h2", {
|
|
142
|
+
className: "mb-3 flex items-center gap-2 text-base font-semibold text-text-primary",
|
|
143
|
+
children: [/* @__PURE__ */ x(g, {
|
|
144
|
+
size: 18,
|
|
145
|
+
className: "text-accent-teal"
|
|
146
|
+
}), " Certificates"]
|
|
147
|
+
}), /* @__PURE__ */ x("div", {
|
|
127
148
|
className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3",
|
|
128
|
-
children:
|
|
129
|
-
className: "flex
|
|
130
|
-
children: [/* @__PURE__ */
|
|
131
|
-
className: "
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
className: "
|
|
137
|
-
children:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
"
|
|
142
|
-
e.
|
|
143
|
-
|
|
144
|
-
i(e.issuedAt)
|
|
145
|
-
]
|
|
149
|
+
children: k.map((e) => /* @__PURE__ */ S(w, {
|
|
150
|
+
className: "group flex flex-col gap-3 p-4 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg",
|
|
151
|
+
children: [/* @__PURE__ */ S("div", {
|
|
152
|
+
className: "flex items-center gap-3",
|
|
153
|
+
children: [/* @__PURE__ */ x("span", {
|
|
154
|
+
className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-status-warning-bg-subtle text-status-warning-text ring-1 ring-status-warning-border/30 transition-transform duration-200 group-hover:scale-105",
|
|
155
|
+
children: /* @__PURE__ */ x(g, { size: 22 })
|
|
156
|
+
}), /* @__PURE__ */ S("div", {
|
|
157
|
+
className: "min-w-0",
|
|
158
|
+
children: [/* @__PURE__ */ x("div", {
|
|
159
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
160
|
+
children: e.course?.title ?? "Certificate"
|
|
161
|
+
}), /* @__PURE__ */ S("div", {
|
|
162
|
+
className: "truncate text-xs text-text-muted",
|
|
163
|
+
children: ["Serial ", e.serial]
|
|
164
|
+
})]
|
|
146
165
|
})]
|
|
166
|
+
}), /* @__PURE__ */ S("div", {
|
|
167
|
+
className: "mt-auto flex items-center justify-between border-t border-border-seam pt-3 text-xs text-text-muted",
|
|
168
|
+
children: [/* @__PURE__ */ S("span", { children: [
|
|
169
|
+
"Score ",
|
|
170
|
+
/* @__PURE__ */ x("span", {
|
|
171
|
+
className: "font-semibold text-text-primary",
|
|
172
|
+
children: e.score
|
|
173
|
+
}),
|
|
174
|
+
" ·",
|
|
175
|
+
" ",
|
|
176
|
+
s(e.issuedAt)
|
|
177
|
+
] }), e.status === "ISSUED" ? /* @__PURE__ */ S("span", {
|
|
178
|
+
className: "inline-flex items-center gap-1 rounded-full border border-status-success-border bg-status-success-bg-subtle px-2 py-0.5 font-medium text-status-success-text",
|
|
179
|
+
children: [/* @__PURE__ */ x(b, { size: 12 }), " Verified"]
|
|
180
|
+
}) : /* @__PURE__ */ x(l, { status: e.status })]
|
|
147
181
|
})]
|
|
148
182
|
}, e.id))
|
|
149
183
|
})]
|
|
@@ -152,6 +186,6 @@ function x() {
|
|
|
152
186
|
});
|
|
153
187
|
}
|
|
154
188
|
//#endregion
|
|
155
|
-
export {
|
|
189
|
+
export { E as CoursesMyLearningPagePage };
|
|
156
190
|
|
|
157
191
|
//# sourceMappingURL=CoursesMyLearningPagePage.js.map
|