@burdenoff/microfe-technospam 2026.719.2 → 2026.720.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.
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsAnalyticsPagePage.js","names":[],"sources":["../../../src/technospam/pages/AnalyticsAnalyticsPagePage.tsx"],"sourcesContent":["import { useMemo, type CSSProperties, type SVGProps } from 'react';\nimport {\n Activity,\n Award,\n BarChart3,\n BookOpen,\n Code2,\n GraduationCap,\n Library,\n Percent,\n TrendingUp,\n Trophy,\n Users,\n type LucideIcon,\n} from 'lucide-react';\nimport { GlassCard, Button } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n Legend,\n Pie,\n PieChart,\n ResponsiveContainer,\n Tooltip as ReTooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport {\n EmptyView,\n ErrorView,\n LoadingGrid,\n LoadingRows,\n PageLayout,\n StatCard,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCertificatesQuery,\n useCoursesQuery,\n useEnrollmentsQuery,\n useHackathonsQuery,\n useProblemsQuery,\n useSessionsQuery,\n useSubmissionsQuery,\n type TecEnrollmentStatus,\n type TecSubmissionVerdict,\n} from '../api/technospamApi';\nimport { humanizeEnum } from '../utils/format';\n\n/* ----------------------------------------------------------- chart config */\n\nconst ENROLL_STATUS_ORDER: TecEnrollmentStatus[] = [\n 'ENROLLED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DROPPED',\n];\n\nconst ENROLL_STATUS_COLOR: Record<TecEnrollmentStatus, string> = {\n ENROLLED: 'var(--color-accent-primary)',\n IN_PROGRESS: 'var(--color-accent-teal)',\n COMPLETED: 'var(--color-status-success)',\n DROPPED: 'var(--color-status-warning)',\n};\n\nconst VERDICT_ORDER: TecSubmissionVerdict[] = [\n 'ACCEPTED',\n 'WRONG_ANSWER',\n 'TIME_LIMIT_EXCEEDED',\n 'RUNTIME_ERROR',\n 'COMPILE_ERROR',\n 'PENDING',\n];\n\nconst VERDICT_LABEL: Record<TecSubmissionVerdict, string> = {\n ACCEPTED: 'Accepted',\n WRONG_ANSWER: 'Wrong',\n TIME_LIMIT_EXCEEDED: 'TLE',\n RUNTIME_ERROR: 'Runtime',\n COMPILE_ERROR: 'Compile',\n PENDING: 'Pending',\n};\n\nconst VERDICT_COLOR: Record<TecSubmissionVerdict, string> = {\n ACCEPTED: 'var(--color-status-success)',\n WRONG_ANSWER: 'var(--color-status-error)',\n TIME_LIMIT_EXCEEDED: 'var(--color-status-warning)',\n RUNTIME_ERROR: 'var(--color-status-error)',\n COMPILE_ERROR: 'var(--color-status-error)',\n PENDING: 'var(--color-text-muted)',\n};\n\nconst TOOLTIP_STYLE: CSSProperties = {\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 12,\n color: 'var(--color-text-primary)',\n fontSize: 12,\n};\nconst TOOLTIP_LABEL_STYLE: CSSProperties = { color: 'var(--color-text-secondary)' };\nconst AXIS_TICK: SVGProps<SVGTextElement> = { fill: 'var(--color-text-muted)', fontSize: 12 };\n\ninterface StatusDatum {\n name: string;\n value: number;\n color: string;\n}\ninterface VerdictDatum {\n label: string;\n count: number;\n color: string;\n}\ninterface ActivityDatum {\n label: string;\n submissions: number;\n enrollments: number;\n}\n\n/** Normalize an ISO timestamp to the start of its (Sunday-based) week. */\nfunction weekBucket(iso: string): { key: number; label: string } {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return { key: 0, label: '—' };\n const start = new Date(d.getFullYear(), d.getMonth(), d.getDate() - d.getDay());\n return {\n key: start.getTime(),\n label: start.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),\n };\n}\n\n/* -------------------------------------------------------- chart wrappers */\n\ntype ChipTone = 'blue' | 'teal' | 'purple' | 'indigo';\n\nconst CHIP: Record<ChipTone, string> = {\n blue: 'bg-accent-primary/15 text-accent-primary ring-accent-primary/20',\n teal: 'bg-accent-teal/15 text-accent-teal ring-accent-teal/20',\n purple: 'bg-accent-purple/15 text-accent-purple ring-accent-purple/20',\n indigo: 'bg-accent-indigo/15 text-accent-indigo ring-accent-indigo/20',\n};\n\nfunction ChartHeader({\n icon: Icon,\n title,\n subtitle,\n tone,\n}: {\n icon: LucideIcon;\n title: string;\n subtitle?: string;\n tone: ChipTone;\n}) {\n return (\n <div className=\"mb-4 flex items-center gap-3\">\n <span\n className={cn(\n 'flex h-9 w-9 shrink-0 items-center justify-center rounded-xl ring-1',\n CHIP[tone]\n )}\n >\n <Icon size={17} />\n </span>\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{title}</h3>\n {subtitle ? <p className=\"truncate text-xs text-text-muted\">{subtitle}</p> : null}\n </div>\n </div>\n );\n}\n\nfunction ChartCard({\n title,\n subtitle,\n icon,\n tone = 'teal',\n isEmpty,\n emptyLabel,\n children,\n}: {\n title: string;\n subtitle?: string;\n icon: LucideIcon;\n tone?: ChipTone;\n isEmpty: boolean;\n emptyLabel: string;\n children: React.ReactElement;\n}) {\n return (\n <GlassCard className=\"p-5 transition-shadow duration-200 hover:shadow-lg\">\n <ChartHeader icon={icon} title={title} subtitle={subtitle} tone={tone} />\n {isEmpty ? (\n <div className=\"flex h-[240px] items-center justify-center text-center text-sm text-text-muted\">\n {emptyLabel}\n </div>\n ) : (\n <ResponsiveContainer width=\"100%\" height={260}>\n {children}\n </ResponsiveContainer>\n )}\n </GlassCard>\n );\n}\n\n/* --------------------------------------------------------------- page */\n\nexport function AnalyticsAnalyticsPagePage() {\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 problemsQ = useProblemsQuery({ status: 'PUBLISHED' });\n const hackathonsQ = useHackathonsQuery({});\n\n const enrollments = useMemo(\n () => enrollmentsQ.data?.tecListEnrollments.items ?? [],\n [enrollmentsQ.data]\n );\n const submissions = useMemo(\n () => submissionsQ.data?.tecListSubmissions.items ?? [],\n [submissionsQ.data]\n );\n const sessions = sessionsQ.data?.tecListSessions.items ?? [];\n const certificates = certificatesQ.data?.tecListCertificates ?? [];\n const coursesTotal = coursesQ.data?.tecListCourses.items.length ?? 0;\n const problemsTotal = problemsQ.data?.tecListProblems.items.length ?? 0;\n const hackathonsTotal = hackathonsQ.data?.tecListHackathons.items.length ?? 0;\n\n const metrics = useMemo(() => {\n const coursesCompleted = enrollments.filter((e) => e.status === 'COMPLETED').length;\n const avgProgress = enrollments.length\n ? Math.round(enrollments.reduce((s, e) => s + e.progressPct, 0) / enrollments.length)\n : 0;\n const acceptedSubs = submissions.filter((s) => s.verdict === 'ACCEPTED');\n const problemsSolved = new Set(acceptedSubs.map((s) => s.problemId)).size;\n const acceptanceRate = submissions.length\n ? Math.round((acceptedSubs.length / submissions.length) * 100)\n : 0;\n return { coursesCompleted, avgProgress, problemsSolved, acceptanceRate };\n }, [enrollments, submissions]);\n\n const enrollmentsByStatus = useMemo<StatusDatum[]>(\n () =>\n ENROLL_STATUS_ORDER.map((s) => ({\n name: humanizeEnum(s),\n value: enrollments.filter((e) => e.status === s).length,\n color: ENROLL_STATUS_COLOR[s],\n })).filter((d) => d.value > 0),\n [enrollments]\n );\n\n const submissionsByVerdict = useMemo<VerdictDatum[]>(\n () =>\n VERDICT_ORDER.map((v) => ({\n label: VERDICT_LABEL[v],\n count: submissions.filter((s) => s.verdict === v).length,\n color: VERDICT_COLOR[v],\n })).filter((d) => d.count > 0),\n [submissions]\n );\n\n const activityData = useMemo<ActivityDatum[]>(() => {\n const buckets = new Map<number, ActivityDatum>();\n const add = (iso: string, key: 'submissions' | 'enrollments') => {\n const { key: bucketKey, label } = weekBucket(iso);\n const existing = buckets.get(bucketKey) ?? { label, submissions: 0, enrollments: 0 };\n existing[key] += 1;\n buckets.set(bucketKey, existing);\n };\n submissions.forEach((s) => add(s.createdAt, 'submissions'));\n enrollments.forEach((e) => add(e.createdAt, 'enrollments'));\n return [...buckets.entries()]\n .sort((a, b) => a[0] - b[0])\n .slice(-8)\n .map(([, v]) => v);\n }, [submissions, enrollments]);\n\n const hasActivity =\n enrollments.length > 0 ||\n submissions.length > 0 ||\n sessions.length > 0 ||\n certificates.length > 0;\n\n const learnerLoading =\n enrollmentsQ.loading || submissionsQ.loading || sessionsQ.loading || certificatesQ.loading;\n const learnerError =\n enrollmentsQ.error || submissionsQ.error || sessionsQ.error || certificatesQ.error;\n const showLoading = learnerLoading && !hasActivity;\n\n const workspaceOverview = (\n <div>\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">Workspace overview</h2>\n <p className=\"mb-4 max-w-2xl text-sm text-text-secondary\">\n Live content available across the TechnoSpam learning workspace right now.\n </p>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatCard label=\"Published courses\" value={coursesTotal} icon={Library} tone=\"blue\" />\n <StatCard label=\"Published problems\" value={problemsTotal} icon={Code2} tone=\"indigo\" />\n <StatCard label=\"Hackathons\" value={hackathonsTotal} icon={Trophy} tone=\"purple\" />\n </div>\n </div>\n );\n\n return (\n <PageLayout\n hero\n title=\"Analytics\"\n description=\"Your real learning performance across courses, problems, mentoring and certificates.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/courses/my-learning-page')}>\n <GraduationCap size={16} /> My Learning\n </Button>\n }\n >\n {!learnerId ? (\n <div className=\"space-y-8\">\n <EmptyView\n icon={<BarChart3 size={26} />}\n title=\"Sign in to view your analytics\"\n description=\"Your personal learning metrics appear here once you're signed in.\"\n />\n {workspaceOverview}\n </div>\n ) : showLoading ? (\n <div className=\"space-y-6\">\n <LoadingGrid count={4} height=\"h-24\" />\n <LoadingRows count={2} height=\"h-72\" />\n </div>\n ) : learnerError && !hasActivity ? (\n <ErrorView title=\"Couldn't load your analytics\" error={learnerError} />\n ) : (\n <div className=\"space-y-8\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 xl:grid-cols-4\">\n <StatCard\n label=\"Courses enrolled\"\n value={enrollments.length}\n icon={BookOpen}\n tone=\"blue\"\n />\n <StatCard\n label=\"Courses completed\"\n value={metrics.coursesCompleted}\n icon={GraduationCap}\n tone=\"green\"\n />\n <StatCard\n label=\"Avg progress\"\n value={`${metrics.avgProgress}%`}\n icon={TrendingUp}\n tone=\"purple\"\n />\n <StatCard\n label=\"Problems solved\"\n value={metrics.problemsSolved}\n icon={Code2}\n tone=\"indigo\"\n />\n <StatCard\n label=\"Acceptance rate\"\n value={`${metrics.acceptanceRate}%`}\n icon={Percent}\n tone=\"teal\"\n />\n <StatCard label=\"Mentor sessions\" value={sessions.length} icon={Users} tone=\"blue\" />\n <StatCard label=\"Certificates\" value={certificates.length} icon={Award} tone=\"amber\" />\n </div>\n\n {!hasActivity ? (\n <EmptyView\n icon={<Activity size={26} />}\n title=\"No learning activity yet\"\n description=\"Enroll in a course or solve a problem and your progress charts will build here. TechnoSpam is pre-launch — start learning to see your data.\"\n action={\n <Button onClick={() => navigate('/courses/courses-page')}>Browse courses</Button>\n }\n />\n ) : (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <ChartCard\n title=\"Enrollments by status\"\n subtitle=\"How your courses are progressing\"\n icon={BookOpen}\n tone=\"blue\"\n isEmpty={enrollmentsByStatus.length === 0}\n emptyLabel=\"No enrollments yet\"\n >\n <PieChart>\n <Pie\n data={enrollmentsByStatus}\n dataKey=\"value\"\n nameKey=\"name\"\n innerRadius={60}\n outerRadius={92}\n paddingAngle={2}\n stroke=\"var(--color-bg-surface)\"\n strokeWidth={2}\n >\n {enrollmentsByStatus.map((d) => (\n <Cell key={d.name} fill={d.color} />\n ))}\n </Pie>\n <ReTooltip contentStyle={TOOLTIP_STYLE} labelStyle={TOOLTIP_LABEL_STYLE} />\n <Legend iconType=\"circle\" wrapperStyle={{ fontSize: 12 }} />\n </PieChart>\n </ChartCard>\n\n <ChartCard\n title=\"Submissions by verdict\"\n subtitle=\"Outcomes across your attempts\"\n icon={Code2}\n tone=\"purple\"\n isEmpty={submissionsByVerdict.length === 0}\n emptyLabel=\"No submissions yet\"\n >\n <BarChart\n data={submissionsByVerdict}\n margin={{ top: 8, right: 8, left: -18, bottom: 0 }}\n >\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-border-seam)\"\n vertical={false}\n />\n <XAxis\n dataKey=\"label\"\n tick={AXIS_TICK}\n axisLine={{ stroke: 'var(--color-border-seam)' }}\n tickLine={false}\n />\n <YAxis\n allowDecimals={false}\n tick={AXIS_TICK}\n axisLine={false}\n tickLine={false}\n />\n <ReTooltip\n contentStyle={TOOLTIP_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n cursor={{ fill: 'var(--color-accent-primary)', fillOpacity: 0.08 }}\n />\n <Bar dataKey=\"count\" name=\"Submissions\" radius={[6, 6, 0, 0]} maxBarSize={56}>\n {submissionsByVerdict.map((d) => (\n <Cell key={d.label} fill={d.color} />\n ))}\n </Bar>\n </BarChart>\n </ChartCard>\n </div>\n\n <GlassCard className=\"p-5 transition-shadow duration-200 hover:shadow-lg\">\n <ChartHeader\n icon={Activity}\n title=\"Learning activity over time\"\n subtitle=\"Submissions and enrollments per week\"\n tone=\"teal\"\n />\n {activityData.length === 0 ? (\n <div className=\"flex h-[240px] items-center justify-center text-sm text-text-muted\">\n No dated activity yet\n </div>\n ) : (\n <ResponsiveContainer width=\"100%\" height={280}>\n <AreaChart\n data={activityData}\n margin={{ top: 8, right: 12, left: -18, bottom: 0 }}\n >\n <defs>\n <linearGradient id=\"tec-grad-submissions\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop\n offset=\"0%\"\n stopColor=\"var(--color-accent-primary)\"\n stopOpacity={0.35}\n />\n <stop\n offset=\"100%\"\n stopColor=\"var(--color-accent-primary)\"\n stopOpacity={0}\n />\n </linearGradient>\n <linearGradient id=\"tec-grad-enrollments\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop\n offset=\"0%\"\n stopColor=\"var(--color-accent-teal)\"\n stopOpacity={0.35}\n />\n <stop\n offset=\"100%\"\n stopColor=\"var(--color-accent-teal)\"\n stopOpacity={0}\n />\n </linearGradient>\n </defs>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-border-seam)\"\n vertical={false}\n />\n <XAxis\n dataKey=\"label\"\n tick={AXIS_TICK}\n axisLine={{ stroke: 'var(--color-border-seam)' }}\n tickLine={false}\n />\n <YAxis\n allowDecimals={false}\n tick={AXIS_TICK}\n axisLine={false}\n tickLine={false}\n />\n <ReTooltip contentStyle={TOOLTIP_STYLE} labelStyle={TOOLTIP_LABEL_STYLE} />\n <Legend iconType=\"circle\" wrapperStyle={{ fontSize: 12 }} />\n <Area\n type=\"monotone\"\n dataKey=\"submissions\"\n name=\"Submissions\"\n stroke=\"var(--color-accent-primary)\"\n strokeWidth={2}\n fill=\"url(#tec-grad-submissions)\"\n />\n <Area\n type=\"monotone\"\n dataKey=\"enrollments\"\n name=\"Enrollments\"\n stroke=\"var(--color-accent-teal)\"\n strokeWidth={2}\n fill=\"url(#tec-grad-enrollments)\"\n />\n </AreaChart>\n </ResponsiveContainer>\n )}\n </GlassCard>\n </div>\n )}\n\n {workspaceOverview}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AnalyticsAnalyticsPagePage.js","names":[],"sources":["../../../src/technospam/pages/AnalyticsAnalyticsPagePage.tsx"],"sourcesContent":["import { useMemo, useState, type CSSProperties, type SVGProps } from 'react';\nimport {\n Activity,\n Award,\n BarChart3,\n BookOpen,\n CalendarRange,\n Code2,\n GraduationCap,\n Library,\n Percent,\n TrendingUp,\n Trophy,\n Users,\n X,\n type LucideIcon,\n} from 'lucide-react';\nimport { GlassCard, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n Legend,\n Pie,\n PieChart,\n ResponsiveContainer,\n Tooltip as ReTooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport {\n EmptyView,\n ErrorView,\n LoadingGrid,\n LoadingRows,\n PageLayout,\n StatCard,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n useCertificatesQuery,\n useCoursesQuery,\n useEnrollmentsQuery,\n useHackathonsQuery,\n useProblemsQuery,\n useSessionsQuery,\n useSubmissionsQuery,\n type TecEnrollmentStatus,\n type TecSubmissionVerdict,\n} from '../api/technospamApi';\nimport { humanizeEnum } from '../utils/format';\n\n/* ----------------------------------------------------------- chart config */\n\nconst ENROLL_STATUS_ORDER: TecEnrollmentStatus[] = [\n 'ENROLLED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DROPPED',\n];\n\nconst ENROLL_STATUS_COLOR: Record<TecEnrollmentStatus, string> = {\n ENROLLED: 'var(--color-accent-primary)',\n IN_PROGRESS: 'var(--color-accent-teal)',\n COMPLETED: 'var(--color-status-success)',\n DROPPED: 'var(--color-status-warning)',\n};\n\nconst VERDICT_ORDER: TecSubmissionVerdict[] = [\n 'ACCEPTED',\n 'WRONG_ANSWER',\n 'TIME_LIMIT_EXCEEDED',\n 'RUNTIME_ERROR',\n 'COMPILE_ERROR',\n 'PENDING',\n];\n\nconst VERDICT_LABEL: Record<TecSubmissionVerdict, string> = {\n ACCEPTED: 'Accepted',\n WRONG_ANSWER: 'Wrong',\n TIME_LIMIT_EXCEEDED: 'TLE',\n RUNTIME_ERROR: 'Runtime',\n COMPILE_ERROR: 'Compile',\n PENDING: 'Pending',\n};\n\nconst VERDICT_COLOR: Record<TecSubmissionVerdict, string> = {\n ACCEPTED: 'var(--color-status-success)',\n WRONG_ANSWER: 'var(--color-status-error)',\n TIME_LIMIT_EXCEEDED: 'var(--color-status-warning)',\n RUNTIME_ERROR: 'var(--color-status-error)',\n COMPILE_ERROR: 'var(--color-status-error)',\n PENDING: 'var(--color-text-muted)',\n};\n\nconst TOOLTIP_STYLE: CSSProperties = {\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 12,\n color: 'var(--color-text-primary)',\n fontSize: 12,\n};\nconst TOOLTIP_LABEL_STYLE: CSSProperties = { color: 'var(--color-text-secondary)' };\nconst AXIS_TICK: SVGProps<SVGTextElement> = { fill: 'var(--color-text-muted)', fontSize: 12 };\n\ninterface StatusDatum {\n name: string;\n value: number;\n color: string;\n}\ninterface VerdictDatum {\n label: string;\n count: number;\n color: string;\n}\ninterface ActivityDatum {\n label: string;\n submissions: number;\n enrollments: number;\n}\n\n/** Normalize an ISO timestamp to the start of its (Sunday-based) week. */\nfunction weekBucket(iso: string): { key: number; label: string } {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return { key: 0, label: '—' };\n const start = new Date(d.getFullYear(), d.getMonth(), d.getDate() - d.getDay());\n return {\n key: start.getTime(),\n label: start.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),\n };\n}\n\n/* -------------------------------------------------------- chart wrappers */\n\ntype ChipTone = 'blue' | 'teal' | 'purple' | 'indigo';\n\nconst CHIP: Record<ChipTone, string> = {\n blue: 'bg-accent-primary/15 text-accent-primary ring-accent-primary/20',\n teal: 'bg-accent-teal/15 text-accent-teal ring-accent-teal/20',\n purple: 'bg-accent-purple/15 text-accent-purple ring-accent-purple/20',\n indigo: 'bg-accent-indigo/15 text-accent-indigo ring-accent-indigo/20',\n};\n\nfunction ChartHeader({\n icon: Icon,\n title,\n subtitle,\n tone,\n}: {\n icon: LucideIcon;\n title: string;\n subtitle?: string;\n tone: ChipTone;\n}) {\n return (\n <div className=\"mb-4 flex items-center gap-3\">\n <span\n className={cn(\n 'flex h-9 w-9 shrink-0 items-center justify-center rounded-xl ring-1',\n CHIP[tone]\n )}\n >\n <Icon size={17} />\n </span>\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{title}</h3>\n {subtitle ? <p className=\"truncate text-xs text-text-muted\">{subtitle}</p> : null}\n </div>\n </div>\n );\n}\n\nfunction ChartCard({\n title,\n subtitle,\n icon,\n tone = 'teal',\n isEmpty,\n emptyLabel,\n children,\n}: {\n title: string;\n subtitle?: string;\n icon: LucideIcon;\n tone?: ChipTone;\n isEmpty: boolean;\n emptyLabel: string;\n children: React.ReactElement;\n}) {\n return (\n <GlassCard className=\"p-5 transition-shadow duration-200 hover:shadow-lg\">\n <ChartHeader icon={icon} title={title} subtitle={subtitle} tone={tone} />\n {isEmpty ? (\n <div className=\"flex h-[240px] items-center justify-center text-center text-sm text-text-muted\">\n {emptyLabel}\n </div>\n ) : (\n <ResponsiveContainer width=\"100%\" height={260}>\n {children}\n </ResponsiveContainer>\n )}\n </GlassCard>\n );\n}\n\n/* ---------------------------------------------------------- date range */\n\n/** Convert a native `<input type=\"date\">` value (YYYY-MM-DD) into inclusive\n * ISO bounds so the server-side createdAt filter covers the whole day. */\nfunction dayStartIso(date: string): string | undefined {\n return date ? `${date}T00:00:00.000Z` : undefined;\n}\nfunction dayEndIso(date: string): string | undefined {\n return date ? `${date}T23:59:59.999Z` : undefined;\n}\n\nfunction DateRangeControls({\n start,\n end,\n onStart,\n onEnd,\n onPreset,\n onClear,\n}: {\n start: string;\n end: string;\n onStart: (v: string) => void;\n onEnd: (v: string) => void;\n onPreset: (days: number) => void;\n onClear: () => void;\n}) {\n const active = Boolean(start || end);\n return (\n <GlassCard className=\"mb-6 flex flex-col gap-3 p-4 lg:flex-row lg:items-end lg:justify-between\">\n <div className=\"flex flex-wrap items-end gap-3\">\n <div className=\"flex items-center gap-2 self-center text-sm font-medium text-text-secondary\">\n <CalendarRange size={16} className=\"text-accent-teal\" />\n Date range\n </div>\n <div>\n <label\n className=\"mb-1 block text-xs font-medium text-text-muted\"\n htmlFor=\"tec-range-from\"\n >\n From\n </label>\n <Input\n id=\"tec-range-from\"\n type=\"date\"\n value={start}\n max={end || undefined}\n onChange={(e) => onStart(e.target.value)}\n className=\"w-40\"\n />\n </div>\n <div>\n <label className=\"mb-1 block text-xs font-medium text-text-muted\" htmlFor=\"tec-range-to\">\n To\n </label>\n <Input\n id=\"tec-range-to\"\n type=\"date\"\n value={end}\n min={start || undefined}\n onChange={(e) => onEnd(e.target.value)}\n className=\"w-40\"\n />\n </div>\n {active ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={onClear}>\n <X size={14} /> Clear\n </Button>\n ) : null}\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => onPreset(7)}>\n Last 7 days\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => onPreset(30)}>\n Last 30 days\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => onPreset(90)}>\n Last 90 days\n </Button>\n </div>\n </GlassCard>\n );\n}\n\n/* --------------------------------------------------------------- page */\n\nexport function AnalyticsAnalyticsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser } = useTechnoSpam();\n const learnerId = currentUser?.id;\n\n const [rangeStart, setRangeStart] = useState('');\n const [rangeEnd, setRangeEnd] = useState('');\n const startDate = dayStartIso(rangeStart);\n const endDate = dayEndIso(rangeEnd);\n\n const applyPreset = (days: number) => {\n const now = new Date();\n const from = new Date();\n from.setDate(from.getDate() - days);\n setRangeStart(from.toISOString().slice(0, 10));\n setRangeEnd(now.toISOString().slice(0, 10));\n };\n const clearRange = () => {\n setRangeStart('');\n setRangeEnd('');\n };\n\n const dateVars = startDate || endDate ? { startDate, endDate } : {};\n const enrollmentsQ = useEnrollmentsQuery(learnerId ? { learnerId, ...dateVars } : {});\n const submissionsQ = useSubmissionsQuery(learnerId ? { learnerId, ...dateVars } : {});\n const sessionsQ = useSessionsQuery(learnerId ? { menteeId: learnerId } : {});\n const certificatesQ = useCertificatesQuery(learnerId ? { learnerId } : {});\n const coursesQ = useCoursesQuery({ status: 'PUBLISHED' });\n const problemsQ = useProblemsQuery({ status: 'PUBLISHED' });\n const hackathonsQ = useHackathonsQuery({});\n\n const enrollments = useMemo(\n () => enrollmentsQ.data?.tecListEnrollments.items ?? [],\n [enrollmentsQ.data]\n );\n const submissions = useMemo(\n () => submissionsQ.data?.tecListSubmissions.items ?? [],\n [submissionsQ.data]\n );\n const sessions = sessionsQ.data?.tecListSessions.items ?? [];\n const certificates = certificatesQ.data?.tecListCertificates ?? [];\n const coursesTotal = coursesQ.data?.tecListCourses.items.length ?? 0;\n const problemsTotal = problemsQ.data?.tecListProblems.items.length ?? 0;\n const hackathonsTotal = hackathonsQ.data?.tecListHackathons.items.length ?? 0;\n\n const metrics = useMemo(() => {\n const coursesCompleted = enrollments.filter((e) => e.status === 'COMPLETED').length;\n const avgProgress = enrollments.length\n ? Math.round(enrollments.reduce((s, e) => s + e.progressPct, 0) / enrollments.length)\n : 0;\n const acceptedSubs = submissions.filter((s) => s.verdict === 'ACCEPTED');\n const problemsSolved = new Set(acceptedSubs.map((s) => s.problemId)).size;\n const acceptanceRate = submissions.length\n ? Math.round((acceptedSubs.length / submissions.length) * 100)\n : 0;\n return { coursesCompleted, avgProgress, problemsSolved, acceptanceRate };\n }, [enrollments, submissions]);\n\n const enrollmentsByStatus = useMemo<StatusDatum[]>(\n () =>\n ENROLL_STATUS_ORDER.map((s) => ({\n name: humanizeEnum(s),\n value: enrollments.filter((e) => e.status === s).length,\n color: ENROLL_STATUS_COLOR[s],\n })).filter((d) => d.value > 0),\n [enrollments]\n );\n\n const submissionsByVerdict = useMemo<VerdictDatum[]>(\n () =>\n VERDICT_ORDER.map((v) => ({\n label: VERDICT_LABEL[v],\n count: submissions.filter((s) => s.verdict === v).length,\n color: VERDICT_COLOR[v],\n })).filter((d) => d.count > 0),\n [submissions]\n );\n\n const activityData = useMemo<ActivityDatum[]>(() => {\n const buckets = new Map<number, ActivityDatum>();\n const add = (iso: string, key: 'submissions' | 'enrollments') => {\n const { key: bucketKey, label } = weekBucket(iso);\n const existing = buckets.get(bucketKey) ?? { label, submissions: 0, enrollments: 0 };\n existing[key] += 1;\n buckets.set(bucketKey, existing);\n };\n submissions.forEach((s) => add(s.createdAt, 'submissions'));\n enrollments.forEach((e) => add(e.createdAt, 'enrollments'));\n return [...buckets.entries()]\n .sort((a, b) => a[0] - b[0])\n .slice(-8)\n .map(([, v]) => v);\n }, [submissions, enrollments]);\n\n const hasActivity =\n enrollments.length > 0 ||\n submissions.length > 0 ||\n sessions.length > 0 ||\n certificates.length > 0;\n\n const learnerLoading =\n enrollmentsQ.loading || submissionsQ.loading || sessionsQ.loading || certificatesQ.loading;\n const learnerError =\n enrollmentsQ.error || submissionsQ.error || sessionsQ.error || certificatesQ.error;\n const showLoading = learnerLoading && !hasActivity;\n\n const workspaceOverview = (\n <div>\n <h2 className=\"mb-3 text-base font-semibold text-text-primary\">Workspace overview</h2>\n <p className=\"mb-4 max-w-2xl text-sm text-text-secondary\">\n Live content available across the TechnoSpam learning workspace right now.\n </p>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatCard label=\"Published courses\" value={coursesTotal} icon={Library} tone=\"blue\" />\n <StatCard label=\"Published problems\" value={problemsTotal} icon={Code2} tone=\"indigo\" />\n <StatCard label=\"Hackathons\" value={hackathonsTotal} icon={Trophy} tone=\"purple\" />\n </div>\n </div>\n );\n\n return (\n <PageLayout\n hero\n title=\"Analytics\"\n description=\"Your real learning performance across courses, problems, mentoring and certificates.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/courses/my-learning-page')}>\n <GraduationCap size={16} /> My Learning\n </Button>\n }\n >\n {!learnerId ? (\n <div className=\"space-y-8\">\n <EmptyView\n icon={<BarChart3 size={26} />}\n title=\"Sign in to view your analytics\"\n description=\"Your personal learning metrics appear here once you're signed in.\"\n />\n {workspaceOverview}\n </div>\n ) : showLoading ? (\n <div className=\"space-y-6\">\n <LoadingGrid count={4} height=\"h-24\" />\n <LoadingRows count={2} height=\"h-72\" />\n </div>\n ) : learnerError && !hasActivity ? (\n <ErrorView title=\"Couldn't load your analytics\" error={learnerError} />\n ) : (\n <div className=\"space-y-8\">\n <DateRangeControls\n start={rangeStart}\n end={rangeEnd}\n onStart={setRangeStart}\n onEnd={setRangeEnd}\n onPreset={applyPreset}\n onClear={clearRange}\n />\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 xl:grid-cols-4\">\n <StatCard\n label=\"Courses enrolled\"\n value={enrollments.length}\n icon={BookOpen}\n tone=\"blue\"\n />\n <StatCard\n label=\"Courses completed\"\n value={metrics.coursesCompleted}\n icon={GraduationCap}\n tone=\"green\"\n />\n <StatCard\n label=\"Avg progress\"\n value={`${metrics.avgProgress}%`}\n icon={TrendingUp}\n tone=\"purple\"\n />\n <StatCard\n label=\"Problems solved\"\n value={metrics.problemsSolved}\n icon={Code2}\n tone=\"indigo\"\n />\n <StatCard\n label=\"Acceptance rate\"\n value={`${metrics.acceptanceRate}%`}\n icon={Percent}\n tone=\"teal\"\n />\n <StatCard label=\"Mentor sessions\" value={sessions.length} icon={Users} tone=\"blue\" />\n <StatCard label=\"Certificates\" value={certificates.length} icon={Award} tone=\"amber\" />\n </div>\n\n {!hasActivity ? (\n <EmptyView\n icon={<Activity size={26} />}\n title=\"No learning activity yet\"\n description=\"Enroll in a course or solve a problem and your progress charts will build here. TechnoSpam is pre-launch — start learning to see your data.\"\n action={\n <Button onClick={() => navigate('/courses/courses-page')}>Browse courses</Button>\n }\n />\n ) : (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <ChartCard\n title=\"Enrollments by status\"\n subtitle=\"How your courses are progressing\"\n icon={BookOpen}\n tone=\"blue\"\n isEmpty={enrollmentsByStatus.length === 0}\n emptyLabel=\"No enrollments yet\"\n >\n <PieChart>\n <Pie\n data={enrollmentsByStatus}\n dataKey=\"value\"\n nameKey=\"name\"\n innerRadius={60}\n outerRadius={92}\n paddingAngle={2}\n stroke=\"var(--color-bg-surface)\"\n strokeWidth={2}\n >\n {enrollmentsByStatus.map((d) => (\n <Cell key={d.name} fill={d.color} />\n ))}\n </Pie>\n <ReTooltip contentStyle={TOOLTIP_STYLE} labelStyle={TOOLTIP_LABEL_STYLE} />\n <Legend iconType=\"circle\" wrapperStyle={{ fontSize: 12 }} />\n </PieChart>\n </ChartCard>\n\n <ChartCard\n title=\"Submissions by verdict\"\n subtitle=\"Outcomes across your attempts\"\n icon={Code2}\n tone=\"purple\"\n isEmpty={submissionsByVerdict.length === 0}\n emptyLabel=\"No submissions yet\"\n >\n <BarChart\n data={submissionsByVerdict}\n margin={{ top: 8, right: 8, left: -18, bottom: 0 }}\n >\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-border-seam)\"\n vertical={false}\n />\n <XAxis\n dataKey=\"label\"\n tick={AXIS_TICK}\n axisLine={{ stroke: 'var(--color-border-seam)' }}\n tickLine={false}\n />\n <YAxis\n allowDecimals={false}\n tick={AXIS_TICK}\n axisLine={false}\n tickLine={false}\n />\n <ReTooltip\n contentStyle={TOOLTIP_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n cursor={{ fill: 'var(--color-accent-primary)', fillOpacity: 0.08 }}\n />\n <Bar dataKey=\"count\" name=\"Submissions\" radius={[6, 6, 0, 0]} maxBarSize={56}>\n {submissionsByVerdict.map((d) => (\n <Cell key={d.label} fill={d.color} />\n ))}\n </Bar>\n </BarChart>\n </ChartCard>\n </div>\n\n <GlassCard className=\"p-5 transition-shadow duration-200 hover:shadow-lg\">\n <ChartHeader\n icon={Activity}\n title=\"Learning activity over time\"\n subtitle=\"Submissions and enrollments per week\"\n tone=\"teal\"\n />\n {activityData.length === 0 ? (\n <div className=\"flex h-[240px] items-center justify-center text-sm text-text-muted\">\n No dated activity yet\n </div>\n ) : (\n <ResponsiveContainer width=\"100%\" height={280}>\n <AreaChart\n data={activityData}\n margin={{ top: 8, right: 12, left: -18, bottom: 0 }}\n >\n <defs>\n <linearGradient id=\"tec-grad-submissions\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop\n offset=\"0%\"\n stopColor=\"var(--color-accent-primary)\"\n stopOpacity={0.35}\n />\n <stop\n offset=\"100%\"\n stopColor=\"var(--color-accent-primary)\"\n stopOpacity={0}\n />\n </linearGradient>\n <linearGradient id=\"tec-grad-enrollments\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop\n offset=\"0%\"\n stopColor=\"var(--color-accent-teal)\"\n stopOpacity={0.35}\n />\n <stop\n offset=\"100%\"\n stopColor=\"var(--color-accent-teal)\"\n stopOpacity={0}\n />\n </linearGradient>\n </defs>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-border-seam)\"\n vertical={false}\n />\n <XAxis\n dataKey=\"label\"\n tick={AXIS_TICK}\n axisLine={{ stroke: 'var(--color-border-seam)' }}\n tickLine={false}\n />\n <YAxis\n allowDecimals={false}\n tick={AXIS_TICK}\n axisLine={false}\n tickLine={false}\n />\n <ReTooltip contentStyle={TOOLTIP_STYLE} labelStyle={TOOLTIP_LABEL_STYLE} />\n <Legend iconType=\"circle\" wrapperStyle={{ fontSize: 12 }} />\n <Area\n type=\"monotone\"\n dataKey=\"submissions\"\n name=\"Submissions\"\n stroke=\"var(--color-accent-primary)\"\n strokeWidth={2}\n fill=\"url(#tec-grad-submissions)\"\n />\n <Area\n type=\"monotone\"\n dataKey=\"enrollments\"\n name=\"Enrollments\"\n stroke=\"var(--color-accent-teal)\"\n strokeWidth={2}\n fill=\"url(#tec-grad-enrollments)\"\n />\n </AreaChart>\n </ResponsiveContainer>\n )}\n </GlassCard>\n </div>\n )}\n\n {workspaceOverview}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MentorshipMentorProfilePagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/MentorshipMentorProfilePagePage.tsx"],"names":[],"mappings":"AAmLA,wBAAgB,+BAA+B,gCAkK9C"}
1
+ {"version":3,"file":"MentorshipMentorProfilePagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/MentorshipMentorProfilePagePage.tsx"],"names":[],"mappings":"AAmLA,wBAAgB,+BAA+B,gCAqK9C"}
@@ -199,17 +199,24 @@ function F() {
199
199
  }), O.isAcceptingMentees ? /* @__PURE__ */ T("span", { className: "absolute bottom-1 right-1 h-4 w-4 rounded-full border-2 border-bg-surface bg-status-success-text" }) : null]
