@burdenoff/microfe-technospam 2026.828.1 → 2026.830.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/index.js +4 -3
  2. package/dist/technospam/TechnoSpamRoot.js +4 -4
  3. package/dist/technospam/components/PageLayout.d.ts.map +1 -1
  4. package/dist/technospam/components/PageLayout.js +24 -23
  5. package/dist/technospam/components/PageLayout.js.map +1 -1
  6. package/dist/technospam/components/StateViews.d.ts +1 -1
  7. package/dist/technospam/components/StateViews.d.ts.map +1 -1
  8. package/dist/technospam/components/StateViews.js +28 -26
  9. package/dist/technospam/components/StateViews.js.map +1 -1
  10. package/dist/technospam/components/TagInput.d.ts +1 -1
  11. package/dist/technospam/components/TagInput.d.ts.map +1 -1
  12. package/dist/technospam/components/TagInput.js +39 -34
  13. package/dist/technospam/components/TagInput.js.map +1 -1
  14. package/dist/technospam/hooks/useTr.d.ts +17 -0
  15. package/dist/technospam/hooks/useTr.d.ts.map +1 -0
  16. package/dist/technospam/hooks/useTr.js +12 -0
  17. package/dist/technospam/hooks/useTr.js.map +1 -0
  18. package/dist/technospam/index.d.ts +1 -0
  19. package/dist/technospam/index.d.ts.map +1 -1
  20. package/dist/technospam/index.js +1 -0
  21. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
  22. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +198 -189
  23. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  24. package/dist/technospam/pages/ApplicationsProblemsPagePage.d.ts.map +1 -1
  25. package/dist/technospam/pages/ApplicationsProblemsPagePage.js +165 -163
  26. package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
  27. package/dist/technospam/pages/CoursesCoursesPagePage.d.ts.map +1 -1
  28. package/dist/technospam/pages/CoursesCoursesPagePage.js +117 -113
  29. package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
  30. package/dist/technospam/pages/DashboardDashboardPagePage.d.ts.map +1 -1
  31. package/dist/technospam/pages/DashboardDashboardPagePage.js +211 -193
  32. package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
  33. package/dist/technospam/pages/HackathonsHackathonsPagePage.d.ts.map +1 -1
  34. package/dist/technospam/pages/HackathonsHackathonsPagePage.js +110 -110
  35. package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
  36. package/dist/technospam/pages/MentorshipMentorsPagePage.d.ts.map +1 -1
  37. package/dist/technospam/pages/MentorshipMentorsPagePage.js +174 -160
  38. package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
  39. package/dist/technospam/pages/MentorshipSessionsPagePage.d.ts.map +1 -1
  40. package/dist/technospam/pages/MentorshipSessionsPagePage.js +156 -151
  41. package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
  42. package/dist/technospam/utils/i18n.js +1 -1
  43. package/dist/technospam/utils/i18n.js.map +1 -1
  44. package/package.json +1 -1
@@ -1,54 +1,55 @@
1
1
  import { useTechnoSpam as e, useTechnoSpamNavigate as t } from "../providers/TechnoSpamProvider.js";
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 { humanizeEnum as a } from "../utils/format.js";
6
- import { EmptyView as o, ErrorView as ee, LoadingGrid as te, LoadingRows as ne } from "../components/StateViews.js";
2
+ import { useTr as n } from "../hooks/useTr.js";
3
+ import { cn as r } from "../utils/cn.js";
4
+ import { PageLayout as i } from "../components/PageLayout.js";
5
+ import { StatCard as a } from "../components/StatCard.js";
6
+ import { humanizeEnum as o } from "../utils/format.js";
7
+ import { EmptyView as s, ErrorView as ee, LoadingGrid as te, LoadingRows as ne } from "../components/StateViews.js";
7
8
  import "../components/index.js";
8
9
  import { useCertificatesQuery as re, useCoursesQuery as ie, useEnrollmentsQuery as ae, useHackathonsQuery as oe, useProblemsQuery as se, useSessionsQuery as ce, useSubmissionsQuery as le } from "../api/technospamApi.js";
9
- import { Legend as s } from "../../node_modules/recharts/es6/component/Legend.js";
10
- import { Tooltip as c } from "../../node_modules/recharts/es6/component/Tooltip.js";
11
- import { ResponsiveContainer as l } from "../../node_modules/recharts/es6/component/ResponsiveContainer.js";
12
- import { Cell as u } from "../../node_modules/recharts/es6/component/Cell.js";
10
+ import { Legend as c } from "../../node_modules/recharts/es6/component/Legend.js";
11
+ import { Tooltip as l } from "../../node_modules/recharts/es6/component/Tooltip.js";
12
+ import { ResponsiveContainer as u } from "../../node_modules/recharts/es6/component/ResponsiveContainer.js";
13
+ import { Cell as d } from "../../node_modules/recharts/es6/component/Cell.js";
13
14
  import { Pie as ue } from "../../node_modules/recharts/es6/polar/Pie.js";
14
15
  import { Bar as de } from "../../node_modules/recharts/es6/cartesian/Bar.js";
