@burdenoff/microfe-buildmyiq 2026.705.3 → 2026.705.5

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.
@@ -57,7 +57,7 @@ var a = () => {
57
57
  }, c = 24, l = (e, t = c) => e ? {
58
58
  limit: t,
59
59
  cursor: e
60
- } : { limit: t }, u = "id name url mimeType", d = "\n id workspaceId name category description isActive createdAt updatedAt\n", f = `
60
+ } : { limit: t }, u = "id name downloadUrl mimeType", d = "\n id workspaceId name category description isActive createdAt updatedAt\n", f = `
61
61
  id workspaceId title slug summary description status level language
62
62
  estimatedHours isPublic tags skillId instructorId publishedAt createdAt updatedAt
63
63
  cover { ${u} }
@@ -1 +1 @@
1
- {"version":3,"file":"useBuildmyiqApi.js","names":[],"sources":["../../../src/buildmyiq/hooks/useBuildmyiqApi.ts"],"sourcesContent":["/**\n * Buildmyiq API hooks\n * @module buildmyiq/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-buildmyiq-svc`\n * federated GraphQL contract (the `bui*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data, no codegen.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL + a workspace-scoped token.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useBuildmyiq } from '../context';\nimport type {\n BuiConnection,\n BuiCourse,\n BuiCourseLevel,\n BuiCourseStatus,\n BuiModule,\n BuiLesson,\n BuiAssessment,\n BuiAssessmentStatus,\n BuiQuestion,\n BuiSubmission,\n BuiSubmissionStatus,\n BuiEnrollment,\n BuiEnrollmentStatus,\n BuiCohort,\n BuiCohortStatus,\n BuiSkill,\n BuiSkillCategory,\n BuiCertificate,\n BuiLessonProgress,\n BuiCreateCourseInput,\n BuiUpdateCourseInput,\n BuiCreateModuleInput,\n BuiCreateLessonInput,\n BuiCreateAssessmentInput,\n BuiCreateQuestionInput,\n BuiCreateSkillInput,\n BuiCreateCohortInput,\n BuiEnrollInput,\n BuiRecordLessonProgressInput,\n BuiSubmitAssessmentInput,\n BuiGradeSubmissionInput,\n BuiIssueCertificateInput,\n PaginationInput,\n} from '../types';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in an in-memory cache keyed\n * by operationName+variables for ~15s (mutations are never cached). A read\n * issued right after a write (e.g. the React-Query refetch triggered by our\n * `invalidateQueries`) would otherwise return the PRE-mutation response until the\n * TTL expires — making just-created/updated rows invisible until a full reload.\n * We clear those caches after every buildmyiq mutation so every follow-up read\n * is fresh.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\nconst buiQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n if (/^\\s*mutation\\b/.test(query)) {\n clearGraphqlReadCaches();\n }\n return response.data;\n};\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n courses: ['buildmyiq', 'courses'] as const,\n course: (id: string) => ['buildmyiq', 'course', id] as const,\n modules: (courseId: string) => ['buildmyiq', 'modules', courseId] as const,\n lessons: (courseId: string) => ['buildmyiq', 'lessons', courseId] as const,\n assessments: (courseId: string) => ['buildmyiq', 'assessments', courseId] as const,\n assessment: (id: string) => ['buildmyiq', 'assessment', id] as const,\n enrollments: ['buildmyiq', 'enrollments'] as const,\n enrollment: (id: string) => ['buildmyiq', 'enrollment', id] as const,\n certificates: ['buildmyiq', 'certificates'] as const,\n cohorts: ['buildmyiq', 'cohorts'] as const,\n skills: ['buildmyiq', 'skills'] as const,\n submissions: ['buildmyiq', 'submissions'] as const,\n};\n\nconst DEFAULT_PAGE_SIZE = 24;\n\n/**\n * Build a `PaginationInput` for a list query. The FIRST page (undefined cursor)\n * OMITS the cursor key entirely — the svc rejects an explicit `cursor: null`.\n */\nconst pageVars = (cursor?: string, limit = DEFAULT_PAGE_SIZE): PaginationInput =>\n cursor ? { limit, cursor } : { limit };\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness)\n// ============================================================================\n\nconst FILE_FIELDS = `id name url mimeType`;\n\nconst SKILL_FIELDS = `\n id workspaceId name category description isActive createdAt updatedAt\n`;\n\nconst COURSE_CORE_FIELDS = `\n id workspaceId title slug summary description status level language\n estimatedHours isPublic tags skillId instructorId publishedAt createdAt updatedAt\n cover { ${FILE_FIELDS} }\n skill { id name category }\n`;\n\nconst MODULE_FIELDS = `\n id workspaceId courseId title description position createdAt updatedAt\n`;\n\nconst LESSON_FIELDS = `\n id workspaceId courseId moduleId title type content durationMin position isPreview\n createdAt updatedAt\n media { ${FILE_FIELDS} }\n`;\n\nconst COURSE_FULL_FIELDS = `\n ${COURSE_CORE_FIELDS}\n modules { ${MODULE_FIELDS} lessons { ${LESSON_FIELDS} } }\n lessons { ${LESSON_FIELDS} }\n`;\n\nconst ASSESSMENT_FIELDS = `\n id workspaceId courseId title description type status passingScore maxAttempts\n timeLimitMin isGraded createdAt updatedAt\n`;\n\n// NOTE: BuiQuestion has NO `answerKey` on the type (create-input only).\nconst QUESTION_FIELDS = `\n id workspaceId assessmentId prompt type options points position explanation\n createdAt updatedAt\n`;\n\nconst ASSESSMENT_FULL_FIELDS = `\n ${ASSESSMENT_FIELDS}\n questions { ${QUESTION_FIELDS} }\n`;\n\nconst SUBMISSION_FIELDS = `\n id workspaceId assessmentId enrollmentId learnerId attempt answers status score\n passed feedback gradedById gradedAt submittedAt createdAt updatedAt\n`;\n\nconst COHORT_FIELDS = `\n id workspaceId courseId name capacity facilitatorId startDate endDate status\n createdAt updatedAt\n`;\n\nconst LESSON_PROGRESS_FIELDS = `\n id workspaceId enrollmentId lessonId status secondsSpent completedAt createdAt updatedAt\n`;\n\nconst ENROLLMENT_FIELDS = `\n id workspaceId courseId learnerId cohortId status progressPct enrolledAt startedAt\n completedAt lastActiveAt expiresAt createdAt updatedAt\n`;\n\nconst ENROLLMENT_FULL_FIELDS = `\n ${ENROLLMENT_FIELDS}\n cohort { ${COHORT_FIELDS} }\n lessonProgress { ${LESSON_PROGRESS_FIELDS} }\n`;\n\nconst CERTIFICATE_FIELDS = `\n id workspaceId courseId learnerId enrollmentId serial status issuedAt expiresAt\n revokedAt finalScore createdAt updatedAt\n file { ${FILE_FIELDS} }\n`;\n\n// ============================================================================\n// Shared hook helper: resolve gateway URL from context\n// ============================================================================\n\nconst useGateway = (): string | undefined => {\n const { apiGatewayUrl } = useBuildmyiq();\n return apiGatewayUrl;\n};\n\n// ============================================================================\n// Courses\n// ============================================================================\n\nexport interface UseBuiCoursesArgs {\n level?: BuiCourseLevel;\n status?: BuiCourseStatus;\n cursor?: string;\n limit?: number;\n enabled?: boolean;\n}\n\nexport const useBuiCourses = (args: UseBuiCoursesArgs = {}) => {\n const baseUrl = useGateway();\n const { level, status, cursor, limit, enabled = true } = args;\n return useQuery({\n queryKey: [...KEY.courses, { level, status, cursor, limit }],\n enabled,\n queryFn: async () => {\n const data = await buiQuery<{ buiListCourses: BuiConnection<BuiCourse> }>(\n `query BuiListCourses($level: BuiCourseLevel, $status: BuiCourseStatus, $pagination: PaginationInput) {\n buiListCourses(level: $level, status: $status, pagination: $pagination) {\n items { ${COURSE_CORE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { level, status, pagination: pageVars(cursor, limit) },\n baseUrl\n );\n return data.buiListCourses;\n },\n });\n};\n\nexport const useBuiCourse = (id: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: id ? KEY.course(id) : ['buildmyiq', 'course', 'nil'],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await buiQuery<{ buiCourse: BuiCourse | null }>(\n `query BuiCourse($id: ID!) {\n buiCourse(id: $id) { ${COURSE_FULL_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiCourse;\n },\n });\n};\n\nexport const useBuiCreateCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateCourseInput) => {\n const data = await buiQuery<{ buiCreateCourse: BuiCourse }>(\n `mutation BuiCreateCourse($input: BuiCreateCourseInput!) {\n buiCreateCourse(input: $input) { ${COURSE_CORE_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateCourse;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.courses }),\n });\n};\n\nexport const useBuiUpdateCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiUpdateCourseInput }) => {\n const data = await buiQuery<{ buiUpdateCourse: BuiCourse }>(\n `mutation BuiUpdateCourse($id: ID!, $input: BuiUpdateCourseInput!) {\n buiUpdateCourse(id: $id, input: $input) { ${COURSE_CORE_FIELDS} }\n }`,\n args,\n baseUrl\n );\n return data.buiUpdateCourse;\n },\n onSuccess: (course) => {\n qc.invalidateQueries({ queryKey: KEY.courses });\n qc.invalidateQueries({ queryKey: KEY.course(course.id) });\n },\n });\n};\n\nexport const useBuiPublishCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiPublishCourse: BuiCourse }>(\n `mutation BuiPublishCourse($id: ID!) {\n buiPublishCourse(id: $id) { ${COURSE_CORE_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiPublishCourse;\n },\n onSuccess: (course) => {\n qc.invalidateQueries({ queryKey: KEY.courses });\n qc.invalidateQueries({ queryKey: KEY.course(course.id) });\n },\n });\n};\n\nexport const useBuiArchiveCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiArchiveCourse: boolean }>(\n `mutation BuiArchiveCourse($id: ID!) { buiArchiveCourse(id: $id) }`,\n { id },\n baseUrl\n );\n return data.buiArchiveCourse;\n },\n onSuccess: (_r, id) => {\n qc.invalidateQueries({ queryKey: KEY.courses });\n qc.invalidateQueries({ queryKey: KEY.course(id) });\n },\n });\n};\n\n// ============================================================================\n// Modules & lessons\n// ============================================================================\n\nexport const useBuiModules = (courseId: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: courseId ? KEY.modules(courseId) : ['buildmyiq', 'modules', 'nil'],\n enabled: Boolean(courseId),\n queryFn: async () => {\n const data = await buiQuery<{ buiListModules: BuiModule[] }>(\n `query BuiListModules($courseId: ID!) {\n buiListModules(courseId: $courseId) { ${MODULE_FIELDS} lessons { ${LESSON_FIELDS} } }\n }`,\n { courseId },\n baseUrl\n );\n return data.buiListModules;\n },\n });\n};\n\nexport const useBuiLessons = (courseId: string | undefined, moduleId?: string) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: courseId ? [...KEY.lessons(courseId), { moduleId }] : ['buildmyiq', 'lessons', 'nil'],\n enabled: Boolean(courseId),\n queryFn: async () => {\n const data = await buiQuery<{ buiListLessons: BuiLesson[] }>(\n `query BuiListLessons($courseId: ID!, $moduleId: ID) {\n buiListLessons(courseId: $courseId, moduleId: $moduleId) { ${LESSON_FIELDS} }\n }`,\n { courseId, moduleId },\n baseUrl\n );\n return data.buiListLessons;\n },\n });\n};\n\nexport const useBuiCreateModule = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateModuleInput) => {\n const data = await buiQuery<{ buiCreateModule: BuiModule }>(\n `mutation BuiCreateModule($input: BuiCreateModuleInput!) {\n buiCreateModule(input: $input) { ${MODULE_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateModule;\n },\n onSuccess: (m) => {\n qc.invalidateQueries({ queryKey: KEY.modules(m.courseId) });\n qc.invalidateQueries({ queryKey: KEY.course(m.courseId) });\n },\n });\n};\n\nexport const useBuiCreateLesson = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateLessonInput) => {\n const data = await buiQuery<{ buiCreateLesson: BuiLesson }>(\n `mutation BuiCreateLesson($input: BuiCreateLessonInput!) {\n buiCreateLesson(input: $input) { ${LESSON_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateLesson;\n },\n onSuccess: (l) => {\n qc.invalidateQueries({ queryKey: KEY.lessons(l.courseId) });\n qc.invalidateQueries({ queryKey: KEY.modules(l.courseId) });\n qc.invalidateQueries({ queryKey: KEY.course(l.courseId) });\n },\n });\n};\n\n// ============================================================================\n// Assessments & questions\n// ============================================================================\n\nexport const useBuiAssessments = (courseId: string | undefined, status?: BuiAssessmentStatus) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: courseId\n ? [...KEY.assessments(courseId), { status }]\n : ['buildmyiq', 'assessments', 'nil'],\n enabled: Boolean(courseId),\n queryFn: async () => {\n const data = await buiQuery<{ buiListAssessments: BuiAssessment[] }>(\n `query BuiListAssessments($courseId: ID!, $status: BuiAssessmentStatus) {\n buiListAssessments(courseId: $courseId, status: $status) { ${ASSESSMENT_FIELDS} }\n }`,\n { courseId, status },\n baseUrl\n );\n return data.buiListAssessments;\n },\n });\n};\n\nexport const useBuiAssessment = (id: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: id ? KEY.assessment(id) : ['buildmyiq', 'assessment', 'nil'],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await buiQuery<{ buiAssessment: BuiAssessment | null }>(\n `query BuiAssessment($id: ID!) {\n buiAssessment(id: $id) { ${ASSESSMENT_FULL_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiAssessment;\n },\n });\n};\n\nexport const useBuiCreateAssessment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateAssessmentInput) => {\n const data = await buiQuery<{ buiCreateAssessment: BuiAssessment }>(\n `mutation BuiCreateAssessment($input: BuiCreateAssessmentInput!) {\n buiCreateAssessment(input: $input) { ${ASSESSMENT_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateAssessment;\n },\n onSuccess: (a) => qc.invalidateQueries({ queryKey: KEY.assessments(a.courseId) }),\n });\n};\n\nexport const useBuiPublishAssessment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiPublishAssessment: BuiAssessment }>(\n `mutation BuiPublishAssessment($id: ID!) {\n buiPublishAssessment(id: $id) { ${ASSESSMENT_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiPublishAssessment;\n },\n onSuccess: (a) => {\n qc.invalidateQueries({ queryKey: KEY.assessment(a.id) });\n qc.invalidateQueries({ queryKey: KEY.assessments(a.courseId) });\n },\n });\n};\n\nexport const useBuiCreateQuestion = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateQuestionInput) => {\n const data = await buiQuery<{ buiCreateQuestion: BuiQuestion }>(\n `mutation BuiCreateQuestion($input: BuiCreateQuestionInput!) {\n buiCreateQuestion(input: $input) { ${QUESTION_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateQuestion;\n },\n onSuccess: (q) => qc.invalidateQueries({ queryKey: KEY.assessment(q.assessmentId) }),\n });\n};\n\n// ============================================================================\n// Submissions & grading\n// ============================================================================\n\nexport interface UseBuiSubmissionsArgs {\n assessmentId?: string;\n learnerId?: string;\n status?: BuiSubmissionStatus;\n cursor?: string;\n limit?: number;\n enabled?: boolean;\n}\n\nexport const useBuiSubmissions = (args: UseBuiSubmissionsArgs = {}) => {\n const baseUrl = useGateway();\n const { assessmentId, learnerId, status, cursor, limit, enabled = true } = args;\n return useQuery({\n queryKey: [...KEY.submissions, { assessmentId, learnerId, status, cursor, limit }],\n enabled,\n queryFn: async () => {\n const data = await buiQuery<{ buiListSubmissions: BuiConnection<BuiSubmission> }>(\n `query BuiListSubmissions($assessmentId: ID, $learnerId: ID, $status: BuiSubmissionStatus, $pagination: PaginationInput) {\n buiListSubmissions(assessmentId: $assessmentId, learnerId: $learnerId, status: $status, pagination: $pagination) {\n items { ${SUBMISSION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { assessmentId, learnerId, status, pagination: pageVars(cursor, limit) },\n baseUrl\n );\n return data.buiListSubmissions;\n },\n });\n};\n\nexport const useBuiSubmitAssessment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiSubmitAssessmentInput) => {\n const data = await buiQuery<{ buiSubmitAssessment: BuiSubmission }>(\n `mutation BuiSubmitAssessment($input: BuiSubmitAssessmentInput!) {\n buiSubmitAssessment(input: $input) { ${SUBMISSION_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiSubmitAssessment;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.submissions }),\n });\n};\n\nexport const useBuiGradeSubmission = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiGradeSubmissionInput }) => {\n const data = await buiQuery<{ buiGradeSubmission: BuiSubmission }>(\n `mutation BuiGradeSubmission($id: ID!, $input: BuiGradeSubmissionInput!) {\n buiGradeSubmission(id: $id, input: $input) { ${SUBMISSION_FIELDS} }\n }`,\n args,\n baseUrl\n );\n return data.buiGradeSubmission;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.submissions }),\n });\n};\n\n// ============================================================================\n// Enrollments & progress\n// ============================================================================\n\nexport interface UseBuiEnrollmentsArgs {\n courseId?: string;\n learnerId?: string;\n status?: BuiEnrollmentStatus;\n cursor?: string;\n limit?: number;\n enabled?: boolean;\n}\n\nexport const useBuiEnrollments = (args: UseBuiEnrollmentsArgs = {}) => {\n const baseUrl = useGateway();\n const { courseId, learnerId, status, cursor, limit, enabled = true } = args;\n return useQuery({\n queryKey: [...KEY.enrollments, { courseId, learnerId, status, cursor, limit }],\n enabled,\n queryFn: async () => {\n const data = await buiQuery<{ buiListEnrollments: BuiConnection<BuiEnrollment> }>(\n `query BuiListEnrollments($courseId: ID, $learnerId: ID, $status: BuiEnrollmentStatus, $pagination: PaginationInput) {\n buiListEnrollments(courseId: $courseId, learnerId: $learnerId, status: $status, pagination: $pagination) {\n items { ${ENROLLMENT_FIELDS} cohort { ${COHORT_FIELDS} } }\n pageInfo { cursor hasMore }\n }\n }`,\n { courseId, learnerId, status, pagination: pageVars(cursor, limit) },\n baseUrl\n );\n return data.buiListEnrollments;\n },\n });\n};\n\nexport const useBuiEnrollment = (id: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: id ? KEY.enrollment(id) : ['buildmyiq', 'enrollment', 'nil'],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await buiQuery<{ buiEnrollment: BuiEnrollment | null }>(\n `query BuiEnrollment($id: ID!) {\n buiEnrollment(id: $id) { ${ENROLLMENT_FULL_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiEnrollment;\n },\n });\n};\n\nexport const useBuiEnroll = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiEnrollInput) => {\n const data = await buiQuery<{ buiEnroll: BuiEnrollment }>(\n `mutation BuiEnroll($input: BuiEnrollInput!) {\n buiEnroll(input: $input) { ${ENROLLMENT_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiEnroll;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.enrollments }),\n });\n};\n\nexport const useBuiTransitionEnrollment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; status: BuiEnrollmentStatus }) => {\n const data = await buiQuery<{ buiTransitionEnrollment: BuiEnrollment }>(\n `mutation BuiTransitionEnrollment($id: ID!, $status: BuiEnrollmentStatus!) {\n buiTransitionEnrollment(id: $id, status: $status) { ${ENROLLMENT_FIELDS} }\n }`,\n args,\n baseUrl\n );\n return data.buiTransitionEnrollment;\n },\n onSuccess: (e) => {\n qc.invalidateQueries({ queryKey: KEY.enrollments });\n qc.invalidateQueries({ queryKey: KEY.enrollment(e.id) });\n },\n });\n};\n\nexport const useBuiRecordLessonProgress = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiRecordLessonProgressInput) => {\n const data = await buiQuery<{ buiRecordLessonProgress: BuiLessonProgress }>(\n `mutation BuiRecordLessonProgress($input: BuiRecordLessonProgressInput!) {\n buiRecordLessonProgress(input: $input) { ${LESSON_PROGRESS_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiRecordLessonProgress;\n },\n onSuccess: (p) => {\n qc.invalidateQueries({ queryKey: KEY.enrollment(p.enrollmentId) });\n qc.invalidateQueries({ queryKey: KEY.enrollments });\n },\n });\n};\n\n// ============================================================================\n// Cohorts\n// ============================================================================\n\nexport const useBuiCohorts = (courseId?: string, status?: BuiCohortStatus) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: [...KEY.cohorts, { courseId, status }],\n queryFn: async () => {\n const data = await buiQuery<{ buiListCohorts: BuiCohort[] }>(\n `query BuiListCohorts($courseId: ID, $status: BuiCohortStatus) {\n buiListCohorts(courseId: $courseId, status: $status) { ${COHORT_FIELDS} }\n }`,\n { courseId, status },\n baseUrl\n );\n return data.buiListCohorts;\n },\n });\n};\n\nexport const useBuiCreateCohort = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateCohortInput) => {\n const data = await buiQuery<{ buiCreateCohort: BuiCohort }>(\n `mutation BuiCreateCohort($input: BuiCreateCohortInput!) {\n buiCreateCohort(input: $input) { ${COHORT_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateCohort;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.cohorts }),\n });\n};\n\n// ============================================================================\n// Skills\n// ============================================================================\n\nexport const useBuiSkills = (category?: BuiSkillCategory) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: [...KEY.skills, { category }],\n queryFn: async () => {\n const data = await buiQuery<{ buiListSkills: BuiSkill[] }>(\n `query BuiListSkills($category: BuiSkillCategory) {\n buiListSkills(category: $category) { ${SKILL_FIELDS} }\n }`,\n { category },\n baseUrl\n );\n return data.buiListSkills;\n },\n });\n};\n\nexport const useBuiCreateSkill = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateSkillInput) => {\n const data = await buiQuery<{ buiCreateSkill: BuiSkill }>(\n `mutation BuiCreateSkill($input: BuiCreateSkillInput!) {\n buiCreateSkill(input: $input) { ${SKILL_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateSkill;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.skills }),\n });\n};\n\n// ============================================================================\n// Certificates\n// ============================================================================\n\nexport const useBuiCertificates = (courseId?: string, learnerId?: string) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: [...KEY.certificates, { courseId, learnerId }],\n queryFn: async () => {\n const data = await buiQuery<{ buiListCertificates: BuiCertificate[] }>(\n `query BuiListCertificates($courseId: ID, $learnerId: ID) {\n buiListCertificates(courseId: $courseId, learnerId: $learnerId) { ${CERTIFICATE_FIELDS} }\n }`,\n { courseId, learnerId },\n baseUrl\n );\n return data.buiListCertificates;\n },\n });\n};\n\nexport const useBuiIssueCertificate = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiIssueCertificateInput) => {\n const data = await buiQuery<{ buiIssueCertificate: BuiCertificate }>(\n `mutation BuiIssueCertificate($input: BuiIssueCertificateInput!) {\n buiIssueCertificate(input: $input) { ${CERTIFICATE_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiIssueCertificate;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.certificates }),\n });\n};\n\nexport const useBuiRevokeCertificate = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiRevokeCertificate: BuiCertificate }>(\n `mutation BuiRevokeCertificate($id: ID!) {\n buiRevokeCertificate(id: $id) { ${CERTIFICATE_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiRevokeCertificate;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.certificates }),\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useBuildmyiqApi.js","names":[],"sources":["../../../src/buildmyiq/hooks/useBuildmyiqApi.ts"],"sourcesContent":["/**\n * Buildmyiq API hooks\n * @module buildmyiq/hooks\n *\n * React-Query hooks wired DIRECTLY to the real `wspace-buildmyiq-svc`\n * federated GraphQL contract (the `bui*` operations). Every query/mutation\n * below uses an inline gql string whose fields match the svc\n * `.hive-schema.graphql` exactly. No mock data, no codegen.\n *\n * Transport: `graphqlFetch({ gateway: 'workspace', workspaceToken: true })` —\n * the host shell supplies the gateway base URL + a workspace-scoped token.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useBuildmyiq } from '../context';\nimport type {\n BuiConnection,\n BuiCourse,\n BuiCourseLevel,\n BuiCourseStatus,\n BuiModule,\n BuiLesson,\n BuiAssessment,\n BuiAssessmentStatus,\n BuiQuestion,\n BuiSubmission,\n BuiSubmissionStatus,\n BuiEnrollment,\n BuiEnrollmentStatus,\n BuiCohort,\n BuiCohortStatus,\n BuiSkill,\n BuiSkillCategory,\n BuiCertificate,\n BuiLessonProgress,\n BuiCreateCourseInput,\n BuiUpdateCourseInput,\n BuiCreateModuleInput,\n BuiCreateLessonInput,\n BuiCreateAssessmentInput,\n BuiCreateQuestionInput,\n BuiCreateSkillInput,\n BuiCreateCohortInput,\n BuiEnrollInput,\n BuiRecordLessonProgressInput,\n BuiSubmitAssessmentInput,\n BuiGradeSubmissionInput,\n BuiIssueCertificateInput,\n PaginationInput,\n} from '../types';\n\n// ============================================================================\n// Transport\n// ============================================================================\n\n/**\n * fe-libs `graphqlFetch` coalesces `query` responses in an in-memory cache keyed\n * by operationName+variables for ~15s (mutations are never cached). A read\n * issued right after a write (e.g. the React-Query refetch triggered by our\n * `invalidateQueries`) would otherwise return the PRE-mutation response until the\n * TTL expires — making just-created/updated rows invisible until a full reload.\n * We clear those caches after every buildmyiq mutation so every follow-up read\n * is fresh.\n */\ntype GraphqlReadCacheGlobals = {\n __graphqlFetchResponseCache?: { clear: () => void };\n __graphqlFetchPendingResponses?: { clear: () => void };\n __boffGraphQLResponseCache?: { clear: () => void };\n};\n\nconst clearGraphqlReadCaches = (): void => {\n const g = globalThis as GraphqlReadCacheGlobals;\n g.__graphqlFetchResponseCache?.clear();\n g.__graphqlFetchPendingResponses?.clear();\n g.__boffGraphQLResponseCache?.clear();\n};\n\nconst buiQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n if (/^\\s*mutation\\b/.test(query)) {\n clearGraphqlReadCaches();\n }\n return response.data;\n};\n\n// React-Query key roots (one namespace per domain entity).\nconst KEY = {\n courses: ['buildmyiq', 'courses'] as const,\n course: (id: string) => ['buildmyiq', 'course', id] as const,\n modules: (courseId: string) => ['buildmyiq', 'modules', courseId] as const,\n lessons: (courseId: string) => ['buildmyiq', 'lessons', courseId] as const,\n assessments: (courseId: string) => ['buildmyiq', 'assessments', courseId] as const,\n assessment: (id: string) => ['buildmyiq', 'assessment', id] as const,\n enrollments: ['buildmyiq', 'enrollments'] as const,\n enrollment: (id: string) => ['buildmyiq', 'enrollment', id] as const,\n certificates: ['buildmyiq', 'certificates'] as const,\n cohorts: ['buildmyiq', 'cohorts'] as const,\n skills: ['buildmyiq', 'skills'] as const,\n submissions: ['buildmyiq', 'submissions'] as const,\n};\n\nconst DEFAULT_PAGE_SIZE = 24;\n\n/**\n * Build a `PaginationInput` for a list query. The FIRST page (undefined cursor)\n * OMITS the cursor key entirely — the svc rejects an explicit `cursor: null`.\n */\nconst pageVars = (cursor?: string, limit = DEFAULT_PAGE_SIZE): PaginationInput =>\n cursor ? { limit, cursor } : { limit };\n\n// ============================================================================\n// Reusable gql field selections (codegen-free strictness)\n// ============================================================================\n\nconst FILE_FIELDS = `id name downloadUrl mimeType`;\n\nconst SKILL_FIELDS = `\n id workspaceId name category description isActive createdAt updatedAt\n`;\n\nconst COURSE_CORE_FIELDS = `\n id workspaceId title slug summary description status level language\n estimatedHours isPublic tags skillId instructorId publishedAt createdAt updatedAt\n cover { ${FILE_FIELDS} }\n skill { id name category }\n`;\n\nconst MODULE_FIELDS = `\n id workspaceId courseId title description position createdAt updatedAt\n`;\n\nconst LESSON_FIELDS = `\n id workspaceId courseId moduleId title type content durationMin position isPreview\n createdAt updatedAt\n media { ${FILE_FIELDS} }\n`;\n\nconst COURSE_FULL_FIELDS = `\n ${COURSE_CORE_FIELDS}\n modules { ${MODULE_FIELDS} lessons { ${LESSON_FIELDS} } }\n lessons { ${LESSON_FIELDS} }\n`;\n\nconst ASSESSMENT_FIELDS = `\n id workspaceId courseId title description type status passingScore maxAttempts\n timeLimitMin isGraded createdAt updatedAt\n`;\n\n// NOTE: BuiQuestion has NO `answerKey` on the type (create-input only).\nconst QUESTION_FIELDS = `\n id workspaceId assessmentId prompt type options points position explanation\n createdAt updatedAt\n`;\n\nconst ASSESSMENT_FULL_FIELDS = `\n ${ASSESSMENT_FIELDS}\n questions { ${QUESTION_FIELDS} }\n`;\n\nconst SUBMISSION_FIELDS = `\n id workspaceId assessmentId enrollmentId learnerId attempt answers status score\n passed feedback gradedById gradedAt submittedAt createdAt updatedAt\n`;\n\nconst COHORT_FIELDS = `\n id workspaceId courseId name capacity facilitatorId startDate endDate status\n createdAt updatedAt\n`;\n\nconst LESSON_PROGRESS_FIELDS = `\n id workspaceId enrollmentId lessonId status secondsSpent completedAt createdAt updatedAt\n`;\n\nconst ENROLLMENT_FIELDS = `\n id workspaceId courseId learnerId cohortId status progressPct enrolledAt startedAt\n completedAt lastActiveAt expiresAt createdAt updatedAt\n`;\n\nconst ENROLLMENT_FULL_FIELDS = `\n ${ENROLLMENT_FIELDS}\n cohort { ${COHORT_FIELDS} }\n lessonProgress { ${LESSON_PROGRESS_FIELDS} }\n`;\n\nconst CERTIFICATE_FIELDS = `\n id workspaceId courseId learnerId enrollmentId serial status issuedAt expiresAt\n revokedAt finalScore createdAt updatedAt\n file { ${FILE_FIELDS} }\n`;\n\n// ============================================================================\n// Shared hook helper: resolve gateway URL from context\n// ============================================================================\n\nconst useGateway = (): string | undefined => {\n const { apiGatewayUrl } = useBuildmyiq();\n return apiGatewayUrl;\n};\n\n// ============================================================================\n// Courses\n// ============================================================================\n\nexport interface UseBuiCoursesArgs {\n level?: BuiCourseLevel;\n status?: BuiCourseStatus;\n cursor?: string;\n limit?: number;\n enabled?: boolean;\n}\n\nexport const useBuiCourses = (args: UseBuiCoursesArgs = {}) => {\n const baseUrl = useGateway();\n const { level, status, cursor, limit, enabled = true } = args;\n return useQuery({\n queryKey: [...KEY.courses, { level, status, cursor, limit }],\n enabled,\n queryFn: async () => {\n const data = await buiQuery<{ buiListCourses: BuiConnection<BuiCourse> }>(\n `query BuiListCourses($level: BuiCourseLevel, $status: BuiCourseStatus, $pagination: PaginationInput) {\n buiListCourses(level: $level, status: $status, pagination: $pagination) {\n items { ${COURSE_CORE_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { level, status, pagination: pageVars(cursor, limit) },\n baseUrl\n );\n return data.buiListCourses;\n },\n });\n};\n\nexport const useBuiCourse = (id: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: id ? KEY.course(id) : ['buildmyiq', 'course', 'nil'],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await buiQuery<{ buiCourse: BuiCourse | null }>(\n `query BuiCourse($id: ID!) {\n buiCourse(id: $id) { ${COURSE_FULL_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiCourse;\n },\n });\n};\n\nexport const useBuiCreateCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateCourseInput) => {\n const data = await buiQuery<{ buiCreateCourse: BuiCourse }>(\n `mutation BuiCreateCourse($input: BuiCreateCourseInput!) {\n buiCreateCourse(input: $input) { ${COURSE_CORE_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateCourse;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.courses }),\n });\n};\n\nexport const useBuiUpdateCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiUpdateCourseInput }) => {\n const data = await buiQuery<{ buiUpdateCourse: BuiCourse }>(\n `mutation BuiUpdateCourse($id: ID!, $input: BuiUpdateCourseInput!) {\n buiUpdateCourse(id: $id, input: $input) { ${COURSE_CORE_FIELDS} }\n }`,\n args,\n baseUrl\n );\n return data.buiUpdateCourse;\n },\n onSuccess: (course) => {\n qc.invalidateQueries({ queryKey: KEY.courses });\n qc.invalidateQueries({ queryKey: KEY.course(course.id) });\n },\n });\n};\n\nexport const useBuiPublishCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiPublishCourse: BuiCourse }>(\n `mutation BuiPublishCourse($id: ID!) {\n buiPublishCourse(id: $id) { ${COURSE_CORE_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiPublishCourse;\n },\n onSuccess: (course) => {\n qc.invalidateQueries({ queryKey: KEY.courses });\n qc.invalidateQueries({ queryKey: KEY.course(course.id) });\n },\n });\n};\n\nexport const useBuiArchiveCourse = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiArchiveCourse: boolean }>(\n `mutation BuiArchiveCourse($id: ID!) { buiArchiveCourse(id: $id) }`,\n { id },\n baseUrl\n );\n return data.buiArchiveCourse;\n },\n onSuccess: (_r, id) => {\n qc.invalidateQueries({ queryKey: KEY.courses });\n qc.invalidateQueries({ queryKey: KEY.course(id) });\n },\n });\n};\n\n// ============================================================================\n// Modules & lessons\n// ============================================================================\n\nexport const useBuiModules = (courseId: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: courseId ? KEY.modules(courseId) : ['buildmyiq', 'modules', 'nil'],\n enabled: Boolean(courseId),\n queryFn: async () => {\n const data = await buiQuery<{ buiListModules: BuiModule[] }>(\n `query BuiListModules($courseId: ID!) {\n buiListModules(courseId: $courseId) { ${MODULE_FIELDS} lessons { ${LESSON_FIELDS} } }\n }`,\n { courseId },\n baseUrl\n );\n return data.buiListModules;\n },\n });\n};\n\nexport const useBuiLessons = (courseId: string | undefined, moduleId?: string) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: courseId ? [...KEY.lessons(courseId), { moduleId }] : ['buildmyiq', 'lessons', 'nil'],\n enabled: Boolean(courseId),\n queryFn: async () => {\n const data = await buiQuery<{ buiListLessons: BuiLesson[] }>(\n `query BuiListLessons($courseId: ID!, $moduleId: ID) {\n buiListLessons(courseId: $courseId, moduleId: $moduleId) { ${LESSON_FIELDS} }\n }`,\n { courseId, moduleId },\n baseUrl\n );\n return data.buiListLessons;\n },\n });\n};\n\nexport const useBuiCreateModule = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateModuleInput) => {\n const data = await buiQuery<{ buiCreateModule: BuiModule }>(\n `mutation BuiCreateModule($input: BuiCreateModuleInput!) {\n buiCreateModule(input: $input) { ${MODULE_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateModule;\n },\n onSuccess: (m) => {\n qc.invalidateQueries({ queryKey: KEY.modules(m.courseId) });\n qc.invalidateQueries({ queryKey: KEY.course(m.courseId) });\n },\n });\n};\n\nexport const useBuiCreateLesson = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateLessonInput) => {\n const data = await buiQuery<{ buiCreateLesson: BuiLesson }>(\n `mutation BuiCreateLesson($input: BuiCreateLessonInput!) {\n buiCreateLesson(input: $input) { ${LESSON_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateLesson;\n },\n onSuccess: (l) => {\n qc.invalidateQueries({ queryKey: KEY.lessons(l.courseId) });\n qc.invalidateQueries({ queryKey: KEY.modules(l.courseId) });\n qc.invalidateQueries({ queryKey: KEY.course(l.courseId) });\n },\n });\n};\n\n// ============================================================================\n// Assessments & questions\n// ============================================================================\n\nexport const useBuiAssessments = (courseId: string | undefined, status?: BuiAssessmentStatus) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: courseId\n ? [...KEY.assessments(courseId), { status }]\n : ['buildmyiq', 'assessments', 'nil'],\n enabled: Boolean(courseId),\n queryFn: async () => {\n const data = await buiQuery<{ buiListAssessments: BuiAssessment[] }>(\n `query BuiListAssessments($courseId: ID!, $status: BuiAssessmentStatus) {\n buiListAssessments(courseId: $courseId, status: $status) { ${ASSESSMENT_FIELDS} }\n }`,\n { courseId, status },\n baseUrl\n );\n return data.buiListAssessments;\n },\n });\n};\n\nexport const useBuiAssessment = (id: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: id ? KEY.assessment(id) : ['buildmyiq', 'assessment', 'nil'],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await buiQuery<{ buiAssessment: BuiAssessment | null }>(\n `query BuiAssessment($id: ID!) {\n buiAssessment(id: $id) { ${ASSESSMENT_FULL_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiAssessment;\n },\n });\n};\n\nexport const useBuiCreateAssessment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateAssessmentInput) => {\n const data = await buiQuery<{ buiCreateAssessment: BuiAssessment }>(\n `mutation BuiCreateAssessment($input: BuiCreateAssessmentInput!) {\n buiCreateAssessment(input: $input) { ${ASSESSMENT_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateAssessment;\n },\n onSuccess: (a) => qc.invalidateQueries({ queryKey: KEY.assessments(a.courseId) }),\n });\n};\n\nexport const useBuiPublishAssessment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiPublishAssessment: BuiAssessment }>(\n `mutation BuiPublishAssessment($id: ID!) {\n buiPublishAssessment(id: $id) { ${ASSESSMENT_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiPublishAssessment;\n },\n onSuccess: (a) => {\n qc.invalidateQueries({ queryKey: KEY.assessment(a.id) });\n qc.invalidateQueries({ queryKey: KEY.assessments(a.courseId) });\n },\n });\n};\n\nexport const useBuiCreateQuestion = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateQuestionInput) => {\n const data = await buiQuery<{ buiCreateQuestion: BuiQuestion }>(\n `mutation BuiCreateQuestion($input: BuiCreateQuestionInput!) {\n buiCreateQuestion(input: $input) { ${QUESTION_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateQuestion;\n },\n onSuccess: (q) => qc.invalidateQueries({ queryKey: KEY.assessment(q.assessmentId) }),\n });\n};\n\n// ============================================================================\n// Submissions & grading\n// ============================================================================\n\nexport interface UseBuiSubmissionsArgs {\n assessmentId?: string;\n learnerId?: string;\n status?: BuiSubmissionStatus;\n cursor?: string;\n limit?: number;\n enabled?: boolean;\n}\n\nexport const useBuiSubmissions = (args: UseBuiSubmissionsArgs = {}) => {\n const baseUrl = useGateway();\n const { assessmentId, learnerId, status, cursor, limit, enabled = true } = args;\n return useQuery({\n queryKey: [...KEY.submissions, { assessmentId, learnerId, status, cursor, limit }],\n enabled,\n queryFn: async () => {\n const data = await buiQuery<{ buiListSubmissions: BuiConnection<BuiSubmission> }>(\n `query BuiListSubmissions($assessmentId: ID, $learnerId: ID, $status: BuiSubmissionStatus, $pagination: PaginationInput) {\n buiListSubmissions(assessmentId: $assessmentId, learnerId: $learnerId, status: $status, pagination: $pagination) {\n items { ${SUBMISSION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { assessmentId, learnerId, status, pagination: pageVars(cursor, limit) },\n baseUrl\n );\n return data.buiListSubmissions;\n },\n });\n};\n\nexport const useBuiSubmitAssessment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiSubmitAssessmentInput) => {\n const data = await buiQuery<{ buiSubmitAssessment: BuiSubmission }>(\n `mutation BuiSubmitAssessment($input: BuiSubmitAssessmentInput!) {\n buiSubmitAssessment(input: $input) { ${SUBMISSION_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiSubmitAssessment;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.submissions }),\n });\n};\n\nexport const useBuiGradeSubmission = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiGradeSubmissionInput }) => {\n const data = await buiQuery<{ buiGradeSubmission: BuiSubmission }>(\n `mutation BuiGradeSubmission($id: ID!, $input: BuiGradeSubmissionInput!) {\n buiGradeSubmission(id: $id, input: $input) { ${SUBMISSION_FIELDS} }\n }`,\n args,\n baseUrl\n );\n return data.buiGradeSubmission;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.submissions }),\n });\n};\n\n// ============================================================================\n// Enrollments & progress\n// ============================================================================\n\nexport interface UseBuiEnrollmentsArgs {\n courseId?: string;\n learnerId?: string;\n status?: BuiEnrollmentStatus;\n cursor?: string;\n limit?: number;\n enabled?: boolean;\n}\n\nexport const useBuiEnrollments = (args: UseBuiEnrollmentsArgs = {}) => {\n const baseUrl = useGateway();\n const { courseId, learnerId, status, cursor, limit, enabled = true } = args;\n return useQuery({\n queryKey: [...KEY.enrollments, { courseId, learnerId, status, cursor, limit }],\n enabled,\n queryFn: async () => {\n const data = await buiQuery<{ buiListEnrollments: BuiConnection<BuiEnrollment> }>(\n `query BuiListEnrollments($courseId: ID, $learnerId: ID, $status: BuiEnrollmentStatus, $pagination: PaginationInput) {\n buiListEnrollments(courseId: $courseId, learnerId: $learnerId, status: $status, pagination: $pagination) {\n items { ${ENROLLMENT_FIELDS} cohort { ${COHORT_FIELDS} } }\n pageInfo { cursor hasMore }\n }\n }`,\n { courseId, learnerId, status, pagination: pageVars(cursor, limit) },\n baseUrl\n );\n return data.buiListEnrollments;\n },\n });\n};\n\nexport const useBuiEnrollment = (id: string | undefined) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: id ? KEY.enrollment(id) : ['buildmyiq', 'enrollment', 'nil'],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await buiQuery<{ buiEnrollment: BuiEnrollment | null }>(\n `query BuiEnrollment($id: ID!) {\n buiEnrollment(id: $id) { ${ENROLLMENT_FULL_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiEnrollment;\n },\n });\n};\n\nexport const useBuiEnroll = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiEnrollInput) => {\n const data = await buiQuery<{ buiEnroll: BuiEnrollment }>(\n `mutation BuiEnroll($input: BuiEnrollInput!) {\n buiEnroll(input: $input) { ${ENROLLMENT_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiEnroll;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.enrollments }),\n });\n};\n\nexport const useBuiTransitionEnrollment = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; status: BuiEnrollmentStatus }) => {\n const data = await buiQuery<{ buiTransitionEnrollment: BuiEnrollment }>(\n `mutation BuiTransitionEnrollment($id: ID!, $status: BuiEnrollmentStatus!) {\n buiTransitionEnrollment(id: $id, status: $status) { ${ENROLLMENT_FIELDS} }\n }`,\n args,\n baseUrl\n );\n return data.buiTransitionEnrollment;\n },\n onSuccess: (e) => {\n qc.invalidateQueries({ queryKey: KEY.enrollments });\n qc.invalidateQueries({ queryKey: KEY.enrollment(e.id) });\n },\n });\n};\n\nexport const useBuiRecordLessonProgress = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiRecordLessonProgressInput) => {\n const data = await buiQuery<{ buiRecordLessonProgress: BuiLessonProgress }>(\n `mutation BuiRecordLessonProgress($input: BuiRecordLessonProgressInput!) {\n buiRecordLessonProgress(input: $input) { ${LESSON_PROGRESS_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiRecordLessonProgress;\n },\n onSuccess: (p) => {\n qc.invalidateQueries({ queryKey: KEY.enrollment(p.enrollmentId) });\n qc.invalidateQueries({ queryKey: KEY.enrollments });\n },\n });\n};\n\n// ============================================================================\n// Cohorts\n// ============================================================================\n\nexport const useBuiCohorts = (courseId?: string, status?: BuiCohortStatus) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: [...KEY.cohorts, { courseId, status }],\n queryFn: async () => {\n const data = await buiQuery<{ buiListCohorts: BuiCohort[] }>(\n `query BuiListCohorts($courseId: ID, $status: BuiCohortStatus) {\n buiListCohorts(courseId: $courseId, status: $status) { ${COHORT_FIELDS} }\n }`,\n { courseId, status },\n baseUrl\n );\n return data.buiListCohorts;\n },\n });\n};\n\nexport const useBuiCreateCohort = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateCohortInput) => {\n const data = await buiQuery<{ buiCreateCohort: BuiCohort }>(\n `mutation BuiCreateCohort($input: BuiCreateCohortInput!) {\n buiCreateCohort(input: $input) { ${COHORT_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateCohort;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.cohorts }),\n });\n};\n\n// ============================================================================\n// Skills\n// ============================================================================\n\nexport const useBuiSkills = (category?: BuiSkillCategory) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: [...KEY.skills, { category }],\n queryFn: async () => {\n const data = await buiQuery<{ buiListSkills: BuiSkill[] }>(\n `query BuiListSkills($category: BuiSkillCategory) {\n buiListSkills(category: $category) { ${SKILL_FIELDS} }\n }`,\n { category },\n baseUrl\n );\n return data.buiListSkills;\n },\n });\n};\n\nexport const useBuiCreateSkill = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiCreateSkillInput) => {\n const data = await buiQuery<{ buiCreateSkill: BuiSkill }>(\n `mutation BuiCreateSkill($input: BuiCreateSkillInput!) {\n buiCreateSkill(input: $input) { ${SKILL_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiCreateSkill;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.skills }),\n });\n};\n\n// ============================================================================\n// Certificates\n// ============================================================================\n\nexport const useBuiCertificates = (courseId?: string, learnerId?: string) => {\n const baseUrl = useGateway();\n return useQuery({\n queryKey: [...KEY.certificates, { courseId, learnerId }],\n queryFn: async () => {\n const data = await buiQuery<{ buiListCertificates: BuiCertificate[] }>(\n `query BuiListCertificates($courseId: ID, $learnerId: ID) {\n buiListCertificates(courseId: $courseId, learnerId: $learnerId) { ${CERTIFICATE_FIELDS} }\n }`,\n { courseId, learnerId },\n baseUrl\n );\n return data.buiListCertificates;\n },\n });\n};\n\nexport const useBuiIssueCertificate = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (input: BuiIssueCertificateInput) => {\n const data = await buiQuery<{ buiIssueCertificate: BuiCertificate }>(\n `mutation BuiIssueCertificate($input: BuiIssueCertificateInput!) {\n buiIssueCertificate(input: $input) { ${CERTIFICATE_FIELDS} }\n }`,\n { input },\n baseUrl\n );\n return data.buiIssueCertificate;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.certificates }),\n });\n};\n\nexport const useBuiRevokeCertificate = () => {\n const baseUrl = useGateway();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await buiQuery<{ buiRevokeCertificate: BuiCertificate }>(\n `mutation BuiRevokeCertificate($id: ID!) {\n buiRevokeCertificate(id: $id) { ${CERTIFICATE_FIELDS} }\n }`,\n { id },\n baseUrl\n );\n return data.buiRevokeCertificate;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: KEY.certificates }),\n });\n};\n"],"mappings":"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"}
@@ -14,8 +14,8 @@ var l = ({ course: l, onClick: u, showStatus: d, className: f }) => {
14
14
  onClick: u,
15
15
  children: [/* @__PURE__ */ s("div", {
16
16
  className: "relative h-32 w-full overflow-hidden bg-bg-sunken",
17
- children: [l.cover?.url ? /* @__PURE__ */ o("img", {
18
- src: l.cover.url,
17
+ children: [l.cover?.downloadUrl ? /* @__PURE__ */ o("img", {
18
+ src: l.cover.downloadUrl,
19
19
  alt: "",
20
20
  className: "h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
21
21
  }) : /* @__PURE__ */ o("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"CourseCard.js","names":[],"sources":["../../../../src/buildmyiq/pages/_shared/CourseCard.tsx"],"sourcesContent":["/**\n * CourseCard — a reusable course tile for catalog / authoring grids.\n * @module buildmyiq/pages/_shared\n */\n\nimport type { FC } from 'react';\nimport { BookOpen, Clock, Layers } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from '../../components';\nimport { cn } from '../../utils/cn';\nimport { formatHours } from '../../utils/formatters';\nimport type { BuiCourse } from '../../types';\n\ninterface CourseCardProps {\n course: BuiCourse;\n onClick?: () => void;\n /** Show the workflow status pill (authoring view) in addition to level. */\n showStatus?: boolean;\n className?: string;\n}\n\nexport const CourseCard: FC<CourseCardProps> = ({ course, onClick, showStatus, className }) => {\n const moduleCount = course.modules?.length ?? 0;\n const lessonCount = course.lessons?.length ?? 0;\n\n return (\n <GlassCard\n treatment=\"plain\"\n className={cn(\n 'group flex flex-col overflow-hidden transition-shadow',\n onClick && 'cursor-pointer hover:shadow-lg',\n className\n )}\n onClick={onClick}\n >\n <div className=\"relative h-32 w-full overflow-hidden bg-bg-sunken\">\n {course.cover?.url ? (\n <img\n src={course.cover.url}\n alt=\"\"\n className=\"h-full w-full object-cover transition-transform duration-500 group-hover:scale-105\"\n />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center bg-[var(--color-accent-soft)]\">\n <BookOpen className=\"h-8 w-8 text-text-secondary opacity-60\" />\n </div>\n )}\n <div className=\"absolute left-2 top-2 flex flex-wrap gap-1.5\">\n <StatusBadge status={course.level} />\n {showStatus && <StatusBadge status={course.status} />}\n </div>\n </div>\n\n <div className=\"flex flex-1 flex-col gap-2 p-4\">\n <h3 className=\"line-clamp-2 font-semibold text-text-primary\">{course.title}</h3>\n {course.summary && (\n <p className=\"line-clamp-2 text-sm text-text-secondary\">{course.summary}</p>\n )}\n <div className=\"mt-auto flex flex-wrap items-center gap-3 pt-2 text-xs text-text-secondary\">\n {course.skill?.name && (\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">{course.skill.name}</span>\n )}\n <span className=\"inline-flex items-center gap-1\">\n <Layers className=\"h-3.5 w-3.5\" /> {moduleCount} mod · {lessonCount} lessons\n </span>\n {course.estimatedHours > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatHours(course.estimatedHours)}\n </span>\n )}\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;;;;;AAqBA,IAAa,KAAmC,EAAE,WAAQ,YAAS,eAAY,mBAAgB;CAC7F,IAAM,IAAc,EAAO,SAAS,UAAU,GACxC,IAAc,EAAO,SAAS,UAAU;AAE9C,QACE,kBAAC,GAAD;EACE,WAAU;EACV,WAAW,EACT,yDACA,KAAW,kCACX,EACD;EACQ;YAPX,CASE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAO,OAAO,MACb,kBAAC,OAAD;IACE,KAAK,EAAO,MAAM;IAClB,KAAI;IACJ,WAAU;IACV,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAU,WAAU,0CAA2C,CAAA;IAC3D,CAAA,EAER,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAO,OAAS,CAAA,EACpC,KAAc,kBAAC,GAAD,EAAa,QAAQ,EAAO,QAAU,CAAA,CACjD;MACF;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eAAgD,EAAO;KAAW,CAAA;IAC/E,EAAO,WACN,kBAAC,KAAD;KAAG,WAAU;eAA4C,EAAO;KAAY,CAAA;IAE9E,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAO,OAAO,QACb,kBAAC,QAAD;OAAM,WAAU;iBAAyC,EAAO,MAAM;OAAY,CAAA;MAEpF,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA;;QAAE;QAAY;QAAQ;QAAY;QAC/D;;MACN,EAAO,iBAAiB,KACvB,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA;;QAAE,EAAY,EAAO,eAAe;QAChE;;MAEL;;IACF;KACI"}
1
+ {"version":3,"file":"CourseCard.js","names":[],"sources":["../../../../src/buildmyiq/pages/_shared/CourseCard.tsx"],"sourcesContent":["/**\n * CourseCard — a reusable course tile for catalog / authoring grids.\n * @module buildmyiq/pages/_shared\n */\n\nimport type { FC } from 'react';\nimport { BookOpen, Clock, Layers } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from '../../components';\nimport { cn } from '../../utils/cn';\nimport { formatHours } from '../../utils/formatters';\nimport type { BuiCourse } from '../../types';\n\ninterface CourseCardProps {\n course: BuiCourse;\n onClick?: () => void;\n /** Show the workflow status pill (authoring view) in addition to level. */\n showStatus?: boolean;\n className?: string;\n}\n\nexport const CourseCard: FC<CourseCardProps> = ({ course, onClick, showStatus, className }) => {\n const moduleCount = course.modules?.length ?? 0;\n const lessonCount = course.lessons?.length ?? 0;\n\n return (\n <GlassCard\n treatment=\"plain\"\n className={cn(\n 'group flex flex-col overflow-hidden transition-shadow',\n onClick && 'cursor-pointer hover:shadow-lg',\n className\n )}\n onClick={onClick}\n >\n <div className=\"relative h-32 w-full overflow-hidden bg-bg-sunken\">\n {course.cover?.downloadUrl ? (\n <img\n src={course.cover.downloadUrl}\n alt=\"\"\n className=\"h-full w-full object-cover transition-transform duration-500 group-hover:scale-105\"\n />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center bg-[var(--color-accent-soft)]\">\n <BookOpen className=\"h-8 w-8 text-text-secondary opacity-60\" />\n </div>\n )}\n <div className=\"absolute left-2 top-2 flex flex-wrap gap-1.5\">\n <StatusBadge status={course.level} />\n {showStatus && <StatusBadge status={course.status} />}\n </div>\n </div>\n\n <div className=\"flex flex-1 flex-col gap-2 p-4\">\n <h3 className=\"line-clamp-2 font-semibold text-text-primary\">{course.title}</h3>\n {course.summary && (\n <p className=\"line-clamp-2 text-sm text-text-secondary\">{course.summary}</p>\n )}\n <div className=\"mt-auto flex flex-wrap items-center gap-3 pt-2 text-xs text-text-secondary\">\n {course.skill?.name && (\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">{course.skill.name}</span>\n )}\n <span className=\"inline-flex items-center gap-1\">\n <Layers className=\"h-3.5 w-3.5\" /> {moduleCount} mod · {lessonCount} lessons\n </span>\n {course.estimatedHours > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatHours(course.estimatedHours)}\n </span>\n )}\n </div>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;;;;;AAqBA,IAAa,KAAmC,EAAE,WAAQ,YAAS,eAAY,mBAAgB;CAC7F,IAAM,IAAc,EAAO,SAAS,UAAU,GACxC,IAAc,EAAO,SAAS,UAAU;AAE9C,QACE,kBAAC,GAAD;EACE,WAAU;EACV,WAAW,EACT,yDACA,KAAW,kCACX,EACD;EACQ;YAPX,CASE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAO,OAAO,cACb,kBAAC,OAAD;IACE,KAAK,EAAO,MAAM;IAClB,KAAI;IACJ,WAAU;IACV,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAU,WAAU,0CAA2C,CAAA;IAC3D,CAAA,EAER,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAO,OAAS,CAAA,EACpC,KAAc,kBAAC,GAAD,EAAa,QAAQ,EAAO,QAAU,CAAA,CACjD;MACF;MAEN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eAAgD,EAAO;KAAW,CAAA;IAC/E,EAAO,WACN,kBAAC,KAAD;KAAG,WAAU;eAA4C,EAAO;KAAY,CAAA;IAE9E,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAO,OAAO,QACb,kBAAC,QAAD;OAAM,WAAU;iBAAyC,EAAO,MAAM;OAAY,CAAA;MAEpF,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA;;QAAE;QAAY;QAAQ;QAAY;QAC/D;;MACN,EAAO,iBAAiB,KACvB,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA;;QAAE,EAAY,EAAO,eAAe;QAChE;;MAEL;;IACF;KACI"}
@@ -190,8 +190,8 @@ var K = ({ course: e }) => {
190
190
  children: [
191
191
  /* @__PURE__ */ z("div", {
192
192
  className: "h-36 w-full overflow-hidden rounded-xl border border-border-seam bg-bg-sunken",
193
- children: e.cover?.url ? /* @__PURE__ */ z("img", {
194
- src: e.cover.url,
193
+ children: e.cover?.downloadUrl ? /* @__PURE__ */ z("img", {
194
+ src: e.cover.downloadUrl,
195
195
  alt: "",
196
196
  className: "h-full w-full object-cover"
197
197
  }) : /* @__PURE__ */ z("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"CourseBuilderPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/authoring/CourseBuilderPage.tsx"],"sourcesContent":["/**\n * CourseBuilderPage — the per-course authoring workspace.\n * @module buildmyiq/pages/authoring\n *\n * Loads one course (`useBuiCourse`) and exposes four tabs:\n * - Details — editable course meta (`useBuiUpdateCourse`), cover upload\n * (EvidenceUpload → coverFileId), Publish (`useBuiPublishCourse`) and Archive\n * (`useBuiArchiveCourse`).\n * - Curriculum — modules (`useBuiModules`, `useBuiCreateModule`) and their\n * lessons (`useBuiCreateLesson`).\n * - Assessments — course assessments (`useBuiAssessments`) linking out to the\n * assessment editor.\n * - Discussion — the shared wspace-conversations thread (`BuiDiscussion`).\n * Every list carries loading / error / empty states; all data is live `bui*` data.\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n Archive,\n ArrowLeft,\n BookOpen,\n Clock,\n FileText,\n ListChecks,\n MessageSquare,\n PlayCircle,\n Plus,\n Send,\n} from 'lucide-react';\nimport { Button, GlassCard, Input, Switch, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n Tabs,\n type TabItem,\n StatusBadge,\n EmptyState,\n LoadingView,\n ErrorView,\n Section,\n EvidenceUpload,\n BuiDiscussion,\n} from '../../components';\nimport { Modal, Field, SelectField, NO_SKILL } from './_forms';\nimport { useBuildmyiq } from '../../context';\nimport {\n useBuiCourse,\n useBuiUpdateCourse,\n useBuiPublishCourse,\n useBuiArchiveCourse,\n useBuiModules,\n useBuiCreateModule,\n useBuiCreateLesson,\n useBuiAssessments,\n useBuiSkills,\n type UploadedBuiFile,\n} from '../../hooks';\nimport { COURSE_LEVELS, LESSON_TYPES } from '../../types';\nimport type {\n BuiCourse,\n BuiCourseLevel,\n BuiCreateLessonInput,\n BuiCreateModuleInput,\n BuiLessonType,\n BuiModule,\n BuiUpdateCourseInput,\n} from '../../types';\nimport { formatDuration, formatEnumLabel } from '../../utils/formatters';\n\ntype BuilderTab = 'details' | 'curriculum' | 'assessments' | 'discussion';\n\n// ============================================================================\n// Details tab\n// ============================================================================\n\nconst DetailsTab: FC<{ course: BuiCourse }> = ({ course }) => {\n const updateCourse = useBuiUpdateCourse();\n const publishCourse = useBuiPublishCourse();\n const archiveCourse = useBuiArchiveCourse();\n const skillsQuery = useBuiSkills();\n const skills = skillsQuery.data ?? [];\n\n const [title, setTitle] = useState(course.title);\n const [summary, setSummary] = useState(course.summary ?? '');\n const [description, setDescription] = useState(course.description ?? '');\n const [level, setLevel] = useState<BuiCourseLevel>(course.level);\n const [language, setLanguage] = useState(course.language);\n const [estimatedHours, setEstimatedHours] = useState(String(course.estimatedHours ?? 0));\n const [skillId, setSkillId] = useState<string>(course.skillId ?? NO_SKILL);\n const [isPublic, setIsPublic] = useState(course.isPublic);\n const [coverFile, setCoverFile] = useState<UploadedBuiFile | null>(null);\n\n const [saveError, setSaveError] = useState<string | null>(null);\n const [coverError, setCoverError] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [confirmArchive, setConfirmArchive] = useState(false);\n\n const canPublish = course.status === 'DRAFT' || course.status === 'IN_REVIEW';\n const canArchive = course.status !== 'ARCHIVED';\n\n const handleSave = async () => {\n setSaveError(null);\n const input: BuiUpdateCourseInput = {\n title: title.trim() || course.title,\n summary: summary.trim() || undefined,\n description: description.trim() || undefined,\n level,\n language: language.trim() || 'en',\n estimatedHours: estimatedHours.trim() ? Number(estimatedHours) : 0,\n skillId: skillId !== NO_SKILL ? skillId : undefined,\n isPublic,\n };\n try {\n await updateCourse.mutateAsync({ id: course.id, input });\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'Failed to save changes.');\n }\n };\n\n const handleCoverChange = async (file: UploadedBuiFile | null) => {\n setCoverFile(file);\n if (!file) return;\n setCoverError(null);\n try {\n await updateCourse.mutateAsync({ id: course.id, input: { coverFileId: file.fileId } });\n } catch (e) {\n setCoverError(e instanceof Error ? e.message : 'Failed to update the cover.');\n }\n };\n\n const handlePublish = async () => {\n setActionError(null);\n try {\n await publishCourse.mutateAsync(course.id);\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'Failed to publish the course.');\n }\n };\n\n const handleArchive = async () => {\n setActionError(null);\n try {\n await archiveCourse.mutateAsync(course.id);\n setConfirmArchive(false);\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'Failed to archive the course.');\n }\n };\n\n return (\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <Section\n title=\"Course details\"\n description=\"Metadata learners see in the catalog.\"\n action={\n <Button onClick={handleSave} disabled={updateCourse.isPending}>\n {updateCourse.isPending ? 'Saving…' : 'Save changes'}\n </Button>\n }\n >\n <div className=\"grid gap-4\">\n <Field label=\"Title\" htmlFor=\"detail-title\" required>\n <Input id=\"detail-title\" value={title} onChange={(e) => setTitle(e.target.value)} />\n </Field>\n <Field label=\"Summary\" htmlFor=\"detail-summary\">\n <Textarea\n id=\"detail-summary\"\n rows={2}\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n placeholder=\"A short description shown on the catalog card.\"\n />\n </Field>\n <Field label=\"Description\" htmlFor=\"detail-description\">\n <Textarea\n id=\"detail-description\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"The full course overview.\"\n />\n </Field>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <Field label=\"Level\">\n <SelectField\n value={level}\n onChange={(v) => setLevel(v as BuiCourseLevel)}\n options={COURSE_LEVELS.map((l) => ({ value: l, label: formatEnumLabel(l) }))}\n />\n </Field>\n <Field label=\"Language\" htmlFor=\"detail-language\">\n <Input\n id=\"detail-language\"\n value={language}\n onChange={(e) => setLanguage(e.target.value)}\n placeholder=\"en\"\n />\n </Field>\n <Field label=\"Estimated hours\" htmlFor=\"detail-hours\">\n <Input\n id=\"detail-hours\"\n type=\"number\"\n min={0}\n value={estimatedHours}\n onChange={(e) => setEstimatedHours(e.target.value)}\n />\n </Field>\n <Field label=\"Skill\">\n <SelectField\n value={skillId}\n onChange={setSkillId}\n options={[\n { value: NO_SKILL, label: skillsQuery.isLoading ? 'Loading…' : 'No skill' },\n ...skills.map((s) => ({ value: s.id, label: s.name })),\n ]}\n />\n </Field>\n </div>\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm text-text-secondary\">\n <Switch checked={isPublic} onCheckedChange={setIsPublic} />\n Publicly visible in the catalog\n </label>\n {saveError && <p className=\"text-sm text-status-error-text\">{saveError}</p>}\n </div>\n </Section>\n </div>\n\n <div className=\"flex flex-col gap-6\">\n <Section title=\"Cover image\">\n <div className=\"grid gap-3\">\n <div className=\"h-36 w-full overflow-hidden rounded-xl border border-border-seam bg-bg-sunken\">\n {course.cover?.url ? (\n <img src={course.cover.url} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full items-center justify-center text-sm text-text-secondary\">\n No cover yet\n </div>\n )}\n </div>\n <EvidenceUpload\n id=\"course-cover\"\n label=\"Upload cover\"\n value={coverFile}\n onChange={handleCoverChange}\n accept=\"image/*\"\n hint=\"PNG or JPG, shown on catalog cards.\"\n />\n {coverError && <p className=\"text-xs text-status-error-text\">{coverError}</p>}\n </div>\n </Section>\n\n <Section title=\"Publishing\">\n <div className=\"grid gap-3\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n Status <StatusBadge status={course.status} />\n </div>\n {canPublish && (\n <Button onClick={handlePublish} disabled={publishCourse.isPending}>\n <Send className=\"mr-1.5 h-4 w-4\" />\n {publishCourse.isPending ? 'Publishing…' : 'Publish course'}\n </Button>\n )}\n {canArchive && (\n <Button variant=\"outline\" onClick={() => setConfirmArchive(true)}>\n <Archive className=\"mr-1.5 h-4 w-4\" /> Archive\n </Button>\n )}\n {actionError && <p className=\"text-sm text-status-error-text\">{actionError}</p>}\n </div>\n </Section>\n </div>\n\n {confirmArchive && (\n <Modal\n open\n onClose={() => setConfirmArchive(false)}\n title=\"Archive this course?\"\n description=\"Archived courses are hidden from the catalog and cannot be enrolled in.\"\n footer={\n <>\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmArchive(false)}\n disabled={archiveCourse.isPending}\n >\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n onClick={handleArchive}\n disabled={archiveCourse.isPending}\n >\n {archiveCourse.isPending ? 'Archiving…' : 'Archive course'}\n </Button>\n </>\n }\n >\n <p className=\"text-sm text-text-secondary\">\n You can still find it in Authoring under the Archived filter.\n </p>\n </Modal>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Curriculum tab\n// ============================================================================\n\nconst AddModuleModal: FC<{ courseId: string; position: number; onClose: () => void }> = ({\n courseId,\n position,\n onClose,\n}) => {\n const createModule = useBuiCreateModule();\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const canSubmit = title.trim().length > 0 && !createModule.isPending;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n setError(null);\n const input: BuiCreateModuleInput = {\n courseId,\n title: title.trim(),\n description: description.trim() || undefined,\n position,\n };\n try {\n await createModule.mutateAsync(input);\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Failed to add the module.');\n }\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Add module\"\n footer={\n <>\n <Button variant=\"ghost\" onClick={onClose} disabled={createModule.isPending}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n {createModule.isPending ? 'Adding…' : 'Add module'}\n </Button>\n </>\n }\n >\n <div className=\"grid gap-4\">\n <Field label=\"Module title\" htmlFor=\"module-title\" required>\n <Input\n id=\"module-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. Getting started\"\n />\n </Field>\n <Field label=\"Description\" htmlFor=\"module-description\">\n <Textarea\n id=\"module-description\"\n rows={3}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n />\n </Field>\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n </Modal>\n );\n};\n\nconst AddLessonModal: FC<{\n courseId: string;\n moduleId: string;\n position: number;\n onClose: () => void;\n}> = ({ courseId, moduleId, position, onClose }) => {\n const createLesson = useBuiCreateLesson();\n const [title, setTitle] = useState('');\n const [type, setType] = useState<BuiLessonType>('ARTICLE');\n const [content, setContent] = useState('');\n const [durationMin, setDurationMin] = useState('');\n const [isPreview, setIsPreview] = useState(false);\n const [media, setMedia] = useState<UploadedBuiFile | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const canSubmit = title.trim().length > 0 && !createLesson.isPending;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n setError(null);\n const input: BuiCreateLessonInput = {\n courseId,\n moduleId,\n title: title.trim(),\n type,\n content: content.trim() || undefined,\n durationMin: durationMin.trim() ? Number(durationMin) : undefined,\n position,\n isPreview,\n mediaFileId: media?.fileId,\n };\n try {\n await createLesson.mutateAsync(input);\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Failed to add the lesson.');\n }\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Add lesson\"\n className=\"sm:max-w-xl\"\n footer={\n <>\n <Button variant=\"ghost\" onClick={onClose} disabled={createLesson.isPending}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n {createLesson.isPending ? 'Adding…' : 'Add lesson'}\n </Button>\n </>\n }\n >\n <div className=\"grid gap-4\">\n <Field label=\"Lesson title\" htmlFor=\"lesson-title\" required>\n <Input\n id=\"lesson-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. What is data literacy?\"\n />\n </Field>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <Field label=\"Type\">\n <SelectField\n value={type}\n onChange={(v) => setType(v as BuiLessonType)}\n options={LESSON_TYPES.map((t) => ({ value: t, label: formatEnumLabel(t) }))}\n />\n </Field>\n <Field label=\"Duration (minutes)\" htmlFor=\"lesson-duration\">\n <Input\n id=\"lesson-duration\"\n type=\"number\"\n min={0}\n value={durationMin}\n onChange={(e) => setDurationMin(e.target.value)}\n placeholder=\"0\"\n />\n </Field>\n </div>\n <Field\n label=\"Content\"\n htmlFor=\"lesson-content\"\n hint=\"Lesson body — markdown or plain text.\"\n >\n <Textarea\n id=\"lesson-content\"\n rows={5}\n value={content}\n onChange={(e) => setContent(e.target.value)}\n />\n </Field>\n <EvidenceUpload\n id=\"lesson-media\"\n label=\"Media (optional)\"\n value={media}\n onChange={setMedia}\n hint=\"Attach a video, audio file or PDF for this lesson.\"\n />\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm text-text-secondary\">\n <Switch checked={isPreview} onCheckedChange={setIsPreview} />\n Free preview lesson\n </label>\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n </Modal>\n );\n};\n\nconst ModuleCard: FC<{ module: BuiModule; index: number; onAddLesson: () => void }> = ({\n module,\n index,\n onAddLesson,\n}) => {\n const lessons = [...(module.lessons ?? [])].sort((a, b) => a.position - b.position);\n return (\n <GlassCard treatment=\"plain\" className=\"p-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h3 className=\"font-semibold text-text-primary\">\n <span className=\"mr-2 text-text-tertiary\">Module {index + 1}</span>\n {module.title}\n </h3>\n {module.description && (\n <p className=\"mt-0.5 text-sm text-text-secondary\">{module.description}</p>\n )}\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={onAddLesson}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add lesson\n </Button>\n </div>\n <div className=\"mt-3\">\n {lessons.length === 0 ? (\n <p className=\"rounded-lg border border-dashed border-border-seam px-3 py-3 text-sm text-text-secondary\">\n No lessons yet.\n </p>\n ) : (\n <ul className=\"flex flex-col gap-1.5\">\n {lessons.map((lesson) => (\n <li\n key={lesson.id}\n className=\"flex flex-wrap items-center gap-3 rounded-lg border border-border-seam bg-bg-surface px-3 py-2\"\n >\n <PlayCircle className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n <span className=\"min-w-0 flex-1 truncate text-sm text-text-primary\">\n {lesson.title}\n </span>\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n {formatEnumLabel(lesson.type)}\n </span>\n {lesson.isPreview && (\n <span className=\"rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-xs text-text-primary\">\n Preview\n </span>\n )}\n {lesson.durationMin > 0 && (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(lesson.durationMin)}\n </span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n </GlassCard>\n );\n};\n\nconst CurriculumTab: FC<{ courseId: string }> = ({ courseId }) => {\n const modulesQuery = useBuiModules(courseId);\n const [showAddModule, setShowAddModule] = useState(false);\n const [lessonModuleId, setLessonModuleId] = useState<string | null>(null);\n\n const modules = modulesQuery.data ?? [];\n const lessonModule = modules.find((m) => m.id === lessonModuleId) ?? null;\n\n return (\n <Section\n title=\"Curriculum\"\n description=\"Organise the course into modules and lessons.\"\n action={\n <Button onClick={() => setShowAddModule(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add module\n </Button>\n }\n >\n {modulesQuery.isLoading ? (\n <LoadingView label=\"Loading curriculum…\" />\n ) : modulesQuery.isError ? (\n <ErrorView\n message=\"We couldn't load the curriculum.\"\n onRetry={() => modulesQuery.refetch()}\n />\n ) : modules.length === 0 ? (\n <EmptyState\n illustration=\"onboarding\"\n title=\"No modules yet\"\n description=\"Add your first module, then fill it with lessons.\"\n action={\n <Button onClick={() => setShowAddModule(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add module\n </Button>\n }\n />\n ) : (\n <div className=\"flex flex-col gap-4\">\n {[...modules]\n .sort((a, b) => a.position - b.position)\n .map((mod, idx) => (\n <ModuleCard\n key={mod.id}\n module={mod}\n index={idx}\n onAddLesson={() => setLessonModuleId(mod.id)}\n />\n ))}\n </div>\n )}\n\n {showAddModule && (\n <AddModuleModal\n courseId={courseId}\n position={modules.length}\n onClose={() => setShowAddModule(false)}\n />\n )}\n {lessonModuleId && (\n <AddLessonModal\n courseId={courseId}\n moduleId={lessonModuleId}\n position={lessonModule?.lessons?.length ?? 0}\n onClose={() => setLessonModuleId(null)}\n />\n )}\n </Section>\n );\n};\n\n// ============================================================================\n// Assessments tab\n// ============================================================================\n\nconst AssessmentsTab: FC<{ courseId: string }> = ({ courseId }) => {\n const { navigateTo } = useBuildmyiq();\n const assessmentsQuery = useBuiAssessments(courseId);\n const assessments = assessmentsQuery.data ?? [];\n\n return (\n <Section\n title=\"Assessments\"\n description=\"Quizzes, exams and assignments attached to this course.\"\n >\n {assessmentsQuery.isLoading ? (\n <LoadingView label=\"Loading assessments…\" />\n ) : assessmentsQuery.isError ? (\n <ErrorView\n message=\"We couldn't load the assessments.\"\n onRetry={() => assessmentsQuery.refetch()}\n />\n ) : assessments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No assessments yet\"\n description=\"Create an assessment in the Assessments workspace to test learners on this course.\"\n action={\n <Button variant=\"outline\" onClick={() => navigateTo('assessments')}>\n Open assessments\n </Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {assessments.map((a) => (\n <GlassCard\n key={a.id}\n treatment=\"plain\"\n className=\"flex cursor-pointer flex-col gap-2 p-4 transition-shadow hover:shadow-lg\"\n onClick={() => navigateTo(`assessments/${a.id}`)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <h3 className=\"min-w-0 font-semibold text-text-primary\">{a.title}</h3>\n <StatusBadge status={a.status} />\n </div>\n {a.description && (\n <p className=\"line-clamp-2 text-sm text-text-secondary\">{a.description}</p>\n )}\n <div className=\"mt-auto flex flex-wrap items-center gap-3 pt-1 text-xs text-text-secondary\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">\n {formatEnumLabel(a.type)}\n </span>\n <span>Pass ≥ {a.passingScore ?? 0}%</span>\n {a.timeLimitMin > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(a.timeLimitMin)}\n </span>\n )}\n </div>\n </GlassCard>\n ))}\n </div>\n )}\n </Section>\n );\n};\n\n// ============================================================================\n// Page\n// ============================================================================\n\nexport const CourseBuilderPage: FC = () => {\n const { courseId } = useParams<{ courseId: string }>();\n const { navigateTo } = useBuildmyiq();\n const [tab, setTab] = useState<BuilderTab>('details');\n const courseQuery = useBuiCourse(courseId);\n const course = courseQuery.data ?? null;\n\n if (courseQuery.isLoading) {\n return (\n <PageLayout title=\"Course builder\">\n <LoadingView label=\"Loading course…\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isError) {\n return (\n <PageLayout title=\"Course builder\">\n <ErrorView message=\"We couldn't load this course.\" onRetry={() => courseQuery.refetch()} />\n </PageLayout>\n );\n }\n\n if (!courseId || !course) {\n return (\n <PageLayout title=\"Course builder\">\n <EmptyState\n illustration=\"empty-search\"\n title=\"Course not found\"\n description=\"This course may have been archived or removed.\"\n action={<Button onClick={() => navigateTo('authoring')}>Back to authoring</Button>}\n />\n </PageLayout>\n );\n }\n\n const tabs: TabItem<BuilderTab>[] = [\n { value: 'details', label: 'Details', icon: <FileText className=\"h-4 w-4\" /> },\n {\n value: 'curriculum',\n label: 'Curriculum',\n icon: <BookOpen className=\"h-4 w-4\" />,\n count: course.modules?.length ?? 0,\n },\n { value: 'assessments', label: 'Assessments', icon: <ListChecks className=\"h-4 w-4\" /> },\n { value: 'discussion', label: 'Discussion', icon: <MessageSquare className=\"h-4 w-4\" /> },\n ];\n\n return (\n <PageLayout\n title={course.title}\n description={course.summary ?? undefined}\n actions={\n <Button variant=\"ghost\" onClick={() => navigateTo('authoring')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Back\n </Button>\n }\n >\n <div className=\"flex flex-col gap-5\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.status} />\n <StatusBadge status={course.level} />\n </div>\n\n <Tabs items={tabs} value={tab} onChange={setTab} />\n\n {tab === 'details' && <DetailsTab key={course.id} course={course} />}\n {tab === 'curriculum' && <CurriculumTab courseId={courseId} />}\n {tab === 'assessments' && <AssessmentsTab courseId={courseId} />}\n {tab === 'discussion' && (\n <BuiDiscussion entityType=\"buildmyiq-course\" entityId={courseId} />\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4EA,IAAM,KAAyC,EAAE,gBAAa;CAC5D,IAAM,IAAe,GAAoB,EACnC,IAAgB,GAAqB,EACrC,IAAgB,GAAqB,EACrC,IAAc,GAAc,EAC5B,IAAS,EAAY,QAAQ,EAAE,EAE/B,CAAC,GAAO,KAAY,EAAS,EAAO,MAAM,EAC1C,CAAC,GAAS,KAAc,EAAS,EAAO,WAAW,GAAG,EACtD,CAAC,GAAa,KAAkB,EAAS,EAAO,eAAe,GAAG,EAClE,CAAC,GAAO,KAAY,EAAyB,EAAO,MAAM,EAC1D,CAAC,GAAU,KAAe,EAAS,EAAO,SAAS,EACnD,CAAC,GAAgB,KAAqB,EAAS,OAAO,EAAO,kBAAkB,EAAE,CAAC,EAClF,CAAC,GAAS,KAAc,EAAiB,EAAO,WAAA,WAAoB,EACpE,CAAC,GAAU,KAAe,EAAS,EAAO,SAAS,EACnD,CAAC,GAAW,KAAgB,EAAiC,KAAK,EAElE,CAAC,GAAW,KAAgB,EAAwB,KAAK,EACzD,CAAC,GAAY,KAAiB,EAAwB,KAAK,EAC3D,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAgB,KAAqB,EAAS,GAAM,EAErD,KAAa,EAAO,WAAW,WAAW,EAAO,WAAW,aAC5D,KAAa,EAAO,WAAW,YAE/B,KAAa,YAAY;AAC7B,IAAa,KAAK;EAClB,IAAM,IAA8B;GAClC,OAAO,EAAM,MAAM,IAAI,EAAO;GAC9B,SAAS,EAAQ,MAAM,IAAI,KAAA;GAC3B,aAAa,EAAY,MAAM,IAAI,KAAA;GACnC;GACA,UAAU,EAAS,MAAM,IAAI;GAC7B,gBAAgB,EAAe,MAAM,GAAG,OAAO,EAAe,GAAG;GACjE,SAAS,MAAA,aAAiC,KAAA,IAAV;GAChC;GACD;AACD,MAAI;AACF,SAAM,EAAa,YAAY;IAAE,IAAI,EAAO;IAAI;IAAO,CAAC;WACjD,GAAG;AACV,KAAa,aAAa,QAAQ,EAAE,UAAU,0BAA0B;;IAItE,KAAoB,OAAO,MAAiC;AAChE,QAAa,EAAK,EACb,GACL;KAAc,KAAK;AACnB,OAAI;AACF,UAAM,EAAa,YAAY;KAAE,IAAI,EAAO;KAAI,OAAO,EAAE,aAAa,EAAK,QAAQ;KAAE,CAAC;YAC/E,GAAG;AACV,MAAc,aAAa,QAAQ,EAAE,UAAU,8BAA8B;;;IAI3E,KAAgB,YAAY;AAChC,IAAe,KAAK;AACpB,MAAI;AACF,SAAM,EAAc,YAAY,EAAO,GAAG;WACnC,GAAG;AACV,KAAe,aAAa,QAAQ,EAAE,UAAU,gCAAgC;;IAI9E,KAAgB,YAAY;AAChC,IAAe,KAAK;AACpB,MAAI;AAEF,GADA,MAAM,EAAc,YAAY,EAAO,GAAG,EAC1C,EAAkB,GAAM;WACjB,GAAG;AACV,KAAe,aAAa,QAAQ,EAAE,UAAU,gCAAgC;;;AAIpF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KACE,OAAM;KACN,aAAY;KACZ,QACE,kBAAC,GAAD;MAAQ,SAAS;MAAY,UAAU,EAAa;gBACjD,EAAa,YAAY,YAAY;MAC/B,CAAA;eAGX,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD;QAAO,OAAM;QAAQ,SAAQ;QAAe,UAAA;kBAC1C,kBAAC,GAAD;SAAO,IAAG;SAAe,OAAO;SAAO,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;SAAI,CAAA;QAC9E,CAAA;OACR,kBAAC,GAAD;QAAO,OAAM;QAAU,SAAQ;kBAC7B,kBAAC,GAAD;SACE,IAAG;SACH,MAAM;SACN,OAAO;SACP,WAAW,MAAM,EAAW,EAAE,OAAO,MAAM;SAC3C,aAAY;SACZ,CAAA;QACI,CAAA;OACR,kBAAC,GAAD;QAAO,OAAM;QAAc,SAAQ;kBACjC,kBAAC,GAAD;SACE,IAAG;SACH,MAAM;SACN,OAAO;SACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;SAC/C,aAAY;SACZ,CAAA;QACI,CAAA;OACR,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,GAAD;UAAO,OAAM;oBACX,kBAAC,GAAD;WACE,OAAO;WACP,WAAW,MAAM,EAAS,EAAoB;WAC9C,SAAS,EAAc,KAAK,OAAO;YAAE,OAAO;YAAG,OAAO,EAAgB,EAAE;YAAE,EAAE;WAC5E,CAAA;UACI,CAAA;SACR,kBAAC,GAAD;UAAO,OAAM;UAAW,SAAQ;oBAC9B,kBAAC,GAAD;WACE,IAAG;WACH,OAAO;WACP,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;WAC5C,aAAY;WACZ,CAAA;UACI,CAAA;SACR,kBAAC,GAAD;UAAO,OAAM;UAAkB,SAAQ;oBACrC,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,KAAK;WACL,OAAO;WACP,WAAW,MAAM,EAAkB,EAAE,OAAO,MAAM;WAClD,CAAA;UACI,CAAA;SACR,kBAAC,GAAD;UAAO,OAAM;oBACX,kBAAC,GAAD;WACE,OAAO;WACP,UAAU;WACV,SAAS,CACP;YAAE,OAAO;YAAU,OAAO,EAAY,YAAY,aAAa;YAAY,EAC3E,GAAG,EAAO,KAAK,OAAO;YAAE,OAAO,EAAE;YAAI,OAAO,EAAE;YAAM,EAAE,CACvD;WACD,CAAA;UACI,CAAA;SACJ;;OACN,kBAAC,SAAD;QAAO,WAAU;kBAAjB,CACE,kBAAC,GAAD;SAAQ,SAAS;SAAU,iBAAiB;SAAe,CAAA,EAAA,kCAErD;;OACP,KAAa,kBAAC,KAAD;QAAG,WAAU;kBAAkC;QAAc,CAAA;OACvE;;KACE,CAAA;IACN,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAS,OAAM;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAO,OAAO,MACb,kBAAC,OAAD;SAAK,KAAK,EAAO,MAAM;SAAK,KAAI;SAAG,WAAU;SAA+B,CAAA,GAE5E,kBAAC,OAAD;SAAK,WAAU;mBAAsE;SAE/E,CAAA;QAEJ,CAAA;OACN,kBAAC,GAAD;QACE,IAAG;QACH,OAAM;QACN,OAAO;QACP,UAAU;QACV,QAAO;QACP,MAAK;QACL,CAAA;OACD,KAAc,kBAAC,KAAD;QAAG,WAAU;kBAAkC;QAAe,CAAA;OACzE;;KACE,CAAA,EAEV,kBAAC,GAAD;KAAS,OAAM;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CAAqE,WAC5D,kBAAC,GAAD,EAAa,QAAQ,EAAO,QAAU,CAAA,CACzC;;OACL,MACC,kBAAC,GAAD;QAAQ,SAAS;QAAe,UAAU,EAAc;kBAAxD,CACE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAClC,EAAc,YAAY,gBAAgB,iBACpC;;OAEV,MACC,kBAAC,GAAD;QAAQ,SAAQ;QAAU,eAAe,EAAkB,GAAK;kBAAhE,CACE,kBAAC,IAAD,EAAS,WAAU,kBAAmB,CAAA,EAAA,WAC/B;;OAEV,KAAe,kBAAC,KAAD;QAAG,WAAU;kBAAkC;QAAgB,CAAA;OAC3E;;KACE,CAAA,CACN;;GAEL,KACC,kBAAC,GAAD;IACE,MAAA;IACA,eAAe,EAAkB,GAAM;IACvC,OAAM;IACN,aAAY;IACZ,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;KACE,SAAQ;KACR,eAAe,EAAkB,GAAM;KACvC,UAAU,EAAc;eACzB;KAEQ,CAAA,EACT,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,UAAU,EAAc;eAEvB,EAAc,YAAY,eAAe;KACnC,CAAA,CACR,EAAA,CAAA;cAGL,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAEvC,CAAA;IACE,CAAA;GAEN;;GAQJ,KAAmF,EACvF,aACA,aACA,iBACI;CACJ,IAAM,IAAe,GAAoB,EACnC,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAY,EAAM,MAAM,CAAC,SAAS,KAAK,CAAC,EAAa;AAmB3D,QACE,kBAAC,GAAD;EACE,MAAA;EACS;EACT,OAAM;EACN,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,SAAS;GAAS,UAAU,EAAa;aAAW;GAEnE,CAAA,EACT,kBAAC,GAAD;GAAQ,SA3BK,YAAY;AAC/B,QAAI,CAAC,EAAW;AAChB,MAAS,KAAK;IACd,IAAM,IAA8B;KAClC;KACA,OAAO,EAAM,MAAM;KACnB,aAAa,EAAY,MAAM,IAAI,KAAA;KACnC;KACD;AACD,QAAI;AAEF,KADA,MAAM,EAAa,YAAY,EAAM,EACrC,GAAS;aACF,GAAG;AACV,OAAS,aAAa,QAAQ,EAAE,UAAU,4BAA4B;;;GAcnC,UAAU,CAAC;aACvC,EAAa,YAAY,YAAY;GAC/B,CAAA,CACR,EAAA,CAAA;YAGL,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KAAO,OAAM;KAAe,SAAQ;KAAe,UAAA;eACjD,kBAAC,GAAD;MACE,IAAG;MACH,OAAO;MACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;MACzC,aAAY;MACZ,CAAA;KACI,CAAA;IACR,kBAAC,GAAD;KAAO,OAAM;KAAc,SAAQ;eACjC,kBAAC,GAAD;MACE,IAAG;MACH,MAAM;MACN,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,CAAA;KACI,CAAA;IACP,KAAS,kBAAC,KAAD;KAAG,WAAU;eAAkC;KAAU,CAAA;IAC/D;;EACA,CAAA;GAIN,KAKA,EAAE,aAAU,aAAU,aAAU,iBAAc;CAClD,IAAM,IAAe,GAAoB,EACnC,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,CAAC,GAAM,KAAW,EAAwB,UAAU,EACpD,CAAC,GAAS,KAAc,EAAS,GAAG,EACpC,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAO,KAAY,EAAiC,KAAK,EAC1D,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAY,EAAM,MAAM,CAAC,SAAS,KAAK,CAAC,EAAa;AAwB3D,QACE,kBAAC,GAAD;EACE,MAAA;EACS;EACT,OAAM;EACN,WAAU;EACV,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,SAAS;GAAS,UAAU,EAAa;aAAW;GAEnE,CAAA,EACT,kBAAC,GAAD;GAAQ,SAjCK,YAAY;AAC/B,QAAI,CAAC,EAAW;AAChB,MAAS,KAAK;IACd,IAAM,IAA8B;KAClC;KACA;KACA,OAAO,EAAM,MAAM;KACnB;KACA,SAAS,EAAQ,MAAM,IAAI,KAAA;KAC3B,aAAa,EAAY,MAAM,GAAG,OAAO,EAAY,GAAG,KAAA;KACxD;KACA;KACA,aAAa,GAAO;KACrB;AACD,QAAI;AAEF,KADA,MAAM,EAAa,YAAY,EAAM,EACrC,GAAS;aACF,GAAG;AACV,OAAS,aAAa,QAAQ,EAAE,UAAU,4BAA4B;;;GAenC,UAAU,CAAC;aACvC,EAAa,YAAY,YAAY;GAC/B,CAAA,CACR,EAAA,CAAA;YAGL,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KAAO,OAAM;KAAe,SAAQ;KAAe,UAAA;eACjD,kBAAC,GAAD;MACE,IAAG;MACH,OAAO;MACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;MACzC,aAAY;MACZ,CAAA;KACI,CAAA;IACR,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAO,OAAM;gBACX,kBAAC,GAAD;OACE,OAAO;OACP,WAAW,MAAM,EAAQ,EAAmB;OAC5C,SAAS,EAAa,KAAK,OAAO;QAAE,OAAO;QAAG,OAAO,EAAgB,EAAE;QAAE,EAAE;OAC3E,CAAA;MACI,CAAA,EACR,kBAAC,GAAD;MAAO,OAAM;MAAqB,SAAQ;gBACxC,kBAAC,GAAD;OACE,IAAG;OACH,MAAK;OACL,KAAK;OACL,OAAO;OACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;OAC/C,aAAY;OACZ,CAAA;MACI,CAAA,CACJ;;IACN,kBAAC,GAAD;KACE,OAAM;KACN,SAAQ;KACR,MAAK;eAEL,kBAAC,GAAD;MACE,IAAG;MACH,MAAM;MACN,OAAO;MACP,WAAW,MAAM,EAAW,EAAE,OAAO,MAAM;MAC3C,CAAA;KACI,CAAA;IACR,kBAAC,GAAD;KACE,IAAG;KACH,OAAM;KACN,OAAO;KACP,UAAU;KACV,MAAK;KACL,CAAA;IACF,kBAAC,SAAD;KAAO,WAAU;eAAjB,CACE,kBAAC,GAAD;MAAQ,SAAS;MAAW,iBAAiB;MAAgB,CAAA,EAAA,sBAEvD;;IACP,KAAS,kBAAC,KAAD;KAAG,WAAU;eAAkC;KAAU,CAAA;IAC/D;;EACA,CAAA;GAIN,KAAiF,EACrF,WACA,UACA,qBACI;CACJ,IAAM,IAAU,CAAC,GAAI,EAAO,WAAW,EAAE,CAAE,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS;AACnF,QACE,kBAAC,GAAD;EAAW,WAAU;EAAQ,WAAU;YAAvC,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAAd,CACE,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CAA0C,WAAQ,IAAQ,EAAS;SAClE,EAAO,MACL;QACJ,EAAO,eACN,kBAAC,KAAD;KAAG,WAAU;eAAsC,EAAO;KAAgB,CAAA,CAExE;OACN,kBAAC,GAAD;IAAQ,SAAQ;IAAU,MAAK;IAAK,SAAS;cAA7C,CACE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAAA,cAC5B;MACL;MACN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAQ,WAAW,IAClB,kBAAC,KAAD;IAAG,WAAU;cAA2F;IAEpG,CAAA,GAEJ,kBAAC,MAAD;IAAI,WAAU;cACX,EAAQ,KAAK,MACZ,kBAAC,MAAD;KAEE,WAAU;eAFZ;MAIE,kBAAC,GAAD,EAAY,WAAU,uCAAwC,CAAA;MAC9D,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAO;OACH,CAAA;MACP,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAgB,EAAO,KAAK;OACxB,CAAA;MACN,EAAO,aACN,kBAAC,QAAD;OAAM,WAAU;iBAAmF;OAE5F,CAAA;MAER,EAAO,cAAc,KACpB,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA;;QAAE,EAAe,EAAO,YAAY;QAChE;;MAEN;OApBE,EAAO,GAoBT,CACL;IACC,CAAA;GAEH,CAAA,CACI;;GAIV,KAA2C,EAAE,kBAAe;CAChE,IAAM,IAAe,EAAc,EAAS,EACtC,CAAC,GAAe,KAAoB,EAAS,GAAM,EACnD,CAAC,GAAgB,KAAqB,EAAwB,KAAK,EAEnE,IAAU,EAAa,QAAQ,EAAE,EACjC,IAAe,EAAQ,MAAM,MAAM,EAAE,OAAO,EAAe,IAAI;AAErE,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,QACE,kBAAC,GAAD;GAAQ,eAAe,EAAiB,GAAK;aAA7C,CACE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAAA,cAC5B;;YANb;GASG,EAAa,YACZ,kBAAC,GAAD,EAAa,OAAM,uBAAwB,CAAA,GACzC,EAAa,UACf,kBAAC,GAAD;IACE,SAAQ;IACR,eAAe,EAAa,SAAS;IACrC,CAAA,GACA,EAAQ,WAAW,IACrB,kBAAC,GAAD;IACE,cAAa;IACb,OAAM;IACN,aAAY;IACZ,QACE,kBAAC,GAAD;KAAQ,eAAe,EAAiB,GAAK;eAA7C,CACE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAAA,cAC5B;;IAEX,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACZ,CAAC,GAAG,EAAQ,CACV,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS,CACvC,KAAK,GAAK,MACT,kBAAC,GAAD;KAEE,QAAQ;KACR,OAAO;KACP,mBAAmB,EAAkB,EAAI,GAAG;KAC5C,EAJK,EAAI,GAIT,CACF;IACA,CAAA;GAGP,KACC,kBAAC,GAAD;IACY;IACV,UAAU,EAAQ;IAClB,eAAe,EAAiB,GAAM;IACtC,CAAA;GAEH,KACC,kBAAC,GAAD;IACY;IACV,UAAU;IACV,UAAU,GAAc,SAAS,UAAU;IAC3C,eAAe,EAAkB,KAAK;IACtC,CAAA;GAEI;;GAQR,KAA4C,EAAE,kBAAe;CACjE,IAAM,EAAE,kBAAe,GAAc,EAC/B,IAAmB,EAAkB,EAAS,EAC9C,IAAc,EAAiB,QAAQ,EAAE;AAE/C,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEX,EAAiB,YAChB,kBAAC,GAAD,EAAa,OAAM,wBAAyB,CAAA,GAC1C,EAAiB,UACnB,kBAAC,GAAD;GACE,SAAQ;GACR,eAAe,EAAiB,SAAS;GACzC,CAAA,GACA,EAAY,WAAW,IACzB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,GAAD;IAAQ,SAAQ;IAAU,eAAe,EAAW,cAAc;cAAE;IAE3D,CAAA;GAEX,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAY,KAAK,MAChB,kBAAC,GAAD;IAEE,WAAU;IACV,WAAU;IACV,eAAe,EAAW,eAAe,EAAE,KAAK;cAJlD;KAME,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAA2C,EAAE;OAAW,CAAA,EACtE,kBAAC,GAAD,EAAa,QAAQ,EAAE,QAAU,CAAA,CAC7B;;KACL,EAAE,eACD,kBAAC,KAAD;MAAG,WAAU;gBAA4C,EAAE;MAAgB,CAAA;KAE7E,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAgB,EAAE,KAAK;QACnB,CAAA;OACP,kBAAC,QAAD,EAAA,UAAA;QAAM;QAAQ,EAAE,gBAAgB;QAAE;QAAQ,EAAA,CAAA;OACzC,EAAE,eAAe,KAChB,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA;;SAAE,EAAe,EAAE,aAAa;SAC5D;;OAEL;;KACI;MAvBL,EAAE,GAuBG,CACZ;GACE,CAAA;EAEA,CAAA;GAQD,UAA8B;CACzC,IAAM,EAAE,gBAAa,GAAiC,EAChD,EAAE,kBAAe,GAAc,EAC/B,CAAC,GAAK,KAAU,EAAqB,UAAU,EAC/C,IAAc,EAAa,EAAS,EACpC,IAAS,EAAY,QAAQ;AAEnC,KAAI,EAAY,UACd,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,mBAAoB,CAAA;EAC5B,CAAA;AAIjB,KAAI,EAAY,QACd,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GAAW,SAAQ;GAAgC,eAAe,EAAY,SAAS;GAAI,CAAA;EAChF,CAAA;AAIjB,KAAI,CAAC,KAAY,CAAC,EAChB,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,QAAQ,kBAAC,GAAD;IAAQ,eAAe,EAAW,YAAY;cAAE;IAA0B,CAAA;GAClF,CAAA;EACS,CAAA;CAIjB,IAAM,IAA8B;EAClC;GAAE,OAAO;GAAW,OAAO;GAAW,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;GAAE;EAC9E;GACE,OAAO;GACP,OAAO;GACP,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;GACtC,OAAO,EAAO,SAAS,UAAU;GAClC;EACD;GAAE,OAAO;GAAe,OAAO;GAAe,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;GAAE;EACxF;GAAE,OAAO;GAAc,OAAO;GAAc,MAAM,kBAAC,GAAD,EAAe,WAAU,WAAY,CAAA;GAAE;EAC1F;AAED,QACE,kBAAC,GAAD;EACE,OAAO,EAAO;EACd,aAAa,EAAO,WAAW,KAAA;EAC/B,SACE,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,eAAe,EAAW,YAAY;aAA9D,CACE,kBAAC,GAAD,EAAW,WAAU,kBAAmB,CAAA,EAAA,QACjC;;YAGX,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAO,QAAU,CAAA,EACtC,kBAAC,GAAD,EAAa,QAAQ,EAAO,OAAS,CAAA,CACjC;;IAEN,kBAAC,GAAD;KAAM,OAAO;KAAM,OAAO;KAAK,UAAU;KAAU,CAAA;IAElD,MAAQ,aAAa,kBAAC,GAAD,EAAoC,WAAU,EAA7B,EAAO,GAAsB;IACnE,MAAQ,gBAAgB,kBAAC,GAAD,EAAyB,aAAY,CAAA;IAC7D,MAAQ,iBAAiB,kBAAC,GAAD,EAA0B,aAAY,CAAA;IAC/D,MAAQ,gBACP,kBAAC,GAAD;KAAe,YAAW;KAAmB,UAAU;KAAY,CAAA;IAEjE;;EACK,CAAA"}
1
+ {"version":3,"file":"CourseBuilderPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/authoring/CourseBuilderPage.tsx"],"sourcesContent":["/**\n * CourseBuilderPage — the per-course authoring workspace.\n * @module buildmyiq/pages/authoring\n *\n * Loads one course (`useBuiCourse`) and exposes four tabs:\n * - Details — editable course meta (`useBuiUpdateCourse`), cover upload\n * (EvidenceUpload → coverFileId), Publish (`useBuiPublishCourse`) and Archive\n * (`useBuiArchiveCourse`).\n * - Curriculum — modules (`useBuiModules`, `useBuiCreateModule`) and their\n * lessons (`useBuiCreateLesson`).\n * - Assessments — course assessments (`useBuiAssessments`) linking out to the\n * assessment editor.\n * - Discussion — the shared wspace-conversations thread (`BuiDiscussion`).\n * Every list carries loading / error / empty states; all data is live `bui*` data.\n */\n\nimport type { FC } from 'react';\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n Archive,\n ArrowLeft,\n BookOpen,\n Clock,\n FileText,\n ListChecks,\n MessageSquare,\n PlayCircle,\n Plus,\n Send,\n} from 'lucide-react';\nimport { Button, GlassCard, Input, Switch, Textarea } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n Tabs,\n type TabItem,\n StatusBadge,\n EmptyState,\n LoadingView,\n ErrorView,\n Section,\n EvidenceUpload,\n BuiDiscussion,\n} from '../../components';\nimport { Modal, Field, SelectField, NO_SKILL } from './_forms';\nimport { useBuildmyiq } from '../../context';\nimport {\n useBuiCourse,\n useBuiUpdateCourse,\n useBuiPublishCourse,\n useBuiArchiveCourse,\n useBuiModules,\n useBuiCreateModule,\n useBuiCreateLesson,\n useBuiAssessments,\n useBuiSkills,\n type UploadedBuiFile,\n} from '../../hooks';\nimport { COURSE_LEVELS, LESSON_TYPES } from '../../types';\nimport type {\n BuiCourse,\n BuiCourseLevel,\n BuiCreateLessonInput,\n BuiCreateModuleInput,\n BuiLessonType,\n BuiModule,\n BuiUpdateCourseInput,\n} from '../../types';\nimport { formatDuration, formatEnumLabel } from '../../utils/formatters';\n\ntype BuilderTab = 'details' | 'curriculum' | 'assessments' | 'discussion';\n\n// ============================================================================\n// Details tab\n// ============================================================================\n\nconst DetailsTab: FC<{ course: BuiCourse }> = ({ course }) => {\n const updateCourse = useBuiUpdateCourse();\n const publishCourse = useBuiPublishCourse();\n const archiveCourse = useBuiArchiveCourse();\n const skillsQuery = useBuiSkills();\n const skills = skillsQuery.data ?? [];\n\n const [title, setTitle] = useState(course.title);\n const [summary, setSummary] = useState(course.summary ?? '');\n const [description, setDescription] = useState(course.description ?? '');\n const [level, setLevel] = useState<BuiCourseLevel>(course.level);\n const [language, setLanguage] = useState(course.language);\n const [estimatedHours, setEstimatedHours] = useState(String(course.estimatedHours ?? 0));\n const [skillId, setSkillId] = useState<string>(course.skillId ?? NO_SKILL);\n const [isPublic, setIsPublic] = useState(course.isPublic);\n const [coverFile, setCoverFile] = useState<UploadedBuiFile | null>(null);\n\n const [saveError, setSaveError] = useState<string | null>(null);\n const [coverError, setCoverError] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n const [confirmArchive, setConfirmArchive] = useState(false);\n\n const canPublish = course.status === 'DRAFT' || course.status === 'IN_REVIEW';\n const canArchive = course.status !== 'ARCHIVED';\n\n const handleSave = async () => {\n setSaveError(null);\n const input: BuiUpdateCourseInput = {\n title: title.trim() || course.title,\n summary: summary.trim() || undefined,\n description: description.trim() || undefined,\n level,\n language: language.trim() || 'en',\n estimatedHours: estimatedHours.trim() ? Number(estimatedHours) : 0,\n skillId: skillId !== NO_SKILL ? skillId : undefined,\n isPublic,\n };\n try {\n await updateCourse.mutateAsync({ id: course.id, input });\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'Failed to save changes.');\n }\n };\n\n const handleCoverChange = async (file: UploadedBuiFile | null) => {\n setCoverFile(file);\n if (!file) return;\n setCoverError(null);\n try {\n await updateCourse.mutateAsync({ id: course.id, input: { coverFileId: file.fileId } });\n } catch (e) {\n setCoverError(e instanceof Error ? e.message : 'Failed to update the cover.');\n }\n };\n\n const handlePublish = async () => {\n setActionError(null);\n try {\n await publishCourse.mutateAsync(course.id);\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'Failed to publish the course.');\n }\n };\n\n const handleArchive = async () => {\n setActionError(null);\n try {\n await archiveCourse.mutateAsync(course.id);\n setConfirmArchive(false);\n } catch (e) {\n setActionError(e instanceof Error ? e.message : 'Failed to archive the course.');\n }\n };\n\n return (\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <Section\n title=\"Course details\"\n description=\"Metadata learners see in the catalog.\"\n action={\n <Button onClick={handleSave} disabled={updateCourse.isPending}>\n {updateCourse.isPending ? 'Saving…' : 'Save changes'}\n </Button>\n }\n >\n <div className=\"grid gap-4\">\n <Field label=\"Title\" htmlFor=\"detail-title\" required>\n <Input id=\"detail-title\" value={title} onChange={(e) => setTitle(e.target.value)} />\n </Field>\n <Field label=\"Summary\" htmlFor=\"detail-summary\">\n <Textarea\n id=\"detail-summary\"\n rows={2}\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n placeholder=\"A short description shown on the catalog card.\"\n />\n </Field>\n <Field label=\"Description\" htmlFor=\"detail-description\">\n <Textarea\n id=\"detail-description\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"The full course overview.\"\n />\n </Field>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <Field label=\"Level\">\n <SelectField\n value={level}\n onChange={(v) => setLevel(v as BuiCourseLevel)}\n options={COURSE_LEVELS.map((l) => ({ value: l, label: formatEnumLabel(l) }))}\n />\n </Field>\n <Field label=\"Language\" htmlFor=\"detail-language\">\n <Input\n id=\"detail-language\"\n value={language}\n onChange={(e) => setLanguage(e.target.value)}\n placeholder=\"en\"\n />\n </Field>\n <Field label=\"Estimated hours\" htmlFor=\"detail-hours\">\n <Input\n id=\"detail-hours\"\n type=\"number\"\n min={0}\n value={estimatedHours}\n onChange={(e) => setEstimatedHours(e.target.value)}\n />\n </Field>\n <Field label=\"Skill\">\n <SelectField\n value={skillId}\n onChange={setSkillId}\n options={[\n { value: NO_SKILL, label: skillsQuery.isLoading ? 'Loading…' : 'No skill' },\n ...skills.map((s) => ({ value: s.id, label: s.name })),\n ]}\n />\n </Field>\n </div>\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm text-text-secondary\">\n <Switch checked={isPublic} onCheckedChange={setIsPublic} />\n Publicly visible in the catalog\n </label>\n {saveError && <p className=\"text-sm text-status-error-text\">{saveError}</p>}\n </div>\n </Section>\n </div>\n\n <div className=\"flex flex-col gap-6\">\n <Section title=\"Cover image\">\n <div className=\"grid gap-3\">\n <div className=\"h-36 w-full overflow-hidden rounded-xl border border-border-seam bg-bg-sunken\">\n {course.cover?.downloadUrl ? (\n <img src={course.cover.downloadUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full items-center justify-center text-sm text-text-secondary\">\n No cover yet\n </div>\n )}\n </div>\n <EvidenceUpload\n id=\"course-cover\"\n label=\"Upload cover\"\n value={coverFile}\n onChange={handleCoverChange}\n accept=\"image/*\"\n hint=\"PNG or JPG, shown on catalog cards.\"\n />\n {coverError && <p className=\"text-xs text-status-error-text\">{coverError}</p>}\n </div>\n </Section>\n\n <Section title=\"Publishing\">\n <div className=\"grid gap-3\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n Status <StatusBadge status={course.status} />\n </div>\n {canPublish && (\n <Button onClick={handlePublish} disabled={publishCourse.isPending}>\n <Send className=\"mr-1.5 h-4 w-4\" />\n {publishCourse.isPending ? 'Publishing…' : 'Publish course'}\n </Button>\n )}\n {canArchive && (\n <Button variant=\"outline\" onClick={() => setConfirmArchive(true)}>\n <Archive className=\"mr-1.5 h-4 w-4\" /> Archive\n </Button>\n )}\n {actionError && <p className=\"text-sm text-status-error-text\">{actionError}</p>}\n </div>\n </Section>\n </div>\n\n {confirmArchive && (\n <Modal\n open\n onClose={() => setConfirmArchive(false)}\n title=\"Archive this course?\"\n description=\"Archived courses are hidden from the catalog and cannot be enrolled in.\"\n footer={\n <>\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmArchive(false)}\n disabled={archiveCourse.isPending}\n >\n Cancel\n </Button>\n <Button\n variant=\"destructive\"\n onClick={handleArchive}\n disabled={archiveCourse.isPending}\n >\n {archiveCourse.isPending ? 'Archiving…' : 'Archive course'}\n </Button>\n </>\n }\n >\n <p className=\"text-sm text-text-secondary\">\n You can still find it in Authoring under the Archived filter.\n </p>\n </Modal>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Curriculum tab\n// ============================================================================\n\nconst AddModuleModal: FC<{ courseId: string; position: number; onClose: () => void }> = ({\n courseId,\n position,\n onClose,\n}) => {\n const createModule = useBuiCreateModule();\n const [title, setTitle] = useState('');\n const [description, setDescription] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n const canSubmit = title.trim().length > 0 && !createModule.isPending;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n setError(null);\n const input: BuiCreateModuleInput = {\n courseId,\n title: title.trim(),\n description: description.trim() || undefined,\n position,\n };\n try {\n await createModule.mutateAsync(input);\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Failed to add the module.');\n }\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Add module\"\n footer={\n <>\n <Button variant=\"ghost\" onClick={onClose} disabled={createModule.isPending}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n {createModule.isPending ? 'Adding…' : 'Add module'}\n </Button>\n </>\n }\n >\n <div className=\"grid gap-4\">\n <Field label=\"Module title\" htmlFor=\"module-title\" required>\n <Input\n id=\"module-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. Getting started\"\n />\n </Field>\n <Field label=\"Description\" htmlFor=\"module-description\">\n <Textarea\n id=\"module-description\"\n rows={3}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n />\n </Field>\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n </Modal>\n );\n};\n\nconst AddLessonModal: FC<{\n courseId: string;\n moduleId: string;\n position: number;\n onClose: () => void;\n}> = ({ courseId, moduleId, position, onClose }) => {\n const createLesson = useBuiCreateLesson();\n const [title, setTitle] = useState('');\n const [type, setType] = useState<BuiLessonType>('ARTICLE');\n const [content, setContent] = useState('');\n const [durationMin, setDurationMin] = useState('');\n const [isPreview, setIsPreview] = useState(false);\n const [media, setMedia] = useState<UploadedBuiFile | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const canSubmit = title.trim().length > 0 && !createLesson.isPending;\n\n const handleSubmit = async () => {\n if (!canSubmit) return;\n setError(null);\n const input: BuiCreateLessonInput = {\n courseId,\n moduleId,\n title: title.trim(),\n type,\n content: content.trim() || undefined,\n durationMin: durationMin.trim() ? Number(durationMin) : undefined,\n position,\n isPreview,\n mediaFileId: media?.fileId,\n };\n try {\n await createLesson.mutateAsync(input);\n onClose();\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Failed to add the lesson.');\n }\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"Add lesson\"\n className=\"sm:max-w-xl\"\n footer={\n <>\n <Button variant=\"ghost\" onClick={onClose} disabled={createLesson.isPending}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={!canSubmit}>\n {createLesson.isPending ? 'Adding…' : 'Add lesson'}\n </Button>\n </>\n }\n >\n <div className=\"grid gap-4\">\n <Field label=\"Lesson title\" htmlFor=\"lesson-title\" required>\n <Input\n id=\"lesson-title\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. What is data literacy?\"\n />\n </Field>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <Field label=\"Type\">\n <SelectField\n value={type}\n onChange={(v) => setType(v as BuiLessonType)}\n options={LESSON_TYPES.map((t) => ({ value: t, label: formatEnumLabel(t) }))}\n />\n </Field>\n <Field label=\"Duration (minutes)\" htmlFor=\"lesson-duration\">\n <Input\n id=\"lesson-duration\"\n type=\"number\"\n min={0}\n value={durationMin}\n onChange={(e) => setDurationMin(e.target.value)}\n placeholder=\"0\"\n />\n </Field>\n </div>\n <Field\n label=\"Content\"\n htmlFor=\"lesson-content\"\n hint=\"Lesson body — markdown or plain text.\"\n >\n <Textarea\n id=\"lesson-content\"\n rows={5}\n value={content}\n onChange={(e) => setContent(e.target.value)}\n />\n </Field>\n <EvidenceUpload\n id=\"lesson-media\"\n label=\"Media (optional)\"\n value={media}\n onChange={setMedia}\n hint=\"Attach a video, audio file or PDF for this lesson.\"\n />\n <label className=\"inline-flex cursor-pointer items-center gap-2 text-sm text-text-secondary\">\n <Switch checked={isPreview} onCheckedChange={setIsPreview} />\n Free preview lesson\n </label>\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n </Modal>\n );\n};\n\nconst ModuleCard: FC<{ module: BuiModule; index: number; onAddLesson: () => void }> = ({\n module,\n index,\n onAddLesson,\n}) => {\n const lessons = [...(module.lessons ?? [])].sort((a, b) => a.position - b.position);\n return (\n <GlassCard treatment=\"plain\" className=\"p-4\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h3 className=\"font-semibold text-text-primary\">\n <span className=\"mr-2 text-text-tertiary\">Module {index + 1}</span>\n {module.title}\n </h3>\n {module.description && (\n <p className=\"mt-0.5 text-sm text-text-secondary\">{module.description}</p>\n )}\n </div>\n <Button variant=\"outline\" size=\"sm\" onClick={onAddLesson}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add lesson\n </Button>\n </div>\n <div className=\"mt-3\">\n {lessons.length === 0 ? (\n <p className=\"rounded-lg border border-dashed border-border-seam px-3 py-3 text-sm text-text-secondary\">\n No lessons yet.\n </p>\n ) : (\n <ul className=\"flex flex-col gap-1.5\">\n {lessons.map((lesson) => (\n <li\n key={lesson.id}\n className=\"flex flex-wrap items-center gap-3 rounded-lg border border-border-seam bg-bg-surface px-3 py-2\"\n >\n <PlayCircle className=\"h-4 w-4 shrink-0 text-text-tertiary\" />\n <span className=\"min-w-0 flex-1 truncate text-sm text-text-primary\">\n {lesson.title}\n </span>\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n {formatEnumLabel(lesson.type)}\n </span>\n {lesson.isPreview && (\n <span className=\"rounded-full bg-[var(--color-accent-soft)] px-2 py-0.5 text-xs text-text-primary\">\n Preview\n </span>\n )}\n {lesson.durationMin > 0 && (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(lesson.durationMin)}\n </span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n </GlassCard>\n );\n};\n\nconst CurriculumTab: FC<{ courseId: string }> = ({ courseId }) => {\n const modulesQuery = useBuiModules(courseId);\n const [showAddModule, setShowAddModule] = useState(false);\n const [lessonModuleId, setLessonModuleId] = useState<string | null>(null);\n\n const modules = modulesQuery.data ?? [];\n const lessonModule = modules.find((m) => m.id === lessonModuleId) ?? null;\n\n return (\n <Section\n title=\"Curriculum\"\n description=\"Organise the course into modules and lessons.\"\n action={\n <Button onClick={() => setShowAddModule(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add module\n </Button>\n }\n >\n {modulesQuery.isLoading ? (\n <LoadingView label=\"Loading curriculum…\" />\n ) : modulesQuery.isError ? (\n <ErrorView\n message=\"We couldn't load the curriculum.\"\n onRetry={() => modulesQuery.refetch()}\n />\n ) : modules.length === 0 ? (\n <EmptyState\n illustration=\"onboarding\"\n title=\"No modules yet\"\n description=\"Add your first module, then fill it with lessons.\"\n action={\n <Button onClick={() => setShowAddModule(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add module\n </Button>\n }\n />\n ) : (\n <div className=\"flex flex-col gap-4\">\n {[...modules]\n .sort((a, b) => a.position - b.position)\n .map((mod, idx) => (\n <ModuleCard\n key={mod.id}\n module={mod}\n index={idx}\n onAddLesson={() => setLessonModuleId(mod.id)}\n />\n ))}\n </div>\n )}\n\n {showAddModule && (\n <AddModuleModal\n courseId={courseId}\n position={modules.length}\n onClose={() => setShowAddModule(false)}\n />\n )}\n {lessonModuleId && (\n <AddLessonModal\n courseId={courseId}\n moduleId={lessonModuleId}\n position={lessonModule?.lessons?.length ?? 0}\n onClose={() => setLessonModuleId(null)}\n />\n )}\n </Section>\n );\n};\n\n// ============================================================================\n// Assessments tab\n// ============================================================================\n\nconst AssessmentsTab: FC<{ courseId: string }> = ({ courseId }) => {\n const { navigateTo } = useBuildmyiq();\n const assessmentsQuery = useBuiAssessments(courseId);\n const assessments = assessmentsQuery.data ?? [];\n\n return (\n <Section\n title=\"Assessments\"\n description=\"Quizzes, exams and assignments attached to this course.\"\n >\n {assessmentsQuery.isLoading ? (\n <LoadingView label=\"Loading assessments…\" />\n ) : assessmentsQuery.isError ? (\n <ErrorView\n message=\"We couldn't load the assessments.\"\n onRetry={() => assessmentsQuery.refetch()}\n />\n ) : assessments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No assessments yet\"\n description=\"Create an assessment in the Assessments workspace to test learners on this course.\"\n action={\n <Button variant=\"outline\" onClick={() => navigateTo('assessments')}>\n Open assessments\n </Button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {assessments.map((a) => (\n <GlassCard\n key={a.id}\n treatment=\"plain\"\n className=\"flex cursor-pointer flex-col gap-2 p-4 transition-shadow hover:shadow-lg\"\n onClick={() => navigateTo(`assessments/${a.id}`)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <h3 className=\"min-w-0 font-semibold text-text-primary\">{a.title}</h3>\n <StatusBadge status={a.status} />\n </div>\n {a.description && (\n <p className=\"line-clamp-2 text-sm text-text-secondary\">{a.description}</p>\n )}\n <div className=\"mt-auto flex flex-wrap items-center gap-3 pt-1 text-xs text-text-secondary\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">\n {formatEnumLabel(a.type)}\n </span>\n <span>Pass ≥ {a.passingScore ?? 0}%</span>\n {a.timeLimitMin > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(a.timeLimitMin)}\n </span>\n )}\n </div>\n </GlassCard>\n ))}\n </div>\n )}\n </Section>\n );\n};\n\n// ============================================================================\n// Page\n// ============================================================================\n\nexport const CourseBuilderPage: FC = () => {\n const { courseId } = useParams<{ courseId: string }>();\n const { navigateTo } = useBuildmyiq();\n const [tab, setTab] = useState<BuilderTab>('details');\n const courseQuery = useBuiCourse(courseId);\n const course = courseQuery.data ?? null;\n\n if (courseQuery.isLoading) {\n return (\n <PageLayout title=\"Course builder\">\n <LoadingView label=\"Loading course…\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isError) {\n return (\n <PageLayout title=\"Course builder\">\n <ErrorView message=\"We couldn't load this course.\" onRetry={() => courseQuery.refetch()} />\n </PageLayout>\n );\n }\n\n if (!courseId || !course) {\n return (\n <PageLayout title=\"Course builder\">\n <EmptyState\n illustration=\"empty-search\"\n title=\"Course not found\"\n description=\"This course may have been archived or removed.\"\n action={<Button onClick={() => navigateTo('authoring')}>Back to authoring</Button>}\n />\n </PageLayout>\n );\n }\n\n const tabs: TabItem<BuilderTab>[] = [\n { value: 'details', label: 'Details', icon: <FileText className=\"h-4 w-4\" /> },\n {\n value: 'curriculum',\n label: 'Curriculum',\n icon: <BookOpen className=\"h-4 w-4\" />,\n count: course.modules?.length ?? 0,\n },\n { value: 'assessments', label: 'Assessments', icon: <ListChecks className=\"h-4 w-4\" /> },\n { value: 'discussion', label: 'Discussion', icon: <MessageSquare className=\"h-4 w-4\" /> },\n ];\n\n return (\n <PageLayout\n title={course.title}\n description={course.summary ?? undefined}\n actions={\n <Button variant=\"ghost\" onClick={() => navigateTo('authoring')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Back\n </Button>\n }\n >\n <div className=\"flex flex-col gap-5\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.status} />\n <StatusBadge status={course.level} />\n </div>\n\n <Tabs items={tabs} value={tab} onChange={setTab} />\n\n {tab === 'details' && <DetailsTab key={course.id} course={course} />}\n {tab === 'curriculum' && <CurriculumTab courseId={courseId} />}\n {tab === 'assessments' && <AssessmentsTab courseId={courseId} />}\n {tab === 'discussion' && (\n <BuiDiscussion entityType=\"buildmyiq-course\" entityId={courseId} />\n )}\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -88,8 +88,8 @@ var B = "buildmyiq-course", V = {
88
88
  className: "grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,3fr)]",
89
89
  children: [/* @__PURE__ */ I("div", {
90
90
  className: "relative h-48 w-full overflow-hidden bg-bg-sunken lg:h-full",
91
- children: K.cover?.url ? /* @__PURE__ */ I("img", {
92
- src: K.cover.url,
91
+ children: K.cover?.downloadUrl ? /* @__PURE__ */ I("img", {
92
+ src: K.cover.downloadUrl,
93
93
  alt: "",
94
94
  className: "h-full w-full object-cover"
95
95
  }) : /* @__PURE__ */ I("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"CourseDetailPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/catalog/CourseDetailPage.tsx"],"sourcesContent":["/**\n * CourseDetailPage — a single published course: hero, curriculum, assessments,\n * discussion + tags, and the enrol / continue-learning call to action.\n * @module buildmyiq/pages/catalog\n *\n * All data is live: `buiCourse` (hero + flat lessons), `buiListModules`\n * (curriculum), `buiListAssessments` (course exams), and `buiListEnrollments`\n * (to decide Enrol vs Continue). Enrolling calls `buiEnroll` then routes the\n * learner straight into their new enrollment. Every list has its own\n * loading / error / empty state.\n */\n\nimport type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport type { LucideIcon } from 'lucide-react';\nimport {\n ArrowLeft,\n BookOpen,\n ClipboardCheck,\n ClipboardList,\n Clock,\n FileText,\n GraduationCap,\n Layers,\n ListChecks,\n MousePointerClick,\n PlayCircle,\n Radio,\n Sparkles,\n Video,\n} from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n Section,\n LoadingView,\n ErrorView,\n EmptyState,\n MiniBar,\n BuiDiscussion,\n BuiTags,\n} from '../../components';\nimport { useBuildmyiq } from '../../context';\nimport {\n useBuiCourse,\n useBuiModules,\n useBuiAssessments,\n useBuiEnrollments,\n useBuiEnroll,\n} from '../../hooks';\nimport { formatHours, formatDuration, formatEnumLabel } from '../../utils/formatters';\nimport type { BuiLesson, BuiLessonType } from '../../types';\n\nconst COURSE_ENTITY = 'buildmyiq-course';\n\n/** Lesson-type → icon, so learners can scan a module at a glance. */\nconst LESSON_ICON: Record<BuiLessonType, LucideIcon> = {\n ARTICLE: FileText,\n VIDEO: Video,\n QUIZ: ListChecks,\n ASSIGNMENT: ClipboardList,\n INTERACTIVE: MousePointerClick,\n LIVE_SESSION: Radio,\n};\n\nconst LessonRow: FC<{ lesson: BuiLesson }> = ({ lesson }) => {\n const Icon = LESSON_ICON[lesson.type] ?? FileText;\n return (\n <li className=\"flex items-center gap-3 px-4 py-3\">\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <Icon className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{lesson.title}</p>\n <p className=\"text-xs text-text-tertiary\">{formatEnumLabel(lesson.type)}</p>\n </div>\n {lesson.isPreview && (\n <span className=\"shrink-0 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n Preview\n </span>\n )}\n {lesson.durationMin > 0 && (\n <span className=\"hidden shrink-0 items-center gap-1 text-xs tabular-nums text-text-secondary sm:inline-flex\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(lesson.durationMin)}\n </span>\n )}\n </li>\n );\n};\n\nexport const CourseDetailPage: FC = () => {\n const { courseId } = useParams<{ courseId: string }>();\n const { currentUser, navigateTo } = useBuildmyiq();\n const learnerId = currentUser?.id;\n\n const courseQuery = useBuiCourse(courseId);\n const modulesQuery = useBuiModules(courseId);\n const assessmentsQuery = useBuiAssessments(courseId);\n const enrollmentsQuery = useBuiEnrollments({\n courseId,\n learnerId,\n enabled: Boolean(courseId && learnerId),\n });\n\n const enroll = useBuiEnroll();\n const [enrolError, setEnrolError] = useState<string | null>(null);\n\n const course = courseQuery.data ?? null;\n const modules = modulesQuery.data ?? [];\n const assessments = assessmentsQuery.data ?? [];\n const enrollments = enrollmentsQuery.data?.items ?? [];\n\n // An existing, non-terminal enrollment means \"Continue\" instead of \"Enrol\".\n const activeEnrollment = useMemo(\n () => enrollments.find((e) => e.status !== 'DROPPED' && e.status !== 'EXPIRED'),\n [enrollments]\n );\n\n // Lessons attached directly to the course (no module) — surfaced as their own group.\n const ungroupedLessons = useMemo(\n () => (course?.lessons ?? []).filter((lesson) => !lesson.moduleId),\n [course]\n );\n\n const totalLessons = course?.lessons?.length ?? 0;\n\n const handleEnrol = async (): Promise<void> => {\n if (!courseId || !learnerId) return;\n setEnrolError(null);\n try {\n const created = await enroll.mutateAsync({ courseId, learnerId });\n navigateTo(`learning/${created.id}`);\n } catch (err) {\n setEnrolError(err instanceof Error ? err.message : 'Could not enrol in this course.');\n }\n };\n\n // Top-level page states.\n if (!courseId) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView title=\"Missing course\" message=\"No course was specified.\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isLoading) {\n return (\n <PageLayout title=\"Course\">\n <LoadingView label=\"Loading course…\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isError) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView\n title=\"Couldn't load this course\"\n message={courseQuery.error instanceof Error ? courseQuery.error.message : undefined}\n onRetry={() => courseQuery.refetch()}\n />\n </PageLayout>\n );\n }\n\n if (!course) {\n return (\n <PageLayout title=\"Course\">\n <EmptyState\n illustration=\"empty-search\"\n title=\"Course not found\"\n description=\"This course may have been unpublished or removed.\"\n action={<Button onClick={() => navigateTo('catalog')}>Back to catalog</Button>}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title={course.title}>\n <div className=\"mx-auto flex w-full max-w-5xl flex-col gap-8\">\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog')}\n className=\"inline-flex w-fit items-center gap-1.5 text-sm text-text-secondary transition-colors hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back to catalog\n </button>\n\n {/* Hero */}\n <GlassCard treatment=\"plain\" className=\"overflow-hidden\">\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,3fr)]\">\n <div className=\"relative h-48 w-full overflow-hidden bg-bg-sunken lg:h-full\">\n {course.cover?.url ? (\n <img src={course.cover.url} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full min-h-[12rem] w-full items-center justify-center bg-[var(--color-accent-soft)]\">\n <BookOpen className=\"h-10 w-10 text-text-secondary opacity-60\" />\n </div>\n )}\n </div>\n\n <div className=\"flex flex-col gap-4 p-6\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.level} />\n {course.skill?.name && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary\">\n <Sparkles className=\"h-3.5 w-3.5\" /> {course.skill.name}\n </span>\n )}\n </div>\n\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">{course.title}</h1>\n {course.summary && (\n <p className=\"mt-2 text-sm text-text-secondary\">{course.summary}</p>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n <Layers className=\"h-3.5 w-3.5\" /> {modules.length} module\n {modules.length === 1 ? '' : 's'} · {totalLessons} lesson\n {totalLessons === 1 ? '' : 's'}\n </span>\n {course.estimatedHours > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatHours(course.estimatedHours)}\n </span>\n )}\n </div>\n\n {course.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {course.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n\n {course.description && (\n <p className=\"whitespace-pre-wrap text-sm leading-relaxed text-text-secondary\">\n {course.description}\n </p>\n )}\n\n {/* Primary CTA — Continue if enrolled, else Enrol */}\n <div className=\"mt-auto flex flex-col gap-2 pt-2\">\n {activeEnrollment ? (\n <>\n <Button\n size=\"lg\"\n className=\"w-full sm:w-auto\"\n onClick={() => navigateTo(`learning/${activeEnrollment.id}`)}\n >\n <PlayCircle className=\"mr-2 h-4 w-4\" /> Continue learning\n </Button>\n <div className=\"flex items-center gap-2\">\n <MiniBar value={activeEnrollment.progressPct} className=\"flex-1\" />\n <span className=\"shrink-0 text-xs tabular-nums text-text-secondary\">\n {activeEnrollment.progressPct}% complete\n </span>\n </div>\n </>\n ) : (\n <>\n <Button\n size=\"lg\"\n className=\"w-full sm:w-auto\"\n onClick={handleEnrol}\n disabled={enroll.isPending || !learnerId}\n >\n <GraduationCap className=\"mr-2 h-4 w-4\" />\n {enroll.isPending ? 'Enrolling…' : 'Enrol in this course'}\n </Button>\n {!learnerId && (\n <p className=\"text-xs text-text-tertiary\">\n Sign in to your workspace to enrol.\n </p>\n )}\n {enrolError && <p className=\"text-xs text-status-error-text\">{enrolError}</p>}\n </>\n )}\n </div>\n </div>\n </div>\n </GlassCard>\n\n {/* Curriculum */}\n <Section title=\"Curriculum\" description=\"Modules and lessons in this course.\">\n {modulesQuery.isLoading ? (\n <LoadingView label=\"Loading curriculum…\" />\n ) : modulesQuery.isError ? (\n <ErrorView\n title=\"Couldn't load the curriculum\"\n message={modulesQuery.error instanceof Error ? modulesQuery.error.message : undefined}\n onRetry={() => modulesQuery.refetch()}\n />\n ) : modules.length === 0 && ungroupedLessons.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No lessons yet\"\n description=\"The instructor hasn't added any modules or lessons to this course.\"\n />\n ) : (\n <div className=\"flex flex-col gap-4\">\n {modules.map((module, index) => {\n const lessons = module.lessons ?? [];\n return (\n <div\n key={module.id}\n className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-surface\"\n >\n <div className=\"border-b border-border-seam px-4 py-3\">\n <div className=\"flex items-baseline justify-between gap-3\">\n <h3 className=\"font-semibold text-text-primary\">\n <span className=\"mr-2 text-text-tertiary\">\n {String(index + 1).padStart(2, '0')}\n </span>\n {module.title}\n </h3>\n <span className=\"shrink-0 text-xs text-text-tertiary\">\n {lessons.length} lesson{lessons.length === 1 ? '' : 's'}\n </span>\n </div>\n {module.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">{module.description}</p>\n )}\n </div>\n {lessons.length === 0 ? (\n <p className=\"px-4 py-3 text-sm text-text-tertiary\">\n No lessons in this module yet.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-seam\">\n {lessons.map((lesson) => (\n <LessonRow key={lesson.id} lesson={lesson} />\n ))}\n </ul>\n )}\n </div>\n );\n })}\n\n {ungroupedLessons.length > 0 && (\n <div className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-surface\">\n <div className=\"border-b border-border-seam px-4 py-3\">\n <h3 className=\"font-semibold text-text-primary\">Additional lessons</h3>\n </div>\n <ul className=\"divide-y divide-border-seam\">\n {ungroupedLessons.map((lesson) => (\n <LessonRow key={lesson.id} lesson={lesson} />\n ))}\n </ul>\n </div>\n )}\n </div>\n )}\n </Section>\n\n {/* Assessments */}\n <Section title=\"Assessments\" description=\"Quizzes and exams for this course.\">\n {assessmentsQuery.isLoading ? (\n <LoadingView label=\"Loading assessments…\" />\n ) : assessmentsQuery.isError ? (\n <ErrorView\n title=\"Couldn't load assessments\"\n message={\n assessmentsQuery.error instanceof Error ? assessmentsQuery.error.message : undefined\n }\n onRetry={() => assessmentsQuery.refetch()}\n />\n ) : assessments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ClipboardCheck className=\"h-9 w-9\" />}\n title=\"No assessments yet\"\n description=\"This course doesn't have any quizzes or exams attached.\"\n />\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {assessments.map((assessment) => (\n <li\n key={assessment.id}\n className=\"flex flex-wrap items-center gap-3 rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <ClipboardCheck className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium text-text-primary\">{assessment.title}</p>\n <div className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span>Pass ≥ {assessment.passingScore}%</span>\n <span>\n {assessment.maxAttempts} attempt\n {assessment.maxAttempts === 1 ? '' : 's'}\n </span>\n {assessment.timeLimitMin > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {formatDuration(assessment.timeLimitMin)}\n </span>\n )}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <StatusBadge status={assessment.type} />\n <StatusBadge status={assessment.status} />\n </div>\n </li>\n ))}\n </ul>\n )}\n </Section>\n\n {/* Tags (platform wspace-tags) */}\n <BuiTags entityType={COURSE_ENTITY} entityId={courseId} />\n\n {/* Discussion (platform wspace-conversations) */}\n <BuiDiscussion\n entityType={COURSE_ENTITY}\n entityId={courseId}\n description=\"Ask questions and discuss this course with your workspace.\"\n />\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"CourseDetailPage.js","names":[],"sources":["../../../../src/buildmyiq/pages/catalog/CourseDetailPage.tsx"],"sourcesContent":["/**\n * CourseDetailPage — a single published course: hero, curriculum, assessments,\n * discussion + tags, and the enrol / continue-learning call to action.\n * @module buildmyiq/pages/catalog\n *\n * All data is live: `buiCourse` (hero + flat lessons), `buiListModules`\n * (curriculum), `buiListAssessments` (course exams), and `buiListEnrollments`\n * (to decide Enrol vs Continue). Enrolling calls `buiEnroll` then routes the\n * learner straight into their new enrollment. Every list has its own\n * loading / error / empty state.\n */\n\nimport type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport type { LucideIcon } from 'lucide-react';\nimport {\n ArrowLeft,\n BookOpen,\n ClipboardCheck,\n ClipboardList,\n Clock,\n FileText,\n GraduationCap,\n Layers,\n ListChecks,\n MousePointerClick,\n PlayCircle,\n Radio,\n Sparkles,\n Video,\n} from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n Section,\n LoadingView,\n ErrorView,\n EmptyState,\n MiniBar,\n BuiDiscussion,\n BuiTags,\n} from '../../components';\nimport { useBuildmyiq } from '../../context';\nimport {\n useBuiCourse,\n useBuiModules,\n useBuiAssessments,\n useBuiEnrollments,\n useBuiEnroll,\n} from '../../hooks';\nimport { formatHours, formatDuration, formatEnumLabel } from '../../utils/formatters';\nimport type { BuiLesson, BuiLessonType } from '../../types';\n\nconst COURSE_ENTITY = 'buildmyiq-course';\n\n/** Lesson-type → icon, so learners can scan a module at a glance. */\nconst LESSON_ICON: Record<BuiLessonType, LucideIcon> = {\n ARTICLE: FileText,\n VIDEO: Video,\n QUIZ: ListChecks,\n ASSIGNMENT: ClipboardList,\n INTERACTIVE: MousePointerClick,\n LIVE_SESSION: Radio,\n};\n\nconst LessonRow: FC<{ lesson: BuiLesson }> = ({ lesson }) => {\n const Icon = LESSON_ICON[lesson.type] ?? FileText;\n return (\n <li className=\"flex items-center gap-3 px-4 py-3\">\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <Icon className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{lesson.title}</p>\n <p className=\"text-xs text-text-tertiary\">{formatEnumLabel(lesson.type)}</p>\n </div>\n {lesson.isPreview && (\n <span className=\"shrink-0 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n Preview\n </span>\n )}\n {lesson.durationMin > 0 && (\n <span className=\"hidden shrink-0 items-center gap-1 text-xs tabular-nums text-text-secondary sm:inline-flex\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatDuration(lesson.durationMin)}\n </span>\n )}\n </li>\n );\n};\n\nexport const CourseDetailPage: FC = () => {\n const { courseId } = useParams<{ courseId: string }>();\n const { currentUser, navigateTo } = useBuildmyiq();\n const learnerId = currentUser?.id;\n\n const courseQuery = useBuiCourse(courseId);\n const modulesQuery = useBuiModules(courseId);\n const assessmentsQuery = useBuiAssessments(courseId);\n const enrollmentsQuery = useBuiEnrollments({\n courseId,\n learnerId,\n enabled: Boolean(courseId && learnerId),\n });\n\n const enroll = useBuiEnroll();\n const [enrolError, setEnrolError] = useState<string | null>(null);\n\n const course = courseQuery.data ?? null;\n const modules = modulesQuery.data ?? [];\n const assessments = assessmentsQuery.data ?? [];\n const enrollments = enrollmentsQuery.data?.items ?? [];\n\n // An existing, non-terminal enrollment means \"Continue\" instead of \"Enrol\".\n const activeEnrollment = useMemo(\n () => enrollments.find((e) => e.status !== 'DROPPED' && e.status !== 'EXPIRED'),\n [enrollments]\n );\n\n // Lessons attached directly to the course (no module) — surfaced as their own group.\n const ungroupedLessons = useMemo(\n () => (course?.lessons ?? []).filter((lesson) => !lesson.moduleId),\n [course]\n );\n\n const totalLessons = course?.lessons?.length ?? 0;\n\n const handleEnrol = async (): Promise<void> => {\n if (!courseId || !learnerId) return;\n setEnrolError(null);\n try {\n const created = await enroll.mutateAsync({ courseId, learnerId });\n navigateTo(`learning/${created.id}`);\n } catch (err) {\n setEnrolError(err instanceof Error ? err.message : 'Could not enrol in this course.');\n }\n };\n\n // Top-level page states.\n if (!courseId) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView title=\"Missing course\" message=\"No course was specified.\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isLoading) {\n return (\n <PageLayout title=\"Course\">\n <LoadingView label=\"Loading course…\" />\n </PageLayout>\n );\n }\n\n if (courseQuery.isError) {\n return (\n <PageLayout title=\"Course\">\n <ErrorView\n title=\"Couldn't load this course\"\n message={courseQuery.error instanceof Error ? courseQuery.error.message : undefined}\n onRetry={() => courseQuery.refetch()}\n />\n </PageLayout>\n );\n }\n\n if (!course) {\n return (\n <PageLayout title=\"Course\">\n <EmptyState\n illustration=\"empty-search\"\n title=\"Course not found\"\n description=\"This course may have been unpublished or removed.\"\n action={<Button onClick={() => navigateTo('catalog')}>Back to catalog</Button>}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout title={course.title}>\n <div className=\"mx-auto flex w-full max-w-5xl flex-col gap-8\">\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog')}\n className=\"inline-flex w-fit items-center gap-1.5 text-sm text-text-secondary transition-colors hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back to catalog\n </button>\n\n {/* Hero */}\n <GlassCard treatment=\"plain\" className=\"overflow-hidden\">\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,3fr)]\">\n <div className=\"relative h-48 w-full overflow-hidden bg-bg-sunken lg:h-full\">\n {course.cover?.downloadUrl ? (\n <img src={course.cover.downloadUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full min-h-[12rem] w-full items-center justify-center bg-[var(--color-accent-soft)]\">\n <BookOpen className=\"h-10 w-10 text-text-secondary opacity-60\" />\n </div>\n )}\n </div>\n\n <div className=\"flex flex-col gap-4 p-6\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={course.level} />\n {course.skill?.name && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary\">\n <Sparkles className=\"h-3.5 w-3.5\" /> {course.skill.name}\n </span>\n )}\n </div>\n\n <div>\n <h1 className=\"text-2xl font-semibold text-text-primary\">{course.title}</h1>\n {course.summary && (\n <p className=\"mt-2 text-sm text-text-secondary\">{course.summary}</p>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-2 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n <Layers className=\"h-3.5 w-3.5\" /> {modules.length} module\n {modules.length === 1 ? '' : 's'} · {totalLessons} lesson\n {totalLessons === 1 ? '' : 's'}\n </span>\n {course.estimatedHours > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" /> {formatHours(course.estimatedHours)}\n </span>\n )}\n </div>\n\n {course.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {course.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n\n {course.description && (\n <p className=\"whitespace-pre-wrap text-sm leading-relaxed text-text-secondary\">\n {course.description}\n </p>\n )}\n\n {/* Primary CTA — Continue if enrolled, else Enrol */}\n <div className=\"mt-auto flex flex-col gap-2 pt-2\">\n {activeEnrollment ? (\n <>\n <Button\n size=\"lg\"\n className=\"w-full sm:w-auto\"\n onClick={() => navigateTo(`learning/${activeEnrollment.id}`)}\n >\n <PlayCircle className=\"mr-2 h-4 w-4\" /> Continue learning\n </Button>\n <div className=\"flex items-center gap-2\">\n <MiniBar value={activeEnrollment.progressPct} className=\"flex-1\" />\n <span className=\"shrink-0 text-xs tabular-nums text-text-secondary\">\n {activeEnrollment.progressPct}% complete\n </span>\n </div>\n </>\n ) : (\n <>\n <Button\n size=\"lg\"\n className=\"w-full sm:w-auto\"\n onClick={handleEnrol}\n disabled={enroll.isPending || !learnerId}\n >\n <GraduationCap className=\"mr-2 h-4 w-4\" />\n {enroll.isPending ? 'Enrolling…' : 'Enrol in this course'}\n </Button>\n {!learnerId && (\n <p className=\"text-xs text-text-tertiary\">\n Sign in to your workspace to enrol.\n </p>\n )}\n {enrolError && <p className=\"text-xs text-status-error-text\">{enrolError}</p>}\n </>\n )}\n </div>\n </div>\n </div>\n </GlassCard>\n\n {/* Curriculum */}\n <Section title=\"Curriculum\" description=\"Modules and lessons in this course.\">\n {modulesQuery.isLoading ? (\n <LoadingView label=\"Loading curriculum…\" />\n ) : modulesQuery.isError ? (\n <ErrorView\n title=\"Couldn't load the curriculum\"\n message={modulesQuery.error instanceof Error ? modulesQuery.error.message : undefined}\n onRetry={() => modulesQuery.refetch()}\n />\n ) : modules.length === 0 && ungroupedLessons.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No lessons yet\"\n description=\"The instructor hasn't added any modules or lessons to this course.\"\n />\n ) : (\n <div className=\"flex flex-col gap-4\">\n {modules.map((module, index) => {\n const lessons = module.lessons ?? [];\n return (\n <div\n key={module.id}\n className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-surface\"\n >\n <div className=\"border-b border-border-seam px-4 py-3\">\n <div className=\"flex items-baseline justify-between gap-3\">\n <h3 className=\"font-semibold text-text-primary\">\n <span className=\"mr-2 text-text-tertiary\">\n {String(index + 1).padStart(2, '0')}\n </span>\n {module.title}\n </h3>\n <span className=\"shrink-0 text-xs text-text-tertiary\">\n {lessons.length} lesson{lessons.length === 1 ? '' : 's'}\n </span>\n </div>\n {module.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">{module.description}</p>\n )}\n </div>\n {lessons.length === 0 ? (\n <p className=\"px-4 py-3 text-sm text-text-tertiary\">\n No lessons in this module yet.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-seam\">\n {lessons.map((lesson) => (\n <LessonRow key={lesson.id} lesson={lesson} />\n ))}\n </ul>\n )}\n </div>\n );\n })}\n\n {ungroupedLessons.length > 0 && (\n <div className=\"overflow-hidden rounded-xl border border-border-seam bg-bg-surface\">\n <div className=\"border-b border-border-seam px-4 py-3\">\n <h3 className=\"font-semibold text-text-primary\">Additional lessons</h3>\n </div>\n <ul className=\"divide-y divide-border-seam\">\n {ungroupedLessons.map((lesson) => (\n <LessonRow key={lesson.id} lesson={lesson} />\n ))}\n </ul>\n </div>\n )}\n </div>\n )}\n </Section>\n\n {/* Assessments */}\n <Section title=\"Assessments\" description=\"Quizzes and exams for this course.\">\n {assessmentsQuery.isLoading ? (\n <LoadingView label=\"Loading assessments…\" />\n ) : assessmentsQuery.isError ? (\n <ErrorView\n title=\"Couldn't load assessments\"\n message={\n assessmentsQuery.error instanceof Error ? assessmentsQuery.error.message : undefined\n }\n onRetry={() => assessmentsQuery.refetch()}\n />\n ) : assessments.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<ClipboardCheck className=\"h-9 w-9\" />}\n title=\"No assessments yet\"\n description=\"This course doesn't have any quizzes or exams attached.\"\n />\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {assessments.map((assessment) => (\n <li\n key={assessment.id}\n className=\"flex flex-wrap items-center gap-3 rounded-xl border border-border-seam bg-bg-surface p-4\"\n >\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <ClipboardCheck className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium text-text-primary\">{assessment.title}</p>\n <div className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span>Pass ≥ {assessment.passingScore}%</span>\n <span>\n {assessment.maxAttempts} attempt\n {assessment.maxAttempts === 1 ? '' : 's'}\n </span>\n {assessment.timeLimitMin > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" />\n {formatDuration(assessment.timeLimitMin)}\n </span>\n )}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <StatusBadge status={assessment.type} />\n <StatusBadge status={assessment.status} />\n </div>\n </li>\n ))}\n </ul>\n )}\n </Section>\n\n {/* Tags (platform wspace-tags) */}\n <BuiTags entityType={COURSE_ENTITY} entityId={courseId} />\n\n {/* Discussion (platform wspace-conversations) */}\n <BuiDiscussion\n entityType={COURSE_ENTITY}\n entityId={courseId}\n description=\"Ask questions and discuss this course with your workspace.\"\n />\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -74,7 +74,7 @@ export interface BuiConnection<T> {
74
74
  export interface BuiFileRef {
75
75
  id: string;
76
76
  name?: string | null;
77
- url?: string | null;
77
+ downloadUrl?: string | null;
78
78
  mimeType?: string | null;
79
79
  sizeBytes?: number | null;
80
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC;IACT,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,KAAK,MAAM,IAAI,CAAC;IAC9D,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,KAAK,MAAM,IAAI,CAAC;CACxE;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;AAMvD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,WAAW,CAAC;CACvB;AAMD,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAMD,MAAM,MAAM,gBAAgB,GACxB,WAAW,GACX,UAAU,GACV,UAAU,GACV,WAAW,GACX,QAAQ,GACR,UAAU,CAAC;AAEf,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,cAAc,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEjF,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAE/E,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,OAAO,GACP,MAAM,GACN,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;AAExF,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;AAErE,MAAM,MAAM,eAAe,GACvB,eAAe,GACf,iBAAiB,GACjB,YAAY,GACZ,cAAc,GACd,OAAO,GACP,MAAM,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;AAElG,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAEnG,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,aAAa,GAAG,WAAW,CAAC;AAE5E,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AAE/F,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAMpE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,iBAAiB,EAAE,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,4BAA4B;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAMD,eAAO,MAAM,aAAa,EAAE,cAAc,EAAuD,CAAC;AAClG,eAAO,MAAM,eAAe,EAAE,eAAe,EAAoD,CAAC;AAClG,eAAO,MAAM,YAAY,EAAE,aAAa,EAOvC,CAAC;AACF,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,EAM/C,CAAC;AACF,eAAO,MAAM,cAAc,EAAE,eAAe,EAO3C,CAAC;AACF,eAAO,MAAM,gBAAgB,EAAE,gBAAgB,EAO9C,CAAC;AACF,eAAO,MAAM,mBAAmB,EAAE,mBAAmB,EAMpD,CAAC;AACF,eAAO,MAAM,eAAe,EAAE,eAAe,EAM5C,CAAC;AACF,eAAO,MAAM,mBAAmB,EAAE,mBAAmB,EAMpD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/types/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/buildmyiq/types/index.ts"],"sourcesContent":["/**\n * Buildmyiq Microfrontend — TypeScript Type Definitions\n *\n * Buildmyiq — the AI-native education, learning & development system of record.\n * Domain pillars, each 1:1 with a `wspace-buildmyiq-svc` capability:\n * - Catalog & authoring: courses → modules → lessons, skills taxonomy\n * - Assessment: assessments → questions → submissions → grading\n * - Enrolment & progress: enrollments, lesson progress, cohorts\n * - Credentialing: certificates\n *\n * All server-facing types below mirror the `wspace-buildmyiq-svc` federated\n * GraphQL contract exactly (the `Bui*` types, `bui*` root fields). No mock data.\n *\n * @module buildmyiq/types\n */\n\nimport type { ReactNode } from 'react';\n\n// ============================================================================\n// Shell Integration Types\n// ============================================================================\n\nexport interface NavItem {\n id: string;\n label: string;\n path: string;\n icon?: ReactNode;\n badge?: number;\n order?: number;\n group?: string;\n visible?: boolean;\n external?: boolean;\n children?: NavItem[];\n}\n\nexport interface FooterItem {\n id: string;\n label: string;\n icon?: string;\n onClick?: () => void;\n type?: 'status' | 'action' | 'info';\n order?: number;\n badge?: string;\n section?: 'left' | 'center' | 'right';\n visible?: boolean;\n}\n\n/**\n * Props for the BuildmyiqRoot component. Host-contract preserving: the app\n * shell spreads `workspaceBaseProps` (basePath, currentUser, workspaceId,\n * tenantId, apiGatewayUrl, authToken, navigate, registerNavItems,\n * registerFooterItems) onto this component.\n */\nexport interface BuildmyiqRootProps {\n basePath?: string;\n workspaceId?: string;\n tenantId?: string;\n apiGatewayUrl?: string;\n authToken?: string;\n navigate?: (path: string) => void;\n currentUser?: {\n id: string;\n email: string;\n firstName?: string;\n lastName?: string;\n avatar?: string;\n username?: string;\n name?: string;\n role?: string;\n } | null;\n registerNavItems?: (items: NavItem | NavItem[]) => () => void;\n registerFooterItems?: (items: FooterItem | FooterItem[]) => () => void;\n}\n\nexport type TrendDirection = 'up' | 'down' | 'neutral';\n\n// ============================================================================\n// Pagination (mirror svc PaginationInput / Bui*PageInfo)\n// ============================================================================\n\n/**\n * The svc `PaginationInput` accepts { limit, offset, cursor } but the resolver\n * uses cursor+limit only (offset is a no-op). We drive pages by cursor:\n * pass `pagination.cursor = previous pageInfo.cursor` for the next page. The\n * FIRST page must OMIT cursor entirely (an explicit `cursor: null` is rejected).\n */\nexport interface PaginationInput {\n limit?: number;\n offset?: number;\n cursor?: string | null;\n}\n\n/** All Bui*PageInfo variants are structurally { cursor, hasMore }. */\nexport interface BuiPageInfo {\n cursor?: string | null;\n hasMore: boolean;\n}\n\nexport interface BuiConnection<T> {\n items: T[];\n pageInfo: BuiPageInfo;\n}\n\n// ============================================================================\n// Federated stubs (owned by other subgraphs — wspace-files-svc)\n// ============================================================================\n\n/** A wspace-files-svc File reference resolved for cover/media/certificate. */\nexport interface BuiFileRef {\n id: string;\n name?: string | null;\n url?: string | null;\n mimeType?: string | null;\n sizeBytes?: number | null;\n}\n\n// ============================================================================\n// Domain enums (mirror wspace-buildmyiq-svc .hive-schema.graphql exactly)\n// ============================================================================\n\nexport type BuiSkillCategory =\n | 'TECHNICAL'\n | 'BUSINESS'\n | 'CREATIVE'\n | 'COGNITIVE'\n | 'SOCIAL'\n | 'LANGUAGE';\n\nexport type BuiCourseLevel = 'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED' | 'EXPERT';\n\nexport type BuiCourseStatus = 'DRAFT' | 'IN_REVIEW' | 'PUBLISHED' | 'ARCHIVED';\n\nexport type BuiLessonType =\n | 'ARTICLE'\n | 'VIDEO'\n | 'QUIZ'\n | 'ASSIGNMENT'\n | 'INTERACTIVE'\n | 'LIVE_SESSION';\n\nexport type BuiAssessmentType = 'QUIZ' | 'EXAM' | 'ASSIGNMENT' | 'PRACTICAL' | 'SURVEY';\n\nexport type BuiAssessmentStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\n\nexport type BuiQuestionType =\n | 'SINGLE_CHOICE'\n | 'MULTIPLE_CHOICE'\n | 'TRUE_FALSE'\n | 'SHORT_ANSWER'\n | 'ESSAY'\n | 'CODE';\n\nexport type BuiSubmissionStatus = 'IN_PROGRESS' | 'SUBMITTED' | 'GRADING' | 'GRADED' | 'RETURNED';\n\nexport type BuiEnrollmentStatus = 'ENROLLED' | 'IN_PROGRESS' | 'COMPLETED' | 'DROPPED' | 'EXPIRED';\n\nexport type BuiProgressStatus = 'NOT_STARTED' | 'IN_PROGRESS' | 'COMPLETED';\n\nexport type BuiCohortStatus = 'SCHEDULED' | 'ENROLLING' | 'ACTIVE' | 'COMPLETED' | 'CANCELLED';\n\nexport type BuiCertificateStatus = 'ISSUED' | 'EXPIRED' | 'REVOKED';\n\n// ============================================================================\n// Domain entity types (mirror the `Bui*` GraphQL types exactly)\n// ============================================================================\n\nexport interface BuiSkill {\n id: string;\n workspaceId: string;\n name: string;\n category: BuiSkillCategory;\n description?: string | null;\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiModule {\n id: string;\n workspaceId: string;\n courseId: string;\n title: string;\n description?: string | null;\n position: number;\n lessons: BuiLesson[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiLesson {\n id: string;\n workspaceId: string;\n courseId: string;\n moduleId?: string | null;\n title: string;\n type: BuiLessonType;\n content?: string | null;\n media?: BuiFileRef | null;\n durationMin: number;\n position: number;\n isPreview: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiCourse {\n id: string;\n workspaceId: string;\n title: string;\n slug: string;\n summary?: string | null;\n description?: string | null;\n status: BuiCourseStatus;\n level: BuiCourseLevel;\n language: string;\n estimatedHours: number;\n isPublic: boolean;\n tags: string[];\n skillId?: string | null;\n skill?: BuiSkill | null;\n instructorId?: string | null;\n cover?: BuiFileRef | null;\n publishedAt?: string | null;\n modules: BuiModule[];\n lessons: BuiLesson[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiQuestion {\n id: string;\n workspaceId: string;\n assessmentId: string;\n prompt: string;\n type: BuiQuestionType;\n /**\n * JSON blob — array of `{ id?, label }` choices for choice questions. NOTE:\n * `answerKey` is a CREATE-INPUT field only; it is NOT exposed on the type\n * (never query it in a fragment — GRAPHQL_VALIDATION_FAILED).\n */\n options?: unknown;\n points: number;\n position: number;\n explanation?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiAssessment {\n id: string;\n workspaceId: string;\n courseId: string;\n title: string;\n description?: string | null;\n type: BuiAssessmentType;\n status: BuiAssessmentStatus;\n passingScore: number;\n maxAttempts: number;\n timeLimitMin: number;\n isGraded: boolean;\n questions: BuiQuestion[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiSubmission {\n id: string;\n workspaceId: string;\n assessmentId: string;\n enrollmentId?: string | null;\n learnerId: string;\n attempt: number;\n /** JSON blob — learner answers keyed by questionId. */\n answers?: unknown;\n status: BuiSubmissionStatus;\n score?: number | null;\n passed?: boolean | null;\n feedback?: string | null;\n gradedById?: string | null;\n gradedAt?: string | null;\n submittedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiLessonProgress {\n id: string;\n workspaceId: string;\n enrollmentId: string;\n lessonId: string;\n status: BuiProgressStatus;\n secondsSpent: number;\n completedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiCohort {\n id: string;\n workspaceId: string;\n courseId: string;\n name: string;\n capacity: number;\n facilitatorId?: string | null;\n startDate?: string | null;\n endDate?: string | null;\n status: BuiCohortStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiEnrollment {\n id: string;\n workspaceId: string;\n courseId: string;\n learnerId: string;\n cohortId?: string | null;\n cohort?: BuiCohort | null;\n status: BuiEnrollmentStatus;\n progressPct: number;\n enrolledAt: string;\n startedAt?: string | null;\n completedAt?: string | null;\n lastActiveAt?: string | null;\n expiresAt?: string | null;\n lessonProgress: BuiLessonProgress[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiCertificate {\n id: string;\n workspaceId: string;\n courseId: string;\n learnerId: string;\n enrollmentId?: string | null;\n serial: string;\n status: BuiCertificateStatus;\n issuedAt: string;\n expiresAt?: string | null;\n revokedAt?: string | null;\n finalScore?: number | null;\n file?: BuiFileRef | null;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Mutation input types (mirror the svc `Bui*Input` shapes)\n// ============================================================================\n\nexport interface BuiCreateCourseInput {\n title: string;\n slug: string;\n summary?: string;\n description?: string;\n level?: BuiCourseLevel;\n language?: string;\n estimatedHours?: number;\n isPublic?: boolean;\n tags?: string[];\n skillId?: string;\n instructorId?: string;\n coverFileId?: string;\n}\n\nexport interface BuiUpdateCourseInput {\n title?: string;\n summary?: string;\n description?: string;\n level?: BuiCourseLevel;\n language?: string;\n estimatedHours?: number;\n isPublic?: boolean;\n tags?: string[];\n skillId?: string;\n instructorId?: string;\n coverFileId?: string;\n}\n\nexport interface BuiCreateModuleInput {\n courseId: string;\n title: string;\n description?: string;\n position?: number;\n}\n\nexport interface BuiCreateLessonInput {\n courseId: string;\n moduleId?: string;\n title: string;\n type?: BuiLessonType;\n content?: string;\n durationMin?: number;\n position?: number;\n isPreview?: boolean;\n mediaFileId?: string;\n}\n\nexport interface BuiCreateAssessmentInput {\n courseId: string;\n title: string;\n description?: string;\n type?: BuiAssessmentType;\n passingScore?: number;\n maxAttempts?: number;\n timeLimitMin?: number;\n isGraded?: boolean;\n}\n\nexport interface BuiCreateQuestionInput {\n assessmentId: string;\n prompt: string;\n type?: BuiQuestionType;\n options?: unknown;\n answerKey?: unknown;\n points?: number;\n position?: number;\n explanation?: string;\n}\n\nexport interface BuiCreateSkillInput {\n name: string;\n category?: BuiSkillCategory;\n description?: string;\n}\n\nexport interface BuiCreateCohortInput {\n courseId: string;\n name: string;\n capacity?: number;\n facilitatorId?: string;\n startDate?: string;\n endDate?: string;\n}\n\nexport interface BuiEnrollInput {\n courseId: string;\n learnerId?: string;\n cohortId?: string;\n expiresAt?: string;\n}\n\nexport interface BuiRecordLessonProgressInput {\n enrollmentId: string;\n lessonId: string;\n secondsSpent?: number;\n status?: BuiProgressStatus;\n}\n\nexport interface BuiSubmitAssessmentInput {\n assessmentId: string;\n learnerId?: string;\n enrollmentId?: string;\n attempt?: number;\n answers?: unknown;\n}\n\nexport interface BuiGradeSubmissionInput {\n score: number;\n passed?: boolean;\n feedback?: string;\n}\n\nexport interface BuiIssueCertificateInput {\n courseId: string;\n learnerId: string;\n enrollmentId?: string;\n serial: string;\n finalScore?: number;\n expiresAt?: string;\n fileId?: string;\n}\n\n// ============================================================================\n// Convenience option lists (for select controls in authoring UIs)\n// ============================================================================\n\nexport const COURSE_LEVELS: BuiCourseLevel[] = ['BEGINNER', 'INTERMEDIATE', 'ADVANCED', 'EXPERT'];\nexport const COURSE_STATUSES: BuiCourseStatus[] = ['DRAFT', 'IN_REVIEW', 'PUBLISHED', 'ARCHIVED'];\nexport const LESSON_TYPES: BuiLessonType[] = [\n 'ARTICLE',\n 'VIDEO',\n 'QUIZ',\n 'ASSIGNMENT',\n 'INTERACTIVE',\n 'LIVE_SESSION',\n];\nexport const ASSESSMENT_TYPES: BuiAssessmentType[] = [\n 'QUIZ',\n 'EXAM',\n 'ASSIGNMENT',\n 'PRACTICAL',\n 'SURVEY',\n];\nexport const QUESTION_TYPES: BuiQuestionType[] = [\n 'SINGLE_CHOICE',\n 'MULTIPLE_CHOICE',\n 'TRUE_FALSE',\n 'SHORT_ANSWER',\n 'ESSAY',\n 'CODE',\n];\nexport const SKILL_CATEGORIES: BuiSkillCategory[] = [\n 'TECHNICAL',\n 'BUSINESS',\n 'CREATIVE',\n 'COGNITIVE',\n 'SOCIAL',\n 'LANGUAGE',\n];\nexport const ENROLLMENT_STATUSES: BuiEnrollmentStatus[] = [\n 'ENROLLED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DROPPED',\n 'EXPIRED',\n];\nexport const COHORT_STATUSES: BuiCohortStatus[] = [\n 'SCHEDULED',\n 'ENROLLING',\n 'ACTIVE',\n 'COMPLETED',\n 'CANCELLED',\n];\nexport const SUBMISSION_STATUSES: BuiSubmissionStatus[] = [\n 'IN_PROGRESS',\n 'SUBMITTED',\n 'GRADING',\n 'GRADED',\n 'RETURNED',\n];\n"],"mappings":";AA8dA,IAAa,IAAkC;CAAC;CAAY;CAAgB;CAAY;CAAS,EAEpF,IAAgC;CAC3C;CACA;CACA;CACA;CACA;CACA;CACD,EACY,IAAwC;CACnD;CACA;CACA;CACA;CACA;CACD,EACY,IAAoC;CAC/C;CACA;CACA;CACA;CACA;CACA;CACD,EACY,IAAuC;CAClD;CACA;CACA;CACA;CACA;CACA;CACD,EAQY,IAAqC;CAChD;CACA;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/buildmyiq/types/index.ts"],"sourcesContent":["/**\n * Buildmyiq Microfrontend — TypeScript Type Definitions\n *\n * Buildmyiq — the AI-native education, learning & development system of record.\n * Domain pillars, each 1:1 with a `wspace-buildmyiq-svc` capability:\n * - Catalog & authoring: courses → modules → lessons, skills taxonomy\n * - Assessment: assessments → questions → submissions → grading\n * - Enrolment & progress: enrollments, lesson progress, cohorts\n * - Credentialing: certificates\n *\n * All server-facing types below mirror the `wspace-buildmyiq-svc` federated\n * GraphQL contract exactly (the `Bui*` types, `bui*` root fields). No mock data.\n *\n * @module buildmyiq/types\n */\n\nimport type { ReactNode } from 'react';\n\n// ============================================================================\n// Shell Integration Types\n// ============================================================================\n\nexport interface NavItem {\n id: string;\n label: string;\n path: string;\n icon?: ReactNode;\n badge?: number;\n order?: number;\n group?: string;\n visible?: boolean;\n external?: boolean;\n children?: NavItem[];\n}\n\nexport interface FooterItem {\n id: string;\n label: string;\n icon?: string;\n onClick?: () => void;\n type?: 'status' | 'action' | 'info';\n order?: number;\n badge?: string;\n section?: 'left' | 'center' | 'right';\n visible?: boolean;\n}\n\n/**\n * Props for the BuildmyiqRoot component. Host-contract preserving: the app\n * shell spreads `workspaceBaseProps` (basePath, currentUser, workspaceId,\n * tenantId, apiGatewayUrl, authToken, navigate, registerNavItems,\n * registerFooterItems) onto this component.\n */\nexport interface BuildmyiqRootProps {\n basePath?: string;\n workspaceId?: string;\n tenantId?: string;\n apiGatewayUrl?: string;\n authToken?: string;\n navigate?: (path: string) => void;\n currentUser?: {\n id: string;\n email: string;\n firstName?: string;\n lastName?: string;\n avatar?: string;\n username?: string;\n name?: string;\n role?: string;\n } | null;\n registerNavItems?: (items: NavItem | NavItem[]) => () => void;\n registerFooterItems?: (items: FooterItem | FooterItem[]) => () => void;\n}\n\nexport type TrendDirection = 'up' | 'down' | 'neutral';\n\n// ============================================================================\n// Pagination (mirror svc PaginationInput / Bui*PageInfo)\n// ============================================================================\n\n/**\n * The svc `PaginationInput` accepts { limit, offset, cursor } but the resolver\n * uses cursor+limit only (offset is a no-op). We drive pages by cursor:\n * pass `pagination.cursor = previous pageInfo.cursor` for the next page. The\n * FIRST page must OMIT cursor entirely (an explicit `cursor: null` is rejected).\n */\nexport interface PaginationInput {\n limit?: number;\n offset?: number;\n cursor?: string | null;\n}\n\n/** All Bui*PageInfo variants are structurally { cursor, hasMore }. */\nexport interface BuiPageInfo {\n cursor?: string | null;\n hasMore: boolean;\n}\n\nexport interface BuiConnection<T> {\n items: T[];\n pageInfo: BuiPageInfo;\n}\n\n// ============================================================================\n// Federated stubs (owned by other subgraphs — wspace-files-svc)\n// ============================================================================\n\n/** A wspace-files-svc File reference resolved for cover/media/certificate. */\nexport interface BuiFileRef {\n id: string;\n name?: string | null;\n downloadUrl?: string | null;\n mimeType?: string | null;\n sizeBytes?: number | null;\n}\n\n// ============================================================================\n// Domain enums (mirror wspace-buildmyiq-svc .hive-schema.graphql exactly)\n// ============================================================================\n\nexport type BuiSkillCategory =\n | 'TECHNICAL'\n | 'BUSINESS'\n | 'CREATIVE'\n | 'COGNITIVE'\n | 'SOCIAL'\n | 'LANGUAGE';\n\nexport type BuiCourseLevel = 'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED' | 'EXPERT';\n\nexport type BuiCourseStatus = 'DRAFT' | 'IN_REVIEW' | 'PUBLISHED' | 'ARCHIVED';\n\nexport type BuiLessonType =\n | 'ARTICLE'\n | 'VIDEO'\n | 'QUIZ'\n | 'ASSIGNMENT'\n | 'INTERACTIVE'\n | 'LIVE_SESSION';\n\nexport type BuiAssessmentType = 'QUIZ' | 'EXAM' | 'ASSIGNMENT' | 'PRACTICAL' | 'SURVEY';\n\nexport type BuiAssessmentStatus = 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';\n\nexport type BuiQuestionType =\n | 'SINGLE_CHOICE'\n | 'MULTIPLE_CHOICE'\n | 'TRUE_FALSE'\n | 'SHORT_ANSWER'\n | 'ESSAY'\n | 'CODE';\n\nexport type BuiSubmissionStatus = 'IN_PROGRESS' | 'SUBMITTED' | 'GRADING' | 'GRADED' | 'RETURNED';\n\nexport type BuiEnrollmentStatus = 'ENROLLED' | 'IN_PROGRESS' | 'COMPLETED' | 'DROPPED' | 'EXPIRED';\n\nexport type BuiProgressStatus = 'NOT_STARTED' | 'IN_PROGRESS' | 'COMPLETED';\n\nexport type BuiCohortStatus = 'SCHEDULED' | 'ENROLLING' | 'ACTIVE' | 'COMPLETED' | 'CANCELLED';\n\nexport type BuiCertificateStatus = 'ISSUED' | 'EXPIRED' | 'REVOKED';\n\n// ============================================================================\n// Domain entity types (mirror the `Bui*` GraphQL types exactly)\n// ============================================================================\n\nexport interface BuiSkill {\n id: string;\n workspaceId: string;\n name: string;\n category: BuiSkillCategory;\n description?: string | null;\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiModule {\n id: string;\n workspaceId: string;\n courseId: string;\n title: string;\n description?: string | null;\n position: number;\n lessons: BuiLesson[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiLesson {\n id: string;\n workspaceId: string;\n courseId: string;\n moduleId?: string | null;\n title: string;\n type: BuiLessonType;\n content?: string | null;\n media?: BuiFileRef | null;\n durationMin: number;\n position: number;\n isPreview: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiCourse {\n id: string;\n workspaceId: string;\n title: string;\n slug: string;\n summary?: string | null;\n description?: string | null;\n status: BuiCourseStatus;\n level: BuiCourseLevel;\n language: string;\n estimatedHours: number;\n isPublic: boolean;\n tags: string[];\n skillId?: string | null;\n skill?: BuiSkill | null;\n instructorId?: string | null;\n cover?: BuiFileRef | null;\n publishedAt?: string | null;\n modules: BuiModule[];\n lessons: BuiLesson[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiQuestion {\n id: string;\n workspaceId: string;\n assessmentId: string;\n prompt: string;\n type: BuiQuestionType;\n /**\n * JSON blob — array of `{ id?, label }` choices for choice questions. NOTE:\n * `answerKey` is a CREATE-INPUT field only; it is NOT exposed on the type\n * (never query it in a fragment — GRAPHQL_VALIDATION_FAILED).\n */\n options?: unknown;\n points: number;\n position: number;\n explanation?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiAssessment {\n id: string;\n workspaceId: string;\n courseId: string;\n title: string;\n description?: string | null;\n type: BuiAssessmentType;\n status: BuiAssessmentStatus;\n passingScore: number;\n maxAttempts: number;\n timeLimitMin: number;\n isGraded: boolean;\n questions: BuiQuestion[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiSubmission {\n id: string;\n workspaceId: string;\n assessmentId: string;\n enrollmentId?: string | null;\n learnerId: string;\n attempt: number;\n /** JSON blob — learner answers keyed by questionId. */\n answers?: unknown;\n status: BuiSubmissionStatus;\n score?: number | null;\n passed?: boolean | null;\n feedback?: string | null;\n gradedById?: string | null;\n gradedAt?: string | null;\n submittedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiLessonProgress {\n id: string;\n workspaceId: string;\n enrollmentId: string;\n lessonId: string;\n status: BuiProgressStatus;\n secondsSpent: number;\n completedAt?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiCohort {\n id: string;\n workspaceId: string;\n courseId: string;\n name: string;\n capacity: number;\n facilitatorId?: string | null;\n startDate?: string | null;\n endDate?: string | null;\n status: BuiCohortStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiEnrollment {\n id: string;\n workspaceId: string;\n courseId: string;\n learnerId: string;\n cohortId?: string | null;\n cohort?: BuiCohort | null;\n status: BuiEnrollmentStatus;\n progressPct: number;\n enrolledAt: string;\n startedAt?: string | null;\n completedAt?: string | null;\n lastActiveAt?: string | null;\n expiresAt?: string | null;\n lessonProgress: BuiLessonProgress[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BuiCertificate {\n id: string;\n workspaceId: string;\n courseId: string;\n learnerId: string;\n enrollmentId?: string | null;\n serial: string;\n status: BuiCertificateStatus;\n issuedAt: string;\n expiresAt?: string | null;\n revokedAt?: string | null;\n finalScore?: number | null;\n file?: BuiFileRef | null;\n createdAt: string;\n updatedAt: string;\n}\n\n// ============================================================================\n// Mutation input types (mirror the svc `Bui*Input` shapes)\n// ============================================================================\n\nexport interface BuiCreateCourseInput {\n title: string;\n slug: string;\n summary?: string;\n description?: string;\n level?: BuiCourseLevel;\n language?: string;\n estimatedHours?: number;\n isPublic?: boolean;\n tags?: string[];\n skillId?: string;\n instructorId?: string;\n coverFileId?: string;\n}\n\nexport interface BuiUpdateCourseInput {\n title?: string;\n summary?: string;\n description?: string;\n level?: BuiCourseLevel;\n language?: string;\n estimatedHours?: number;\n isPublic?: boolean;\n tags?: string[];\n skillId?: string;\n instructorId?: string;\n coverFileId?: string;\n}\n\nexport interface BuiCreateModuleInput {\n courseId: string;\n title: string;\n description?: string;\n position?: number;\n}\n\nexport interface BuiCreateLessonInput {\n courseId: string;\n moduleId?: string;\n title: string;\n type?: BuiLessonType;\n content?: string;\n durationMin?: number;\n position?: number;\n isPreview?: boolean;\n mediaFileId?: string;\n}\n\nexport interface BuiCreateAssessmentInput {\n courseId: string;\n title: string;\n description?: string;\n type?: BuiAssessmentType;\n passingScore?: number;\n maxAttempts?: number;\n timeLimitMin?: number;\n isGraded?: boolean;\n}\n\nexport interface BuiCreateQuestionInput {\n assessmentId: string;\n prompt: string;\n type?: BuiQuestionType;\n options?: unknown;\n answerKey?: unknown;\n points?: number;\n position?: number;\n explanation?: string;\n}\n\nexport interface BuiCreateSkillInput {\n name: string;\n category?: BuiSkillCategory;\n description?: string;\n}\n\nexport interface BuiCreateCohortInput {\n courseId: string;\n name: string;\n capacity?: number;\n facilitatorId?: string;\n startDate?: string;\n endDate?: string;\n}\n\nexport interface BuiEnrollInput {\n courseId: string;\n learnerId?: string;\n cohortId?: string;\n expiresAt?: string;\n}\n\nexport interface BuiRecordLessonProgressInput {\n enrollmentId: string;\n lessonId: string;\n secondsSpent?: number;\n status?: BuiProgressStatus;\n}\n\nexport interface BuiSubmitAssessmentInput {\n assessmentId: string;\n learnerId?: string;\n enrollmentId?: string;\n attempt?: number;\n answers?: unknown;\n}\n\nexport interface BuiGradeSubmissionInput {\n score: number;\n passed?: boolean;\n feedback?: string;\n}\n\nexport interface BuiIssueCertificateInput {\n courseId: string;\n learnerId: string;\n enrollmentId?: string;\n serial: string;\n finalScore?: number;\n expiresAt?: string;\n fileId?: string;\n}\n\n// ============================================================================\n// Convenience option lists (for select controls in authoring UIs)\n// ============================================================================\n\nexport const COURSE_LEVELS: BuiCourseLevel[] = ['BEGINNER', 'INTERMEDIATE', 'ADVANCED', 'EXPERT'];\nexport const COURSE_STATUSES: BuiCourseStatus[] = ['DRAFT', 'IN_REVIEW', 'PUBLISHED', 'ARCHIVED'];\nexport const LESSON_TYPES: BuiLessonType[] = [\n 'ARTICLE',\n 'VIDEO',\n 'QUIZ',\n 'ASSIGNMENT',\n 'INTERACTIVE',\n 'LIVE_SESSION',\n];\nexport const ASSESSMENT_TYPES: BuiAssessmentType[] = [\n 'QUIZ',\n 'EXAM',\n 'ASSIGNMENT',\n 'PRACTICAL',\n 'SURVEY',\n];\nexport const QUESTION_TYPES: BuiQuestionType[] = [\n 'SINGLE_CHOICE',\n 'MULTIPLE_CHOICE',\n 'TRUE_FALSE',\n 'SHORT_ANSWER',\n 'ESSAY',\n 'CODE',\n];\nexport const SKILL_CATEGORIES: BuiSkillCategory[] = [\n 'TECHNICAL',\n 'BUSINESS',\n 'CREATIVE',\n 'COGNITIVE',\n 'SOCIAL',\n 'LANGUAGE',\n];\nexport const ENROLLMENT_STATUSES: BuiEnrollmentStatus[] = [\n 'ENROLLED',\n 'IN_PROGRESS',\n 'COMPLETED',\n 'DROPPED',\n 'EXPIRED',\n];\nexport const COHORT_STATUSES: BuiCohortStatus[] = [\n 'SCHEDULED',\n 'ENROLLING',\n 'ACTIVE',\n 'COMPLETED',\n 'CANCELLED',\n];\nexport const SUBMISSION_STATUSES: BuiSubmissionStatus[] = [\n 'IN_PROGRESS',\n 'SUBMITTED',\n 'GRADING',\n 'GRADED',\n 'RETURNED',\n];\n"],"mappings":";AA8dA,IAAa,IAAkC;CAAC;CAAY;CAAgB;CAAY;CAAS,EAEpF,IAAgC;CAC3C;CACA;CACA;CACA;CACA;CACA;CACD,EACY,IAAwC;CACnD;CACA;CACA;CACA;CACA;CACD,EACY,IAAoC;CAC/C;CACA;CACA;CACA;CACA;CACA;CACD,EACY,IAAuC;CAClD;CACA;CACA;CACA;CACA;CACA;CACD,EAQY,IAAqC;CAChD;CACA;CACA;CACA;CACA;CACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-buildmyiq",
3
- "version": "2026.705.3",
3
+ "version": "2026.705.5",
4
4
  "description": "Burdenoff BuildMyIQ Microfrontend — education, learning & development",
5
5
  "type": "module",
6
6
  "files": [