200
200
  }), /* @__PURE__ */ E("div", {
201
201
  className: "min-w-0 flex-1 sm:pb-1",
202
- children: [/* @__PURE__ */ T("h1", {
203
- className: "text-xl font-semibold text-text-primary sm:text-2xl",
204
- children: O.headline
205
- }), /* @__PURE__ */ E("div", {
206
- className: "mt-2 flex flex-wrap items-center gap-2",
207
- children: [/* @__PURE__ */ T(u, { status: O.status }), O.isAcceptingMentees ? /* @__PURE__ */ E(D, {
208
- variant: "outline",
209
- className: "inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text",
210
- children: [/* @__PURE__ */ T("span", { className: "h-1.5 w-1.5 rounded-full bg-status-success-text" }), " Accepting mentees"]
211
- }) : null]
212
- })]
202
+ children: [
203
+ /* @__PURE__ */ T("h1", {
204
+ className: "text-xl font-semibold text-text-primary sm:text-2xl",
205
+ children: O.headline
206
+ }),
207
+ O.role ? /* @__PURE__ */ T("p", {
208
+ className: "mt-1 text-sm font-medium text-text-secondary",
209
+ children: O.role
210
+ }) : null,
211
+ /* @__PURE__ */ E("div", {
212
+ className: "mt-2 flex flex-wrap items-center gap-2",
213
+ children: [/* @__PURE__ */ T(u, { status: O.status }), O.isAcceptingMentees ? /* @__PURE__ */ E(D, {
214
+ variant: "outline",
215
+ className: "inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text",
216
+ children: [/* @__PURE__ */ T("span", { className: "h-1.5 w-1.5 rounded-full bg-status-success-text" }), " Accepting mentees"]
217
+ }) : null]
218
+ })
219
+ ]
213
220
  })]
