@burdenoff/microfe-technospam 2026.704.2 → 2026.705.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/technospam/api/technospamApi.js +233 -150
- package/dist/technospam/api/technospamApi.js.map +1 -1
- package/dist/technospam/components/LoadMore.js +18 -2
- package/dist/technospam/components/LoadMore.js.map +1 -0
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js +664 -334
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +79 -72
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +140 -87
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +75 -68
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesMyLearningPagePage.js +3 -0
- package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +76 -53
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +36 -35
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +112 -103
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js +219 -110
- package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminAdminDashboardPagePage.js","names":[],"sources":["../../../src/technospam/pages/AdminAdminDashboardPagePage.tsx"],"sourcesContent":["import { useState, type ReactNode } from 'react';\nimport { Archive, BookOpen, Code2, Plus, Rocket, Trophy, UserCheck, Users, X } 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 TabsList,\n TabsTrigger,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { EmptyView, ErrorView, LoadingRows, PageLayout, StatusBadge } from '../components';\nimport {\n useApproveMentor,\n useArchiveCourse,\n useCoursesQuery,\n useCreateCourse,\n useCreateHackathon,\n useCreateProblem,\n useHackathonsQuery,\n useMentorsQuery,\n useOpenRegistration,\n useProblemsQuery,\n usePublishCourse,\n usePublishProblem,\n type TecCourseLevel,\n type TecProblemDifficulty,\n} from '../api/technospamApi';\nimport { formatDateTime, formatDuration, formatMoney, humanizeEnum } from '../utils/format';\nimport { notify } from '../lib/toast';\n\n/* --------------------------------------------------------------- helpers */\n\nconst LEVELS: TecCourseLevel[] = ['BEGINNER', 'INTERMEDIATE', 'ADVANCED', 'EXPERT'];\nconst DIFFICULTIES: TecProblemDifficulty[] = ['EASY', 'MEDIUM', 'HARD'];\n\n/** lowercase-hyphenated, safe for URL slugs. */\nfunction slugify(value: string): string {\n return value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nfunction parseCsv(value: string): string[] {\n return value\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n}\n\nfunction parseIntOrUndef(value: string): number | undefined {\n const n = Number.parseInt(value, 10);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction toIsoOrNull(local: string): string | null {\n if (!local) return null;\n const d = new Date(local);\n return Number.isNaN(d.getTime()) ? null : d.toISOString();\n}\n\n/* ----------------------------------------------------------- form atoms */\n\nfunction Field({\n label,\n required,\n className,\n children,\n}: {\n label: string;\n required?: boolean;\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={`flex flex-col gap-1.5 ${className ?? ''}`}>\n <span className=\"text-xs font-medium text-text-secondary\">\n {label}\n {required ? <span className=\"text-status-error-text\"> *</span> : null}\n </span>\n {children}\n </div>\n );\n}\n\nfunction FormCard({\n title,\n children,\n footer,\n}: {\n title: string;\n children: ReactNode;\n footer: ReactNode;\n}) {\n return (\n <GlassCard className=\"space-y-4 p-4 sm:p-5\">\n <h3 className=\"text-sm font-semibold text-text-primary\">{title}</h3>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">{children}</div>\n <div className=\"flex justify-end gap-2\">{footer}</div>\n </GlassCard>\n );\n}\n\nfunction TabHeader({\n summary,\n actionLabel,\n open,\n onToggle,\n}: {\n summary: string;\n actionLabel?: string;\n open?: boolean;\n onToggle?: () => void;\n}) {\n return (\n <div className=\"flex items-center justify-between gap-3\">\n <p className=\"text-sm text-text-secondary\">{summary}</p>\n {actionLabel && onToggle ? (\n <Button size=\"sm\" variant={open ? 'outline' : 'default'} onClick={onToggle}>\n {open ? <X size={15} /> : <Plus size={15} />}\n {open ? 'Close' : actionLabel}\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction RowShell({ children, actions }: { children: ReactNode; actions?: ReactNode }) {\n return (\n <GlassCard className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0\">{children}</div>\n {actions ? <div className=\"flex shrink-0 flex-wrap items-center gap-2\">{actions}</div> : null}\n </GlassCard>\n );\n}\n\n/* --------------------------------------------------------------- Courses */\n\nfunction CoursesTab() {\n const { data, loading, error, refetch } = useCoursesQuery({});\n const [createCourse, { loading: creating }] = useCreateCourse();\n const [publishCourse] = usePublishCourse();\n const [archiveCourse] = useArchiveCourse();\n\n const [showForm, setShowForm] = useState(false);\n const [actingId, setActingId] = useState<string | null>(null);\n\n const [title, setTitle] = useState('');\n const [slug, setSlug] = useState('');\n const [summary, setSummary] = useState('');\n const [topic, setTopic] = useState('');\n const [level, setLevel] = useState<TecCourseLevel>('BEGINNER');\n const [minutes, setMinutes] = useState('');\n const [tags, setTags] = useState('');\n\n const courses = data?.tecListCourses.items ?? [];\n\n const resetForm = () => {\n setTitle('');\n setSlug('');\n setSummary('');\n setTopic('');\n setLevel('BEGINNER');\n setMinutes('');\n setTags('');\n setShowForm(false);\n };\n\n const handleCreate = async () => {\n const t = title.trim();\n if (!t) return notify.error('Title is required');\n const finalSlug = slugify(slug || t);\n if (!finalSlug) return notify.error('A valid slug is required');\n const res = await createCourse({\n variables: {\n input: {\n title: t,\n slug: finalSlug,\n summary: summary.trim() || undefined,\n topic: topic.trim() || undefined,\n level,\n estimatedMinutes: parseIntOrUndef(minutes),\n tags: parseCsv(tags),\n },\n },\n });\n if (res.data?.tecCreateCourse) {\n notify.success('Course created', `\"${t}\" saved as a draft.`);\n resetForm();\n await refetch();\n }\n };\n\n const handlePublish = async (id: string) => {\n setActingId(id);\n try {\n const res = await publishCourse({ variables: { id } });\n if (res.data?.tecPublishCourse) {\n notify.success('Course published');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n const handleArchive = async (id: string) => {\n setActingId(id);\n try {\n const res = await archiveCourse({ variables: { id } });\n if (res.data?.tecArchiveCourse) {\n notify.success('Course archived');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${courses.length} course${courses.length === 1 ? '' : 's'}`}\n actionLabel=\"New course\"\n open={showForm}\n onToggle={() => setShowForm((v) => !v)}\n />\n\n {showForm ? (\n <FormCard\n title=\"New course\"\n footer={\n <>\n <Button variant=\"outline\" size=\"sm\" onClick={resetForm}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={creating}>\n {creating ? 'Creating…' : 'Create course'}\n </Button>\n </>\n }\n >\n <Field label=\"Title\" required>\n <Input\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"Intro to TypeScript\"\n />\n </Field>\n <Field label=\"Slug\" required>\n <Input\n value={slug}\n onChange={(e) => setSlug(e.target.value)}\n placeholder=\"auto from title if blank\"\n />\n </Field>\n <Field label=\"Topic\">\n <Input\n value={topic}\n onChange={(e) => setTopic(e.target.value)}\n placeholder=\"Languages\"\n />\n </Field>\n <Field label=\"Level\">\n <Select value={level} onValueChange={(v) => setLevel(v as TecCourseLevel)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {LEVELS.map((l) => (\n <SelectItem key={l} value={l}>\n {humanizeEnum(l)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Estimated minutes\">\n <Input\n type=\"number\"\n min={0}\n value={minutes}\n onChange={(e) => setMinutes(e.target.value)}\n placeholder=\"120\"\n />\n </Field>\n <Field label=\"Tags (comma-separated)\">\n <Input\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder=\"typescript, basics\"\n />\n </Field>\n <Field label=\"Summary\" className=\"sm:col-span-2\">\n <Textarea\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n placeholder=\"What learners will build and take away.\"\n />\n </Field>\n </FormCard>\n ) : null}\n\n {loading && !courses.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load courses\" error={error} />\n ) : courses.length === 0 ? (\n <EmptyView\n icon={<BookOpen size={26} />}\n title=\"No courses yet\"\n description=\"Create your first course with the button above. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {courses.map((c) => (\n <RowShell\n key={c.id}\n actions={\n <>\n {c.status === 'DRAFT' ? (\n <Button\n size=\"sm\"\n onClick={() => handlePublish(c.id)}\n disabled={actingId === c.id}\n >\n <Rocket size={15} /> Publish\n </Button>\n ) : null}\n {c.status !== 'ARCHIVED' ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => handleArchive(c.id)}\n disabled={actingId === c.id}\n >\n <Archive size={15} /> Archive\n </Button>\n ) : null}\n </>\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">{c.title}</span>\n <StatusBadge status={c.status} />\n <StatusBadge status={c.level} kind=\"level\" />\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {c.slug} · {c.topic ?? 'No topic'} · {formatDuration(c.estimatedMinutes)}\n </div>\n </RowShell>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* -------------------------------------------------------------- Problems */\n\nfunction ProblemsTab() {\n const { data, loading, error, refetch } = useProblemsQuery({});\n const [createProblem, { loading: creating }] = useCreateProblem();\n const [publishProblem] = usePublishProblem();\n\n const [showForm, setShowForm] = useState(false);\n const [actingId, setActingId] = useState<string | null>(null);\n\n const [title, setTitle] = useState('');\n const [slug, setSlug] = useState('');\n const [statement, setStatement] = useState('');\n const [topic, setTopic] = useState('');\n const [difficulty, setDifficulty] = useState<TecProblemDifficulty>('EASY');\n const [points, setPoints] = useState('');\n const [languages, setLanguages] = useState('');\n const [starterCode, setStarterCode] = useState('');\n\n const problems = data?.tecListProblems.items ?? [];\n\n const resetForm = () => {\n setTitle('');\n setSlug('');\n setStatement('');\n setTopic('');\n setDifficulty('EASY');\n setPoints('');\n setLanguages('');\n setStarterCode('');\n setShowForm(false);\n };\n\n const handleCreate = async () => {\n const t = title.trim();\n if (!t) return notify.error('Title is required');\n const finalSlug = slugify(slug || t);\n if (!finalSlug) return notify.error('A valid slug is required');\n const res = await createProblem({\n variables: {\n input: {\n title: t,\n slug: finalSlug,\n statement: statement.trim() || undefined,\n topic: topic.trim() || undefined,\n difficulty,\n points: parseIntOrUndef(points),\n languages: parseCsv(languages),\n starterCode: starterCode.trim() || undefined,\n },\n },\n });\n if (res.data?.tecCreateProblem) {\n notify.success('Problem created', `\"${t}\" saved as a draft.`);\n resetForm();\n await refetch();\n }\n };\n\n const handlePublish = async (id: string) => {\n setActingId(id);\n try {\n const res = await publishProblem({ variables: { id } });\n if (res.data?.tecPublishProblem) {\n notify.success('Problem published');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${problems.length} problem${problems.length === 1 ? '' : 's'}`}\n actionLabel=\"New problem\"\n open={showForm}\n onToggle={() => setShowForm((v) => !v)}\n />\n\n {showForm ? (\n <FormCard\n title=\"New problem\"\n footer={\n <>\n <Button variant=\"outline\" size=\"sm\" onClick={resetForm}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={creating}>\n {creating ? 'Creating…' : 'Create problem'}\n </Button>\n </>\n }\n >\n <Field label=\"Title\" required>\n <Input value={title} onChange={(e) => setTitle(e.target.value)} placeholder=\"Two Sum\" />\n </Field>\n <Field label=\"Slug\" required>\n <Input\n value={slug}\n onChange={(e) => setSlug(e.target.value)}\n placeholder=\"auto from title if blank\"\n />\n </Field>\n <Field label=\"Topic\">\n <Input value={topic} onChange={(e) => setTopic(e.target.value)} placeholder=\"Arrays\" />\n </Field>\n <Field label=\"Difficulty\">\n <Select\n value={difficulty}\n onValueChange={(v) => setDifficulty(v as TecProblemDifficulty)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DIFFICULTIES.map((d) => (\n <SelectItem key={d} value={d}>\n {humanizeEnum(d)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Points\">\n <Input\n type=\"number\"\n min={0}\n value={points}\n onChange={(e) => setPoints(e.target.value)}\n placeholder=\"100\"\n />\n </Field>\n <Field label=\"Languages (comma-separated)\">\n <Input\n value={languages}\n onChange={(e) => setLanguages(e.target.value)}\n placeholder=\"python, typescript\"\n />\n </Field>\n <Field label=\"Statement\" className=\"sm:col-span-2\">\n <Textarea\n value={statement}\n onChange={(e) => setStatement(e.target.value)}\n placeholder=\"Describe the problem and constraints.\"\n />\n </Field>\n <Field label=\"Starter code\" className=\"sm:col-span-2\">\n <Textarea\n value={starterCode}\n onChange={(e) => setStarterCode(e.target.value)}\n className=\"font-mono\"\n placeholder=\"def solve(nums, target):\\n pass\"\n />\n </Field>\n </FormCard>\n ) : null}\n\n {loading && !problems.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load problems\" error={error} />\n ) : problems.length === 0 ? (\n <EmptyView\n icon={<Code2 size={26} />}\n title=\"No problems yet\"\n description=\"Create your first coding problem with the button above. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {problems.map((p) => (\n <RowShell\n key={p.id}\n actions={\n p.status === 'DRAFT' ? (\n <Button\n size=\"sm\"\n onClick={() => handlePublish(p.id)}\n disabled={actingId === p.id}\n >\n <Rocket size={15} /> Publish\n </Button>\n ) : undefined\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">{p.title}</span>\n <StatusBadge status={p.status} />\n <StatusBadge status={p.difficulty} kind=\"level\" />\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {p.slug} · {p.topic ?? 'No topic'} · {p.points} pts ·{' '}\n {p.languages.length ? p.languages.join(', ') : 'No languages'}\n </div>\n </RowShell>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------ Hackathons */\n\nfunction HackathonsTab() {\n const { data, loading, error, refetch } = useHackathonsQuery({});\n const [createHackathon, { loading: creating }] = useCreateHackathon();\n const [openRegistration] = useOpenRegistration();\n\n const [showForm, setShowForm] = useState(false);\n const [actingId, setActingId] = useState<string | null>(null);\n\n const [title, setTitle] = useState('');\n const [slug, setSlug] = useState('');\n const [theme, setTheme] = useState('');\n const [description, setDescription] = useState('');\n const [startAt, setStartAt] = useState('');\n const [endAt, setEndAt] = useState('');\n const [prizePool, setPrizePool] = useState('');\n const [maxTeamSize, setMaxTeamSize] = useState('');\n const [tags, setTags] = useState('');\n\n const hackathons = data?.tecListHackathons.items ?? [];\n\n const resetForm = () => {\n setTitle('');\n setSlug('');\n setTheme('');\n setDescription('');\n setStartAt('');\n setEndAt('');\n setPrizePool('');\n setMaxTeamSize('');\n setTags('');\n setShowForm(false);\n };\n\n const handleCreate = async () => {\n const t = title.trim();\n if (!t) return notify.error('Title is required');\n const finalSlug = slugify(slug || t);\n if (!finalSlug) return notify.error('A valid slug is required');\n const startIso = toIsoOrNull(startAt);\n const endIso = toIsoOrNull(endAt);\n if (!startIso || !endIso) return notify.error('Start and end date/time are required');\n if (new Date(endIso) <= new Date(startIso)) return notify.error('End must be after the start');\n const res = await createHackathon({\n variables: {\n input: {\n title: t,\n slug: finalSlug,\n theme: theme.trim() || undefined,\n description: description.trim() || undefined,\n startAt: startIso,\n endAt: endIso,\n prizePool: parseIntOrUndef(prizePool),\n maxTeamSize: parseIntOrUndef(maxTeamSize),\n tags: parseCsv(tags),\n },\n },\n });\n if (res.data?.tecCreateHackathon) {\n notify.success('Hackathon created', `\"${t}\" saved as a draft.`);\n resetForm();\n await refetch();\n }\n };\n\n const handleOpen = async (id: string) => {\n setActingId(id);\n try {\n const res = await openRegistration({ variables: { id } });\n if (res.data?.tecOpenRegistration) {\n notify.success('Registration open', 'Teams can now register.');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${hackathons.length} hackathon${hackathons.length === 1 ? '' : 's'}`}\n actionLabel=\"New hackathon\"\n open={showForm}\n onToggle={() => setShowForm((v) => !v)}\n />\n\n {showForm ? (\n <FormCard\n title=\"New hackathon\"\n footer={\n <>\n <Button variant=\"outline\" size=\"sm\" onClick={resetForm}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={creating}>\n {creating ? 'Creating…' : 'Create hackathon'}\n </Button>\n </>\n }\n >\n <Field label=\"Title\" required>\n <Input\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"Build Days 2026\"\n />\n </Field>\n <Field label=\"Slug\" required>\n <Input\n value={slug}\n onChange={(e) => setSlug(e.target.value)}\n placeholder=\"auto from title if blank\"\n />\n </Field>\n <Field label=\"Theme\">\n <Input\n value={theme}\n onChange={(e) => setTheme(e.target.value)}\n placeholder=\"AI for good\"\n />\n </Field>\n <Field label=\"Tags (comma-separated)\">\n <Input value={tags} onChange={(e) => setTags(e.target.value)} placeholder=\"ai, web\" />\n </Field>\n <Field label=\"Starts\" required>\n <Input\n type=\"datetime-local\"\n value={startAt}\n onChange={(e) => setStartAt(e.target.value)}\n />\n </Field>\n <Field label=\"Ends\" required>\n <Input type=\"datetime-local\" value={endAt} onChange={(e) => setEndAt(e.target.value)} />\n </Field>\n <Field label=\"Prize pool\">\n <Input\n type=\"number\"\n min={0}\n value={prizePool}\n onChange={(e) => setPrizePool(e.target.value)}\n placeholder=\"5000\"\n />\n </Field>\n <Field label=\"Max team size\">\n <Input\n type=\"number\"\n min={1}\n value={maxTeamSize}\n onChange={(e) => setMaxTeamSize(e.target.value)}\n placeholder=\"4\"\n />\n </Field>\n <Field label=\"Description\" className=\"sm:col-span-2\">\n <Textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What the hackathon is about and how judging works.\"\n />\n </Field>\n </FormCard>\n ) : null}\n\n {loading && !hackathons.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load hackathons\" error={error} />\n ) : hackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={26} />}\n title=\"No hackathons yet\"\n description=\"Create your first hackathon with the button above. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {hackathons.map((h) => (\n <RowShell\n key={h.id}\n actions={\n h.status === 'DRAFT' ? (\n <Button size=\"sm\" onClick={() => handleOpen(h.id)} disabled={actingId === h.id}>\n <Rocket size={15} /> Open registration\n </Button>\n ) : undefined\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">{h.title}</span>\n <StatusBadge status={h.status} />\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {h.slug} · {formatDateTime(h.startAt)} → {formatDateTime(h.endAt)}\n {h.prizePool ? ` · ${formatMoney(h.prizePool, h.currency)} prize` : ''}\n </div>\n </RowShell>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* --------------------------------------------------------------- Mentors */\n\nfunction MentorsTab() {\n const { data, loading, error, refetch } = useMentorsQuery({});\n const [approveMentor] = useApproveMentor();\n const [actingId, setActingId] = useState<string | null>(null);\n\n const mentors = data?.tecListMentors.items ?? [];\n const pending = mentors.filter((m) => m.status === 'PENDING').length;\n\n const handleApprove = async (id: string) => {\n setActingId(id);\n try {\n const res = await approveMentor({ variables: { id } });\n if (res.data?.tecApproveMentor) {\n notify.success('Mentor approved', 'They can now accept mentees.');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${mentors.length} mentor${mentors.length === 1 ? '' : 's'}${\n pending ? ` · ${pending} pending approval` : ''\n }`}\n />\n\n {loading && !mentors.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load mentors\" error={error} />\n ) : mentors.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"No mentors yet\"\n description=\"Mentor applications will appear here for review. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {mentors.map((m) => (\n <RowShell\n key={m.id}\n actions={\n m.status === 'PENDING' ? (\n <Button\n size=\"sm\"\n onClick={() => handleApprove(m.id)}\n disabled={actingId === m.id}\n >\n <UserCheck size={15} /> Approve\n </Button>\n ) : undefined\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {m.headline}\n </span>\n <StatusBadge status={m.status} />\n {m.isAcceptingMentees ? (\n <Badge variant=\"secondary\" className=\"text-[11px]\">\n Accepting mentees\n </Badge>\n ) : null}\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {m.expertise.length ? m.expertise.slice(0, 4).join(', ') : 'No expertise listed'} ·{' '}\n {formatMoney(m.hourlyRate, m.currency)}/hr · {m.sessionsCount} sessions\n </div>\n </RowShell>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------ page shell */\n\ntype AdminTab = 'courses' | 'problems' | 'hackathons' | 'mentors';\n\nexport function AdminAdminDashboardPagePage() {\n const [tab, setTab] = useState<AdminTab>('courses');\n\n return (\n <PageLayout\n hero\n title=\"Authoring Console\"\n description=\"Create and manage TechnoSpam content — courses, problems, hackathons, and mentor applications.\"\n >\n <Tabs value={tab} onValueChange={(v) => setTab(v as AdminTab)}>\n <TabsList className=\"mb-5\">\n <TabsTrigger value=\"courses\">\n <BookOpen size={15} /> Courses\n </TabsTrigger>\n <TabsTrigger value=\"problems\">\n <Code2 size={15} /> Problems\n </TabsTrigger>\n <TabsTrigger value=\"hackathons\">\n <Trophy size={15} /> Hackathons\n </TabsTrigger>\n <TabsTrigger value=\"mentors\">\n <Users size={15} /> Mentors\n </TabsTrigger>\n </TabsList>\n </Tabs>\n\n {tab === 'courses' ? (\n <CoursesTab />\n ) : tab === 'problems' ? (\n <ProblemsTab />\n ) : tab === 'hackathons' ? (\n <HackathonsTab />\n ) : (\n <MentorsTab />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AdminAdminDashboardPagePage.js","names":[],"sources":["../../../src/technospam/pages/AdminAdminDashboardPagePage.tsx"],"sourcesContent":["import { useState, type ReactNode } from 'react';\nimport {\n Archive,\n Award,\n BookOpen,\n Code2,\n Gavel,\n ListChecks,\n Play,\n Plus,\n Rocket,\n ShieldAlert,\n Trophy,\n UserCheck,\n Users,\n X,\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 TabsList,\n TabsTrigger,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { EmptyView, ErrorView, LoadingRows, PageLayout, StatusBadge } from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport {\n useApproveMentor,\n useArchiveCourse,\n useCompleteHackathon,\n useCoursesQuery,\n useCreateCourse,\n useCreateHackathon,\n useCreateLesson,\n useCreateProblem,\n useGradeSubmission,\n useHackathonsQuery,\n useLessonsQuery,\n useMentorsQuery,\n useOpenRegistration,\n useProblemsQuery,\n usePublishCourse,\n usePublishProblem,\n useScoreTeam,\n useStartHackathon,\n useStartJudging,\n useSubmissionsQuery,\n useTeamsQuery,\n type TecCourseLevel,\n type TecHackathon,\n type TecLessonKind,\n type TecProblemDifficulty,\n type TecSubmissionVerdict,\n} from '../api/technospamApi';\nimport { formatDateTime, formatDuration, formatMoney, humanizeEnum } from '../utils/format';\nimport { notify } from '../lib/toast';\n\nconst LESSON_KINDS: TecLessonKind[] = ['ARTICLE', 'VIDEO', 'INTERACTIVE', 'QUIZ', 'PROJECT'];\nconst VERDICTS: TecSubmissionVerdict[] = [\n 'ACCEPTED',\n 'WRONG_ANSWER',\n 'TIME_LIMIT_EXCEEDED',\n 'RUNTIME_ERROR',\n 'COMPILE_ERROR',\n];\n\n/* --------------------------------------------------------------- helpers */\n\nconst LEVELS: TecCourseLevel[] = ['BEGINNER', 'INTERMEDIATE', 'ADVANCED', 'EXPERT'];\nconst DIFFICULTIES: TecProblemDifficulty[] = ['EASY', 'MEDIUM', 'HARD'];\n\n/** lowercase-hyphenated, safe for URL slugs. */\nfunction slugify(value: string): string {\n return value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nfunction parseCsv(value: string): string[] {\n return value\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n}\n\nfunction parseIntOrUndef(value: string): number | undefined {\n const n = Number.parseInt(value, 10);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction toIsoOrNull(local: string): string | null {\n if (!local) return null;\n const d = new Date(local);\n return Number.isNaN(d.getTime()) ? null : d.toISOString();\n}\n\n/* ----------------------------------------------------------- form atoms */\n\nfunction Field({\n label,\n required,\n className,\n children,\n}: {\n label: string;\n required?: boolean;\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={`flex flex-col gap-1.5 ${className ?? ''}`}>\n <span className=\"text-xs font-medium text-text-secondary\">\n {label}\n {required ? <span className=\"text-status-error-text\"> *</span> : null}\n </span>\n {children}\n </div>\n );\n}\n\nfunction FormCard({\n title,\n children,\n footer,\n}: {\n title: string;\n children: ReactNode;\n footer: ReactNode;\n}) {\n return (\n <GlassCard className=\"space-y-4 p-4 sm:p-5\">\n <h3 className=\"text-sm font-semibold text-text-primary\">{title}</h3>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">{children}</div>\n <div className=\"flex justify-end gap-2\">{footer}</div>\n </GlassCard>\n );\n}\n\nfunction TabHeader({\n summary,\n actionLabel,\n open,\n onToggle,\n}: {\n summary: string;\n actionLabel?: string;\n open?: boolean;\n onToggle?: () => void;\n}) {\n return (\n <div className=\"flex items-center justify-between gap-3\">\n <p className=\"text-sm text-text-secondary\">{summary}</p>\n {actionLabel && onToggle ? (\n <Button size=\"sm\" variant={open ? 'outline' : 'default'} onClick={onToggle}>\n {open ? <X size={15} /> : <Plus size={15} />}\n {open ? 'Close' : actionLabel}\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction RowShell({ children, actions }: { children: ReactNode; actions?: ReactNode }) {\n return (\n <GlassCard className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0\">{children}</div>\n {actions ? <div className=\"flex shrink-0 flex-wrap items-center gap-2\">{actions}</div> : null}\n </GlassCard>\n );\n}\n\n/* -------------------------------------------- lesson authoring (per course) */\n\nfunction LessonManager({ courseId }: { courseId: string }) {\n const { data, loading, refetch } = useLessonsQuery(courseId);\n const [createLesson, { loading: creating }] = useCreateLesson();\n const [title, setTitle] = useState('');\n const [kind, setKind] = useState<TecLessonKind>('ARTICLE');\n const [content, setContent] = useState('');\n const [minutes, setMinutes] = useState('');\n const [preview, setPreview] = useState(false);\n\n const lessons = [...(data?.tecListLessons ?? [])].sort((a, b) => a.position - b.position);\n\n const addLesson = async () => {\n const t = title.trim();\n if (!t) return notify.error('Lesson title is required');\n const res = await createLesson({\n variables: {\n input: {\n courseId,\n title: t,\n kind,\n content: content.trim() || undefined,\n position: lessons.length + 1,\n estimatedMinutes: parseIntOrUndef(minutes),\n isPreview: preview,\n },\n },\n });\n if (res.data?.tecCreateLesson) {\n notify.success('Lesson added', t);\n setTitle('');\n setContent('');\n setMinutes('');\n setPreview(false);\n await refetch();\n }\n };\n\n return (\n <div className=\"mt-3 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <div className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-muted\">\n Curriculum ({lessons.length})\n </div>\n {loading && lessons.length === 0 ? (\n <LoadingRows count={2} height=\"h-10\" />\n ) : lessons.length === 0 ? (\n <p className=\"mb-3 text-xs text-text-muted\">No lessons yet — add the first below.</p>\n ) : (\n <ol className=\"mb-3 space-y-1\">\n {lessons.map((l, i) => (\n <li key={l.id} className=\"flex items-center gap-2 text-sm text-text-primary\">\n <span className=\"text-xs text-text-muted\">{i + 1}.</span>\n <span className=\"truncate\">{l.title}</span>\n <Badge variant=\"secondary\" className=\"text-[11px]\">\n {humanizeEnum(l.kind)}\n </Badge>\n {l.isPreview ? (\n <Badge variant=\"outline\" className=\"text-[11px]\">\n Preview\n </Badge>\n ) : null}\n <span className=\"ml-auto text-xs text-text-muted\">\n {formatDuration(l.estimatedMinutes)}\n </span>\n </li>\n ))}\n </ol>\n )}\n <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n <Input\n placeholder=\"Lesson title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n />\n <Select value={kind} onValueChange={(v) => setKind(v as TecLessonKind)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {LESSON_KINDS.map((k) => (\n <SelectItem key={k} value={k}>\n {humanizeEnum(k)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <Textarea\n className=\"mt-2\"\n placeholder=\"Lesson content (markdown / notes)\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n />\n <div className=\"mt-2 flex flex-wrap items-center gap-3\">\n <Input\n type=\"number\"\n className=\"w-28\"\n placeholder=\"Minutes\"\n value={minutes}\n onChange={(e) => setMinutes(e.target.value)}\n />\n <label className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <input type=\"checkbox\" checked={preview} onChange={(e) => setPreview(e.target.checked)} />\n Free preview\n </label>\n <Button size=\"sm\" onClick={addLesson} disabled={creating} className=\"ml-auto\">\n <Plus size={14} /> Add lesson\n </Button>\n </div>\n </div>\n );\n}\n\n/* --------------------------------------- submission grading (per problem) */\n\nfunction SubmissionGrader({ problemId }: { problemId: string }) {\n const { data, loading, refetch } = useSubmissionsQuery({ problemId });\n const [gradeSubmission] = useGradeSubmission();\n const [gradingId, setGradingId] = useState<string | null>(null);\n\n const submissions = data?.tecListSubmissions.items ?? [];\n const grade = async (id: string, verdict: TecSubmissionVerdict) => {\n setGradingId(id);\n try {\n const res = await gradeSubmission({ variables: { id, verdict } });\n if (res.data?.tecGradeSubmission) {\n notify.success('Submission graded', humanizeEnum(verdict));\n await refetch();\n }\n } finally {\n setGradingId(null);\n }\n };\n\n return (\n <div className=\"mt-3 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <div className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-muted\">\n Submissions ({submissions.length})\n </div>\n {loading && submissions.length === 0 ? (\n <LoadingRows count={2} height=\"h-10\" />\n ) : submissions.length === 0 ? (\n <p className=\"text-xs text-text-muted\">No submissions yet.</p>\n ) : (\n <div className=\"space-y-2\">\n {submissions.map((s) => (\n <div key={s.id} className=\"flex flex-wrap items-center gap-2 text-sm\">\n <StatusBadge status={s.verdict} />\n <span className=\"text-xs text-text-muted\">{s.language}</span>\n <span className=\"text-xs text-text-muted\">{formatDateTime(s.createdAt)}</span>\n {s.verdict === 'PENDING' ? (\n <div className=\"ml-auto flex flex-wrap gap-1\">\n {VERDICTS.map((v) => (\n <Button\n key={v}\n size=\"sm\"\n variant={v === 'ACCEPTED' ? 'default' : 'outline'}\n onClick={() => grade(s.id, v)}\n disabled={gradingId === s.id}\n >\n {v === 'ACCEPTED' ? 'Accept' : humanizeEnum(v)}\n </Button>\n ))}\n </div>\n ) : (\n <span className=\"ml-auto text-xs text-text-muted\">{s.pointsAwarded} pts</span>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* -------------------------------- hackathon lifecycle + judging (per event) */\n\nfunction HackathonManager({ hackathon }: { hackathon: TecHackathon }) {\n const { data, loading, refetch } = useTeamsQuery(hackathon.id);\n const [scoreTeam] = useScoreTeam();\n const [scoringId, setScoringId] = useState<string | null>(null);\n const [scores, setScores] = useState<Record<string, string>>({});\n\n const teams = data?.tecListTeams ?? [];\n const submitScore = async (teamId: string, winner: boolean) => {\n const score = Math.max(0, Number(scores[teamId] ?? '0') || 0);\n setScoringId(teamId);\n try {\n const res = await scoreTeam({ variables: { id: teamId, score, winner } });\n if (res.data?.tecScoreTeam) {\n notify.success('Team scored', `${score} pts${winner ? ' · winner' : ''}`);\n await refetch();\n }\n } finally {\n setScoringId(null);\n }\n };\n\n return (\n <div className=\"mt-3 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <div className=\"mb-2 text-xs font-semibold uppercase tracking-wide text-text-muted\">\n Teams ({teams.length})\n </div>\n {loading && teams.length === 0 ? (\n <LoadingRows count={2} height=\"h-10\" />\n ) : teams.length === 0 ? (\n <p className=\"text-xs text-text-muted\">No teams registered yet.</p>\n ) : (\n <div className=\"space-y-2\">\n {teams.map((t) => (\n <div key={t.id} className=\"flex flex-wrap items-center gap-2 text-sm\">\n <span className=\"truncate font-medium text-text-primary\">{t.name}</span>\n <StatusBadge status={t.status} />\n {t.projectName ? (\n <span className=\"text-xs text-text-muted\">{t.projectName}</span>\n ) : null}\n {hackathon.status === 'JUDGING' ? (\n <div className=\"ml-auto flex items-center gap-1\">\n <Input\n type=\"number\"\n className=\"w-20\"\n placeholder=\"Score\"\n value={scores[t.id] ?? ''}\n onChange={(e) => setScores((s) => ({ ...s, [t.id]: e.target.value }))}\n />\n <Button\n size=\"sm\"\n onClick={() => submitScore(t.id, false)}\n disabled={scoringId === t.id}\n >\n Score\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => submitScore(t.id, true)}\n disabled={scoringId === t.id}\n >\n <Trophy size={14} /> Winner\n </Button>\n </div>\n ) : (\n <span className=\"ml-auto text-xs text-text-muted\">{t.score} pts</span>\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* --------------------------------------------------------------- Courses */\n\nfunction CoursesTab() {\n const { data, loading, error, refetch } = useCoursesQuery({});\n const [createCourse, { loading: creating }] = useCreateCourse();\n const [publishCourse] = usePublishCourse();\n const [archiveCourse] = useArchiveCourse();\n\n const [showForm, setShowForm] = useState(false);\n const [actingId, setActingId] = useState<string | null>(null);\n const [lessonsFor, setLessonsFor] = useState<string | null>(null);\n\n const [title, setTitle] = useState('');\n const [slug, setSlug] = useState('');\n const [summary, setSummary] = useState('');\n const [topic, setTopic] = useState('');\n const [level, setLevel] = useState<TecCourseLevel>('BEGINNER');\n const [minutes, setMinutes] = useState('');\n const [tags, setTags] = useState('');\n\n const courses = data?.tecListCourses.items ?? [];\n\n const resetForm = () => {\n setTitle('');\n setSlug('');\n setSummary('');\n setTopic('');\n setLevel('BEGINNER');\n setMinutes('');\n setTags('');\n setShowForm(false);\n };\n\n const handleCreate = async () => {\n const t = title.trim();\n if (!t) return notify.error('Title is required');\n const finalSlug = slugify(slug || t);\n if (!finalSlug) return notify.error('A valid slug is required');\n const res = await createCourse({\n variables: {\n input: {\n title: t,\n slug: finalSlug,\n summary: summary.trim() || undefined,\n topic: topic.trim() || undefined,\n level,\n estimatedMinutes: parseIntOrUndef(minutes),\n tags: parseCsv(tags),\n },\n },\n });\n if (res.data?.tecCreateCourse) {\n notify.success('Course created', `\"${t}\" saved as a draft.`);\n resetForm();\n await refetch();\n }\n };\n\n const handlePublish = async (id: string) => {\n setActingId(id);\n try {\n const res = await publishCourse({ variables: { id } });\n if (res.data?.tecPublishCourse) {\n notify.success('Course published');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n const handleArchive = async (id: string) => {\n setActingId(id);\n try {\n const res = await archiveCourse({ variables: { id } });\n if (res.data?.tecArchiveCourse) {\n notify.success('Course archived');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${courses.length} course${courses.length === 1 ? '' : 's'}`}\n actionLabel=\"New course\"\n open={showForm}\n onToggle={() => setShowForm((v) => !v)}\n />\n\n {showForm ? (\n <FormCard\n title=\"New course\"\n footer={\n <>\n <Button variant=\"outline\" size=\"sm\" onClick={resetForm}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={creating}>\n {creating ? 'Creating…' : 'Create course'}\n </Button>\n </>\n }\n >\n <Field label=\"Title\" required>\n <Input\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"Intro to TypeScript\"\n />\n </Field>\n <Field label=\"Slug\" required>\n <Input\n value={slug}\n onChange={(e) => setSlug(e.target.value)}\n placeholder=\"auto from title if blank\"\n />\n </Field>\n <Field label=\"Topic\">\n <Input\n value={topic}\n onChange={(e) => setTopic(e.target.value)}\n placeholder=\"e.g. Web, AI, Data, Cloud\"\n />\n </Field>\n <Field label=\"Level\">\n <Select value={level} onValueChange={(v) => setLevel(v as TecCourseLevel)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {LEVELS.map((l) => (\n <SelectItem key={l} value={l}>\n {humanizeEnum(l)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Estimated minutes\">\n <Input\n type=\"number\"\n min={0}\n value={minutes}\n onChange={(e) => setMinutes(e.target.value)}\n placeholder=\"120\"\n />\n </Field>\n <Field label=\"Tags (comma-separated)\">\n <Input\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder=\"typescript, basics\"\n />\n </Field>\n <Field label=\"Summary\" className=\"sm:col-span-2\">\n <Textarea\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n placeholder=\"What learners will build and take away.\"\n />\n </Field>\n </FormCard>\n ) : null}\n\n {loading && !courses.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load courses\" error={error} />\n ) : courses.length === 0 ? (\n <EmptyView\n icon={<BookOpen size={26} />}\n title=\"No courses yet\"\n description=\"Create your first course with the button above. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {courses.map((c) => (\n <div key={c.id}>\n <RowShell\n actions={\n <>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setLessonsFor(lessonsFor === c.id ? null : c.id)}\n >\n <ListChecks size={15} /> Lessons\n </Button>\n {c.status === 'DRAFT' ? (\n <Button\n size=\"sm\"\n onClick={() => handlePublish(c.id)}\n disabled={actingId === c.id}\n >\n <Rocket size={15} /> Publish\n </Button>\n ) : null}\n {c.status !== 'ARCHIVED' ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => handleArchive(c.id)}\n disabled={actingId === c.id}\n >\n <Archive size={15} /> Archive\n </Button>\n ) : null}\n </>\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {c.title}\n </span>\n <StatusBadge status={c.status} />\n <StatusBadge status={c.level} kind=\"level\" />\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {c.slug} · {c.topic ?? 'No topic'} · {formatDuration(c.estimatedMinutes)}\n </div>\n </RowShell>\n {lessonsFor === c.id ? <LessonManager courseId={c.id} /> : null}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* -------------------------------------------------------------- Problems */\n\nfunction ProblemsTab() {\n const { data, loading, error, refetch } = useProblemsQuery({});\n const [createProblem, { loading: creating }] = useCreateProblem();\n const [publishProblem] = usePublishProblem();\n\n const [showForm, setShowForm] = useState(false);\n const [actingId, setActingId] = useState<string | null>(null);\n const [gradeFor, setGradeFor] = useState<string | null>(null);\n\n const [title, setTitle] = useState('');\n const [slug, setSlug] = useState('');\n const [statement, setStatement] = useState('');\n const [topic, setTopic] = useState('');\n const [difficulty, setDifficulty] = useState<TecProblemDifficulty>('EASY');\n const [points, setPoints] = useState('');\n const [languages, setLanguages] = useState('');\n const [starterCode, setStarterCode] = useState('');\n\n const problems = data?.tecListProblems.items ?? [];\n\n const resetForm = () => {\n setTitle('');\n setSlug('');\n setStatement('');\n setTopic('');\n setDifficulty('EASY');\n setPoints('');\n setLanguages('');\n setStarterCode('');\n setShowForm(false);\n };\n\n const handleCreate = async () => {\n const t = title.trim();\n if (!t) return notify.error('Title is required');\n const finalSlug = slugify(slug || t);\n if (!finalSlug) return notify.error('A valid slug is required');\n const res = await createProblem({\n variables: {\n input: {\n title: t,\n slug: finalSlug,\n statement: statement.trim() || undefined,\n topic: topic.trim() || undefined,\n difficulty,\n points: parseIntOrUndef(points),\n languages: parseCsv(languages),\n starterCode: starterCode.trim() || undefined,\n },\n },\n });\n if (res.data?.tecCreateProblem) {\n notify.success('Problem created', `\"${t}\" saved as a draft.`);\n resetForm();\n await refetch();\n }\n };\n\n const handlePublish = async (id: string) => {\n setActingId(id);\n try {\n const res = await publishProblem({ variables: { id } });\n if (res.data?.tecPublishProblem) {\n notify.success('Problem published');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${problems.length} problem${problems.length === 1 ? '' : 's'}`}\n actionLabel=\"New problem\"\n open={showForm}\n onToggle={() => setShowForm((v) => !v)}\n />\n\n {showForm ? (\n <FormCard\n title=\"New problem\"\n footer={\n <>\n <Button variant=\"outline\" size=\"sm\" onClick={resetForm}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={creating}>\n {creating ? 'Creating…' : 'Create problem'}\n </Button>\n </>\n }\n >\n <Field label=\"Title\" required>\n <Input value={title} onChange={(e) => setTitle(e.target.value)} placeholder=\"Two Sum\" />\n </Field>\n <Field label=\"Slug\" required>\n <Input\n value={slug}\n onChange={(e) => setSlug(e.target.value)}\n placeholder=\"auto from title if blank\"\n />\n </Field>\n <Field label=\"Topic\">\n <Input value={topic} onChange={(e) => setTopic(e.target.value)} placeholder=\"Arrays\" />\n </Field>\n <Field label=\"Difficulty\">\n <Select\n value={difficulty}\n onValueChange={(v) => setDifficulty(v as TecProblemDifficulty)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {DIFFICULTIES.map((d) => (\n <SelectItem key={d} value={d}>\n {humanizeEnum(d)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n <Field label=\"Points\">\n <Input\n type=\"number\"\n min={0}\n value={points}\n onChange={(e) => setPoints(e.target.value)}\n placeholder=\"100\"\n />\n </Field>\n <Field label=\"Languages (comma-separated)\">\n <Input\n value={languages}\n onChange={(e) => setLanguages(e.target.value)}\n placeholder=\"python, typescript\"\n />\n </Field>\n <Field label=\"Statement\" className=\"sm:col-span-2\">\n <Textarea\n value={statement}\n onChange={(e) => setStatement(e.target.value)}\n placeholder=\"Describe the problem and constraints.\"\n />\n </Field>\n <Field label=\"Starter code\" className=\"sm:col-span-2\">\n <Textarea\n value={starterCode}\n onChange={(e) => setStarterCode(e.target.value)}\n className=\"font-mono\"\n placeholder=\"def solve(nums, target):\\n pass\"\n />\n </Field>\n </FormCard>\n ) : null}\n\n {loading && !problems.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load problems\" error={error} />\n ) : problems.length === 0 ? (\n <EmptyView\n icon={<Code2 size={26} />}\n title=\"No problems yet\"\n description=\"Create your first coding problem with the button above. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {problems.map((p) => (\n <div key={p.id}>\n <RowShell\n actions={\n <>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setGradeFor(gradeFor === p.id ? null : p.id)}\n >\n <Gavel size={15} /> Grade\n </Button>\n {p.status === 'DRAFT' ? (\n <Button\n size=\"sm\"\n onClick={() => handlePublish(p.id)}\n disabled={actingId === p.id}\n >\n <Rocket size={15} /> Publish\n </Button>\n ) : null}\n </>\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {p.title}\n </span>\n <StatusBadge status={p.status} />\n <StatusBadge status={p.difficulty} kind=\"level\" />\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {p.slug} · {p.topic ?? 'No topic'} · {p.points} pts ·{' '}\n {p.languages.length ? p.languages.join(', ') : 'No languages'}\n </div>\n </RowShell>\n {gradeFor === p.id ? <SubmissionGrader problemId={p.id} /> : null}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------ Hackathons */\n\nfunction HackathonsTab() {\n const { data, loading, error, refetch } = useHackathonsQuery({});\n const [createHackathon, { loading: creating }] = useCreateHackathon();\n const [openRegistration] = useOpenRegistration();\n const [startHackathon] = useStartHackathon();\n const [startJudging] = useStartJudging();\n const [completeHackathon] = useCompleteHackathon();\n\n const [showForm, setShowForm] = useState(false);\n const [actingId, setActingId] = useState<string | null>(null);\n const [judgeFor, setJudgeFor] = useState<string | null>(null);\n\n const [title, setTitle] = useState('');\n const [slug, setSlug] = useState('');\n const [theme, setTheme] = useState('');\n const [description, setDescription] = useState('');\n const [startAt, setStartAt] = useState('');\n const [endAt, setEndAt] = useState('');\n const [prizePool, setPrizePool] = useState('');\n const [maxTeamSize, setMaxTeamSize] = useState('');\n const [tags, setTags] = useState('');\n\n const hackathons = data?.tecListHackathons.items ?? [];\n\n const resetForm = () => {\n setTitle('');\n setSlug('');\n setTheme('');\n setDescription('');\n setStartAt('');\n setEndAt('');\n setPrizePool('');\n setMaxTeamSize('');\n setTags('');\n setShowForm(false);\n };\n\n const handleCreate = async () => {\n const t = title.trim();\n if (!t) return notify.error('Title is required');\n const finalSlug = slugify(slug || t);\n if (!finalSlug) return notify.error('A valid slug is required');\n const startIso = toIsoOrNull(startAt);\n const endIso = toIsoOrNull(endAt);\n if (!startIso || !endIso) return notify.error('Start and end date/time are required');\n if (new Date(endIso) <= new Date(startIso)) return notify.error('End must be after the start');\n const res = await createHackathon({\n variables: {\n input: {\n title: t,\n slug: finalSlug,\n theme: theme.trim() || undefined,\n description: description.trim() || undefined,\n startAt: startIso,\n endAt: endIso,\n prizePool: parseIntOrUndef(prizePool),\n maxTeamSize: parseIntOrUndef(maxTeamSize),\n tags: parseCsv(tags),\n },\n },\n });\n if (res.data?.tecCreateHackathon) {\n notify.success('Hackathon created', `\"${t}\" saved as a draft.`);\n resetForm();\n await refetch();\n }\n };\n\n const handleOpen = async (id: string) => {\n setActingId(id);\n try {\n const res = await openRegistration({ variables: { id } });\n if (res.data?.tecOpenRegistration) {\n notify.success('Registration open', 'Teams can now register.');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n const advance = async (\n id: string,\n run: (v: { variables: { id: string } }) => Promise<{ data?: unknown }>,\n message: string\n ) => {\n setActingId(id);\n try {\n const res = await run({ variables: { id } });\n if (res.data) {\n notify.success(message);\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${hackathons.length} hackathon${hackathons.length === 1 ? '' : 's'}`}\n actionLabel=\"New hackathon\"\n open={showForm}\n onToggle={() => setShowForm((v) => !v)}\n />\n\n {showForm ? (\n <FormCard\n title=\"New hackathon\"\n footer={\n <>\n <Button variant=\"outline\" size=\"sm\" onClick={resetForm}>\n Cancel\n </Button>\n <Button size=\"sm\" onClick={handleCreate} disabled={creating}>\n {creating ? 'Creating…' : 'Create hackathon'}\n </Button>\n </>\n }\n >\n <Field label=\"Title\" required>\n <Input\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"Build Days 2026\"\n />\n </Field>\n <Field label=\"Slug\" required>\n <Input\n value={slug}\n onChange={(e) => setSlug(e.target.value)}\n placeholder=\"auto from title if blank\"\n />\n </Field>\n <Field label=\"Theme\">\n <Input\n value={theme}\n onChange={(e) => setTheme(e.target.value)}\n placeholder=\"AI for good\"\n />\n </Field>\n <Field label=\"Tags (comma-separated)\">\n <Input value={tags} onChange={(e) => setTags(e.target.value)} placeholder=\"ai, web\" />\n </Field>\n <Field label=\"Starts\" required>\n <Input\n type=\"datetime-local\"\n value={startAt}\n onChange={(e) => setStartAt(e.target.value)}\n />\n </Field>\n <Field label=\"Ends\" required>\n <Input type=\"datetime-local\" value={endAt} onChange={(e) => setEndAt(e.target.value)} />\n </Field>\n <Field label=\"Prize pool\">\n <Input\n type=\"number\"\n min={0}\n value={prizePool}\n onChange={(e) => setPrizePool(e.target.value)}\n placeholder=\"5000\"\n />\n </Field>\n <Field label=\"Max team size\">\n <Input\n type=\"number\"\n min={1}\n value={maxTeamSize}\n onChange={(e) => setMaxTeamSize(e.target.value)}\n placeholder=\"4\"\n />\n </Field>\n <Field label=\"Description\" className=\"sm:col-span-2\">\n <Textarea\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What the hackathon is about and how judging works.\"\n />\n </Field>\n </FormCard>\n ) : null}\n\n {loading && !hackathons.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load hackathons\" error={error} />\n ) : hackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={26} />}\n title=\"No hackathons yet\"\n description=\"Create your first hackathon with the button above. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {hackathons.map((h) => (\n <div key={h.id}>\n <RowShell\n actions={\n <>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setJudgeFor(judgeFor === h.id ? null : h.id)}\n >\n <Users size={15} /> Teams\n </Button>\n {h.status === 'DRAFT' ? (\n <Button\n size=\"sm\"\n onClick={() => handleOpen(h.id)}\n disabled={actingId === h.id}\n >\n <Rocket size={15} /> Open registration\n </Button>\n ) : null}\n {h.status === 'REGISTRATION_OPEN' ? (\n <Button\n size=\"sm\"\n onClick={() => advance(h.id, startHackathon, 'Hackathon started')}\n disabled={actingId === h.id}\n >\n <Play size={15} /> Start\n </Button>\n ) : null}\n {h.status === 'IN_PROGRESS' ? (\n <Button\n size=\"sm\"\n onClick={() => advance(h.id, startJudging, 'Judging started')}\n disabled={actingId === h.id}\n >\n <Gavel size={15} /> Start judging\n </Button>\n ) : null}\n {h.status === 'JUDGING' ? (\n <Button\n size=\"sm\"\n onClick={() => advance(h.id, completeHackathon, 'Hackathon completed')}\n disabled={actingId === h.id}\n >\n <Award size={15} /> Complete\n </Button>\n ) : null}\n </>\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {h.title}\n </span>\n <StatusBadge status={h.status} />\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {h.slug} · {formatDateTime(h.startAt)} → {formatDateTime(h.endAt)}\n {h.prizePool ? ` · ${formatMoney(h.prizePool, h.currency)} prize` : ''}\n </div>\n </RowShell>\n {judgeFor === h.id ? <HackathonManager hackathon={h} /> : null}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* --------------------------------------------------------------- Mentors */\n\nfunction MentorsTab() {\n const { data, loading, error, refetch } = useMentorsQuery({});\n const [approveMentor] = useApproveMentor();\n const [actingId, setActingId] = useState<string | null>(null);\n\n const mentors = data?.tecListMentors.items ?? [];\n const pending = mentors.filter((m) => m.status === 'PENDING').length;\n\n const handleApprove = async (id: string) => {\n setActingId(id);\n try {\n const res = await approveMentor({ variables: { id } });\n if (res.data?.tecApproveMentor) {\n notify.success('Mentor approved', 'They can now accept mentees.');\n await refetch();\n }\n } finally {\n setActingId(null);\n }\n };\n\n return (\n <div className=\"space-y-4\">\n <TabHeader\n summary={`${mentors.length} mentor${mentors.length === 1 ? '' : 's'}${\n pending ? ` · ${pending} pending approval` : ''\n }`}\n />\n\n {loading && !mentors.length ? (\n <LoadingRows count={4} />\n ) : error ? (\n <ErrorView title=\"Couldn't load mentors\" error={error} />\n ) : mentors.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"No mentors yet\"\n description=\"Mentor applications will appear here for review. TechnoSpam is pre-launch.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {mentors.map((m) => (\n <RowShell\n key={m.id}\n actions={\n m.status === 'PENDING' ? (\n <Button\n size=\"sm\"\n onClick={() => handleApprove(m.id)}\n disabled={actingId === m.id}\n >\n <UserCheck size={15} /> Approve\n </Button>\n ) : undefined\n }\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {m.headline}\n </span>\n <StatusBadge status={m.status} />\n {m.isAcceptingMentees ? (\n <Badge variant=\"secondary\" className=\"text-[11px]\">\n Accepting mentees\n </Badge>\n ) : null}\n </div>\n <div className=\"mt-1 truncate text-xs text-text-muted\">\n {m.expertise.length ? m.expertise.slice(0, 4).join(', ') : 'No expertise listed'} ·{' '}\n {formatMoney(m.hourlyRate, m.currency)}/hr · {m.sessionsCount} sessions\n </div>\n </RowShell>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/* ------------------------------------------------------------ page shell */\n\ntype AdminTab = 'courses' | 'problems' | 'hackathons' | 'mentors';\n\nexport function AdminAdminDashboardPagePage() {\n const [tab, setTab] = useState<AdminTab>('courses');\n const { currentUser } = useTechnoSpam();\n const role = (currentUser?.role ?? '').toLowerCase();\n const privileged =\n role.includes('admin') || role.includes('owner') || role.includes('instructor');\n\n return (\n <PageLayout\n hero\n title=\"Authoring Console\"\n description=\"Create and manage TechnoSpam content — courses, problems, hackathons, and mentor applications.\"\n >\n {!privileged ? (\n <GlassCard className=\"mb-5 flex items-start gap-3 border-status-warning-border p-4\">\n <ShieldAlert size={18} className=\"mt-0.5 shrink-0 text-status-warning-text\" />\n <div className=\"text-sm text-text-secondary\">\n <span className=\"font-medium text-text-primary\">\n Authoring is limited to workspace admins.\n </span>{' '}\n You can review content here, but create/publish actions require the right permission and\n will be rejected at the gateway otherwise.\n </div>\n </GlassCard>\n ) : null}\n <Tabs value={tab} onValueChange={(v) => setTab(v as AdminTab)}>\n <TabsList className=\"mb-5\">\n <TabsTrigger value=\"courses\">\n <BookOpen size={15} /> Courses\n </TabsTrigger>\n <TabsTrigger value=\"problems\">\n <Code2 size={15} /> Problems\n </TabsTrigger>\n <TabsTrigger value=\"hackathons\">\n <Trophy size={15} /> Hackathons\n </TabsTrigger>\n <TabsTrigger value=\"mentors\">\n <Users size={15} /> Mentors\n </TabsTrigger>\n </TabsList>\n </Tabs>\n\n {tab === 'courses' ? (\n <CoursesTab />\n ) : tab === 'problems' ? (\n <ProblemsTab />\n ) : tab === 'hackathons' ? (\n <HackathonsTab />\n ) : (\n <MentorsTab />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,15 +2,16 @@ import { useTechnoSpam as e, useTechnoSpamNavigate as t } from "../providers/Tec
|
|
|
2
2
|
import { PageLayout as n } from "../components/PageLayout.js";
|
|
3
3
|
import { StatCard as r } from "../components/StatCard.js";
|
|
4
4
|
import { StatusBadge as i } from "../components/StatusBadge.js";
|
|
5
|
-
import {
|
|
5
|
+
import { LoadMore as a } from "../components/LoadMore.js";
|
|
6
|
+
import { EmptyView as o, ErrorView as s, LoadingGrid as c } from "../components/StateViews.js";
|
|
6
7
|
import "../components/index.js";
|
|
7
|
-
import { useProblemsQuery as
|
|
8
|
-
import { useMemo as
|
|
9
|
-
import { CheckCircle2 as
|
|
10
|
-
import { jsx as
|
|
11
|
-
import { Badge as
|
|
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";
|
|
12
13
|
//#region src/technospam/pages/ApplicationsProblemsPagePage.tsx
|
|
13
|
-
var
|
|
14
|
+
var j = [
|
|
14
15
|
{
|
|
15
16
|
value: "ALL",
|
|
16
17
|
label: "All"
|
|
@@ -28,7 +29,7 @@ var O = [
|
|
|
28
29
|
label: "Hard"
|
|
29
30
|
}
|
|
30
31
|
];
|
|
31
|
-
function
|
|
32
|
+
function M(e) {
|
|
32
33
|
let t = [
|
|
33
34
|
"from-accent-primary/25 to-accent-teal/20",
|
|
34
35
|
"from-accent-teal/25 to-accent-primary/15",
|
|
@@ -38,63 +39,63 @@ function k(e) {
|
|
|
38
39
|
for (let t = 0; t < e.length; t += 1) n = n * 31 + e.charCodeAt(t) >>> 0;
|
|
39
40
|
return t[n % t.length];
|
|
40
41
|
}
|
|
41
|
-
function
|
|
42
|
-
return /* @__PURE__ */
|
|
42
|
+
function N({ problem: e, solved: t, onOpen: n }) {
|
|
43
|
+
return /* @__PURE__ */ w(E, {
|
|
43
44
|
className: "group flex cursor-pointer flex-col overflow-hidden transition-shadow hover:shadow-md",
|
|
44
45
|
onClick: n,
|
|
45
|
-
children: [/* @__PURE__ */
|
|
46
|
-
className: `relative flex h-20 items-end bg-gradient-to-br ${
|
|
46
|
+
children: [/* @__PURE__ */ w("div", {
|
|
47
|
+
className: `relative flex h-20 items-end bg-gradient-to-br ${M(e.topic ?? e.difficulty)} p-4`,
|
|
47
48
|
children: [
|
|
48
|
-
/* @__PURE__ */
|
|
49
|
+
/* @__PURE__ */ C(g, {
|
|
49
50
|
className: "absolute right-3 top-3 text-text-muted/60",
|
|
50
51
|
size: 18
|
|
51
52
|
}),
|
|
52
|
-
t ? /* @__PURE__ */
|
|
53
|
+
t ? /* @__PURE__ */ w("span", {
|
|
53
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",
|
|
54
|
-
children: [/* @__PURE__ */
|
|
55
|
+
children: [/* @__PURE__ */ C(h, { size: 12 }), " Solved"]
|
|
55
56
|
}) : null,
|
|
56
|
-
/* @__PURE__ */
|
|
57
|
+
/* @__PURE__ */ C(i, {
|
|
57
58
|
status: e.difficulty,
|
|
58
59
|
kind: "level"
|
|
59
60
|
})
|
|
60
61
|
]
|
|
61
|
-
}), /* @__PURE__ */
|
|
62
|
+
}), /* @__PURE__ */ w("div", {
|
|
62
63
|
className: "flex flex-1 flex-col gap-3 p-4",
|
|
63
64
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
65
|
+
/* @__PURE__ */ w("div", {
|
|
65
66
|
className: "min-w-0",
|
|
66
|
-
children: [/* @__PURE__ */
|
|
67
|
+
children: [/* @__PURE__ */ C("h3", {
|
|
67
68
|
className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
|
|
68
69
|
children: e.title
|
|
69
|
-
}), e.statement ? /* @__PURE__ */
|
|
70
|
+
}), e.statement ? /* @__PURE__ */ C("p", {
|
|
70
71
|
className: "mt-1 line-clamp-2 text-sm text-text-secondary",
|
|
71
72
|
children: e.statement
|
|
72
73
|
}) : null]
|
|
73
74
|
}),
|
|
74
|
-
/* @__PURE__ */
|
|
75
|
+
/* @__PURE__ */ w("div", {
|
|
75
76
|
className: "mt-auto flex flex-wrap items-center gap-3 text-xs text-text-muted",
|
|
76
77
|
children: [
|
|
77
|
-
e.topic ? /* @__PURE__ */
|
|
78
|
+
e.topic ? /* @__PURE__ */ w("span", {
|
|
78
79
|
className: "inline-flex items-center gap-1",
|
|
79
80
|
children: [
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ C(y, { size: 13 }),
|
|
81
82
|
" ",
|
|
82
83
|
e.topic
|
|
83
84
|
]
|
|
84
85
|
}) : null,
|
|
85
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ w("span", {
|
|
86
87
|
className: "inline-flex items-center gap-1",
|
|
87
88
|
children: [
|
|
88
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ C(S, { size: 13 }),
|
|
89
90
|
" ",
|
|
90
91
|
e.points,
|
|
91
92
|
" pts"
|
|
92
93
|
]
|
|
93
94
|
}),
|
|
94
|
-
e.languages.length ? /* @__PURE__ */
|
|
95
|
+
e.languages.length ? /* @__PURE__ */ w("span", {
|
|
95
96
|
className: "inline-flex items-center gap-1",
|
|
96
97
|
children: [
|
|
97
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ C(g, { size: 13 }),
|
|
98
99
|
" ",
|
|
99
100
|
e.languages.length,
|
|
100
101
|
" lang",
|
|
@@ -103,12 +104,12 @@ function A({ problem: e, solved: t, onOpen: n }) {
|
|
|
103
104
|
}) : null
|
|
104
105
|
]
|
|
105
106
|
}),
|
|
106
|
-
e.tags.length ? /* @__PURE__ */
|
|
107
|
+
e.tags.length ? /* @__PURE__ */ C("div", {
|
|
107
108
|
className: "flex flex-wrap gap-1.5",
|
|
108
|
-
children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */
|
|
109
|
+
children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */ w(T, {
|
|
109
110
|
variant: "secondary",
|
|
110
111
|
className: "text-[11px]",
|
|
111
|
-
children: [/* @__PURE__ */
|
|
112
|
+
children: [/* @__PURE__ */ C(x, {
|
|
112
113
|
size: 10,
|
|
113
114
|
className: "mr-1"
|
|
114
115
|
}), e]
|
|
@@ -118,85 +119,91 @@ function A({ problem: e, solved: t, onOpen: n }) {
|
|
|
118
119
|
})]
|
|
119
120
|
});
|
|
120
121
|
}
|
|
121
|
-
function
|
|
122
|
-
let i = t(), { currentUser:
|
|
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({
|
|
123
124
|
status: "PUBLISHED",
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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();
|
|
129
|
+
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, {
|
|
130
132
|
hero: !0,
|
|
131
133
|
title: "Coding Problems",
|
|
132
|
-
description: "Sharpen your problem-solving with
|
|
134
|
+
description: "Sharpen your problem-solving with hands-on, mentor-judged challenges across topics and difficulty.",
|
|
133
135
|
children: [
|
|
134
|
-
/* @__PURE__ */
|
|
136
|
+
/* @__PURE__ */ w("div", {
|
|
135
137
|
className: "mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
136
138
|
children: [
|
|
137
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ C(r, {
|
|
138
140
|
label: "Problems",
|
|
139
|
-
value:
|
|
140
|
-
icon:
|
|
141
|
+
value: B.length,
|
|
142
|
+
icon: g
|
|
141
143
|
}),
|
|
142
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ C(r, {
|
|
143
145
|
label: "Solved",
|
|
144
|
-
value:
|
|
145
|
-
icon:
|
|
146
|
+
value: U,
|
|
147
|
+
icon: h
|
|
146
148
|
}),
|
|
147
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ C(r, {
|
|
148
150
|
label: "Easy",
|
|
149
|
-
value:
|
|
150
|
-
icon:
|
|
151
|
+
value: W,
|
|
152
|
+
icon: v
|
|
151
153
|
}),
|
|
152
|
-
/* @__PURE__ */
|
|
154
|
+
/* @__PURE__ */ C(r, {
|
|
153
155
|
label: "Hard",
|
|
154
|
-
value:
|
|
155
|
-
icon:
|
|
156
|
+
value: G,
|
|
157
|
+
icon: _
|
|
156
158
|
})
|
|
157
159
|
]
|
|
158
160
|
}),
|
|
159
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ w("div", {
|
|
160
162
|
className: "mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
161
|
-
children: [/* @__PURE__ */
|
|
162
|
-
value:
|
|
163
|
-
onValueChange: (e) =>
|
|
164
|
-
children: /* @__PURE__ */
|
|
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, {
|
|
165
167
|
value: e.value,
|
|
166
168
|
children: e.label
|
|
167
169
|
}, e.value)) })
|
|
168
|
-
}), /* @__PURE__ */
|
|
170
|
+
}), /* @__PURE__ */ w("div", {
|
|
169
171
|
className: "relative w-full sm:w-72",
|
|
170
|
-
children: [/* @__PURE__ */ b
|
|
172
|
+
children: [/* @__PURE__ */ C(b, {
|
|
171
173
|
className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted",
|
|
172
174
|
size: 16
|
|
173
|
-
}), /* @__PURE__ */
|
|
175
|
+
}), /* @__PURE__ */ C(D, {
|
|
174
176
|
className: "pl-9",
|
|
175
177
|
placeholder: "Search problems…",
|
|
176
|
-
value:
|
|
177
|
-
onChange: (e) =>
|
|
178
|
+
value: E,
|
|
179
|
+
onChange: (e) => M(e.target.value)
|
|
178
180
|
})]
|
|
179
181
|
})]
|
|
180
182
|
}),
|
|
181
|
-
|
|
183
|
+
L && !B.length ? /* @__PURE__ */ C(c, {}) : R ? /* @__PURE__ */ C(s, {
|
|
182
184
|
title: "Couldn't load problems",
|
|
183
|
-
error:
|
|
184
|
-
}) :
|
|
185
|
-
icon: /* @__PURE__ */
|
|
186
|
-
title:
|
|
187
|
-
description:
|
|
188
|
-
}) : /* @__PURE__ */
|
|
185
|
+
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", {
|
|
189
191
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
190
|
-
children:
|
|
192
|
+
children: K.map((e) => /* @__PURE__ */ C(N, {
|
|
191
193
|
problem: e,
|
|
192
|
-
solved:
|
|
194
|
+
solved: H.has(e.id),
|
|
193
195
|
onOpen: () => i(`/applications/problem-details-page?id=${e.id}`)
|
|
194
196
|
}, e.id))
|
|
197
|
+
}),
|
|
198
|
+
/* @__PURE__ */ C(a, {
|
|
199
|
+
hasMore: V,
|
|
200
|
+
loading: L,
|
|
201
|
+
onClick: F
|
|
195
202
|
})
|
|
196
203
|
]
|
|
197
204
|
});
|
|
198
205
|
}
|
|
199
206
|
//#endregion
|
|
200
|
-
export {
|
|
207
|
+
export { P as ApplicationsProblemsPagePage };
|
|
201
208
|
|
|
202
209
|
//# 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 LoadingGrid,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\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 { data, loading, error } = useProblemsQuery({\n status: 'PUBLISHED',\n ...(difficulty !== 'ALL' ? { difficulty } : {}),\n });\n const { data: subsData } = useSubmissionsQuery(learnerId ? { learnerId } : {});\n\n const problems = data?.tecListProblems.items ?? [];\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 runnable, 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 </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
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":"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"}
|