15
- import { CartesianGrid as d } from "../../node_modules/recharts/es6/cartesian/CartesianGrid.js";
16
- import { Area as f } from "../../node_modules/recharts/es6/cartesian/Area.js";
17
- import { XAxis as p } from "../../node_modules/recharts/es6/cartesian/XAxis.js";
18
- import { YAxis as m } from "../../node_modules/recharts/es6/cartesian/YAxis.js";
16
+ import { CartesianGrid as f } from "../../node_modules/recharts/es6/cartesian/CartesianGrid.js";
17
+ import { Area as p } from "../../node_modules/recharts/es6/cartesian/Area.js";
18
+ import { XAxis as m } from "../../node_modules/recharts/es6/cartesian/XAxis.js";
19
+ import { YAxis as h } from "../../node_modules/recharts/es6/cartesian/YAxis.js";
19
20
  import { BarChart as fe } from "../../node_modules/recharts/es6/chart/BarChart.js";
20
21
  import { PieChart as pe } from "../../node_modules/recharts/es6/chart/PieChart.js";
21
22
  import { AreaChart as me } from "../../node_modules/recharts/es6/chart/AreaChart.js";
22
- import { useMemo as h, useState as g } from "react";
23
- import { Activity as _, Award as he, BarChart3 as ge, BookOpen as v, CalendarRange as y, Code2 as b, GraduationCap as x, Library as _e, Percent as ve, Target as S, TrendingUp as ye, Trophy as be, Users as xe, X as C } from "lucide-react";
23
+ import { useMemo as g, useState as _ } from "react";
24
+ import { Activity as v, Award as he, BarChart3 as ge, BookOpen as _e, CalendarRange as y, Code2 as b, GraduationCap as x, Library as ve, Percent as ye, Target as S, TrendingUp as be, Trophy as xe, Users as Se, X as C } from "lucide-react";
24
25
  import { jsx as w, jsxs as T } from "react/jsx-runtime";
25
26
  import { Button as E, GlassCard as D, Input as O } from "@burdenoff/fe-libs/ui";
26
27
  //#region src/technospam/pages/AnalyticsAnalyticsPagePage.tsx
