@burdenoff/microfe-technospam 2026.720.1 → 2026.730.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/technospam/TechnoSpamRoot.d.ts.map +1 -1
  2. package/dist/technospam/TechnoSpamRoot.js +174 -212
  3. package/dist/technospam/TechnoSpamRoot.js.map +1 -1
  4. package/dist/technospam/TechnoSpamRoutes.d.ts.map +1 -1
  5. package/dist/technospam/TechnoSpamRoutes.js +31 -30
  6. package/dist/technospam/TechnoSpamRoutes.js.map +1 -1
  7. package/dist/technospam/api/technospamApi.d.ts +166 -0
  8. package/dist/technospam/api/technospamApi.d.ts.map +1 -1
  9. package/dist/technospam/api/technospamApi.js +336 -147
  10. package/dist/technospam/api/technospamApi.js.map +1 -1
  11. package/dist/technospam/components/UpgradeGate.d.ts +24 -0
  12. package/dist/technospam/components/UpgradeGate.d.ts.map +1 -0
  13. package/dist/technospam/components/UpgradeGate.js +47 -0
  14. package/dist/technospam/components/UpgradeGate.js.map +1 -0
  15. package/dist/technospam/components/index.d.ts +1 -0
  16. package/dist/technospam/components/index.d.ts.map +1 -1
  17. package/dist/technospam/components/index.js +1 -0
  18. package/dist/technospam/pages/ApplicationsPortfolioPagePage.d.ts +2 -0
  19. package/dist/technospam/pages/ApplicationsPortfolioPagePage.d.ts.map +1 -0
  20. package/dist/technospam/pages/ApplicationsPortfolioPagePage.js +275 -0
  21. package/dist/technospam/pages/ApplicationsPortfolioPagePage.js.map +1 -0
  22. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.d.ts.map +1 -1
  23. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +380 -168
  24. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
  25. package/dist/technospam/pages/ApplicationsProblemsPagePage.d.ts.map +1 -1
  26. package/dist/technospam/pages/ApplicationsProblemsPagePage.js +81 -77
  27. package/dist/technospam/pages/ApplicationsProblemsPagePage.js.map +1 -1
  28. package/dist/technospam/pages/CoursesCourseDetailsPagePage.d.ts.map +1 -1
  29. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +200 -178
  30. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
  31. package/dist/technospam/pages/CoursesCoursesPagePage.d.ts.map +1 -1
  32. package/dist/technospam/pages/CoursesCoursesPagePage.js +66 -62
  33. package/dist/technospam/pages/CoursesCoursesPagePage.js.map +1 -1
  34. package/dist/technospam/pages/StudyPlannerStudyPlannerPagePage.d.ts +2 -0
  35. package/dist/technospam/pages/StudyPlannerStudyPlannerPagePage.d.ts.map +1 -0
  36. package/dist/technospam/pages/StudyPlannerStudyPlannerPagePage.js +266 -0
  37. package/dist/technospam/pages/StudyPlannerStudyPlannerPagePage.js.map +1 -0
  38. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"technospamApi.js","names":[],"sources":["../../../src/technospam/api/technospamApi.ts"],"sourcesContent":["/**\n * TechnoSpam data layer — Apollo operations + typed hooks over the\n * wspace-technospam-svc subgraph (Tec* fields), reached through the host\n * shell's default workspace ApolloProvider (defaultGateway: \"workspace\").\n *\n * Every page consumes real backend data through these hooks. There is NO mock\n * data. List queries are cursor-paginated: page 1 omits `cursor` entirely\n * (passing cursor: null makes the Prisma cursor resolver 500), \"load more\"\n * passes the previous page's `pageInfo.cursor`.\n */\nimport { useState } from 'react';\nimport { gql, type ErrorLike } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\n\nimport { notify } from '../lib/toast';\n\n/* ------------------------------------------------------------------ enums */\n\nexport type TecCourseLevel = 'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED' | 'EXPERT';\nexport type TecCourseStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\nexport type TecLessonKind = 'VIDEO' | 'ARTICLE' | 'INTERACTIVE' | 'QUIZ' | 'PROJECT';\nexport type TecEnrollmentStatus = 'ENROLLED' | 'IN_PROGRESS' | 'COMPLETED' | 'DROPPED';\nexport type TecCertificateStatus = 'ISSUED' | 'REVOKED';\nexport type TecProblemDifficulty = 'EASY' | 'MEDIUM' | 'HARD';\nexport type TecProblemStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\nexport type TecInterviewFrequency = 'LOW' | 'MEDIUM' | 'HIGH';\nexport type TecSubmissionVerdict =\n | 'PENDING'\n | 'ACCEPTED'\n | 'WRONG_ANSWER'\n | 'TIME_LIMIT_EXCEEDED'\n | 'RUNTIME_ERROR'\n | 'COMPILE_ERROR';\nexport type TecMentorStatus = 'PENDING' | 'ACTIVE' | 'PAUSED' | 'INACTIVE';\nexport type TecSessionStatus = 'REQUESTED' | 'CONFIRMED' | 'COMPLETED' | 'CANCELLED' | 'NO_SHOW';\nexport type TecHackathonStatus =\n 'DRAFT' | 'REGISTRATION_OPEN' | 'IN_PROGRESS' | 'JUDGING' | 'COMPLETED' | 'CANCELLED';\nexport type TecTeamSubmissionStatus = 'DRAFT' | 'SUBMITTED' | 'DISQUALIFIED' | 'WINNER';\n\n/* ------------------------------------------------------------------ types */\n\nexport interface TecCourse {\n id: string;\n slug: string;\n title: string;\n summary?: string | null;\n topic?: string | null;\n level: TecCourseLevel;\n status: TecCourseStatus;\n tags: string[];\n estimatedMinutes: number;\n instructorId?: string | null;\n publishedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n lessons?: TecLesson[];\n enrollments?: TecEnrollment[];\n}\n\nexport interface TecLesson {\n id: string;\n courseId: string;\n title: string;\n kind: TecLessonKind;\n content?: string | null;\n position: number;\n estimatedMinutes: number;\n isPreview: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface TecEnrollment {\n id: string;\n courseId: string;\n learnerId: string;\n status: TecEnrollmentStatus;\n progressPct: number;\n lessonsCompleted: number;\n startedAt: string;\n lastActiveAt?: string | null;\n completedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n course?: TecCourse | null;\n}\n\nexport interface TecCertificate {\n id: string;\n courseId: string;\n learnerId: string;\n serial: string;\n score: number;\n status: TecCertificateStatus;\n issuedAt: string;\n revokedAt?: string | null;\n revokeReason?: string | null;\n createdAt: string;\n course?: TecCourse | null;\n}\n\nexport interface TecProblem {\n id: string;\n slug: string;\n title: string;\n statement?: string | null;\n topic?: string | null;\n difficulty: TecProblemDifficulty;\n status: TecProblemStatus;\n tags: string[];\n languages: string[];\n companies: string[];\n roles: string[];\n interviewFrequency?: TecInterviewFrequency | null;\n points: number;\n starterCode?: string | null;\n publishedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n submissions?: TecSubmission[];\n}\n\nexport interface TecSubmission {\n id: string;\n problemId: string;\n learnerId: string;\n language: string;\n code: string;\n verdict: TecSubmissionVerdict;\n runtimeMs: number;\n pointsAwarded: number;\n judgedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n problem?: TecProblem | null;\n}\n\nexport interface TecMentor {\n id: string;\n userId: string;\n headline: string;\n role?: string | null;\n bio?: string | null;\n expertise: string[];\n hourlyRate: number;\n currency: string;\n status: TecMentorStatus;\n isAcceptingMentees: boolean;\n ratingAvg: number;\n sessionsCount: number;\n createdAt: string;\n updatedAt: string;\n sessions?: TecMentorSession[];\n}\n\nexport interface TecMentorSession {\n id: string;\n mentorId: string;\n menteeId: string;\n topic: string;\n agenda?: string | null;\n scheduledAt: string;\n durationMinutes: number;\n status: TecSessionStatus;\n meetingUrl?: string | null;\n rating?: number | null;\n feedback?: string | null;\n completedAt?: string | null;\n cancelledAt?: string | null;\n createdAt: string;\n updatedAt: string;\n mentor?: TecMentor | null;\n}\n\nexport interface TecHackathon {\n id: string;\n slug: string;\n title: string;\n theme?: string | null;\n description?: string | null;\n status: TecHackathonStatus;\n startAt: string;\n endAt: string;\n submissionDeadline?: string | null;\n prizePool: number;\n currency: string;\n maxTeamSize: number;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n teams?: TecHackathonTeam[];\n}\n\nexport interface TecHackathonTeam {\n id: string;\n hackathonId: string;\n name: string;\n captainId: string;\n memberIds: string[];\n projectName?: string | null;\n projectUrl?: string | null;\n repoUrl?: string | null;\n pitch?: string | null;\n status: TecTeamSubmissionStatus;\n score: number;\n submittedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n hackathon?: TecHackathon | null;\n}\n\nexport interface TecPageInfo {\n cursor?: string | null;\n hasMore: boolean;\n}\n\nexport interface PaginationInput {\n limit?: number;\n cursor?: string | null;\n}\n\n/** Build a pagination arg that NEVER sends cursor:null (page-1 500 guard). */\nexport function pageArg(limit = 50, cursor?: string | null): { limit: number; cursor?: string } {\n return cursor ? { limit, cursor } : { limit };\n}\n\n/* -------------------------------------------------------------- fragments */\n\nconst COURSE_FIELDS = gql`\n fragment CourseFields on TecCourse {\n id\n slug\n title\n summary\n topic\n level\n status\n tags\n estimatedMinutes\n instructorId\n publishedAt\n createdAt\n updatedAt\n }\n`;\n\nconst LESSON_FIELDS = gql`\n fragment LessonFields on TecLesson {\n id\n courseId\n title\n kind\n content\n position\n estimatedMinutes\n isPreview\n createdAt\n updatedAt\n }\n`;\n\nconst ENROLLMENT_FIELDS = gql`\n fragment EnrollmentFields on TecEnrollment {\n id\n courseId\n learnerId\n status\n progressPct\n lessonsCompleted\n startedAt\n lastActiveAt\n completedAt\n createdAt\n updatedAt\n }\n`;\n\nconst PROBLEM_FIELDS = gql`\n fragment ProblemFields on TecProblem {\n id\n slug\n title\n statement\n topic\n difficulty\n status\n tags\n languages\n companies\n roles\n interviewFrequency\n points\n starterCode\n publishedAt\n createdAt\n updatedAt\n }\n`;\n\nconst SUBMISSION_FIELDS = gql`\n fragment SubmissionFields on TecSubmission {\n id\n problemId\n learnerId\n language\n code\n verdict\n runtimeMs\n pointsAwarded\n judgedAt\n createdAt\n updatedAt\n }\n`;\n\nconst MENTOR_FIELDS = gql`\n fragment MentorFields on TecMentor {\n id\n userId\n headline\n role\n bio\n expertise\n hourlyRate\n currency\n status\n isAcceptingMentees\n ratingAvg\n sessionsCount\n createdAt\n updatedAt\n }\n`;\n\nconst SESSION_FIELDS = gql`\n fragment SessionFields on TecMentorSession {\n id\n mentorId\n menteeId\n topic\n agenda\n scheduledAt\n durationMinutes\n status\n meetingUrl\n rating\n feedback\n completedAt\n cancelledAt\n createdAt\n updatedAt\n }\n`;\n\nconst HACKATHON_FIELDS = gql`\n fragment HackathonFields on TecHackathon {\n id\n slug\n title\n theme\n description\n status\n startAt\n endAt\n submissionDeadline\n prizePool\n currency\n maxTeamSize\n tags\n createdAt\n updatedAt\n }\n`;\n\nconst TEAM_FIELDS = gql`\n fragment TeamFields on TecHackathonTeam {\n id\n hackathonId\n name\n captainId\n memberIds\n projectName\n projectUrl\n repoUrl\n pitch\n status\n score\n submittedAt\n createdAt\n updatedAt\n }\n`;\n\nconst CERTIFICATE_FIELDS = gql`\n fragment CertificateFields on TecCertificate {\n id\n courseId\n learnerId\n serial\n score\n status\n issuedAt\n revokedAt\n revokeReason\n createdAt\n }\n`;\n\n/* --------------------------------------------------------------- queries */\n\nconst LIST_COURSES = gql`\n ${COURSE_FIELDS}\n query TecListCourses(\n $level: TecCourseLevel\n $status: TecCourseStatus\n $pagination: PaginationInput\n ) {\n tecListCourses(level: $level, status: $status, pagination: $pagination) {\n items {\n ...CourseFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_COURSE = gql`\n ${COURSE_FIELDS}\n ${LESSON_FIELDS}\n ${ENROLLMENT_FIELDS}\n query TecCourse($id: ID!) {\n tecCourse(id: $id) {\n ...CourseFields\n lessons {\n ...LessonFields\n }\n enrollments {\n ...EnrollmentFields\n }\n }\n }\n`;\n\nconst LIST_ENROLLMENTS = gql`\n ${ENROLLMENT_FIELDS}\n ${COURSE_FIELDS}\n query TecListEnrollments(\n $learnerId: ID\n $courseId: ID\n $pagination: PaginationInput\n $startDate: DateTime\n $endDate: DateTime\n ) {\n tecListEnrollments(\n learnerId: $learnerId\n courseId: $courseId\n pagination: $pagination\n startDate: $startDate\n endDate: $endDate\n ) {\n items {\n ...EnrollmentFields\n course {\n ...CourseFields\n }\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_CERTIFICATES = gql`\n ${CERTIFICATE_FIELDS}\n ${COURSE_FIELDS}\n query TecListCertificates($learnerId: ID, $courseId: ID) {\n tecListCertificates(learnerId: $learnerId, courseId: $courseId) {\n ...CertificateFields\n course {\n ...CourseFields\n }\n }\n }\n`;\n\nconst LIST_PROBLEMS = gql`\n ${PROBLEM_FIELDS}\n query TecListProblems(\n $difficulty: TecProblemDifficulty\n $status: TecProblemStatus\n $topic: String\n $company: String\n $role: String\n $interviewFrequency: TecInterviewFrequency\n $pagination: PaginationInput\n ) {\n tecListProblems(\n difficulty: $difficulty\n status: $status\n topic: $topic\n company: $company\n role: $role\n interviewFrequency: $interviewFrequency\n pagination: $pagination\n ) {\n items {\n ...ProblemFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_PROBLEM = gql`\n ${PROBLEM_FIELDS}\n ${SUBMISSION_FIELDS}\n query TecProblem($id: ID!) {\n tecProblem(id: $id) {\n ...ProblemFields\n submissions {\n ...SubmissionFields\n }\n }\n }\n`;\n\nconst LIST_SUBMISSIONS = gql`\n ${SUBMISSION_FIELDS}\n ${PROBLEM_FIELDS}\n query TecListSubmissions(\n $learnerId: ID\n $problemId: ID\n $pagination: PaginationInput\n $startDate: DateTime\n $endDate: DateTime\n ) {\n tecListSubmissions(\n learnerId: $learnerId\n problemId: $problemId\n pagination: $pagination\n startDate: $startDate\n endDate: $endDate\n ) {\n items {\n ...SubmissionFields\n problem {\n ...ProblemFields\n }\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_MENTORS = gql`\n ${MENTOR_FIELDS}\n query TecListMentors($status: TecMentorStatus, $pagination: PaginationInput) {\n tecListMentors(status: $status, pagination: $pagination) {\n items {\n ...MentorFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_MENTOR = gql`\n ${MENTOR_FIELDS}\n ${SESSION_FIELDS}\n query TecMentor($id: ID!) {\n tecMentor(id: $id) {\n ...MentorFields\n sessions {\n ...SessionFields\n }\n }\n }\n`;\n\nconst LIST_SESSIONS = gql`\n ${SESSION_FIELDS}\n ${MENTOR_FIELDS}\n query TecListSessions(\n $mentorId: ID\n $menteeId: ID\n $status: TecSessionStatus\n $pagination: PaginationInput\n ) {\n tecListSessions(\n mentorId: $mentorId\n menteeId: $menteeId\n status: $status\n pagination: $pagination\n ) {\n items {\n ...SessionFields\n mentor {\n ...MentorFields\n }\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_HACKATHONS = gql`\n ${HACKATHON_FIELDS}\n query TecListHackathons($status: TecHackathonStatus, $pagination: PaginationInput) {\n tecListHackathons(status: $status, pagination: $pagination) {\n items {\n ...HackathonFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n ${TEAM_FIELDS}\n query TecHackathon($id: ID!) {\n tecHackathon(id: $id) {\n ...HackathonFields\n teams {\n ...TeamFields\n }\n }\n }\n`;\n\nconst LIST_TEAMS = gql`\n ${TEAM_FIELDS}\n query TecListTeams($hackathonId: ID!, $pagination: PaginationInput) {\n tecListTeams(hackathonId: $hackathonId, pagination: $pagination) {\n items {\n ...TeamFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_LESSONS = gql`\n ${LESSON_FIELDS}\n query TecListLessons($courseId: ID!, $pagination: PaginationInput) {\n tecListLessons(courseId: $courseId, pagination: $pagination) {\n items {\n ...LessonFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\n/* ------------------------------------------------------- response typings */\n\ntype Conn<K extends string, T> = Record<K, { items: T[]; pageInfo: TecPageInfo }>;\n\n/* ---------------------------------------------------------- query hooks */\n\nexport const useCoursesQuery = (vars: {\n level?: TecCourseLevel;\n status?: TecCourseStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListCourses', TecCourse>>(LIST_COURSES, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useCourseQuery = (id: string) =>\n useQuery<{ tecCourse: TecCourse | null }>(GET_COURSE, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useEnrollmentsQuery = (vars: {\n learnerId?: string;\n courseId?: string;\n startDate?: string;\n endDate?: string;\n}) =>\n useQuery<Conn<'tecListEnrollments', TecEnrollment>>(LIST_ENROLLMENTS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useCertificatesQuery = (vars: { learnerId?: string; courseId?: string }) =>\n useQuery<{ tecListCertificates: TecCertificate[] }>(LIST_CERTIFICATES, {\n variables: vars,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useProblemsQuery = (vars: {\n difficulty?: TecProblemDifficulty;\n status?: TecProblemStatus;\n topic?: string;\n company?: string;\n role?: string;\n interviewFrequency?: TecInterviewFrequency;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListProblems', TecProblem>>(LIST_PROBLEMS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useProblemQuery = (id: string) =>\n useQuery<{ tecProblem: TecProblem | null }>(GET_PROBLEM, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useSubmissionsQuery = (vars: {\n learnerId?: string;\n problemId?: string;\n startDate?: string;\n endDate?: string;\n}) =>\n useQuery<Conn<'tecListSubmissions', TecSubmission>>(LIST_SUBMISSIONS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useMentorsQuery = (vars: {\n status?: TecMentorStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListMentors', TecMentor>>(LIST_MENTORS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useMentorQuery = (id: string) =>\n useQuery<{ tecMentor: TecMentor | null }>(GET_MENTOR, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useSessionsQuery = (vars: {\n mentorId?: string;\n menteeId?: string;\n status?: TecSessionStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListSessions', TecMentorSession>>(LIST_SESSIONS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useHackathonsQuery = (vars: {\n status?: TecHackathonStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListHackathons', TecHackathon>>(LIST_HACKATHONS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useHackathonQuery = (id: string) =>\n useQuery<{ tecHackathon: TecHackathon | null }>(GET_HACKATHON, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useTeamsQuery = (\n hackathonId: string,\n pagination?: { limit: number; cursor?: string }\n) =>\n useQuery<Conn<'tecListTeams', TecHackathonTeam>>(LIST_TEAMS, {\n variables: { hackathonId, pagination: pagination ?? pageArg(50) },\n skip: !hackathonId,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useLessonsQuery = (\n courseId: string,\n pagination?: { limit: number; cursor?: string }\n) =>\n useQuery<Conn<'tecListLessons', TecLesson>>(LIST_LESSONS, {\n variables: { courseId, pagination: pagination ?? pageArg(50) },\n skip: !courseId,\n fetchPolicy: 'cache-and-network',\n });\n\n/* ------------------------------------------------------------ mutations */\n\nconst onMutationError = (error: ErrorLike): void => {\n notify.error('Something went wrong', error.message || 'Please try again.');\n};\n\nconst REFETCH = {\n courses: 'TecListCourses',\n enrollments: 'TecListEnrollments',\n problems: 'TecListProblems',\n submissions: 'TecListSubmissions',\n mentors: 'TecListMentors',\n sessions: 'TecListSessions',\n hackathons: 'TecListHackathons',\n} as const;\n\nconst ENROLL = gql`\n ${ENROLLMENT_FIELDS}\n mutation TecEnroll($input: TecEnrollInput!) {\n tecEnroll(input: $input) {\n ...EnrollmentFields\n }\n }\n`;\n\nconst UPDATE_PROGRESS = gql`\n ${ENROLLMENT_FIELDS}\n mutation TecUpdateProgress($input: TecUpdateProgressInput!) {\n tecUpdateProgress(input: $input) {\n ...EnrollmentFields\n }\n }\n`;\n\nconst SUBMIT_SOLUTION = gql`\n ${SUBMISSION_FIELDS}\n mutation TecSubmitSolution($input: TecSubmitSolutionInput!) {\n tecSubmitSolution(input: $input) {\n ...SubmissionFields\n }\n }\n`;\n\nconst BOOK_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecBookSession($input: TecBookSessionInput!) {\n tecBookSession(input: $input) {\n ...SessionFields\n }\n }\n`;\n\nconst CANCEL_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecCancelSession($id: ID!) {\n tecCancelSession(id: $id) {\n ...SessionFields\n }\n }\n`;\n\nconst BECOME_MENTOR = gql`\n ${MENTOR_FIELDS}\n mutation TecBecomeMentor($input: TecCreateMentorInput!) {\n tecBecomeMentor(input: $input) {\n ...MentorFields\n }\n }\n`;\n\nconst REGISTER_TEAM = gql`\n ${TEAM_FIELDS}\n mutation TecRegisterTeam($input: TecRegisterTeamInput!) {\n tecRegisterTeam(input: $input) {\n ...TeamFields\n }\n }\n`;\n\nconst SUBMIT_PROJECT = gql`\n ${TEAM_FIELDS}\n mutation TecSubmitProject($input: TecSubmitProjectInput!) {\n tecSubmitProject(input: $input) {\n ...TeamFields\n }\n }\n`;\n\n/* ------- admin / authoring mutations ------- */\n\nconst CREATE_COURSE = gql`\n ${COURSE_FIELDS}\n mutation TecCreateCourse($input: TecCreateCourseInput!) {\n tecCreateCourse(input: $input) {\n ...CourseFields\n }\n }\n`;\n\nconst PUBLISH_COURSE = gql`\n ${COURSE_FIELDS}\n mutation TecPublishCourse($id: ID!) {\n tecPublishCourse(id: $id) {\n ...CourseFields\n }\n }\n`;\n\nconst ARCHIVE_COURSE = gql`\n mutation TecArchiveCourse($id: ID!) {\n tecArchiveCourse(id: $id)\n }\n`;\n\nconst CREATE_LESSON = gql`\n ${LESSON_FIELDS}\n mutation TecCreateLesson($input: TecCreateLessonInput!) {\n tecCreateLesson(input: $input) {\n ...LessonFields\n }\n }\n`;\n\nconst CREATE_PROBLEM = gql`\n ${PROBLEM_FIELDS}\n mutation TecCreateProblem($input: TecCreateProblemInput!) {\n tecCreateProblem(input: $input) {\n ...ProblemFields\n }\n }\n`;\n\nconst PUBLISH_PROBLEM = gql`\n ${PROBLEM_FIELDS}\n mutation TecPublishProblem($id: ID!) {\n tecPublishProblem(id: $id) {\n ...ProblemFields\n }\n }\n`;\n\nconst CREATE_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n mutation TecCreateHackathon($input: TecCreateHackathonInput!) {\n tecCreateHackathon(input: $input) {\n ...HackathonFields\n }\n }\n`;\n\nconst OPEN_REGISTRATION = gql`\n ${HACKATHON_FIELDS}\n mutation TecOpenRegistration($id: ID!) {\n tecOpenRegistration(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\nconst APPROVE_MENTOR = gql`\n ${MENTOR_FIELDS}\n mutation TecApproveMentor($id: ID!) {\n tecApproveMentor(id: $id) {\n ...MentorFields\n }\n }\n`;\n\nconst SCORE_TEAM = gql`\n ${TEAM_FIELDS}\n mutation TecScoreTeam($id: ID!, $score: Int!, $winner: Boolean) {\n tecScoreTeam(id: $id, score: $score, winner: $winner) {\n ...TeamFields\n }\n }\n`;\n\nconst CONFIRM_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecConfirmSession($id: ID!, $meetingUrl: String) {\n tecConfirmSession(id: $id, meetingUrl: $meetingUrl) {\n ...SessionFields\n }\n }\n`;\n\nconst COMPLETE_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecCompleteSession($id: ID!, $rating: Int, $feedback: String) {\n tecCompleteSession(id: $id, rating: $rating, feedback: $feedback) {\n ...SessionFields\n }\n }\n`;\n\nconst GRADE_SUBMISSION = gql`\n ${SUBMISSION_FIELDS}\n mutation TecGradeSubmission($id: ID!, $verdict: TecSubmissionVerdict!, $runtimeMs: Int) {\n tecGradeSubmission(id: $id, verdict: $verdict, runtimeMs: $runtimeMs) {\n ...SubmissionFields\n }\n }\n`;\n\nconst ISSUE_CERTIFICATE = gql`\n ${CERTIFICATE_FIELDS}\n mutation TecIssueCertificate($courseId: ID!, $learnerId: ID!, $score: Int!) {\n tecIssueCertificate(courseId: $courseId, learnerId: $learnerId, score: $score) {\n ...CertificateFields\n }\n }\n`;\n\nconst REVOKE_CERTIFICATE = gql`\n ${CERTIFICATE_FIELDS}\n mutation TecRevokeCertificate($id: ID!, $reason: String) {\n tecRevokeCertificate(id: $id, reason: $reason) {\n ...CertificateFields\n }\n }\n`;\n\nconst START_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n mutation TecStartHackathon($id: ID!) {\n tecStartHackathon(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\nconst START_JUDGING = gql`\n ${HACKATHON_FIELDS}\n mutation TecStartJudging($id: ID!) {\n tecStartJudging(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\nconst COMPLETE_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n mutation TecCompleteHackathon($id: ID!) {\n tecCompleteHackathon(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\n/* ---------------------------------------------------------- mutation hooks */\n\nexport const useEnroll = () =>\n useMutation<{ tecEnroll: TecEnrollment }>(ENROLL, {\n onError: onMutationError,\n refetchQueries: [REFETCH.enrollments, REFETCH.courses],\n });\n\nexport const useUpdateProgress = () =>\n useMutation<{ tecUpdateProgress: TecEnrollment }>(UPDATE_PROGRESS, {\n onError: onMutationError,\n refetchQueries: [REFETCH.enrollments],\n });\n\nexport const useSubmitSolution = () =>\n useMutation<{ tecSubmitSolution: TecSubmission }>(SUBMIT_SOLUTION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.submissions],\n });\n\nexport const useBookSession = () =>\n useMutation<{ tecBookSession: TecMentorSession }>(BOOK_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions, REFETCH.mentors],\n });\n\nexport const useCancelSession = () =>\n useMutation<{ tecCancelSession: TecMentorSession }>(CANCEL_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions],\n });\n\nexport const useBecomeMentor = () =>\n useMutation<{ tecBecomeMentor: TecMentor }>(BECOME_MENTOR, {\n onError: onMutationError,\n refetchQueries: [REFETCH.mentors],\n });\n\nexport const useRegisterTeam = () =>\n useMutation<{ tecRegisterTeam: TecHackathonTeam }>(REGISTER_TEAM, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useSubmitProject = () =>\n useMutation<{ tecSubmitProject: TecHackathonTeam }>(SUBMIT_PROJECT, {\n onError: onMutationError,\n });\n\nexport const useCreateCourse = () =>\n useMutation<{ tecCreateCourse: TecCourse }>(CREATE_COURSE, {\n onError: onMutationError,\n refetchQueries: [REFETCH.courses],\n });\n\nexport const usePublishCourse = () =>\n useMutation<{ tecPublishCourse: TecCourse }>(PUBLISH_COURSE, {\n onError: onMutationError,\n refetchQueries: [REFETCH.courses],\n });\n\nexport const useArchiveCourse = () =>\n useMutation<{ tecArchiveCourse: boolean }>(ARCHIVE_COURSE, {\n onError: onMutationError,\n refetchQueries: [REFETCH.courses],\n });\n\nexport const useCreateLesson = () =>\n useMutation<{ tecCreateLesson: TecLesson }>(CREATE_LESSON, { onError: onMutationError });\n\nexport const useCreateProblem = () =>\n useMutation<{ tecCreateProblem: TecProblem }>(CREATE_PROBLEM, {\n onError: onMutationError,\n refetchQueries: [REFETCH.problems],\n });\n\nexport const usePublishProblem = () =>\n useMutation<{ tecPublishProblem: TecProblem }>(PUBLISH_PROBLEM, {\n onError: onMutationError,\n refetchQueries: [REFETCH.problems],\n });\n\nexport const useCreateHackathon = () =>\n useMutation<{ tecCreateHackathon: TecHackathon }>(CREATE_HACKATHON, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useOpenRegistration = () =>\n useMutation<{ tecOpenRegistration: TecHackathon }>(OPEN_REGISTRATION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useApproveMentor = () =>\n useMutation<{ tecApproveMentor: TecMentor }>(APPROVE_MENTOR, {\n onError: onMutationError,\n refetchQueries: [REFETCH.mentors],\n });\n\nexport const useScoreTeam = () =>\n useMutation<{ tecScoreTeam: TecHackathonTeam }>(SCORE_TEAM, { onError: onMutationError });\n\nexport const useConfirmSession = () =>\n useMutation<{ tecConfirmSession: TecMentorSession }>(CONFIRM_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions],\n });\n\nexport const useCompleteSession = () =>\n useMutation<{ tecCompleteSession: TecMentorSession }>(COMPLETE_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions],\n });\n\nexport const useGradeSubmission = () =>\n useMutation<{ tecGradeSubmission: TecSubmission }>(GRADE_SUBMISSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.submissions],\n });\n\nexport const useIssueCertificate = () =>\n useMutation<{ tecIssueCertificate: TecCertificate }>(ISSUE_CERTIFICATE, {\n onError: onMutationError,\n });\n\nexport const useRevokeCertificate = () =>\n useMutation<{ tecRevokeCertificate: TecCertificate }>(REVOKE_CERTIFICATE, {\n onError: onMutationError,\n });\n\nexport const useStartHackathon = () =>\n useMutation<{ tecStartHackathon: TecHackathon }>(START_HACKATHON, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useStartJudging = () =>\n useMutation<{ tecStartJudging: TecHackathon }>(START_JUDGING, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useCompleteHackathon = () =>\n useMutation<{ tecCompleteHackathon: TecHackathon }>(COMPLETE_HACKATHON, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\n/* ------------------------------------------------------- pagination helper */\n\nexport interface PageLimit {\n limit: number;\n more: () => void;\n}\n\n/**\n * Simple, robust \"load more\". The backend paginates with `take = limit + 1`\n * (offset is ignored; only `cursor` shifts the window), so a larger `limit`\n * simply fetches more rows from the top and `pageInfo.hasMore` reports whether\n * still more exist. Growing the limit avoids cursor-merge/fetchMore complexity\n * and never sends `cursor: null` (the page-1 500 guard). Pass `limit` into the\n * query's `pageArg` and render <LoadMore hasMore={...} onClick={more} />.\n */\nexport function usePageLimit(step = 24, initial = 24): PageLimit {\n const [limit, setLimit] = useState(initial);\n return { limit, more: () => setLimit((l) => l + step) };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"technospamApi.js","names":[],"sources":["../../../src/technospam/api/technospamApi.ts"],"sourcesContent":["/**\n * TechnoSpam data layer — Apollo operations + typed hooks over the\n * wspace-technospam-svc subgraph (Tec* fields), reached through the host\n * shell's default workspace ApolloProvider (defaultGateway: \"workspace\").\n *\n * Every page consumes real backend data through these hooks. There is NO mock\n * data. List queries are cursor-paginated: page 1 omits `cursor` entirely\n * (passing cursor: null makes the Prisma cursor resolver 500), \"load more\"\n * passes the previous page's `pageInfo.cursor`.\n */\nimport { useState } from 'react';\nimport { gql, type ErrorLike } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\n\nimport { notify } from '../lib/toast';\n\n/* ------------------------------------------------------------------ enums */\n\nexport type TecCourseLevel = 'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED' | 'EXPERT';\nexport type TecCourseStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\nexport type TecLessonKind = 'VIDEO' | 'ARTICLE' | 'INTERACTIVE' | 'QUIZ' | 'PROJECT';\nexport type TecEnrollmentStatus = 'ENROLLED' | 'IN_PROGRESS' | 'COMPLETED' | 'DROPPED';\nexport type TecCertificateStatus = 'ISSUED' | 'REVOKED';\nexport type TecProblemDifficulty = 'EASY' | 'MEDIUM' | 'HARD';\nexport type TecProblemStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\nexport type TecInterviewFrequency = 'LOW' | 'MEDIUM' | 'HIGH';\nexport type TecSubmissionVerdict =\n | 'PENDING'\n | 'ACCEPTED'\n | 'WRONG_ANSWER'\n | 'TIME_LIMIT_EXCEEDED'\n | 'RUNTIME_ERROR'\n | 'COMPILE_ERROR';\nexport type TecMentorStatus = 'PENDING' | 'ACTIVE' | 'PAUSED' | 'INACTIVE';\nexport type TecSessionStatus = 'REQUESTED' | 'CONFIRMED' | 'COMPLETED' | 'CANCELLED' | 'NO_SHOW';\nexport type TecHackathonStatus =\n 'DRAFT' | 'REGISTRATION_OPEN' | 'IN_PROGRESS' | 'JUDGING' | 'COMPLETED' | 'CANCELLED';\nexport type TecTeamSubmissionStatus = 'DRAFT' | 'SUBMITTED' | 'DISQUALIFIED' | 'WINNER';\n\n/* ------------------------------------------------------------------ types */\n\nexport interface TecCourse {\n id: string;\n slug: string;\n title: string;\n summary?: string | null;\n topic?: string | null;\n level: TecCourseLevel;\n status: TecCourseStatus;\n tags: string[];\n estimatedMinutes: number;\n instructorId?: string | null;\n /** BOFF-4416: true when this course requires a paid TechnoSpam plan. */\n isPremiumOnly: boolean;\n /**\n * BOFF-4416: computed for the calling workspace — true when this course\n * is `isPremiumOnly` and the workspace has no paid plan. When true, every\n * non-preview lesson's `content` is already null in the API response.\n */\n isLocked: boolean;\n publishedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n lessons?: TecLesson[];\n enrollments?: TecEnrollment[];\n}\n\nexport interface TecLesson {\n id: string;\n courseId: string;\n title: string;\n kind: TecLessonKind;\n content?: string | null;\n position: number;\n estimatedMinutes: number;\n isPreview: boolean;\n /**\n * BOFF-4416: true when this lesson's `content` is gated behind a paid\n * TechnoSpam plan (never true for `isPreview` lessons). `content` is\n * already null in the API response whenever this is true.\n */\n isLocked: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface TecEnrollment {\n id: string;\n courseId: string;\n learnerId: string;\n status: TecEnrollmentStatus;\n progressPct: number;\n lessonsCompleted: number;\n startedAt: string;\n lastActiveAt?: string | null;\n completedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n course?: TecCourse | null;\n}\n\nexport interface TecCertificate {\n id: string;\n courseId: string;\n learnerId: string;\n serial: string;\n score: number;\n status: TecCertificateStatus;\n issuedAt: string;\n revokedAt?: string | null;\n revokeReason?: string | null;\n createdAt: string;\n course?: TecCourse | null;\n}\n\nexport interface TecProblem {\n id: string;\n slug: string;\n title: string;\n statement?: string | null;\n topic?: string | null;\n difficulty: TecProblemDifficulty;\n status: TecProblemStatus;\n tags: string[];\n languages: string[];\n companies: string[];\n roles: string[];\n interviewFrequency?: TecInterviewFrequency | null;\n points: number;\n starterCode?: string | null;\n /** BOFF-4416: true when this problem requires a paid TechnoSpam plan. */\n isPremiumOnly: boolean;\n /**\n * BOFF-4416: computed for the calling workspace — true when this problem\n * is `isPremiumOnly` and the workspace has no paid plan. `statement` /\n * `starterCode` are already null and `publicTestCases` already empty in\n * the API response whenever this is true.\n */\n isLocked: boolean;\n publishedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n submissions?: TecSubmission[];\n /** Worked-example fixtures the grader runs against; PUBLIC cases only. */\n publicTestCases?: TecProblemTestCase[];\n}\n\n/** Visibility of a problem test case. Mirrors TecTestCaseVisibility. */\nexport type TecTestCaseVisibility = 'PUBLIC' | 'HIDDEN';\n\n/** Per-test-case outcome of a graded submission. Mirrors TecTestCaseStatus. */\nexport type TecTestCaseStatus =\n 'PASSED' | 'WRONG_ANSWER' | 'RUNTIME_ERROR' | 'TIME_LIMIT_EXCEEDED' | 'COMPILE_ERROR' | 'SKIPPED';\n\n/**\n * A worked-example fixture shown on the problem page. Only PUBLIC cases are\n * ever returned to a learner, so `input`/`expectedOutput` are always present\n * in practice; they stay optional because the schema allows null for the\n * author-facing redacted shape.\n */\nexport interface TecProblemTestCase {\n id: string;\n problemId: string;\n name: string;\n ordering: number;\n visibility: TecTestCaseVisibility;\n timeLimitMs: number;\n input?: string | null;\n expectedOutput?: string | null;\n}\n\n/** Grading detail for one test case of a submission. */\nexport interface TecTestCaseResult {\n testCaseId: string;\n name: string;\n visibility: TecTestCaseVisibility;\n status: TecTestCaseStatus;\n passed: boolean;\n durationMs: number;\n input?: string | null;\n expectedOutput?: string | null;\n actualOutput?: string | null;\n}\n\nexport interface TecSubmission {\n id: string;\n problemId: string;\n learnerId: string;\n language: string;\n code: string;\n verdict: TecSubmissionVerdict;\n runtimeMs: number;\n pointsAwarded: number;\n passedCount: number;\n totalCount: number;\n stderr?: string | null;\n testResults: TecTestCaseResult[];\n judgedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n problem?: TecProblem | null;\n}\n\nexport interface TecMentor {\n id: string;\n userId: string;\n headline: string;\n role?: string | null;\n bio?: string | null;\n expertise: string[];\n hourlyRate: number;\n currency: string;\n status: TecMentorStatus;\n isAcceptingMentees: boolean;\n ratingAvg: number;\n sessionsCount: number;\n createdAt: string;\n updatedAt: string;\n sessions?: TecMentorSession[];\n}\n\nexport interface TecMentorSession {\n id: string;\n mentorId: string;\n menteeId: string;\n topic: string;\n agenda?: string | null;\n scheduledAt: string;\n durationMinutes: number;\n status: TecSessionStatus;\n meetingUrl?: string | null;\n rating?: number | null;\n feedback?: string | null;\n completedAt?: string | null;\n cancelledAt?: string | null;\n createdAt: string;\n updatedAt: string;\n mentor?: TecMentor | null;\n}\n\nexport interface TecHackathon {\n id: string;\n slug: string;\n title: string;\n theme?: string | null;\n description?: string | null;\n status: TecHackathonStatus;\n startAt: string;\n endAt: string;\n submissionDeadline?: string | null;\n prizePool: number;\n currency: string;\n maxTeamSize: number;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n teams?: TecHackathonTeam[];\n}\n\nexport interface TecHackathonTeam {\n id: string;\n hackathonId: string;\n name: string;\n captainId: string;\n memberIds: string[];\n projectName?: string | null;\n projectUrl?: string | null;\n repoUrl?: string | null;\n pitch?: string | null;\n status: TecTeamSubmissionStatus;\n score: number;\n submittedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n hackathon?: TecHackathon | null;\n}\n\nexport interface TecPageInfo {\n cursor?: string | null;\n hasMore: boolean;\n}\n\nexport interface PaginationInput {\n limit?: number;\n cursor?: string | null;\n}\n\n/** Build a pagination arg that NEVER sends cursor:null (page-1 500 guard). */\nexport function pageArg(limit = 50, cursor?: string | null): { limit: number; cursor?: string } {\n return cursor ? { limit, cursor } : { limit };\n}\n\n/* -------------------------------------------------------------- fragments */\n\nconst COURSE_FIELDS = gql`\n fragment CourseFields on TecCourse {\n id\n slug\n title\n summary\n topic\n level\n status\n tags\n estimatedMinutes\n instructorId\n isPremiumOnly\n isLocked\n publishedAt\n createdAt\n updatedAt\n }\n`;\n\nconst LESSON_FIELDS = gql`\n fragment LessonFields on TecLesson {\n id\n courseId\n title\n kind\n content\n position\n estimatedMinutes\n isPreview\n isLocked\n createdAt\n updatedAt\n }\n`;\n\nconst ENROLLMENT_FIELDS = gql`\n fragment EnrollmentFields on TecEnrollment {\n id\n courseId\n learnerId\n status\n progressPct\n lessonsCompleted\n startedAt\n lastActiveAt\n completedAt\n createdAt\n updatedAt\n }\n`;\n\nconst PROBLEM_FIELDS = gql`\n fragment ProblemFields on TecProblem {\n id\n slug\n title\n statement\n topic\n difficulty\n status\n tags\n languages\n companies\n roles\n interviewFrequency\n points\n starterCode\n isPremiumOnly\n isLocked\n publishedAt\n createdAt\n updatedAt\n }\n`;\n\nconst SUBMISSION_FIELDS = gql`\n fragment SubmissionFields on TecSubmission {\n id\n problemId\n learnerId\n language\n code\n verdict\n runtimeMs\n pointsAwarded\n passedCount\n totalCount\n stderr\n testResults {\n testCaseId\n name\n visibility\n status\n passed\n durationMs\n input\n expectedOutput\n actualOutput\n }\n judgedAt\n createdAt\n updatedAt\n }\n`;\n\nconst PROBLEM_TEST_CASE_FIELDS = gql`\n fragment ProblemTestCaseFields on TecProblemTestCase {\n id\n problemId\n name\n ordering\n visibility\n timeLimitMs\n input\n expectedOutput\n }\n`;\n\nconst MENTOR_FIELDS = gql`\n fragment MentorFields on TecMentor {\n id\n userId\n headline\n role\n bio\n expertise\n hourlyRate\n currency\n status\n isAcceptingMentees\n ratingAvg\n sessionsCount\n createdAt\n updatedAt\n }\n`;\n\nconst SESSION_FIELDS = gql`\n fragment SessionFields on TecMentorSession {\n id\n mentorId\n menteeId\n topic\n agenda\n scheduledAt\n durationMinutes\n status\n meetingUrl\n rating\n feedback\n completedAt\n cancelledAt\n createdAt\n updatedAt\n }\n`;\n\nconst HACKATHON_FIELDS = gql`\n fragment HackathonFields on TecHackathon {\n id\n slug\n title\n theme\n description\n status\n startAt\n endAt\n submissionDeadline\n prizePool\n currency\n maxTeamSize\n tags\n createdAt\n updatedAt\n }\n`;\n\nconst TEAM_FIELDS = gql`\n fragment TeamFields on TecHackathonTeam {\n id\n hackathonId\n name\n captainId\n memberIds\n projectName\n projectUrl\n repoUrl\n pitch\n status\n score\n submittedAt\n createdAt\n updatedAt\n }\n`;\n\nconst CERTIFICATE_FIELDS = gql`\n fragment CertificateFields on TecCertificate {\n id\n courseId\n learnerId\n serial\n score\n status\n issuedAt\n revokedAt\n revokeReason\n createdAt\n }\n`;\n\n/* --------------------------------------------------------------- queries */\n\nconst LIST_COURSES = gql`\n ${COURSE_FIELDS}\n query TecListCourses(\n $level: TecCourseLevel\n $status: TecCourseStatus\n $pagination: PaginationInput\n ) {\n tecListCourses(level: $level, status: $status, pagination: $pagination) {\n items {\n ...CourseFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_COURSE = gql`\n ${COURSE_FIELDS}\n ${LESSON_FIELDS}\n ${ENROLLMENT_FIELDS}\n query TecCourse($id: ID!) {\n tecCourse(id: $id) {\n ...CourseFields\n lessons {\n ...LessonFields\n }\n enrollments {\n ...EnrollmentFields\n }\n }\n }\n`;\n\nconst LIST_ENROLLMENTS = gql`\n ${ENROLLMENT_FIELDS}\n ${COURSE_FIELDS}\n query TecListEnrollments(\n $learnerId: ID\n $courseId: ID\n $pagination: PaginationInput\n $startDate: DateTime\n $endDate: DateTime\n ) {\n tecListEnrollments(\n learnerId: $learnerId\n courseId: $courseId\n pagination: $pagination\n startDate: $startDate\n endDate: $endDate\n ) {\n items {\n ...EnrollmentFields\n course {\n ...CourseFields\n }\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_CERTIFICATES = gql`\n ${CERTIFICATE_FIELDS}\n ${COURSE_FIELDS}\n query TecListCertificates($learnerId: ID, $courseId: ID) {\n tecListCertificates(learnerId: $learnerId, courseId: $courseId) {\n ...CertificateFields\n course {\n ...CourseFields\n }\n }\n }\n`;\n\nconst LIST_PROBLEMS = gql`\n ${PROBLEM_FIELDS}\n query TecListProblems(\n $difficulty: TecProblemDifficulty\n $status: TecProblemStatus\n $topic: String\n $company: String\n $role: String\n $interviewFrequency: TecInterviewFrequency\n $pagination: PaginationInput\n ) {\n tecListProblems(\n difficulty: $difficulty\n status: $status\n topic: $topic\n company: $company\n role: $role\n interviewFrequency: $interviewFrequency\n pagination: $pagination\n ) {\n items {\n ...ProblemFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_PROBLEM = gql`\n ${PROBLEM_FIELDS}\n ${SUBMISSION_FIELDS}\n ${PROBLEM_TEST_CASE_FIELDS}\n query TecProblem($id: ID!) {\n tecProblem(id: $id) {\n ...ProblemFields\n publicTestCases {\n ...ProblemTestCaseFields\n }\n submissions {\n ...SubmissionFields\n }\n }\n }\n`;\n\nconst REGRADE_SUBMISSION = gql`\n ${SUBMISSION_FIELDS}\n mutation TecRegradeSubmission($id: ID!) {\n tecRegradeSubmission(id: $id) {\n ...SubmissionFields\n }\n }\n`;\n\nconst LIST_SUBMISSIONS = gql`\n ${SUBMISSION_FIELDS}\n ${PROBLEM_FIELDS}\n query TecListSubmissions(\n $learnerId: ID\n $problemId: ID\n $pagination: PaginationInput\n $startDate: DateTime\n $endDate: DateTime\n ) {\n tecListSubmissions(\n learnerId: $learnerId\n problemId: $problemId\n pagination: $pagination\n startDate: $startDate\n endDate: $endDate\n ) {\n items {\n ...SubmissionFields\n problem {\n ...ProblemFields\n }\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_MENTORS = gql`\n ${MENTOR_FIELDS}\n query TecListMentors($status: TecMentorStatus, $pagination: PaginationInput) {\n tecListMentors(status: $status, pagination: $pagination) {\n items {\n ...MentorFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_MENTOR = gql`\n ${MENTOR_FIELDS}\n ${SESSION_FIELDS}\n query TecMentor($id: ID!) {\n tecMentor(id: $id) {\n ...MentorFields\n sessions {\n ...SessionFields\n }\n }\n }\n`;\n\nconst LIST_SESSIONS = gql`\n ${SESSION_FIELDS}\n ${MENTOR_FIELDS}\n query TecListSessions(\n $mentorId: ID\n $menteeId: ID\n $status: TecSessionStatus\n $pagination: PaginationInput\n ) {\n tecListSessions(\n mentorId: $mentorId\n menteeId: $menteeId\n status: $status\n pagination: $pagination\n ) {\n items {\n ...SessionFields\n mentor {\n ...MentorFields\n }\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_HACKATHONS = gql`\n ${HACKATHON_FIELDS}\n query TecListHackathons($status: TecHackathonStatus, $pagination: PaginationInput) {\n tecListHackathons(status: $status, pagination: $pagination) {\n items {\n ...HackathonFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GET_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n ${TEAM_FIELDS}\n query TecHackathon($id: ID!) {\n tecHackathon(id: $id) {\n ...HackathonFields\n teams {\n ...TeamFields\n }\n }\n }\n`;\n\nconst LIST_TEAMS = gql`\n ${TEAM_FIELDS}\n query TecListTeams($hackathonId: ID!, $pagination: PaginationInput) {\n tecListTeams(hackathonId: $hackathonId, pagination: $pagination) {\n items {\n ...TeamFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst LIST_LESSONS = gql`\n ${LESSON_FIELDS}\n query TecListLessons($courseId: ID!, $pagination: PaginationInput) {\n tecListLessons(courseId: $courseId, pagination: $pagination) {\n items {\n ...LessonFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\n/* ------------------------------------------------------- response typings */\n\ntype Conn<K extends string, T> = Record<K, { items: T[]; pageInfo: TecPageInfo }>;\n\n/* ---------------------------------------------------------- query hooks */\n\nexport const useCoursesQuery = (vars: {\n level?: TecCourseLevel;\n status?: TecCourseStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListCourses', TecCourse>>(LIST_COURSES, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useCourseQuery = (id: string) =>\n useQuery<{ tecCourse: TecCourse | null }>(GET_COURSE, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useEnrollmentsQuery = (vars: {\n learnerId?: string;\n courseId?: string;\n startDate?: string;\n endDate?: string;\n}) =>\n useQuery<Conn<'tecListEnrollments', TecEnrollment>>(LIST_ENROLLMENTS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useCertificatesQuery = (vars: { learnerId?: string; courseId?: string }) =>\n useQuery<{ tecListCertificates: TecCertificate[] }>(LIST_CERTIFICATES, {\n variables: vars,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useProblemsQuery = (vars: {\n difficulty?: TecProblemDifficulty;\n status?: TecProblemStatus;\n topic?: string;\n company?: string;\n role?: string;\n interviewFrequency?: TecInterviewFrequency;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListProblems', TecProblem>>(LIST_PROBLEMS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useProblemQuery = (id: string) =>\n useQuery<{ tecProblem: TecProblem | null }>(GET_PROBLEM, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useSubmissionsQuery = (vars: {\n learnerId?: string;\n problemId?: string;\n startDate?: string;\n endDate?: string;\n}) =>\n useQuery<Conn<'tecListSubmissions', TecSubmission>>(LIST_SUBMISSIONS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useMentorsQuery = (vars: {\n status?: TecMentorStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListMentors', TecMentor>>(LIST_MENTORS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useMentorQuery = (id: string) =>\n useQuery<{ tecMentor: TecMentor | null }>(GET_MENTOR, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useSessionsQuery = (vars: {\n mentorId?: string;\n menteeId?: string;\n status?: TecSessionStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListSessions', TecMentorSession>>(LIST_SESSIONS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useHackathonsQuery = (vars: {\n status?: TecHackathonStatus;\n pagination?: { limit: number; cursor?: string };\n}) =>\n useQuery<Conn<'tecListHackathons', TecHackathon>>(LIST_HACKATHONS, {\n variables: { pagination: pageArg(50), ...vars },\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useHackathonQuery = (id: string) =>\n useQuery<{ tecHackathon: TecHackathon | null }>(GET_HACKATHON, {\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useTeamsQuery = (\n hackathonId: string,\n pagination?: { limit: number; cursor?: string }\n) =>\n useQuery<Conn<'tecListTeams', TecHackathonTeam>>(LIST_TEAMS, {\n variables: { hackathonId, pagination: pagination ?? pageArg(50) },\n skip: !hackathonId,\n fetchPolicy: 'cache-and-network',\n });\n\nexport const useLessonsQuery = (\n courseId: string,\n pagination?: { limit: number; cursor?: string }\n) =>\n useQuery<Conn<'tecListLessons', TecLesson>>(LIST_LESSONS, {\n variables: { courseId, pagination: pagination ?? pageArg(50) },\n skip: !courseId,\n fetchPolicy: 'cache-and-network',\n });\n\n/* ------------------------------------------------------------ mutations */\n\nconst onMutationError = (error: ErrorLike): void => {\n notify.error('Something went wrong', error.message || 'Please try again.');\n};\n\nconst REFETCH = {\n courses: 'TecListCourses',\n enrollments: 'TecListEnrollments',\n problems: 'TecListProblems',\n submissions: 'TecListSubmissions',\n mentors: 'TecListMentors',\n sessions: 'TecListSessions',\n hackathons: 'TecListHackathons',\n} as const;\n\nconst ENROLL = gql`\n ${ENROLLMENT_FIELDS}\n mutation TecEnroll($input: TecEnrollInput!) {\n tecEnroll(input: $input) {\n ...EnrollmentFields\n }\n }\n`;\n\nconst UPDATE_PROGRESS = gql`\n ${ENROLLMENT_FIELDS}\n mutation TecUpdateProgress($input: TecUpdateProgressInput!) {\n tecUpdateProgress(input: $input) {\n ...EnrollmentFields\n }\n }\n`;\n\nconst SUBMIT_SOLUTION = gql`\n ${SUBMISSION_FIELDS}\n mutation TecSubmitSolution($input: TecSubmitSolutionInput!) {\n tecSubmitSolution(input: $input) {\n ...SubmissionFields\n }\n }\n`;\n\nconst BOOK_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecBookSession($input: TecBookSessionInput!) {\n tecBookSession(input: $input) {\n ...SessionFields\n }\n }\n`;\n\nconst CANCEL_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecCancelSession($id: ID!) {\n tecCancelSession(id: $id) {\n ...SessionFields\n }\n }\n`;\n\nconst BECOME_MENTOR = gql`\n ${MENTOR_FIELDS}\n mutation TecBecomeMentor($input: TecCreateMentorInput!) {\n tecBecomeMentor(input: $input) {\n ...MentorFields\n }\n }\n`;\n\nconst REGISTER_TEAM = gql`\n ${TEAM_FIELDS}\n mutation TecRegisterTeam($input: TecRegisterTeamInput!) {\n tecRegisterTeam(input: $input) {\n ...TeamFields\n }\n }\n`;\n\nconst SUBMIT_PROJECT = gql`\n ${TEAM_FIELDS}\n mutation TecSubmitProject($input: TecSubmitProjectInput!) {\n tecSubmitProject(input: $input) {\n ...TeamFields\n }\n }\n`;\n\n/* ------- admin / authoring mutations ------- */\n\nconst CREATE_COURSE = gql`\n ${COURSE_FIELDS}\n mutation TecCreateCourse($input: TecCreateCourseInput!) {\n tecCreateCourse(input: $input) {\n ...CourseFields\n }\n }\n`;\n\nconst PUBLISH_COURSE = gql`\n ${COURSE_FIELDS}\n mutation TecPublishCourse($id: ID!) {\n tecPublishCourse(id: $id) {\n ...CourseFields\n }\n }\n`;\n\nconst ARCHIVE_COURSE = gql`\n mutation TecArchiveCourse($id: ID!) {\n tecArchiveCourse(id: $id)\n }\n`;\n\nconst CREATE_LESSON = gql`\n ${LESSON_FIELDS}\n mutation TecCreateLesson($input: TecCreateLessonInput!) {\n tecCreateLesson(input: $input) {\n ...LessonFields\n }\n }\n`;\n\nconst CREATE_PROBLEM = gql`\n ${PROBLEM_FIELDS}\n mutation TecCreateProblem($input: TecCreateProblemInput!) {\n tecCreateProblem(input: $input) {\n ...ProblemFields\n }\n }\n`;\n\nconst PUBLISH_PROBLEM = gql`\n ${PROBLEM_FIELDS}\n mutation TecPublishProblem($id: ID!) {\n tecPublishProblem(id: $id) {\n ...ProblemFields\n }\n }\n`;\n\nconst CREATE_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n mutation TecCreateHackathon($input: TecCreateHackathonInput!) {\n tecCreateHackathon(input: $input) {\n ...HackathonFields\n }\n }\n`;\n\nconst OPEN_REGISTRATION = gql`\n ${HACKATHON_FIELDS}\n mutation TecOpenRegistration($id: ID!) {\n tecOpenRegistration(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\nconst APPROVE_MENTOR = gql`\n ${MENTOR_FIELDS}\n mutation TecApproveMentor($id: ID!) {\n tecApproveMentor(id: $id) {\n ...MentorFields\n }\n }\n`;\n\nconst SCORE_TEAM = gql`\n ${TEAM_FIELDS}\n mutation TecScoreTeam($id: ID!, $score: Int!, $winner: Boolean) {\n tecScoreTeam(id: $id, score: $score, winner: $winner) {\n ...TeamFields\n }\n }\n`;\n\nconst CONFIRM_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecConfirmSession($id: ID!, $meetingUrl: String) {\n tecConfirmSession(id: $id, meetingUrl: $meetingUrl) {\n ...SessionFields\n }\n }\n`;\n\nconst COMPLETE_SESSION = gql`\n ${SESSION_FIELDS}\n mutation TecCompleteSession($id: ID!, $rating: Int, $feedback: String) {\n tecCompleteSession(id: $id, rating: $rating, feedback: $feedback) {\n ...SessionFields\n }\n }\n`;\n\nconst GRADE_SUBMISSION = gql`\n ${SUBMISSION_FIELDS}\n mutation TecGradeSubmission($id: ID!, $verdict: TecSubmissionVerdict!, $runtimeMs: Int) {\n tecGradeSubmission(id: $id, verdict: $verdict, runtimeMs: $runtimeMs) {\n ...SubmissionFields\n }\n }\n`;\n\nconst ISSUE_CERTIFICATE = gql`\n ${CERTIFICATE_FIELDS}\n mutation TecIssueCertificate($courseId: ID!, $learnerId: ID!, $score: Int!) {\n tecIssueCertificate(courseId: $courseId, learnerId: $learnerId, score: $score) {\n ...CertificateFields\n }\n }\n`;\n\nconst REVOKE_CERTIFICATE = gql`\n ${CERTIFICATE_FIELDS}\n mutation TecRevokeCertificate($id: ID!, $reason: String) {\n tecRevokeCertificate(id: $id, reason: $reason) {\n ...CertificateFields\n }\n }\n`;\n\nconst START_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n mutation TecStartHackathon($id: ID!) {\n tecStartHackathon(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\nconst START_JUDGING = gql`\n ${HACKATHON_FIELDS}\n mutation TecStartJudging($id: ID!) {\n tecStartJudging(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\nconst COMPLETE_HACKATHON = gql`\n ${HACKATHON_FIELDS}\n mutation TecCompleteHackathon($id: ID!) {\n tecCompleteHackathon(id: $id) {\n ...HackathonFields\n }\n }\n`;\n\n/* ---------------------------------------------------------- mutation hooks */\n\nexport const useEnroll = () =>\n useMutation<{ tecEnroll: TecEnrollment }>(ENROLL, {\n onError: onMutationError,\n refetchQueries: [REFETCH.enrollments, REFETCH.courses],\n });\n\nexport const useUpdateProgress = () =>\n useMutation<{ tecUpdateProgress: TecEnrollment }>(UPDATE_PROGRESS, {\n onError: onMutationError,\n refetchQueries: [REFETCH.enrollments],\n });\n\nexport const useSubmitSolution = () =>\n useMutation<{ tecSubmitSolution: TecSubmission }>(SUBMIT_SOLUTION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.submissions],\n });\n\n/**\n * Re-run the grader for a submission. Used by the problem page when a verdict\n * came back PENDING (grader unavailable at submit time) so a learner can retry\n * without resubmitting identical code.\n */\nexport const useRegradeSubmission = () =>\n useMutation<{ tecRegradeSubmission: TecSubmission }>(REGRADE_SUBMISSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.submissions],\n });\n\nexport const useBookSession = () =>\n useMutation<{ tecBookSession: TecMentorSession }>(BOOK_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions, REFETCH.mentors],\n });\n\nexport const useCancelSession = () =>\n useMutation<{ tecCancelSession: TecMentorSession }>(CANCEL_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions],\n });\n\nexport const useBecomeMentor = () =>\n useMutation<{ tecBecomeMentor: TecMentor }>(BECOME_MENTOR, {\n onError: onMutationError,\n refetchQueries: [REFETCH.mentors],\n });\n\nexport const useRegisterTeam = () =>\n useMutation<{ tecRegisterTeam: TecHackathonTeam }>(REGISTER_TEAM, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useSubmitProject = () =>\n useMutation<{ tecSubmitProject: TecHackathonTeam }>(SUBMIT_PROJECT, {\n onError: onMutationError,\n });\n\nexport const useCreateCourse = () =>\n useMutation<{ tecCreateCourse: TecCourse }>(CREATE_COURSE, {\n onError: onMutationError,\n refetchQueries: [REFETCH.courses],\n });\n\nexport const usePublishCourse = () =>\n useMutation<{ tecPublishCourse: TecCourse }>(PUBLISH_COURSE, {\n onError: onMutationError,\n refetchQueries: [REFETCH.courses],\n });\n\nexport const useArchiveCourse = () =>\n useMutation<{ tecArchiveCourse: boolean }>(ARCHIVE_COURSE, {\n onError: onMutationError,\n refetchQueries: [REFETCH.courses],\n });\n\nexport const useCreateLesson = () =>\n useMutation<{ tecCreateLesson: TecLesson }>(CREATE_LESSON, { onError: onMutationError });\n\nexport const useCreateProblem = () =>\n useMutation<{ tecCreateProblem: TecProblem }>(CREATE_PROBLEM, {\n onError: onMutationError,\n refetchQueries: [REFETCH.problems],\n });\n\nexport const usePublishProblem = () =>\n useMutation<{ tecPublishProblem: TecProblem }>(PUBLISH_PROBLEM, {\n onError: onMutationError,\n refetchQueries: [REFETCH.problems],\n });\n\nexport const useCreateHackathon = () =>\n useMutation<{ tecCreateHackathon: TecHackathon }>(CREATE_HACKATHON, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useOpenRegistration = () =>\n useMutation<{ tecOpenRegistration: TecHackathon }>(OPEN_REGISTRATION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useApproveMentor = () =>\n useMutation<{ tecApproveMentor: TecMentor }>(APPROVE_MENTOR, {\n onError: onMutationError,\n refetchQueries: [REFETCH.mentors],\n });\n\nexport const useScoreTeam = () =>\n useMutation<{ tecScoreTeam: TecHackathonTeam }>(SCORE_TEAM, { onError: onMutationError });\n\nexport const useConfirmSession = () =>\n useMutation<{ tecConfirmSession: TecMentorSession }>(CONFIRM_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions],\n });\n\nexport const useCompleteSession = () =>\n useMutation<{ tecCompleteSession: TecMentorSession }>(COMPLETE_SESSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.sessions],\n });\n\nexport const useGradeSubmission = () =>\n useMutation<{ tecGradeSubmission: TecSubmission }>(GRADE_SUBMISSION, {\n onError: onMutationError,\n refetchQueries: [REFETCH.submissions],\n });\n\nexport const useIssueCertificate = () =>\n useMutation<{ tecIssueCertificate: TecCertificate }>(ISSUE_CERTIFICATE, {\n onError: onMutationError,\n });\n\nexport const useRevokeCertificate = () =>\n useMutation<{ tecRevokeCertificate: TecCertificate }>(REVOKE_CERTIFICATE, {\n onError: onMutationError,\n });\n\nexport const useStartHackathon = () =>\n useMutation<{ tecStartHackathon: TecHackathon }>(START_HACKATHON, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useStartJudging = () =>\n useMutation<{ tecStartJudging: TecHackathon }>(START_JUDGING, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\nexport const useCompleteHackathon = () =>\n useMutation<{ tecCompleteHackathon: TecHackathon }>(COMPLETE_HACKATHON, {\n onError: onMutationError,\n refetchQueries: [REFETCH.hackathons],\n });\n\n/* ============================================================ Study Planner\n * BOFF-4415 — deterministic, rule-based goal -> plan scheduler. NOT an LLM\n * feature; see the backend StudyPlanService honesty note. Every query/\n * mutation below is self-scoped (learnerId comes from the authenticated\n * actor server-side) so no learnerId variable is ever sent from the client.\n * ========================================================================= */\n\nexport type TecStudyPlanStatus = 'ACTIVE' | 'COMPLETED' | 'ARCHIVED';\nexport type TecStudyPlanStepKind = 'COURSE' | 'PROBLEM';\nexport type TecStudyPlanStepStatus = 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'SKIPPED';\n\nexport interface TecStudyPlanStep {\n id: string;\n order: number;\n kind: TecStudyPlanStepKind;\n targetId: string;\n title: string;\n scheduledWeek: number;\n status: TecStudyPlanStepStatus;\n rationale: string;\n estimatedMinutes: number;\n completedAt?: string | null;\n}\n\nexport interface TecStudyPlan {\n id: string;\n goal: string;\n topic?: string | null;\n timeframeWeeks: number;\n status: TecStudyPlanStatus;\n targetCompletionDate?: string | null;\n progressPct: number;\n totalSteps: number;\n completedSteps: number;\n createdAt: string;\n steps: TecStudyPlanStep[];\n}\n\nconst STUDY_PLAN_STEP_FIELDS = gql`\n fragment StudyPlanStepFields on TecStudyPlanStep {\n id\n order\n kind\n targetId\n title\n scheduledWeek\n status\n rationale\n estimatedMinutes\n completedAt\n }\n`;\n\nconst STUDY_PLAN_FIELDS = gql`\n ${STUDY_PLAN_STEP_FIELDS}\n fragment StudyPlanFields on TecStudyPlan {\n id\n goal\n topic\n timeframeWeeks\n status\n targetCompletionDate\n progressPct\n totalSteps\n completedSteps\n createdAt\n steps {\n ...StudyPlanStepFields\n }\n }\n`;\n\nconst LIST_MY_STUDY_PLANS = gql`\n ${STUDY_PLAN_FIELDS}\n query TecMyStudyPlans {\n tecMyStudyPlans {\n items {\n ...StudyPlanFields\n }\n pageInfo {\n cursor\n hasMore\n }\n }\n }\n`;\n\nconst GENERATE_STUDY_PLAN = gql`\n ${STUDY_PLAN_FIELDS}\n mutation TecGenerateStudyPlan($input: TecGenerateStudyPlanInput!) {\n tecGenerateStudyPlan(input: $input) {\n ...StudyPlanFields\n }\n }\n`;\n\nconst UPDATE_STUDY_PLAN_STEP_STATUS = gql`\n ${STUDY_PLAN_STEP_FIELDS}\n mutation TecUpdateStudyPlanStepStatus($input: TecUpdateStudyPlanStepStatusInput!) {\n tecUpdateStudyPlanStepStatus(input: $input) {\n ...StudyPlanStepFields\n }\n }\n`;\n\nconst ARCHIVE_STUDY_PLAN = gql`\n mutation TecArchiveStudyPlan($id: ID!) {\n tecArchiveStudyPlan(id: $id)\n }\n`;\n\nexport const useMyStudyPlansQuery = () =>\n useQuery<{ tecMyStudyPlans: { items: TecStudyPlan[]; pageInfo: TecPageInfo } }>(\n LIST_MY_STUDY_PLANS,\n {\n fetchPolicy: 'cache-and-network',\n }\n );\n\nexport const useGenerateStudyPlan = () =>\n useMutation<{ tecGenerateStudyPlan: TecStudyPlan }>(GENERATE_STUDY_PLAN, {\n onError: onMutationError,\n refetchQueries: ['TecMyStudyPlans'],\n });\n\nexport const useUpdateStudyPlanStepStatus = () =>\n useMutation<{ tecUpdateStudyPlanStepStatus: TecStudyPlanStep }>(UPDATE_STUDY_PLAN_STEP_STATUS, {\n onError: onMutationError,\n refetchQueries: ['TecMyStudyPlans'],\n });\n\nexport const useArchiveStudyPlan = () =>\n useMutation<{ tecArchiveStudyPlan: boolean }>(ARCHIVE_STUDY_PLAN, {\n onError: onMutationError,\n refetchQueries: ['TecMyStudyPlans'],\n });\n\n/* ================================================================ Portfolio\n * BOFF-4432 — learner-curated showcase of real completed hackathon\n * projects, certificates, and courses. `tecPublicPortfolio` is a public,\n * unauthenticated field (@rbac public: true) reached through the same\n * gateway; there is no separate unauthenticated *page* wired up yet (see\n * ApplicationsPortfolioPagePage's deferred-scope note).\n * ========================================================================= */\n\nexport type TecPortfolioItemKind = 'HACKATHON_PROJECT' | 'CERTIFICATE' | 'COURSE_COMPLETION';\n\nexport interface TecPortfolioItem {\n id: string;\n kind: TecPortfolioItemKind;\n sourceId: string;\n title: string;\n description?: string | null;\n link?: string | null;\n completionDate: string;\n order: number;\n}\n\nexport interface TecPortfolio {\n id: string;\n isPublished: boolean;\n publicSlug?: string | null;\n publishedAt?: string | null;\n items: TecPortfolioItem[];\n}\n\nconst PORTFOLIO_ITEM_FIELDS = gql`\n fragment PortfolioItemFields on TecPortfolioItem {\n id\n kind\n sourceId\n title\n description\n link\n completionDate\n order\n }\n`;\n\nconst PORTFOLIO_FIELDS = gql`\n ${PORTFOLIO_ITEM_FIELDS}\n fragment PortfolioFields on TecPortfolio {\n id\n isPublished\n publicSlug\n publishedAt\n items {\n ...PortfolioItemFields\n }\n }\n`;\n\nconst GET_MY_PORTFOLIO = gql`\n ${PORTFOLIO_FIELDS}\n query TecMyPortfolio {\n tecMyPortfolio {\n ...PortfolioFields\n }\n }\n`;\n\nconst ADD_PORTFOLIO_ITEM = gql`\n ${PORTFOLIO_ITEM_FIELDS}\n mutation TecAddPortfolioItem($input: TecAddPortfolioItemInput!) {\n tecAddPortfolioItem(input: $input) {\n ...PortfolioItemFields\n }\n }\n`;\n\nconst REORDER_PORTFOLIO_ITEMS = gql`\n ${PORTFOLIO_FIELDS}\n mutation TecReorderPortfolioItems($input: TecReorderPortfolioItemsInput!) {\n tecReorderPortfolioItems(input: $input) {\n ...PortfolioFields\n }\n }\n`;\n\nconst REMOVE_PORTFOLIO_ITEM = gql`\n mutation TecRemovePortfolioItem($id: ID!) {\n tecRemovePortfolioItem(id: $id)\n }\n`;\n\nconst PUBLISH_PORTFOLIO = gql`\n ${PORTFOLIO_FIELDS}\n mutation TecPublishPortfolio {\n tecPublishPortfolio {\n ...PortfolioFields\n }\n }\n`;\n\nconst UNPUBLISH_PORTFOLIO = gql`\n ${PORTFOLIO_FIELDS}\n mutation TecUnpublishPortfolio {\n tecUnpublishPortfolio {\n ...PortfolioFields\n }\n }\n`;\n\nexport const useMyPortfolioQuery = () =>\n useQuery<{ tecMyPortfolio: TecPortfolio }>(GET_MY_PORTFOLIO, {\n fetchPolicy: 'cache-and-network',\n });\n\nconst REFETCH_PORTFOLIO = ['TecMyPortfolio'];\n\nexport const useAddPortfolioItem = () =>\n useMutation<{ tecAddPortfolioItem: TecPortfolioItem }>(ADD_PORTFOLIO_ITEM, {\n onError: onMutationError,\n refetchQueries: REFETCH_PORTFOLIO,\n });\n\nexport const useReorderPortfolioItems = () =>\n useMutation<{ tecReorderPortfolioItems: TecPortfolio }>(REORDER_PORTFOLIO_ITEMS, {\n onError: onMutationError,\n });\n\nexport const useRemovePortfolioItem = () =>\n useMutation<{ tecRemovePortfolioItem: boolean }>(REMOVE_PORTFOLIO_ITEM, {\n onError: onMutationError,\n refetchQueries: REFETCH_PORTFOLIO,\n });\n\nexport const usePublishPortfolio = () =>\n useMutation<{ tecPublishPortfolio: TecPortfolio }>(PUBLISH_PORTFOLIO, {\n onError: onMutationError,\n refetchQueries: REFETCH_PORTFOLIO,\n });\n\nexport const useUnpublishPortfolio = () =>\n useMutation<{ tecUnpublishPortfolio: TecPortfolio }>(UNPUBLISH_PORTFOLIO, {\n onError: onMutationError,\n refetchQueries: REFETCH_PORTFOLIO,\n });\n\n/* ------------------------------------------------------- pagination helper */\n\nexport interface PageLimit {\n limit: number;\n more: () => void;\n}\n\n/**\n * Simple, robust \"load more\". The backend paginates with `take = limit + 1`\n * (offset is ignored; only `cursor` shifts the window), so a larger `limit`\n * simply fetches more rows from the top and `pageInfo.hasMore` reports whether\n * still more exist. Growing the limit avoids cursor-merge/fetchMore complexity\n * and never sends `cursor: null` (the page-1 500 guard). Pass `limit` into the\n * query's `pageArg` and render <LoadMore hasMore={...} onClick={more} />.\n */\nexport function usePageLimit(step = 24, initial = 24): PageLimit {\n const [limit, setLimit] = useState(initial);\n return { limit, more: () => setLimit((l) => l + step) };\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ /**
4
+ * BOFF-4416 free-tier content gating: the "this content requires a paid
5
+ * plan" empty state. Rendered whenever a course/lesson/problem's `isLocked`
6
+ * flag comes back true from the API — the underlying content
7
+ * (`content`/`statement`/`starterCode`/`publicTestCases`) is ALREADY null
8
+ * or empty in the response at that point (the gate is enforced server-side,
9
+ * this is purely the "why is this empty" explanation for the learner).
10
+ *
11
+ * Deliberately reuses no live billing/checkout UI — this is a read-only
12
+ * "upgrade required" message, not a purchase flow (billing boundary: no
13
+ * live Stripe/Razorpay integration without founder/finance sign-off).
14
+ */
15
+ export declare function UpgradeGate({ title, description, compact, }: {
16
+ title?: string;
17
+ description?: string;
18
+ compact?: boolean;
19
+ }): import("react").JSX.Element;
20
+ /** Small "Premium" pill for course/problem cards and headers. */
21
+ export declare function PremiumBadge({ locked }: {
22
+ locked?: boolean;
23
+ }): ReactNode;
24
+ //# sourceMappingURL=UpgradeGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpgradeGate.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/UpgradeGate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAyB,EACzB,WAA8G,EAC9G,OAAe,GAChB,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,+BAmBA;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,EAAE,MAAc,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAShF"}
@@ -0,0 +1,47 @@
1
+ import { Crown as e, Lock as t } from "lucide-react";
2
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
3
+ import { Badge as i } from "@burdenoff/fe-libs/ui";
4
+ //#region src/technospam/components/UpgradeGate.tsx
5
+ function a({ title: e = "Premium content", description: i = "This content is part of a paid TechnoSpam plan. Ask a workspace admin to upgrade to unlock it.", compact: a = !1 }) {
6
+ return a ? /* @__PURE__ */ r("div", {
7
+ className: "flex items-center gap-2 rounded-xl border border-status-warning-border/60 bg-status-warning-bg-subtle/40 px-3 py-2.5 text-sm text-status-warning-text",
8
+ children: [/* @__PURE__ */ n(t, {
9
+ size: 14,
10
+ className: "shrink-0"
11
+ }), /* @__PURE__ */ n("span", {
12
+ className: "min-w-0 flex-1 truncate",
13
+ children: i
14
+ })]
15
+ }) : /* @__PURE__ */ r("div", {
16
+ className: "flex flex-col items-center justify-center gap-3 rounded-2xl border border-status-warning-border/60 bg-status-warning-bg-subtle/30 px-6 py-14 text-center",
17
+ children: [
18
+ /* @__PURE__ */ n("span", {
19
+ className: "flex h-14 w-14 items-center justify-center rounded-2xl bg-status-warning-bg-subtle text-status-warning-text ring-1 ring-status-warning-border/30",
20
+ children: /* @__PURE__ */ n(t, { size: 26 })
21
+ }),
22
+ /* @__PURE__ */ n("h3", {
23
+ className: "text-base font-semibold text-text-primary",
24
+ children: e
25
+ }),
26
+ /* @__PURE__ */ n("p", {
27
+ className: "max-w-md text-sm text-text-secondary",
28
+ children: i
29
+ })
30
+ ]
31
+ });
32
+ }
33
+ function o({ locked: t = !1 }) {
34
+ return /* @__PURE__ */ r(i, {
35
+ variant: "outline",
36
+ className: "gap-1 border-status-warning-border/60 bg-status-warning-bg-subtle text-status-warning-text",
37
+ children: [
38
+ /* @__PURE__ */ n(e, { size: 12 }),
39
+ " ",
40
+ t ? "Premium — locked" : "Premium"
41
+ ]
42
+ });
43
+ }
44
+ //#endregion
45
+ export { o as PremiumBadge, a as UpgradeGate };
46
+
47
+ //# sourceMappingURL=UpgradeGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpgradeGate.js","names":[],"sources":["../../../src/technospam/components/UpgradeGate.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Crown, Lock } from 'lucide-react';\nimport { Badge } from '@burdenoff/fe-libs/ui';\n\n/**\n * BOFF-4416 free-tier content gating: the \"this content requires a paid\n * plan\" empty state. Rendered whenever a course/lesson/problem's `isLocked`\n * flag comes back true from the API — the underlying content\n * (`content`/`statement`/`starterCode`/`publicTestCases`) is ALREADY null\n * or empty in the response at that point (the gate is enforced server-side,\n * this is purely the \"why is this empty\" explanation for the learner).\n *\n * Deliberately reuses no live billing/checkout UI — this is a read-only\n * \"upgrade required\" message, not a purchase flow (billing boundary: no\n * live Stripe/Razorpay integration without founder/finance sign-off).\n */\nexport function UpgradeGate({\n title = 'Premium content',\n description = 'This content is part of a paid TechnoSpam plan. Ask a workspace admin to upgrade to unlock it.',\n compact = false,\n}: {\n title?: string;\n description?: string;\n compact?: boolean;\n}) {\n if (compact) {\n return (\n <div className=\"flex items-center gap-2 rounded-xl border border-status-warning-border/60 bg-status-warning-bg-subtle/40 px-3 py-2.5 text-sm text-status-warning-text\">\n <Lock size={14} className=\"shrink-0\" />\n <span className=\"min-w-0 flex-1 truncate\">{description}</span>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col items-center justify-center gap-3 rounded-2xl border border-status-warning-border/60 bg-status-warning-bg-subtle/30 px-6 py-14 text-center\">\n <span className=\"flex h-14 w-14 items-center justify-center rounded-2xl bg-status-warning-bg-subtle text-status-warning-text ring-1 ring-status-warning-border/30\">\n <Lock size={26} />\n </span>\n <h3 className=\"text-base font-semibold text-text-primary\">{title}</h3>\n <p className=\"max-w-md text-sm text-text-secondary\">{description}</p>\n </div>\n );\n}\n\n/** Small \"Premium\" pill for course/problem cards and headers. */\nexport function PremiumBadge({ locked = false }: { locked?: boolean }): ReactNode {\n return (\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-status-warning-border/60 bg-status-warning-bg-subtle text-status-warning-text\"\n >\n <Crown size={12} /> {locked ? 'Premium — locked' : 'Premium'}\n </Badge>\n );\n}\n"],"mappings":";;;;AAgBA,SAAgB,EAAY,EAC1B,WAAQ,mBACR,iBAAc,kGACd,aAAU,MAKT;AAUD,QATI,IAEA,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GAAM,MAAM;GAAI,WAAU;GAAa,CAAA,EACvC,kBAAC,QAAD;GAAM,WAAU;aAA2B;GAAmB,CAAA,CAC1D;MAKR,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,QAAD;IAAM,WAAU;cACd,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IACb,CAAA;GACP,kBAAC,MAAD;IAAI,WAAU;cAA6C;IAAW,CAAA;GACtE,kBAAC,KAAD;IAAG,WAAU;cAAwC;IAAgB,CAAA;GACjE;;;AAKV,SAAgB,EAAa,EAAE,YAAS,MAA0C;AAChF,QACE,kBAAC,GAAD;EACE,SAAQ;EACR,WAAU;YAFZ;GAIE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;GAAE,IAAS,qBAAqB;GAC7C"}
@@ -6,4 +6,5 @@ export { LoadMore } from './LoadMore';
6
6
  export { EmptyView, ErrorView, LoadingGrid, LoadingRows } from './StateViews';
7
7
  export { TagStrip } from './TagStrip';
8
8
  export { TagInput } from './TagInput';
9
+ export { UpgradeGate, PremiumBadge } from './UpgradeGate';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
@@ -6,3 +6,4 @@ import "./LoadMore.js";
6
6
  import "./StateViews.js";
7
7
  import "./TagStrip.js";
8
8
  import "./TagInput.js";
9
+ import "./UpgradeGate.js";
@@ -0,0 +1,2 @@
1
+ export declare function ApplicationsPortfolioPagePage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=ApplicationsPortfolioPagePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApplicationsPortfolioPagePage.d.ts","sourceRoot":"","sources":["../../../src/technospam/pages/ApplicationsPortfolioPagePage.tsx"],"names":[],"mappings":"AAwQA,wBAAgB,6BAA6B,gCAwI5C"}
@@ -0,0 +1,275 @@
1
+ import { useTechnoSpam as e } from "../providers/TechnoSpamProvider.js";
2
+ import { PageLayout as t } from "../components/PageLayout.js";
3
+ import { formatDate as n } from "../utils/format.js";
4
+ import { EmptyView as r, ErrorView as i, LoadingRows as a } from "../components/StateViews.js";
5
+ import "../components/index.js";
6
+ import { notify as o } from "../lib/toast.js";
7
+ import { useAddPortfolioItem as s, useCertificatesQuery as c, useEnrollmentsQuery as l, useHackathonsQuery as u, useMyPortfolioQuery as d, usePublishPortfolio as f, useRemovePortfolioItem as p, useTeamsQuery as m, useUnpublishPortfolio as h } from "../api/technospamApi.js";
8
+ import { useState as g } from "react";
9
+ import { Award as _, Briefcase as v, Check as y, Copy as b, ExternalLink as x, GraduationCap as S, Link2 as C, Plus as w, Trash2 as T, Trophy as E, X as D } from "lucide-react";
10
+ import { jsx as O, jsxs as k } from "react/jsx-runtime";
11
+ import { Button as A, GlassCard as j, Select as M, SelectContent as N, SelectItem as P, SelectTrigger as F, SelectValue as I } from "@burdenoff/fe-libs/ui";
12
+ import { nativeConfirm as L } from "@burdenoff/fe-libs/shared/native";
13
+ //#region src/technospam/pages/ApplicationsPortfolioPagePage.tsx
14
+ var R = {
15
+ HACKATHON_PROJECT: E,
16
+ CERTIFICATE: _,
17
+ COURSE_COMPLETION: S
18
+ }, z = {
19
+ HACKATHON_PROJECT: "Hackathon project",
20
+ CERTIFICATE: "Certificate",
21
+ COURSE_COMPLETION: "Completed course"
22
+ };
23
+ function B({ item: e, onRemove: t }) {
24
+ let r = R[e.kind];
25
+ return /* @__PURE__ */ k(j, {
26
+ className: "group flex flex-col gap-3 p-4 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md sm:flex-row sm:items-start sm:justify-between",
27
+ children: [/* @__PURE__ */ k("div", {
28
+ className: "flex min-w-0 gap-3",
29
+ children: [/* @__PURE__ */ O("span", {
30
+ className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-accent-purple/15 text-accent-purple ring-1 ring-accent-purple/20",
31
+ children: /* @__PURE__ */ O(r, { size: 18 })
32
+ }), /* @__PURE__ */ k("div", {
33
+ className: "min-w-0",
34
+ children: [
35
+ /* @__PURE__ */ k("div", {
36
+ className: "flex flex-wrap items-center gap-2",
37
+ children: [/* @__PURE__ */ O("span", {
38
+ className: "truncate text-sm font-semibold text-text-primary",
39
+ children: e.title
40
+ }), /* @__PURE__ */ O("span", {
41
+ className: "rounded-full border border-border-seam px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-text-muted",
42
+ children: z[e.kind]
43
+ })]
44
+ }),
45
+ e.description ? /* @__PURE__ */ O("p", {
46
+ className: "mt-1 line-clamp-2 text-xs text-text-secondary",
47
+ children: e.description
48
+ }) : null,
49
+ /* @__PURE__ */ k("div", {
50
+ className: "mt-2 flex flex-wrap items-center gap-3 text-xs text-text-muted",
51
+ children: [/* @__PURE__ */ k("span", { children: ["Completed ", n(e.completionDate)] }), e.link ? /* @__PURE__ */ k("a", {
52
+ href: e.link,
53
+ target: "_blank",
54
+ rel: "noreferrer",
55
+ className: "inline-flex items-center gap-1 text-accent-primary hover:underline",
56
+ children: [/* @__PURE__ */ O(x, { size: 12 }), " View"]
57
+ }) : null]
58
+ })
59
+ ]
60
+ })]
61
+ }), /* @__PURE__ */ O(A, {
62
+ variant: "ghost",
63
+ size: "sm",
64
+ className: "shrink-0 text-status-error-text hover:text-status-error-text",
65
+ onClick: t,
66
+ children: /* @__PURE__ */ O(T, { size: 14 })
67
+ })]
68
+ });
69
+ }
70
+ function V({ onAdded: t }) {
71
+ let { currentUser: n } = e(), r = n?.id, { data: i } = c(r ? { learnerId: r } : {}), [a, { loading: l }] = s(), u = (i?.tecListCertificates ?? []).filter((e) => e.status === "ISSUED");
72
+ return u.length === 0 ? /* @__PURE__ */ O("p", {
73
+ className: "text-xs text-text-muted",
74
+ children: "No issued certificates yet."
75
+ }) : /* @__PURE__ */ O("div", {
76
+ className: "space-y-2",
77
+ children: u.map((e) => /* @__PURE__ */ k("div", {
78
+ className: "flex items-center justify-between gap-2 rounded-lg border border-border-seam p-2",
79
+ children: [/* @__PURE__ */ k("span", {
80
+ className: "min-w-0 truncate text-xs text-text-primary",
81
+ children: [
82
+ e.course?.title ?? "Certificate",
83
+ " · Serial ",
84
+ e.serial
85
+ ]
86
+ }), /* @__PURE__ */ k(A, {
87
+ size: "sm",
88
+ variant: "outline",
89
+ disabled: l,
90
+ onClick: async () => {
91
+ (await a({ variables: { input: {
92
+ kind: "CERTIFICATE",
93
+ sourceId: e.id
94
+ } } })).data?.tecAddPortfolioItem && (o.success("Added to portfolio"), t());
95
+ },
96
+ children: [/* @__PURE__ */ O(w, { size: 12 }), " Add"]
97
+ })]
98
+ }, e.id))
99
+ });
100
+ }
101
+ function H({ onAdded: t }) {
102
+ let { currentUser: n } = e(), r = n?.id, { data: i } = l(r ? { learnerId: r } : {}), [a, { loading: c }] = s(), u = (i?.tecListEnrollments.items ?? []).filter((e) => e.status === "COMPLETED");
103
+ return u.length === 0 ? /* @__PURE__ */ O("p", {
104
+ className: "text-xs text-text-muted",
105
+ children: "No completed courses yet."
106
+ }) : /* @__PURE__ */ O("div", {
107
+ className: "space-y-2",
108
+ children: u.map((e) => /* @__PURE__ */ k("div", {
109
+ className: "flex items-center justify-between gap-2 rounded-lg border border-border-seam p-2",
110
+ children: [/* @__PURE__ */ O("span", {
111
+ className: "min-w-0 truncate text-xs text-text-primary",
112
+ children: e.course?.title ?? "Course"
113
+ }), /* @__PURE__ */ k(A, {
114
+ size: "sm",
115
+ variant: "outline",
116
+ disabled: c,
117
+ onClick: async () => {
118
+ (await a({ variables: { input: {
119
+ kind: "COURSE_COMPLETION",
120
+ sourceId: e.id
121
+ } } })).data?.tecAddPortfolioItem && (o.success("Added to portfolio"), t());
122
+ },
123
+ children: [/* @__PURE__ */ O(w, { size: 12 }), " Add"]
124
+ })]
125
+ }, e.id))
126
+ });
127
+ }
128
+ function U({ onAdded: t }) {
129
+ let { currentUser: n } = e(), r = n?.id, { data: i } = u({}), a = i?.tecListHackathons.items ?? [], [c, l] = g(""), { data: d } = m(c), [f, { loading: p }] = s(), h = (d?.tecListTeams.items ?? []).filter((e) => (e.status === "SUBMITTED" || e.status === "WINNER") && (e.captainId === r || e.memberIds.includes(r ?? "")));
130
+ return /* @__PURE__ */ k("div", {
131
+ className: "space-y-2",
132
+ children: [
133
+ /* @__PURE__ */ k(M, {
134
+ value: c,
135
+ onValueChange: l,
136
+ children: [/* @__PURE__ */ O(F, {
137
+ className: "w-full",
138
+ children: /* @__PURE__ */ O(I, { placeholder: "Choose a hackathon" })
139
+ }), /* @__PURE__ */ O(N, { children: a.map((e) => /* @__PURE__ */ O(P, {
140
+ value: e.id,
141
+ children: e.title
142
+ }, e.id)) })]
143
+ }),
144
+ c && h.length === 0 ? /* @__PURE__ */ O("p", {
145
+ className: "text-xs text-text-muted",
146
+ children: "No submitted team of yours in this hackathon."
147
+ }) : null,
148
+ h.map((e) => /* @__PURE__ */ k("div", {
149
+ className: "flex items-center justify-between gap-2 rounded-lg border border-border-seam p-2",
150
+ children: [/* @__PURE__ */ O("span", {
151
+ className: "min-w-0 truncate text-xs text-text-primary",
152
+ children: e.projectName || e.name
153
+ }), /* @__PURE__ */ k(A, {
154
+ size: "sm",
155
+ variant: "outline",
156
+ disabled: p,
157
+ onClick: async () => {
158
+ (await f({ variables: { input: {
159
+ kind: "HACKATHON_PROJECT",
160
+ sourceId: e.id
161
+ } } })).data?.tecAddPortfolioItem && (o.success("Added to portfolio"), t());
162
+ },
163
+ children: [/* @__PURE__ */ O(w, { size: 12 }), " Add"]
164
+ })]
165
+ }, e.id))
166
+ ]
167
+ });
168
+ }
169
+ function W() {
170
+ let { data: e, loading: n, error: s, refetch: c } = d(), [l] = p(), [u, { loading: m }] = f(), [_, { loading: x }] = h(), [S, T] = g(!1), [E, M] = g(!1), N = e?.tecMyPortfolio, P = N?.items ?? [], F = N?.publicSlug ? `${typeof window < "u" ? window.location.origin : ""}/technospam/portfolio/${N.publicSlug}` : null, I = async (e, t) => {
171
+ await L({
172
+ title: "Remove from portfolio",
173
+ message: `Remove "${t}" from your portfolio? This does not delete the underlying record.`,
174
+ okButtonTitle: "Remove",
175
+ cancelButtonTitle: "Cancel"
176
+ }) && (await l({ variables: { id: e } })).data?.tecRemovePortfolioItem && o.success("Removed from portfolio");
177
+ }, R = async () => {
178
+ N && (N.isPublished ? (await _()).data?.tecUnpublishPortfolio && o.success("Portfolio unpublished") : (await u()).data?.tecPublishPortfolio && o.success("Portfolio published"));
179
+ }, z = async () => {
180
+ F && (await navigator.clipboard.writeText(F), M(!0), setTimeout(() => M(!1), 1500));
181
+ };
182
+ return /* @__PURE__ */ k(t, {
183
+ hero: !0,
184
+ title: "Portfolio",
185
+ description: "Showcase your real completed courses, certificates, and hackathon projects.",
186
+ actions: N ? /* @__PURE__ */ O(A, {
187
+ variant: N.isPublished ? "outline" : "default",
188
+ onClick: () => void R(),
189
+ disabled: m || x || !N.isPublished && P.length === 0,
190
+ children: N.isPublished ? "Unpublish" : "Publish"
191
+ }) : null,
192
+ children: [
193
+ N?.isPublished && F ? /* @__PURE__ */ k(j, {
194
+ className: "mb-6 flex flex-wrap items-center justify-between gap-3 p-3",
195
+ children: [/* @__PURE__ */ k("div", {
196
+ className: "flex min-w-0 items-center gap-2 text-xs text-text-secondary",
197
+ children: [/* @__PURE__ */ O(C, {
198
+ size: 14,
199
+ className: "shrink-0 text-accent-teal"
200
+ }), /* @__PURE__ */ O("span", {
201
+ className: "truncate",
202
+ children: F
203
+ })]
204
+ }), /* @__PURE__ */ k(A, {
205
+ variant: "ghost",
206
+ size: "sm",
207
+ onClick: () => void z(),
208
+ children: [
209
+ O(E ? y : b, { size: 14 }),
210
+ " ",
211
+ E ? "Copied" : "Copy link"
212
+ ]
213
+ })]
214
+ }) : null,
215
+ /* @__PURE__ */ k("div", {
216
+ className: "mb-4 flex items-center justify-between",
217
+ children: [/* @__PURE__ */ O("h2", {
218
+ className: "text-sm font-semibold text-text-primary",
219
+ children: "Your items"
220
+ }), /* @__PURE__ */ k(A, {
221
+ size: "sm",
222
+ variant: S ? "outline" : "default",
223
+ onClick: () => T((e) => !e),
224
+ children: [
225
+ O(S ? D : w, { size: 14 }),
226
+ " ",
227
+ S ? "Close" : "Add item"
228
+ ]
229
+ })]
230
+ }),
231
+ S ? /* @__PURE__ */ k(j, {
232
+ className: "mb-6 space-y-4 p-4",
233
+ children: [
234
+ /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("h3", {
235
+ className: "mb-2 text-xs font-semibold uppercase tracking-wide text-text-muted",
236
+ children: "From certificates"
237
+ }), /* @__PURE__ */ O(V, { onAdded: () => void c() })] }),
238
+ /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("h3", {
239
+ className: "mb-2 text-xs font-semibold uppercase tracking-wide text-text-muted",
240
+ children: "From completed courses"
241
+ }), /* @__PURE__ */ O(H, { onAdded: () => void c() })] }),
242
+ /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("h3", {
243
+ className: "mb-2 text-xs font-semibold uppercase tracking-wide text-text-muted",
244
+ children: "From hackathon projects"
245
+ }), /* @__PURE__ */ O(U, { onAdded: () => void c() })] })
246
+ ]
247
+ }) : null,
248
+ n && !N ? /* @__PURE__ */ O(a, {
249
+ count: 3,
250
+ height: "h-24"
251
+ }) : s ? /* @__PURE__ */ O(i, {
252
+ title: "Couldn't load your portfolio",
253
+ error: s
254
+ }) : P.length === 0 ? /* @__PURE__ */ O(r, {
255
+ icon: /* @__PURE__ */ O(v, { size: 26 }),
256
+ title: "Your portfolio is empty",
257
+ description: "Add a certificate, completed course, or submitted hackathon project to start building your showcase.",
258
+ action: /* @__PURE__ */ k(A, {
259
+ onClick: () => T(!0),
260
+ children: [/* @__PURE__ */ O(w, { size: 15 }), " Add your first item"]
261
+ })
262
+ }) : /* @__PURE__ */ O("div", {
263
+ className: "space-y-3",
264
+ children: P.map((e) => /* @__PURE__ */ O(B, {
265
+ item: e,
266
+ onRemove: () => void I(e.id, e.title)
267
+ }, e.id))
268
+ })
269
+ ]
270
+ });
271
+ }
272
+ //#endregion
273
+ export { W as ApplicationsPortfolioPagePage };
274
+
275
+ //# sourceMappingURL=ApplicationsPortfolioPagePage.js.map