@burdenoff/microfe-technospam 2026.705.1 → 2026.709.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/generated/wspace-operations.js +67 -0
  2. package/dist/generated/wspace-operations.js.map +1 -0
  3. package/dist/index.js +3 -1
  4. package/dist/technospam/components/MediaCover.js +57 -0
  5. package/dist/technospam/components/MediaCover.js.map +1 -0
  6. package/dist/technospam/components/PageLayout.js +1 -1
  7. package/dist/technospam/components/PageLayout.js.map +1 -1
  8. package/dist/technospam/components/StatCard.js +19 -11
  9. package/dist/technospam/components/StatCard.js.map +1 -1
  10. package/dist/technospam/components/StatusBadge.js +1 -1
  11. package/dist/technospam/components/StatusBadge.js.map +1 -1
  12. package/dist/technospam/components/index.js +1 -0
  13. package/dist/technospam/hooks/useTechnoSpamAnalytics.js +13 -0
  14. package/dist/technospam/hooks/useTechnoSpamAnalytics.js.map +1 -0
  15. package/dist/technospam/index.js +2 -0
  16. package/dist/technospam/pages/AdminAdminDashboardPagePage.js +525 -459
  17. package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
  18. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +167 -127
  19. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  20. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +178 -101
  21. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
  22. package/dist/technospam/pages/ApplicationsProblemsPagePage.js +103 -99
  23. package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
  24. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +316 -184
  25. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
  26. package/dist/technospam/pages/CoursesCoursesPagePage.js +101 -93
  27. package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
  28. package/dist/technospam/pages/CoursesMyLearningPagePage.js +119 -88
  29. package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
  30. package/dist/technospam/pages/DashboardDashboardPagePage.js +232 -199
  31. package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
  32. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +128 -106
  33. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
  34. package/dist/technospam/pages/HackathonsHackathonsPagePage.js +99 -91
  35. package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
  36. package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +185 -116
  37. package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
  38. package/dist/technospam/pages/MentorshipMentorsPagePage.js +233 -165
  39. package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
  40. package/dist/technospam/pages/MentorshipSessionsPagePage.js +146 -113
  41. package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
  42. package/dist/technospam/services/assistantApi.js +222 -0
  43. package/dist/technospam/services/assistantApi.js.map +1 -0
  44. package/dist/technospam/services/createSandboxAssistantTransport.js +120 -0
  45. package/dist/technospam/services/createSandboxAssistantTransport.js.map +1 -0
  46. package/dist/technospam/utils/pageContext.js +46 -0
  47. package/dist/technospam/utils/pageContext.js.map +1 -0
  48. package/package.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"HackathonsHackathonDetailsPagePage.js","names":[],"sources":["../../../src/technospam/pages/HackathonsHackathonDetailsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport {\n Award,\n CalendarClock,\n CalendarDays,\n ExternalLink,\n Flag,\n Github,\n Send,\n Trophy,\n UserPlus,\n Users,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { EmptyView, ErrorView, PageLayout, StatCard, StatusBadge } from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport {\n useHackathonQuery,\n useRegisterTeam,\n useSubmitProject,\n useTeamsQuery,\n type TecHackathonTeam,\n} from '../api/technospamApi';\nimport { formatDate, formatDateTime, formatMoney } from '../utils/format';\nimport { notify } from '../lib/toast';\n\nfunction TeamCard({ team, isMine }: { team: TecHackathonTeam; isMine: boolean }) {\n return (\n <GlassCard className=\"flex flex-col gap-3 p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">{team.name}</span>\n {isMine ? (\n <Badge variant=\"secondary\" className=\"text-[11px]\">\n Your team\n </Badge>\n ) : null}\n </div>\n {team.projectName ? (\n <p className=\"mt-0.5 truncate text-sm text-text-secondary\">{team.projectName}</p>\n ) : (\n <p className=\"mt-0.5 text-sm text-text-muted\">No project submitted yet</p>\n )}\n </div>\n <StatusBadge status={team.status} />\n </div>\n\n {team.pitch ? <p className=\"line-clamp-3 text-sm text-text-secondary\">{team.pitch}</p> : null}\n\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <Users size={13} /> {team.memberIds.length} member{team.memberIds.length === 1 ? '' : 's'}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Flag size={13} /> Score {team.score}\n </span>\n </div>\n\n {team.repoUrl || team.projectUrl ? (\n <div className=\"flex flex-wrap items-center gap-3\">\n {team.repoUrl ? (\n <a\n href={team.repoUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 text-xs font-medium text-accent-primary hover:underline\"\n >\n <Github size={13} /> Repository\n </a>\n ) : null}\n {team.projectUrl ? (\n <a\n href={team.projectUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 text-xs font-medium text-accent-primary hover:underline\"\n >\n <ExternalLink size={13} /> Live project\n </a>\n ) : null}\n </div>\n ) : null}\n </GlassCard>\n );\n}\n\nexport function HackathonsHackathonDetailsPagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { currentUser } = useTechnoSpam();\n\n const { data, loading, error, refetch } = useHackathonQuery(id);\n const {\n data: teamsData,\n loading: teamsLoading,\n error: teamsError,\n refetch: refetchTeams,\n } = useTeamsQuery(id);\n\n const [registerTeam, { loading: registering }] = useRegisterTeam();\n const [submitProject, { loading: submitting }] = useSubmitProject();\n\n // register-team form state\n const [teamName, setTeamName] = useState('');\n const [memberIdsRaw, setMemberIdsRaw] = useState('');\n\n // submit-project form state\n const [projectTeamId, setProjectTeamId] = useState('');\n const [projectName, setProjectName] = useState('');\n const [projectUrl, setProjectUrl] = useState('');\n const [repoUrl, setRepoUrl] = useState('');\n const [pitch, setPitch] = useState('');\n\n const hackathon = data?.tecHackathon ?? null;\n const teams = teamsData?.tecListTeams ?? [];\n const isRegistrationOpen = hackathon?.status === 'REGISTRATION_OPEN';\n const captainedTeams = currentUser?.id ? teams.filter((t) => t.captainId === currentUser.id) : [];\n const activeProjectTeamId = projectTeamId || captainedTeams[0]?.id || '';\n\n const handleRegister = async () => {\n if (!id || !teamName.trim()) return;\n const memberIds = memberIdsRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n const res = await registerTeam({\n variables: { input: { hackathonId: id, name: teamName.trim(), memberIds } },\n });\n if (res.data?.tecRegisterTeam) {\n notify.success('Team registered', `\"${teamName.trim()}\" is in the running.`);\n setTeamName('');\n setMemberIdsRaw('');\n await Promise.all([refetchTeams(), refetch()]);\n }\n };\n\n const handleSubmitProject = async () => {\n if (!activeProjectTeamId || !projectName.trim()) return;\n const res = await submitProject({\n variables: {\n input: {\n teamId: activeProjectTeamId,\n projectName: projectName.trim(),\n projectUrl: projectUrl.trim() || undefined,\n repoUrl: repoUrl.trim() || undefined,\n pitch: pitch.trim() || undefined,\n },\n },\n });\n if (res.data?.tecSubmitProject) {\n notify.success('Project submitted', `\"${projectName.trim()}\" is submitted for judging.`);\n setProjectName('');\n setProjectUrl('');\n setRepoUrl('');\n setPitch('');\n await Promise.all([refetchTeams(), refetch()]);\n }\n };\n\n if (loading && !hackathon) {\n return (\n <PageLayout title=\"Hackathon\" backPath=\"/hackathons/hackathons-page\">\n <Skeleton className=\"mb-4 h-32 w-full rounded-xl\" />\n <Skeleton className=\"h-64 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !hackathon) {\n return (\n <PageLayout title=\"Hackathon\" backPath=\"/hackathons/hackathons-page\">\n {error ? (\n <ErrorView title=\"Couldn't load hackathon\" error={error} />\n ) : (\n <EmptyView\n title=\"Hackathon not found\"\n description=\"This hackathon may no longer be listed.\"\n />\n )}\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n hero\n backPath=\"/hackathons/hackathons-page\"\n title={hackathon.title}\n description={hackathon.theme ?? undefined}\n >\n <div className=\"mb-5 flex flex-wrap items-center gap-2\">\n <StatusBadge status={hackathon.status} />\n {hackathon.tags.map((t) => (\n <Badge key={t} variant=\"secondary\">\n {t}\n </Badge>\n ))}\n </div>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <StatCard\n label=\"Prize pool\"\n value={formatMoney(hackathon.prizePool, hackathon.currency)}\n icon={Award}\n />\n <StatCard label=\"Max team size\" value={hackathon.maxTeamSize} icon={Users} />\n <StatCard label=\"Teams registered\" value={teams.length} icon={Trophy} />\n <StatCard label=\"Ends\" value={formatDate(hackathon.endAt)} icon={CalendarDays} />\n </div>\n\n {hackathon.description ? (\n <GlassCard className=\"mb-6 p-5\">\n <h2 className=\"mb-2 text-base font-semibold text-text-primary\">About</h2>\n <p className=\"whitespace-pre-line text-sm text-text-secondary\">{hackathon.description}</p>\n </GlassCard>\n ) : null}\n\n <GlassCard className=\"mb-6 p-5\">\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">Schedule</h2>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <CalendarDays size={16} className=\"text-accent-teal\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs text-text-muted\">Starts</div>\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {formatDate(hackathon.startAt)}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <CalendarDays size={16} className=\"text-accent-teal\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs text-text-muted\">Ends</div>\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {formatDate(hackathon.endAt)}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <CalendarClock size={16} className=\"text-accent-teal\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs text-text-muted\">Submission deadline</div>\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {formatDateTime(hackathon.submissionDeadline)}\n </div>\n </div>\n </div>\n </div>\n </GlassCard>\n\n {isRegistrationOpen ? (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-3 flex items-center gap-2\">\n <UserPlus size={18} className=\"text-accent-primary\" />\n <h2 className=\"text-base font-semibold text-text-primary\">Register a team</h2>\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">\n You&apos;ll be the team captain. Add teammates by their user id (optional) — teams can\n be up to {hackathon.maxTeamSize} members.\n </p>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Team name\n </label>\n <Input\n placeholder=\"e.g. Byte Builders\"\n value={teamName}\n onChange={(e) => setTeamName(e.target.value)}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Teammate user ids{' '}\n <span className=\"text-text-muted\">(optional, comma-separated)</span>\n </label>\n <Input\n placeholder=\"user-id-1, user-id-2\"\n value={memberIdsRaw}\n onChange={(e) => setMemberIdsRaw(e.target.value)}\n />\n </div>\n </div>\n <div className=\"mt-4 flex justify-end\">\n <Button onClick={handleRegister} disabled={registering || !teamName.trim()}>\n <UserPlus size={16} /> {registering ? 'Registering…' : 'Register team'}\n </Button>\n </div>\n </GlassCard>\n ) : null}\n\n {captainedTeams.length > 0 ? (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-3 flex items-center gap-2\">\n <Send size={18} className=\"text-accent-primary\" />\n <h2 className=\"text-base font-semibold text-text-primary\">Submit your project</h2>\n </div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {captainedTeams.length > 1 ? (\n <div className=\"sm:col-span-2\">\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">Team</label>\n <Select value={activeProjectTeamId} onValueChange={setProjectTeamId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Choose a team\" />\n </SelectTrigger>\n <SelectContent>\n {captainedTeams.map((t) => (\n <SelectItem key={t.id} value={t.id}>\n {t.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : (\n <div className=\"sm:col-span-2 text-sm text-text-secondary\">\n Submitting for{' '}\n <span className=\"font-medium text-text-primary\">{captainedTeams[0]?.name}</span>\n </div>\n )}\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Project name\n </label>\n <Input\n placeholder=\"e.g. RealtimeCanvas\"\n value={projectName}\n onChange={(e) => setProjectName(e.target.value)}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Live project URL <span className=\"text-text-muted\">(optional)</span>\n </label>\n <Input\n placeholder=\"https://…\"\n value={projectUrl}\n onChange={(e) => setProjectUrl(e.target.value)}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Repository URL <span className=\"text-text-muted\">(optional)</span>\n </label>\n <Input\n placeholder=\"https://github.com/…\"\n value={repoUrl}\n onChange={(e) => setRepoUrl(e.target.value)}\n />\n </div>\n <div className=\"sm:col-span-2\">\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Pitch <span className=\"text-text-muted\">(optional)</span>\n </label>\n <Textarea\n rows={3}\n placeholder=\"What did you build, and why does it matter?\"\n value={pitch}\n onChange={(e) => setPitch(e.target.value)}\n />\n </div>\n </div>\n <div className=\"mt-4 flex justify-end\">\n <Button\n onClick={handleSubmitProject}\n disabled={submitting || !activeProjectTeamId || !projectName.trim()}\n >\n <Send size={16} /> {submitting ? 'Submitting…' : 'Submit project'}\n </Button>\n </div>\n </GlassCard>\n ) : null}\n\n <div>\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">\n Teams {teams.length ? <span className=\"text-text-muted\">({teams.length})</span> : null}\n </h2>\n {teamsLoading && !teams.length ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <Skeleton className=\"h-40 w-full rounded-xl\" />\n <Skeleton className=\"h-40 w-full rounded-xl\" />\n </div>\n ) : teamsError ? (\n <ErrorView title=\"Couldn't load teams\" error={teamsError} />\n ) : teams.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"No teams registered yet\"\n description={\n isRegistrationOpen\n ? 'Be the first to register a team above.'\n : 'Teams will appear here once registration opens.'\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {teams.map((team) => (\n <TeamCard\n key={team.id}\n team={team}\n isMine={!!currentUser?.id && team.captainId === currentUser.id}\n />\n ))}\n </div>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"HackathonsHackathonDetailsPagePage.js","names":[],"sources":["../../../src/technospam/pages/HackathonsHackathonDetailsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport {\n Award,\n CalendarClock,\n CalendarDays,\n Code2,\n ExternalLink,\n Flag,\n Github,\n Send,\n Trophy,\n UserPlus,\n Users,\n type LucideIcon,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n Input,\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 MediaCover,\n PageLayout,\n StatusBadge,\n coverGradient,\n} from '../components';\nimport { cn } from '../utils/cn';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport {\n useHackathonQuery,\n useRegisterTeam,\n useSubmitProject,\n useTeamsQuery,\n type TecHackathonTeam,\n} from '../api/technospamApi';\nimport { formatDate, formatDateTime, formatMoney } from '../utils/format';\nimport { notify } from '../lib/toast';\n\n/** Translucent glass chip used for stats overlaid on the vivid MediaCover hero. */\nfunction HeroChip({ icon: Icon, label }: { icon: LucideIcon; label: string }) {\n return (\n <span className=\"inline-flex items-center gap-1.5 rounded-lg bg-white/15 px-3 py-1.5 text-sm font-medium text-white ring-1 ring-white/25 backdrop-blur-sm\">\n <Icon size={15} /> {label}\n </span>\n );\n}\n\nfunction TeamCard({ team, isMine }: { team: TecHackathonTeam; isMine: boolean }) {\n const isWinner = team.status === 'WINNER';\n return (\n <GlassCard className=\"group flex flex-col gap-3 p-4 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-3\">\n <span\n className={cn(\n 'flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br text-white shadow-sm ring-1 ring-white/10 transition-transform duration-200 group-hover:scale-105',\n coverGradient(team.name)\n )}\n >\n {isWinner ? <Trophy size={19} /> : <Code2 size={19} />}\n </span>\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">{team.name}</span>\n {isMine ? (\n <Badge variant=\"secondary\" className=\"text-[11px]\">\n Your team\n </Badge>\n ) : null}\n </div>\n {team.projectName ? (\n <p className=\"mt-0.5 truncate text-sm text-text-secondary\">{team.projectName}</p>\n ) : (\n <p className=\"mt-0.5 text-sm text-text-muted\">No project submitted yet</p>\n )}\n </div>\n </div>\n <StatusBadge status={team.status} />\n </div>\n\n {team.pitch ? <p className=\"line-clamp-3 text-sm text-text-secondary\">{team.pitch}</p> : null}\n\n <div className=\"mt-auto flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <Users size={13} /> {team.memberIds.length} member{team.memberIds.length === 1 ? '' : 's'}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Flag size={13} /> Score {team.score}\n </span>\n </div>\n\n {team.repoUrl || team.projectUrl ? (\n <div className=\"flex flex-wrap items-center gap-3 border-t border-border-seam pt-3\">\n {team.repoUrl ? (\n <a\n href={team.repoUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 text-xs font-medium text-accent-primary hover:underline\"\n >\n <Github size={13} /> Repository\n </a>\n ) : null}\n {team.projectUrl ? (\n <a\n href={team.projectUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 text-xs font-medium text-accent-primary hover:underline\"\n >\n <ExternalLink size={13} /> Live project\n </a>\n ) : null}\n </div>\n ) : null}\n </GlassCard>\n );\n}\n\nexport function HackathonsHackathonDetailsPagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { currentUser } = useTechnoSpam();\n\n const { data, loading, error, refetch } = useHackathonQuery(id);\n const {\n data: teamsData,\n loading: teamsLoading,\n error: teamsError,\n refetch: refetchTeams,\n } = useTeamsQuery(id);\n\n const [registerTeam, { loading: registering }] = useRegisterTeam();\n const [submitProject, { loading: submitting }] = useSubmitProject();\n\n // register-team form state\n const [teamName, setTeamName] = useState('');\n const [memberIdsRaw, setMemberIdsRaw] = useState('');\n\n // submit-project form state\n const [projectTeamId, setProjectTeamId] = useState('');\n const [projectName, setProjectName] = useState('');\n const [projectUrl, setProjectUrl] = useState('');\n const [repoUrl, setRepoUrl] = useState('');\n const [pitch, setPitch] = useState('');\n\n const hackathon = data?.tecHackathon ?? null;\n const teams = teamsData?.tecListTeams ?? [];\n const isRegistrationOpen = hackathon?.status === 'REGISTRATION_OPEN';\n const captainedTeams = currentUser?.id ? teams.filter((t) => t.captainId === currentUser.id) : [];\n const activeProjectTeamId = projectTeamId || captainedTeams[0]?.id || '';\n\n const handleRegister = async () => {\n if (!id || !teamName.trim()) return;\n const memberIds = memberIdsRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n const res = await registerTeam({\n variables: { input: { hackathonId: id, name: teamName.trim(), memberIds } },\n });\n if (res.data?.tecRegisterTeam) {\n notify.success('Team registered', `\"${teamName.trim()}\" is in the running.`);\n setTeamName('');\n setMemberIdsRaw('');\n await Promise.all([refetchTeams(), refetch()]);\n }\n };\n\n const handleSubmitProject = async () => {\n if (!activeProjectTeamId || !projectName.trim()) return;\n const res = await submitProject({\n variables: {\n input: {\n teamId: activeProjectTeamId,\n projectName: projectName.trim(),\n projectUrl: projectUrl.trim() || undefined,\n repoUrl: repoUrl.trim() || undefined,\n pitch: pitch.trim() || undefined,\n },\n },\n });\n if (res.data?.tecSubmitProject) {\n notify.success('Project submitted', `\"${projectName.trim()}\" is submitted for judging.`);\n setProjectName('');\n setProjectUrl('');\n setRepoUrl('');\n setPitch('');\n await Promise.all([refetchTeams(), refetch()]);\n }\n };\n\n if (loading && !hackathon) {\n return (\n <PageLayout title=\"Hackathon\" backPath=\"/hackathons/hackathons-page\">\n <Skeleton className=\"mb-4 h-32 w-full rounded-xl\" />\n <Skeleton className=\"h-64 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !hackathon) {\n return (\n <PageLayout title=\"Hackathon\" backPath=\"/hackathons/hackathons-page\">\n {error ? (\n <ErrorView title=\"Couldn't load hackathon\" error={error} />\n ) : (\n <EmptyView\n title=\"Hackathon not found\"\n description=\"This hackathon may no longer be listed.\"\n />\n )}\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n backPath=\"/hackathons/hackathons-page\"\n title={hackathon.title}\n description={hackathon.theme ?? undefined}\n >\n <MediaCover\n height=\"h-40\"\n seed={hackathon.theme ?? hackathon.id}\n icon={Trophy}\n className=\"mb-6 rounded-xl\"\n >\n <div className=\"flex w-full flex-col gap-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={hackathon.status} />\n {hackathon.tags.map((t) => (\n <Badge\n key={t}\n variant=\"secondary\"\n className=\"border-white/20 bg-white/15 text-[11px] text-white\"\n >\n {t}\n </Badge>\n ))}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <HeroChip\n icon={Award}\n label={`${formatMoney(hackathon.prizePool, hackathon.currency)} prize pool`}\n />\n <HeroChip\n icon={CalendarDays}\n label={`${formatDate(hackathon.startAt)} – ${formatDate(hackathon.endAt)}`}\n />\n <HeroChip icon={Users} label={`Team of ${hackathon.maxTeamSize}`} />\n <HeroChip\n icon={Trophy}\n label={`${teams.length} team${teams.length === 1 ? '' : 's'} registered`}\n />\n </div>\n </div>\n </MediaCover>\n\n {hackathon.description ? (\n <GlassCard className=\"mb-6 p-5\">\n <h2 className=\"mb-2 text-base font-semibold text-text-primary\">About</h2>\n <p className=\"whitespace-pre-line text-sm text-text-secondary\">{hackathon.description}</p>\n </GlassCard>\n ) : null}\n\n <GlassCard className=\"mb-6 p-5\">\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">Schedule</h2>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <CalendarDays size={16} className=\"text-accent-teal\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs text-text-muted\">Starts</div>\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {formatDate(hackathon.startAt)}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <CalendarDays size={16} className=\"text-accent-teal\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs text-text-muted\">Ends</div>\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {formatDate(hackathon.endAt)}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <CalendarClock size={16} className=\"text-accent-teal\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs text-text-muted\">Submission deadline</div>\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {formatDateTime(hackathon.submissionDeadline)}\n </div>\n </div>\n </div>\n </div>\n </GlassCard>\n\n {isRegistrationOpen ? (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-3 flex items-center gap-3\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-accent-primary/15 text-accent-primary ring-1 ring-accent-primary/20\">\n <UserPlus size={18} />\n </span>\n <h2 className=\"text-base font-semibold text-text-primary\">Register a team</h2>\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">\n You&apos;ll be the team captain. Add teammates by their user id (optional) — teams can\n be up to {hackathon.maxTeamSize} members.\n </p>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Team name\n </label>\n <Input\n placeholder=\"e.g. Byte Builders\"\n value={teamName}\n onChange={(e) => setTeamName(e.target.value)}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Teammate user ids{' '}\n <span className=\"text-text-muted\">(optional, comma-separated)</span>\n </label>\n <Input\n placeholder=\"user-id-1, user-id-2\"\n value={memberIdsRaw}\n onChange={(e) => setMemberIdsRaw(e.target.value)}\n />\n </div>\n </div>\n <div className=\"mt-4 flex justify-end\">\n <Button onClick={handleRegister} disabled={registering || !teamName.trim()}>\n <UserPlus size={16} /> {registering ? 'Registering…' : 'Register team'}\n </Button>\n </div>\n </GlassCard>\n ) : null}\n\n {captainedTeams.length > 0 ? (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-3 flex items-center gap-3\">\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-accent-teal/15 text-accent-teal ring-1 ring-accent-teal/20\">\n <Send size={18} />\n </span>\n <h2 className=\"text-base font-semibold text-text-primary\">Submit your project</h2>\n </div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {captainedTeams.length > 1 ? (\n <div className=\"sm:col-span-2\">\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">Team</label>\n <Select value={activeProjectTeamId} onValueChange={setProjectTeamId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Choose a team\" />\n </SelectTrigger>\n <SelectContent>\n {captainedTeams.map((t) => (\n <SelectItem key={t.id} value={t.id}>\n {t.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : (\n <div className=\"sm:col-span-2 text-sm text-text-secondary\">\n Submitting for{' '}\n <span className=\"font-medium text-text-primary\">{captainedTeams[0]?.name}</span>\n </div>\n )}\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Project name\n </label>\n <Input\n placeholder=\"e.g. RealtimeCanvas\"\n value={projectName}\n onChange={(e) => setProjectName(e.target.value)}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Live project URL <span className=\"text-text-muted\">(optional)</span>\n </label>\n <Input\n placeholder=\"https://…\"\n value={projectUrl}\n onChange={(e) => setProjectUrl(e.target.value)}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Repository URL <span className=\"text-text-muted\">(optional)</span>\n </label>\n <Input\n placeholder=\"https://github.com/…\"\n value={repoUrl}\n onChange={(e) => setRepoUrl(e.target.value)}\n />\n </div>\n <div className=\"sm:col-span-2\">\n <label className=\"mb-1.5 block text-sm font-medium text-text-secondary\">\n Pitch <span className=\"text-text-muted\">(optional)</span>\n </label>\n <Textarea\n rows={3}\n placeholder=\"What did you build, and why does it matter?\"\n value={pitch}\n onChange={(e) => setPitch(e.target.value)}\n />\n </div>\n </div>\n <div className=\"mt-4 flex justify-end\">\n <Button\n onClick={handleSubmitProject}\n disabled={submitting || !activeProjectTeamId || !projectName.trim()}\n >\n <Send size={16} /> {submitting ? 'Submitting…' : 'Submit project'}\n </Button>\n </div>\n </GlassCard>\n ) : null}\n\n <div>\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">\n Teams {teams.length ? <span className=\"text-text-muted\">({teams.length})</span> : null}\n </h2>\n {teamsLoading && !teams.length ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <Skeleton className=\"h-40 w-full rounded-xl\" />\n <Skeleton className=\"h-40 w-full rounded-xl\" />\n </div>\n ) : teamsError ? (\n <ErrorView title=\"Couldn't load teams\" error={teamsError} />\n ) : teams.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"No teams registered yet\"\n description={\n isRegistrationOpen\n ? 'Be the first to register a team above.'\n : 'Teams will appear here once registration opens.'\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {teams.map((team) => (\n <TeamCard\n key={team.id}\n team={team}\n isMine={!!currentUser?.id && team.captainId === currentUser.id}\n />\n ))}\n </div>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1,18 +1,20 @@
1
- import { useTechnoSpamNavigate as e } from "../providers/TechnoSpamProvider.js";
2
- import { PageLayout as t } from "../components/PageLayout.js";
3
- import { StatCard as n } from "../components/StatCard.js";
4
- import { formatDate as r, formatMoney as i } from "../utils/format.js";
5
- import { StatusBadge as a } from "../components/StatusBadge.js";
6
- import { LoadMore as o } from "../components/LoadMore.js";
7
- import { EmptyView as s, ErrorView as c, LoadingGrid as l } from "../components/StateViews.js";
1
+ import { useTechnoSpam as e, useTechnoSpamNavigate as t } from "../providers/TechnoSpamProvider.js";
2
+ import { PageLayout as n } from "../components/PageLayout.js";
3
+ import { StatCard as r } from "../components/StatCard.js";
4
+ import { MediaCover as i } from "../components/MediaCover.js";
5
+ import { formatDate as a, formatMoney as o } from "../utils/format.js";
6
+ import { StatusBadge as s } from "../components/StatusBadge.js";
7
+ import { LoadMore as c } from "../components/LoadMore.js";
8
+ import { EmptyView as l, ErrorView as u, LoadingGrid as d } from "../components/StateViews.js";
8
9
  import "../components/index.js";
9
- import { pageArg as u, useHackathonsQuery as d, usePageLimit as f } from "../api/technospamApi.js";
10
- import { useMemo as p, useState as m } from "react";
11
- import { Award as h, CalendarDays as g, Search as _, Sparkles as v, Trophy as y, Users as b } from "lucide-react";
12
- import { jsx as x, jsxs as S } from "react/jsx-runtime";
13
- import { Badge as C, GlassCard as w, Input as T, Tabs as E, TabsList as D, TabsTrigger as O } from "@burdenoff/fe-libs/ui";
10
+ import { pageArg as f, useHackathonsQuery as p, usePageLimit as m } from "../api/technospamApi.js";
11
+ import { useTechnoSpamAnalytics as h } from "../hooks/useTechnoSpamAnalytics.js";
12
+ import { useMemo as g, useState as _ } from "react";
13
+ import { Award as v, CalendarDays as y, Search as b, Sparkles as x, Trophy as S, Users as C } from "lucide-react";
14
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
15
+ import { Badge as E, GlassCard as D, Input as O, Tabs as k, TabsList as A, TabsTrigger as j } from "@burdenoff/fe-libs/ui";
14
16
  //#region src/technospam/pages/HackathonsHackathonsPagePage.tsx
15
- var k = [
17
+ var M = [
16
18
  {
17
19
  value: "ALL",
18
20
  label: "All"
@@ -34,72 +36,61 @@ var k = [
34
36
  label: "Completed"
35
37
  }
36
38
  ];
37
- function A(e) {
38
- let t = [
39
- "from-accent-primary/25 to-accent-teal/20",
40
- "from-accent-teal/25 to-accent-primary/15",
41
- "from-status-success-bg-subtle to-accent-wash",
42
- "from-accent-wash to-bg-sunken"
43
- ], n = 0;
44
- for (let t = 0; t < e.length; t += 1) n = n * 31 + e.charCodeAt(t) >>> 0;
45
- return t[n % t.length];
46
- }
47
- function j({ hackathon: e, onOpen: t }) {
48
- return /* @__PURE__ */ S(w, {
49
- className: "group flex cursor-pointer flex-col overflow-hidden transition-shadow hover:shadow-md",
39
+ function N({ hackathon: e, onOpen: t }) {
40
+ return /* @__PURE__ */ T(D, {
41
+ className: "group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg",
50
42
  onClick: t,
51
- children: [/* @__PURE__ */ S("div", {
52
- className: `relative flex h-24 items-end bg-gradient-to-br ${A(e.theme ?? e.id)} p-4`,
53
- children: [/* @__PURE__ */ x(y, {
54
- className: "absolute right-3 top-3 text-text-muted/60",
55
- size: 20
56
- }), /* @__PURE__ */ x(a, { status: e.status })]
57
- }), /* @__PURE__ */ S("div", {
43
+ children: [/* @__PURE__ */ w(i, {
44
+ height: "h-32",
45
+ seed: e.theme ?? e.id,
46
+ icon: S,
47
+ children: /* @__PURE__ */ w(s, { status: e.status })
48
+ }), /* @__PURE__ */ T("div", {
58
49
  className: "flex flex-1 flex-col gap-3 p-4",
59
50
  children: [
60
- /* @__PURE__ */ S("div", {
51
+ /* @__PURE__ */ T("div", {
61
52
  className: "min-w-0",
62
- children: [/* @__PURE__ */ x("h3", {
53
+ children: [/* @__PURE__ */ w("h3", {
63
54
  className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
64
55
  children: e.title
65
- }), e.theme ? /* @__PURE__ */ x("p", {
56
+ }), e.theme ? /* @__PURE__ */ w("p", {
66
57
  className: "mt-1 line-clamp-2 text-sm text-text-secondary",
67
58
  children: e.theme
68
59
  }) : null]
69
60
  }),
70
- /* @__PURE__ */ S("div", {
61
+ /* @__PURE__ */ T("div", {
71
62
  className: "mt-auto flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted",
72
- children: [/* @__PURE__ */ S("span", {
63
+ children: [/* @__PURE__ */ T("span", {
73
64
  className: "inline-flex items-center gap-1",
74
65
  children: [
75
- /* @__PURE__ */ x(g, { size: 13 }),
66
+ /* @__PURE__ */ w(y, { size: 13 }),
76
67
  " ",
77
- r(e.startAt),
68
+ a(e.startAt),
78
69
  " –",
79
70
  " ",
80
- r(e.endAt)
71
+ a(e.endAt)
81
72
  ]
82
- }), /* @__PURE__ */ S("span", {
73
+ }), /* @__PURE__ */ T("span", {
83
74
  className: "inline-flex items-center gap-1",
84
75
  children: [
85
- /* @__PURE__ */ x(b, { size: 13 }),
76
+ /* @__PURE__ */ w(C, { size: 13 }),
86
77
  " Team of ",
87
78
  e.maxTeamSize
88
79
  ]
89
80
  })]
90
81
  }),
91
- /* @__PURE__ */ S("div", {
82
+ /* @__PURE__ */ T("div", {
92
83
  className: "flex items-center gap-1.5 text-sm font-medium text-accent-teal",
93
84
  children: [
94
- /* @__PURE__ */ x(h, { size: 15 }),
85
+ /* @__PURE__ */ w(v, { size: 15 }),
95
86
  " ",
96
- i(e.prizePool, e.currency),
87
+ o(e.prizePool, e.currency),
97
88
  " prize pool"
98
89
  ]
99
90
  }),
100
- e.tags.length ? /* @__PURE__ */ x("div", {
91
+ e.tags.length ? /* @__PURE__ */ w("div", {
101
92
  className: "flex flex-wrap gap-1.5",
102
- children: e.tags.slice(0, 4).map((e) => /* @__PURE__ */ x(C, {
93
+ children: e.tags.slice(0, 4).map((e) => /* @__PURE__ */ w(E, {
103
94
  variant: "secondary",
104
95
  className: "text-[11px]",
105
96
  children: e
@@ -109,84 +100,101 @@ function j({ hackathon: e, onOpen: t }) {
109
100
  })]
110
101
  });
111
102
  }
112
- function M() {
113
- let r = e(), [a, g] = m("ALL"), [b, C] = m(""), { limit: w, more: A } = f(), { data: M, loading: N, error: P } = d({
114
- pagination: u(w),
115
- ...a === "ALL" ? {} : { status: a }
116
- }), F = M?.tecListHackathons.items ?? [], I = M?.tecListHackathons.pageInfo.hasMore ?? !1, L = p(() => {
117
- let e = b.trim().toLowerCase();
118
- return e ? F.filter((t) => t.title.toLowerCase().includes(e) || (t.theme ?? "").toLowerCase().includes(e) || t.tags.some((t) => t.toLowerCase().includes(e))) : F;
119
- }, [F, b]), R = L.filter((e) => e.status === "REGISTRATION_OPEN").length, z = L.reduce((e, t) => e + t.prizePool, 0), B = L[0]?.currency ?? "USD";
120
- return /* @__PURE__ */ S(t, {
103
+ function P() {
104
+ let i = t(), { workspaceId: a } = e(), { emit: s } = h(), [y, C] = _("ALL"), [E, D] = _(""), { limit: P, more: F } = m(), { data: I, loading: L, error: R } = p({
105
+ pagination: f(P),
106
+ ...y === "ALL" ? {} : { status: y }
107
+ }), z = I?.tecListHackathons.items ?? [], B = I?.tecListHackathons.pageInfo.hasMore ?? !1, V = g(() => {
108
+ let e = E.trim().toLowerCase();
109
+ return e ? z.filter((t) => t.title.toLowerCase().includes(e) || (t.theme ?? "").toLowerCase().includes(e) || t.tags.some((t) => t.toLowerCase().includes(e))) : z;
110
+ }, [z, E]), H = V.filter((e) => e.status === "REGISTRATION_OPEN").length, U = V.reduce((e, t) => e + t.prizePool, 0), W = V[0]?.currency ?? "USD";
111
+ return /* @__PURE__ */ T(n, {
121
112
  hero: !0,
122
113
  title: "Hackathons",
123
114
  description: "Compete, collaborate, and ship real projects with a team in a fixed window.",
124
115
  children: [
125
- /* @__PURE__ */ S("div", {
116
+ /* @__PURE__ */ T("div", {
126
117
  className: "mb-5 grid grid-cols-1 gap-3 sm:grid-cols-3",
127
118
  children: [
128
- /* @__PURE__ */ x(n, {
119
+ /* @__PURE__ */ w(r, {
129
120
  label: "Hackathons",
130
- value: L.length,
131
- icon: y
121
+ value: V.length,
122
+ icon: S,
123
+ tone: "purple"
132
124
  }),
133
- /* @__PURE__ */ x(n, {
125
+ /* @__PURE__ */ w(r, {
134
126
  label: "Registration open",
135
- value: R,
136
- icon: v
127
+ value: H,
128
+ icon: x,
129
+ tone: "green"
137
130
  }),
138
- /* @__PURE__ */ x(n, {
131
+ /* @__PURE__ */ w(r, {
139
132
  label: "Total prize pool",
140
- value: i(z, B),
141
- icon: h
133
+ value: o(U, W),
134
+ icon: v,
135
+ tone: "amber"
142
136
  })
143
137
  ]
144
138
  }),
145
- /* @__PURE__ */ S("div", {
139
+ /* @__PURE__ */ T("div", {
146
140
  className: "mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
147
- children: [/* @__PURE__ */ x(E, {
148
- value: a,
149
- onValueChange: (e) => g(e),
150
- children: /* @__PURE__ */ x(D, { children: k.map((e) => /* @__PURE__ */ x(O, {
141
+ children: [/* @__PURE__ */ w(k, {
142
+ value: y,
143
+ onValueChange: (e) => C(e),
144
+ children: /* @__PURE__ */ w(A, { children: M.map((e) => /* @__PURE__ */ w(j, {
151
145
  value: e.value,
152
146
  children: e.label
153
147
  }, e.value)) })
154
- }), /* @__PURE__ */ S("div", {
148
+ }), /* @__PURE__ */ T("div", {
155
149
  className: "relative w-full sm:w-72",
156
- children: [/* @__PURE__ */ x(_, {
150
+ children: [/* @__PURE__ */ w(b, {
157
151
  className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-text-muted",
158
152
  size: 16
159
- }), /* @__PURE__ */ x(T, {
153
+ }), /* @__PURE__ */ w(O, {
160
154
  className: "pl-9",
161
155
  placeholder: "Search hackathons…",
162
- value: b,
163
- onChange: (e) => C(e.target.value)
156
+ value: E,
157
+ onChange: (e) => D(e.target.value),
158
+ onBlur: () => {
159
+ let e = E.trim();
160
+ e && s("technospam.search.performed", {
161
+ workspaceId: a,
162
+ entityType: "hackathon",
163
+ queryLength: e.length
164
+ });
165
+ }
164
166
  })]
165
167
  })]
166
168
  }),
167
- N && !L.length ? /* @__PURE__ */ x(l, {}) : P ? /* @__PURE__ */ x(c, {
169
+ L && !V.length ? /* @__PURE__ */ w(d, {}) : R ? /* @__PURE__ */ w(u, {
168
170
  title: "Couldn't load hackathons",
169
- error: P
170
- }) : L.length === 0 ? /* @__PURE__ */ x(s, {
171
- icon: /* @__PURE__ */ x(y, { size: 26 }),
172
- title: a === "ALL" ? "No hackathons yet" : "No hackathons in this stage",
173
- description: a === "ALL" ? "Upcoming hackathons will appear here. Check back soon — TechnoSpam is pre-launch." : "Try a different stage filter."
174
- }) : /* @__PURE__ */ x("div", {
171
+ error: R
172
+ }) : V.length === 0 ? /* @__PURE__ */ w(l, {
173
+ icon: /* @__PURE__ */ w(S, { size: 26 }),
174
+ title: y === "ALL" ? "No hackathons yet" : "No hackathons in this stage",
175
+ description: y === "ALL" ? "Upcoming hackathons will appear here. Check back soon — TechnoSpam is pre-launch." : "Try a different stage filter."
176
+ }) : /* @__PURE__ */ w("div", {
175
177
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
176
- children: L.map((e) => /* @__PURE__ */ x(j, {
178
+ children: V.map((e) => /* @__PURE__ */ w(N, {
177
179
  hackathon: e,
178
- onOpen: () => r(`/hackathons/hackathon-details-page?id=${e.id}`)
180
+ onOpen: () => {
181
+ s("technospam.hackathon.viewed", {
182
+ workspaceId: a,
183
+ entityId: e.id,
184
+ entityType: "TEC_HACKATHON"
185
+ }), i(`/hackathons/hackathon-details-page?id=${e.id}`);
186
+ }
179
187
  }, e.id))
180
188
  }),
181
- /* @__PURE__ */ x(o, {
182
- hasMore: I,
183
- loading: N,
184
- onClick: A
189
+ /* @__PURE__ */ w(c, {
190
+ hasMore: B,
191
+ loading: L,
192
+ onClick: F
185
193
  })
186
194
  ]
187
195
  });
188
196
  }
189
197
  //#endregion
190
- export { M as HackathonsHackathonsPagePage };
198
+ export { P as HackathonsHackathonsPagePage };
191
199
 
192
200
  //# sourceMappingURL=HackathonsHackathonsPagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HackathonsHackathonsPagePage.js","names":[],"sources":["../../../src/technospam/pages/HackathonsHackathonsPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Award, CalendarDays, Search, Sparkles, Trophy, Users } 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 { useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useHackathonsQuery,\n usePageLimit,\n type TecHackathon,\n type TecHackathonStatus,\n} from '../api/technospamApi';\nimport { formatDate, formatMoney } from '../utils/format';\n\nconst STATUSES: Array<{ value: 'ALL' | TecHackathonStatus; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'REGISTRATION_OPEN', label: 'Registration open' },\n { value: 'IN_PROGRESS', label: 'In progress' },\n { value: 'JUDGING', label: 'Judging' },\n { value: 'COMPLETED', label: 'Completed' },\n];\n\n/** Deterministic token-based header gradient keyed off the hackathon theme/id. */\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 HackathonCard({ hackathon, onOpen }: { hackathon: TecHackathon; onOpen: () => void }) {\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col overflow-hidden transition-shadow hover:shadow-md\"\n onClick={onOpen}\n >\n <div\n className={`relative flex h-24 items-end bg-gradient-to-br ${coverGradient(\n hackathon.theme ?? hackathon.id\n )} p-4`}\n >\n <Trophy className=\"absolute right-3 top-3 text-text-muted/60\" size={20} />\n <StatusBadge status={hackathon.status} />\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 {hackathon.title}\n </h3>\n {hackathon.theme ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{hackathon.theme}</p>\n ) : null}\n </div>\n\n <div className=\"mt-auto flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarDays size={13} /> {formatDate(hackathon.startAt)} –{' '}\n {formatDate(hackathon.endAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Users size={13} /> Team of {hackathon.maxTeamSize}\n </span>\n </div>\n\n <div className=\"flex items-center gap-1.5 text-sm font-medium text-accent-teal\">\n <Award size={15} /> {formatMoney(hackathon.prizePool, hackathon.currency)} prize pool\n </div>\n\n {hackathon.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {hackathon.tags.slice(0, 4).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function HackathonsHackathonsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const [status, setStatus] = useState<'ALL' | TecHackathonStatus>('ALL');\n const [search, setSearch] = useState('');\n const { limit, more } = usePageLimit();\n\n const { data, loading, error } = useHackathonsQuery({\n pagination: pageArg(limit),\n ...(status !== 'ALL' ? { status } : {}),\n });\n\n const allHackathons = data?.tecListHackathons.items ?? [];\n const hasMore = data?.tecListHackathons.pageInfo.hasMore ?? false;\n const hackathons = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return allHackathons;\n return allHackathons.filter(\n (h) =>\n h.title.toLowerCase().includes(q) ||\n (h.theme ?? '').toLowerCase().includes(q) ||\n h.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [allHackathons, search]);\n const openCount = hackathons.filter((h) => h.status === 'REGISTRATION_OPEN').length;\n const totalPrize = hackathons.reduce((s, h) => s + h.prizePool, 0);\n const prizeCurrency = hackathons[0]?.currency ?? 'USD';\n\n return (\n <PageLayout\n hero\n title=\"Hackathons\"\n description=\"Compete, collaborate, and ship real projects with a team in a fixed window.\"\n >\n <div className=\"mb-5 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatCard label=\"Hackathons\" value={hackathons.length} icon={Trophy} />\n <StatCard label=\"Registration open\" value={openCount} icon={Sparkles} />\n <StatCard\n label=\"Total prize pool\"\n value={formatMoney(totalPrize, prizeCurrency)}\n icon={Award}\n />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <Tabs value={status} onValueChange={(v) => setStatus(v as 'ALL' | TecHackathonStatus)}>\n <TabsList>\n {STATUSES.map((s) => (\n <TabsTrigger key={s.value} value={s.value}>\n {s.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 hackathons…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n </div>\n\n {loading && !hackathons.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load hackathons\" error={error} />\n ) : hackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={26} />}\n title={status !== 'ALL' ? 'No hackathons in this stage' : 'No hackathons yet'}\n description={\n status !== 'ALL'\n ? 'Try a different stage filter.'\n : 'Upcoming hackathons 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 {hackathons.map((hackathon) => (\n <HackathonCard\n key={hackathon.id}\n hackathon={hackathon}\n onOpen={() => navigate(`/hackathons/hackathon-details-page?id=${hackathon.id}`)}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"HackathonsHackathonsPagePage.js","names":[],"sources":["../../../src/technospam/pages/HackathonsHackathonsPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Award, CalendarDays, Search, Sparkles, Trophy, Users } 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} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useHackathonsQuery,\n usePageLimit,\n type TecHackathon,\n type TecHackathonStatus,\n} from '../api/technospamApi';\nimport { formatDate, formatMoney } from '../utils/format';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\n\nconst STATUSES: Array<{ value: 'ALL' | TecHackathonStatus; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'REGISTRATION_OPEN', label: 'Registration open' },\n { value: 'IN_PROGRESS', label: 'In progress' },\n { value: 'JUDGING', label: 'Judging' },\n { value: 'COMPLETED', label: 'Completed' },\n];\n\nfunction HackathonCard({ hackathon, onOpen }: { hackathon: TecHackathon; onOpen: () => void }) {\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col overflow-hidden transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\"\n onClick={onOpen}\n >\n <MediaCover height=\"h-32\" seed={hackathon.theme ?? hackathon.id} icon={Trophy}>\n <StatusBadge status={hackathon.status} />\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 {hackathon.title}\n </h3>\n {hackathon.theme ? (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-secondary\">{hackathon.theme}</p>\n ) : null}\n </div>\n\n <div className=\"mt-auto flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarDays size={13} /> {formatDate(hackathon.startAt)} –{' '}\n {formatDate(hackathon.endAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Users size={13} /> Team of {hackathon.maxTeamSize}\n </span>\n </div>\n\n <div className=\"flex items-center gap-1.5 text-sm font-medium text-accent-teal\">\n <Award size={15} /> {formatMoney(hackathon.prizePool, hackathon.currency)} prize pool\n </div>\n\n {hackathon.tags.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {hackathon.tags.slice(0, 4).map((t) => (\n <Badge key={t} variant=\"secondary\" className=\"text-[11px]\">\n {t}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n );\n}\n\nexport function HackathonsHackathonsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const [status, setStatus] = useState<'ALL' | TecHackathonStatus>('ALL');\n const [search, setSearch] = useState('');\n const { limit, more } = usePageLimit();\n\n const { data, loading, error } = useHackathonsQuery({\n pagination: pageArg(limit),\n ...(status !== 'ALL' ? { status } : {}),\n });\n\n const allHackathons = data?.tecListHackathons.items ?? [];\n const hasMore = data?.tecListHackathons.pageInfo.hasMore ?? false;\n const hackathons = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return allHackathons;\n return allHackathons.filter(\n (h) =>\n h.title.toLowerCase().includes(q) ||\n (h.theme ?? '').toLowerCase().includes(q) ||\n h.tags.some((t) => t.toLowerCase().includes(q))\n );\n }, [allHackathons, search]);\n const openCount = hackathons.filter((h) => h.status === 'REGISTRATION_OPEN').length;\n const totalPrize = hackathons.reduce((s, h) => s + h.prizePool, 0);\n const prizeCurrency = hackathons[0]?.currency ?? 'USD';\n\n return (\n <PageLayout\n hero\n title=\"Hackathons\"\n description=\"Compete, collaborate, and ship real projects with a team in a fixed window.\"\n >\n <div className=\"mb-5 grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatCard label=\"Hackathons\" value={hackathons.length} icon={Trophy} tone=\"purple\" />\n <StatCard label=\"Registration open\" value={openCount} icon={Sparkles} tone=\"green\" />\n <StatCard\n label=\"Total prize pool\"\n value={formatMoney(totalPrize, prizeCurrency)}\n icon={Award}\n tone=\"amber\"\n />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <Tabs value={status} onValueChange={(v) => setStatus(v as 'ALL' | TecHackathonStatus)}>\n <TabsList>\n {STATUSES.map((s) => (\n <TabsTrigger key={s.value} value={s.value}>\n {s.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 hackathons…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onBlur={() => {\n const value = search.trim();\n if (value) {\n emit('technospam.search.performed', {\n workspaceId,\n entityType: 'hackathon',\n queryLength: value.length,\n });\n }\n }}\n />\n </div>\n </div>\n\n {loading && !hackathons.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load hackathons\" error={error} />\n ) : hackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={26} />}\n title={status !== 'ALL' ? 'No hackathons in this stage' : 'No hackathons yet'}\n description={\n status !== 'ALL'\n ? 'Try a different stage filter.'\n : 'Upcoming hackathons 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 {hackathons.map((hackathon) => (\n <HackathonCard\n key={hackathon.id}\n hackathon={hackathon}\n onOpen={() => {\n emit('technospam.hackathon.viewed', {\n workspaceId,\n entityId: hackathon.id,\n entityType: 'TEC_HACKATHON',\n });\n navigate(`/hackathons/hackathon-details-page?id=${hackathon.id}`);\n }}\n />\n ))}\n </div>\n )}\n <LoadMore hasMore={hasMore} loading={loading} onClick={more} />\n </PageLayout>\n );\n}\n"],"mappings":"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"}