214
221
  }),
215
222
  O.bio ? /* @__PURE__ */ T("p", {
@@ -1 +1 @@
1
- {"version":3,"file":"MentorshipMentorProfilePagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipMentorProfilePagePage.tsx"],"sourcesContent":["import { createElement, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Award, CalendarClock, DollarSign, MessageSquare, Star, Video } from 'lucide-react';\nimport { Badge, Button, GlassCard, Input, Skeleton, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n PageLayout,\n StatCard,\n StatusBadge,\n coverGradient,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport { useBookSession, useMentorQuery, type TecMentorSession } from '../api/technospamApi';\nimport { formatDateTime, formatDuration, formatMoney } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\n\nfunction BookSessionForm({\n mentorId,\n disabled,\n onBooked,\n workspaceId,\n}: {\n mentorId: string;\n disabled: boolean;\n onBooked?: () => void;\n workspaceId?: string;\n}) {\n const [topic, setTopic] = useState('');\n const [agenda, setAgenda] = useState('');\n const [scheduledAt, setScheduledAt] = useState('');\n const [durationMinutes, setDurationMinutes] = useState('60');\n const [bookSession, { loading }] = useBookSession();\n const { emit } = useTechnoSpamAnalytics();\n\n const parsedDate = scheduledAt ? new Date(scheduledAt) : null;\n const validDate = parsedDate != null && !Number.isNaN(parsedDate.getTime());\n const canSubmit = topic.trim().length > 0 && validDate && !loading && !disabled;\n\n const handleSubmit = async () => {\n if (!canSubmit || !parsedDate) return;\n const input: {\n mentorId: string;\n topic: string;\n agenda?: string;\n scheduledAt: string;\n durationMinutes?: number;\n } = {\n mentorId,\n topic: topic.trim(),\n scheduledAt: parsedDate.toISOString(),\n };\n if (agenda.trim()) input.agenda = agenda.trim();\n const dur = Number.parseInt(durationMinutes, 10);\n if (!Number.isNaN(dur) && dur > 0) input.durationMinutes = dur;\n\n emit('technospam.mentor.book_clicked', {\n workspaceId,\n entityId: mentorId,\n entityType: 'TEC_MENTOR',\n });\n const res = await bookSession({ variables: { input } });\n if (res.data?.tecBookSession) {\n emit('technospam.mentor.booked', {\n workspaceId,\n entityId: mentorId,\n entityType: 'TEC_MENTOR',\n sessionId: res.data.tecBookSession.id,\n });\n notify.success('Session requested', 'Your mentor will confirm the booking soon.');\n setTopic('');\n setAgenda('');\n setScheduledAt('');\n setDurationMinutes('60');\n onBooked?.();\n }\n };\n\n return (\n <GlassCard className=\"p-5\">\n <div className=\"mb-4 flex items-start gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-accent-primary to-accent-purple text-white shadow-sm\">\n <CalendarClock size={20} />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Book a session</h2>\n <p className=\"text-sm text-text-secondary\">Schedule 1:1 time with your mentor.</p>\n </div>\n </div>\n\n {disabled ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-sunken px-3 py-2 text-sm text-text-secondary\">\n This mentor isn&apos;t accepting new mentees right now.\n </p>\n ) : null}\n\n <div className=\"mt-4 grid grid-cols-1 gap-4\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Topic <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n placeholder=\"e.g. System design interview prep\"\n value={topic}\n onChange={(e) => setTopic(e.target.value)}\n disabled={disabled}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Agenda</label>\n <Textarea\n rows={3}\n placeholder=\"What would you like to cover? Share context so your mentor can prepare.\"\n value={agenda}\n onChange={(e) => setAgenda(e.target.value)}\n disabled={disabled}\n />\n </div>\n\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-primary\">\n When <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n type=\"datetime-local\"\n value={scheduledAt}\n onChange={(e) => setScheduledAt(e.target.value)}\n disabled={disabled}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Duration (min)\n </label>\n <Input\n type=\"number\"\n min={15}\n step={15}\n value={durationMinutes}\n onChange={(e) => setDurationMinutes(e.target.value)}\n disabled={disabled}\n />\n </div>\n </div>\n\n <Button\n className=\"w-full bg-gradient-to-r from-accent-primary to-accent-purple\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n >\n <CalendarClock size={16} /> {loading ? 'Requesting…' : 'Request session'}\n </Button>\n </div>\n </GlassCard>\n );\n}\n\nfunction SessionSummaryRow({ session }: { session: TecMentorSession }) {\n return (\n <div className=\"flex items-center gap-3 rounded-lg px-1 py-3 transition-colors hover:bg-bg-sunken\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent-purple/12 text-accent-purple\">\n <Video size={16} />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium text-text-primary\">{session.topic}</div>\n <div className=\"text-xs text-text-muted\">\n {formatDateTime(session.scheduledAt)} · {formatDuration(session.durationMinutes)}\n </div>\n </div>\n <StatusBadge status={session.status} />\n </div>\n );\n}\n\nexport function MentorshipMentorProfilePagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { workspaceId } = useTechnoSpam();\n const { data, loading, error, refetch } = useMentorQuery(id);\n\n const mentor = data?.tecMentor ?? null;\n\n if (loading && !mentor) {\n return (\n <PageLayout title=\"Mentor\" backPath=\"/mentorship/mentors-page\">\n <Skeleton className=\"mb-4 h-40 w-full rounded-xl\" />\n <Skeleton className=\"h-64 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !mentor) {\n return (\n <PageLayout title=\"Mentor\" backPath=\"/mentorship/mentors-page\">\n {error ? (\n <ErrorView title=\"Couldn't load mentor\" error={error} />\n ) : (\n <EmptyView\n title=\"Mentor not found\"\n description=\"This mentor profile may no longer be available.\"\n />\n )}\n </PageLayout>\n );\n }\n\n const sessions = mentor.sessions ?? [];\n const recentSessions = [...sessions]\n .sort((a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime())\n .slice(0, 5);\n\n const HeroIcon = topicIcon(mentor.expertise.join(' ') || mentor.headline);\n\n return (\n <PageLayout hero backPath=\"/mentorship/mentors-page\" title=\"Mentor Profile\">\n <GlassCard className=\"mb-6 overflow-hidden p-0\">\n <div\n className={cn(\n 'relative h-24 overflow-hidden bg-gradient-to-br',\n coverGradient(mentor.headline)\n )}\n >\n {createElement(HeroIcon, {\n className: 'pointer-events-none absolute -right-3 -top-4 text-white/15',\n size: 120,\n strokeWidth: 1.3,\n })}\n <div className=\"pointer-events-none absolute inset-0 bg-gradient-to-t from-black/25 to-transparent\" />\n </div>\n <div className=\"px-6 pb-6\">\n <div className=\"-mt-10 flex flex-col gap-4 sm:flex-row sm:items-end\">\n <div className=\"relative shrink-0\">\n <span\n className={cn(\n 'flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br text-white shadow-lg ring-4 ring-bg-surface',\n coverGradient(mentor.headline)\n )}\n >\n {createElement(HeroIcon, { size: 34, strokeWidth: 1.6 })}\n </span>\n {mentor.isAcceptingMentees ? (\n <span className=\"absolute bottom-1 right-1 h-4 w-4 rounded-full border-2 border-bg-surface bg-status-success-text\" />\n ) : null}\n </div>\n <div className=\"min-w-0 flex-1 sm:pb-1\">\n <h1 className=\"text-xl font-semibold text-text-primary sm:text-2xl\">\n {mentor.headline}\n </h1>\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={mentor.status} />\n {mentor.isAcceptingMentees ? (\n <Badge\n variant=\"outline\"\n className=\"inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-success-text\" /> Accepting\n mentees\n </Badge>\n ) : null}\n </div>\n </div>\n </div>\n\n {mentor.bio ? (\n <p className=\"mt-4 max-w-2xl text-sm leading-relaxed text-text-secondary\">\n {mentor.bio}\n </p>\n ) : null}\n\n {mentor.expertise.length ? (\n <div className=\"mt-4 flex flex-wrap gap-1.5\">\n {mentor.expertise.map((skill) => (\n <Badge key={skill} variant=\"secondary\">\n {skill}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label=\"Rate\"\n value={`${formatMoney(mentor.hourlyRate, mentor.currency)}/hr`}\n icon={DollarSign}\n tone=\"blue\"\n />\n <StatCard\n label=\"Rating\"\n value={mentor.ratingAvg > 0 ? mentor.ratingAvg.toFixed(1) : 'New'}\n icon={Star}\n tone=\"amber\"\n />\n <StatCard\n label=\"Sessions\"\n value={mentor.sessionsCount}\n icon={MessageSquare}\n tone=\"purple\"\n />\n <StatCard\n label=\"Status\"\n value={mentor.status === 'ACTIVE' ? 'Active' : 'Pending'}\n icon={Award}\n tone=\"teal\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <BookSessionForm\n mentorId={mentor.id}\n disabled={!mentor.isAcceptingMentees}\n onBooked={() => void refetch()}\n workspaceId={workspaceId}\n />\n\n <GlassCard className=\"p-5\">\n <div className=\"mb-3 flex items-center gap-2\">\n <CalendarClock size={18} className=\"text-accent-teal\" />\n <h2 className=\"text-base font-semibold text-text-primary\">Recent sessions</h2>\n </div>\n {recentSessions.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-muted\">\n No sessions booked yet. Be the first to request time with this mentor.\n </p>\n ) : (\n <div className=\"divide-y divide-border-seam\">\n {recentSessions.map((session) => (\n <SessionSummaryRow key={session.id} session={session} />\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MentorshipMentorProfilePagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipMentorProfilePagePage.tsx"],"sourcesContent":["import { createElement, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Award, CalendarClock, DollarSign, MessageSquare, Star, Video } from 'lucide-react';\nimport { Badge, Button, GlassCard, Input, Skeleton, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n PageLayout,\n StatCard,\n StatusBadge,\n coverGradient,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam } from '../providers/TechnoSpamProvider';\nimport { useBookSession, useMentorQuery, type TecMentorSession } from '../api/technospamApi';\nimport { formatDateTime, formatDuration, formatMoney } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\n\nfunction BookSessionForm({\n mentorId,\n disabled,\n onBooked,\n workspaceId,\n}: {\n mentorId: string;\n disabled: boolean;\n onBooked?: () => void;\n workspaceId?: string;\n}) {\n const [topic, setTopic] = useState('');\n const [agenda, setAgenda] = useState('');\n const [scheduledAt, setScheduledAt] = useState('');\n const [durationMinutes, setDurationMinutes] = useState('60');\n const [bookSession, { loading }] = useBookSession();\n const { emit } = useTechnoSpamAnalytics();\n\n const parsedDate = scheduledAt ? new Date(scheduledAt) : null;\n const validDate = parsedDate != null && !Number.isNaN(parsedDate.getTime());\n const canSubmit = topic.trim().length > 0 && validDate && !loading && !disabled;\n\n const handleSubmit = async () => {\n if (!canSubmit || !parsedDate) return;\n const input: {\n mentorId: string;\n topic: string;\n agenda?: string;\n scheduledAt: string;\n durationMinutes?: number;\n } = {\n mentorId,\n topic: topic.trim(),\n scheduledAt: parsedDate.toISOString(),\n };\n if (agenda.trim()) input.agenda = agenda.trim();\n const dur = Number.parseInt(durationMinutes, 10);\n if (!Number.isNaN(dur) && dur > 0) input.durationMinutes = dur;\n\n emit('technospam.mentor.book_clicked', {\n workspaceId,\n entityId: mentorId,\n entityType: 'TEC_MENTOR',\n });\n const res = await bookSession({ variables: { input } });\n if (res.data?.tecBookSession) {\n emit('technospam.mentor.booked', {\n workspaceId,\n entityId: mentorId,\n entityType: 'TEC_MENTOR',\n sessionId: res.data.tecBookSession.id,\n });\n notify.success('Session requested', 'Your mentor will confirm the booking soon.');\n setTopic('');\n setAgenda('');\n setScheduledAt('');\n setDurationMinutes('60');\n onBooked?.();\n }\n };\n\n return (\n <GlassCard className=\"p-5\">\n <div className=\"mb-4 flex items-start gap-3\">\n <span className=\"flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-accent-primary to-accent-purple text-white shadow-sm\">\n <CalendarClock size={20} />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Book a session</h2>\n <p className=\"text-sm text-text-secondary\">Schedule 1:1 time with your mentor.</p>\n </div>\n </div>\n\n {disabled ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-sunken px-3 py-2 text-sm text-text-secondary\">\n This mentor isn&apos;t accepting new mentees right now.\n </p>\n ) : null}\n\n <div className=\"mt-4 grid grid-cols-1 gap-4\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Topic <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n placeholder=\"e.g. System design interview prep\"\n value={topic}\n onChange={(e) => setTopic(e.target.value)}\n disabled={disabled}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Agenda</label>\n <Textarea\n rows={3}\n placeholder=\"What would you like to cover? Share context so your mentor can prepare.\"\n value={agenda}\n onChange={(e) => setAgenda(e.target.value)}\n disabled={disabled}\n />\n </div>\n\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-primary\">\n When <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n type=\"datetime-local\"\n value={scheduledAt}\n onChange={(e) => setScheduledAt(e.target.value)}\n disabled={disabled}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Duration (min)\n </label>\n <Input\n type=\"number\"\n min={15}\n step={15}\n value={durationMinutes}\n onChange={(e) => setDurationMinutes(e.target.value)}\n disabled={disabled}\n />\n </div>\n </div>\n\n <Button\n className=\"w-full bg-gradient-to-r from-accent-primary to-accent-purple\"\n onClick={handleSubmit}\n disabled={!canSubmit}\n >\n <CalendarClock size={16} /> {loading ? 'Requesting…' : 'Request session'}\n </Button>\n </div>\n </GlassCard>\n );\n}\n\nfunction SessionSummaryRow({ session }: { session: TecMentorSession }) {\n return (\n <div className=\"flex items-center gap-3 rounded-lg px-1 py-3 transition-colors hover:bg-bg-sunken\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-accent-purple/12 text-accent-purple\">\n <Video size={16} />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium text-text-primary\">{session.topic}</div>\n <div className=\"text-xs text-text-muted\">\n {formatDateTime(session.scheduledAt)} · {formatDuration(session.durationMinutes)}\n </div>\n </div>\n <StatusBadge status={session.status} />\n </div>\n );\n}\n\nexport function MentorshipMentorProfilePagePage() {\n const [params] = useSearchParams();\n const id = params.get('id') ?? '';\n const { workspaceId } = useTechnoSpam();\n const { data, loading, error, refetch } = useMentorQuery(id);\n\n const mentor = data?.tecMentor ?? null;\n\n if (loading && !mentor) {\n return (\n <PageLayout title=\"Mentor\" backPath=\"/mentorship/mentors-page\">\n <Skeleton className=\"mb-4 h-40 w-full rounded-xl\" />\n <Skeleton className=\"h-64 w-full rounded-xl\" />\n </PageLayout>\n );\n }\n\n if (error || !mentor) {\n return (\n <PageLayout title=\"Mentor\" backPath=\"/mentorship/mentors-page\">\n {error ? (\n <ErrorView title=\"Couldn't load mentor\" error={error} />\n ) : (\n <EmptyView\n title=\"Mentor not found\"\n description=\"This mentor profile may no longer be available.\"\n />\n )}\n </PageLayout>\n );\n }\n\n const sessions = mentor.sessions ?? [];\n const recentSessions = [...sessions]\n .sort((a, b) => new Date(b.scheduledAt).getTime() - new Date(a.scheduledAt).getTime())\n .slice(0, 5);\n\n const HeroIcon = topicIcon(mentor.expertise.join(' ') || mentor.headline);\n\n return (\n <PageLayout hero backPath=\"/mentorship/mentors-page\" title=\"Mentor Profile\">\n <GlassCard className=\"mb-6 overflow-hidden p-0\">\n <div\n className={cn(\n 'relative h-24 overflow-hidden bg-gradient-to-br',\n coverGradient(mentor.headline)\n )}\n >\n {createElement(HeroIcon, {\n className: 'pointer-events-none absolute -right-3 -top-4 text-white/15',\n size: 120,\n strokeWidth: 1.3,\n })}\n <div className=\"pointer-events-none absolute inset-0 bg-gradient-to-t from-black/25 to-transparent\" />\n </div>\n <div className=\"px-6 pb-6\">\n <div className=\"-mt-10 flex flex-col gap-4 sm:flex-row sm:items-end\">\n <div className=\"relative shrink-0\">\n <span\n className={cn(\n 'flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br text-white shadow-lg ring-4 ring-bg-surface',\n coverGradient(mentor.headline)\n )}\n >\n {createElement(HeroIcon, { size: 34, strokeWidth: 1.6 })}\n </span>\n {mentor.isAcceptingMentees ? (\n <span className=\"absolute bottom-1 right-1 h-4 w-4 rounded-full border-2 border-bg-surface bg-status-success-text\" />\n ) : null}\n </div>\n <div className=\"min-w-0 flex-1 sm:pb-1\">\n <h1 className=\"text-xl font-semibold text-text-primary sm:text-2xl\">\n {mentor.headline}\n </h1>\n {mentor.role ? (\n <p className=\"mt-1 text-sm font-medium text-text-secondary\">{mentor.role}</p>\n ) : null}\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={mentor.status} />\n {mentor.isAcceptingMentees ? (\n <Badge\n variant=\"outline\"\n className=\"inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-success-text\" /> Accepting\n mentees\n </Badge>\n ) : null}\n </div>\n </div>\n </div>\n\n {mentor.bio ? (\n <p className=\"mt-4 max-w-2xl text-sm leading-relaxed text-text-secondary\">\n {mentor.bio}\n </p>\n ) : null}\n\n {mentor.expertise.length ? (\n <div className=\"mt-4 flex flex-wrap gap-1.5\">\n {mentor.expertise.map((skill) => (\n <Badge key={skill} variant=\"secondary\">\n {skill}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n </GlassCard>\n\n <div className=\"mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard\n label=\"Rate\"\n value={`${formatMoney(mentor.hourlyRate, mentor.currency)}/hr`}\n icon={DollarSign}\n tone=\"blue\"\n />\n <StatCard\n label=\"Rating\"\n value={mentor.ratingAvg > 0 ? mentor.ratingAvg.toFixed(1) : 'New'}\n icon={Star}\n tone=\"amber\"\n />\n <StatCard\n label=\"Sessions\"\n value={mentor.sessionsCount}\n icon={MessageSquare}\n tone=\"purple\"\n />\n <StatCard\n label=\"Status\"\n value={mentor.status === 'ACTIVE' ? 'Active' : 'Pending'}\n icon={Award}\n tone=\"teal\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <BookSessionForm\n mentorId={mentor.id}\n disabled={!mentor.isAcceptingMentees}\n onBooked={() => void refetch()}\n workspaceId={workspaceId}\n />\n\n <GlassCard className=\"p-5\">\n <div className=\"mb-3 flex items-center gap-2\">\n <CalendarClock size={18} className=\"text-accent-teal\" />\n <h2 className=\"text-base font-semibold text-text-primary\">Recent sessions</h2>\n </div>\n {recentSessions.length === 0 ? (\n <p className=\"py-6 text-center text-sm text-text-muted\">\n No sessions booked yet. Be the first to request time with this mentor.\n </p>\n ) : (\n <div className=\"divide-y divide-border-seam\">\n {recentSessions.map((session) => (\n <SessionSummaryRow key={session.id} session={session} />\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MentorshipMentorsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"names":[],"mappings":"AA8QA,wBAAgB,yBAAyB,gCAwIxC"}
1
+ {"version":3,"file":"MentorshipMentorsPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"names":[],"mappings":"AAkSA,wBAAgB,yBAAyB,gCAwIxC"}
@@ -36,18 +36,25 @@ function L({ mentor: e, onOpen: t }) {
36
36
  className: "flex items-start gap-4",
37
37
  children: [/* @__PURE__ */ k(I, { mentor: e }), /* @__PURE__ */ A("div", {
38
38
  className: "min-w-0 flex-1",
39
- children: [/* @__PURE__ */ k("h3", {
40
- className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
41
- children: e.headline
42
- }), e.isAcceptingMentees ? /* @__PURE__ */ A(j, {
43
- variant: "outline",
44
- className: "mt-1.5 inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text",
45
- children: [/* @__PURE__ */ k("span", { className: "h-1.5 w-1.5 rounded-full bg-status-success-text" }), " Accepting mentees"]
46
- }) : /* @__PURE__ */ k(j, {
47
- variant: "outline",
48
- className: "mt-1.5 border-border-seam bg-bg-sunken text-text-secondary",
49
- children: "Not accepting"
50
- })]
39
+ children: [
40
+ /* @__PURE__ */ k("h3", {
41
+ className: "truncate text-base font-semibold text-text-primary group-hover:text-accent-primary",
42
+ children: e.headline
43
+ }),
44
+ e.role ? /* @__PURE__ */ k("p", {
45
+ className: "mt-0.5 truncate text-xs font-medium text-text-secondary",
46
+ children: e.role
47
+ }) : null,
48
+ e.isAcceptingMentees ? /* @__PURE__ */ A(j, {
49
+ variant: "outline",
50
+ className: "mt-1.5 inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text",
51
+ children: [/* @__PURE__ */ k("span", { className: "h-1.5 w-1.5 rounded-full bg-status-success-text" }), " Accepting mentees"]
52
+ }) : /* @__PURE__ */ k(j, {
53
+ variant: "outline",
54
+ className: "mt-1.5 border-border-seam bg-bg-sunken text-text-secondary",
55
+ children: "Not accepting"
56
+ })
57
+ ]
51
58
  })]
52
59
  }),
53
60
  e.bio ? /* @__PURE__ */ k("p", {
@@ -114,7 +121,7 @@ function L({ mentor: e, onOpen: t }) {
114
121
  });
115
122
  }
116
123
  function R({ onClose: e, onDone: t, workspaceId: r }) {
117
- let [i, a] = b(""), [o, s] = b(""), [c, l] = b(""), [u, d] = b(""), [f, m] = b("USD"), [g, { loading: _ }] = h(), { emit: v } = n(), y = i.trim().length > 0 && !_;
124
+ let [i, a] = b(""), [o, s] = b(""), [c, l] = b(""), [u, d] = b(""), [f, m] = b(""), [g, _] = b("USD"), [v, { loading: y }] = h(), { emit: x } = n(), S = i.trim().length > 0 && !y;
118
125
  return /* @__PURE__ */ A(N, {
119
126
  className: "mb-6 p-5",
120
127
  children: [/* @__PURE__ */ A("div", {
@@ -152,14 +159,29 @@ function R({ onClose: e, onDone: t, workspaceId: r }) {
152
159
  value: i,
153
160
  onChange: (e) => a(e.target.value)
154
161
  })] }),
162
+ /* @__PURE__ */ A("div", { children: [
163
+ /* @__PURE__ */ k("label", {
164
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
165
+ children: "Role & company"
166
+ }),
167
+ /* @__PURE__ */ k(P, {
168
+ placeholder: "e.g. Staff Engineer @ Acme",
169
+ value: o,
170
+ onChange: (e) => s(e.target.value)
171
+ }),
172
+ /* @__PURE__ */ k("p", {
173
+ className: "mt-1 text-xs text-text-muted",
174
+ children: "Shown as a subtitle under your headline. Optional."
175
+ })
176
+ ] }),
155
177
  /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("label", {
156
178
  className: "mb-1.5 block text-sm font-medium text-text-primary",
157
179
  children: "Bio"
158
180
  }), /* @__PURE__ */ k(F, {
159
181
  rows: 3,
160
182
  placeholder: "Tell mentees about your experience and how you can help.",
161
- value: o,
162
- onChange: (e) => s(e.target.value)
183
+ value: c,
184
+ onChange: (e) => l(e.target.value)
163
185
  })] }),
164
186
  /* @__PURE__ */ A("div", { children: [
165
187
  /* @__PURE__ */ k("label", {
@@ -168,8 +190,8 @@ function R({ onClose: e, onDone: t, workspaceId: r }) {
168
190
  }),
169
191
  /* @__PURE__ */ k(P, {
170
192
  placeholder: "React, System design, Career coaching",
171
- value: c,
172
- onChange: (e) => l(e.target.value)
193
+ value: u,
194
+ onChange: (e) => d(e.target.value)
173
195
  }),
174
196
  /* @__PURE__ */ k("p", {
175
197
  className: "mt-1 text-xs text-text-muted",
@@ -187,8 +209,8 @@ function R({ onClose: e, onDone: t, workspaceId: r }) {
187
209
  type: "number",
188
210
  min: 0,
189
211
  placeholder: "0",
190
- value: u,
191
- onChange: (e) => d(e.target.value)
212
+ value: f,
213
+ onChange: (e) => m(e.target.value)
192
214
  }),
193
215
  /* @__PURE__ */ k("p", {
194
216
  className: "mt-1 text-xs text-text-muted",
@@ -199,38 +221,38 @@ function R({ onClose: e, onDone: t, workspaceId: r }) {
199
221
  children: "Currency"
200
222
  }), /* @__PURE__ */ k(P, {
201
223
  placeholder: "USD",
202
- value: f,
203
- onChange: (e) => m(e.target.value)
224
+ value: g,
225
+ onChange: (e) => _(e.target.value)
204
226
  })] })]
205
227
  }),
206
228
  /* @__PURE__ */ A("div", {
207
229
  className: "flex flex-wrap items-center gap-2",
208
230
  children: [/* @__PURE__ */ A(M, {
209
231
  onClick: async () => {
210
- if (!y) return;
232
+ if (!S) return;
211
233
  let e = { headline: i.trim() };
212
- o.trim() && (e.bio = o.trim());
213
- let n = c.split(",").map((e) => e.trim()).filter(Boolean);
234
+ o.trim() && (e.role = o.trim()), c.trim() && (e.bio = c.trim());
235
+ let n = u.split(",").map((e) => e.trim()).filter(Boolean);
214
236
  n.length && (e.expertise = n);
215
- let a = Number.parseInt(u, 10);
216
- !Number.isNaN(a) && a >= 0 && (e.hourlyRate = a), f.trim() && (e.currency = f.trim().toUpperCase()), v("technospam.mentor.become_mentor_clicked", { workspaceId: r });
217
- let s = await g({ variables: { input: e } });
218
- s.data?.tecBecomeMentor && (v("technospam.mentor.became_mentor", {
237
+ let a = Number.parseInt(f, 10);
238
+ !Number.isNaN(a) && a >= 0 && (e.hourlyRate = a), g.trim() && (e.currency = g.trim().toUpperCase()), x("technospam.mentor.become_mentor_clicked", { workspaceId: r });
239
+ let s = await v({ variables: { input: e } });
240
+ s.data?.tecBecomeMentor && (x("technospam.mentor.became_mentor", {
219
241
  workspaceId: r,
220
242
  entityId: s.data.tecBecomeMentor.id,
221
243
  entityType: "TEC_MENTOR"
222
244
  }), p.success("Mentor profile created", "Your profile is pending review."), t());
223
245
  },
224
- disabled: !y,
246
+ disabled: !S,
225
247
  children: [
226
248
  /* @__PURE__ */ k(E, { size: 16 }),
227
249
  " ",
228
- _ ? "Submitting…" : "Submit profile"
250
+ y ? "Submitting…" : "Submit profile"
229
251
  ]
230
252
  }), /* @__PURE__ */ k(M, {
231
253
  variant: "outline",
232
254
  onClick: e,
233
- disabled: _,
255
+ disabled: y,
234
256
  children: "Cancel"
235
257
  })]
236
258
  })
@@ -1 +1 @@
1
- {"version":3,"file":"MentorshipMentorsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"sourcesContent":["import { createElement, useMemo, useState } from 'react';\nimport { Award, MessageSquare, Search, Sparkles, Star, UserPlus, Users, X } from 'lucide-react';\nimport { Badge, Button, GlassCard, Input, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n PageLayout,\n StatCard,\n coverGradient,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useBecomeMentor,\n useMentorsQuery,\n usePageLimit,\n type TecMentor,\n} from '../api/technospamApi';\nimport { formatMoney } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\n\n/** Circular gradient medallion standing in for a mentor avatar, with a live\n * \"accepting\" presence dot — mirrors the directory mockup within the dark theme. */\nfunction MentorMedallion({ mentor, size = 'md' }: { mentor: TecMentor; size?: 'md' | 'lg' }) {\n const box = size === 'lg' ? 'h-20 w-20' : 'h-16 w-16';\n return (\n <div className=\"relative shrink-0\">\n <span\n className={cn(\n 'flex items-center justify-center rounded-full bg-gradient-to-br text-white shadow-md ring-1 ring-white/15',\n box,\n coverGradient(mentor.headline)\n )}\n >\n {createElement(topicIcon(mentor.expertise.join(' ') || mentor.headline), {\n size: size === 'lg' ? 32 : 26,\n strokeWidth: 1.7,\n })}\n </span>\n {mentor.isAcceptingMentees ? (\n <span className=\"absolute -bottom-0.5 -right-0.5 h-4 w-4 rounded-full border-2 border-bg-surface bg-status-success-text\" />\n ) : null}\n </div>\n );\n}\n\nfunction MentorCard({ mentor, onOpen }: { mentor: TecMentor; onOpen: () => void }) {\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col gap-4 p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\"\n onClick={onOpen}\n >\n <div className=\"flex items-start gap-4\">\n <MentorMedallion mentor={mentor} />\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n {mentor.headline}\n </h3>\n {mentor.isAcceptingMentees ? (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-success-text\" /> Accepting mentees\n </Badge>\n ) : (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 border-border-seam bg-bg-sunken text-text-secondary\"\n >\n Not accepting\n </Badge>\n )}\n </div>\n </div>\n\n {mentor.bio ? <p className=\"line-clamp-2 text-sm text-text-secondary\">{mentor.bio}</p> : null}\n\n {mentor.expertise.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {mentor.expertise.slice(0, 4).map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-[11px]\">\n {skill}\n </Badge>\n ))}\n {mentor.expertise.length > 4 ? (\n <span className=\"self-center text-xs text-text-muted\">\n +{mentor.expertise.length - 4}\n </span>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"mt-auto grid grid-cols-3 divide-x divide-border-seam rounded-xl border border-border-seam bg-bg-sunken text-center\">\n <div className=\"px-2 py-2.5\">\n <div className=\"flex items-center justify-center gap-1 text-sm font-semibold text-text-primary\">\n <Star size={13} className=\"text-accent-teal\" />\n {mentor.ratingAvg > 0 ? mentor.ratingAvg.toFixed(1) : 'New'}\n </div>\n <div className=\"text-[11px] text-text-muted\">rating</div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">{mentor.sessionsCount}</div>\n <div className=\"text-[11px] text-text-muted\">sessions</div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">\n {formatMoney(mentor.hourlyRate, mentor.currency)}\n </div>\n <div className=\"text-[11px] text-text-muted\">/ hr</div>\n </div>\n </div>\n\n <Button\n className=\"w-full\"\n onClick={(e) => {\n e.stopPropagation();\n onOpen();\n }}\n >\n View profile\n </Button>\n </GlassCard>\n );\n}\n\nfunction BecomeMentorForm({\n onClose,\n onDone,\n workspaceId,\n}: {\n onClose: () => void;\n onDone: () => void;\n workspaceId?: string;\n}) {\n const [headline, setHeadline] = useState('');\n const [bio, setBio] = useState('');\n const [expertise, setExpertise] = useState('');\n const [hourlyRate, setHourlyRate] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [becomeMentor, { loading }] = useBecomeMentor();\n const { emit } = useTechnoSpamAnalytics();\n\n const canSubmit = headline.trim().length > 0 && !loading;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n const input: {\n headline: string;\n bio?: string;\n expertise?: string[];\n hourlyRate?: number;\n currency?: string;\n } = { headline: headline.trim() };\n if (bio.trim()) input.bio = bio.trim();\n const exp = expertise\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n if (exp.length) input.expertise = exp;\n const rate = Number.parseInt(hourlyRate, 10);\n if (!Number.isNaN(rate) && rate >= 0) input.hourlyRate = rate;\n if (currency.trim()) input.currency = currency.trim().toUpperCase();\n\n emit('technospam.mentor.become_mentor_clicked', { workspaceId });\n const res = await becomeMentor({ variables: { input } });\n if (res.data?.tecBecomeMentor) {\n emit('technospam.mentor.became_mentor', {\n workspaceId,\n entityId: res.data.tecBecomeMentor.id,\n entityType: 'TEC_MENTOR',\n });\n notify.success('Mentor profile created', 'Your profile is pending review.');\n onDone();\n }\n };\n\n return (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-4 flex items-start justify-between gap-3\">\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-gradient-to-br from-accent-primary to-accent-indigo text-white shadow-sm\">\n <UserPlus size={20} />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Become a mentor</h2>\n <p className=\"text-sm text-text-secondary\">\n Share your expertise and start mentoring builders in the community.\n </p>\n </div>\n </div>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClose} aria-label=\"Close\">\n <X size={16} />\n </Button>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Headline <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n placeholder=\"e.g. Staff Engineer · Distributed systems & career growth\"\n value={headline}\n onChange={(e) => setHeadline(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Bio</label>\n <Textarea\n rows={3}\n placeholder=\"Tell mentees about your experience and how you can help.\"\n value={bio}\n onChange={(e) => setBio(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Expertise</label>\n <Input\n placeholder=\"React, System design, Career coaching\"\n value={expertise}\n onChange={(e) => setExpertise(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">Comma-separated topics.</p>\n </div>\n\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-primary\">\n Hourly rate\n </label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"0\"\n value={hourlyRate}\n onChange={(e) => setHourlyRate(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">Whole number. Leave 0 for free.</p>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Currency</label>\n <Input\n placeholder=\"USD\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n <UserPlus size={16} /> {loading ? 'Submitting…' : 'Submit profile'}\n </Button>\n <Button variant=\"outline\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n}\n\nexport function MentorshipMentorsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const [search, setSearch] = useState('');\n const [showForm, setShowForm] = useState(false);\n\n const { limit, more } = usePageLimit();\n const { data, loading, error, refetch } = useMentorsQuery({\n status: 'ACTIVE',\n pagination: pageArg(limit),\n });\n\n const mentors = data?.tecListMentors.items ?? [];\n const hasMore = data?.tecListMentors.pageInfo.hasMore ?? false;\n const userId = currentUser?.id;\n const alreadyMentor = Boolean(userId && mentors.some((m) => m.userId === userId));\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return mentors;\n return mentors.filter(\n (m) =>\n m.headline.toLowerCase().includes(q) ||\n m.expertise.some((skill) => skill.toLowerCase().includes(q))\n );\n }, [mentors, search]);\n\n const accepting = mentors.filter((m) => m.isAcceptingMentees).length;\n const totalSessions = mentors.reduce((s, m) => s + m.sessionsCount, 0);\n const rated = mentors.filter((m) => m.ratingAvg > 0);\n const avgRating = rated.length\n ? (rated.reduce((s, m) => s + m.ratingAvg, 0) / rated.length).toFixed(1)\n : '—';\n\n return (\n <PageLayout\n hero\n title=\"Find a Mentor\"\n description=\"Connect with experienced builders for 1:1 guidance, code review, and career coaching.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/sessions-page')}>\n <MessageSquare size={16} /> My sessions\n </Button>\n }\n >\n {alreadyMentor ? (\n <GlassCard className=\"mb-6 flex items-center gap-3 p-4\">\n <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-status-success-bg-subtle text-status-success-text\">\n <Award size={20} />\n </span>\n <div>\n <div className=\"text-sm font-semibold text-text-primary\">You&apos;re a mentor</div>\n <div className=\"text-xs text-text-secondary\">\n Your mentor profile is live. Mentees can request sessions with you.\n </div>\n </div>\n </GlassCard>\n ) : showForm ? (\n <BecomeMentorForm\n onClose={() => setShowForm(false)}\n onDone={() => {\n setShowForm(false);\n void refetch();\n }}\n workspaceId={workspaceId}\n />\n ) : null}\n\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Mentors\" value={mentors.length} icon={Users} tone=\"blue\" />\n <StatCard label=\"Accepting mentees\" value={accepting} icon={Sparkles} tone=\"green\" />\n <StatCard label=\"Avg rating\" value={avgRating} icon={Star} tone=\"amber\" />\n <StatCard label=\"Total sessions\" value={totalSessions} icon={MessageSquare} tone=\"purple\" />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"relative w-full sm:w-80\">\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 by headline or expertise…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n {!alreadyMentor && !showForm ? (\n <Button onClick={() => setShowForm(true)}>\n <UserPlus size={16} /> Become a mentor\n </Button>\n ) : null}\n </div>\n\n {loading && !mentors.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load mentors\" error={error} />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title={search ? 'No matching mentors' : 'No mentors yet'}\n description={\n search\n ? 'Try a different search term.'\n : 'Active mentors will appear here. TechnoSpam is pre-launch — be one of the first to sign up.'\n }\n action={\n !search && !alreadyMentor ? (\n <Button onClick={() => setShowForm(true)}>Become a mentor</Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((mentor) => (\n <MentorCard\n key={mentor.id}\n mentor={mentor}\n onOpen={() => {\n emit('technospam.mentor.viewed', {\n workspaceId,\n entityId: mentor.id,\n entityType: 'TEC_MENTOR',\n });\n navigate(`/mentorship/mentor-profile-page?id=${mentor.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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"}
1
+ {"version":3,"file":"MentorshipMentorsPagePage.js","names":[],"sources":["../../../src/technospam/pages/MentorshipMentorsPagePage.tsx"],"sourcesContent":["import { createElement, useMemo, useState } from 'react';\nimport { Award, MessageSquare, Search, Sparkles, Star, UserPlus, Users, X } from 'lucide-react';\nimport { Badge, Button, GlassCard, Input, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n EmptyView,\n ErrorView,\n LoadMore,\n LoadingGrid,\n PageLayout,\n StatCard,\n coverGradient,\n topicIcon,\n} from '../components';\nimport { useTechnoSpam, useTechnoSpamNavigate } from '../providers/TechnoSpamProvider';\nimport {\n pageArg,\n useBecomeMentor,\n useMentorsQuery,\n usePageLimit,\n type TecMentor,\n} from '../api/technospamApi';\nimport { formatMoney } from '../utils/format';\nimport { cn } from '../utils/cn';\nimport { notify } from '../lib/toast';\nimport { useTechnoSpamAnalytics } from '../hooks/useTechnoSpamAnalytics';\n\n/** Circular gradient medallion standing in for a mentor avatar, with a live\n * \"accepting\" presence dot — mirrors the directory mockup within the dark theme. */\nfunction MentorMedallion({ mentor, size = 'md' }: { mentor: TecMentor; size?: 'md' | 'lg' }) {\n const box = size === 'lg' ? 'h-20 w-20' : 'h-16 w-16';\n return (\n <div className=\"relative shrink-0\">\n <span\n className={cn(\n 'flex items-center justify-center rounded-full bg-gradient-to-br text-white shadow-md ring-1 ring-white/15',\n box,\n coverGradient(mentor.headline)\n )}\n >\n {createElement(topicIcon(mentor.expertise.join(' ') || mentor.headline), {\n size: size === 'lg' ? 32 : 26,\n strokeWidth: 1.7,\n })}\n </span>\n {mentor.isAcceptingMentees ? (\n <span className=\"absolute -bottom-0.5 -right-0.5 h-4 w-4 rounded-full border-2 border-bg-surface bg-status-success-text\" />\n ) : null}\n </div>\n );\n}\n\nfunction MentorCard({ mentor, onOpen }: { mentor: TecMentor; onOpen: () => void }) {\n return (\n <GlassCard\n className=\"group flex cursor-pointer flex-col gap-4 p-5 transition-all duration-200 hover:-translate-y-1 hover:shadow-lg\"\n onClick={onOpen}\n >\n <div className=\"flex items-start gap-4\">\n <MentorMedallion mentor={mentor} />\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-base font-semibold text-text-primary group-hover:text-accent-primary\">\n {mentor.headline}\n </h3>\n {mentor.role ? (\n <p className=\"mt-0.5 truncate text-xs font-medium text-text-secondary\">{mentor.role}</p>\n ) : null}\n {mentor.isAcceptingMentees ? (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 inline-flex items-center gap-1.5 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <span className=\"h-1.5 w-1.5 rounded-full bg-status-success-text\" /> Accepting mentees\n </Badge>\n ) : (\n <Badge\n variant=\"outline\"\n className=\"mt-1.5 border-border-seam bg-bg-sunken text-text-secondary\"\n >\n Not accepting\n </Badge>\n )}\n </div>\n </div>\n\n {mentor.bio ? <p className=\"line-clamp-2 text-sm text-text-secondary\">{mentor.bio}</p> : null}\n\n {mentor.expertise.length ? (\n <div className=\"flex flex-wrap gap-1.5\">\n {mentor.expertise.slice(0, 4).map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-[11px]\">\n {skill}\n </Badge>\n ))}\n {mentor.expertise.length > 4 ? (\n <span className=\"self-center text-xs text-text-muted\">\n +{mentor.expertise.length - 4}\n </span>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"mt-auto grid grid-cols-3 divide-x divide-border-seam rounded-xl border border-border-seam bg-bg-sunken text-center\">\n <div className=\"px-2 py-2.5\">\n <div className=\"flex items-center justify-center gap-1 text-sm font-semibold text-text-primary\">\n <Star size={13} className=\"text-accent-teal\" />\n {mentor.ratingAvg > 0 ? mentor.ratingAvg.toFixed(1) : 'New'}\n </div>\n <div className=\"text-[11px] text-text-muted\">rating</div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">{mentor.sessionsCount}</div>\n <div className=\"text-[11px] text-text-muted\">sessions</div>\n </div>\n <div className=\"px-2 py-2.5\">\n <div className=\"text-sm font-semibold text-text-primary\">\n {formatMoney(mentor.hourlyRate, mentor.currency)}\n </div>\n <div className=\"text-[11px] text-text-muted\">/ hr</div>\n </div>\n </div>\n\n <Button\n className=\"w-full\"\n onClick={(e) => {\n e.stopPropagation();\n onOpen();\n }}\n >\n View profile\n </Button>\n </GlassCard>\n );\n}\n\nfunction BecomeMentorForm({\n onClose,\n onDone,\n workspaceId,\n}: {\n onClose: () => void;\n onDone: () => void;\n workspaceId?: string;\n}) {\n const [headline, setHeadline] = useState('');\n const [role, setRole] = useState('');\n const [bio, setBio] = useState('');\n const [expertise, setExpertise] = useState('');\n const [hourlyRate, setHourlyRate] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [becomeMentor, { loading }] = useBecomeMentor();\n const { emit } = useTechnoSpamAnalytics();\n\n const canSubmit = headline.trim().length > 0 && !loading;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n const input: {\n headline: string;\n role?: string;\n bio?: string;\n expertise?: string[];\n hourlyRate?: number;\n currency?: string;\n } = { headline: headline.trim() };\n if (role.trim()) input.role = role.trim();\n if (bio.trim()) input.bio = bio.trim();\n const exp = expertise\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n if (exp.length) input.expertise = exp;\n const rate = Number.parseInt(hourlyRate, 10);\n if (!Number.isNaN(rate) && rate >= 0) input.hourlyRate = rate;\n if (currency.trim()) input.currency = currency.trim().toUpperCase();\n\n emit('technospam.mentor.become_mentor_clicked', { workspaceId });\n const res = await becomeMentor({ variables: { input } });\n if (res.data?.tecBecomeMentor) {\n emit('technospam.mentor.became_mentor', {\n workspaceId,\n entityId: res.data.tecBecomeMentor.id,\n entityType: 'TEC_MENTOR',\n });\n notify.success('Mentor profile created', 'Your profile is pending review.');\n onDone();\n }\n };\n\n return (\n <GlassCard className=\"mb-6 p-5\">\n <div className=\"mb-4 flex items-start justify-between gap-3\">\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-gradient-to-br from-accent-primary to-accent-indigo text-white shadow-sm\">\n <UserPlus size={20} />\n </span>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Become a mentor</h2>\n <p className=\"text-sm text-text-secondary\">\n Share your expertise and start mentoring builders in the community.\n </p>\n </div>\n </div>\n <Button variant=\"ghost\" size=\"sm\" onClick={onClose} aria-label=\"Close\">\n <X size={16} />\n </Button>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Headline <span className=\"text-status-error-text\">*</span>\n </label>\n <Input\n placeholder=\"e.g. Staff Engineer · Distributed systems & career growth\"\n value={headline}\n onChange={(e) => setHeadline(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n Role &amp; company\n </label>\n <Input\n placeholder=\"e.g. Staff Engineer @ Acme\"\n value={role}\n onChange={(e) => setRole(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">\n Shown as a subtitle under your headline. Optional.\n </p>\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Bio</label>\n <Textarea\n rows={3}\n placeholder=\"Tell mentees about your experience and how you can help.\"\n value={bio}\n onChange={(e) => setBio(e.target.value)}\n />\n </div>\n\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Expertise</label>\n <Input\n placeholder=\"React, System design, Career coaching\"\n value={expertise}\n onChange={(e) => setExpertise(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">Comma-separated topics.</p>\n </div>\n\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-primary\">\n Hourly rate\n </label>\n <Input\n type=\"number\"\n min={0}\n placeholder=\"0\"\n value={hourlyRate}\n onChange={(e) => setHourlyRate(e.target.value)}\n />\n <p className=\"mt-1 text-xs text-text-muted\">Whole number. Leave 0 for free.</p>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Currency</label>\n <Input\n placeholder=\"USD\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n <UserPlus size={16} /> {loading ? 'Submitting…' : 'Submit profile'}\n </Button>\n <Button variant=\"outline\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n}\n\nexport function MentorshipMentorsPagePage() {\n const navigate = useTechnoSpamNavigate();\n const { currentUser, workspaceId } = useTechnoSpam();\n const { emit } = useTechnoSpamAnalytics();\n const [search, setSearch] = useState('');\n const [showForm, setShowForm] = useState(false);\n\n const { limit, more } = usePageLimit();\n const { data, loading, error, refetch } = useMentorsQuery({\n status: 'ACTIVE',\n pagination: pageArg(limit),\n });\n\n const mentors = data?.tecListMentors.items ?? [];\n const hasMore = data?.tecListMentors.pageInfo.hasMore ?? false;\n const userId = currentUser?.id;\n const alreadyMentor = Boolean(userId && mentors.some((m) => m.userId === userId));\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return mentors;\n return mentors.filter(\n (m) =>\n m.headline.toLowerCase().includes(q) ||\n m.expertise.some((skill) => skill.toLowerCase().includes(q))\n );\n }, [mentors, search]);\n\n const accepting = mentors.filter((m) => m.isAcceptingMentees).length;\n const totalSessions = mentors.reduce((s, m) => s + m.sessionsCount, 0);\n const rated = mentors.filter((m) => m.ratingAvg > 0);\n const avgRating = rated.length\n ? (rated.reduce((s, m) => s + m.ratingAvg, 0) / rated.length).toFixed(1)\n : '—';\n\n return (\n <PageLayout\n hero\n title=\"Find a Mentor\"\n description=\"Connect with experienced builders for 1:1 guidance, code review, and career coaching.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigate('/mentorship/sessions-page')}>\n <MessageSquare size={16} /> My sessions\n </Button>\n }\n >\n {alreadyMentor ? (\n <GlassCard className=\"mb-6 flex items-center gap-3 p-4\">\n <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-status-success-bg-subtle text-status-success-text\">\n <Award size={20} />\n </span>\n <div>\n <div className=\"text-sm font-semibold text-text-primary\">You&apos;re a mentor</div>\n <div className=\"text-xs text-text-secondary\">\n Your mentor profile is live. Mentees can request sessions with you.\n </div>\n </div>\n </GlassCard>\n ) : showForm ? (\n <BecomeMentorForm\n onClose={() => setShowForm(false)}\n onDone={() => {\n setShowForm(false);\n void refetch();\n }}\n workspaceId={workspaceId}\n />\n ) : null}\n\n <div className=\"mb-5 grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatCard label=\"Mentors\" value={mentors.length} icon={Users} tone=\"blue\" />\n <StatCard label=\"Accepting mentees\" value={accepting} icon={Sparkles} tone=\"green\" />\n <StatCard label=\"Avg rating\" value={avgRating} icon={Star} tone=\"amber\" />\n <StatCard label=\"Total sessions\" value={totalSessions} icon={MessageSquare} tone=\"purple\" />\n </div>\n\n <div className=\"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"relative w-full sm:w-80\">\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 by headline or expertise…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n {!alreadyMentor && !showForm ? (\n <Button onClick={() => setShowForm(true)}>\n <UserPlus size={16} /> Become a mentor\n </Button>\n ) : null}\n </div>\n\n {loading && !mentors.length ? (\n <LoadingGrid />\n ) : error ? (\n <ErrorView title=\"Couldn't load mentors\" error={error} />\n ) : filtered.length === 0 ? (\n <EmptyView\n icon={<Users size={26} />}\n title={search ? 'No matching mentors' : 'No mentors yet'}\n description={\n search\n ? 'Try a different search term.'\n : 'Active mentors will appear here. TechnoSpam is pre-launch — be one of the first to sign up.'\n }\n action={\n !search && !alreadyMentor ? (\n <Button onClick={() => setShowForm(true)}>Become a mentor</Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((mentor) => (\n <MentorCard\n key={mentor.id}\n mentor={mentor}\n onOpen={() => {\n emit('technospam.mentor.viewed', {\n workspaceId,\n entityId: mentor.id,\n entityType: 'TEC_MENTOR',\n });\n navigate(`/mentorship/mentor-profile-page?id=${mentor.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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-technospam",
3
- "version": "2026.719.2",
3
+ "version": "2026.720.1",
4
4
  "description": "Burdenoff TechnoSpam Microfrontend",
5
5
  "type": "module",
6
6
  "files": [