27
- var Se = [
28
+ var Ce = [
28
29
  "ENROLLED",
29
30
  "IN_PROGRESS",
30
31
  "COMPLETED",
31
32
  "DROPPED"
32
- ], Ce = {
33
+ ], we = {
33
34
  ENROLLED: "var(--color-accent-primary)",
34
35
  IN_PROGRESS: "var(--color-accent-teal)",
35
36
  COMPLETED: "var(--color-status-success)",
36
37
  DROPPED: "var(--color-status-warning)"
37
- }, we = [
38
+ }, Te = [
38
39
  "ACCEPTED",
39
40
  "WRONG_ANSWER",
40
41
  "TIME_LIMIT_EXCEEDED",
41
42
  "RUNTIME_ERROR",
42
43
  "COMPILE_ERROR",
43
44
  "PENDING"
44
- ], Te = {
45
+ ], Ee = {
45
46
  ACCEPTED: "Accepted",
46
47
  WRONG_ANSWER: "Wrong",
47
48
  TIME_LIMIT_EXCEEDED: "TLE",
48
49
  RUNTIME_ERROR: "Runtime",
49
50
  COMPILE_ERROR: "Compile",
50
51
  PENDING: "Pending"
51
- }, Ee = {
52
+ }, De = {
52
53
  ACCEPTED: "var(--color-status-success)",
53
54
  WRONG_ANSWER: "var(--color-status-error)",
54
55
  TIME_LIMIT_EXCEEDED: "var(--color-status-warning)",
@@ -65,7 +66,7 @@ var Se = [
65
66
  fill: "var(--color-text-muted)",
66
67
  fontSize: 12
67
68
  };
68
- function De(e) {
69
+ function Oe(e) {
69
70
  let t = new Date(e);
70
71
  if (Number.isNaN(t.getTime())) return {
71
72
  key: 0,
@@ -86,20 +87,20 @@ var M = {
86
87
  purple: "bg-accent-purple/15 text-accent-purple ring-accent-purple/20",
87
88
  indigo: "bg-accent-indigo/15 text-accent-indigo ring-accent-indigo/20"
88
89
  };
89
- function N({ icon: e, title: t, subtitle: r, tone: i }) {
90
+ function N({ icon: e, title: t, subtitle: n, tone: i }) {
90
91
  return /* @__PURE__ */ T("div", {
91
92
  className: "mb-4 flex items-center gap-3",
92
93
  children: [/* @__PURE__ */ w("span", {
93
- className: n("flex h-9 w-9 shrink-0 items-center justify-center rounded-xl ring-1", M[i]),
94
+ className: r("flex h-9 w-9 shrink-0 items-center justify-center rounded-xl ring-1", M[i]),
94
95
  children: /* @__PURE__ */ w(e, { size: 17 })
95
96
  }), /* @__PURE__ */ T("div", {
96
97
  className: "min-w-0",
97
98
  children: [/* @__PURE__ */ w("h3", {
98
99
  className: "truncate text-sm font-semibold text-text-primary",
99
100
  children: t
100
- }), r ? /* @__PURE__ */ w("p", {
101
+ }), n ? /* @__PURE__ */ w("p", {
101
102
  className: "truncate text-xs text-text-muted",
102
- children: r
103
+ children: n
103
104
  }) : null]
104
105
  })]
105
106
  });
@@ -115,29 +116,29 @@ function P({ title: e, subtitle: t, icon: n, tone: r = "teal", isEmpty: i, empty
115
116
  }), i ? /* @__PURE__ */ w("div", {
116
117
  className: "flex h-[240px] items-center justify-center text-center text-sm text-text-muted",
117
118
  children: a
118
- }) : /* @__PURE__ */ w(l, {
119
+ }) : /* @__PURE__ */ w(u, {
119
120
  width: "100%",
120
121
  height: 260,
121
122
  children: o
122
123
  })]
123
124
  });
124
125
  }
125
- function Oe({ data: e }) {
126
- let t = e.length > 1 ? e[e.length - 1] : void 0;
126
+ function ke({ data: e, title: t, subtitle: n, noData: i, lowestRateLabel: a }) {
127
+ let o = e.length > 1 ? e[e.length - 1] : void 0;
127
128
  return /* @__PURE__ */ T(D, {
128
129
  className: "p-5 transition-shadow duration-200 hover:shadow-lg",
129
130
  children: [/* @__PURE__ */ w(N, {
130
131
  icon: S,
131
- title: "Accepted rate by topic",
132
- subtitle: "Where your solutions land, and where they don't",
132
+ title: t,
133
+ subtitle: n,
133
134
  tone: "indigo"
134
135
  }), e.length === 0 ? /* @__PURE__ */ w("div", {
135
136
  className: "flex h-[240px] items-center justify-center text-center text-sm text-text-muted",
136
- children: "Solve a practice problem and your per-topic rate builds here"
137
+ children: i
137
138
  }) : /* @__PURE__ */ T("div", {
138
139
  className: "space-y-3",
139
140
  children: [e.map((e) => {
140
- let r = t?.topic === e.topic;
141
+ let t = o?.topic === e.topic;
141
142
  return /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ T("div", {
142
143
  className: "mb-1 flex flex-wrap items-baseline gap-x-2",
143
144
  children: [
@@ -146,7 +147,7 @@ function Oe({ data: e }) {
146
147
  children: e.topic
147
148
  }),
148
149
  /* @__PURE__ */ T("span", {
149
- className: n("text-sm font-semibold tabular-nums", r ? "text-status-warning-text" : "text-text-secondary"),
150
+ className: r("text-sm font-semibold tabular-nums", t ? "text-status-warning-text" : "text-text-secondary"),
150
151
  children: [e.rate, "%"]
151
152
  }),
152
153
  /* @__PURE__ */ T("span", {
@@ -162,36 +163,25 @@ function Oe({ data: e }) {
162
163
  }), /* @__PURE__ */ w("div", {
163
164
  className: "h-2.5 w-full overflow-hidden rounded-full bg-bg-sunken",
164
165
  children: /* @__PURE__ */ w("div", {
165
- className: n("h-full rounded-full transition-all duration-500", r ? "bg-status-warning-text" : "bg-accent-primary"),
166
+ className: r("h-full rounded-full transition-all duration-500", t ? "bg-status-warning-text" : "bg-accent-primary"),
166
167
  style: { width: `${e.rate}%` }
167
168
  })
168
169
  })] }, e.topic);
169
- }), t ? /* @__PURE__ */ T("p", {
170
+ }), o ? /* @__PURE__ */ w("p", {
170
171
  className: "pt-1 text-xs text-text-muted",
171
- children: [
172
- "Lowest measured rate: ",
173
- /* @__PURE__ */ w("span", {
174
- className: "text-text-secondary",
175
- children: t.topic
176
- }),
177
- " —",
178
- " ",
179
- t.accepted,
180
- " of ",
181
- t.attempted,
182
- " attempts accepted in the loaded range."
183
- ]
172
+ children: a(o.topic, o.accepted, o.attempted)
184
173
  }) : null]
185
174
  })]
186
175
  });
187
176
  }
188
- function ke(e) {
177
+ function Ae(e) {
189
178
  return e ? `${e}T00:00:00.000Z` : void 0;
190
179
  }
191
- function Ae(e) {
180
+ function je(e) {
192
181
  return e ? `${e}T23:59:59.999Z` : void 0;
193
182
  }
194
- function je({ start: e, end: t, onStart: n, onEnd: r, onPreset: i, onClear: a }) {
183
+ function Me({ start: e, end: t, onStart: n, onEnd: r, onPreset: i, onClear: a, tr: o }) {
184
+ let s = !!(e || t);
195
185
  return /* @__PURE__ */ T(D, {
196
186
  className: "mb-6 flex flex-col gap-3 p-4 lg:flex-row lg:items-end lg:justify-between",
197
187
  children: [/* @__PURE__ */ T("div", {
@@ -202,12 +192,12 @@ function je({ start: e, end: t, onStart: n, onEnd: r, onPreset: i, onClear: a })
202
192
  children: [/* @__PURE__ */ w(y, {
203
193
  size: 16,
204
194
  className: "text-accent-teal"
205
- }), "Date range"]
195
+ }), o("technospam.analytics.dateRangeTitle", "Date range")]
206
196
  }),
207
197
  /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("label", {
208
198
  className: "mb-1 block text-xs font-medium text-text-muted",
209
199
  htmlFor: "tec-range-from",
210
- children: "From"
200
+ children: o("technospam.analytics.from", "From")
211
201
  }), /* @__PURE__ */ w(O, {
212
202
  id: "tec-range-from",
213
203
  type: "date",
@@ -219,7 +209,7 @@ function je({ start: e, end: t, onStart: n, onEnd: r, onPreset: i, onClear: a })
219
209
  /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("label", {
220
210
  className: "mb-1 block text-xs font-medium text-text-muted",
221
211
  htmlFor: "tec-range-to",
222
- children: "To"
212
+ children: o("technospam.analytics.to", "To")
223
213
  }), /* @__PURE__ */ w(O, {
224
214
  id: "tec-range-to",
225
215
  type: "date",
@@ -228,11 +218,15 @@ function je({ start: e, end: t, onStart: n, onEnd: r, onPreset: i, onClear: a })
228
218
  onChange: (e) => r(e.target.value),
229
219
  className: "w-40"
230
220
  })] }),
231
- e || t ? /* @__PURE__ */ T(E, {
221
+ s ? /* @__PURE__ */ T(E, {
232
222
  variant: "ghost",
233
223
  size: "sm",
234
224
  onClick: a,
235
- children: [/* @__PURE__ */ w(C, { size: 14 }), " Clear"]
225
+ children: [
226
+ /* @__PURE__ */ w(C, { size: 14 }),
227
+ " ",
228
+ o("technospam.analytics.clear", "Clear")
229
+ ]
236
230
  }) : null
237
231
  ]
238
232
  }), /* @__PURE__ */ T("div", {
@@ -242,58 +236,58 @@ function je({ start: e, end: t, onStart: n, onEnd: r, onPreset: i, onClear: a })
242
236
  variant: "outline",
243
237
  size: "sm",
244
238
  onClick: () => i(7),
245
- children: "Last 7 days"
239
+ children: o("technospam.analytics.last7Days", "Last 7 days")
246
240
  }),
247
241
  /* @__PURE__ */ w(E, {
248
242
  variant: "outline",
249
243
  size: "sm",
250
244
  onClick: () => i(30),
251
- children: "Last 30 days"
245
+ children: o("technospam.analytics.last30Days", "Last 30 days")
252
246
  }),
253
247
  /* @__PURE__ */ w(E, {
254
248
  variant: "outline",
255
249
  size: "sm",
256
250
  onClick: () => i(90),
257
- children: "Last 90 days"
251
+ children: o("technospam.analytics.last90Days", "Last 90 days")
258
252
  })
259
253
  ]
260
254
  })]
261
255
  });
