@things-factory/learning 10.1.264 → 10.1.266
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.
|
@@ -242,11 +242,11 @@ let LearningView = class LearningView extends localize(i18next)(PageView) {
|
|
|
242
242
|
${one.units.map((row) => html `<li>
|
|
243
243
|
<button
|
|
244
244
|
aria-current=${row.unit.id === this.unitId ? 'true' : 'false'}
|
|
245
|
-
aria-label=${`${row.unit.
|
|
245
|
+
aria-label=${`${row.unit.name}, ${unitKindWord(row.unit.kind)}${row.progress?.doneAt ? `, ${t('text.learning-unit-done')}` : ''}`}
|
|
246
246
|
@click=${() => this.open(row.unit.id)}
|
|
247
247
|
>
|
|
248
248
|
<md-icon ?done=${!!row.progress?.doneAt} aria-hidden="true">${row.progress?.doneAt ? 'check_circle' : row.counts ? 'radio_button_unchecked' : 'link'}</md-icon>
|
|
249
|
-
<span class="name" aria-hidden="true">${row.unit.
|
|
249
|
+
<span class="name" aria-hidden="true">${row.unit.name}</span>
|
|
250
250
|
<span class="kind" aria-hidden="true">${unitKindWord(row.unit.kind)}</span>
|
|
251
251
|
</button>
|
|
252
252
|
</li>`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learning-view.js","sourceRoot":"","sources":["../../client/pages/learning-view.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/learning/ox-learning-progress.js'\nimport '@operato/learning/ox-lesson.js'\nimport '@operato/learning/ox-quiz.js'\nimport '@operato/list-state/ox-page-state.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\n\nimport { MutationController, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport type { InkStroke, LessonNotes, LessonTick, QuizAnswers, QuizQuestion } from '@operato/learning'\nimport { PageView } from '@operato/shell'\nimport { DocumentPageStyles } from '@operato/styles'\nimport { issueDocument } from '@things-factory/pdf/dist-client'\n\nimport { LEARNING_FIELDS, LessonStarts, pageLookedOf, PROGRESS_FIELDS, resumeUnitId, unitsDoneOf } from '../utils/learning-api.js'\nimport { dayOf, minutesOf, missingWord, stateWord, t, unitKindWord } from '../utils/learning-words.js'\n\nconst TICK_MUTATION = `mutation ($enrollmentId: String!, $unitId: String!, $seconds: Int!, $position: Int!) {\n recordLearningTick(enrollmentId: $enrollmentId, unitId: $unitId, seconds: $seconds, position: $position) {\n enrollment { id status }\n progress { ${PROGRESS_FIELDS} }\n }\n}`\n\n/**\n * 과정 화면 (ADR-0194 decisions 3-9) - one enrolment: the units in order with the one open played by `ox-lesson`, whose\n * ticks go to the server as they come (the server counts the time); the quiz drawn by the server and scored there; the\n * acknowledgement; and the certificate once completed. On a phone the unit list sits above the lesson.\n */\n@customElement('learning-view')\nexport class LearningView extends localize(i18next)(PageView) {\n static styles = [\n DocumentPageStyles,\n css`\n .head {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small, 4px);\n }\n .head h2 {\n margin: 0;\n font-size: var(--ui-t-title-large, 22px);\n overflow-wrap: anywhere;\n }\n .meta {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n color: var(--ui-muted);\n font-size: var(--ui-t-small, 12px);\n }\n .study {\n display: grid;\n grid-template-columns: minmax(200px, 280px) minmax(0, 1fr);\n gap: var(--spacing-large, 12px);\n align-items: start;\n }\n @media (max-width: 760px) {\n .study {\n grid-template-columns: minmax(0, 1fr);\n }\n }\n ol.units {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n ol.units button {\n display: flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n width: 100%;\n min-height: 40px;\n padding: 6px 8px;\n border: 0;\n border-radius: var(--ui-r-sm, 6px);\n background: transparent;\n color: var(--ui-ink);\n font: inherit;\n text-align: left;\n cursor: pointer;\n }\n ol.units button[aria-current='true'] {\n background: var(--ui-line-soft, var(--md-sys-color-surface-container));\n font-weight: 600;\n }\n ol.units button:focus-visible {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: -2px;\n }\n ol.units md-icon {\n --md-icon-size: 18px;\n color: var(--ui-muted);\n flex: none;\n }\n ol.units md-icon[done] {\n color: var(--ui-ok, var(--md-sys-color-primary));\n }\n ol.units .name {\n flex: 1;\n min-width: 0;\n overflow-wrap: anywhere;\n }\n ol.units .kind {\n color: var(--ui-muted);\n font-size: var(--ui-t-small, 12px);\n }\n .lesson {\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n .lesson h3 {\n margin: 0;\n font-size: var(--ui-t-title, 15px);\n }\n .error {\n color: var(--ui-crit, var(--md-sys-color-error));\n font-size: var(--ui-t-small, 12px);\n }\n .check {\n display: flex;\n align-items: flex-start;\n gap: var(--spacing-small, 4px);\n line-height: 1.6;\n }\n .acknowledgement {\n white-space: pre-wrap;\n margin: 0;\n line-height: 1.6;\n }\n .saved {\n margin: 0;\n min-height: 1.4em;\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ui-t-small, 12px);\n }\n .result {\n margin: 0;\n font-weight: 600;\n }\n `\n ]\n\n @state() private enrollmentId = ''\n @state() private unitId = ''\n @state() private drawn?: { attemptId: string; questions: QuizQuestion[] }\n @state() private result?: { score: number; passed: boolean; attemptsLeft?: number | null }\n @state() private agreed = false\n @state() private tickError = ''\n /* While one lesson leaves for another, nothing is shown - the leaving one's last tick is answered first. */\n @state() private switching = false\n\n private read = new QueryController(this, gql`query ($id: String!) { myEnrollment(id: $id) { ${LEARNING_FIELDS} } }`, {\n variables: () => (this.enrollmentId ? { id: this.enrollmentId } : undefined),\n keepPrevious: true\n })\n\n @state() private savedAt?: Date\n /** The notes of the PDF unit open, as written here since they were read (ADR-0194 amendment 2) - keyed by enrolment and unit. */\n @state() private written?: { key: string; pages: LessonNotes }\n @state() private noteError = ''\n\n /* A PDF unit's notes - read when it opens, the learner's own. Never from the cache: a note written is not put there. */\n private noteRead = new QueryController(this, gql`query ($enrollmentId: String!, $unitId: String!) { myLessonNotes(enrollmentId: $enrollmentId, unitId: $unitId) { page strokes } }`, {\n variables: () => {\n const unit = this.enrollment?.units?.find((row: any) => row.unit.id === this.unitId)?.unit\n return unit?.kind === 'PDF' && !this.switching ? { enrollmentId: this.enrollmentId, unitId: unit.id } : undefined\n },\n fetchPolicy: 'network-only'\n })\n private noteSave = new MutationController(\n this,\n gql`mutation ($enrollmentId: String!, $unitId: String!, $page: Int!, $strokes: Object!) { saveLessonNote(enrollmentId: $enrollmentId, unitId: $unitId, page: $page, strokes: $strokes) { id updatedAt } }`,\n { showsError: true }\n )\n /* Notes go one after another, each the page's whole strokes - the last written is the one kept. */\n private noteSaves: Promise<unknown> = Promise.resolve()\n\n private tickSave = new MutationController(this, gql(TICK_MUTATION), { showsError: true })\n private quizStart = new MutationController(this, gql`mutation ($enrollmentId: String!) { startQuizAttempt(enrollmentId: $enrollmentId) { attemptId questions { id kind text choices { id text } } } }`, {\n showsError: true\n })\n private quizSubmit = new MutationController(this, gql`mutation ($attemptId: String!, $answers: Object!) { submitQuizAttempt(attemptId: $attemptId, answers: $answers) { score passed attemptsLeft enrollment { id status } } }`, {\n refetch: () => [this.read],\n showsError: true\n })\n private acknowledgement = new MutationController(this, gql`mutation ($id: String!) { acknowledgeEnrollment(id: $id) { id status } }`, { refetch: () => [this.read], showsError: true })\n\n /*\n * Ticks go one after another - the leaving one too - so the server takes them in the order they were looked at: a\n * stop right after a start is not dropped while the start is out, and a page left on is never overtaken by an older one.\n */\n private ticks: Promise<unknown> = Promise.resolve()\n /** Where each lesson starts - the server's last answer for its unit, else what the page read (LessonStarts). */\n private starts = new LessonStarts()\n\n get enrollment(): any {\n return this.read.data?.myEnrollment ?? null\n }\n\n get context() {\n /* The enrolment is the dock's subject - a question on the course is answered from its own version's units (ADR-0194 decision 12). */\n return { title: t('title.learning-learning'), frame: 'document', menu: 'my-learning', ...(this.enrollmentId ? { subject: { type: 'enrollment', id: this.enrollmentId } } : {}) }\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (!this.active || !(changes.active || changes.params)) return\n const id = lifecycle?.params?.id\n if (id && id !== this.enrollmentId) {\n this.enrollmentId = id\n this.unitId = ''\n this.written = undefined\n this.drawn = undefined\n this.result = undefined\n }\n }\n\n updated() {\n const one = this.enrollment\n if (one && !this.unitId && one.units?.length) {\n /* Where the learner was - the unit learned last (resumeUnitId). */\n this.unitId = resumeUnitId(one)\n }\n }\n\n render() {\n const one = this.enrollment\n return html`<ox-page-state .loading=${this.read.loading && !one} .error=${this.read.error} .held=${!!one} .answeredAt=${this.read.answeredAt} @retry=${() => this.read.refetch()}>\n ${one ? this.renderEnrollment(one) : nothing}\n </ox-page-state>`\n }\n\n private renderEnrollment(one: any) {\n const { done, total } = unitsDoneOf(one.units)\n const current = one.units.find((row: any) => row.unit.id === this.unitId)\n const completed = one.status === 'COMPLETED'\n return html`<div class=\"page\">\n <section class=\"page-section head\">\n <h2>${one.course.name}</h2>\n <div class=\"meta\">\n <span>${stateWord(one.state)}</span>\n ${one.version ? html`<span>${t('text.learning-version-number', { number: one.version.number })}</span>` : nothing}\n ${one.dueOn ? html`<span>${t('text.learning-due-on', { day: one.dueOn })}</span>` : nothing}\n <span>${t('text.learning-learned-minutes', { minutes: minutesOf(one.learnedSeconds), required: minutesOf(one.version?.minSeconds) })}</span>\n </div>\n <ox-learning-progress .value=${done} .max=${total} ?done=${completed} label=${t('label.learning-units-done')}></ox-learning-progress>\n ${!completed && one.missing?.length ? html`<p class=\"page-section-note\">${t('text.learning-missing-lead')} ${one.missing.map(missingWord).join(' · ')}</p>` : nothing}\n ${one.course.description ? html`<p class=\"page-section-note\">${one.course.description}</p>` : nothing}\n </section>\n\n <section class=\"page-section study\">\n <nav aria-label=${t('label.learning-units')}>\n <ol class=\"units\">\n ${one.units.map(\n (row: any) => html`<li>\n <button\n aria-current=${row.unit.id === this.unitId ? 'true' : 'false'}\n aria-label=${`${row.unit.seq}. ${row.unit.name}, ${unitKindWord(row.unit.kind)}${row.progress?.doneAt ? `, ${t('text.learning-unit-done')}` : ''}`}\n @click=${() => this.open(row.unit.id)}\n >\n <md-icon ?done=${!!row.progress?.doneAt} aria-hidden=\"true\">${row.progress?.doneAt ? 'check_circle' : row.counts ? 'radio_button_unchecked' : 'link'}</md-icon>\n <span class=\"name\" aria-hidden=\"true\">${row.unit.seq}. ${row.unit.name}</span>\n <span class=\"kind\" aria-hidden=\"true\">${unitKindWord(row.unit.kind)}</span>\n </button>\n </li>`\n )}\n </ol>\n </nav>\n <div class=\"lesson\">${current ? this.renderLesson(one, current) : nothing}</div>\n </section>\n\n ${one.quizSize > 0 ? this.renderQuiz(one) : nothing}\n ${one.version?.acknowledgement ? this.renderAcknowledgement(one) : nothing}\n ${completed\n ? html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${t('title.learning-certificate')}</h3></header>\n <p class=\"page-section-note\">${t('text.learning-completed-detail', { day: dayOf(one.completedAt), number: one.certificateNo ?? '' })}</p>\n <md-filled-button style=\"align-self:flex-start\" @click=${() => issueDocument({ kind: 'learning.certificate', refId: one.id })}>${t('button.learning-certificate')}</md-filled-button>\n </section>`\n : nothing}\n </div>`\n }\n\n private renderLesson(one: any, row: any) {\n const unit = row.unit\n if (this.switching) return html`<h3>${unit.name}</h3>`\n const progress = unit.kind === 'LINK' ? {} : this.starts.startOf(one.id, unit.id, row.progress)\n if (unit.kind === 'LINK')\n return html`<h3>${unit.name}</h3>\n <p class=\"page-section-note\">${t('text.learning-link-not-counted')}</p>\n <a href=${unit.url} target=\"_blank\" rel=\"noopener noreferrer\">${unit.url}</a>`\n /*\n * One element per enrolment and unit: leaving one, its element says its own time to its own enrolment and unit -\n * never under the next. Keyed by the unit alone, the same unit opened from another enrolment kept the element and\n * its clock, and the first enrolment's seconds went out under the second (2026-11-08).\n */\n /* A PDF's notes, once read - until then nothing is written, so a stroke never replaces a page not read yet. */\n const notes = unit.kind === 'PDF' ? this.notesOf(one.id, unit.id) : undefined\n return html`<h3>${unit.name}</h3>\n ${keyed(\n `${one.id}:${unit.id}`,\n html`<ox-lesson\n .kind=${unit.kind}\n .src=${unit.file?.fullpath}\n .body=${unit.body ?? ''}\n .label=${unit.name}\n .watched=${unit.kind === 'PDF' ? (progress.pagesRead ?? 0) : (progress.watchedSeconds ?? 0)}\n .position=${unit.kind === 'PDF' ? (progress.pageAt ?? 0) : (progress.positionSeconds ?? 0)}\n .pages=${unit.pageCount ?? 0}\n .pageSeconds=${unit.secondsPerPage ?? undefined}\n .pageLooked=${unit.kind === 'PDF' ? pageLookedOf(progress) : 0}\n .requiredSeconds=${unit.minSeconds ?? 60}\n .learnedSeconds=${progress.learnedSeconds ?? 0}\n .done=${!!row.progress?.doneAt || !!progress.doneAt || one.status === 'COMPLETED'}\n .notes=${notes ?? {}}\n ?noting=${!!notes && one.status !== 'CANCELLED'}\n @lesson-tick=${(e: CustomEvent<LessonTick>) => this.tick(one.id, unit.id, e.detail)}\n @lesson-note=${(e: CustomEvent<{ page: number; strokes: InkStroke[] }>) => this.note(one.id, unit.id, e.detail)}\n ></ox-lesson>`\n )}\n ${this.tickError || this.noteError\n ? html`<div class=\"error\" role=\"alert\">${this.tickError || this.noteError}</div>`\n : html`<p class=\"saved\" role=\"status\">${this.savedAt ? t('text.learning-saved-at', { time: this.savedAt.toLocaleTimeString(i18next.language) }) : ''}</p>`}`\n }\n\n private renderQuiz(one: any) {\n const completed = one.status === 'COMPLETED'\n const passed = one.score != null && one.version?.passScore != null && one.score >= one.version.passScore\n return html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${t('title.learning-quiz')}</h3></header>\n <p class=\"page-section-note\">\n ${t('text.learning-quiz-rule', { count: one.quizSize, pass: one.version.passScore })}\n ${one.attemptsLeft != null ? t('text.learning-attempts-left', { count: one.attemptsLeft }) : ''}\n ${one.score != null ? t('text.learning-best-score', { score: one.score }) : ''}\n </p>\n ${this.result\n ? html`<p class=\"result\" role=\"status\">${this.result.passed ? t('text.learning-quiz-passed', { score: this.result.score }) : t('text.learning-quiz-failed', { score: this.result.score })}</p>`\n : nothing}\n ${this.drawn\n ? html`<ox-quiz .questions=${this.drawn.questions} .busy=${this.quizSubmit.pending} @quiz-submit=${(e: CustomEvent<{ answers: QuizAnswers }>) => this.submit(e.detail.answers)}></ox-quiz>`\n : !completed && !passed && one.attemptsLeft !== 0\n ? html`<md-filled-button style=\"align-self:flex-start\" ?disabled=${this.quizStart.pending} @click=${() => this.startQuiz(one.id)}>${t('button.learning-quiz-start')}</md-filled-button>`\n : nothing}\n ${this.quizStart.error || this.quizSubmit.error ? html`<div class=\"error\" role=\"alert\">${this.errorText(this.quizStart.error || this.quizSubmit.error)}</div>` : nothing}\n </section>`\n }\n\n private renderAcknowledgement(one: any) {\n return html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${t('title.learning-acknowledgement')}</h3></header>\n <p class=\"acknowledgement\">${one.version.acknowledgement}</p>\n ${one.acknowledgedAt\n ? html`<p class=\"page-section-note\">${t('text.learning-acknowledged-on', { day: dayOf(one.acknowledgedAt) })}</p>`\n : html`<label class=\"check\"><input type=\"checkbox\" .checked=${this.agreed} @change=${(e: any) => (this.agreed = e.target.checked)} />${t('text.learning-acknowledge-label')}</label>\n <md-filled-button style=\"align-self:flex-start\" ?disabled=${!this.agreed || this.acknowledgement.pending} @click=${() => this.acknowledgement.run({ id: one.id })}\n >${t('button.learning-acknowledge')}</md-filled-button\n >\n ${this.acknowledgement.error ? html`<div class=\"error\" role=\"alert\">${this.errorText(this.acknowledgement.error)}</div>` : nothing}`}\n </section>`\n }\n\n /**\n * Opens a unit. The lesson shown leaves first and its last tick is answered, so the unit opened - the same one coming\n * back too - starts from what the server counted, not from what the page read when it opened (2026-11-08).\n */\n private async open(unitId: string) {\n if (unitId === this.unitId || this.switching) return\n this.tickError = ''\n this.noteError = ''\n this.switching = true\n await this.updateComplete\n await this.ticks\n await this.noteSaves\n this.starts.reopen()\n this.written = undefined\n this.unitId = unitId\n this.switching = false\n }\n\n /** The notes of a PDF unit by page: as written here, else as read - undefined while they are read. */\n private notesOf(enrollmentId: string, unitId: string): LessonNotes | undefined {\n const key = `${enrollmentId}:${unitId}`\n if (this.written?.key === key) return this.written.pages\n const rows = this.noteRead.data?.myLessonNotes\n if (!rows) return undefined\n return Object.fromEntries(rows.map((row: any) => [row.page, row.strokes ?? []]))\n }\n\n /** A page's notes changed - kept here at once and sent, one after another. */\n private note(enrollmentId: string, unitId: string, { page, strokes }: { page: number; strokes: InkStroke[] }) {\n const key = `${enrollmentId}:${unitId}`\n const pages = this.notesOf(enrollmentId, unitId) ?? {}\n this.written = { key, pages: { ...pages, [page]: strokes } }\n this.noteSaves = this.noteSaves.then(async () => {\n const answer = await this.noteSave.run({ enrollmentId, unitId, page, strokes })\n if (!answer) {\n this.noteError = this.errorText(this.noteSave.error)\n return\n }\n this.noteError = ''\n this.savedAt = new Date()\n })\n }\n\n /** Keeps the server's answer for a unit - the next time it opens, it starts there. */\n private keep(enrollmentId: string, unitId: string, answer: any) {\n this.starts.keep(enrollmentId, unitId, answer?.progress)\n this.savedAt = new Date()\n }\n\n private tick(enrollmentId: string, unitId: string, detail: LessonTick) {\n const variables = { enrollmentId, unitId, seconds: Math.round(detail.seconds), position: Math.floor(detail.position) }\n /*\n * Leaving - the tab hidden, closed or reloaded - the last piece goes out on a request the browser finishes after the\n * page is gone (keepalive). Through the usual queue it was dropped with the page, and up to a tick was lost.\n */\n if (document.visibilityState === 'hidden') {\n this.ticks = this.ticks.then(() => this.tickLeaving(variables))\n return\n }\n this.ticks = this.ticks.then(async () => {\n const before = this.enrollment\n const answer = await this.tickSave.run(variables)\n if (!answer) {\n this.tickError = this.errorText(this.tickSave.error)\n await this.read.refetch()\n return\n }\n this.tickError = ''\n this.keep(enrollmentId, unitId, answer.recordLearningTick)\n const row = before?.units?.find((one: any) => one.unit.id === unitId)\n const newlyDone = !!answer.recordLearningTick.progress.doneAt && !row?.progress?.doneAt\n if (newlyDone || answer.recordLearningTick.enrollment.status !== before?.status) await this.read.refetch()\n })\n }\n\n /*\n * The leaving tick goes after the ticks before it, on a request the browser finishes after the page is gone\n * (keepalive). Only when the page is closed while an earlier tick is still out is it not sent - the order is kept.\n */\n private async tickLeaving(variables: { enrollmentId: string; unitId: string }) {\n await fetch('/graphql', {\n method: 'POST',\n keepalive: true,\n credentials: 'include',\n headers: { 'Content-Type': 'application/json', 'Apollo-Require-Preflight': 'true' },\n body: JSON.stringify({ query: TICK_MUTATION, variables })\n })\n .then(response => response.json())\n .then(answer => {\n if (answer?.data?.recordLearningTick) this.keep(variables.enrollmentId, variables.unitId, answer.data.recordLearningTick)\n else this.tickError = answer?.errors?.[0]?.message ?? ''\n })\n .catch(error => (this.tickError = error?.message ?? String(error)))\n }\n\n private async startQuiz(enrollmentId: string) {\n this.result = undefined\n const answer = await this.quizStart.run({ enrollmentId })\n if (answer) this.drawn = answer.startQuizAttempt\n }\n\n private async submit(answers: QuizAnswers) {\n if (!this.drawn) return\n const answer = await this.quizSubmit.run({ attemptId: this.drawn.attemptId, answers })\n if (!answer) return\n this.result = answer.submitQuizAttempt\n this.drawn = undefined\n }\n\n private errorText(error: any): string {\n return error?.graphQLErrors?.[0]?.message ?? error?.message ?? ''\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"learning-view.js","sourceRoot":"","sources":["../../client/pages/learning-view.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/learning/ox-learning-progress.js'\nimport '@operato/learning/ox-lesson.js'\nimport '@operato/learning/ox-quiz.js'\nimport '@operato/list-state/ox-page-state.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, nothing } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\n\nimport { MutationController, QueryController } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport type { InkStroke, LessonNotes, LessonTick, QuizAnswers, QuizQuestion } from '@operato/learning'\nimport { PageView } from '@operato/shell'\nimport { DocumentPageStyles } from '@operato/styles'\nimport { issueDocument } from '@things-factory/pdf/dist-client'\n\nimport { LEARNING_FIELDS, LessonStarts, pageLookedOf, PROGRESS_FIELDS, resumeUnitId, unitsDoneOf } from '../utils/learning-api.js'\nimport { dayOf, minutesOf, missingWord, stateWord, t, unitKindWord } from '../utils/learning-words.js'\n\nconst TICK_MUTATION = `mutation ($enrollmentId: String!, $unitId: String!, $seconds: Int!, $position: Int!) {\n recordLearningTick(enrollmentId: $enrollmentId, unitId: $unitId, seconds: $seconds, position: $position) {\n enrollment { id status }\n progress { ${PROGRESS_FIELDS} }\n }\n}`\n\n/**\n * 과정 화면 (ADR-0194 decisions 3-9) - one enrolment: the units in order with the one open played by `ox-lesson`, whose\n * ticks go to the server as they come (the server counts the time); the quiz drawn by the server and scored there; the\n * acknowledgement; and the certificate once completed. On a phone the unit list sits above the lesson.\n */\n@customElement('learning-view')\nexport class LearningView extends localize(i18next)(PageView) {\n static styles = [\n DocumentPageStyles,\n css`\n .head {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small, 4px);\n }\n .head h2 {\n margin: 0;\n font-size: var(--ui-t-title-large, 22px);\n overflow-wrap: anywhere;\n }\n .meta {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);\n color: var(--ui-muted);\n font-size: var(--ui-t-small, 12px);\n }\n .study {\n display: grid;\n grid-template-columns: minmax(200px, 280px) minmax(0, 1fr);\n gap: var(--spacing-large, 12px);\n align-items: start;\n }\n @media (max-width: 760px) {\n .study {\n grid-template-columns: minmax(0, 1fr);\n }\n }\n ol.units {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n ol.units button {\n display: flex;\n align-items: center;\n gap: var(--spacing-small, 4px);\n width: 100%;\n min-height: 40px;\n padding: 6px 8px;\n border: 0;\n border-radius: var(--ui-r-sm, 6px);\n background: transparent;\n color: var(--ui-ink);\n font: inherit;\n text-align: left;\n cursor: pointer;\n }\n ol.units button[aria-current='true'] {\n background: var(--ui-line-soft, var(--md-sys-color-surface-container));\n font-weight: 600;\n }\n ol.units button:focus-visible {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: -2px;\n }\n ol.units md-icon {\n --md-icon-size: 18px;\n color: var(--ui-muted);\n flex: none;\n }\n ol.units md-icon[done] {\n color: var(--ui-ok, var(--md-sys-color-primary));\n }\n ol.units .name {\n flex: 1;\n min-width: 0;\n overflow-wrap: anywhere;\n }\n ol.units .kind {\n color: var(--ui-muted);\n font-size: var(--ui-t-small, 12px);\n }\n .lesson {\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n }\n .lesson h3 {\n margin: 0;\n font-size: var(--ui-t-title, 15px);\n }\n .error {\n color: var(--ui-crit, var(--md-sys-color-error));\n font-size: var(--ui-t-small, 12px);\n }\n .check {\n display: flex;\n align-items: flex-start;\n gap: var(--spacing-small, 4px);\n line-height: 1.6;\n }\n .acknowledgement {\n white-space: pre-wrap;\n margin: 0;\n line-height: 1.6;\n }\n .saved {\n margin: 0;\n min-height: 1.4em;\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ui-t-small, 12px);\n }\n .result {\n margin: 0;\n font-weight: 600;\n }\n `\n ]\n\n @state() private enrollmentId = ''\n @state() private unitId = ''\n @state() private drawn?: { attemptId: string; questions: QuizQuestion[] }\n @state() private result?: { score: number; passed: boolean; attemptsLeft?: number | null }\n @state() private agreed = false\n @state() private tickError = ''\n /* While one lesson leaves for another, nothing is shown - the leaving one's last tick is answered first. */\n @state() private switching = false\n\n private read = new QueryController(this, gql`query ($id: String!) { myEnrollment(id: $id) { ${LEARNING_FIELDS} } }`, {\n variables: () => (this.enrollmentId ? { id: this.enrollmentId } : undefined),\n keepPrevious: true\n })\n\n @state() private savedAt?: Date\n /** The notes of the PDF unit open, as written here since they were read (ADR-0194 amendment 2) - keyed by enrolment and unit. */\n @state() private written?: { key: string; pages: LessonNotes }\n @state() private noteError = ''\n\n /* A PDF unit's notes - read when it opens, the learner's own. Never from the cache: a note written is not put there. */\n private noteRead = new QueryController(this, gql`query ($enrollmentId: String!, $unitId: String!) { myLessonNotes(enrollmentId: $enrollmentId, unitId: $unitId) { page strokes } }`, {\n variables: () => {\n const unit = this.enrollment?.units?.find((row: any) => row.unit.id === this.unitId)?.unit\n return unit?.kind === 'PDF' && !this.switching ? { enrollmentId: this.enrollmentId, unitId: unit.id } : undefined\n },\n fetchPolicy: 'network-only'\n })\n private noteSave = new MutationController(\n this,\n gql`mutation ($enrollmentId: String!, $unitId: String!, $page: Int!, $strokes: Object!) { saveLessonNote(enrollmentId: $enrollmentId, unitId: $unitId, page: $page, strokes: $strokes) { id updatedAt } }`,\n { showsError: true }\n )\n /* Notes go one after another, each the page's whole strokes - the last written is the one kept. */\n private noteSaves: Promise<unknown> = Promise.resolve()\n\n private tickSave = new MutationController(this, gql(TICK_MUTATION), { showsError: true })\n private quizStart = new MutationController(this, gql`mutation ($enrollmentId: String!) { startQuizAttempt(enrollmentId: $enrollmentId) { attemptId questions { id kind text choices { id text } } } }`, {\n showsError: true\n })\n private quizSubmit = new MutationController(this, gql`mutation ($attemptId: String!, $answers: Object!) { submitQuizAttempt(attemptId: $attemptId, answers: $answers) { score passed attemptsLeft enrollment { id status } } }`, {\n refetch: () => [this.read],\n showsError: true\n })\n private acknowledgement = new MutationController(this, gql`mutation ($id: String!) { acknowledgeEnrollment(id: $id) { id status } }`, { refetch: () => [this.read], showsError: true })\n\n /*\n * Ticks go one after another - the leaving one too - so the server takes them in the order they were looked at: a\n * stop right after a start is not dropped while the start is out, and a page left on is never overtaken by an older one.\n */\n private ticks: Promise<unknown> = Promise.resolve()\n /** Where each lesson starts - the server's last answer for its unit, else what the page read (LessonStarts). */\n private starts = new LessonStarts()\n\n get enrollment(): any {\n return this.read.data?.myEnrollment ?? null\n }\n\n get context() {\n /* The enrolment is the dock's subject - a question on the course is answered from its own version's units (ADR-0194 decision 12). */\n return { title: t('title.learning-learning'), frame: 'document', menu: 'my-learning', ...(this.enrollmentId ? { subject: { type: 'enrollment', id: this.enrollmentId } } : {}) }\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (!this.active || !(changes.active || changes.params)) return\n const id = lifecycle?.params?.id\n if (id && id !== this.enrollmentId) {\n this.enrollmentId = id\n this.unitId = ''\n this.written = undefined\n this.drawn = undefined\n this.result = undefined\n }\n }\n\n updated() {\n const one = this.enrollment\n if (one && !this.unitId && one.units?.length) {\n /* Where the learner was - the unit learned last (resumeUnitId). */\n this.unitId = resumeUnitId(one)\n }\n }\n\n render() {\n const one = this.enrollment\n return html`<ox-page-state .loading=${this.read.loading && !one} .error=${this.read.error} .held=${!!one} .answeredAt=${this.read.answeredAt} @retry=${() => this.read.refetch()}>\n ${one ? this.renderEnrollment(one) : nothing}\n </ox-page-state>`\n }\n\n private renderEnrollment(one: any) {\n const { done, total } = unitsDoneOf(one.units)\n const current = one.units.find((row: any) => row.unit.id === this.unitId)\n const completed = one.status === 'COMPLETED'\n return html`<div class=\"page\">\n <section class=\"page-section head\">\n <h2>${one.course.name}</h2>\n <div class=\"meta\">\n <span>${stateWord(one.state)}</span>\n ${one.version ? html`<span>${t('text.learning-version-number', { number: one.version.number })}</span>` : nothing}\n ${one.dueOn ? html`<span>${t('text.learning-due-on', { day: one.dueOn })}</span>` : nothing}\n <span>${t('text.learning-learned-minutes', { minutes: minutesOf(one.learnedSeconds), required: minutesOf(one.version?.minSeconds) })}</span>\n </div>\n <ox-learning-progress .value=${done} .max=${total} ?done=${completed} label=${t('label.learning-units-done')}></ox-learning-progress>\n ${!completed && one.missing?.length ? html`<p class=\"page-section-note\">${t('text.learning-missing-lead')} ${one.missing.map(missingWord).join(' · ')}</p>` : nothing}\n ${one.course.description ? html`<p class=\"page-section-note\">${one.course.description}</p>` : nothing}\n </section>\n\n <section class=\"page-section study\">\n <nav aria-label=${t('label.learning-units')}>\n <ol class=\"units\">\n ${one.units.map(\n (row: any) => html`<li>\n <button\n aria-current=${row.unit.id === this.unitId ? 'true' : 'false'}\n aria-label=${`${row.unit.name}, ${unitKindWord(row.unit.kind)}${row.progress?.doneAt ? `, ${t('text.learning-unit-done')}` : ''}`}\n @click=${() => this.open(row.unit.id)}\n >\n <md-icon ?done=${!!row.progress?.doneAt} aria-hidden=\"true\">${row.progress?.doneAt ? 'check_circle' : row.counts ? 'radio_button_unchecked' : 'link'}</md-icon>\n <span class=\"name\" aria-hidden=\"true\">${row.unit.name}</span>\n <span class=\"kind\" aria-hidden=\"true\">${unitKindWord(row.unit.kind)}</span>\n </button>\n </li>`\n )}\n </ol>\n </nav>\n <div class=\"lesson\">${current ? this.renderLesson(one, current) : nothing}</div>\n </section>\n\n ${one.quizSize > 0 ? this.renderQuiz(one) : nothing}\n ${one.version?.acknowledgement ? this.renderAcknowledgement(one) : nothing}\n ${completed\n ? html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${t('title.learning-certificate')}</h3></header>\n <p class=\"page-section-note\">${t('text.learning-completed-detail', { day: dayOf(one.completedAt), number: one.certificateNo ?? '' })}</p>\n <md-filled-button style=\"align-self:flex-start\" @click=${() => issueDocument({ kind: 'learning.certificate', refId: one.id })}>${t('button.learning-certificate')}</md-filled-button>\n </section>`\n : nothing}\n </div>`\n }\n\n private renderLesson(one: any, row: any) {\n const unit = row.unit\n if (this.switching) return html`<h3>${unit.name}</h3>`\n const progress = unit.kind === 'LINK' ? {} : this.starts.startOf(one.id, unit.id, row.progress)\n if (unit.kind === 'LINK')\n return html`<h3>${unit.name}</h3>\n <p class=\"page-section-note\">${t('text.learning-link-not-counted')}</p>\n <a href=${unit.url} target=\"_blank\" rel=\"noopener noreferrer\">${unit.url}</a>`\n /*\n * One element per enrolment and unit: leaving one, its element says its own time to its own enrolment and unit -\n * never under the next. Keyed by the unit alone, the same unit opened from another enrolment kept the element and\n * its clock, and the first enrolment's seconds went out under the second (2026-11-08).\n */\n /* A PDF's notes, once read - until then nothing is written, so a stroke never replaces a page not read yet. */\n const notes = unit.kind === 'PDF' ? this.notesOf(one.id, unit.id) : undefined\n return html`<h3>${unit.name}</h3>\n ${keyed(\n `${one.id}:${unit.id}`,\n html`<ox-lesson\n .kind=${unit.kind}\n .src=${unit.file?.fullpath}\n .body=${unit.body ?? ''}\n .label=${unit.name}\n .watched=${unit.kind === 'PDF' ? (progress.pagesRead ?? 0) : (progress.watchedSeconds ?? 0)}\n .position=${unit.kind === 'PDF' ? (progress.pageAt ?? 0) : (progress.positionSeconds ?? 0)}\n .pages=${unit.pageCount ?? 0}\n .pageSeconds=${unit.secondsPerPage ?? undefined}\n .pageLooked=${unit.kind === 'PDF' ? pageLookedOf(progress) : 0}\n .requiredSeconds=${unit.minSeconds ?? 60}\n .learnedSeconds=${progress.learnedSeconds ?? 0}\n .done=${!!row.progress?.doneAt || !!progress.doneAt || one.status === 'COMPLETED'}\n .notes=${notes ?? {}}\n ?noting=${!!notes && one.status !== 'CANCELLED'}\n @lesson-tick=${(e: CustomEvent<LessonTick>) => this.tick(one.id, unit.id, e.detail)}\n @lesson-note=${(e: CustomEvent<{ page: number; strokes: InkStroke[] }>) => this.note(one.id, unit.id, e.detail)}\n ></ox-lesson>`\n )}\n ${this.tickError || this.noteError\n ? html`<div class=\"error\" role=\"alert\">${this.tickError || this.noteError}</div>`\n : html`<p class=\"saved\" role=\"status\">${this.savedAt ? t('text.learning-saved-at', { time: this.savedAt.toLocaleTimeString(i18next.language) }) : ''}</p>`}`\n }\n\n private renderQuiz(one: any) {\n const completed = one.status === 'COMPLETED'\n const passed = one.score != null && one.version?.passScore != null && one.score >= one.version.passScore\n return html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${t('title.learning-quiz')}</h3></header>\n <p class=\"page-section-note\">\n ${t('text.learning-quiz-rule', { count: one.quizSize, pass: one.version.passScore })}\n ${one.attemptsLeft != null ? t('text.learning-attempts-left', { count: one.attemptsLeft }) : ''}\n ${one.score != null ? t('text.learning-best-score', { score: one.score }) : ''}\n </p>\n ${this.result\n ? html`<p class=\"result\" role=\"status\">${this.result.passed ? t('text.learning-quiz-passed', { score: this.result.score }) : t('text.learning-quiz-failed', { score: this.result.score })}</p>`\n : nothing}\n ${this.drawn\n ? html`<ox-quiz .questions=${this.drawn.questions} .busy=${this.quizSubmit.pending} @quiz-submit=${(e: CustomEvent<{ answers: QuizAnswers }>) => this.submit(e.detail.answers)}></ox-quiz>`\n : !completed && !passed && one.attemptsLeft !== 0\n ? html`<md-filled-button style=\"align-self:flex-start\" ?disabled=${this.quizStart.pending} @click=${() => this.startQuiz(one.id)}>${t('button.learning-quiz-start')}</md-filled-button>`\n : nothing}\n ${this.quizStart.error || this.quizSubmit.error ? html`<div class=\"error\" role=\"alert\">${this.errorText(this.quizStart.error || this.quizSubmit.error)}</div>` : nothing}\n </section>`\n }\n\n private renderAcknowledgement(one: any) {\n return html`<section class=\"page-section\">\n <header class=\"page-section-header\"><h3>${t('title.learning-acknowledgement')}</h3></header>\n <p class=\"acknowledgement\">${one.version.acknowledgement}</p>\n ${one.acknowledgedAt\n ? html`<p class=\"page-section-note\">${t('text.learning-acknowledged-on', { day: dayOf(one.acknowledgedAt) })}</p>`\n : html`<label class=\"check\"><input type=\"checkbox\" .checked=${this.agreed} @change=${(e: any) => (this.agreed = e.target.checked)} />${t('text.learning-acknowledge-label')}</label>\n <md-filled-button style=\"align-self:flex-start\" ?disabled=${!this.agreed || this.acknowledgement.pending} @click=${() => this.acknowledgement.run({ id: one.id })}\n >${t('button.learning-acknowledge')}</md-filled-button\n >\n ${this.acknowledgement.error ? html`<div class=\"error\" role=\"alert\">${this.errorText(this.acknowledgement.error)}</div>` : nothing}`}\n </section>`\n }\n\n /**\n * Opens a unit. The lesson shown leaves first and its last tick is answered, so the unit opened - the same one coming\n * back too - starts from what the server counted, not from what the page read when it opened (2026-11-08).\n */\n private async open(unitId: string) {\n if (unitId === this.unitId || this.switching) return\n this.tickError = ''\n this.noteError = ''\n this.switching = true\n await this.updateComplete\n await this.ticks\n await this.noteSaves\n this.starts.reopen()\n this.written = undefined\n this.unitId = unitId\n this.switching = false\n }\n\n /** The notes of a PDF unit by page: as written here, else as read - undefined while they are read. */\n private notesOf(enrollmentId: string, unitId: string): LessonNotes | undefined {\n const key = `${enrollmentId}:${unitId}`\n if (this.written?.key === key) return this.written.pages\n const rows = this.noteRead.data?.myLessonNotes\n if (!rows) return undefined\n return Object.fromEntries(rows.map((row: any) => [row.page, row.strokes ?? []]))\n }\n\n /** A page's notes changed - kept here at once and sent, one after another. */\n private note(enrollmentId: string, unitId: string, { page, strokes }: { page: number; strokes: InkStroke[] }) {\n const key = `${enrollmentId}:${unitId}`\n const pages = this.notesOf(enrollmentId, unitId) ?? {}\n this.written = { key, pages: { ...pages, [page]: strokes } }\n this.noteSaves = this.noteSaves.then(async () => {\n const answer = await this.noteSave.run({ enrollmentId, unitId, page, strokes })\n if (!answer) {\n this.noteError = this.errorText(this.noteSave.error)\n return\n }\n this.noteError = ''\n this.savedAt = new Date()\n })\n }\n\n /** Keeps the server's answer for a unit - the next time it opens, it starts there. */\n private keep(enrollmentId: string, unitId: string, answer: any) {\n this.starts.keep(enrollmentId, unitId, answer?.progress)\n this.savedAt = new Date()\n }\n\n private tick(enrollmentId: string, unitId: string, detail: LessonTick) {\n const variables = { enrollmentId, unitId, seconds: Math.round(detail.seconds), position: Math.floor(detail.position) }\n /*\n * Leaving - the tab hidden, closed or reloaded - the last piece goes out on a request the browser finishes after the\n * page is gone (keepalive). Through the usual queue it was dropped with the page, and up to a tick was lost.\n */\n if (document.visibilityState === 'hidden') {\n this.ticks = this.ticks.then(() => this.tickLeaving(variables))\n return\n }\n this.ticks = this.ticks.then(async () => {\n const before = this.enrollment\n const answer = await this.tickSave.run(variables)\n if (!answer) {\n this.tickError = this.errorText(this.tickSave.error)\n await this.read.refetch()\n return\n }\n this.tickError = ''\n this.keep(enrollmentId, unitId, answer.recordLearningTick)\n const row = before?.units?.find((one: any) => one.unit.id === unitId)\n const newlyDone = !!answer.recordLearningTick.progress.doneAt && !row?.progress?.doneAt\n if (newlyDone || answer.recordLearningTick.enrollment.status !== before?.status) await this.read.refetch()\n })\n }\n\n /*\n * The leaving tick goes after the ticks before it, on a request the browser finishes after the page is gone\n * (keepalive). Only when the page is closed while an earlier tick is still out is it not sent - the order is kept.\n */\n private async tickLeaving(variables: { enrollmentId: string; unitId: string }) {\n await fetch('/graphql', {\n method: 'POST',\n keepalive: true,\n credentials: 'include',\n headers: { 'Content-Type': 'application/json', 'Apollo-Require-Preflight': 'true' },\n body: JSON.stringify({ query: TICK_MUTATION, variables })\n })\n .then(response => response.json())\n .then(answer => {\n if (answer?.data?.recordLearningTick) this.keep(variables.enrollmentId, variables.unitId, answer.data.recordLearningTick)\n else this.tickError = answer?.errors?.[0]?.message ?? ''\n })\n .catch(error => (this.tickError = error?.message ?? String(error)))\n }\n\n private async startQuiz(enrollmentId: string) {\n this.result = undefined\n const answer = await this.quizStart.run({ enrollmentId })\n if (answer) this.drawn = answer.startQuizAttempt\n }\n\n private async submit(answers: QuizAnswers) {\n if (!this.drawn) return\n const answer = await this.quizSubmit.run({ attemptId: this.drawn.attemptId, answers })\n if (!answer) return\n this.result = answer.submitQuizAttempt\n this.drawn = undefined\n }\n\n private errorText(error: any): string {\n return error?.graphQLErrors?.[0]?.message ?? error?.message ?? ''\n }\n}\n"]}
|