@burdenoff/microfe-technospam 2026.1101.3 → 2026.1101.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,5 +6,10 @@ export default meta;
6
6
  type Story = StoryObj<typeof meta>;
7
7
  /** Pick a problem from the practice list, submit a solution, see the verdict. */
8
8
  export declare const PracticeAndSubmit: Story;
9
+ /**
10
+ * BOFF-3157: in the card layout a keyboard-only learner Tabs to a problem card
11
+ * (its title is the card's button) and opens it with Enter.
12
+ */
13
+ export declare const OpenProblemCardWithKeyboard: Story;
9
14
  export declare const BackendUnavailable: Story;
10
15
  //# sourceMappingURL=Problems.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Problems.stories.d.ts","sourceRoot":"","sources":["../../../src/stories/journeys/Problems.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGpE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,kBAAkB,CAMzC,CAAC;AACF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,EAAE,KA8B/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAMhC,CAAC"}
1
+ {"version":3,"file":"Problems.stories.d.ts","sourceRoot":"","sources":["../../../src/stories/journeys/Problems.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAIpE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,kBAAkB,CAMzC,CAAC;AACF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,EAAE,KA8B/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,KAoBzC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAMhC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ApplicationsProblemsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/ApplicationsProblemsPagePage.tsx"],"names":[],"mappings":"AA2JA,wBAAgB,4BAA4B,gCAuT3C"}
1
+ {"version":3,"file":"ApplicationsProblemsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/ApplicationsProblemsPagePage.tsx"],"names":[],"mappings":"AAyJA,wBAAgB,4BAA4B,gCAuT3C"}
@@ -5,31 +5,31 @@ import { PageLayout as i } from "../components/PageLayout.js";
5
5
  import { StatCard as a } from "../components/StatCard.js";
6
6
  import { MediaCover as o, topicIcon as s } from "../components/MediaCover.js";
7
7
  import { StatusBadge as c } from "../components/StatusBadge.js";
8
- import { readProblemCatalogView as l, safeLocalStorage as u, writeProblemCatalogView as ee } from "../utils/problemCatalog.js";
9
- import { PremiumBadge as d } from "../components/UpgradeGate.js";
10
- import { ProblemsTable as f } from "../components/ProblemsTable.js";
8
+ import { readProblemCatalogView as l, safeLocalStorage as u, writeProblemCatalogView as d } from "../utils/problemCatalog.js";
9
+ import { PremiumBadge as f } from "../components/UpgradeGate.js";
10
+ import { ProblemsTable as ee } from "../components/ProblemsTable.js";
11
11
  import { LoadMore as te } from "../components/LoadMore.js";
12
- import { EmptyView as p, ErrorView as m, LoadingGrid as ne } from "../components/StateViews.js";
13
- import { pageArg as re, usePageLimit as ie, useProblemsQuery as h, useSolvedProblemIds as ae } from "../api/technospamApi.js";
12
+ import { EmptyView as ne, ErrorView as re, LoadingGrid as p } from "../components/StateViews.js";
13
+ import { pageArg as ie, usePageLimit as ae, useProblemsQuery as oe, useSolvedProblemIds as se } from "../api/technospamApi.js";
14
+ import { CardOpenButton as m } from "../components/CardOpenButton.js";
14
15
  import "../components/index.js";
15
- import { TAB_PANEL_FOCUS_CLASS as oe } from "../lib/a11y.js";
16
- import { useCallback as g, useMemo as _, useState as v } from "react";
17
- import { Building2 as y, CheckCircle2 as b, Code2 as x, Flame as S, Gauge as se, Layers as C, LayoutGrid as w, List as ce, Search as le, Tag as T, Trophy as E } from "lucide-react";
16
+ import { TAB_PANEL_FOCUS_CLASS as ce } from "../lib/a11y.js";
17
+ import { useCallback as h, useMemo as g, useState as _ } from "react";
18
+ import { Building2 as v, CheckCircle2 as y, Code2 as b, Flame as x, Gauge as S, Layers as C, LayoutGrid as le, List as ue, Search as w, Tag as T, Trophy as E } from "lucide-react";
18
19
  import { jsx as D, jsxs as O } from "react/jsx-runtime";
19
- import { Badge as k, Button as A, GlassCard as j, Input as ue, Select as M, SelectContent as N, SelectItem as P, SelectTrigger as F, SelectValue as I, Tabs as L, TabsContent as R, TabsList as z, TabsTrigger as B } from "@burdenoff/fe-libs/ui";
20
+ import { Badge as k, Button as A, GlassCard as j, Input as de, Select as M, SelectContent as N, SelectItem as P, SelectTrigger as F, SelectValue as I, Tabs as L, TabsContent as R, TabsList as z, TabsTrigger as B } from "@burdenoff/fe-libs/ui";
20
21
  //#region src/technospam/pages/ApplicationsProblemsPagePage.tsx