262
256
  }
263
257
  function F() {
264
- let n = t(), { currentUser: y } = e(), S = y?.id, [C, O] = g(""), [M, F] = g(""), I = ke(C), L = Ae(M), Me = (e) => {
258
+ let r = t(), { currentUser: y } = e(), S = n(), C = y?.id, [O, M] = _(""), [F, I] = _(""), L = Ae(O), R = je(F), Ne = (e) => {
265
259
  let t = /* @__PURE__ */ new Date(), n = /* @__PURE__ */ new Date();
266
- n.setDate(n.getDate() - e), O(n.toISOString().slice(0, 10)), F(t.toISOString().slice(0, 10));
267
- }, Ne = () => {
268
- O(""), F("");
269
- }, R = I || L ? {
270
- startDate: I,
271
- endDate: L
272
- } : {}, z = ae(S ? {
273
- learnerId: S,
274
- ...R
275
- } : {}), B = le(S ? {
276
- learnerId: S,
277
- ...R
278
- } : {}), V = ce(S ? { menteeId: S } : {}), H = re(S ? { learnerId: S } : {}), Pe = ie({ status: "PUBLISHED" }), Fe = se({ status: "PUBLISHED" }), Ie = oe({}), U = h(() => z.data?.tecListEnrollments?.items ?? [], [z.data]), W = h(() => B.data?.tecListSubmissions?.items ?? [], [B.data]), G = V.data?.tecListSessions?.items ?? [], K = H.data?.tecListCertificates ?? [], Le = Pe.data?.tecListCourses?.items.length ?? 0, Re = Fe.data?.tecListProblems?.items.length ?? 0, ze = Ie.data?.tecListHackathons?.items.length ?? 0, q = h(() => {
279
- let e = U.filter((e) => e.status === "COMPLETED").length, t = U.length ? Math.round(U.reduce((e, t) => e + t.progressPct, 0) / U.length) : 0, n = W.filter((e) => e.verdict === "ACCEPTED");
260
+ n.setDate(n.getDate() - e), M(n.toISOString().slice(0, 10)), I(t.toISOString().slice(0, 10));
261
+ }, Pe = () => {
262
+ M(""), I("");
263
+ }, z = L || R ? {
264
+ startDate: L,
265
+ endDate: R
266
+ } : {}, B = ae(C ? {
267
+ learnerId: C,
268
+ ...z
269
+ } : {}), V = le(C ? {
270
+ learnerId: C,
271
+ ...z
272
+ } : {}), H = ce(C ? { menteeId: C } : {}), U = re(C ? { learnerId: C } : {}), Fe = ie({ status: "PUBLISHED" }), Ie = se({ status: "PUBLISHED" }), Le = oe({}), W = g(() => B.data?.tecListEnrollments?.items ?? [], [B.data]), G = g(() => V.data?.tecListSubmissions?.items ?? [], [V.data]), K = H.data?.tecListSessions?.items ?? [], q = U.data?.tecListCertificates ?? [], Re = Fe.data?.tecListCourses?.items.length ?? 0, ze = Ie.data?.tecListProblems?.items.length ?? 0, Be = Le.data?.tecListHackathons?.items.length ?? 0, J = g(() => {
273
+ let e = W.filter((e) => e.status === "COMPLETED").length, t = W.length ? Math.round(W.reduce((e, t) => e + t.progressPct, 0) / W.length) : 0, n = G.filter((e) => e.verdict === "ACCEPTED");
280
274
  return {
281
275
  coursesCompleted: e,
282
276
  avgProgress: t,
283
277
  problemsSolved: new Set(n.map((e) => e.problemId)).size,
284
- acceptanceRate: W.length ? Math.round(n.length / W.length * 100) : 0
278
+ acceptanceRate: G.length ? Math.round(n.length / G.length * 100) : 0
285
279
  };
286
- }, [U, W]), J = h(() => Se.map((e) => ({
287
- name: a(e),
288
- value: U.filter((t) => t.status === e).length,
289
- color: Ce[e]
290
- })).filter((e) => e.value > 0), [U]), Y = h(() => we.map((e) => ({
291
- label: Te[e],
292
- count: W.filter((t) => t.verdict === e).length,
293
- color: Ee[e]
294
- })).filter((e) => e.count > 0), [W]), Be = h(() => {
280
+ }, [W, G]), Y = g(() => Ce.map((e) => ({
281
+ name: o(e),
282
+ value: W.filter((t) => t.status === e).length,
283
+ color: we[e]
284
+ })).filter((e) => e.value > 0), [W]), X = g(() => Te.map((e) => ({
285
+ label: Ee[e],
286
+ count: G.filter((t) => t.verdict === e).length,
287
+ color: De[e]
288
+ })).filter((e) => e.count > 0), [G]), Ve = g(() => {
295
289
  let e = /* @__PURE__ */ new Map();
296
- return W.forEach((t) => {
290
+ return G.forEach((t) => {
297
291
  let n = t.problem?.topic?.trim() || "Untagged", r = e.get(n) ?? {
298
292
  accepted: 0,
299
293
  attempted: 0
@@ -305,59 +299,63 @@ function F() {
305
299
  attempted: t.attempted,
306
300
  rate: Math.round(t.accepted / t.attempted * 100)
307
301
  })).sort((e, t) => t.rate - e.rate || t.attempted - e.attempted);
308
- }, [W]), X = h(() => {
302
+ }, [G]), Z = g(() => {
309
303
  let e = /* @__PURE__ */ new Map(), t = (t, n) => {
310
- let { key: r, label: i } = De(t), a = e.get(r) ?? {
304
+ let { key: r, label: i } = Oe(t), a = e.get(r) ?? {
311
305
  label: i,
312
306
  submissions: 0,
313
307
  enrollments: 0
314
308
  };
315
309
  a[n] += 1, e.set(r, a);
316
310
  };
317
- return W.forEach((e) => t(e.createdAt, "submissions")), U.forEach((e) => t(e.createdAt, "enrollments")), [...e.entries()].sort((e, t) => e[0] - t[0]).slice(-8).map(([, e]) => e);
318
- }, [W, U]), Z = U.length > 0 || W.length > 0 || G.length > 0 || K.length > 0, Ve = z.loading || B.loading || V.loading || H.loading, Q = z.error || B.error || V.error || H.error, He = Ve && !Z, $ = /* @__PURE__ */ T("div", { children: [
311
+ return G.forEach((e) => t(e.createdAt, "submissions")), W.forEach((e) => t(e.createdAt, "enrollments")), [...e.entries()].sort((e, t) => e[0] - t[0]).slice(-8).map(([, e]) => e);
312
+ }, [G, W]), Q = W.length > 0 || G.length > 0 || K.length > 0 || q.length > 0, He = B.loading || V.loading || H.loading || U.loading, $ = B.error || V.error || H.error || U.error, Ue = He && !Q, We = /* @__PURE__ */ T("div", { children: [
319
313
  /* @__PURE__ */ w("h2", {
320
314
  className: "mb-3 text-base font-semibold text-text-primary",
321
- children: "Workspace overview"
315
+ children: S("technospam.analytics.workspaceOverviewTitle", "Workspace overview")
322
316
  }),
323
317
  /* @__PURE__ */ w("p", {
324
318
  className: "mb-4 max-w-2xl text-sm text-text-secondary",
325
- children: "Live content available across the TechnoSpam learning workspace right now."
319
+ children: S("technospam.analytics.workspaceOverviewDesc", "Live content available across the TechnoSpam learning workspace right now.")
326
320
  }),
327
321
  /* @__PURE__ */ T("div", {
328
322
  className: "grid grid-cols-1 gap-3 sm:grid-cols-3",
329
323
  children: [
330
- /* @__PURE__ */ w(i, {
331
- label: "Published courses",
332
- value: Le,
333
- icon: _e,
324
+ /* @__PURE__ */ w(a, {
325
+ label: S("technospam.analytics.statPublishedCourses", "Published courses"),
326
+ value: Re,
327
+ icon: ve,
334
328
  tone: "blue"
335
329
  }),
336
- /* @__PURE__ */ w(i, {
337
- label: "Published problems",
338
- value: Re,
330
+ /* @__PURE__ */ w(a, {
331
+ label: S("technospam.analytics.statPublishedProblems", "Published problems"),
332
+ value: ze,
339
333
  icon: b,
340
334
  tone: "indigo"
341
335
  }),
342
- /* @__PURE__ */ w(i, {
343
- label: "Hackathons",
344
- value: ze,
345
- icon: be,
336
+ /* @__PURE__ */ w(a, {
337
+ label: S("technospam.analytics.statHackathons", "Hackathons"),
338
+ value: Be,
339
+ icon: xe,
346
340
  tone: "purple"
347
341
  })
348
342
  ]
349
343
  })
350
344
  ] });
351
- return /* @__PURE__ */ w(r, {
345
+ return /* @__PURE__ */ w(i, {
352
346
  hero: !0,
353
- title: "Analytics",
354
- description: "Your real learning performance across courses, problems, mentoring and certificates.",
347
+ title: S("technospam.analytics.title", "Analytics"),
348
+ description: S("technospam.analytics.description", "Your real learning performance across courses, problems, mentoring and certificates."),
355
349
  actions: /* @__PURE__ */ T(E, {
356
350
  variant: "outline",
357
- onClick: () => n("/courses/my-learning-page"),
358
- children: [/* @__PURE__ */ w(x, { size: 16 }), " My Learning"]
351
+ onClick: () => r("/courses/my-learning-page"),
352
+ children: [
353
+ /* @__PURE__ */ w(x, { size: 16 }),
354
+ " ",
355
+ S("technospam.common.myLearning", "My Learning")
356
+ ]
359
357
  }),
360
- children: S ? He ? /* @__PURE__ */ T("div", {
358
+ children: C ? Ue ? /* @__PURE__ */ T("div", {
361
359
  className: "space-y-6",
362
360
  children: [/* @__PURE__ */ w(te, {
363
361
  count: 4,
@@ -366,82 +364,83 @@ function F() {
366
364
  count: 2,
367
365
  height: "h-72"
368
366
  })]
369
- }) : Q && !Z ? /* @__PURE__ */ w(ee, {
370
- title: "Couldn't load your analytics",
371
- error: Q
367
+ }) : $ && !Q ? /* @__PURE__ */ w(ee, {
368
+ title: S("technospam.common.errorLoadAnalytics", "Couldn't load your analytics"),
369
+ error: $
372
370
  }) : /* @__PURE__ */ T("div", {
373
371
  className: "space-y-8",
374
372
  children: [
375
- /* @__PURE__ */ w(je, {
376
- start: C,
377
- end: M,
378
- onStart: O,
379
- onEnd: F,
380
- onPreset: Me,
381
- onClear: Ne
373
+ /* @__PURE__ */ w(Me, {
374
+ start: O,
375
+ end: F,
376
+ onStart: M,
377
+ onEnd: I,
378
+ onPreset: Ne,
379
+ onClear: Pe,
380
+ tr: S
382
381
  }),
383
382
  /* @__PURE__ */ T("div", {
384
383
  className: "grid grid-cols-2 gap-3 sm:grid-cols-3 xl:grid-cols-4",
385
384
  children: [
386
- /* @__PURE__ */ w(i, {
387
- label: "Courses enrolled",
388
- value: U.length,
389
- icon: v,
385
+ /* @__PURE__ */ w(a, {
386
+ label: S("technospam.analytics.statCoursesEnrolled", "Courses enrolled"),
387
+ value: W.length,
388
+ icon: _e,
390
389
  tone: "blue"
391
390
  }),
392
- /* @__PURE__ */ w(i, {
393
- label: "Courses completed",
394
- value: q.coursesCompleted,
391
+ /* @__PURE__ */ w(a, {
392
+ label: S("technospam.analytics.statCoursesCompleted", "Courses completed"),
393
+ value: J.coursesCompleted,
395
394
  icon: x,
396
395
  tone: "green"
397
396
  }),
398
- /* @__PURE__ */ w(i, {
399
- label: "Avg progress",
400
- value: `${q.avgProgress}%`,
401
- icon: ye,
397
+ /* @__PURE__ */ w(a, {
398
+ label: S("technospam.analytics.statAvgProgress", "Avg progress"),
399
+ value: `${J.avgProgress}%`,
400
+ icon: be,
402
401
  tone: "purple"
403
402
  }),
404
- /* @__PURE__ */ w(i, {
405
- label: "Problems solved",
406
- value: q.problemsSolved,
403
+ /* @__PURE__ */ w(a, {
404
+ label: S("technospam.analytics.statProblemsSolved", "Problems solved"),
405
+ value: J.problemsSolved,
407
406
  icon: b,
408
407
  tone: "indigo"
409
408
  }),
410
- /* @__PURE__ */ w(i, {
411
- label: "Acceptance rate",
412
- value: `${q.acceptanceRate}%`,
413
- icon: ve,
409
+ /* @__PURE__ */ w(a, {
410
+ label: S("technospam.analytics.statAcceptanceRate", "Acceptance rate"),
411
+ value: `${J.acceptanceRate}%`,
412
+ icon: ye,
414
413
  tone: "teal"
415
414
  }),
416
- /* @__PURE__ */ w(i, {
417
- label: "Mentor sessions",
418
- value: G.length,
419
- icon: xe,
415
+ /* @__PURE__ */ w(a, {
416
+ label: S("technospam.analytics.statMentorSessions", "Mentor sessions"),
417
+ value: K.length,
418
+ icon: Se,
420
419
  tone: "blue"
421
420
  }),
422
- /* @__PURE__ */ w(i, {
423
- label: "Certificates",
424
- value: K.length,
421
+ /* @__PURE__ */ w(a, {
422
+ label: S("technospam.analytics.statCertificates", "Certificates"),
423
+ value: q.length,
425
424
  icon: he,
426
425
  tone: "amber"
427
426
  })
428
427
  ]
429
428
  }),
430
- Z ? /* @__PURE__ */ T("div", {
429
+ Q ? /* @__PURE__ */ T("div", {
431
430
  className: "space-y-4",
432
431
  children: [
433
432
  /* @__PURE__ */ T("div", {
434
433
  className: "grid grid-cols-1 gap-4 lg:grid-cols-2",
435
434
  children: [/* @__PURE__ */ w(P, {
436
- title: "Enrollments by status",
437
- subtitle: "How your courses are progressing",
438
- icon: v,
435
+ title: S("technospam.analytics.enrollmentsByStatusTitle", "Enrollments by status"),
436
+ subtitle: S("technospam.analytics.enrollmentsByStatusSubtitle", "How your courses are progressing"),
437
+ icon: _e,
439
438
  tone: "blue",
440
- isEmpty: J.length === 0,
441
- emptyLabel: "No enrollments yet",
439
+ isEmpty: Y.length === 0,
440
+ emptyLabel: S("technospam.analytics.noEnrollments", "No enrollments yet"),
442
441
  children: /* @__PURE__ */ T(pe, { children: [
443
442
  /* @__PURE__ */ w(ue, {
444
- data: J,
443
+ data: Y,
445
444
  dataKey: "value",
446
445
  nameKey: "name",
447
446
  innerRadius: 60,
@@ -449,26 +448,26 @@ function F() {
449
448
  paddingAngle: 2,
450
449
  stroke: "var(--color-bg-surface)",
451
450
  strokeWidth: 2,
452
- children: J.map((e) => /* @__PURE__ */ w(u, { fill: e.color }, e.name))
451
+ children: Y.map((e) => /* @__PURE__ */ w(d, { fill: e.color }, e.name))
453
452
  }),
454
- /* @__PURE__ */ w(c, {
453
+ /* @__PURE__ */ w(l, {
455
454
  contentStyle: k,
456
455
  labelStyle: A
457
456
  }),
458
- /* @__PURE__ */ w(s, {
457
+ /* @__PURE__ */ w(c, {
459
458
  iconType: "circle",
460
459
  wrapperStyle: { fontSize: 12 }
461
460
  })
462
461
  ] })
463
462
  }), /* @__PURE__ */ w(P, {
464
- title: "Submissions by verdict",
465
- subtitle: "Outcomes across your attempts",
463
+ title: S("technospam.analytics.submissionsByVerdictTitle", "Submissions by verdict"),
464
+ subtitle: S("technospam.analytics.submissionsByVerdictSubtitle", "Outcomes across your attempts"),
466
465
  icon: b,
467
466
  tone: "purple",
468
- isEmpty: Y.length === 0,
469
- emptyLabel: "No submissions yet",
467
+ isEmpty: X.length === 0,
468
+ emptyLabel: S("technospam.analytics.noSubmissions", "No submissions yet"),
470
469
  children: /* @__PURE__ */ T(fe, {
471
- data: Y,
470
+ data: X,
472
471
  margin: {
473
472
  top: 8,
474
473
  right: 8,
@@ -476,24 +475,24 @@ function F() {
476
475
  bottom: 0
477
476
  },
478
477
  children: [
479
- /* @__PURE__ */ w(d, {
478
+ /* @__PURE__ */ w(f, {
480
479
  strokeDasharray: "3 3",
481
480
  stroke: "var(--color-border-seam)",
482
481
  vertical: !1
483
482
  }),
484
- /* @__PURE__ */ w(p, {
483
+ /* @__PURE__ */ w(m, {
485
484
  dataKey: "label",
486
485
  tick: j,
487
486
  axisLine: { stroke: "var(--color-border-seam)" },
488
487
  tickLine: !1
489
488
  }),
490
- /* @__PURE__ */ w(m, {
489
+ /* @__PURE__ */ w(h, {
491
490
  allowDecimals: !1,
492
491
  tick: j,
493
492
  axisLine: !1,
494
493
  tickLine: !1
495
494
  }),
496
- /* @__PURE__ */ w(c, {
495
+ /* @__PURE__ */ w(l, {
497
496
  contentStyle: k,
498
497
  labelStyle: A,
499
498
  cursor: {
@@ -511,28 +510,38 @@ function F() {
511
510
  0
512
511
  ],
513
512
  maxBarSize: 56,
514
- children: Y.map((e) => /* @__PURE__ */ w(u, { fill: e.color }, e.label))
513
+ children: X.map((e) => /* @__PURE__ */ w(d, { fill: e.color }, e.label))
515
514
  })
516
515
  ]
517
516
  })
518
517
  })]
519
518
  }),
520
- /* @__PURE__ */ w(Oe, { data: Be }),
519
+ /* @__PURE__ */ w(ke, {
520
+ data: Ve,
521
+ title: S("technospam.analytics.topicAcceptanceTitle", "Accepted rate by topic"),
522
+ subtitle: S("technospam.analytics.topicAcceptanceSubtitle", "Where your solutions land, and where they don't"),
523
+ noData: S("technospam.analytics.noTopicData", "Solve a practice problem and your per-topic rate builds here"),
524
+ lowestRateLabel: (e, t, n) => S("technospam.analytics.lowestMeasuredRate", "Lowest measured rate: {{topic}} — {{accepted}} of {{attempted}} attempts accepted in the loaded range.", {
525
+ topic: e,
526
+ accepted: t,
527
+ attempted: n
528
+ })
529
+ }),
521
530
  /* @__PURE__ */ T(D, {
522
531
  className: "p-5 transition-shadow duration-200 hover:shadow-lg",
523
532
  children: [/* @__PURE__ */ w(N, {
524
- icon: _,
525
- title: "Learning activity over time",
526
- subtitle: "Submissions and enrollments per week",
533
+ icon: v,
534
+ title: S("technospam.analytics.activityOverTimeTitle", "Learning activity over time"),
535
+ subtitle: S("technospam.analytics.activityOverTimeSubtitle", "Submissions and enrollments per week"),
527
536
  tone: "teal"
528
- }), X.length === 0 ? /* @__PURE__ */ w("div", {
537
+ }), Z.length === 0 ? /* @__PURE__ */ w("div", {
529
538
  className: "flex h-[240px] items-center justify-center text-sm text-text-muted",
530
- children: "No dated activity yet"
531
- }) : /* @__PURE__ */ w(l, {
539
+ children: S("technospam.analytics.noDatedActivity", "No dated activity yet")
540
+ }) : /* @__PURE__ */ w(u, {
532
541
  width: "100%",
533
542
  height: 280,
534
543
  children: /* @__PURE__ */ T(me, {
535
- data: X,
544
+ data: Z,
536
545
  margin: {
537
546
  top: 8,
538
547
  right: 12,
@@ -571,32 +580,32 @@ function F() {
571
580
  stopOpacity: 0
572
581
  })]
573
582
  })] }),
574
- /* @__PURE__ */ w(d, {
583
+ /* @__PURE__ */ w(f, {
575
584
  strokeDasharray: "3 3",
576
585
  stroke: "var(--color-border-seam)",
577
586
  vertical: !1
578
587
  }),
579
- /* @__PURE__ */ w(p, {
588
+ /* @__PURE__ */ w(m, {
580
589
  dataKey: "label",
581
590
  tick: j,
582
591
  axisLine: { stroke: "var(--color-border-seam)" },
583
592
  tickLine: !1
584
593
  }),
585
- /* @__PURE__ */ w(m, {
594
+ /* @__PURE__ */ w(h, {
586
595
  allowDecimals: !1,
587
596
  tick: j,
588
597
  axisLine: !1,
589
598
  tickLine: !1
590
599
  }),
591
- /* @__PURE__ */ w(c, {
600
+ /* @__PURE__ */ w(l, {
592
601
  contentStyle: k,
593
602
  labelStyle: A
594
603
  }),
595
- /* @__PURE__ */ w(s, {
604
+ /* @__PURE__ */ w(c, {
596
605
  iconType: "circle",
597
606
  wrapperStyle: { fontSize: 12 }
598
607
  }),
599
- /* @__PURE__ */ w(f, {
608
+ /* @__PURE__ */ w(p, {
600
609
  type: "monotone",
601
610
  dataKey: "submissions",
602
611
  name: "Submissions",
@@ -604,7 +613,7 @@ function F() {
604
613
  strokeWidth: 2,
605
614
  fill: "url(#tec-grad-submissions)"
606
615
  }),
607
- /* @__PURE__ */ w(f, {
616
+ /* @__PURE__ */ w(p, {
608
617
  type: "monotone",
609
618
  dataKey: "enrollments",
610
619
  name: "Enrollments",
@@ -617,24 +626,24 @@ function F() {
617
626
  })]
618
627
  })
619
628
  ]
620
- }) : /* @__PURE__ */ w(o, {
621
- icon: /* @__PURE__ */ w(_, { size: 26 }),
622
- title: "No learning activity yet",
623
- description: "Enroll in a course or solve a problem and your progress charts will build here. TechnoSpam is pre-launch — start learning to see your data.",
629
+ }) : /* @__PURE__ */ w(s, {
630
+ icon: /* @__PURE__ */ w(v, { size: 26 }),
631
+ title: S("technospam.analytics.noActivityTitle", "No learning activity yet"),
632
+ description: S("technospam.analytics.noActivityDesc", "Enroll in a course or solve a problem and your progress charts will build here. TechnoSpam is pre-launch — start learning to see your data."),
624
633
  action: /* @__PURE__ */ w(E, {
625
- onClick: () => n("/courses/courses-page"),
626
- children: "Browse courses"
634
+ onClick: () => r("/courses/courses-page"),
635
+ children: S("technospam.common.browseCourses", "Browse courses")
627
636
  })
628
637
  }),
629
- $
638
+ We
630
639
  ]
631
640
  }) : /* @__PURE__ */ T("div", {
632
641
  className: "space-y-8",
633
- children: [/* @__PURE__ */ w(o, {
642
+ children: [/* @__PURE__ */ w(s, {
634
643
  icon: /* @__PURE__ */ w(ge, { size: 26 }),
635
- title: "Sign in to view your analytics",
636
- description: "Your personal learning metrics appear here once you're signed in."
637
- }), $]
644
+ title: S("technospam.analytics.signInTitle", "Sign in to view your analytics"),
645
+ description: S("technospam.analytics.signInDesc", "Your personal learning metrics appear here once you're signed in.")
646
+ }), We]
638
647
  })
639
648
  });
640
649
  }