@burdenoff/microfe-technospam 2026.705.1 → 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.
Files changed (36) hide show
  1. package/dist/technospam/components/MediaCover.js +57 -0
  2. package/dist/technospam/components/MediaCover.js.map +1 -0
  3. package/dist/technospam/components/PageLayout.js +1 -1
  4. package/dist/technospam/components/PageLayout.js.map +1 -1
  5. package/dist/technospam/components/StatCard.js +19 -11
  6. package/dist/technospam/components/StatCard.js.map +1 -1
  7. package/dist/technospam/components/StatusBadge.js +1 -1
  8. package/dist/technospam/components/StatusBadge.js.map +1 -1
  9. package/dist/technospam/components/index.js +1 -0
  10. package/dist/technospam/pages/AdminAdminDashboardPagePage.js +525 -459
  11. package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
  12. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +167 -127
  13. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  14. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +178 -125
  15. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
  16. package/dist/technospam/pages/ApplicationsProblemsPagePage.js +77 -88
  17. package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
  18. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +287 -186
  19. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
  20. package/dist/technospam/pages/CoursesCoursesPagePage.js +76 -83
  21. package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
  22. package/dist/technospam/pages/CoursesMyLearningPagePage.js +119 -88
  23. package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
  24. package/dist/technospam/pages/DashboardDashboardPagePage.js +232 -199
  25. package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
  26. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +128 -106
  27. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
  28. package/dist/technospam/pages/HackathonsHackathonsPagePage.js +71 -78
  29. package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
  30. package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +165 -110
  31. package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
  32. package/dist/technospam/pages/MentorshipMentorsPagePage.js +210 -156
  33. package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
  34. package/dist/technospam/pages/MentorshipSessionsPagePage.js +59 -43
  35. package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
  36. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ApplicationsProblemDetailsPagePage.js","names":[],"sources":["../../../src/technospam/pages/ApplicationsProblemDetailsPagePage.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Clock, Code2, FileText, Layers, Send, Tag, Trophy } from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport {\n useProblemQuery,\n useSubmissionsQuery,\n useSubmitSolution,\n type TecSubmission,\n} from '../api/technospamApi';\nimport { formatDateTime, humanizeEnum } from '../utils/format';\nimport { notify } from '../lib/toast';\n\nconst FALLBACK_LANGUAGES = ['javascript', 'python', 'typescript'];\n\nfunction SubmissionRow({ s }: { s: TecSubmission }) {\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 border-b border-border-seam py-3 last:border-0\">\n <StatusBadge status={s.verdict} />\n <span className=\"inline-flex items-center gap-1 text-sm font-medium text-text-primary\">\n <Code2 size={13} /> {humanizeEnum(s.language)}\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Clock size={12} /> {s.runtimeMs} ms\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Trophy size={12} /> {s.pointsAwarded} pts\n </span>\n <span className=\"ml-auto text-xs text-text-muted\">{formatDateTime(s.createdAt)}</span>\n </div>\n );\n}\n\nexport function ApplicationsProblemDetailsPagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { currentUser } = useTechnoSpam();\n const learnerId = currentUser?.id;\n\n const { data, loading, error, refetch } = useProblemQuery(id);\n const {\n data: subsData,\n loading: subsLoading,\n error: subsError,\n refetch: refetchSubs,\n } = useSubmissionsQuery({ ...(learnerId ? { learnerId } : {}), problemId: id });\n const [submit, { loading: submitting }] = useSubmitSolution();\n\n const problem = data?.tecProblem ?? null;\n\n const languages = useMemo(\n () => (problem?.languages?.length ? problem.languages : FALLBACK_LANGUAGES),\n [problem]\n );\n\n const [language, setLanguage] = useState('');\n const [code, setCode] = useState('');\n const initedRef = useRef(false);\n\n useEffect(() => {\n if (problem && !initedRef.current) {\n setLanguage(problem.languages[0] ?? FALLBACK_LANGUAGES[0]!);\n setCode(problem.starterCode ?? '');\n initedRef.current = true;\n }\n }, [problem]);\n\n const submissions = useMemo(\n () =>\n [...(subsData?.tecListSubmissions.items ?? [])].sort(\n (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n ),\n [subsData]\n );\n\n const handleSubmit = async () => {\n if (!id) return;\n if (!language) {\n notify.error('Pick a language', 'Choose a language before submitting.');\n return;\n }\n if (!code.trim()) {\n notify.error('Add your solution', 'Write some code before submitting.');\n return;\n }\n const res = await submit({ variables: { input: { problemId: id, language, code } } });\n if (res.data?.tecSubmitSolution) {\n notify.success('Solution submitted', 'Your submission was recorded.');\n await Promise.all([refetch(), refetchSubs()]);\n }\n };\n\n if (loading && !problem) {\n return (\n <PageLayout title=\"Problem\" backPath=\"/applications/problems-page\">\n <Skeleton className=\"mb-4 h-28 w-full rounded-xl\" />\n <Skeleton className=\"h-72 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !problem) {\n return (\n <PageLayout title=\"Problem\" backPath=\"/applications/problems-page\">\n {error ? (\n <ErrorView title=\"Couldn't load problem\" error={error} />\n ) : (\n <EmptyView\n title=\"Problem not found\"\n description=\"This problem may have been unpublished.\"\n />\n )}\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n hero\n backPath=\"/applications/problems-page\"\n title={problem.title}\n description={problem.topic ?? undefined}\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-2\">\n <StatusBadge status={problem.difficulty} kind=\"level\" />\n <StatusBadge status={problem.status} />\n {problem.topic ? (\n <Badge variant=\"outline\" className=\"gap-1\">\n <Layers size={12} /> {problem.topic}\n </Badge>\n ) : null}\n {problem.tags.map((t) => (\n <Badge key={t} variant=\"secondary\">\n <Tag size={10} className=\"mr-1\" />\n {t}\n </Badge>\n ))}\n </div>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Points\" value={problem.points} icon={Trophy} />\n <StatCard label=\"Languages\" value={languages.length} icon={Code2} />\n <StatCard label=\"Difficulty\" value={humanizeEnum(problem.difficulty)} icon={Layers} />\n <StatCard label=\"My submissions\" value={submissions.length} icon={FileText} />\n </div>\n\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-3\">\n <div className=\"space-y-5 lg:col-span-2\">\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-2 text-base font-semibold text-text-primary\">Problem statement</h2>\n {problem.statement ? (\n <p className=\"whitespace-pre-wrap text-sm leading-relaxed text-text-secondary\">\n {problem.statement}\n </p>\n ) : (\n <p className=\"py-4 text-center text-sm text-text-muted\">\n The statement for this problem is being prepared.\n </p>\n )}\n </GlassCard>\n\n {problem.starterCode ? (\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-2 text-base font-semibold text-text-primary\">Starter code</h2>\n <pre className=\"max-h-72 overflow-auto rounded-xl bg-bg-sunken p-4 font-mono text-xs leading-relaxed text-text-primary\">\n {problem.starterCode}\n </pre>\n </GlassCard>\n ) : null}\n\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">Submit a solution</h2>\n <div className=\"space-y-3\">\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <span className=\"text-sm text-text-secondary sm:w-28\">Language</span>\n <Select value={language} onValueChange={setLanguage}>\n <SelectTrigger className=\"w-full sm:w-56\">\n <SelectValue placeholder=\"Choose a language\" />\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l} value={l}>\n {humanizeEnum(l)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <Textarea\n value={code}\n onChange={(e) => setCode(e.target.value)}\n placeholder=\"Write your solution…\"\n className=\"min-h-[240px] font-mono text-xs leading-relaxed\"\n spellCheck={false}\n />\n <div className=\"flex justify-end\">\n <Button onClick={handleSubmit} disabled={submitting || !code.trim()}>\n <Send size={16} /> {submitting ? 'Submitting…' : 'Submit solution'}\n </Button>\n </div>\n </div>\n </GlassCard>\n </div>\n\n <div className=\"lg:col-span-1\">\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">My submissions</h2>\n {subsLoading && !submissions.length ? (\n <LoadingRows count={3} height=\"h-12\" />\n ) : subsError ? (\n <ErrorView title=\"Couldn't load submissions\" error={subsError} />\n ) : submissions.length === 0 ? (\n <EmptyView\n icon={<FileText size={24} />}\n title=\"No submissions yet\"\n description=\"Submit a solution above to see your verdicts and points here.\"\n />\n ) : (\n <div>\n {submissions.map((s) => (\n <SubmissionRow key={s.id} s={s} />\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiCA,IAAM,IAAqB;CAAC;CAAc;CAAU;CAAa;AAEjE,SAAS,EAAc,EAAE,QAA2B;AAClD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAa,QAAQ,EAAE,SAAW,CAAA;GAClC,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;KAAE,EAAa,EAAE,SAAS;KACxC;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;KAAE,EAAE;KAAU;KAC5B;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;KAAE,EAAE;KAAc;KACjC;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAmC,EAAe,EAAE,UAAU;IAAQ,CAAA;GAClF;;;AAIV,SAAgB,IAAqC;CACnD,IAAM,CAAC,KAAU,GAAiB,EAC5B,IAAK,EAAO,IAAI,KAAK,IAAI,IACzB,EAAE,mBAAgB,GAAe,EACjC,IAAY,GAAa,IAEzB,EAAE,SAAM,YAAS,UAAO,eAAY,EAAgB,EAAG,EACvD,EACJ,MAAM,GACN,SAAS,GACT,OAAO,GACP,SAAS,MACP,EAAoB;EAAE,GAAI,IAAY,EAAE,cAAW,GAAG,EAAE;EAAG,WAAW;EAAI,CAAC,EACzE,CAAC,GAAQ,EAAE,SAAS,OAAgB,GAAmB,EAEvD,IAAU,GAAM,cAAc,MAE9B,IAAY,QACT,GAAS,WAAW,SAAS,EAAQ,YAAY,GACxD,CAAC,EAAQ,CACV,EAEK,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,IAAY,EAAO,GAAM;AAE/B,SAAgB;AACd,EAAI,KAAW,CAAC,EAAU,YACxB,EAAY,EAAQ,UAAU,MAAM,EAAmB,GAAI,EAC3D,EAAQ,EAAQ,eAAe,GAAG,EAClC,EAAU,UAAU;IAErB,CAAC,EAAQ,CAAC;CAEb,IAAM,IAAc,QAEhB,CAAC,GAAI,GAAU,mBAAmB,SAAS,EAAE,CAAE,CAAC,MAC7C,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CAC5E,EACH,CAAC,EAAS,CACX;AA2CD,QAxBI,KAAW,CAAC,IAEZ,kBAAC,GAAD;EAAY,OAAM;EAAU,UAAS;YAArC,CACE,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA,EACpD,kBAAC,GAAD,EAAU,WAAU,0BAA2B,CAAA,CACpC;MAIb,KAAS,CAAC,IAEV,kBAAC,GAAD;EAAY,OAAM;EAAU,UAAS;YAClC,IACC,kBAAC,GAAD;GAAW,OAAM;GAA+B;GAAS,CAAA,GAEzD,kBAAC,GAAD;GACE,OAAM;GACN,aAAY;GACZ,CAAA;EAEO,CAAA,GAKf,kBAAC,GAAD;EACE,MAAA;EACA,UAAS;EACT,OAAO,EAAQ;EACf,aAAa,EAAQ,SAAS,KAAA;YAJhC;GAME,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAa,QAAQ,EAAQ;MAAY,MAAK;MAAU,CAAA;KACxD,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA;KACtC,EAAQ,QACP,kBAAC,GAAD;MAAO,SAAQ;MAAU,WAAU;gBAAnC;OACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;OAAE,EAAQ;OACxB;UACN;KACH,EAAQ,KAAK,KAAK,MACjB,kBAAC,GAAD;MAAe,SAAQ;gBAAvB,CACE,kBAAC,GAAD;OAAK,MAAM;OAAI,WAAU;OAAS,CAAA,EACjC,EACK;QAHI,EAGJ,CACR;KACE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,OAAM;MAAS,OAAO,EAAQ;MAAQ,MAAM;MAAU,CAAA;KAChE,kBAAC,GAAD;MAAU,OAAM;MAAY,OAAO,EAAU;MAAQ,MAAM;MAAS,CAAA;KACpE,kBAAC,GAAD;MAAU,OAAM;MAAa,OAAO,EAAa,EAAQ,WAAW;MAAE,MAAM;MAAU,CAAA;KACtF,kBAAC,GAAD;MAAU,OAAM;MAAiB,OAAO,EAAY;MAAQ,MAAM;MAAY,CAAA;KAC1E;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAW,WAAU;iBAArB,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAiD;QAAsB,CAAA,EACpF,EAAQ,YACP,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAQ;QACP,CAAA,GAEJ,kBAAC,KAAD;QAAG,WAAU;kBAA2C;QAEpD,CAAA,CAEI;;MAEX,EAAQ,cACP,kBAAC,GAAD;OAAW,WAAU;iBAArB,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAiD;QAAiB,CAAA,EAChF,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAQ;QACL,CAAA,CACI;WACV;MAEJ,kBAAC,GAAD;OAAW,WAAU;iBAArB,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAiD;QAAsB,CAAA,EACrF,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsC;WAAe,CAAA,EACrE,kBAAC,GAAD;WAAQ,OAAO;WAAU,eAAe;qBAAxC,CACE,kBAAC,IAAD;YAAe,WAAU;sBACvB,kBAAC,IAAD,EAAa,aAAY,qBAAsB,CAAA;YACjC,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAU,KAAK,MACd,kBAAC,IAAD;YAAoB,OAAO;sBACxB,EAAa,EAAE;YACL,EAFI,EAEJ,CACb,EACY,CAAA,CACT;aACL;;SACN,kBAAC,IAAD;UACE,OAAO;UACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;UACxC,aAAY;UACZ,WAAU;UACV,YAAY;UACZ,CAAA;SACF,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD;WAAQ,SAzHD,YAAY;AAC1B,mBACL;iBAAI,CAAC,GAAU;AACb,gBAAO,MAAM,mBAAmB,uCAAuC;AACvE;;AAEF,iBAAI,CAAC,EAAK,MAAM,EAAE;AAChB,gBAAO,MAAM,qBAAqB,qCAAqC;AACvE;;AAGF,cADY,MAAM,EAAO,EAAE,WAAW,EAAE,OAAO;cAAE,WAAW;cAAI;cAAU;cAAM,EAAE,EAAE,CAAC,EAC7E,MAAM,sBACZ,EAAO,QAAQ,sBAAsB,gCAAgC,EACrE,MAAM,QAAQ,IAAI,CAAC,GAAS,EAAE,GAAa,CAAC,CAAC;;;WA4GJ,UAAU,KAAc,CAAC,EAAK,MAAM;qBAAnE;YACE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;;YAAE,IAAa,gBAAgB;YAC1C;;UACL,CAAA;SACF;UACI;;MACR;QAEN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAW,WAAU;gBAArB,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAiD;OAAmB,CAAA,EACjF,KAAe,CAAC,EAAY,SAC3B,kBAAC,IAAD;OAAa,OAAO;OAAG,QAAO;OAAS,CAAA,GACrC,IACF,kBAAC,GAAD;OAAW,OAAM;OAA4B,OAAO;OAAa,CAAA,GAC/D,EAAY,WAAW,IACzB,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;OAC5B,OAAM;OACN,aAAY;OACZ,CAAA,GAEF,kBAAC,OAAD,EAAA,UACG,EAAY,KAAK,MAChB,kBAAC,GAAD,EAA6B,MAAK,EAAd,EAAE,GAAY,CAClC,EACE,CAAA,CAEE;;KACR,CAAA,CACF;;GACK"}
1
+ {"version":3,"file":"ApplicationsProblemDetailsPagePage.js","names":[],"sources":["../../../src/technospam/pages/ApplicationsProblemDetailsPagePage.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Clock, Code2, FileText, Layers, Send, Tag, Trophy } from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport {\n useProblemQuery,\n useSubmissionsQuery,\n useSubmitSolution,\n type TecSubmission,\n} from '../api/technospamApi';\nimport { formatDateTime, humanizeEnum } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport { notify } from '../lib/toast';\n\nconst FALLBACK_LANGUAGES = ['javascript', 'python', 'typescript'];\n\n/**\n * A dark, editor-window styled code surface: mac-style traffic-light dots plus a\n * language label header over a scrollable monospace body so read-only code reads\n * like a real IDE panel rather than a flat block.\n */\nfunction CodePanel({\n label,\n children,\n bodyClassName,\n}: {\n label: string;\n children: ReactNode;\n bodyClassName?: string;\n}) {\n return (\n <div className=\"overflow-hidden rounded-xl border border-border-strong bg-bg-sunken shadow-sm\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam bg-bg-canvas/40 px-4 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-error-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-warning-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-success-border\" />\n </div>\n <span className=\"inline-flex items-center gap-1.5 font-mono text-xs text-text-muted\">\n <Code2 size={13} /> {label}\n </span>\n </div>\n <pre\n className={cn(\n 'overflow-auto p-4 font-mono text-xs leading-relaxed text-text-primary',\n bodyClassName\n )}\n >\n {children}\n </pre>\n </div>\n );\n}\n\nfunction SubmissionRow({ s }: { s: TecSubmission }) {\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 rounded-lg border border-transparent px-2 py-3 transition-colors hover:border-border-seam hover:bg-bg-sunken\">\n <StatusBadge status={s.verdict} />\n <span className=\"inline-flex items-center gap-1 text-sm font-medium text-text-primary\">\n <Code2 size={13} /> {humanizeEnum(s.language)}\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Clock size={12} /> {s.runtimeMs} ms\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Trophy size={12} /> {s.pointsAwarded} pts\n </span>\n <span className=\"ml-auto text-xs text-text-muted\">{formatDateTime(s.createdAt)}</span>\n </div>\n );\n}\n\nexport function ApplicationsProblemDetailsPagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { currentUser } = useTechnoSpam();\n const learnerId = currentUser?.id;\n\n const { data, loading, error, refetch } = useProblemQuery(id);\n const {\n data: subsData,\n loading: subsLoading,\n error: subsError,\n refetch: refetchSubs,\n } = useSubmissionsQuery({ ...(learnerId ? { learnerId } : {}), problemId: id });\n const [submit, { loading: submitting }] = useSubmitSolution();\n\n const problem = data?.tecProblem ?? null;\n\n const languages = useMemo(\n () => (problem?.languages?.length ? problem.languages : FALLBACK_LANGUAGES),\n [problem]\n );\n\n const [language, setLanguage] = useState('');\n const [code, setCode] = useState('');\n const initedRef = useRef(false);\n\n useEffect(() => {\n if (problem && !initedRef.current) {\n setLanguage(problem.languages[0] ?? FALLBACK_LANGUAGES[0]!);\n setCode(problem.starterCode ?? '');\n initedRef.current = true;\n }\n }, [problem]);\n\n const submissions = useMemo(\n () =>\n [...(subsData?.tecListSubmissions.items ?? [])].sort(\n (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n ),\n [subsData]\n );\n\n const handleSubmit = async () => {\n if (!id) return;\n if (!language) {\n notify.error('Pick a language', 'Choose a language before submitting.');\n return;\n }\n if (!code.trim()) {\n notify.error('Add your solution', 'Write some code before submitting.');\n return;\n }\n const res = await submit({ variables: { input: { problemId: id, language, code } } });\n if (res.data?.tecSubmitSolution) {\n notify.success('Solution submitted', 'Your submission was recorded.');\n await Promise.all([refetch(), refetchSubs()]);\n }\n };\n\n if (loading && !problem) {\n return (\n <PageLayout title=\"Problem\" backPath=\"/applications/problems-page\">\n <Skeleton className=\"mb-4 h-28 w-full rounded-xl\" />\n <Skeleton className=\"h-72 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !problem) {\n return (\n <PageLayout title=\"Problem\" backPath=\"/applications/problems-page\">\n {error ? (\n <ErrorView title=\"Couldn't load problem\" error={error} />\n ) : (\n <EmptyView\n title=\"Problem not found\"\n description=\"This problem may have been unpublished.\"\n />\n )}\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n hero\n backPath=\"/applications/problems-page\"\n title={problem.title}\n description={problem.topic ?? undefined}\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-2\">\n <StatusBadge status={problem.difficulty} kind=\"level\" />\n <StatusBadge status={problem.status} />\n {problem.topic ? (\n <Badge variant=\"outline\" className=\"gap-1\">\n <Layers size={12} /> {problem.topic}\n </Badge>\n ) : null}\n {problem.tags.map((t) => (\n <Badge key={t} variant=\"secondary\">\n <Tag size={10} className=\"mr-1\" />\n {t}\n </Badge>\n ))}\n </div>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Points\" value={problem.points} icon={Trophy} tone=\"amber\" />\n <StatCard label=\"Languages\" value={languages.length} icon={Code2} tone=\"blue\" />\n <StatCard\n label=\"Difficulty\"\n value={humanizeEnum(problem.difficulty)}\n icon={Layers}\n tone=\"purple\"\n />\n <StatCard label=\"My submissions\" value={submissions.length} icon={FileText} tone=\"teal\" />\n </div>\n\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-3\">\n <div className=\"space-y-5 lg:col-span-2\">\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-2 text-base font-semibold text-text-primary\">Problem statement</h2>\n {problem.statement ? (\n <p className=\"whitespace-pre-wrap text-sm leading-relaxed text-text-secondary\">\n {problem.statement}\n </p>\n ) : (\n <p className=\"py-4 text-center text-sm text-text-muted\">\n The statement for this problem is being prepared.\n </p>\n )}\n </GlassCard>\n\n {problem.starterCode ? (\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">Starter code</h2>\n <CodePanel label={humanizeEnum(languages[0] ?? 'code')} bodyClassName=\"max-h-72\">\n {problem.starterCode}\n </CodePanel>\n </GlassCard>\n ) : null}\n\n <GlassCard className=\"p-5\">\n <div className=\"mb-3 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <h2 className=\"text-base font-semibold text-text-primary\">Submit a solution</h2>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Language</span>\n <Select value={language} onValueChange={setLanguage}>\n <SelectTrigger className=\"w-full sm:w-48\">\n <SelectValue placeholder=\"Choose a language\" />\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l} value={l}>\n {humanizeEnum(l)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <div className=\"overflow-hidden rounded-xl border border-border-strong bg-bg-sunken shadow-sm\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border-seam bg-bg-canvas/40 px-4 py-2\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-error-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-warning-border\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-status-success-border\" />\n </div>\n <span className=\"inline-flex items-center gap-1.5 font-mono text-xs text-text-muted\">\n <Code2 size={13} /> {language ? humanizeEnum(language) : 'solution'}\n </span>\n </div>\n <Textarea\n value={code}\n onChange={(e) => setCode(e.target.value)}\n placeholder=\"Write your solution…\"\n className=\"min-h-[280px] resize-y rounded-none border-0 bg-transparent font-mono text-xs leading-relaxed focus-visible:ring-0 focus-visible:ring-offset-0\"\n spellCheck={false}\n />\n </div>\n\n <Button\n className=\"mt-4 w-full\"\n onClick={handleSubmit}\n disabled={submitting || !code.trim()}\n >\n <Send size={16} /> {submitting ? 'Submitting…' : 'Submit solution'}\n </Button>\n </GlassCard>\n </div>\n\n <div className=\"lg:col-span-1\">\n <GlassCard className=\"p-5\">\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">My submissions</h2>\n {subsLoading && !submissions.length ? (\n <LoadingRows count={3} height=\"h-12\" />\n ) : subsError ? (\n <ErrorView title=\"Couldn't load submissions\" error={subsError} />\n ) : submissions.length === 0 ? (\n <EmptyView\n icon={<FileText size={24} />}\n title=\"No submissions yet\"\n description=\"Submit a solution above to see your verdicts and points here.\"\n />\n ) : (\n <div className=\"space-y-1\">\n {submissions.map((s) => (\n <SubmissionRow key={s.id} s={s} />\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkCA,IAAM,IAAqB;CAAC;CAAc;CAAU;CAAa;AAOjE,SAAS,EAAU,EACjB,UACA,aACA,oBAKC;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD,EAAM,WAAU,mDAAoD,CAAA;KACpE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;KACtE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;KAClE;OACN,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;KAAE;KAChB;MACH;MACN,kBAAC,OAAD;GACE,WAAW,EACT,yEACA,EACD;GAEA;GACG,CAAA,CACF;;;AAIV,SAAS,EAAc,EAAE,QAA2B;AAClD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAa,QAAQ,EAAE,SAAW,CAAA;GAClC,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;KAAE,EAAa,EAAE,SAAS;KACxC;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;KAAE,EAAE;KAAU;KAC5B;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;KAAE,EAAE;KAAc;KACjC;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAmC,EAAe,EAAE,UAAU;IAAQ,CAAA;GAClF;;;AAIV,SAAgB,IAAqC;CACnD,IAAM,CAAC,KAAU,GAAiB,EAC5B,IAAK,EAAO,IAAI,KAAK,IAAI,IACzB,EAAE,mBAAgB,GAAe,EACjC,IAAY,GAAa,IAEzB,EAAE,SAAM,YAAS,UAAO,eAAY,EAAgB,EAAG,EACvD,EACJ,MAAM,GACN,SAAS,GACT,OAAO,GACP,SAAS,MACP,GAAoB;EAAE,GAAI,IAAY,EAAE,cAAW,GAAG,EAAE;EAAG,WAAW;EAAI,CAAC,EACzE,CAAC,GAAQ,EAAE,SAAS,OAAgB,GAAmB,EAEvD,IAAU,GAAM,cAAc,MAE9B,IAAY,QACT,GAAS,WAAW,SAAS,EAAQ,YAAY,GACxD,CAAC,EAAQ,CACV,EAEK,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,IAAY,EAAO,GAAM;AAE/B,SAAgB;AACd,EAAI,KAAW,CAAC,EAAU,YACxB,EAAY,EAAQ,UAAU,MAAM,EAAmB,GAAI,EAC3D,EAAQ,EAAQ,eAAe,GAAG,EAClC,EAAU,UAAU;IAErB,CAAC,EAAQ,CAAC;CAEb,IAAM,IAAc,QAEhB,CAAC,GAAI,GAAU,mBAAmB,SAAS,EAAE,CAAE,CAAC,MAC7C,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CAC5E,EACH,CAAC,EAAS,CACX;AA2CD,QAxBI,KAAW,CAAC,IAEZ,kBAAC,GAAD;EAAY,OAAM;EAAU,UAAS;YAArC,CACE,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA,EACpD,kBAAC,GAAD,EAAU,WAAU,0BAA2B,CAAA,CACpC;MAIb,KAAS,CAAC,IAEV,kBAAC,GAAD;EAAY,OAAM;EAAU,UAAS;YAClC,IACC,kBAAC,GAAD;GAAW,OAAM;GAA+B;GAAS,CAAA,GAEzD,kBAAC,GAAD;GACE,OAAM;GACN,aAAY;GACZ,CAAA;EAEO,CAAA,GAKf,kBAAC,GAAD;EACE,MAAA;EACA,UAAS;EACT,OAAO,EAAQ;EACf,aAAa,EAAQ,SAAS,KAAA;YAJhC;GAME,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAa,QAAQ,EAAQ;MAAY,MAAK;MAAU,CAAA;KACxD,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA;KACtC,EAAQ,QACP,kBAAC,GAAD;MAAO,SAAQ;MAAU,WAAU;gBAAnC;OACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;OAAE,EAAQ;OACxB;UACN;KACH,EAAQ,KAAK,KAAK,MACjB,kBAAC,GAAD;MAAe,SAAQ;gBAAvB,CACE,kBAAC,GAAD;OAAK,MAAM;OAAI,WAAU;OAAS,CAAA,EACjC,EACK;QAHI,EAGJ,CACR;KACE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,OAAM;MAAS,OAAO,EAAQ;MAAQ,MAAM;MAAQ,MAAK;MAAU,CAAA;KAC7E,kBAAC,GAAD;MAAU,OAAM;MAAY,OAAO,EAAU;MAAQ,MAAM;MAAO,MAAK;MAAS,CAAA;KAChF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAa,EAAQ,WAAW;MACvC,MAAM;MACN,MAAK;MACL,CAAA;KACF,kBAAC,GAAD;MAAU,OAAM;MAAiB,OAAO,EAAY;MAAQ,MAAM;MAAU,MAAK;MAAS,CAAA;KACtF;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAW,WAAU;iBAArB,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAiD;QAAsB,CAAA,EACpF,EAAQ,YACP,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAQ;QACP,CAAA,GAEJ,kBAAC,KAAD;QAAG,WAAU;kBAA2C;QAEpD,CAAA,CAEI;;MAEX,EAAQ,cACP,kBAAC,GAAD;OAAW,WAAU;iBAArB,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAiD;QAAiB,CAAA,EAChF,kBAAC,GAAD;QAAW,OAAO,EAAa,EAAU,MAAM,OAAO;QAAE,eAAc;kBACnE,EAAQ;QACC,CAAA,CACF;WACV;MAEJ,kBAAC,GAAD;OAAW,WAAU;iBAArB;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAA4C;UAAsB,CAAA,EAChF,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAA8B;WAAe,CAAA,EAC7D,kBAAC,IAAD;WAAQ,OAAO;WAAU,eAAe;qBAAxC,CACE,kBAAC,IAAD;YAAe,WAAU;sBACvB,kBAAC,IAAD,EAAa,aAAY,qBAAsB,CAAA;YACjC,CAAA,EAChB,kBAAC,IAAD,EAAA,UACG,EAAU,KAAK,MACd,kBAAC,IAAD;YAAoB,OAAO;sBACxB,EAAa,EAAE;YACL,EAFI,EAEJ,CACb,EACY,CAAA,CACT;aACL;YACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,QAAD,EAAM,WAAU,mDAAoD,CAAA;YACpE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;YACtE,kBAAC,QAAD,EAAM,WAAU,qDAAsD,CAAA;YAClE;cACN,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;YAAE,IAAW,EAAa,EAAS,GAAG;YACpD;aACH;aACN,kBAAC,GAAD;UACE,OAAO;UACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;UACxC,aAAY;UACZ,WAAU;UACV,YAAY;UACZ,CAAA,CACE;;QAEN,kBAAC,GAAD;SACE,WAAU;SACV,SA9IS,YAAY;AAC1B,iBACL;eAAI,CAAC,GAAU;AACb,cAAO,MAAM,mBAAmB,uCAAuC;AACvE;;AAEF,eAAI,CAAC,EAAK,MAAM,EAAE;AAChB,cAAO,MAAM,qBAAqB,qCAAqC;AACvE;;AAGF,YADY,MAAM,EAAO,EAAE,WAAW,EAAE,OAAO;YAAE,WAAW;YAAI;YAAU;YAAM,EAAE,EAAE,CAAC,EAC7E,MAAM,sBACZ,EAAO,QAAQ,sBAAsB,gCAAgC,EACrE,MAAM,QAAQ,IAAI,CAAC,GAAS,EAAE,GAAa,CAAC,CAAC;;;SAkIrC,UAAU,KAAc,CAAC,EAAK,MAAM;mBAHtC;UAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;;UAAE,IAAa,gBAAgB;UAC1C;;QACC;;MACR;QAEN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAW,WAAU;gBAArB,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAiD;OAAmB,CAAA,EACjF,KAAe,CAAC,EAAY,SAC3B,kBAAC,GAAD;OAAa,OAAO;OAAG,QAAO;OAAS,CAAA,GACrC,IACF,kBAAC,GAAD;OAAW,OAAM;OAA4B,OAAO;OAAa,CAAA,GAC/D,EAAY,WAAW,IACzB,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;OAC5B,OAAM;OACN,aAAY;OACZ,CAAA,GAEF,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAY,KAAK,MAChB,kBAAC,GAAD,EAA6B,MAAK,EAAd,EAAE,GAAY,CAClC;OACE,CAAA,CAEE;;KACR,CAAA,CACF;;GACK"}
@@ -1,17 +1,18 @@
1
1
  import { useTechnoSpam as e, useTechnoSpamNavigate as t } from "../providers/TechnoSpamProvider.js";
2
2
  import { PageLayout as n } from "../components/PageLayout.js";
3
3
  import { StatCard as r } from "../components/StatCard.js";
4
- import { StatusBadge as i } from "../components/StatusBadge.js";
5
- import { LoadMore as a } from "../components/LoadMore.js";
6
- import { EmptyView as o, ErrorView as s, LoadingGrid as c } from "../components/StateViews.js";
4
+ import { MediaCover as i, topicIcon as a } from "../components/MediaCover.js";
5
+ import { StatusBadge as o } from "../components/StatusBadge.js";
6
+ import { LoadMore as s } from "../components/LoadMore.js";
7
+ import { EmptyView as c, ErrorView as l, LoadingGrid as u } from "../components/StateViews.js";
7
8
  import "../components/index.js";
8
- import { pageArg as l, usePageLimit as u, useProblemsQuery as d, useSubmissionsQuery as f } from "../api/technospamApi.js";
9
- import { useMemo as p, useState as m } from "react";
10
- import { CheckCircle2 as h, Code2 as g, Flame as _, Gauge as v, Layers as y, Search as b, Tag as x, Trophy as S } from "lucide-react";
11
- import { jsx as C, jsxs as w } from "react/jsx-runtime";
12
- import { Badge as T, GlassCard as E, Input as D, Tabs as O, TabsList as k, TabsTrigger as A } from "@burdenoff/fe-libs/ui";
9
+ import { pageArg as d, usePageLimit as f, useProblemsQuery as p, useSubmissionsQuery as m } from "../api/technospamApi.js";
10
+ import { useMemo as h, useState as g } from "react";
11
+ import { CheckCircle2 as _, Code2 as v, Flame as y, Gauge as b, Layers as x, Search as S, Tag as C, Trophy as w } from "lucide-react";
12
+ import { jsx as T, jsxs as E } from "react/jsx-runtime";
13
+ import { Badge as D, GlassCard as O, Input as k, Tabs as A, TabsList as j, TabsTrigger as M } from "@burdenoff/fe-libs/ui";
13
14
  //#region src/technospam/pages/ApplicationsProblemsPagePage.tsx
14
- var j = [
15
+ var N = [
15
16
  {
16
17
  value: "ALL",
17
18
  label: "All"
@@ -29,73 +30,57 @@ var j = [
29
30
  label: "Hard"
30
31
  }
31
32
  ];
32
- function M(e) {
33
- let t = [
34
- "from-accent-primary/25 to-accent-teal/20",
35
- "from-accent-teal/25 to-accent-primary/15",
36
- "from-status-success-bg-subtle to-accent-wash",
37
- "from-accent-wash to-bg-sunken"
38
- ], n = 0;
39
- for (let t = 0; t < e.length; t += 1) n = n * 31 + e.charCodeAt(t) >>> 0;
40
- return t[n % t.length];
41
- }
42
- function N({ problem: e, solved: t, onOpen: n }) {
43
- return /* @__PURE__ */ w(E, {
44
- className: "group flex cursor-pointer flex-col overflow-hidden transition-shadow hover:shadow-md",
33
+ function P({ problem: e, solved: t, onOpen: n }) {
34
+ return /* @__PURE__ */ E(O, {
35
+ className: "group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg",
45
36
  onClick: n,
46
- children: [/* @__PURE__ */ w("div", {
47
- className: `relative flex h-20 items-end bg-gradient-to-br ${M(e.topic ?? e.difficulty)} p-4`,
48
- children: [
49
- /* @__PURE__ */ C(g, {
50
- className: "absolute right-3 top-3 text-text-muted/60",
51
- size: 18
52
- }),
53
- t ? /* @__PURE__ */ w("span", {
54
- className: "absolute left-3 top-3 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",
55
- children: [/* @__PURE__ */ C(h, { size: 12 }), " Solved"]
56
- }) : null,
57
- /* @__PURE__ */ C(i, {
58
- status: e.difficulty,
59
- kind: "level"
60
- })
61
- ]
62
- }), /* @__PURE__ */ w("div", {
37
+ children: [/* @__PURE__ */ E(i, {
38
+ seed: `${e.topic ?? ""} ${e.difficulty} ${e.title}`,
39
+ icon: a(e.topic ?? e.title),
40
+ children: [t ? /* @__PURE__ */ E("span", {
41
+ 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",
42
+ children: [/* @__PURE__ */ T(_, { size: 12 }), " Solved"]
43
+ }) : /* @__PURE__ */ T("span", {}), /* @__PURE__ */ T(o, {
44
+ status: e.difficulty,
45
+ kind: "level"
46
+ })]
47
+ }), /* @__PURE__ */ E("div", {
63
48
  className: "flex flex-1 flex-col gap-3 p-4",
64
49
  children: [
65
- /* @__PURE__ */ w("div", {
50
+ /* @__PURE__ */ E("div", {
66
51
  className: "min-w-0",
67
- children: [/* @__PURE__ */ C("h3", {
52
+ children: [/* @__PURE__ */ T("h3", {
68
53
  className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
69
54
  children: e.title
70
- }), e.statement ? /* @__PURE__ */ C("p", {
55
+ }), e.statement ? /* @__PURE__ */ T("p", {
71
56
  className: "mt-1 line-clamp-2 text-sm text-text-secondary",
72
57
  children: e.statement
73
58
  }) : null]
74
59
  }),
75
- /* @__PURE__ */ w("div", {
60
+ /* @__PURE__ */ E("div", {
76
61
  className: "mt-auto flex flex-wrap items-center gap-3 text-xs text-text-muted",
77
62
  children: [
78
- e.topic ? /* @__PURE__ */ w("span", {
63
+ e.topic ? /* @__PURE__ */ E("span", {
79
64
  className: "inline-flex items-center gap-1",
80
65
  children: [
81
- /* @__PURE__ */ C(y, { size: 13 }),
66
+ /* @__PURE__ */ T(x, { size: 13 }),
82
67
  " ",
83
68
  e.topic
84
69
  ]
85
70
  }) : null,
86
- /* @__PURE__ */ w("span", {
71
+ /* @__PURE__ */ E("span", {
87
72
  className: "inline-flex items-center gap-1",
88
73
  children: [
89
- /* @__PURE__ */ C(S, { size: 13 }),
74
+ /* @__PURE__ */ T(w, { size: 13 }),
90
75
  " ",
91
76
  e.points,
92
77
  " pts"
93
78
  ]
94
79
  }),
95
- e.languages.length ? /* @__PURE__ */ w("span", {
80
+ e.languages.length ? /* @__PURE__ */ E("span", {
96
81
  className: "inline-flex items-center gap-1",
97
82
  children: [
98
- /* @__PURE__ */ C(g, { size: 13 }),
83
+ /* @__PURE__ */ T(v, { size: 13 }),
99
84
  " ",
100
85
  e.languages.length,
101
86
  " lang",
@@ -104,12 +89,12 @@ function N({ problem: e, solved: t, onOpen: n }) {
104
89
  }) : null
105
90
  ]
106
91
  }),
107
- e.tags.length ? /* @__PURE__ */ C("div", {
92
+ e.tags.length ? /* @__PURE__ */ T("div", {
108
93
  className: "flex flex-wrap gap-1.5",
109
- children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */ w(T, {
94
+ children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */ E(D, {
110
95
  variant: "secondary",
111
96
  className: "text-[11px]",
112
- children: [/* @__PURE__ */ C(x, {
97
+ children: [/* @__PURE__ */ T(C, {
113
98
  size: 10,
114
99
  className: "mr-1"
115
100
  }), e]
@@ -119,83 +104,87 @@ function N({ problem: e, solved: t, onOpen: n }) {
119
104
  })]
120
105
  });
121
106
  }
122
- function P() {
123
- let i = t(), { currentUser: y } = e(), x = y?.id, [S, T] = m("ALL"), [E, M] = m(""), { limit: P, more: F } = u(), { data: I, loading: L, error: R } = d({
107
+ function F() {
108
+ let i = t(), { currentUser: a } = e(), o = a?.id, [x, C] = g("ALL"), [w, D] = g(""), { limit: O, more: F } = f(), { data: I, loading: L, error: R } = p({
124
109
  status: "PUBLISHED",
125
- pagination: l(P),
126
- ...S === "ALL" ? {} : { difficulty: S }
127
- }), { data: z } = f(x ? { learnerId: x } : {}), B = I?.tecListProblems.items ?? [], V = I?.tecListProblems.pageInfo.hasMore ?? !1, H = p(() => new Set((z?.tecListSubmissions.items ?? []).filter((e) => e.verdict === "ACCEPTED").map((e) => e.problemId)), [z]), U = B.filter((e) => H.has(e.id)).length, W = B.filter((e) => e.difficulty === "EASY").length, G = B.filter((e) => e.difficulty === "HARD").length, K = p(() => {
128
- let e = E.trim().toLowerCase();
110
+ pagination: d(O),
111
+ ...x === "ALL" ? {} : { difficulty: x }
112
+ }), { data: z } = m(o ? { learnerId: o } : {}), B = I?.tecListProblems.items ?? [], V = I?.tecListProblems.pageInfo.hasMore ?? !1, H = h(() => new Set((z?.tecListSubmissions.items ?? []).filter((e) => e.verdict === "ACCEPTED").map((e) => e.problemId)), [z]), U = B.filter((e) => H.has(e.id)).length, W = B.filter((e) => e.difficulty === "EASY").length, G = B.filter((e) => e.difficulty === "HARD").length, K = h(() => {
113
+ let e = w.trim().toLowerCase();
129
114
  return e ? B.filter((t) => t.title.toLowerCase().includes(e) || (t.topic ?? "").toLowerCase().includes(e) || t.tags.some((t) => t.toLowerCase().includes(e))) : B;
130
- }, [B, E]);
131
- return /* @__PURE__ */ w(n, {
115
+ }, [B, w]);
116
+ return /* @__PURE__ */ E(n, {
132
117
  hero: !0,
133
118
  title: "Coding Problems",
134
119
  description: "Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty.",
135
120
  children: [
136
- /* @__PURE__ */ w("div", {
121
+ /* @__PURE__ */ E("div", {
137
122
  className: "mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4",
138
123
  children: [
139
- /* @__PURE__ */ C(r, {
124
+ /* @__PURE__ */ T(r, {
140
125
  label: "Problems",
141
126
  value: B.length,
142
- icon: g
127
+ icon: v,
128
+ tone: "blue"
143
129
  }),
144
- /* @__PURE__ */ C(r, {
130
+ /* @__PURE__ */ T(r, {
145
131
  label: "Solved",
146
132
  value: U,
147
- icon: h
133
+ icon: _,
134
+ tone: "green"
148
135
  }),
149
- /* @__PURE__ */ C(r, {
136
+ /* @__PURE__ */ T(r, {
150
137
  label: "Easy",
151
138
  value: W,
152
- icon: v
139
+ icon: b,
140
+ tone: "teal"
153
141
  }),
154
- /* @__PURE__ */ C(r, {
142
+ /* @__PURE__ */ T(r, {
155
143
  label: "Hard",
156
144
  value: G,
157
- icon: _
145
+ icon: y,
146
+ tone: "amber"
158
147
  })
159
148
  ]
160
149
  }),
161
- /* @__PURE__ */ w("div", {
150
+ /* @__PURE__ */ E("div", {
162
151
  className: "mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
163
- children: [/* @__PURE__ */ C(O, {
164
- value: S,
165
- onValueChange: (e) => T(e),
166
- children: /* @__PURE__ */ C(k, { children: j.map((e) => /* @__PURE__ */ C(A, {
152
+ children: [/* @__PURE__ */ T(A, {
153
+ value: x,
154
+ onValueChange: (e) => C(e),
155
+ children: /* @__PURE__ */ T(j, { children: N.map((e) => /* @__PURE__ */ T(M, {
167
156
  value: e.value,
168
157
  children: e.label
169
158
  }, e.value)) })
170
- }), /* @__PURE__ */ w("div", {
159
+ }), /* @__PURE__ */ E("div", {
171
160
  className: "relative w-full sm:w-72",
172
- children: [/* @__PURE__ */ C(b, {
161
+ children: [/* @__PURE__ */ T(S, {
173
162
  className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted",
174
163
  size: 16
175
- }), /* @__PURE__ */ C(D, {
164
+ }), /* @__PURE__ */ T(k, {
176
165
  className: "pl-9",
177
166
  placeholder: "Search problems…",
178
- value: E,
179
- onChange: (e) => M(e.target.value)
167
+ value: w,
168
+ onChange: (e) => D(e.target.value)
180
169
  })]
181
170
  })]
182
171
  }),
183
- L && !B.length ? /* @__PURE__ */ C(c, {}) : R ? /* @__PURE__ */ C(s, {
172
+ L && !B.length ? /* @__PURE__ */ T(u, {}) : R ? /* @__PURE__ */ T(l, {
184
173
  title: "Couldn't load problems",
185
174
  error: R
186
- }) : K.length === 0 ? /* @__PURE__ */ C(o, {
187
- icon: /* @__PURE__ */ C(g, { size: 26 }),
188
- title: E || S !== "ALL" ? "No matching problems" : "No problems published yet",
189
- description: E || S !== "ALL" ? "Try a different search or difficulty filter." : "Published problems will appear here. Check back soon — TechnoSpam is pre-launch."
190
- }) : /* @__PURE__ */ C("div", {
175
+ }) : K.length === 0 ? /* @__PURE__ */ T(c, {
176
+ icon: /* @__PURE__ */ T(v, { size: 26 }),
177
+ title: w || x !== "ALL" ? "No matching problems" : "No problems published yet",
178
+ description: w || x !== "ALL" ? "Try a different search or difficulty filter." : "Published problems will appear here. Check back soon — TechnoSpam is pre-launch."
179
+ }) : /* @__PURE__ */ T("div", {
191
180
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
192
- children: K.map((e) => /* @__PURE__ */ C(N, {
181
+ children: K.map((e) => /* @__PURE__ */ T(P, {
193
182
  problem: e,
194
183
  solved: H.has(e.id),
195
184
  onOpen: () => i(`/applications/problem-details-page?id=${e.id}`)
196
185
  }, e.id))
197
186
  }),
198
- /* @__PURE__ */ C(a, {
187
+ /* @__PURE__ */ T(s, {
199
188
  hasMore: V,
200
189
  loading: L,
201
190
  onClick: F
@@ -204,6 +193,6 @@ function P() {
204
193
  });
205
194
  }
206
195
  //#endregion
207
- export { P as ApplicationsProblemsPagePage };
196
+ export { F as ApplicationsProblemsPagePage };
208
197
 
209
198
  //# sourceMappingURL=ApplicationsProblemsPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApplicationsProblemsPagePage.js","names":[],"sources":["../../../src/technospam/pages/ApplicationsProblemsPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { CheckCircle2, Code2, Flame, Gauge, Layers, Search, Tag, Trophy } from 'lucide-react';\nimport { Badge, GlassCard, Input, Tabs, TabsList, TabsTrigger } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n usePageLimit,\n useProblemsQuery,\n useSubmissionsQuery,\n type TecProblem,\n type TecProblemDifficulty,\n} from '../api/technospamApi';\n\nconst DIFFICULTIES: Array<{ value: 'ALL' | TecProblemDifficulty; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'EASY', label: 'Easy' },\n { value: 'MEDIUM', label: 'Medium' },\n { value: 'HARD', label: 'Hard' },\n];\n\n/** Deterministic token-based header gradient keyed off the problem topic/difficulty. */\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 ProblemCard({\n problem,\n solved,\n onOpen,\n}: {\n problem: TecProblem;\n solved: boolean;\n onOpen: () => void;\n}) {\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-20 items-end bg-gradient-to-br ${coverGradient(\n problem.topic ?? problem.difficulty\n )} p-4`}\n >\n <Code2 className=\"absolute right-3 top-3 text-text-muted/60\" size={18} />\n {solved ? (\n <span className=\"absolute left-3 top-3 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\">\n <CheckCircle2 size={12} /> Solved\n </span>\n ) : null}\n <StatusBadge status={problem.difficulty} 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 {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} /> {problem.points} pts\n </span>\n {problem.languages.length ? (\n <span className=\"inline-flex items-center gap-1\">\n <Code2 size={13} /> {problem.languages.length} lang\n {problem.languages.length === 1 ? '' : 's'}\n </span>\n ) : null}\n </div>\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 } = useTechnoSpam();\n const learnerId = currentUser?.id;\n const [difficulty, setDifficulty] = useState<'ALL' | TecProblemDifficulty>('ALL');\n const [search, setSearch] = useState('');\n\n const { limit, more } = usePageLimit();\n const { data, loading, error } = useProblemsQuery({\n status: 'PUBLISHED',\n pagination: pageArg(limit),\n ...(difficulty !== 'ALL' ? { difficulty } : {}),\n });\n const { data: subsData } = useSubmissionsQuery(learnerId ? { learnerId } : {});\n\n const problems = data?.tecListProblems.items ?? [];\n const hasMore = data?.tecListProblems.pageInfo.hasMore ?? false;\n\n const solvedSet = useMemo(\n () =>\n new Set(\n (subsData?.tecListSubmissions.items ?? [])\n .filter((s) => s.verdict === 'ACCEPTED')\n .map((s) => s.problemId)\n ),\n [subsData]\n );\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 return (\n <PageLayout\n hero\n title=\"Coding Problems\"\n description=\"Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty.\"\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Problems\" value={problems.length} icon={Code2} />\n <StatCard label=\"Solved\" value={solvedCount} icon={CheckCircle2} />\n <StatCard label=\"Easy\" value={easyCount} icon={Gauge} />\n <StatCard label=\"Hard\" value={hardCount} icon={Flame} />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <Tabs\n value={difficulty}\n onValueChange={(v) => setDifficulty(v as 'ALL' | TecProblemDifficulty)}\n >\n <TabsList>\n {DIFFICULTIES.map((d) => (\n <TabsTrigger key={d.value} value={d.value}>\n {d.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 problems…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n </div>\n\n {loading && !problems.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load problems\" error={error} />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Code2 size={26} />}\n title={\n search || difficulty !== 'ALL' ? 'No matching problems' : 'No problems published yet'\n }\n description={\n search || difficulty !== 'ALL'\n ? 'Try a different search or difficulty filter.'\n : 'Published problems 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((problem) => (\n <ProblemCard\n key={problem.id}\n problem={problem}\n solved={solvedSet.has(problem.id)}\n onOpen={() => navigate(`/applications/problem-details-page?id=${problem.id}`)}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAsBA,IAAM,IAA8E;CAClF;EAAE,OAAO;EAAO,OAAO;EAAO;CAC9B;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAU,OAAO;EAAU;CACpC;EAAE,OAAO;EAAQ,OAAO;EAAQ;CACjC;AAGD,SAAS,EAAc,GAAsB;CAC3C,IAAM,IAAY;EAChB;EACA;EACA;EACA;EACD,EACG,IAAO;AACX,MAAK,IAAI,IAAI,GAAG,IAAI,EAAK,QAAQ,KAAK,EAAG,KAAQ,IAAO,KAAK,EAAK,WAAW,EAAE,KAAM;AACrF,QAAO,EAAU,IAAO,EAAU;;AAGpC,SAAS,EAAY,EACnB,YACA,WACA,aAKC;AACD,QACE,kBAAC,GAAD;EACE,WAAU;EACV,SAAS;YAFX,CAIE,kBAAC,OAAD;GACE,WAAW,kDAAkD,EAC3D,EAAQ,SAAS,EAAQ,WAC1B,CAAC;aAHJ;IAKE,kBAAC,GAAD;KAAO,WAAU;KAA4C,MAAM;KAAM,CAAA;IACxE,IACC,kBAAC,QAAD;KAAM,WAAU;eAAhB,CACE,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA,EAAA,UACrB;SACL;IACJ,kBAAC,GAAD;KAAa,QAAQ,EAAQ;KAAY,MAAK;KAAU,CAAA;IACpD;MACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAQ;MACN,CAAA,EACJ,EAAQ,YACP,kBAAC,KAAD;MAAG,WAAU;gBAAiD,EAAQ;MAAc,CAAA,GAClF,KACA;;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAQ,QACP,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;QAAE,EAAQ;QACzB;WACL;MACJ,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;QAAE,EAAQ;QAAO;QAChC;;MACN,EAAQ,UAAU,SACjB,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;QAAE,EAAQ,UAAU;QAAO;QAC7C,EAAQ,UAAU,WAAW,IAAI,KAAK;QAClC;WACL;MACA;;IACL,EAAQ,KAAK,SACZ,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAQ,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAC7B,kBAAC,GAAD;MAAe,SAAQ;MAAY,WAAU;gBAA7C,CACE,kBAAC,GAAD;OAAK,MAAM;OAAI,WAAU;OAAS,CAAA,EACjC,EACK;QAHI,EAGJ,CACR;KACE,CAAA,GACJ;IACA;KACI;;;AAIhB,SAAgB,IAA+B;CAC7C,IAAM,IAAW,GAAuB,EAClC,EAAE,mBAAgB,GAAe,EACjC,IAAY,GAAa,IACzB,CAAC,GAAY,KAAiB,EAAuC,MAAM,EAC3E,CAAC,GAAQ,KAAa,EAAS,GAAG,EAElC,EAAE,UAAO,YAAS,GAAc,EAChC,EAAE,SAAM,YAAS,aAAU,EAAiB;EAChD,QAAQ;EACR,YAAY,EAAQ,EAAM;EAC1B,GAAI,MAAe,QAAyB,EAAE,GAAnB,EAAE,eAAY;EAC1C,CAAC,EACI,EAAE,MAAM,MAAa,EAAoB,IAAY,EAAE,cAAW,GAAG,EAAE,CAAC,EAExE,IAAW,GAAM,gBAAgB,SAAS,EAAE,EAC5C,IAAU,GAAM,gBAAgB,SAAS,WAAW,IAEpD,IAAY,QAEd,IAAI,KACD,GAAU,mBAAmB,SAAS,EAAE,EACtC,QAAQ,MAAM,EAAE,YAAY,WAAW,CACvC,KAAK,MAAM,EAAE,UAAU,CAC3B,EACH,CAAC,EAAS,CACX,EAEK,IAAc,EAAS,QAAQ,MAAM,EAAU,IAAI,EAAE,GAAG,CAAC,CAAC,QAC1D,IAAY,EAAS,QAAQ,MAAM,EAAE,eAAe,OAAO,CAAC,QAC5D,IAAY,EAAS,QAAQ,MAAM,EAAE,eAAe,OAAO,CAAC,QAE5D,IAAW,QAAc;EAC7B,IAAM,IAAI,EAAO,MAAM,CAAC,aAAa;AAErC,SADK,IACE,EAAS,QACb,MACC,EAAE,MAAM,aAAa,CAAC,SAAS,EAAE,KAChC,EAAE,SAAS,IAAI,aAAa,CAAC,SAAS,EAAE,IACzC,EAAE,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC,SAAS,EAAE,CAAC,CAClD,GANc;IAOd,CAAC,GAAU,EAAO,CAAC;AAEtB,QACE,kBAAC,GAAD;EACE,MAAA;EACA,OAAM;EACN,aAAY;YAHd;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,OAAM;MAAW,OAAO,EAAS;MAAQ,MAAM;MAAS,CAAA;KAClE,kBAAC,GAAD;MAAU,OAAM;MAAS,OAAO;MAAa,MAAM;MAAgB,CAAA;KACnE,kBAAC,GAAD;MAAU,OAAM;MAAO,OAAO;MAAW,MAAM;MAAS,CAAA;KACxD,kBAAC,GAAD;MAAU,OAAM;MAAO,OAAO;MAAW,MAAM;MAAS,CAAA;KACpD;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,OAAO;KACP,gBAAgB,MAAM,EAAc,EAAkC;eAEtE,kBAAC,GAAD,EAAA,UACG,EAAa,KAAK,MACjB,kBAAC,GAAD;MAA2B,OAAO,EAAE;gBACjC,EAAE;MACS,EAFI,EAAE,MAEN,CACd,EACO,CAAA;KACN,CAAA,EACP,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,WAAU;MACV,MAAM;MACN,CAAA,EACF,kBAAC,GAAD;MACE,WAAU;MACV,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;MAC1C,CAAA,CACE;OACF;;GAEL,KAAW,CAAC,EAAS,SACpB,kBAAC,GAAD,EAAe,CAAA,GACb,IACF,kBAAC,GAAD;IAAW,OAAM;IAAgC;IAAS,CAAA,GACxD,EAAS,WAAW,IACtB,kBAAC,GAAD;IACE,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OACE,KAAU,MAAe,QAAQ,yBAAyB;IAE5D,aACE,KAAU,MAAe,QACrB,iDACA;IAEN,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MACb,kBAAC,GAAD;KAEW;KACT,QAAQ,EAAU,IAAI,EAAQ,GAAG;KACjC,cAAc,EAAS,yCAAyC,EAAQ,KAAK;KAC7E,EAJK,EAAQ,GAIb,CACF;IACE,CAAA;GAER,kBAAC,GAAD;IAAmB;IAAkB;IAAS,SAAS;IAAQ,CAAA;GACpD"}
1
+ {"version":3,"file":"ApplicationsProblemsPagePage.js","names":[],"sources":["../../../src/technospam/pages/ApplicationsProblemsPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { CheckCircle2, Code2, Flame, Gauge, Layers, Search, Tag, Trophy } from 'lucide-react';\nimport { Badge, GlassCard, Input, Tabs, TabsList, TabsTrigger } 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 { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n usePageLimit,\n useProblemsQuery,\n useSubmissionsQuery,\n type TecProblem,\n type TecProblemDifficulty,\n} from '../api/technospamApi';\n\nconst DIFFICULTIES: Array<{ value: 'ALL' | TecProblemDifficulty; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'EASY', label: 'Easy' },\n { value: 'MEDIUM', label: 'Medium' },\n { value: 'HARD', label: 'Hard' },\n];\n\nfunction ProblemCard({\n problem,\n solved,\n onOpen,\n}: {\n problem: TecProblem;\n solved: boolean;\n onOpen: () => void;\n}) {\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} /> Solved\n </span>\n ) : (\n <span />\n )}\n <StatusBadge status={problem.difficulty} 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 {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} /> {problem.points} pts\n </span>\n {problem.languages.length ? (\n <span className=\"inline-flex items-center gap-1\">\n <Code2 size={13} /> {problem.languages.length} lang\n {problem.languages.length === 1 ? '' : 's'}\n </span>\n ) : null}\n </div>\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 } = useTechnoSpam();\n const learnerId = currentUser?.id;\n const [difficulty, setDifficulty] = useState<'ALL' | TecProblemDifficulty>('ALL');\n const [search, setSearch] = useState('');\n\n const { limit, more } = usePageLimit();\n const { data, loading, error } = useProblemsQuery({\n status: 'PUBLISHED',\n pagination: pageArg(limit),\n ...(difficulty !== 'ALL' ? { difficulty } : {}),\n });\n const { data: subsData } = useSubmissionsQuery(learnerId ? { learnerId } : {});\n\n const problems = data?.tecListProblems.items ?? [];\n const hasMore = data?.tecListProblems.pageInfo.hasMore ?? false;\n\n const solvedSet = useMemo(\n () =>\n new Set(\n (subsData?.tecListSubmissions.items ?? [])\n .filter((s) => s.verdict === 'ACCEPTED')\n .map((s) => s.problemId)\n ),\n [subsData]\n );\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 return (\n <PageLayout\n hero\n title=\"Coding Problems\"\n description=\"Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty.\"\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Problems\" value={problems.length} icon={Code2} tone=\"blue\" />\n <StatCard label=\"Solved\" value={solvedCount} icon={CheckCircle2} tone=\"green\" />\n <StatCard label=\"Easy\" value={easyCount} icon={Gauge} tone=\"teal\" />\n <StatCard label=\"Hard\" value={hardCount} icon={Flame} tone=\"amber\" />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <Tabs\n value={difficulty}\n onValueChange={(v) => setDifficulty(v as 'ALL' | TecProblemDifficulty)}\n >\n <TabsList>\n {DIFFICULTIES.map((d) => (\n <TabsTrigger key={d.value} value={d.value}>\n {d.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 problems…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n </div>\n\n {loading && !problems.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load problems\" error={error} />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Code2 size={26} />}\n title={\n search || difficulty !== 'ALL' ? 'No matching problems' : 'No problems published yet'\n }\n description={\n search || difficulty !== 'ALL'\n ? 'Try a different search or difficulty filter.'\n : 'Published problems 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((problem) => (\n <ProblemCard\n key={problem.id}\n problem={problem}\n solved={solvedSet.has(problem.id)}\n onOpen={() => navigate(`/applications/problem-details-page?id=${problem.id}`)}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,IAAM,IAA8E;CAClF;EAAE,OAAO;EAAO,OAAO;EAAO;CAC9B;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAU,OAAO;EAAU;CACpC;EAAE,OAAO;EAAQ,OAAO;EAAQ;CACjC;AAED,SAAS,EAAY,EACnB,YACA,WACA,aAKC;AACD,QACE,kBAAC,GAAD;EACE,WAAU;EACV,SAAS;YAFX,CAIE,kBAAC,GAAD;GACE,MAAM,GAAG,EAAQ,SAAS,GAAG,GAAG,EAAQ,WAAW,GAAG,EAAQ;GAC9D,MAAM,EAAU,EAAQ,SAAS,EAAQ,MAAM;aAFjD,CAIG,IACC,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA,EAAA,UACrB;QAEP,kBAAC,QAAD,EAAQ,CAAA,EAEV,kBAAC,GAAD;IAAa,QAAQ,EAAQ;IAAY,MAAK;IAAU,CAAA,CAC7C;MACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAQ;MACN,CAAA,EACJ,EAAQ,YACP,kBAAC,KAAD;MAAG,WAAU;gBAAiD,EAAQ;MAAc,CAAA,GAClF,KACA;;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAQ,QACP,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;QAAE,EAAQ;QACzB;WACL;MACJ,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;;QAAE,EAAQ;QAAO;QAChC;;MACN,EAAQ,UAAU,SACjB,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;QAAE,EAAQ,UAAU;QAAO;QAC7C,EAAQ,UAAU,WAAW,IAAI,KAAK;QAClC;WACL;MACA;;IACL,EAAQ,KAAK,SACZ,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAQ,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAC7B,kBAAC,GAAD;MAAe,SAAQ;MAAY,WAAU;gBAA7C,CACE,kBAAC,GAAD;OAAK,MAAM;OAAI,WAAU;OAAS,CAAA,EACjC,EACK;QAHI,EAGJ,CACR;KACE,CAAA,GACJ;IACA;KACI;;;AAIhB,SAAgB,IAA+B;CAC7C,IAAM,IAAW,GAAuB,EAClC,EAAE,mBAAgB,GAAe,EACjC,IAAY,GAAa,IACzB,CAAC,GAAY,KAAiB,EAAuC,MAAM,EAC3E,CAAC,GAAQ,KAAa,EAAS,GAAG,EAElC,EAAE,UAAO,YAAS,GAAc,EAChC,EAAE,SAAM,YAAS,aAAU,EAAiB;EAChD,QAAQ;EACR,YAAY,EAAQ,EAAM;EAC1B,GAAI,MAAe,QAAyB,EAAE,GAAnB,EAAE,eAAY;EAC1C,CAAC,EACI,EAAE,MAAM,MAAa,EAAoB,IAAY,EAAE,cAAW,GAAG,EAAE,CAAC,EAExE,IAAW,GAAM,gBAAgB,SAAS,EAAE,EAC5C,IAAU,GAAM,gBAAgB,SAAS,WAAW,IAEpD,IAAY,QAEd,IAAI,KACD,GAAU,mBAAmB,SAAS,EAAE,EACtC,QAAQ,MAAM,EAAE,YAAY,WAAW,CACvC,KAAK,MAAM,EAAE,UAAU,CAC3B,EACH,CAAC,EAAS,CACX,EAEK,IAAc,EAAS,QAAQ,MAAM,EAAU,IAAI,EAAE,GAAG,CAAC,CAAC,QAC1D,IAAY,EAAS,QAAQ,MAAM,EAAE,eAAe,OAAO,CAAC,QAC5D,IAAY,EAAS,QAAQ,MAAM,EAAE,eAAe,OAAO,CAAC,QAE5D,IAAW,QAAc;EAC7B,IAAM,IAAI,EAAO,MAAM,CAAC,aAAa;AAErC,SADK,IACE,EAAS,QACb,MACC,EAAE,MAAM,aAAa,CAAC,SAAS,EAAE,KAChC,EAAE,SAAS,IAAI,aAAa,CAAC,SAAS,EAAE,IACzC,EAAE,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC,SAAS,EAAE,CAAC,CAClD,GANc;IAOd,CAAC,GAAU,EAAO,CAAC;AAEtB,QACE,kBAAC,GAAD;EACE,MAAA;EACA,OAAM;EACN,aAAY;YAHd;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,OAAM;MAAW,OAAO,EAAS;MAAQ,MAAM;MAAO,MAAK;MAAS,CAAA;KAC9E,kBAAC,GAAD;MAAU,OAAM;MAAS,OAAO;MAAa,MAAM;MAAc,MAAK;MAAU,CAAA;KAChF,kBAAC,GAAD;MAAU,OAAM;MAAO,OAAO;MAAW,MAAM;MAAO,MAAK;MAAS,CAAA;KACpE,kBAAC,GAAD;MAAU,OAAM;MAAO,OAAO;MAAW,MAAM;MAAO,MAAK;MAAU,CAAA;KACjE;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,OAAO;KACP,gBAAgB,MAAM,EAAc,EAAkC;eAEtE,kBAAC,GAAD,EAAA,UACG,EAAa,KAAK,MACjB,kBAAC,GAAD;MAA2B,OAAO,EAAE;gBACjC,EAAE;MACS,EAFI,EAAE,MAEN,CACd,EACO,CAAA;KACN,CAAA,EACP,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,WAAU;MACV,MAAM;MACN,CAAA,EACF,kBAAC,GAAD;MACE,WAAU;MACV,aAAY;MACZ,OAAO;MACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;MAC1C,CAAA,CACE;OACF;;GAEL,KAAW,CAAC,EAAS,SACpB,kBAAC,GAAD,EAAe,CAAA,GACb,IACF,kBAAC,GAAD;IAAW,OAAM;IAAgC;IAAS,CAAA,GACxD,EAAS,WAAW,IACtB,kBAAC,GAAD;IACE,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OACE,KAAU,MAAe,QAAQ,yBAAyB;IAE5D,aACE,KAAU,MAAe,QACrB,iDACA;IAEN,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MACb,kBAAC,GAAD;KAEW;KACT,QAAQ,EAAU,IAAI,EAAQ,GAAG;KACjC,cAAc,EAAS,yCAAyC,EAAQ,KAAK;KAC7E,EAJK,EAAQ,GAIb,CACF;IACE,CAAA;GAER,kBAAC,GAAD;IAAmB;IAAkB;IAAS,SAAS;IAAQ,CAAA;GACpD"}