@burdenoff/microfe-technospam 2026.801.1 → 2026.828.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/technospam/TechnoSpamRoutes.d.ts.map +1 -1
- package/dist/technospam/TechnoSpamRoutes.js +89 -88
- package/dist/technospam/TechnoSpamRoutes.js.map +1 -1
- package/dist/technospam/api/technospamApi.d.ts +19 -0
- package/dist/technospam/api/technospamApi.d.ts.map +1 -1
- package/dist/technospam/api/technospamApi.js +171 -150
- package/dist/technospam/api/technospamApi.js.map +1 -1
- package/dist/technospam/components/SubmissionViews.d.ts +31 -0
- package/dist/technospam/components/SubmissionViews.d.ts.map +1 -0
- package/dist/technospam/components/SubmissionViews.js +149 -0
- package/dist/technospam/components/SubmissionViews.js.map +1 -0
- package/dist/technospam/components/TechnoSpamErrorBoundary.d.ts +25 -0
- package/dist/technospam/components/TechnoSpamErrorBoundary.d.ts.map +1 -0
- package/dist/technospam/components/TechnoSpamErrorBoundary.js +31 -0
- package/dist/technospam/components/TechnoSpamErrorBoundary.js.map +1 -0
- package/dist/technospam/components/index.d.ts +2 -0
- package/dist/technospam/components/index.d.ts.map +1 -1
- package/dist/technospam/components/index.js +2 -0
- package/dist/technospam/pages/AdminAdminDashboardPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js +725 -500
- package/dist/technospam/pages/AdminAdminDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js +343 -262
- package/dist/technospam/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsPortfolioPagePage.js +2 -2
- package/dist/technospam/pages/ApplicationsPortfolioPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +97 -235
- package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js +1 -1
- package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +293 -202
- package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js +1 -1
- package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
- package/dist/technospam/pages/CoursesMyLearningPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/CoursesMyLearningPagePage.js +2 -2
- package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
- package/dist/technospam/pages/DashboardDashboardPagePage.js +1 -1
- package/dist/technospam/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js +1 -1
- package/dist/technospam/pages/HackathonsHackathonDetailsPagePage.js.map +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js +1 -1
- package/dist/technospam/pages/HackathonsHackathonsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js +1 -2
- package/dist/technospam/pages/MentorshipMentorProfilePagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js +1 -1
- package/dist/technospam/pages/MentorshipMentorsPagePage.js.map +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js +1 -1
- package/dist/technospam/pages/MentorshipSessionsPagePage.js.map +1 -1
- package/dist/technospam/pages/StudyPlannerStudyPlannerPagePage.d.ts.map +1 -1
- package/dist/technospam/pages/StudyPlannerStudyPlannerPagePage.js +180 -121
- package/dist/technospam/pages/StudyPlannerStudyPlannerPagePage.js.map +1 -1
- package/dist/test/setup.d.ts +2 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/package.json +9 -3
|
@@ -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.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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"}
|
|
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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StudyPlannerStudyPlannerPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/StudyPlannerStudyPlannerPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"StudyPlannerStudyPlannerPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/StudyPlannerStudyPlannerPagePage.tsx"],"names":[],"mappings":"AA6OA,wBAAgB,gCAAgC,gCAkJ/C"}
|
|
@@ -1,266 +1,325 @@
|
|
|
1
1
|
import { useTechnoSpamNavigate as e } from "../providers/TechnoSpamProvider.js";
|
|
2
2
|
import { PageLayout as t } from "../components/PageLayout.js";
|
|
3
3
|
import { StatCard as n } from "../components/StatCard.js";
|
|
4
|
-
import { formatDate as r } from "../utils/format.js";
|
|
5
|
-
import { StatusBadge as
|
|
6
|
-
import { EmptyView as
|
|
4
|
+
import { formatDate as r, formatDuration as i } from "../utils/format.js";
|
|
5
|
+
import { StatusBadge as a } from "../components/StatusBadge.js";
|
|
6
|
+
import { EmptyView as o, ErrorView as s, LoadingRows as c } from "../components/StateViews.js";
|
|
7
7
|
import "../components/index.js";
|
|
8
|
-
import { notify as
|
|
9
|
-
import { useArchiveStudyPlan as
|
|
10
|
-
import { useState as
|
|
11
|
-
import { Archive as
|
|
12
|
-
import { jsx as
|
|
13
|
-
import { Button as
|
|
14
|
-
import { nativeConfirm as
|
|
8
|
+
import { notify as l } from "../lib/toast.js";
|
|
9
|
+
import { useArchiveStudyPlan as u, useGenerateStudyPlan as d, useMyStudyPlansQuery as f, useUpdateStudyPlanStepStatus as p } from "../api/technospamApi.js";
|
|
10
|
+
import { useState as m } from "react";
|
|
11
|
+
import { Archive as h, ArrowUpRight as g, Calendar as _, CheckCircle2 as v, Circle as y, Clock as b, ListChecks as x, Sparkles as S, Target as C, Timer as w, TrendingUp as T } from "lucide-react";
|
|
12
|
+
import { jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
13
|
+
import { Button as O, GlassCard as k, Input as A } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { nativeConfirm as j } from "@burdenoff/fe-libs/shared/native";
|
|
15
15
|
//#region src/technospam/pages/StudyPlannerStudyPlannerPagePage.tsx
|
|
16
|
-
var
|
|
17
|
-
function
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
var M = 1, N = 52;
|
|
17
|
+
function P(e) {
|
|
18
|
+
return e.kind === "COURSE" ? `/courses/course-details-page?id=${e.targetId}` : `/applications/problem-details-page?id=${e.targetId}`;
|
|
19
|
+
}
|
|
20
|
+
function F(e) {
|
|
21
|
+
return e.steps.reduce((e, t) => e + t.estimatedMinutes, 0);
|
|
22
|
+
}
|
|
23
|
+
function I({ step: e, onMark: t, onOpen: n }) {
|
|
24
|
+
let r = e.status === "COMPLETED", o = e.status === "SKIPPED";
|
|
25
|
+
return /* @__PURE__ */ D("div", {
|
|
20
26
|
className: "flex flex-col gap-2 rounded-lg border border-border-seam bg-bg-surface p-3 sm:flex-row sm:items-start sm:justify-between",
|
|
21
|
-
children: [/* @__PURE__ */
|
|
27
|
+
children: [/* @__PURE__ */ D("div", {
|
|
22
28
|
className: "flex min-w-0 gap-3",
|
|
23
|
-
children: [/* @__PURE__ */
|
|
29
|
+
children: [/* @__PURE__ */ E("button", {
|
|
24
30
|
type: "button",
|
|
25
31
|
onClick: () => t("COMPLETED"),
|
|
26
|
-
disabled:
|
|
32
|
+
disabled: r,
|
|
27
33
|
className: "mt-0.5 shrink-0 text-text-muted transition-colors hover:text-status-success-text disabled:cursor-default",
|
|
28
|
-
"aria-label":
|
|
29
|
-
children:
|
|
34
|
+
"aria-label": r ? "Completed" : "Mark complete",
|
|
35
|
+
children: r ? /* @__PURE__ */ E(v, {
|
|
30
36
|
size: 18,
|
|
31
37
|
className: "text-status-success-text"
|
|
32
|
-
}) : /* @__PURE__ */
|
|
33
|
-
}), /* @__PURE__ */
|
|
38
|
+
}) : /* @__PURE__ */ E(y, { size: 18 })
|
|
39
|
+
}), /* @__PURE__ */ D("div", {
|
|
34
40
|
className: "min-w-0",
|
|
35
|
-
children: [/* @__PURE__ */
|
|
41
|
+
children: [/* @__PURE__ */ D("div", {
|
|
36
42
|
className: "flex flex-wrap items-center gap-2",
|
|
37
43
|
children: [
|
|
38
|
-
/* @__PURE__ */
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
/* @__PURE__ */ D("button", {
|
|
45
|
+
type: "button",
|
|
46
|
+
onClick: n,
|
|
47
|
+
className: `group inline-flex items-center gap-1 text-left text-sm font-medium transition-colors hover:text-accent-primary ${r || o ? "text-text-muted line-through" : "text-text-primary"}`,
|
|
48
|
+
children: [e.title, /* @__PURE__ */ E(g, {
|
|
49
|
+
size: 13,
|
|
50
|
+
"aria-hidden": !0,
|
|
51
|
+
className: "shrink-0 text-text-muted transition-colors group-hover:text-accent-primary"
|
|
52
|
+
})]
|
|
41
53
|
}),
|
|
42
|
-
/* @__PURE__ */
|
|
54
|
+
/* @__PURE__ */ E("span", {
|
|
43
55
|
className: "rounded-full border border-border-seam px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-text-muted",
|
|
44
56
|
children: e.kind
|
|
45
57
|
}),
|
|
46
|
-
/* @__PURE__ */
|
|
58
|
+
/* @__PURE__ */ D("span", {
|
|
47
59
|
className: "text-xs text-text-muted",
|
|
48
60
|
children: ["Week ", e.scheduledWeek]
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ D("span", {
|
|
63
|
+
className: "inline-flex items-center gap-1 text-xs text-text-muted",
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ E(b, { size: 11 }),
|
|
66
|
+
" ",
|
|
67
|
+
i(e.estimatedMinutes)
|
|
68
|
+
]
|
|
49
69
|
})
|
|
50
70
|
]
|
|
51
|
-
}), /* @__PURE__ */
|
|
71
|
+
}), /* @__PURE__ */ E("p", {
|
|
52
72
|
className: "mt-1 text-xs text-text-secondary",
|
|
53
73
|
children: e.rationale
|
|
54
74
|
})]
|
|
55
75
|
})]
|
|
56
|
-
}),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
}), /* @__PURE__ */ E("div", {
|
|
77
|
+
className: "flex shrink-0 items-center gap-2",
|
|
78
|
+
children: !r && !o ? /* @__PURE__ */ E(O, {
|
|
79
|
+
variant: "ghost",
|
|
80
|
+
size: "sm",
|
|
81
|
+
onClick: () => t("SKIPPED"),
|
|
82
|
+
children: "Skip"
|
|
83
|
+
}) : /* @__PURE__ */ E(a, { status: e.status })
|
|
84
|
+
})]
|
|
63
85
|
});
|
|
64
86
|
}
|
|
65
|
-
function
|
|
66
|
-
let [
|
|
67
|
-
await
|
|
87
|
+
function L({ plan: e, onArchived: t, onOpenStep: n }) {
|
|
88
|
+
let [o] = p(), [s, { loading: c }] = u(), [d, f] = m(e.status === "ACTIVE"), g = async (e, t) => {
|
|
89
|
+
await o({ variables: { input: {
|
|
68
90
|
stepId: e,
|
|
69
91
|
status: t
|
|
70
92
|
} } });
|
|
71
93
|
};
|
|
72
|
-
return /* @__PURE__ */
|
|
94
|
+
return /* @__PURE__ */ D(k, {
|
|
73
95
|
className: "space-y-4 p-4 sm:p-5",
|
|
74
96
|
children: [
|
|
75
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ D("div", {
|
|
76
98
|
className: "flex flex-wrap items-start justify-between gap-3",
|
|
77
|
-
children: [/* @__PURE__ */
|
|
99
|
+
children: [/* @__PURE__ */ D("div", {
|
|
78
100
|
className: "min-w-0",
|
|
79
|
-
children: [/* @__PURE__ */
|
|
101
|
+
children: [/* @__PURE__ */ D("div", {
|
|
80
102
|
className: "flex flex-wrap items-center gap-2",
|
|
81
103
|
children: [
|
|
82
|
-
/* @__PURE__ */
|
|
104
|
+
/* @__PURE__ */ E("h3", {
|
|
83
105
|
className: "text-sm font-semibold text-text-primary",
|
|
84
106
|
children: e.goal
|
|
85
107
|
}),
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
-
e.topic ? /* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ E(a, { status: e.status }),
|
|
109
|
+
e.topic ? /* @__PURE__ */ E("span", {
|
|
88
110
|
className: "rounded-full bg-accent-teal/15 px-2 py-0.5 text-[11px] font-medium text-accent-teal",
|
|
89
111
|
children: e.topic
|
|
90
112
|
}) : null
|
|
91
113
|
]
|
|
92
|
-
}), /* @__PURE__ */
|
|
114
|
+
}), /* @__PURE__ */ D("div", {
|
|
93
115
|
className: "mt-1 flex flex-wrap items-center gap-3 text-xs text-text-muted",
|
|
94
116
|
children: [
|
|
95
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ D("span", {
|
|
96
118
|
className: "inline-flex items-center gap-1",
|
|
97
119
|
children: [
|
|
98
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ E(_, { size: 12 }),
|
|
99
121
|
" ",
|
|
100
122
|
e.timeframeWeeks,
|
|
101
123
|
"-week plan"
|
|
102
124
|
]
|
|
103
125
|
}),
|
|
104
|
-
e.targetCompletionDate ? /* @__PURE__ */
|
|
126
|
+
e.targetCompletionDate ? /* @__PURE__ */ D("span", {
|
|
105
127
|
className: "inline-flex items-center gap-1",
|
|
106
128
|
children: [
|
|
107
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ E(b, { size: 12 }),
|
|
108
130
|
" target ",
|
|
109
131
|
r(e.targetCompletionDate)
|
|
110
132
|
]
|
|
111
133
|
}) : null,
|
|
112
|
-
/* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ D("span", {
|
|
113
135
|
className: "inline-flex items-center gap-1",
|
|
114
136
|
children: [
|
|
115
|
-
/* @__PURE__ */
|
|
137
|
+
/* @__PURE__ */ E(x, { size: 12 }),
|
|
116
138
|
" ",
|
|
139
|
+
e.progressPct,
|
|
140
|
+
"% · ",
|
|
117
141
|
e.completedSteps,
|
|
118
|
-
"
|
|
142
|
+
" of",
|
|
143
|
+
" ",
|
|
119
144
|
e.totalSteps,
|
|
120
|
-
" steps
|
|
145
|
+
" steps"
|
|
146
|
+
]
|
|
147
|
+
}),
|
|
148
|
+
/* @__PURE__ */ D("span", {
|
|
149
|
+
className: "inline-flex items-center gap-1",
|
|
150
|
+
children: [
|
|
151
|
+
/* @__PURE__ */ E(w, { size: 12 }),
|
|
152
|
+
" ",
|
|
153
|
+
i(F(e)),
|
|
154
|
+
" planned"
|
|
121
155
|
]
|
|
122
156
|
})
|
|
123
157
|
]
|
|
124
158
|
})]
|
|
125
|
-
}), /* @__PURE__ */
|
|
159
|
+
}), /* @__PURE__ */ D("div", {
|
|
126
160
|
className: "flex shrink-0 items-center gap-2",
|
|
127
|
-
children: [/* @__PURE__ */
|
|
161
|
+
children: [/* @__PURE__ */ E(O, {
|
|
128
162
|
variant: "ghost",
|
|
129
163
|
size: "sm",
|
|
130
|
-
onClick: () =>
|
|
131
|
-
children:
|
|
132
|
-
}), e.status === "ARCHIVED" ? null : /* @__PURE__ */
|
|
164
|
+
onClick: () => f((e) => !e),
|
|
165
|
+
children: d ? "Hide steps" : "Show steps"
|
|
166
|
+
}), e.status === "ARCHIVED" ? null : /* @__PURE__ */ D(O, {
|
|
133
167
|
variant: "outline",
|
|
134
168
|
size: "sm",
|
|
135
169
|
onClick: async () => {
|
|
136
|
-
await
|
|
170
|
+
await j({
|
|
137
171
|
title: "Archive plan",
|
|
138
172
|
message: `Archive the plan for "${e.goal}"? You can always generate a new one.`,
|
|
139
173
|
okButtonTitle: "Archive",
|
|
140
174
|
cancelButtonTitle: "Cancel"
|
|
141
|
-
}) && (await
|
|
175
|
+
}) && (await s({ variables: { id: e.id } })).data?.tecArchiveStudyPlan && (l.success("Plan archived"), t());
|
|
142
176
|
},
|
|
143
|
-
disabled:
|
|
144
|
-
children: [/* @__PURE__ */
|
|
177
|
+
disabled: c,
|
|
178
|
+
children: [/* @__PURE__ */ E(h, { size: 14 }), " Archive"]
|
|
145
179
|
})]
|
|
146
180
|
})]
|
|
147
181
|
}),
|
|
148
|
-
/* @__PURE__ */
|
|
182
|
+
/* @__PURE__ */ E("div", {
|
|
149
183
|
className: "h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken",
|
|
150
|
-
children: /* @__PURE__ */
|
|
184
|
+
children: /* @__PURE__ */ E("div", {
|
|
151
185
|
className: "h-full rounded-full bg-gradient-to-r from-accent-primary via-accent-indigo to-accent-purple transition-all duration-500",
|
|
152
186
|
style: { width: `${e.progressPct}%` }
|
|
153
187
|
})
|
|
154
188
|
}),
|
|
155
|
-
|
|
189
|
+
d ? /* @__PURE__ */ E("div", {
|
|
156
190
|
className: "space-y-2",
|
|
157
|
-
children: e.steps.map((e) => /* @__PURE__ */
|
|
191
|
+
children: e.steps.map((e) => /* @__PURE__ */ E(I, {
|
|
158
192
|
step: e,
|
|
159
|
-
onMark: (t) => void
|
|
193
|
+
onMark: (t) => void g(e.id, t),
|
|
194
|
+
onOpen: () => n(e)
|
|
160
195
|
}, e.id))
|
|
161
196
|
}) : null
|
|
162
197
|
]
|
|
163
198
|
});
|
|
164
199
|
}
|
|
165
|
-
function
|
|
166
|
-
let r = e(), { data:
|
|
167
|
-
return /* @__PURE__ */
|
|
200
|
+
function R() {
|
|
201
|
+
let r = e(), { data: a, loading: u, error: p, refetch: h } = f(), [g, { loading: _ }] = d(), [y, b] = m(""), [j, I] = m(""), [R, z] = m("4"), B = a?.tecMyStudyPlans?.items ?? [], V = B.filter((e) => e.status === "ACTIVE"), H = B.filter((e) => e.status !== "ARCHIVED"), U = H.reduce((e, t) => e + t.completedSteps, 0), W = H.reduce((e, t) => e + t.totalSteps, 0), G = H.reduce((e, t) => e + F(t), 0), K = B.filter((e) => e.status === "COMPLETED").length, q = (e) => r(P(e));
|
|
202
|
+
return /* @__PURE__ */ D(t, {
|
|
168
203
|
hero: !0,
|
|
169
204
|
title: "Study Planner",
|
|
170
205
|
description: "Tell us your goal and timeframe — we'll sequence real courses and practice problems for you, skipping what you've already done.",
|
|
171
|
-
actions: /* @__PURE__ */
|
|
206
|
+
actions: /* @__PURE__ */ D(O, {
|
|
172
207
|
variant: "outline",
|
|
173
208
|
onClick: () => r("/courses/courses-page"),
|
|
174
|
-
children: [/* @__PURE__ */
|
|
209
|
+
children: [/* @__PURE__ */ E(C, { size: 16 }), " Browse catalog"]
|
|
175
210
|
}),
|
|
176
211
|
children: [
|
|
177
|
-
/* @__PURE__ */
|
|
212
|
+
/* @__PURE__ */ D(k, {
|
|
178
213
|
className: "mb-6 space-y-4 p-4 sm:p-5",
|
|
179
|
-
children: [/* @__PURE__ */
|
|
214
|
+
children: [/* @__PURE__ */ D("div", {
|
|
180
215
|
className: "flex items-center gap-2",
|
|
181
|
-
children: [/* @__PURE__ */
|
|
216
|
+
children: [/* @__PURE__ */ E("span", {
|
|
182
217
|
className: "flex h-8 w-8 items-center justify-center rounded-lg bg-accent-primary/15 text-accent-primary",
|
|
183
|
-
children: /* @__PURE__ */ S
|
|
184
|
-
}), /* @__PURE__ */
|
|
218
|
+
children: /* @__PURE__ */ E(S, { size: 16 })
|
|
219
|
+
}), /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("h2", {
|
|
185
220
|
className: "text-sm font-semibold text-text-primary",
|
|
186
221
|
children: "Generate a plan"
|
|
187
|
-
}), /* @__PURE__ */
|
|
222
|
+
}), /* @__PURE__ */ E("p", {
|
|
188
223
|
className: "text-xs text-text-muted",
|
|
189
224
|
children: "Rule-based sequencing over the real catalog — not an AI/LLM feature."
|
|
190
225
|
})] })]
|
|
191
|
-
}), /* @__PURE__ */
|
|
226
|
+
}), /* @__PURE__ */ D("div", {
|
|
192
227
|
className: "grid grid-cols-1 gap-3 sm:grid-cols-[2fr_1fr_120px_auto]",
|
|
193
228
|
children: [
|
|
194
|
-
/* @__PURE__ */
|
|
195
|
-
value:
|
|
196
|
-
onChange: (e) =>
|
|
229
|
+
/* @__PURE__ */ E(A, {
|
|
230
|
+
value: y,
|
|
231
|
+
onChange: (e) => b(e.target.value),
|
|
197
232
|
placeholder: "Your goal, e.g. \"become a full-stack engineer\""
|
|
198
233
|
}),
|
|
199
|
-
/* @__PURE__ */
|
|
200
|
-
value:
|
|
201
|
-
onChange: (e) =>
|
|
234
|
+
/* @__PURE__ */ E(A, {
|
|
235
|
+
value: j,
|
|
236
|
+
onChange: (e) => I(e.target.value),
|
|
202
237
|
placeholder: "Topic (optional)"
|
|
203
238
|
}),
|
|
204
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ E(A, {
|
|
205
240
|
type: "number",
|
|
206
|
-
min:
|
|
207
|
-
max:
|
|
208
|
-
value:
|
|
209
|
-
onChange: (e) =>
|
|
241
|
+
min: M,
|
|
242
|
+
max: N,
|
|
243
|
+
value: R,
|
|
244
|
+
onChange: (e) => z(e.target.value),
|
|
210
245
|
placeholder: "Weeks"
|
|
211
246
|
}),
|
|
212
|
-
/* @__PURE__ */
|
|
247
|
+
/* @__PURE__ */ E(O, {
|
|
213
248
|
onClick: async () => {
|
|
214
|
-
let e =
|
|
215
|
-
if (!e) return
|
|
216
|
-
let t = Math.min(
|
|
249
|
+
let e = y.trim();
|
|
250
|
+
if (!e) return l.error("Describe your goal first", "e.g. \"become a full-stack engineer\"");
|
|
251
|
+
let t = Math.min(N, Math.max(M, Number.parseInt(R, 10) || 4)), n = await g({ variables: { input: {
|
|
217
252
|
goal: e,
|
|
218
|
-
topic:
|
|
253
|
+
topic: j.trim() || void 0,
|
|
219
254
|
timeframeWeeks: t
|
|
220
255
|
} } });
|
|
221
|
-
n.data?.tecGenerateStudyPlan && (
|
|
256
|
+
n.data?.tecGenerateStudyPlan && (l.success("Plan generated", `${n.data.tecGenerateStudyPlan.totalSteps} steps sequenced for you.`), b(""), I(""));
|
|
222
257
|
},
|
|
223
|
-
disabled:
|
|
224
|
-
children:
|
|
258
|
+
disabled: _,
|
|
259
|
+
children: _ ? "Generating…" : "Generate plan"
|
|
225
260
|
})
|
|
226
261
|
]
|
|
227
262
|
})]
|
|
228
263
|
}),
|
|
229
|
-
/* @__PURE__ */
|
|
230
|
-
className: "mb-
|
|
231
|
-
children: [
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
264
|
+
/* @__PURE__ */ D("div", {
|
|
265
|
+
className: "mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4",
|
|
266
|
+
children: [
|
|
267
|
+
/* @__PURE__ */ E(n, {
|
|
268
|
+
label: "Active plans",
|
|
269
|
+
value: V.length,
|
|
270
|
+
hint: "Plans currently in progress",
|
|
271
|
+
icon: x,
|
|
272
|
+
tone: "indigo"
|
|
273
|
+
}),
|
|
274
|
+
/* @__PURE__ */ E(n, {
|
|
275
|
+
label: "Steps completed",
|
|
276
|
+
value: `${U} / ${W}`,
|
|
277
|
+
hint: "Across your unarchived plans",
|
|
278
|
+
icon: v,
|
|
279
|
+
tone: "green"
|
|
280
|
+
}),
|
|
281
|
+
/* @__PURE__ */ E(n, {
|
|
282
|
+
label: "Time planned",
|
|
283
|
+
value: i(G),
|
|
284
|
+
hint: "Sum of every scheduled step",
|
|
285
|
+
icon: w,
|
|
286
|
+
tone: "teal"
|
|
287
|
+
}),
|
|
288
|
+
/* @__PURE__ */ E(n, {
|
|
289
|
+
label: "Plans completed",
|
|
290
|
+
value: K,
|
|
291
|
+
hint: "Every step reached a terminal state",
|
|
292
|
+
icon: T,
|
|
293
|
+
tone: "purple"
|
|
294
|
+
})
|
|
295
|
+
]
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ E("h2", {
|
|
298
|
+
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
299
|
+
children: "Your plans"
|
|
242
300
|
}),
|
|
243
|
-
|
|
301
|
+
u && !B.length ? /* @__PURE__ */ E(c, {
|
|
244
302
|
count: 2,
|
|
245
303
|
height: "h-32"
|
|
246
|
-
}) :
|
|
304
|
+
}) : p ? /* @__PURE__ */ E(s, {
|
|
247
305
|
title: "Couldn't load your study plans",
|
|
248
|
-
error:
|
|
249
|
-
}) :
|
|
250
|
-
icon: /* @__PURE__ */ S
|
|
306
|
+
error: p
|
|
307
|
+
}) : B.length === 0 ? /* @__PURE__ */ E(o, {
|
|
308
|
+
icon: /* @__PURE__ */ E(S, { size: 26 }),
|
|
251
309
|
title: "No study plans yet",
|
|
252
310
|
description: "Describe a goal above and we'll sequence a plan from the real course and practice catalog."
|
|
253
|
-
}) : /* @__PURE__ */
|
|
311
|
+
}) : /* @__PURE__ */ E("div", {
|
|
254
312
|
className: "space-y-4",
|
|
255
|
-
children:
|
|
313
|
+
children: B.map((e) => /* @__PURE__ */ E(L, {
|
|
256
314
|
plan: e,
|
|
257
|
-
onArchived: () => void
|
|
315
|
+
onArchived: () => void h(),
|
|
316
|
+
onOpenStep: q
|
|
258
317
|
}, e.id))
|
|
259
318
|
})
|
|
260
319
|
]
|
|
261
320
|
});
|
|
262
321
|
}
|
|
263
322
|
//#endregion
|
|
264
|
-
export {
|
|
323
|
+
export { R as StudyPlannerStudyPlannerPagePage };
|
|
265
324
|
|
|
266
325
|
//# sourceMappingURL=StudyPlannerStudyPlannerPagePage.js.map
|