21
22
  function V({ problem: e, solved: t, onOpen: n }) {
22
23
  let i = r();
23
24
  return /* @__PURE__ */ O(j, {
24
25
  className: "group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg",
25
- onClick: n,
26
26
  children: [/* @__PURE__ */ O(o, {
27
27
  seed: `${e.topic ?? ""} ${e.difficulty} ${e.title}`,
28
28
  icon: s(e.topic ?? e.title),
29
29
  children: [t ? /* @__PURE__ */ O("span", {
30
30
  className: "inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[11px] font-medium text-status-success-text ring-1 ring-status-success-border/30",
31
31
  children: [
32
- /* @__PURE__ */ D(b, { size: 12 }),
32
+ /* @__PURE__ */ D(y, { size: 12 }),
33
33
  " ",
34
34
  i("technospam.problems.solved", "Solved")
35
35
  ]
@@ -38,7 +38,7 @@ function V({ problem: e, solved: t, onOpen: n }) {
38
38
  children: [/* @__PURE__ */ D(c, {
39
39
  status: e.difficulty,
40
40
  kind: "level"
41
- }), e.isPremiumOnly ? /* @__PURE__ */ D(d, { locked: e.isLocked }) : null]
41
+ }), e.isPremiumOnly ? /* @__PURE__ */ D(f, { locked: e.isLocked }) : null]
42
42
  })]
43
43
  }), /* @__PURE__ */ O("div", {
44
44
  className: "flex flex-1 flex-col gap-3 p-4",
@@ -47,7 +47,10 @@ function V({ problem: e, solved: t, onOpen: n }) {
47
47
  className: "min-w-0",
48
48
  children: [/* @__PURE__ */ D("h3", {
49
49
  className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
50
- children: e.title
50
+ children: /* @__PURE__ */ D(m, {
51
+ onOpen: n,
52
+ children: e.title
53
+ })
51
54
  }), e.statement ? /* @__PURE__ */ D("p", {
52
55
  className: "mt-1 line-clamp-2 text-sm text-text-secondary",
53
56
  children: e.statement
@@ -75,7 +78,7 @@ function V({ problem: e, solved: t, onOpen: n }) {
75
78
  e.languages.length ? /* @__PURE__ */ O("span", {
76
79
  className: "inline-flex items-center gap-1",
77
80
  children: [
78
- /* @__PURE__ */ D(x, { size: 13 }),
81
+ /* @__PURE__ */ D(b, { size: 13 }),
79
82
  " ",
80
83
  e.languages.length === 1 ? i("technospam.problems.languages", "{{count}} lang", { count: e.languages.length }) : i("technospam.problems.languagesPlural", "{{count}} langs", { count: e.languages.length })
81
84
  ]
@@ -87,14 +90,14 @@ function V({ problem: e, solved: t, onOpen: n }) {
87
90
  children: [e.companies.slice(0, 3).map((e) => /* @__PURE__ */ O(k, {
88
91
  variant: "outline",
89
92
  className: "text-[11px] capitalize",
90
- children: [/* @__PURE__ */ D(y, {
93
+ children: [/* @__PURE__ */ D(v, {
91
94
  size: 10,
92
95
  className: "mr-1"
93
96
  }), e.replace(/-/g, " ")]
94
97
  }, e)), e.interviewFrequency === "HIGH" ? /* @__PURE__ */ O(k, {
95
98
  variant: "secondary",
96
99
  className: "text-[11px] text-status-warning-text",
97
- children: [/* @__PURE__ */ D(S, {
100
+ children: [/* @__PURE__ */ D(x, {
98
101
  size: 10,
99
102
  className: "mr-1"
100
103
  }), i("technospam.problems.frequentlyAsked", "Frequently asked")]
@@ -116,26 +119,26 @@ function V({ problem: e, solved: t, onOpen: n }) {
116
119
  });
117
120
  }
118
121
  function H() {
119
- let o = t(), { currentUser: s, workspaceId: c } = e(), { emit: d } = n(), y = r(), C = s?.id, [T, E] = v("ALL"), [k, j] = v("ALL"), [H, de] = v("ALL"), [U, fe] = v(""), [W, pe] = v(() => l(u())), G = g((e) => {
120
- pe(e), ee(u(), e);
121
- }, []), me = _(() => [
122
+ let o = t(), { currentUser: s, workspaceId: c } = e(), { emit: f } = n(), m = r(), v = s?.id, [C, T] = _("ALL"), [E, k] = _("ALL"), [j, H] = _("ALL"), [U, fe] = _(""), [W, pe] = _(() => l(u())), G = h((e) => {
123
+ pe(e), d(u(), e);
124
+ }, []), me = g(() => [
122
125
  {
123
126
  value: "ALL",
124
- label: y("technospam.problems.filterAll", "All")
127
+ label: m("technospam.problems.filterAll", "All")
125
128
  },
126
129
  {
127
130
  value: "EASY",
128
- label: y("technospam.problems.filterEasy", "Easy")
131
+ label: m("technospam.problems.filterEasy", "Easy")
129
132
  },
130
133
  {
131
134
  value: "MEDIUM",
132
- label: y("technospam.problems.filterMedium", "Medium")
135
+ label: m("technospam.problems.filterMedium", "Medium")
133
136
  },
134
137
  {
135
138
  value: "HARD",
136
- label: y("technospam.problems.filterHard", "Hard")
139
+ label: m("technospam.problems.filterHard", "Hard")
137
140
  }
138
- ], [y]), he = _(() => [
141
+ ], [m]), he = g(() => [
139
142
  {
140
143
  value: "google",
141
144
  label: "Google"
@@ -160,7 +163,7 @@ function H() {
160
163
  value: "netflix",
161
164
  label: "Netflix"
162
165
  }
163
- ], []), ge = _(() => [
166
+ ], []), ge = g(() => [
164
167
  {
165
168
  value: "frontend",
166
169
  label: "Frontend"
@@ -185,62 +188,62 @@ function H() {
185
188
  value: "sre",
186
189
  label: "SRE / Infra"
187
190
  }
188
- ], []), { limit: _e, more: ve } = ie(), { data: K, loading: q, error: J } = h({
191
+ ], []), { limit: _e, more: ve } = ae(), { data: K, loading: q, error: J } = oe({
189
192
  status: "PUBLISHED",
190
- pagination: re(_e),
191
- ...T === "ALL" ? {} : { difficulty: T },
192
- ...k === "ALL" ? {} : { company: k },
193
- ...H === "ALL" ? {} : { role: H }
194
- }), Y = ae(C), X = _(() => K?.tecListProblems?.items ?? [], [K]), Z = K?.tecListProblems?.pageInfo?.hasMore ?? !1, ye = X.filter((e) => Y.has(e.id)).length, be = X.filter((e) => e.difficulty === "EASY").length, xe = X.filter((e) => e.difficulty === "HARD").length, Q = _(() => {
193
+ pagination: ie(_e),
194
+ ...C === "ALL" ? {} : { difficulty: C },
195
+ ...E === "ALL" ? {} : { company: E },
196
+ ...j === "ALL" ? {} : { role: j }
197
+ }), Y = se(v), X = g(() => K?.tecListProblems?.items ?? [], [K]), Z = K?.tecListProblems?.pageInfo?.hasMore ?? !1, ye = X.filter((e) => Y.has(e.id)).length, be = X.filter((e) => e.difficulty === "EASY").length, xe = X.filter((e) => e.difficulty === "HARD").length, Q = g(() => {
195
198
  let e = U.trim().toLowerCase();
196
199
  return e ? X.filter((t) => t.title.toLowerCase().includes(e) || (t.topic ?? "").toLowerCase().includes(e) || t.tags.some((t) => t.toLowerCase().includes(e))) : X;
197
- }, [X, U]), $ = g((e) => {
198
- d("technospam.problem.viewed", {
200
+ }, [X, U]), $ = h((e) => {
201
+ f("technospam.problem.viewed", {
199
202
  workspaceId: c,
200
203
  entityId: e.id,
201
204
  entityType: "TEC_PROBLEM"
202
205
  }), o(`/applications/problem-details-page?id=${e.id}`);
203
206
  }, [
204
- d,
207
+ f,
205
208
  o,
206
209
  c
207
210
  ]);
208
211
  return /* @__PURE__ */ O(i, {
209
212
  hero: !0,
210
- title: y("technospam.problems.title", "Coding Problems"),
211
- description: y("technospam.problems.description", "Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty."),
213
+ title: m("technospam.problems.title", "Coding Problems"),
214
+ description: m("technospam.problems.description", "Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty."),
212
215
  children: [/* @__PURE__ */ O("div", {
213
216
  className: "mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4",
214
217
  children: [
215
218
  /* @__PURE__ */ D(a, {
216
- label: y("technospam.problems.statProblems", "Problems"),
219
+ label: m("technospam.problems.statProblems", "Problems"),
217
220
  value: X.length,
218
- icon: x,
221
+ icon: b,
219
222
  tone: "blue"
220
223
  }),
221
224
  /* @__PURE__ */ D(a, {
222
- label: y("technospam.problems.statSolved", "Solved"),
225
+ label: m("technospam.problems.statSolved", "Solved"),
223
226
  value: ye,
224
- icon: b,
227
+ icon: y,
225
228
  tone: "green"
226
229
  }),
227
230
  /* @__PURE__ */ D(a, {
228
- label: y("technospam.problems.statEasy", "Easy"),
231
+ label: m("technospam.problems.statEasy", "Easy"),
229
232
  value: be,
230
- icon: se,
233
+ icon: S,
231
234
  tone: "teal"
232
235
  }),
233
236
  /* @__PURE__ */ D(a, {
234
- label: y("technospam.problems.statHard", "Hard"),
237
+ label: m("technospam.problems.statHard", "Hard"),
235
238
  value: xe,
236
- icon: S,
239
+ icon: x,
237
240
  tone: "amber"
238
241
  })
239
242
  ]
240
243
  }), /* @__PURE__ */ O(L, {
241
244
  className: "gap-0",
242
- value: T,
243
- onValueChange: (e) => E(e),
245
+ value: C,
246
+ onValueChange: (e) => T(e),
244
247
  children: [
245
248
  /* @__PURE__ */ O("div", {
246
249
  className: "mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
@@ -249,18 +252,18 @@ function H() {
249
252
  children: e.label
250
253
  }, e.value)) }), /* @__PURE__ */ O("div", {
251
254
  className: "relative w-full sm:w-72",
252
- children: [/* @__PURE__ */ D(le, {
255
+ children: [/* @__PURE__ */ D(w, {
253
256
  className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted",
254
257
  size: 16
255
- }), /* @__PURE__ */ D(ue, {
258
+ }), /* @__PURE__ */ D(de, {
256
259
  className: "pl-9",
257
- "aria-label": y("technospam.problems.searchLabel", "Search problems"),
258
- placeholder: y("technospam.problems.searchPlaceholder", "Search problems…"),
260
+ "aria-label": m("technospam.problems.searchLabel", "Search problems"),
261
+ placeholder: m("technospam.problems.searchPlaceholder", "Search problems…"),
259
262
  value: U,
260
263
  onChange: (e) => fe(e.target.value),
261
264
  onBlur: () => {
262
265
  let e = U.trim();
263
- e && d("technospam.search.performed", {
266
+ e && f("technospam.search.performed", {
264
267
  workspaceId: c,
265
268
  entityType: "problem",
266
269
  queryLength: e.length
@@ -273,30 +276,30 @@ function H() {
273
276
  className: "mb-4 flex flex-col gap-3 sm:flex-row sm:items-center",
274
277
  children: [
275
278
  /* @__PURE__ */ O(M, {
276
- value: k,
277
- onValueChange: j,
279
+ value: E,
280
+ onValueChange: k,
278
281
  children: [/* @__PURE__ */ D(F, {
279
282
  className: "w-full sm:w-48",
280
- "aria-label": y("technospam.problems.companyFilterLabel", "Filter by company"),
281
- children: /* @__PURE__ */ D(I, { placeholder: y("technospam.problems.companyPlaceholder", "Company") })
283
+ "aria-label": m("technospam.problems.companyFilterLabel", "Filter by company"),
284
+ children: /* @__PURE__ */ D(I, { placeholder: m("technospam.problems.companyPlaceholder", "Company") })
282
285
  }), /* @__PURE__ */ O(N, { children: [/* @__PURE__ */ D(P, {
283
286
  value: "ALL",
284
- children: y("technospam.problems.companyAll", "All companies")
287
+ children: m("technospam.problems.companyAll", "All companies")
285
288
  }), he.map((e) => /* @__PURE__ */ D(P, {
286
289
  value: e.value,
287
290
  children: e.label
288
291
  }, e.value))] })]
289
292
  }),
290
293
  /* @__PURE__ */ O(M, {
291
- value: H,
292
- onValueChange: de,
294
+ value: j,
295
+ onValueChange: H,
293
296
  children: [/* @__PURE__ */ D(F, {
294
297
  className: "w-full sm:w-48",
295
- "aria-label": y("technospam.problems.roleFilterLabel", "Filter by role"),
296
- children: /* @__PURE__ */ D(I, { placeholder: y("technospam.problems.rolePlaceholder", "Role") })
298
+ "aria-label": m("technospam.problems.roleFilterLabel", "Filter by role"),
299
+ children: /* @__PURE__ */ D(I, { placeholder: m("technospam.problems.rolePlaceholder", "Role") })
297
300
  }), /* @__PURE__ */ O(N, { children: [/* @__PURE__ */ D(P, {
298
301
  value: "ALL",
299
- children: y("technospam.problems.roleAll", "All roles")
302
+ children: m("technospam.problems.roleAll", "All roles")
300
303
  }), ge.map((e) => /* @__PURE__ */ D(P, {
301
304
  value: e.value,
302
305
  children: e.label
@@ -304,7 +307,7 @@ function H() {
304
307
  }),
305
308
  /* @__PURE__ */ O("div", {
306
309
  role: "group",
307
- "aria-label": y("technospam.problems.viewLabel", "Catalog layout"),
310
+ "aria-label": m("technospam.problems.viewLabel", "Catalog layout"),
308
311
  className: "inline-flex items-center gap-1 self-start rounded-md border border-border-subtle bg-bg-surface p-1 sm:ml-auto sm:self-auto",
309
312
  children: [/* @__PURE__ */ O(A, {
310
313
  type: "button",
@@ -312,38 +315,38 @@ function H() {
312
315
  variant: W === "table" ? "secondary" : "ghost",
313
316
  "aria-pressed": W === "table",
314
317
  onClick: () => G("table"),
315
- children: [/* @__PURE__ */ D(ce, {
318
+ children: [/* @__PURE__ */ D(ue, {
316
319
  size: 14,
317
320
  className: "mr-1.5",
318
321
  "aria-hidden": "true"
319
- }), y("technospam.problems.viewTable", "Table")]
322
+ }), m("technospam.problems.viewTable", "Table")]
320
323
  }), /* @__PURE__ */ O(A, {
321
324
  type: "button",
322
325
  size: "sm",
323
326
  variant: W === "cards" ? "secondary" : "ghost",
324
327
  "aria-pressed": W === "cards",
325
328
  onClick: () => G("cards"),
326
- children: [/* @__PURE__ */ D(w, {
329
+ children: [/* @__PURE__ */ D(le, {
327
330
  size: 14,
328
331
  className: "mr-1.5",
329
332
  "aria-hidden": "true"
330
- }), y("technospam.problems.viewCards", "Cards")]
333
+ }), m("technospam.problems.viewCards", "Cards")]
331
334
  })]
332
335
  })
333
336
  ]
334
337
  }),
335
338
  /* @__PURE__ */ O(R, {
336
- value: T,
337
- className: oe,
339
+ value: C,
340
+ className: ce,
338
341
  children: [
339
- q && !X.length ? /* @__PURE__ */ D(ne, {}) : J ? /* @__PURE__ */ D(m, {
340
- title: y("technospam.common.errorLoadProblems", "Couldn't load problems"),
342
+ q && !X.length ? /* @__PURE__ */ D(p, {}) : J ? /* @__PURE__ */ D(re, {
343
+ title: m("technospam.common.errorLoadProblems", "Couldn't load problems"),
341
344
  error: J
342
- }) : Q.length === 0 ? /* @__PURE__ */ D(p, {
343
- icon: /* @__PURE__ */ D(x, { size: 26 }),
344
- title: U || T !== "ALL" || k !== "ALL" || H !== "ALL" ? y("technospam.problems.emptySearchTitle", "No matching problems") : y("technospam.problems.emptyDefaultTitle", "No problems published yet"),
345
- description: U || T !== "ALL" || k !== "ALL" || H !== "ALL" ? y("technospam.problems.emptySearchDesc", "Try a different search, difficulty, company, or role filter.") : y("technospam.problems.emptyDefaultDesc", "Published problems will appear here. Check back soon — TechnoSpam is pre-launch.")
346
- }) : W === "table" ? /* @__PURE__ */ D(f, {
345
+ }) : Q.length === 0 ? /* @__PURE__ */ D(ne, {
346
+ icon: /* @__PURE__ */ D(b, { size: 26 }),
347
+ title: U || C !== "ALL" || E !== "ALL" || j !== "ALL" ? m("technospam.problems.emptySearchTitle", "No matching problems") : m("technospam.problems.emptyDefaultTitle", "No problems published yet"),
348
+ description: U || C !== "ALL" || E !== "ALL" || j !== "ALL" ? m("technospam.problems.emptySearchDesc", "Try a different search, difficulty, company, or role filter.") : m("technospam.problems.emptyDefaultDesc", "Published problems will appear here. Check back soon — TechnoSpam is pre-launch.")
349
+ }) : W === "table" ? /* @__PURE__ */ D(ee, {
347
350
  problems: Q,
348
351
  solvedIds: Y,
349
352
  onOpen: $
@@ -357,10 +360,10 @@ function H() {
357
360
  }),
358
361
  Q.length > 0 && !J ? /* @__PURE__ */ D("p", {
359
362
  className: "mt-4 text-sm text-text-muted",
360
- children: Q.length < X.length ? y("technospam.problems.showingFiltered", "Showing {{shown}} of {{total}} loaded problems", {
363
+ children: Q.length < X.length ? m("technospam.problems.showingFiltered", "Showing {{shown}} of {{total}} loaded problems", {
361
364
  shown: Q.length,
362
365
  total: X.length
363
- }) : Z ? y("technospam.problems.showingMore", "Showing 1 to {{count}} problems — load more to see the rest", { count: Q.length }) : y("technospam.problems.showingAll", "Showing all {{count}} problems", { count: Q.length })
366
+ }) : Z ? m("technospam.problems.showingMore", "Showing 1 to {{count}} problems — load more to see the rest", { count: Q.length }) : m("technospam.problems.showingAll", "Showing all {{count}} problems", { count: Q.length })
364
367
  }) : null,
365
368
  /* @__PURE__ */ D(te, {
366
369
  hasMore: Z,
@@ -1 +1 @@
1
- {"version":3,"file":"ApplicationsProblemsPagePage.js","names":[],"sources":["../../../src/technospam/pages/ApplicationsProblemsPagePage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport {\n Building2,\n CheckCircle2,\n Code2,\n Flame,\n Gauge,\n LayoutGrid,\n Layers,\n List,\n Search,\n Tag,\n Trophy,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { TAB_PANEL_FOCUS_CLASS } from '../lib/a11y';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n MediaCover,\n PageLayout,\n PremiumBadge,\n ProblemsTable,\n StatCard,\n StatusBadge,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n usePageLimit,\n useProblemsQuery,\n useSolvedProblemIds,\n type TecProblem,\n type TecProblemDifficulty,\n} from '../api/technospamApi';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\nimport { useTr } from '../hooks/useTr';\nimport {\n readProblemCatalogView,\n safeLocalStorage,\n writeProblemCatalogView,\n type ProblemCatalogView,\n} from '../utils/problemCatalog';\n\nfunction ProblemCard({\n problem,\n solved,\n onOpen,\n}: {\n problem: TecProblem;\n solved: boolean;\n onOpen: () => void;\n}) {\n const tr = useTr();\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={`${problem.topic ?? ''} ${problem.difficulty} ${problem.title}`}\n icon={topicIcon(problem.topic ?? problem.title)}\n >\n {solved ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[11px] font-medium text-status-success-text ring-1 ring-status-success-border/30\">\n <CheckCircle2 size={12} /> {tr('technospam.problems.solved', 'Solved')}\n </span>\n ) : (\n <span />\n )}\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={problem.difficulty} kind=\"level\" />\n {problem.isPremiumOnly ? <PremiumBadge locked={problem.isLocked} /> : null}\n </div>\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 {problem.title}\n </h3>\n {problem.statement ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{problem.statement}</p>\n ) : null}\n </div>\n <div className=\"mt-auto flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n {problem.topic ? (\n <span className=\"inline-flex items-center gap-1\">\n <Layers size={13} /> {problem.topic}\n </span>\n ) : null}\n <span className=\"inline-flex items-center gap-1\">\n <Trophy size={13} />{' '}\n {tr('technospam.problems.points', '{{count}} pts', { count: problem.points })}\n </span>\n {problem.languages.length ? (\n <span className=\"inline-flex items-center gap-1\">\n <Code2 size={13} />{' '}\n {problem.languages.length === 1\n ? tr('technospam.problems.languages', '{{count}} lang', {\n count: problem.languages.length,\n })\n : tr('technospam.problems.languagesPlural', '{{count}} langs', {\n count: problem.languages.length,\n })}\n </span>\n ) : null}\n </div>\n {problem.companies.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {problem.companies.slice(0, 3).map((c) => (\n <Badge key={c} variant=\"outline\" className=\"text-[11px] capitalize\">\n <Building2 size={10} className=\"mr-1\" />\n {c.replace(/-/g, ' ')}\n </Badge>\n ))}\n {problem.interviewFrequency === 'HIGH' ? (\n <Badge variant=\"secondary\" className=\"text-[11px] text-status-warning-text\">\n <Flame size={10} className=\"mr-1\" />\n {tr('technospam.problems.frequentlyAsked', 'Frequently asked')}\n </Badge>\n ) : null}\n </div>\n ) : null}\n {problem.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {problem.tags.slice(0, 3).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n <Tag size={10} className=\"mr-1\" />\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function ApplicationsProblemsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const tr = useTr();\n const learnerId = currentUser?.id;\n const [difficulty, setDifficulty] = useState<'ALL' | TecProblemDifficulty>('ALL');\n const [company, setCompany] = useState<string>('ALL');\n const [role, setRole] = useState<string>('ALL');\n const [search, setSearch] = useState('');\n // The mock's data table is the default layout; the card grid stays available\n // as a compact visual view and the choice is remembered per viewer (BOFF-4077).\n const [view, setView] = useState<ProblemCatalogView>(() =>\n readProblemCatalogView(safeLocalStorage())\n );\n const changeView = useCallback((next: ProblemCatalogView) => {\n setView(next);\n writeProblemCatalogView(safeLocalStorage(), next);\n }, []);\n\n const difficulties = useMemo(\n () => [\n { value: 'ALL' as const, label: tr('technospam.problems.filterAll', 'All') },\n {\n value: 'EASY' as TecProblemDifficulty,\n label: tr('technospam.problems.filterEasy', 'Easy'),\n },\n {\n value: 'MEDIUM' as TecProblemDifficulty,\n label: tr('technospam.problems.filterMedium', 'Medium'),\n },\n {\n value: 'HARD' as TecProblemDifficulty,\n label: tr('technospam.problems.filterHard', 'Hard'),\n },\n ],\n [tr]\n );\n\n // Curated interview-target lists for the catalog filters. Values follow the\n // backend's lowercase-slug convention (see practice.service.ts normalizeSlug).\n const companies = useMemo(\n () => [\n { value: 'google', label: 'Google' },\n { value: 'amazon', label: 'Amazon' },\n { value: 'meta', label: 'Meta' },\n { value: 'microsoft', label: 'Microsoft' },\n { value: 'apple', label: 'Apple' },\n { value: 'netflix', label: 'Netflix' },\n ],\n []\n );\n\n const roles = useMemo(\n () => [\n { value: 'frontend', label: 'Frontend' },\n { value: 'backend', label: 'Backend' },\n { value: 'fullstack', label: 'Full-Stack' },\n { value: 'data-science', label: 'Data Science' },\n { value: 'mobile', label: 'Mobile' },\n { value: 'sre', label: 'SRE / Infra' },\n ],\n []\n );\n\n const { limit, more } = usePageLimit();\n const { data, loading, error } = useProblemsQuery({\n status: 'PUBLISHED',\n pagination: pageArg(limit),\n ...(difficulty !== 'ALL' ? { difficulty } : {}),\n ...(company !== 'ALL' ? { company } : {}),\n ...(role !== 'ALL' ? { role } : {}),\n });\n const solvedSet = useSolvedProblemIds(learnerId);\n\n const problems = useMemo(() => data?.tecListProblems?.items ?? [], [data]);\n const hasMore = data?.tecListProblems?.pageInfo?.hasMore ?? false;\n\n const solvedCount = problems.filter((p) => solvedSet.has(p.id)).length;\n const easyCount = problems.filter((p) => p.difficulty === 'EASY').length;\n const hardCount = problems.filter((p) => p.difficulty === 'HARD').length;\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return problems;\n return problems.filter(\n (p) =>\n p.title.toLowerCase().includes(q) ||\n (p.topic ?? '').toLowerCase().includes(q) ||\n p.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [problems, search]);\n\n const openProblem = useCallback(\n (problem: TecProblem) => {\n emit('technospam.problem.viewed', {\n workspaceId,\n entityId: problem.id,\n entityType: 'TEC_PROBLEM',\n });\n navigate(`/applications/problem-details-page?id=${problem.id}`);\n },\n [emit, navigate, workspaceId]\n );\n\n return (\n <PageLayout\n hero\n title={tr('technospam.problems.title', 'Coding Problems')}\n description={tr(\n 'technospam.problems.description',\n 'Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty.'\n )}\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label={tr('technospam.problems.statProblems', 'Problems')}\n value={problems.length}\n icon={Code2}\n tone=\"blue\"\n />\n <StatCard\n label={tr('technospam.problems.statSolved', 'Solved')}\n value={solvedCount}\n icon={CheckCircle2}\n tone=\"green\"\n />\n <StatCard\n label={tr('technospam.problems.statEasy', 'Easy')}\n value={easyCount}\n icon={Gauge}\n tone=\"teal\"\n />\n <StatCard\n label={tr('technospam.problems.statHard', 'Hard')}\n value={hardCount}\n icon={Flame}\n tone=\"amber\"\n />\n </div>\n\n {/* The tabs filter one list, so that list is their tab panel: Radix points every\n trigger's aria-controls at a panel id, and without a TabsContent the id\n resolved to nothing (axe aria-valid-attr-value, critical; BOFF-3157). */}\n <Tabs\n className=\"gap-0\"\n value={difficulty}\n onValueChange={(v) => setDifficulty(v as 'ALL' | TecProblemDifficulty)}\n >\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <TabsList>\n {difficulties.map((d) => (\n <TabsTrigger key={d.value} value={d.value}>\n {d.label}\n </TabsTrigger>\n ))}\n </TabsList>\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 aria-label={tr('technospam.problems.searchLabel', 'Search problems')}\n placeholder={tr('technospam.problems.searchPlaceholder', 'Search problems…')}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onBlur={() => {\n const value = search.trim();\n if (value) {\n emit('technospam.search.performed', {\n workspaceId,\n entityType: 'problem',\n queryLength: value.length,\n });\n }\n }}\n />\n </div>\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center\">\n <Select value={company} onValueChange={setCompany}>\n <SelectTrigger\n className=\"w-full sm:w-48\"\n aria-label={tr('technospam.problems.companyFilterLabel', 'Filter by company')}\n >\n <SelectValue placeholder={tr('technospam.problems.companyPlaceholder', 'Company')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">\n {tr('technospam.problems.companyAll', 'All companies')}\n </SelectItem>\n {companies.map((c) => (\n <SelectItem key={c.value} value={c.value}>\n {c.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={role} onValueChange={setRole}>\n <SelectTrigger\n className=\"w-full sm:w-48\"\n aria-label={tr('technospam.problems.roleFilterLabel', 'Filter by role')}\n >\n <SelectValue placeholder={tr('technospam.problems.rolePlaceholder', 'Role')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">{tr('technospam.problems.roleAll', 'All roles')}</SelectItem>\n {roles.map((r) => (\n <SelectItem key={r.value} value={r.value}>\n {r.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div\n role=\"group\"\n aria-label={tr('technospam.problems.viewLabel', 'Catalog layout')}\n className=\"inline-flex items-center gap-1 self-start rounded-md border border-border-subtle bg-bg-surface p-1 sm:ml-auto sm:self-auto\"\n >\n <Button\n type=\"button\"\n size=\"sm\"\n variant={view === 'table' ? 'secondary' : 'ghost'}\n aria-pressed={view === 'table'}\n onClick={() => changeView('table')}\n >\n <List size={14} className=\"mr-1.5\" aria-hidden=\"true\" />\n {tr('technospam.problems.viewTable', 'Table')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant={view === 'cards' ? 'secondary' : 'ghost'}\n aria-pressed={view === 'cards'}\n onClick={() => changeView('cards')}\n >\n <LayoutGrid size={14} className=\"mr-1.5\" aria-hidden=\"true\" />\n {tr('technospam.problems.viewCards', 'Cards')}\n </Button>\n </div>\n </div>\n\n <TabsContent value={difficulty} className={TAB_PANEL_FOCUS_CLASS}>\n {loading && !problems.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView\n title={tr('technospam.common.errorLoadProblems', \"Couldn't load problems\")}\n error={error}\n />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Code2 size={26} />}\n title={\n search || difficulty !== 'ALL' || company !== 'ALL' || role !== 'ALL'\n ? tr('technospam.problems.emptySearchTitle', 'No matching problems')\n : tr('technospam.problems.emptyDefaultTitle', 'No problems published yet')\n }\n description={\n search || difficulty !== 'ALL' || company !== 'ALL' || role !== 'ALL'\n ? tr(\n 'technospam.problems.emptySearchDesc',\n 'Try a different search, difficulty, company, or role filter.'\n )\n : tr(\n 'technospam.problems.emptyDefaultDesc',\n 'Published problems will appear here. Check back soon — TechnoSpam is pre-launch.'\n )\n }\n />\n ) : view === 'table' ? (\n <ProblemsTable problems={filtered} solvedIds={solvedSet} onOpen={openProblem} />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((problem) => (\n <ProblemCard\n key={problem.id}\n problem={problem}\n solved={solvedSet.has(problem.id)}\n onOpen={() => openProblem(problem)}\n />\n ))}\n </div>\n )}\n {filtered.length > 0 && !error ? (\n <p className=\"mt-4 text-sm text-text-muted\">\n {filtered.length < problems.length\n ? tr(\n 'technospam.problems.showingFiltered',\n 'Showing {{shown}} of {{total}} loaded problems',\n { shown: filtered.length, total: problems.length }\n )\n : hasMore\n ? tr(\n 'technospam.problems.showingMore',\n 'Showing 1 to {{count}} problems — load more to see the rest',\n { count: filtered.length }\n )\n : tr('technospam.problems.showingAll', 'Showing all {{count}} problems', {\n count: filtered.length,\n })}\n </p>\n ) : null}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </TabsContent>\n </Tabs>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ApplicationsProblemsPagePage.js","names":[],"sources":["../../../src/technospam/pages/ApplicationsProblemsPagePage.tsx"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport {\n Building2,\n CheckCircle2,\n Code2,\n Flame,\n Gauge,\n LayoutGrid,\n Layers,\n List,\n Search,\n Tag,\n Trophy,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { TAB_PANEL_FOCUS_CLASS } from '../lib/a11y';\nimport {\n CardOpenButton,\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n MediaCover,\n PageLayout,\n PremiumBadge,\n ProblemsTable,\n StatCard,\n StatusBadge,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n usePageLimit,\n useProblemsQuery,\n useSolvedProblemIds,\n type TecProblem,\n type TecProblemDifficulty,\n} from '../api/technospamApi';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\nimport { useTr } from '../hooks/useTr';\nimport {\n readProblemCatalogView,\n safeLocalStorage,\n writeProblemCatalogView,\n type ProblemCatalogView,\n} from '../utils/problemCatalog';\n\nfunction ProblemCard({\n problem,\n solved,\n onOpen,\n}: {\n problem: TecProblem;\n solved: boolean;\n onOpen: () => void;\n}) {\n const tr = useTr();\n return (\n <GlassCard className=\"group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\">\n <MediaCover\n seed={`${problem.topic ?? ''} ${problem.difficulty} ${problem.title}`}\n icon={topicIcon(problem.topic ?? problem.title)}\n >\n {solved ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[11px] font-medium text-status-success-text ring-1 ring-status-success-border/30\">\n <CheckCircle2 size={12} /> {tr('technospam.problems.solved', 'Solved')}\n </span>\n ) : (\n <span />\n )}\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={problem.difficulty} kind=\"level\" />\n {problem.isPremiumOnly ? <PremiumBadge locked={problem.isLocked} /> : null}\n </div>\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 <CardOpenButton onOpen={onOpen}>{problem.title}</CardOpenButton>\n </h3>\n {problem.statement ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{problem.statement}</p>\n ) : null}\n </div>\n <div className=\"mt-auto flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n {problem.topic ? (\n <span className=\"inline-flex items-center gap-1\">\n <Layers size={13} /> {problem.topic}\n </span>\n ) : null}\n <span className=\"inline-flex items-center gap-1\">\n <Trophy size={13} />{' '}\n {tr('technospam.problems.points', '{{count}} pts', { count: problem.points })}\n </span>\n {problem.languages.length ? (\n <span className=\"inline-flex items-center gap-1\">\n <Code2 size={13} />{' '}\n {problem.languages.length === 1\n ? tr('technospam.problems.languages', '{{count}} lang', {\n count: problem.languages.length,\n })\n : tr('technospam.problems.languagesPlural', '{{count}} langs', {\n count: problem.languages.length,\n })}\n </span>\n ) : null}\n </div>\n {problem.companies.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {problem.companies.slice(0, 3).map((c) => (\n <Badge key={c} variant=\"outline\" className=\"text-[11px] capitalize\">\n <Building2 size={10} className=\"mr-1\" />\n {c.replace(/-/g, ' ')}\n </Badge>\n ))}\n {problem.interviewFrequency === 'HIGH' ? (\n <Badge variant=\"secondary\" className=\"text-[11px] text-status-warning-text\">\n <Flame size={10} className=\"mr-1\" />\n {tr('technospam.problems.frequentlyAsked', 'Frequently asked')}\n </Badge>\n ) : null}\n </div>\n ) : null}\n {problem.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {problem.tags.slice(0, 3).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n <Tag size={10} className=\"mr-1\" />\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function ApplicationsProblemsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const tr = useTr();\n const learnerId = currentUser?.id;\n const [difficulty, setDifficulty] = useState<'ALL' | TecProblemDifficulty>('ALL');\n const [company, setCompany] = useState<string>('ALL');\n const [role, setRole] = useState<string>('ALL');\n const [search, setSearch] = useState('');\n // The mock's data table is the default layout; the card grid stays available\n // as a compact visual view and the choice is remembered per viewer (BOFF-4077).\n const [view, setView] = useState<ProblemCatalogView>(() =>\n readProblemCatalogView(safeLocalStorage())\n );\n const changeView = useCallback((next: ProblemCatalogView) => {\n setView(next);\n writeProblemCatalogView(safeLocalStorage(), next);\n }, []);\n\n const difficulties = useMemo(\n () => [\n { value: 'ALL' as const, label: tr('technospam.problems.filterAll', 'All') },\n {\n value: 'EASY' as TecProblemDifficulty,\n label: tr('technospam.problems.filterEasy', 'Easy'),\n },\n {\n value: 'MEDIUM' as TecProblemDifficulty,\n label: tr('technospam.problems.filterMedium', 'Medium'),\n },\n {\n value: 'HARD' as TecProblemDifficulty,\n label: tr('technospam.problems.filterHard', 'Hard'),\n },\n ],\n [tr]\n );\n\n // Curated interview-target lists for the catalog filters. Values follow the\n // backend's lowercase-slug convention (see practice.service.ts normalizeSlug).\n const companies = useMemo(\n () => [\n { value: 'google', label: 'Google' },\n { value: 'amazon', label: 'Amazon' },\n { value: 'meta', label: 'Meta' },\n { value: 'microsoft', label: 'Microsoft' },\n { value: 'apple', label: 'Apple' },\n { value: 'netflix', label: 'Netflix' },\n ],\n []\n );\n\n const roles = useMemo(\n () => [\n { value: 'frontend', label: 'Frontend' },\n { value: 'backend', label: 'Backend' },\n { value: 'fullstack', label: 'Full-Stack' },\n { value: 'data-science', label: 'Data Science' },\n { value: 'mobile', label: 'Mobile' },\n { value: 'sre', label: 'SRE / Infra' },\n ],\n []\n );\n\n const { limit, more } = usePageLimit();\n const { data, loading, error } = useProblemsQuery({\n status: 'PUBLISHED',\n pagination: pageArg(limit),\n ...(difficulty !== 'ALL' ? { difficulty } : {}),\n ...(company !== 'ALL' ? { company } : {}),\n ...(role !== 'ALL' ? { role } : {}),\n });\n const solvedSet = useSolvedProblemIds(learnerId);\n\n const problems = useMemo(() => data?.tecListProblems?.items ?? [], [data]);\n const hasMore = data?.tecListProblems?.pageInfo?.hasMore ?? false;\n\n const solvedCount = problems.filter((p) => solvedSet.has(p.id)).length;\n const easyCount = problems.filter((p) => p.difficulty === 'EASY').length;\n const hardCount = problems.filter((p) => p.difficulty === 'HARD').length;\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return problems;\n return problems.filter(\n (p) =>\n p.title.toLowerCase().includes(q) ||\n (p.topic ?? '').toLowerCase().includes(q) ||\n p.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [problems, search]);\n\n const openProblem = useCallback(\n (problem: TecProblem) => {\n emit('technospam.problem.viewed', {\n workspaceId,\n entityId: problem.id,\n entityType: 'TEC_PROBLEM',\n });\n navigate(`/applications/problem-details-page?id=${problem.id}`);\n },\n [emit, navigate, workspaceId]\n );\n\n return (\n <PageLayout\n hero\n title={tr('technospam.problems.title', 'Coding Problems')}\n description={tr(\n 'technospam.problems.description',\n 'Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty.'\n )}\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label={tr('technospam.problems.statProblems', 'Problems')}\n value={problems.length}\n icon={Code2}\n tone=\"blue\"\n />\n <StatCard\n label={tr('technospam.problems.statSolved', 'Solved')}\n value={solvedCount}\n icon={CheckCircle2}\n tone=\"green\"\n />\n <StatCard\n label={tr('technospam.problems.statEasy', 'Easy')}\n value={easyCount}\n icon={Gauge}\n tone=\"teal\"\n />\n <StatCard\n label={tr('technospam.problems.statHard', 'Hard')}\n value={hardCount}\n icon={Flame}\n tone=\"amber\"\n />\n </div>\n\n {/* The tabs filter one list, so that list is their tab panel: Radix points every\n trigger's aria-controls at a panel id, and without a TabsContent the id\n resolved to nothing (axe aria-valid-attr-value, critical; BOFF-3157). */}\n <Tabs\n className=\"gap-0\"\n value={difficulty}\n onValueChange={(v) => setDifficulty(v as 'ALL' | TecProblemDifficulty)}\n >\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <TabsList>\n {difficulties.map((d) => (\n <TabsTrigger key={d.value} value={d.value}>\n {d.label}\n </TabsTrigger>\n ))}\n </TabsList>\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 aria-label={tr('technospam.problems.searchLabel', 'Search problems')}\n placeholder={tr('technospam.problems.searchPlaceholder', 'Search problems…')}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onBlur={() => {\n const value = search.trim();\n if (value) {\n emit('technospam.search.performed', {\n workspaceId,\n entityType: 'problem',\n queryLength: value.length,\n });\n }\n }}\n />\n </div>\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center\">\n <Select value={company} onValueChange={setCompany}>\n <SelectTrigger\n className=\"w-full sm:w-48\"\n aria-label={tr('technospam.problems.companyFilterLabel', 'Filter by company')}\n >\n <SelectValue placeholder={tr('technospam.problems.companyPlaceholder', 'Company')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">\n {tr('technospam.problems.companyAll', 'All companies')}\n </SelectItem>\n {companies.map((c) => (\n <SelectItem key={c.value} value={c.value}>\n {c.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={role} onValueChange={setRole}>\n <SelectTrigger\n className=\"w-full sm:w-48\"\n aria-label={tr('technospam.problems.roleFilterLabel', 'Filter by role')}\n >\n <SelectValue placeholder={tr('technospam.problems.rolePlaceholder', 'Role')} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">{tr('technospam.problems.roleAll', 'All roles')}</SelectItem>\n {roles.map((r) => (\n <SelectItem key={r.value} value={r.value}>\n {r.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div\n role=\"group\"\n aria-label={tr('technospam.problems.viewLabel', 'Catalog layout')}\n className=\"inline-flex items-center gap-1 self-start rounded-md border border-border-subtle bg-bg-surface p-1 sm:ml-auto sm:self-auto\"\n >\n <Button\n type=\"button\"\n size=\"sm\"\n variant={view === 'table' ? 'secondary' : 'ghost'}\n aria-pressed={view === 'table'}\n onClick={() => changeView('table')}\n >\n <List size={14} className=\"mr-1.5\" aria-hidden=\"true\" />\n {tr('technospam.problems.viewTable', 'Table')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant={view === 'cards' ? 'secondary' : 'ghost'}\n aria-pressed={view === 'cards'}\n onClick={() => changeView('cards')}\n >\n <LayoutGrid size={14} className=\"mr-1.5\" aria-hidden=\"true\" />\n {tr('technospam.problems.viewCards', 'Cards')}\n </Button>\n </div>\n </div>\n\n <TabsContent value={difficulty} className={TAB_PANEL_FOCUS_CLASS}>\n {loading && !problems.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView\n title={tr('technospam.common.errorLoadProblems', \"Couldn't load problems\")}\n error={error}\n />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Code2 size={26} />}\n title={\n search || difficulty !== 'ALL' || company !== 'ALL' || role !== 'ALL'\n ? tr('technospam.problems.emptySearchTitle', 'No matching problems')\n : tr('technospam.problems.emptyDefaultTitle', 'No problems published yet')\n }\n description={\n search || difficulty !== 'ALL' || company !== 'ALL' || role !== 'ALL'\n ? tr(\n 'technospam.problems.emptySearchDesc',\n 'Try a different search, difficulty, company, or role filter.'\n )\n : tr(\n 'technospam.problems.emptyDefaultDesc',\n 'Published problems will appear here. Check back soon — TechnoSpam is pre-launch.'\n )\n }\n />\n ) : view === 'table' ? (\n <ProblemsTable problems={filtered} solvedIds={solvedSet} onOpen={openProblem} />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((problem) => (\n <ProblemCard\n key={problem.id}\n problem={problem}\n solved={solvedSet.has(problem.id)}\n onOpen={() => openProblem(problem)}\n />\n ))}\n </div>\n )}\n {filtered.length > 0 && !error ? (\n <p className=\"mt-4 text-sm text-text-muted\">\n {filtered.length < problems.length\n ? tr(\n 'technospam.problems.showingFiltered',\n 'Showing {{shown}} of {{total}} loaded problems',\n { shown: filtered.length, total: problems.length }\n )\n : hasMore\n ? tr(\n 'technospam.problems.showingMore',\n 'Showing 1 to {{count}} problems — load more to see the rest',\n { count: filtered.length }\n )\n : tr('technospam.problems.showingAll', 'Showing all {{count}} problems', {\n count: filtered.length,\n })}\n </p>\n ) : null}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </TabsContent>\n </Tabs>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-technospam",
3
- "version": "2026.1101.3",
3
+ "version": "2026.1101.4",
4
4
  "description": "Burdenoff TechnoSpam Microfrontend",
5
5
  "type": "module",
6
6
  "files": [