@burdenoff/microfe-technospam 2026.716.2 → 2026.719.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/node_modules/recharts/es6/cartesian/Brush.js.map +1 -1
  2. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js.map +1 -1
  3. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js.map +1 -1
  4. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js.map +1 -1
  5. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js.map +1 -1
  6. package/dist/node_modules/recharts/es6/cartesian/XAxis.js.map +1 -1
  7. package/dist/node_modules/recharts/es6/cartesian/YAxis.js.map +1 -1
  8. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js.map +1 -1
  9. package/dist/node_modules/sonner/dist/index.js.map +1 -1
  10. package/dist/technospam/TechnoSpamRoot.d.ts.map +1 -1
  11. package/dist/technospam/TechnoSpamRoot.js +190 -250
  12. package/dist/technospam/TechnoSpamRoot.js.map +1 -1
  13. package/dist/technospam/TechnoSpamRoutes.d.ts.map +1 -1
  14. package/dist/technospam/TechnoSpamRoutes.js.map +1 -1
  15. package/dist/technospam/api/technospamApi.d.ts +20 -9
  16. package/dist/technospam/api/technospamApi.d.ts.map +1 -1
  17. package/dist/technospam/api/technospamApi.js +62 -16
  18. package/dist/technospam/api/technospamApi.js.map +1 -1
  19. package/dist/technospam/pages/AdminAdminDashboardPagePage.js +2 -2
  20. package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
  21. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +1 -1
  22. package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  23. package/dist/technospam/pages/ApplicationsProblemsPagePage.d.ts.map +1 -1
  24. package/dist/technospam/pages/ApplicationsProblemsPagePage.js +176 -76
  25. package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
  26. package/dist/technospam/pages/DashboardDashboardPagePage.js +1 -1
  27. package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
  28. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +1 -1
  29. package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
  30. package/dist/technospam/pages/MentorshipSessionsPagePage.js +1 -1
  31. package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
  32. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardDashboardPagePage.js","names":[],"sources":["../../../src/technospam/pages/DashboardDashboardPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n ArrowRight,\n Award,\n BookOpen,\n Calendar,\n CalendarClock,\n CheckCircle2,\n Clock,\n Code2,\n GraduationCap,\n PlayCircle,\n Trophy,\n Users,\n} from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n MediaCover,\n PageLayout,\n StatCard,\n StatusBadge,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCertificatesQuery,\n useCoursesQuery,\n useEnrollmentsQuery,\n useHackathonsQuery,\n useSessionsQuery,\n useSubmissionsQuery,\n type TecCourse,\n type TecEnrollment,\n type TecHackathon,\n type TecMentorSession,\n} from '../api/technospamApi';\nimport { formatDate, formatDateTime, formatMoney } from '../utils/format';\n\n/* --------------------------------------------------------------- helpers */\n\nfunction SectionHeader({\n title,\n actionLabel,\n onAction,\n}: {\n title: string;\n actionLabel?: string;\n onAction?: () => void;\n}) {\n return (\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n {actionLabel && onAction ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"text-xs\" onClick={onAction}>\n {actionLabel} <ArrowRight size={13} />\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction ProgressBar({ pct }: { pct: number }) {\n return (\n <div className=\"h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-accent-primary transition-all\"\n style={{ width: `${Math.max(0, Math.min(100, pct))}%` }}\n />\n </div>\n );\n}\n\nfunction ContinueLearningCard({ e, onOpen }: { e: TecEnrollment; onOpen: () => void }) {\n const title = e.course?.title ?? 'Course';\n const seed = `${e.course?.topic ?? ''} ${title}`;\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group flex flex-col overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left transition-all duration-200 hover:-translate-y-1 hover:shadow-lg focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MediaCover seed={seed} icon={topicIcon(e.course?.topic ?? title)} height=\"h-20\">\n {e.course?.level ? <StatusBadge status={e.course.level} kind=\"level\" /> : <span />}\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-white/15 text-white backdrop-blur transition-transform duration-200 group-hover:scale-110\">\n <PlayCircle size={16} />\n </span>\n </MediaCover>\n <div className=\"flex flex-1 flex-col gap-2.5 p-3.5\">\n <div className=\"flex items-start gap-2\">\n <h3 className=\"line-clamp-2 flex-1 text-sm font-semibold text-text-primary group-hover:text-accent-primary\">\n {title}\n </h3>\n <StatusBadge status={e.status} />\n </div>\n <div className=\"mt-auto flex items-center gap-2.5\">\n <div className=\"flex-1\">\n <ProgressBar pct={e.progressPct} />\n </div>\n <span className=\"shrink-0 text-xs font-semibold text-text-secondary\">\n {e.progressPct}%\n </span>\n </div>\n </div>\n </button>\n );\n}\n\nfunction RecommendedCourseCard({ course, onOpen }: { course: TecCourse; onOpen: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group flex w-full flex-col overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left transition-all duration-200 hover:-translate-y-1 hover:shadow-lg focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MediaCover\n seed={`${course.topic ?? ''} ${course.title}`}\n icon={topicIcon(course.topic ?? course.title)}\n height=\"h-20\"\n >\n <StatusBadge status={course.level} kind=\"level\" />\n </MediaCover>\n <div className=\"flex flex-1 flex-col gap-1.5 p-3.5\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary group-hover:text-accent-primary\">\n {course.title}\n </h3>\n {course.summary ? (\n <p className=\"line-clamp-2 text-xs text-text-secondary\">{course.summary}</p>\n ) : null}\n {course.topic ? (\n <span className=\"mt-auto truncate pt-0.5 text-xs text-text-muted\">{course.topic}</span>\n ) : null}\n </div>\n </button>\n );\n}\n\nfunction SessionRow({ s }: { s: TecMentorSession }) {\n return (\n <div className=\"-mx-2 flex items-start gap-3 rounded-lg border-b border-border-seam px-2 py-3 transition-colors last:border-0 hover:bg-bg-sunken\">\n <span className=\"mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent-teal/15 text-accent-teal ring-1 ring-accent-teal/20\">\n <CalendarClock size={16} />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-sm font-medium text-text-primary\">{s.topic}</span>\n <StatusBadge status={s.status} />\n </div>\n {s.mentor?.headline ? (\n <div className=\"truncate text-xs text-text-muted\">{s.mentor.headline}</div>\n ) : null}\n <div className=\"mt-0.5 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock size={12} className=\"text-text-muted\" />\n {formatDateTime(s.scheduledAt)}\n </div>\n </div>\n </div>\n );\n}\n\nfunction HackathonBanner({ h, onOpen }: { h: TecHackathon; onOpen: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group block w-full overflow-hidden rounded-xl border border-border-seam text-left transition-all duration-200 hover:-translate-y-1 hover:shadow-lg focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MediaCover seed={`${h.theme ?? ''} ${h.title}`} icon={Trophy} height=\"h-24\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-white/80\">\n <Trophy size={12} /> Open hackathon\n </div>\n <h3 className=\"mt-0.5 truncate text-sm font-semibold text-white drop-shadow-sm\">\n {h.title}\n </h3>\n </div>\n {h.prizePool > 0 ? (\n <span className=\"shrink-0 rounded-full bg-white/20 px-2.5 py-1 text-xs font-semibold text-white backdrop-blur\">\n {formatMoney(h.prizePool, h.currency)}\n </span>\n ) : null}\n </MediaCover>\n <div className=\"flex items-center justify-between gap-2 bg-bg-surface px-3.5 py-2.5\">\n <span className=\"flex items-center gap-1.5 text-xs text-text-muted\">\n <Calendar size={12} />\n {formatDate(h.startAt)} – {formatDate(h.endAt)}\n </span>\n <span className=\"flex items-center gap-1 text-xs font-medium text-accent-primary opacity-0 transition-opacity group-hover:opacity-100\">\n Register <ArrowRight size={12} />\n </span>\n </div>\n </button>\n );\n}\n\n/* ------------------------------------------------------------------ page */\n\nexport function DashboardDashboardPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser } = useTechnoSpam();\n const learnerId = currentUser?.id;\n\n const enrollmentsQ = useEnrollmentsQuery(learnerId ? { learnerId } : {});\n const submissionsQ = useSubmissionsQuery(learnerId ? { learnerId } : {});\n const sessionsQ = useSessionsQuery(learnerId ? { menteeId: learnerId } : {});\n const certificatesQ = useCertificatesQuery(learnerId ? { learnerId } : {});\n const coursesQ = useCoursesQuery({ status: 'PUBLISHED' });\n const hackathonsQ = useHackathonsQuery({ status: 'REGISTRATION_OPEN' });\n\n const enrollments = enrollmentsQ.data?.tecListEnrollments.items ?? [];\n const submissions = submissionsQ.data?.tecListSubmissions.items ?? [];\n const sessions = sessionsQ.data?.tecListSessions ?? [];\n const certificates = certificatesQ.data?.tecListCertificates ?? [];\n const courses = coursesQ.data?.tecListCourses.items ?? [];\n const hackathons = hackathonsQ.data?.tecListHackathons.items ?? [];\n\n const greetingName =\n currentUser?.firstName || currentUser?.name || currentUser?.email?.split('@')[0] || 'there';\n\n const inProgress = useMemo(\n () => enrollments.filter((e) => e.status === 'IN_PROGRESS' || e.status === 'ENROLLED'),\n [enrollments]\n );\n\n const continueLearning = useMemo(\n () =>\n [...inProgress]\n .sort(\n (a, b) =>\n new Date(b.lastActiveAt ?? b.startedAt).getTime() -\n new Date(a.lastActiveAt ?? a.startedAt).getTime()\n )\n .slice(0, 3),\n [inProgress]\n );\n\n const problemsSolved = useMemo(\n () => new Set(submissions.filter((s) => s.verdict === 'ACCEPTED').map((s) => s.problemId)).size,\n [submissions]\n );\n\n // Stable \"now\" captured once on mount (state initializers may call impure fns).\n const [now] = useState(() => Date.now());\n const upcomingSessions = useMemo(() => {\n return [...sessions]\n .filter(\n (s) =>\n (s.status === 'CONFIRMED' || s.status === 'REQUESTED') &&\n new Date(s.scheduledAt).getTime() > now\n )\n .sort((a, b) => new Date(a.scheduledAt).getTime() - new Date(b.scheduledAt).getTime());\n }, [sessions, now]);\n\n const recommended = useMemo(() => {\n const enrolledIds = new Set(enrollments.map((e) => e.courseId));\n return courses.filter((c) => !enrolledIds.has(c.id)).slice(0, 4);\n }, [courses, enrollments]);\n\n const openHackathons = hackathons.slice(0, 4);\n\n return (\n <PageLayout\n hero\n title={`Welcome back, ${greetingName}`}\n description=\"Your learning hub — pick up where you left off, keep your skills sharp, and jump into what's next.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/courses/my-learning-page')}>\n <GraduationCap size={16} /> My Learning\n </Button>\n }\n >\n {/* Top metrics */}\n <div className=\"mb-5 grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <StatCard\n label=\"Courses in progress\"\n value={inProgress.length}\n icon={BookOpen}\n tone=\"blue\"\n />\n <StatCard label=\"Problems solved\" value={problemsSolved} icon={Code2} tone=\"green\" />\n <StatCard\n label=\"Upcoming sessions\"\n value={upcomingSessions.length}\n icon={CalendarClock}\n tone=\"amber\"\n />\n <StatCard label=\"Certificates\" value={certificates.length} icon={Award} tone=\"purple\" />\n </div>\n\n {/* Quick actions */}\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/courses/courses-page')}\n >\n <BookOpen size={18} />\n <span className=\"text-xs\">Browse courses</span>\n </Button>\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/applications/problems-page')}\n >\n <Code2 size={18} />\n <span className=\"text-xs\">Practice problems</span>\n </Button>\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/mentorship/mentors-page')}\n >\n <Users size={18} />\n <span className=\"text-xs\">Find a mentor</span>\n </Button>\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/hackathons/hackathons-page')}\n >\n <Trophy size={18} />\n <span className=\"text-xs\">Hackathons</span>\n </Button>\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Main column */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Continue learning */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Continue learning\"\n actionLabel=\"My Learning\"\n onAction={() => navigate('/courses/my-learning-page')}\n />\n {enrollmentsQ.loading && !enrollments.length ? (\n <LoadingRows count={2} height=\"h-16\" />\n ) : enrollmentsQ.error ? (\n <ErrorView title=\"Couldn't load your courses\" error={enrollmentsQ.error} />\n ) : continueLearning.length === 0 ? (\n <EmptyView\n icon={<BookOpen size={24} />}\n title=\"No courses in progress\"\n description=\"Enroll in a course to start building skill by doing — your active courses show up here.\"\n action={\n <Button onClick={() => navigate('/courses/courses-page')}>Browse courses</Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {continueLearning.map((e) => (\n <ContinueLearningCard\n key={e.id}\n e={e}\n onOpen={() => navigate(`/courses/course-details-page?id=${e.courseId}`)}\n />\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Recommended courses */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Recommended for you\"\n actionLabel=\"View all\"\n onAction={() => navigate('/courses/courses-page')}\n />\n {coursesQ.loading && !courses.length ? (\n <LoadingRows count={2} height=\"h-20\" />\n ) : coursesQ.error ? (\n <ErrorView title=\"Couldn't load courses\" error={coursesQ.error} />\n ) : recommended.length === 0 ? (\n <EmptyView\n icon={<GraduationCap size={24} />}\n title=\"No courses to recommend yet\"\n description=\"New courses are on the way. TechnoSpam is pre-launch — check back soon.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {recommended.map((c) => (\n <RecommendedCourseCard\n key={c.id}\n course={c}\n onOpen={() => navigate(`/courses/course-details-page?id=${c.id}`)}\n />\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Side column */}\n <div className=\"space-y-6\">\n {/* Upcoming sessions */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Upcoming sessions\"\n actionLabel=\"All sessions\"\n onAction={() => navigate('/mentorship/sessions-page')}\n />\n {sessionsQ.loading && !sessions.length ? (\n <LoadingRows count={2} height=\"h-14\" />\n ) : sessionsQ.error ? (\n <ErrorView title=\"Couldn't load sessions\" error={sessionsQ.error} />\n ) : upcomingSessions.length === 0 ? (\n <EmptyView\n icon={<CalendarClock size={24} />}\n title=\"No sessions booked\"\n description=\"Book time with a mentor to get unblocked — your upcoming sessions appear here.\"\n action={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/mentors-page')}>\n Find a mentor\n </Button>\n }\n />\n ) : (\n <div>\n {upcomingSessions.slice(0, 5).map((s) => (\n <SessionRow key={s.id} s={s} />\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Open hackathons */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Open hackathons\"\n actionLabel=\"View all\"\n onAction={() => navigate('/hackathons/hackathons-page')}\n />\n {hackathonsQ.loading && !hackathons.length ? (\n <LoadingRows count={2} height=\"h-14\" />\n ) : hackathonsQ.error ? (\n <ErrorView title=\"Couldn't load hackathons\" error={hackathonsQ.error} />\n ) : openHackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={24} />}\n title=\"No open hackathons\"\n description=\"When registration opens for a hackathon, it will show up here to join.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {openHackathons.map((h) => (\n <HackathonBanner\n key={h.id}\n h={h}\n onOpen={() => navigate(`/hackathons/hackathon-details-page?id=${h.id}`)}\n />\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Certificates summary */}\n {certificates.length > 0 ? (\n <GlassCard className=\"p-5\">\n <SectionHeader title=\"Latest certificate\" />\n <div className=\"flex items-center gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-accent-primary/12 text-accent-teal\">\n <CheckCircle2 size={20} />\n </span>\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {certificates[0]?.course?.title ?? 'Certificate'}\n </div>\n <div className=\"text-xs text-text-muted\">\n Score {certificates[0]?.score} · Issued {formatDate(certificates[0]?.issuedAt)}\n </div>\n </div>\n </div>\n </GlassCard>\n ) : null}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardDashboardPagePage.js","names":[],"sources":["../../../src/technospam/pages/DashboardDashboardPagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n ArrowRight,\n Award,\n BookOpen,\n Calendar,\n CalendarClock,\n CheckCircle2,\n Clock,\n Code2,\n GraduationCap,\n PlayCircle,\n Trophy,\n Users,\n} from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n MediaCover,\n PageLayout,\n StatCard,\n StatusBadge,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCertificatesQuery,\n useCoursesQuery,\n useEnrollmentsQuery,\n useHackathonsQuery,\n useSessionsQuery,\n useSubmissionsQuery,\n type TecCourse,\n type TecEnrollment,\n type TecHackathon,\n type TecMentorSession,\n} from '../api/technospamApi';\nimport { formatDate, formatDateTime, formatMoney } from '../utils/format';\n\n/* --------------------------------------------------------------- helpers */\n\nfunction SectionHeader({\n title,\n actionLabel,\n onAction,\n}: {\n title: string;\n actionLabel?: string;\n onAction?: () => void;\n}) {\n return (\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-base font-semibold text-text-primary\">{title}</h2>\n {actionLabel && onAction ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"text-xs\" onClick={onAction}>\n {actionLabel} <ArrowRight size={13} />\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction ProgressBar({ pct }: { pct: number }) {\n return (\n <div className=\"h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-accent-primary transition-all\"\n style={{ width: `${Math.max(0, Math.min(100, pct))}%` }}\n />\n </div>\n );\n}\n\nfunction ContinueLearningCard({ e, onOpen }: { e: TecEnrollment; onOpen: () => void }) {\n const title = e.course?.title ?? 'Course';\n const seed = `${e.course?.topic ?? ''} ${title}`;\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group flex flex-col overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left transition-all duration-200 hover:-translate-y-1 hover:shadow-lg focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MediaCover seed={seed} icon={topicIcon(e.course?.topic ?? title)} height=\"h-20\">\n {e.course?.level ? <StatusBadge status={e.course.level} kind=\"level\" /> : <span />}\n <span className=\"flex h-7 w-7 items-center justify-center rounded-full bg-white/15 text-white backdrop-blur transition-transform duration-200 group-hover:scale-110\">\n <PlayCircle size={16} />\n </span>\n </MediaCover>\n <div className=\"flex flex-1 flex-col gap-2.5 p-3.5\">\n <div className=\"flex items-start gap-2\">\n <h3 className=\"line-clamp-2 flex-1 text-sm font-semibold text-text-primary group-hover:text-accent-primary\">\n {title}\n </h3>\n <StatusBadge status={e.status} />\n </div>\n <div className=\"mt-auto flex items-center gap-2.5\">\n <div className=\"flex-1\">\n <ProgressBar pct={e.progressPct} />\n </div>\n <span className=\"shrink-0 text-xs font-semibold text-text-secondary\">\n {e.progressPct}%\n </span>\n </div>\n </div>\n </button>\n );\n}\n\nfunction RecommendedCourseCard({ course, onOpen }: { course: TecCourse; onOpen: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group flex w-full flex-col overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left transition-all duration-200 hover:-translate-y-1 hover:shadow-lg focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MediaCover\n seed={`${course.topic ?? ''} ${course.title}`}\n icon={topicIcon(course.topic ?? course.title)}\n height=\"h-20\"\n >\n <StatusBadge status={course.level} kind=\"level\" />\n </MediaCover>\n <div className=\"flex flex-1 flex-col gap-1.5 p-3.5\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary group-hover:text-accent-primary\">\n {course.title}\n </h3>\n {course.summary ? (\n <p className=\"line-clamp-2 text-xs text-text-secondary\">{course.summary}</p>\n ) : null}\n {course.topic ? (\n <span className=\"mt-auto truncate pt-0.5 text-xs text-text-muted\">{course.topic}</span>\n ) : null}\n </div>\n </button>\n );\n}\n\nfunction SessionRow({ s }: { s: TecMentorSession }) {\n return (\n <div className=\"-mx-2 flex items-start gap-3 rounded-lg border-b border-border-seam px-2 py-3 transition-colors last:border-0 hover:bg-bg-sunken\">\n <span className=\"mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent-teal/15 text-accent-teal ring-1 ring-accent-teal/20\">\n <CalendarClock size={16} />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"truncate text-sm font-medium text-text-primary\">{s.topic}</span>\n <StatusBadge status={s.status} />\n </div>\n {s.mentor?.headline ? (\n <div className=\"truncate text-xs text-text-muted\">{s.mentor.headline}</div>\n ) : null}\n <div className=\"mt-0.5 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock size={12} className=\"text-text-muted\" />\n {formatDateTime(s.scheduledAt)}\n </div>\n </div>\n </div>\n );\n}\n\nfunction HackathonBanner({ h, onOpen }: { h: TecHackathon; onOpen: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group block w-full overflow-hidden rounded-xl border border-border-seam text-left transition-all duration-200 hover:-translate-y-1 hover:shadow-lg focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MediaCover seed={`${h.theme ?? ''} ${h.title}`} icon={Trophy} height=\"h-24\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-white/80\">\n <Trophy size={12} /> Open hackathon\n </div>\n <h3 className=\"mt-0.5 truncate text-sm font-semibold text-white drop-shadow-sm\">\n {h.title}\n </h3>\n </div>\n {h.prizePool > 0 ? (\n <span className=\"shrink-0 rounded-full bg-white/20 px-2.5 py-1 text-xs font-semibold text-white backdrop-blur\">\n {formatMoney(h.prizePool, h.currency)}\n </span>\n ) : null}\n </MediaCover>\n <div className=\"flex items-center justify-between gap-2 bg-bg-surface px-3.5 py-2.5\">\n <span className=\"flex items-center gap-1.5 text-xs text-text-muted\">\n <Calendar size={12} />\n {formatDate(h.startAt)} – {formatDate(h.endAt)}\n </span>\n <span className=\"flex items-center gap-1 text-xs font-medium text-accent-primary opacity-0 transition-opacity group-hover:opacity-100\">\n Register <ArrowRight size={12} />\n </span>\n </div>\n </button>\n );\n}\n\n/* ------------------------------------------------------------------ page */\n\nexport function DashboardDashboardPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser } = useTechnoSpam();\n const learnerId = currentUser?.id;\n\n const enrollmentsQ = useEnrollmentsQuery(learnerId ? { learnerId } : {});\n const submissionsQ = useSubmissionsQuery(learnerId ? { learnerId } : {});\n const sessionsQ = useSessionsQuery(learnerId ? { menteeId: learnerId } : {});\n const certificatesQ = useCertificatesQuery(learnerId ? { learnerId } : {});\n const coursesQ = useCoursesQuery({ status: 'PUBLISHED' });\n const hackathonsQ = useHackathonsQuery({ status: 'REGISTRATION_OPEN' });\n\n const enrollments = enrollmentsQ.data?.tecListEnrollments.items ?? [];\n const submissions = submissionsQ.data?.tecListSubmissions.items ?? [];\n const sessions = sessionsQ.data?.tecListSessions.items ?? [];\n const certificates = certificatesQ.data?.tecListCertificates ?? [];\n const courses = coursesQ.data?.tecListCourses.items ?? [];\n const hackathons = hackathonsQ.data?.tecListHackathons.items ?? [];\n\n const greetingName =\n currentUser?.firstName || currentUser?.name || currentUser?.email?.split('@')[0] || 'there';\n\n const inProgress = useMemo(\n () => enrollments.filter((e) => e.status === 'IN_PROGRESS' || e.status === 'ENROLLED'),\n [enrollments]\n );\n\n const continueLearning = useMemo(\n () =>\n [...inProgress]\n .sort(\n (a, b) =>\n new Date(b.lastActiveAt ?? b.startedAt).getTime() -\n new Date(a.lastActiveAt ?? a.startedAt).getTime()\n )\n .slice(0, 3),\n [inProgress]\n );\n\n const problemsSolved = useMemo(\n () => new Set(submissions.filter((s) => s.verdict === 'ACCEPTED').map((s) => s.problemId)).size,\n [submissions]\n );\n\n // Stable \"now\" captured once on mount (state initializers may call impure fns).\n const [now] = useState(() => Date.now());\n const upcomingSessions = useMemo(() => {\n return [...sessions]\n .filter(\n (s) =>\n (s.status === 'CONFIRMED' || s.status === 'REQUESTED') &&\n new Date(s.scheduledAt).getTime() > now\n )\n .sort((a, b) => new Date(a.scheduledAt).getTime() - new Date(b.scheduledAt).getTime());\n }, [sessions, now]);\n\n const recommended = useMemo(() => {\n const enrolledIds = new Set(enrollments.map((e) => e.courseId));\n return courses.filter((c) => !enrolledIds.has(c.id)).slice(0, 4);\n }, [courses, enrollments]);\n\n const openHackathons = hackathons.slice(0, 4);\n\n return (\n <PageLayout\n hero\n title={`Welcome back, ${greetingName}`}\n description=\"Your learning hub — pick up where you left off, keep your skills sharp, and jump into what's next.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/courses/my-learning-page')}>\n <GraduationCap size={16} /> My Learning\n </Button>\n }\n >\n {/* Top metrics */}\n <div className=\"mb-5 grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <StatCard\n label=\"Courses in progress\"\n value={inProgress.length}\n icon={BookOpen}\n tone=\"blue\"\n />\n <StatCard label=\"Problems solved\" value={problemsSolved} icon={Code2} tone=\"green\" />\n <StatCard\n label=\"Upcoming sessions\"\n value={upcomingSessions.length}\n icon={CalendarClock}\n tone=\"amber\"\n />\n <StatCard label=\"Certificates\" value={certificates.length} icon={Award} tone=\"purple\" />\n </div>\n\n {/* Quick actions */}\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/courses/courses-page')}\n >\n <BookOpen size={18} />\n <span className=\"text-xs\">Browse courses</span>\n </Button>\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/applications/problems-page')}\n >\n <Code2 size={18} />\n <span className=\"text-xs\">Practice problems</span>\n </Button>\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/mentorship/mentors-page')}\n >\n <Users size={18} />\n <span className=\"text-xs\">Find a mentor</span>\n </Button>\n <Button\n variant=\"outline\"\n className=\"h-auto flex-col gap-2 py-4\"\n onClick={() => navigate('/hackathons/hackathons-page')}\n >\n <Trophy size={18} />\n <span className=\"text-xs\">Hackathons</span>\n </Button>\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Main column */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Continue learning */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Continue learning\"\n actionLabel=\"My Learning\"\n onAction={() => navigate('/courses/my-learning-page')}\n />\n {enrollmentsQ.loading && !enrollments.length ? (\n <LoadingRows count={2} height=\"h-16\" />\n ) : enrollmentsQ.error ? (\n <ErrorView title=\"Couldn't load your courses\" error={enrollmentsQ.error} />\n ) : continueLearning.length === 0 ? (\n <EmptyView\n icon={<BookOpen size={24} />}\n title=\"No courses in progress\"\n description=\"Enroll in a course to start building skill by doing — your active courses show up here.\"\n action={\n <Button onClick={() => navigate('/courses/courses-page')}>Browse courses</Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {continueLearning.map((e) => (\n <ContinueLearningCard\n key={e.id}\n e={e}\n onOpen={() => navigate(`/courses/course-details-page?id=${e.courseId}`)}\n />\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Recommended courses */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Recommended for you\"\n actionLabel=\"View all\"\n onAction={() => navigate('/courses/courses-page')}\n />\n {coursesQ.loading && !courses.length ? (\n <LoadingRows count={2} height=\"h-20\" />\n ) : coursesQ.error ? (\n <ErrorView title=\"Couldn't load courses\" error={coursesQ.error} />\n ) : recommended.length === 0 ? (\n <EmptyView\n icon={<GraduationCap size={24} />}\n title=\"No courses to recommend yet\"\n description=\"New courses are on the way. TechnoSpam is pre-launch — check back soon.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {recommended.map((c) => (\n <RecommendedCourseCard\n key={c.id}\n course={c}\n onOpen={() => navigate(`/courses/course-details-page?id=${c.id}`)}\n />\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Side column */}\n <div className=\"space-y-6\">\n {/* Upcoming sessions */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Upcoming sessions\"\n actionLabel=\"All sessions\"\n onAction={() => navigate('/mentorship/sessions-page')}\n />\n {sessionsQ.loading && !sessions.length ? (\n <LoadingRows count={2} height=\"h-14\" />\n ) : sessionsQ.error ? (\n <ErrorView title=\"Couldn't load sessions\" error={sessionsQ.error} />\n ) : upcomingSessions.length === 0 ? (\n <EmptyView\n icon={<CalendarClock size={24} />}\n title=\"No sessions booked\"\n description=\"Book time with a mentor to get unblocked — your upcoming sessions appear here.\"\n action={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/mentors-page')}>\n Find a mentor\n </Button>\n }\n />\n ) : (\n <div>\n {upcomingSessions.slice(0, 5).map((s) => (\n <SessionRow key={s.id} s={s} />\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Open hackathons */}\n <GlassCard className=\"p-5\">\n <SectionHeader\n title=\"Open hackathons\"\n actionLabel=\"View all\"\n onAction={() => navigate('/hackathons/hackathons-page')}\n />\n {hackathonsQ.loading && !hackathons.length ? (\n <LoadingRows count={2} height=\"h-14\" />\n ) : hackathonsQ.error ? (\n <ErrorView title=\"Couldn't load hackathons\" error={hackathonsQ.error} />\n ) : openHackathons.length === 0 ? (\n <EmptyView\n icon={<Trophy size={24} />}\n title=\"No open hackathons\"\n description=\"When registration opens for a hackathon, it will show up here to join.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {openHackathons.map((h) => (\n <HackathonBanner\n key={h.id}\n h={h}\n onOpen={() => navigate(`/hackathons/hackathon-details-page?id=${h.id}`)}\n />\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Certificates summary */}\n {certificates.length > 0 ? (\n <GlassCard className=\"p-5\">\n <SectionHeader title=\"Latest certificate\" />\n <div className=\"flex items-center gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-accent-primary/12 text-accent-teal\">\n <CheckCircle2 size={20} />\n </span>\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-medium text-text-primary\">\n {certificates[0]?.course?.title ?? 'Certificate'}\n </div>\n <div className=\"text-xs text-text-muted\">\n Score {certificates[0]?.score} · Issued {formatDate(certificates[0]?.issuedAt)}\n </div>\n </div>\n </div>\n </GlassCard>\n ) : null}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -102,7 +102,7 @@ function fe({ team: e, isMine: n }) {
102
102
  });
103
103
  }
104
104
  function j() {
105
- let [t] = ce(), i = t.get("id") ?? "", { currentUser: f } = e(), { data: p, loading: m, error: h, refetch: j } = ne(i), { data: pe, loading: me, error: M, refetch: N } = ae(i), [he, { loading: P }] = re(), [F, { loading: I }] = ie(), [L, R] = u(""), [z, B] = u(""), [ge, _e] = u(""), [V, H] = u(""), [U, W] = u(""), [G, K] = u(""), [q, J] = u(""), Y = p?.tecHackathon ?? null, X = pe?.tecListTeams ?? [], Z = Y?.status === "REGISTRATION_OPEN", Q = f?.id ? X.filter((e) => e.captainId === f.id) : [], $ = ge || Q[0]?.id || "";
105
+ let [t] = ce(), i = t.get("id") ?? "", { currentUser: f } = e(), { data: p, loading: m, error: h, refetch: j } = ne(i), { data: pe, loading: me, error: M, refetch: N } = ae(i), [he, { loading: P }] = re(), [F, { loading: I }] = ie(), [L, R] = u(""), [z, B] = u(""), [ge, _e] = u(""), [V, H] = u(""), [U, W] = u(""), [G, K] = u(""), [q, J] = u(""), Y = p?.tecHackathon ?? null, X = pe?.tecListTeams.items ?? [], Z = Y?.status === "REGISTRATION_OPEN", Q = f?.id ? X.filter((e) => e.captainId === f.id) : [], $ = ge || Q[0]?.id || "";
106
106
  return m && !Y ? /* @__PURE__ */ x(n, {
107
107
  title: "Hackathon",
108
108
  backPath: "/hackathons/hackathons-page",
@@ -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 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
+ {"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.items ?? [];\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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"}
@@ -182,7 +182,7 @@ function I({ loading: e, error: t, sessions: n, showMentor: r, emptyTitle: i, em
182
182
  });
183
183
  }
184
184
  function L() {
185
- let a = t(), { currentUser: o, workspaceId: s } = e(), { emit: l } = n(), [y, x] = _("mentee"), [w, T] = _(null), k = o?.id, A = g(k ? { menteeId: k } : {}), P = h({}), F = P.data?.tecListMentors.items.find((e) => e.userId === o?.id), L = F?.id, R = g(L ? { mentorId: L } : {}), [z] = f(), [B] = m(), [V] = p(), H = k ? A.data?.tecListSessions ?? [] : [], U = L ? R.data?.tecListSessions ?? [] : [], W = [...H, ...U], G = W.filter((e) => e.status === "REQUESTED" || e.status === "CONFIRMED").length, K = W.filter((e) => e.status === "COMPLETED").length, q = async (e) => {
185
+ let a = t(), { currentUser: o, workspaceId: s } = e(), { emit: l } = n(), [y, x] = _("mentee"), [w, T] = _(null), k = o?.id, A = g(k ? { menteeId: k } : {}), P = h({}), F = P.data?.tecListMentors.items.find((e) => e.userId === o?.id), L = F?.id, R = g(L ? { mentorId: L } : {}), [z] = f(), [B] = m(), [V] = p(), H = k ? A.data?.tecListSessions.items ?? [] : [], U = L ? R.data?.tecListSessions.items ?? [] : [], W = [...H, ...U], G = W.filter((e) => e.status === "REQUESTED" || e.status === "CONFIRMED").length, K = W.filter((e) => e.status === "COMPLETED").length, q = async (e) => {
186
186
  T(e), l("technospam.session.cancel_clicked", {
187
187
  workspaceId: s,
188
188
  entityId: e,
@@ -1 +1 @@
1
- {"version":3,"file":"MentorshipSessionsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipSessionsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n CalendarClock,\n Check,\n CheckCircle2,\n Clock,\n MessageSquare,\n Users,\n Video,\n X,\n} from 'lucide-react';\nimport { Button, GlassCard, Input, Tabs, TabsList, TabsTrigger } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCancelSession,\n useCompleteSession,\n useConfirmSession,\n useMentorsQuery,\n useSessionsQuery,\n type TecMentorSession,\n} from '../api/technospamApi';\nimport { formatDateTime, formatDuration } from '../utils/format';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\n\ntype Perspective = 'mentee' | 'mentor';\n\nconst CANCELLABLE = new Set(['REQUESTED', 'CONFIRMED']);\n\nfunction SessionRow({\n session,\n showMentor,\n isMentor,\n onCancel,\n onConfirm,\n onComplete,\n busy,\n}: {\n session: TecMentorSession;\n showMentor: boolean;\n isMentor: boolean;\n onCancel: (id: string) => void;\n onConfirm: (id: string, meetingUrl: string) => Promise<void>;\n onComplete: (id: string, rating: number, feedback: string) => Promise<void>;\n busy: boolean;\n}) {\n const canCancel = CANCELLABLE.has(session.status);\n const [mode, setMode] = useState<'none' | 'confirm' | 'complete'>('none');\n const [meetingUrl, setMeetingUrl] = useState('');\n const [rating, setRating] = useState('5');\n const [feedback, setFeedback] = useState('');\n\n const submitConfirm = async () => {\n await onConfirm(session.id, meetingUrl.trim());\n setMode('none');\n setMeetingUrl('');\n };\n const submitComplete = async () => {\n await onComplete(session.id, Math.min(5, Math.max(1, Number(rating) || 5)), feedback.trim());\n setMode('none');\n };\n\n return (\n <GlassCard className=\"flex flex-col gap-3 p-4 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-accent-primary to-accent-purple text-white shadow-sm\">\n <Video size={18} />\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\">\n {session.topic}\n </span>\n <StatusBadge status={session.status} />\n {session.rating ? (\n <span className=\"text-xs text-text-muted\">★ {session.rating}/5</span>\n ) : null}\n </div>\n {showMentor && session.mentor?.headline ? (\n <div className=\"mt-0.5 truncate text-xs text-text-secondary\">\n with {session.mentor.headline}\n </div>\n ) : null}\n <div className=\"mt-1 flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarClock size={13} /> {formatDateTime(session.scheduledAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={13} /> {formatDuration(session.durationMinutes)}\n </span>\n </div>\n {session.agenda ? (\n <p className=\"mt-1 line-clamp-2 text-xs text-text-secondary\">{session.agenda}</p>\n ) : null}\n </div>\n </div>\n <div className=\"flex shrink-0 flex-wrap items-center gap-2\">\n {session.meetingUrl ? (\n <Button\n size=\"sm\"\n onClick={() => window.open(session.meetingUrl ?? '', '_blank', 'noopener,noreferrer')}\n >\n <Video size={15} /> Join\n </Button>\n ) : null}\n {isMentor && session.status === 'REQUESTED' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setMode(mode === 'confirm' ? 'none' : 'confirm')}\n >\n <Check size={15} /> Confirm\n </Button>\n ) : null}\n {isMentor && session.status === 'CONFIRMED' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setMode(mode === 'complete' ? 'none' : 'complete')}\n >\n <CheckCircle2 size={15} /> Mark complete\n </Button>\n ) : null}\n {canCancel ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => onCancel(session.id)} disabled={busy}>\n <X size={15} /> Cancel\n </Button>\n ) : null}\n </div>\n </div>\n\n {mode === 'confirm' ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3 sm:flex-row sm:items-center\">\n <Input\n className=\"flex-1\"\n placeholder=\"Meeting link (e.g. https://meet.…)\"\n value={meetingUrl}\n onChange={(e) => setMeetingUrl(e.target.value)}\n />\n <Button size=\"sm\" onClick={submitConfirm} disabled={busy}>\n Confirm session\n </Button>\n </div>\n ) : null}\n {mode === 'complete' ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs text-text-secondary\">Rating (1–5)</label>\n <Input\n type=\"number\"\n min={1}\n max={5}\n className=\"w-20\"\n value={rating}\n onChange={(e) => setRating(e.target.value)}\n />\n </div>\n <Input\n placeholder=\"Feedback for the mentee (optional)\"\n value={feedback}\n onChange={(e) => setFeedback(e.target.value)}\n />\n <div>\n <Button size=\"sm\" onClick={submitComplete} disabled={busy}>\n Complete session\n </Button>\n </div>\n </div>\n ) : null}\n </GlassCard>\n );\n}\n\nfunction SessionsList({\n loading,\n error,\n sessions,\n showMentor,\n emptyTitle,\n emptyDescription,\n emptyAction,\n isMentor,\n onCancel,\n onConfirm,\n onComplete,\n busyId,\n}: {\n loading: boolean;\n error?: { message?: string };\n sessions: TecMentorSession[];\n showMentor: boolean;\n emptyTitle: string;\n emptyDescription: string;\n emptyAction?: React.ReactNode;\n isMentor: boolean;\n onCancel: (id: string) => void;\n onConfirm: (id: string, meetingUrl: string) => Promise<void>;\n onComplete: (id: string, rating: number, feedback: string) => Promise<void>;\n busyId: string | null;\n}) {\n if (loading && sessions.length === 0) return <LoadingRows count={3} height=\"h-24\" />;\n if (error) return <ErrorView title=\"Couldn't load sessions\" error={error} />;\n if (sessions.length === 0) {\n return (\n <EmptyView\n icon={<MessageSquare size={26} />}\n title={emptyTitle}\n description={emptyDescription}\n action={emptyAction}\n />\n );\n }\n const sorted = [...sessions].sort(\n (a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime()\n );\n return (\n <div className=\"space-y-3\">\n {sorted.map((session) => (\n <SessionRow\n key={session.id}\n session={session}\n showMentor={showMentor}\n isMentor={isMentor}\n onCancel={onCancel}\n onConfirm={onConfirm}\n onComplete={onComplete}\n busy={busyId === session.id}\n />\n ))}\n </div>\n );\n}\n\nexport function MentorshipSessionsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const [tab, setTab] = useState<Perspective>('mentee');\n const [cancellingId, setCancellingId] = useState<string | null>(null);\n\n const menteeId = currentUser?.id;\n\n // As mentee: sessions the current user booked.\n const menteeQ = useSessionsQuery(menteeId ? { menteeId } : {});\n\n // Resolve whether the current user is a mentor, to load their mentor sessions.\n const mentorsQ = useMentorsQuery({});\n const myMentor = mentorsQ.data?.tecListMentors.items.find((m) => m.userId === currentUser?.id);\n const mentorId = myMentor?.id;\n const mentorQ = useSessionsQuery(mentorId ? { mentorId } : {});\n\n const [cancelSession] = useCancelSession();\n const [confirmSession] = useConfirmSession();\n const [completeSession] = useCompleteSession();\n\n const menteeSessions = menteeId ? (menteeQ.data?.tecListSessions ?? []) : [];\n const mentorSessions = mentorId ? (mentorQ.data?.tecListSessions ?? []) : [];\n const allSessions = [...menteeSessions, ...mentorSessions];\n const upcomingCount = allSessions.filter(\n (s) => s.status === 'REQUESTED' || s.status === 'CONFIRMED'\n ).length;\n const completedCount = allSessions.filter((s) => s.status === 'COMPLETED').length;\n\n const handleCancel = async (id: string) => {\n setCancellingId(id);\n emit('technospam.session.cancel_clicked', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n try {\n const res = await cancelSession({ variables: { id } });\n if (res.data?.tecCancelSession) {\n emit('technospam.session.cancelled', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n notify.success('Session cancelled', 'The session has been cancelled.');\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n const handleConfirm = async (id: string, meetingUrl: string) => {\n setCancellingId(id);\n try {\n const res = await confirmSession({\n variables: { id, meetingUrl: meetingUrl || undefined },\n });\n if (res.data?.tecConfirmSession) {\n notify.success('Session confirmed', 'The mentee has been notified.');\n await mentorQ.refetch();\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n const handleComplete = async (id: string, rating: number, feedback: string) => {\n setCancellingId(id);\n emit('technospam.session.complete_clicked', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n try {\n const res = await completeSession({\n variables: { id, rating, feedback: feedback || undefined },\n });\n if (res.data?.tecCompleteSession) {\n emit('technospam.session.completed', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n notify.success('Session completed', 'Nice work — the session is wrapped up.');\n await mentorQ.refetch();\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n if (!currentUser?.id) {\n return (\n <PageLayout hero title=\"My Sessions\" description=\"Track your mentorship sessions.\">\n <EmptyView\n icon={<MessageSquare size={26} />}\n title=\"Sign in to view your sessions\"\n description=\"Your booked and hosted mentorship sessions will appear here once you're signed in.\"\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n hero\n title=\"My Sessions\"\n description=\"Manage the mentorship sessions you've booked and the ones you host.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/mentors-page')}>\n <Users size={16} /> Find a mentor\n </Button>\n }\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label=\"As mentee\"\n value={menteeSessions.length}\n icon={MessageSquare}\n tone=\"blue\"\n />\n <StatCard\n label=\"As mentor\"\n value={mentorId ? mentorSessions.length : 0}\n icon={Users}\n tone=\"purple\"\n />\n <StatCard label=\"Upcoming\" value={upcomingCount} icon={CalendarClock} tone=\"teal\" />\n <StatCard label=\"Completed\" value={completedCount} icon={CheckCircle2} tone=\"green\" />\n </div>\n\n <Tabs value={tab} onValueChange={(v) => setTab(v as Perspective)} className=\"mb-4\">\n <TabsList>\n <TabsTrigger value=\"mentee\">As mentee</TabsTrigger>\n <TabsTrigger value=\"mentor\">As mentor</TabsTrigger>\n </TabsList>\n </Tabs>\n\n {tab === 'mentee' ? (\n <SessionsList\n loading={menteeQ.loading}\n error={menteeQ.error}\n sessions={menteeSessions}\n showMentor\n emptyTitle=\"No sessions booked yet\"\n emptyDescription=\"Find a mentor and request a session to get personalized guidance.\"\n emptyAction={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Find a mentor</Button>\n }\n isMentor={false}\n onCancel={handleCancel}\n onConfirm={handleConfirm}\n onComplete={handleComplete}\n busyId={cancellingId}\n />\n ) : mentorsQ.loading && !myMentor ? (\n <LoadingRows count={3} height=\"h-24\" />\n ) : !mentorId ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"You're not a mentor yet\"\n description=\"Create a mentor profile to start hosting sessions and helping others build.\"\n action={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Become a mentor</Button>\n }\n />\n ) : (\n <SessionsList\n loading={mentorQ.loading}\n error={mentorQ.error}\n sessions={mentorSessions}\n showMentor={false}\n emptyTitle=\"No sessions to host yet\"\n emptyDescription=\"When mentees request time with you, their sessions will show up here.\"\n isMentor\n onCancel={handleCancel}\n onConfirm={handleConfirm}\n onComplete={handleComplete}\n busyId={cancellingId}\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MentorshipSessionsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipSessionsPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n CalendarClock,\n Check,\n CheckCircle2,\n Clock,\n MessageSquare,\n Users,\n Video,\n X,\n} from 'lucide-react';\nimport { Button, GlassCard, Input, Tabs, TabsList, TabsTrigger } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadingRows,\n PageLayout,\n StatCard,\n StatusBadge,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCancelSession,\n useCompleteSession,\n useConfirmSession,\n useMentorsQuery,\n useSessionsQuery,\n type TecMentorSession,\n} from '../api/technospamApi';\nimport { formatDateTime, formatDuration } from '../utils/format';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\n\ntype Perspective = 'mentee' | 'mentor';\n\nconst CANCELLABLE = new Set(['REQUESTED', 'CONFIRMED']);\n\nfunction SessionRow({\n session,\n showMentor,\n isMentor,\n onCancel,\n onConfirm,\n onComplete,\n busy,\n}: {\n session: TecMentorSession;\n showMentor: boolean;\n isMentor: boolean;\n onCancel: (id: string) => void;\n onConfirm: (id: string, meetingUrl: string) => Promise<void>;\n onComplete: (id: string, rating: number, feedback: string) => Promise<void>;\n busy: boolean;\n}) {\n const canCancel = CANCELLABLE.has(session.status);\n const [mode, setMode] = useState<'none' | 'confirm' | 'complete'>('none');\n const [meetingUrl, setMeetingUrl] = useState('');\n const [rating, setRating] = useState('5');\n const [feedback, setFeedback] = useState('');\n\n const submitConfirm = async () => {\n await onConfirm(session.id, meetingUrl.trim());\n setMode('none');\n setMeetingUrl('');\n };\n const submitComplete = async () => {\n await onComplete(session.id, Math.min(5, Math.max(1, Number(rating) || 5)), feedback.trim());\n setMode('none');\n };\n\n return (\n <GlassCard className=\"flex flex-col gap-3 p-4 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-accent-primary to-accent-purple text-white shadow-sm\">\n <Video size={18} />\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\">\n {session.topic}\n </span>\n <StatusBadge status={session.status} />\n {session.rating ? (\n <span className=\"text-xs text-text-muted\">★ {session.rating}/5</span>\n ) : null}\n </div>\n {showMentor && session.mentor?.headline ? (\n <div className=\"mt-0.5 truncate text-xs text-text-secondary\">\n with {session.mentor.headline}\n </div>\n ) : null}\n <div className=\"mt-1 flex flex-wrap items-center gap-3 text-xs text-text-muted\">\n <span className=\"inline-flex items-center gap-1\">\n <CalendarClock size={13} /> {formatDateTime(session.scheduledAt)}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={13} /> {formatDuration(session.durationMinutes)}\n </span>\n </div>\n {session.agenda ? (\n <p className=\"mt-1 line-clamp-2 text-xs text-text-secondary\">{session.agenda}</p>\n ) : null}\n </div>\n </div>\n <div className=\"flex shrink-0 flex-wrap items-center gap-2\">\n {session.meetingUrl ? (\n <Button\n size=\"sm\"\n onClick={() => window.open(session.meetingUrl ?? '', '_blank', 'noopener,noreferrer')}\n >\n <Video size={15} /> Join\n </Button>\n ) : null}\n {isMentor && session.status === 'REQUESTED' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setMode(mode === 'confirm' ? 'none' : 'confirm')}\n >\n <Check size={15} /> Confirm\n </Button>\n ) : null}\n {isMentor && session.status === 'CONFIRMED' ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setMode(mode === 'complete' ? 'none' : 'complete')}\n >\n <CheckCircle2 size={15} /> Mark complete\n </Button>\n ) : null}\n {canCancel ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => onCancel(session.id)} disabled={busy}>\n <X size={15} /> Cancel\n </Button>\n ) : null}\n </div>\n </div>\n\n {mode === 'confirm' ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3 sm:flex-row sm:items-center\">\n <Input\n className=\"flex-1\"\n placeholder=\"Meeting link (e.g. https://meet.…)\"\n value={meetingUrl}\n onChange={(e) => setMeetingUrl(e.target.value)}\n />\n <Button size=\"sm\" onClick={submitConfirm} disabled={busy}>\n Confirm session\n </Button>\n </div>\n ) : null}\n {mode === 'complete' ? (\n <div className=\"flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-sunken p-3\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-xs text-text-secondary\">Rating (1–5)</label>\n <Input\n type=\"number\"\n min={1}\n max={5}\n className=\"w-20\"\n value={rating}\n onChange={(e) => setRating(e.target.value)}\n />\n </div>\n <Input\n placeholder=\"Feedback for the mentee (optional)\"\n value={feedback}\n onChange={(e) => setFeedback(e.target.value)}\n />\n <div>\n <Button size=\"sm\" onClick={submitComplete} disabled={busy}>\n Complete session\n </Button>\n </div>\n </div>\n ) : null}\n </GlassCard>\n );\n}\n\nfunction SessionsList({\n loading,\n error,\n sessions,\n showMentor,\n emptyTitle,\n emptyDescription,\n emptyAction,\n isMentor,\n onCancel,\n onConfirm,\n onComplete,\n busyId,\n}: {\n loading: boolean;\n error?: { message?: string };\n sessions: TecMentorSession[];\n showMentor: boolean;\n emptyTitle: string;\n emptyDescription: string;\n emptyAction?: React.ReactNode;\n isMentor: boolean;\n onCancel: (id: string) => void;\n onConfirm: (id: string, meetingUrl: string) => Promise<void>;\n onComplete: (id: string, rating: number, feedback: string) => Promise<void>;\n busyId: string | null;\n}) {\n if (loading && sessions.length === 0) return <LoadingRows count={3} height=\"h-24\" />;\n if (error) return <ErrorView title=\"Couldn't load sessions\" error={error} />;\n if (sessions.length === 0) {\n return (\n <EmptyView\n icon={<MessageSquare size={26} />}\n title={emptyTitle}\n description={emptyDescription}\n action={emptyAction}\n />\n );\n }\n const sorted = [...sessions].sort(\n (a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime()\n );\n return (\n <div className=\"space-y-3\">\n {sorted.map((session) => (\n <SessionRow\n key={session.id}\n session={session}\n showMentor={showMentor}\n isMentor={isMentor}\n onCancel={onCancel}\n onConfirm={onConfirm}\n onComplete={onComplete}\n busy={busyId === session.id}\n />\n ))}\n </div>\n );\n}\n\nexport function MentorshipSessionsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const [tab, setTab] = useState<Perspective>('mentee');\n const [cancellingId, setCancellingId] = useState<string | null>(null);\n\n const menteeId = currentUser?.id;\n\n // As mentee: sessions the current user booked.\n const menteeQ = useSessionsQuery(menteeId ? { menteeId } : {});\n\n // Resolve whether the current user is a mentor, to load their mentor sessions.\n const mentorsQ = useMentorsQuery({});\n const myMentor = mentorsQ.data?.tecListMentors.items.find((m) => m.userId === currentUser?.id);\n const mentorId = myMentor?.id;\n const mentorQ = useSessionsQuery(mentorId ? { mentorId } : {});\n\n const [cancelSession] = useCancelSession();\n const [confirmSession] = useConfirmSession();\n const [completeSession] = useCompleteSession();\n\n const menteeSessions = menteeId ? (menteeQ.data?.tecListSessions.items ?? []) : [];\n const mentorSessions = mentorId ? (mentorQ.data?.tecListSessions.items ?? []) : [];\n const allSessions = [...menteeSessions, ...mentorSessions];\n const upcomingCount = allSessions.filter(\n (s) => s.status === 'REQUESTED' || s.status === 'CONFIRMED'\n ).length;\n const completedCount = allSessions.filter((s) => s.status === 'COMPLETED').length;\n\n const handleCancel = async (id: string) => {\n setCancellingId(id);\n emit('technospam.session.cancel_clicked', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n try {\n const res = await cancelSession({ variables: { id } });\n if (res.data?.tecCancelSession) {\n emit('technospam.session.cancelled', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n notify.success('Session cancelled', 'The session has been cancelled.');\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n const handleConfirm = async (id: string, meetingUrl: string) => {\n setCancellingId(id);\n try {\n const res = await confirmSession({\n variables: { id, meetingUrl: meetingUrl || undefined },\n });\n if (res.data?.tecConfirmSession) {\n notify.success('Session confirmed', 'The mentee has been notified.');\n await mentorQ.refetch();\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n const handleComplete = async (id: string, rating: number, feedback: string) => {\n setCancellingId(id);\n emit('technospam.session.complete_clicked', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n try {\n const res = await completeSession({\n variables: { id, rating, feedback: feedback || undefined },\n });\n if (res.data?.tecCompleteSession) {\n emit('technospam.session.completed', {\n workspaceId,\n entityId: id,\n entityType: 'TEC_MENTOR_SESSION',\n });\n notify.success('Session completed', 'Nice work — the session is wrapped up.');\n await mentorQ.refetch();\n }\n } finally {\n setCancellingId(null);\n }\n };\n\n if (!currentUser?.id) {\n return (\n <PageLayout hero title=\"My Sessions\" description=\"Track your mentorship sessions.\">\n <EmptyView\n icon={<MessageSquare size={26} />}\n title=\"Sign in to view your sessions\"\n description=\"Your booked and hosted mentorship sessions will appear here once you're signed in.\"\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n hero\n title=\"My Sessions\"\n description=\"Manage the mentorship sessions you've booked and the ones you host.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/mentors-page')}>\n <Users size={16} /> Find a mentor\n </Button>\n }\n >\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label=\"As mentee\"\n value={menteeSessions.length}\n icon={MessageSquare}\n tone=\"blue\"\n />\n <StatCard\n label=\"As mentor\"\n value={mentorId ? mentorSessions.length : 0}\n icon={Users}\n tone=\"purple\"\n />\n <StatCard label=\"Upcoming\" value={upcomingCount} icon={CalendarClock} tone=\"teal\" />\n <StatCard label=\"Completed\" value={completedCount} icon={CheckCircle2} tone=\"green\" />\n </div>\n\n <Tabs value={tab} onValueChange={(v) => setTab(v as Perspective)} className=\"mb-4\">\n <TabsList>\n <TabsTrigger value=\"mentee\">As mentee</TabsTrigger>\n <TabsTrigger value=\"mentor\">As mentor</TabsTrigger>\n </TabsList>\n </Tabs>\n\n {tab === 'mentee' ? (\n <SessionsList\n loading={menteeQ.loading}\n error={menteeQ.error}\n sessions={menteeSessions}\n showMentor\n emptyTitle=\"No sessions booked yet\"\n emptyDescription=\"Find a mentor and request a session to get personalized guidance.\"\n emptyAction={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Find a mentor</Button>\n }\n isMentor={false}\n onCancel={handleCancel}\n onConfirm={handleConfirm}\n onComplete={handleComplete}\n busyId={cancellingId}\n />\n ) : mentorsQ.loading && !myMentor ? (\n <LoadingRows count={3} height=\"h-24\" />\n ) : !mentorId ? (\n <EmptyView\n icon={<Users size={26} />}\n title=\"You're not a mentor yet\"\n description=\"Create a mentor profile to start hosting sessions and helping others build.\"\n action={\n <Button onClick={() => navigate('/mentorship/mentors-page')}>Become a mentor</Button>\n }\n />\n ) : (\n <SessionsList\n loading={mentorQ.loading}\n error={mentorQ.error}\n sessions={mentorSessions}\n showMentor={false}\n emptyTitle=\"No sessions to host yet\"\n emptyDescription=\"When mentees request time with you, their sessions will show up here.\"\n isMentor\n onCancel={handleCancel}\n onConfirm={handleConfirm}\n onComplete={handleComplete}\n busyId={cancellingId}\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-technospam",
3
- "version": "2026.716.2",
3
+ "version": "2026.719.2",
4
4
  "description": "Burdenoff TechnoSpam Microfrontend",
5
5
  "type": "module",
6
6
  "files": [