@tinyweb_dev/oe-exam-sdk 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/exam-entry.d.ts +1 -1
- package/dist/api/exam-entry.types.d.ts +14 -0
- package/dist/api/exam-taking.types.d.ts +2 -0
- package/dist/components/exams/take/ExamTakingPageContainer.js +1 -1
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +1 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.js +1 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +1 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingInfoExchangeRenderer.js +1 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingReadDisplayedContentRenderer.js +1 -1
- package/dist/components/exams/take/exam-taking.utils.d.ts +8 -2
- package/dist/components/exams/take/exam-taking.utils.js +1 -1
- package/dist/components/exams/take/utils/question-transformers.d.ts +4 -0
- package/dist/components/exams/take/utils/question-transformers.js +1 -1
- package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.js +1 -1
- package/dist/components/features/exam-entry/themed/cambridge-yle-waiting-parts.d.ts +18 -0
- package/dist/components/features/exam-entry/themed/cambridge-yle-waiting-parts.js +1 -0
- package/dist/components/features/exam-entry/themed/index.d.ts +3 -0
- package/dist/components/features/exam-entry/themed/index.js +1 -1
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.d.ts +2 -0
- package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -1
- package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -1
- package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -1
- package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -1
- package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -1
- package/dist/components/themes/english-certification/EcWritingTask.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.d.ts +17 -0
- package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.js +1 -0
- package/dist/components/themes/english-certification/EnglishCertificationPartHeader.d.ts +24 -0
- package/dist/components/themes/english-certification/EnglishCertificationPartHeader.js +1 -0
- package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.d.ts +3 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.d.ts +0 -2
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -1
- package/dist/components/themes/english-certification/english-cert-scroll.d.ts +32 -0
- package/dist/components/themes/english-certification/english-cert-scroll.js +1 -0
- package/dist/components/themes/english-certification/index.d.ts +4 -1
- package/dist/components/themes/english-certification/index.js +1 -1
- package/dist/components/themes/index.d.ts +1 -3
- package/dist/components/themes/index.js +1 -1
- package/dist/shared/lib/html-content.d.ts +14 -0
- package/dist/shared/lib/html-content.js +1 -0
- package/dist/shared/types/common.types.d.ts +0 -1
- package/dist/shared/types/common.types.js +1 -1
- package/dist/shared/types/exam-taking.types.d.ts +2 -0
- package/dist/shared/types/student.types.d.ts +14 -0
- package/package.json +2 -2
- package/dist/components/themes/spaceship/SpaceshipAudioPlayer.d.ts +0 -8
- package/dist/components/themes/spaceship/SpaceshipAudioPlayer.js +0 -1
- package/dist/components/themes/spaceship/SpaceshipLayout.d.ts +0 -2
- package/dist/components/themes/spaceship/SpaceshipLayout.js +0 -1
- package/dist/components/themes/spaceship/assets/images/X-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/X.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/audio-bar.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/background.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/bg_sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/bingo.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-wrapper.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/board_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/button_feedback_vi.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-right-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-right.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/focus-vector.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/head-phone_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-mute-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-mute.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play-violet.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/micro.png +0 -0
- package/dist/components/themes/spaceship/assets/images/next-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/next.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/purple-circle.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/question-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/question-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/red-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/red-wrapper.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/sound_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/student-avatar.png +0 -0
- package/dist/components/themes/spaceship/assets/images/teacher-play.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/timer-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/styles/SpaceshipLayout.module.css +0 -347
- package/dist/components/themes/spaceship/assets/styles/SpaceshipWaitingRoom.module.css +0 -395
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/big-blue-badge-sunset.png +0 -0
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/blue-badge-sunset.png +0 -0
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/blue-wrapper-sunset.png +0 -0
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/next-small.webp +0 -0
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/red-badge-sunset.png +0 -0
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/red-wrapper-sunset.png +0 -0
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/robot-avatar.png +0 -0
- /package/dist/components/themes/{spaceship → summer-sky}/assets/images/teacher-play-sunset.png +0 -0
package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as i,jsxs as e}from"react/jsx-runtime";import{EnglishCertificationAudioPlayer as t}from"./EnglishCertificationAudioPlayer";import{EnglishCertificationQuestionItem as o}from"./EnglishCertificationQuestionItem";import{ENGLISH_CERT_CONTENT_WIDTH_CLASS as n}from"./english-certification-theme";import{ENGLISH_CERT_STICKY_AUDIO_ATTR as r,englishCertQuestionDomId as s}from"./english-cert-scroll";export function EnglishCertificationSingleQuestionList({part:a,partConfig:l,answers:u,flaggedQuestions:g,onAnswerChange:d,onToggleFlag:m,isReviewMode:f=!1,isListeningPart:c=!1,partAudioUrl:p}){const h=l.startIndex??0,C=Array.isArray(l.questionConfig)?l.questionConfig:[],w=l.defaultQuestion,x=c&&Boolean(p);return e("div",{className:"flex flex-col items-center gap-5 pb-4",children:[x&&i("div",{[r]:"",className:`sticky top-0 z-20 ${n}`,children:i(t,{audioUrl:p,partNumber:a.partNo})}),a.questions.map((e,t)=>{const n=e.audio_url?Array.from(new Set([...C,"audioUrl"])):C;return i(o,{domId:s(e.id),question:e,questionNumber:h+t+1,questionConfig:n,defaultQuestion:w,isListeningPart:c,answer:u[e.id],isFlagged:g.has(e.id),onAnswerChange:d,onToggleFlag:m,isReviewMode:f},e.id)})]})}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll helpers for English Certification Answer Sheet navigation.
|
|
3
|
+
*
|
|
4
|
+
* Question cards use a stable DOM id (`ec-question-{id}`) so the sidebar can
|
|
5
|
+
* jump to the chosen question after `goToQuestion` re-renders the active part.
|
|
6
|
+
*
|
|
7
|
+
* Listening parts pin the audio bar with `position: sticky`. Manual scroll must
|
|
8
|
+
* subtract that bar's height so the target card is not hidden underneath it.
|
|
9
|
+
*/
|
|
10
|
+
/** Stable DOM id for a question card / row, used for Answer-Sheet scroll-to. */
|
|
11
|
+
export declare function englishCertQuestionDomId(questionId: string): string;
|
|
12
|
+
/** Marker on sticky audio wrappers so scroll offset can be measured at runtime. */
|
|
13
|
+
export declare const ENGLISH_CERT_STICKY_AUDIO_ATTR = "data-ec-sticky-audio";
|
|
14
|
+
/** Nearest ancestor that actually scrolls (falls back to document scrolling element). */
|
|
15
|
+
export declare function findScrollableParent(el: HTMLElement): HTMLElement;
|
|
16
|
+
/**
|
|
17
|
+
* Scroll `el` into view inside its nearest scrollable ancestor.
|
|
18
|
+
* Prefer parent-relative scroll so nested columns (Reading split-view) work.
|
|
19
|
+
* When a sticky Listening audio bar is present, leave room under it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function scrollElementIntoView(el: HTMLElement, options?: {
|
|
22
|
+
behavior?: ScrollBehavior;
|
|
23
|
+
block?: ScrollLogicalPosition;
|
|
24
|
+
}): void;
|
|
25
|
+
/**
|
|
26
|
+
* Find the question anchor by id and scroll it into view.
|
|
27
|
+
* Retries briefly so cross-part navigation can wait for React to mount the card.
|
|
28
|
+
*/
|
|
29
|
+
export declare function scrollToEnglishCertQuestion(questionId: string, options?: {
|
|
30
|
+
behavior?: ScrollBehavior;
|
|
31
|
+
block?: ScrollLogicalPosition;
|
|
32
|
+
}): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function englishCertQuestionDomId(t){return`ec-question-${t}`}export const ENGLISH_CERT_STICKY_AUDIO_ATTR="data-ec-sticky-audio";const t=[0,50,120,250,400];function e(t){const e=window.getComputedStyle(t).overflowY;return("auto"===e||"scroll"===e||"overlay"===e)&&t.scrollHeight>t.clientHeight+1}export function findScrollableParent(t){let n=t.parentElement;for(;n;){if(e(n))return n;n=n.parentElement}return document.scrollingElement??document.documentElement}export function scrollElementIntoView(t,e){const n=e?.behavior??"smooth",o=e?.block??"start",i=findScrollableParent(t),l=function(t,e){const n=t.querySelectorAll("[data-ec-sticky-audio]");if(!n.length)return 0;let o=0;return n.forEach(n=>{if(n===e||n.contains(e))return;if(!t.contains(n))return;const i=n.getBoundingClientRect().height;i>o&&(o=i)}),o>0?o+12:0}(i,t),r=i.getBoundingClientRect(),c=t.getBoundingClientRect(),s=i.scrollTop,u=c.top-r.top+s;let a=u;if("center"===o)a=u-i.clientHeight/2+c.height/2;else if("end"===o)a=u-i.clientHeight+c.height;else if("nearest"===o){const t=s+l,e=s+i.clientHeight,n=u+c.height;if(u>=t&&n<=e)return;a=u<t?u-l:n-i.clientHeight}else a=u-l;"start"===o&&0===l&&(a=Math.max(0,a-12)),i.scrollTo({top:Math.max(0,a),behavior:n})}export function scrollToEnglishCertQuestion(e,n){if("undefined"==typeof document||!e)return;const o=englishCertQuestionDomId(e);let i=0;const l=()=>{const e=document.getElementById(o);e?scrollElementIntoView(e,n):(i+=1,i<t.length&&window.setTimeout(l,t[i]))};window.setTimeout(l,t[0])}
|
|
@@ -6,11 +6,14 @@ export { EnglishCertificationFooterBar } from './EnglishCertificationFooterBar';
|
|
|
6
6
|
export { EnglishCertificationOptionSelector } from './EnglishCertificationOptionSelector';
|
|
7
7
|
export { EnglishCertificationAudioPlayer } from './EnglishCertificationAudioPlayer';
|
|
8
8
|
export { EnglishCertificationSingleQuestion } from './EnglishCertificationSingleQuestion';
|
|
9
|
-
export { EnglishCertificationSingleQuestionList,
|
|
9
|
+
export { EnglishCertificationSingleQuestionList, } from './EnglishCertificationSingleQuestionList';
|
|
10
|
+
export { ENGLISH_CERT_STICKY_AUDIO_ATTR, englishCertQuestionDomId, scrollToEnglishCertQuestion, } from './english-cert-scroll';
|
|
10
11
|
export { EnglishCertificationGroupedQuestion } from './EnglishCertificationGroupedQuestion';
|
|
11
12
|
export { EnglishCertificationReadingSection } from './EnglishCertificationReadingSection';
|
|
12
13
|
export { EnglishCertificationFlagButton } from './EnglishCertificationFlagButton';
|
|
13
14
|
export { EnglishCertificationBrand } from './EnglishCertificationBrand';
|
|
15
|
+
export { EnglishCertificationPartHeader } from './EnglishCertificationPartHeader';
|
|
16
|
+
export { EnglishCertificationInstructionBanner } from './EnglishCertificationInstructionBanner';
|
|
14
17
|
export { EcWordFillStructuredForm } from './EcWordFillStructuredForm';
|
|
15
18
|
export { EcMatchByWritingAnswer } from './EcMatchByWritingAnswer';
|
|
16
19
|
export { EcAnswerTheQuestion } from './EcAnswerTheQuestion';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{EnglishCertificationExamLayout}from"./EnglishCertificationExamLayout";export{EnglishCertificationQuestionRenderer}from"./EnglishCertificationQuestionRenderer";export{EnglishCertificationHeader}from"./EnglishCertificationHeader";export{EnglishCertificationNavigationPanel}from"./EnglishCertificationNavigationPanel";export{EnglishCertificationFooterBar}from"./EnglishCertificationFooterBar";export{EnglishCertificationOptionSelector}from"./EnglishCertificationOptionSelector";export{EnglishCertificationAudioPlayer}from"./EnglishCertificationAudioPlayer";export{EnglishCertificationSingleQuestion}from"./EnglishCertificationSingleQuestion";export{EnglishCertificationSingleQuestionList,englishCertQuestionDomId}from"./
|
|
1
|
+
export{EnglishCertificationExamLayout}from"./EnglishCertificationExamLayout";export{EnglishCertificationQuestionRenderer}from"./EnglishCertificationQuestionRenderer";export{EnglishCertificationHeader}from"./EnglishCertificationHeader";export{EnglishCertificationNavigationPanel}from"./EnglishCertificationNavigationPanel";export{EnglishCertificationFooterBar}from"./EnglishCertificationFooterBar";export{EnglishCertificationOptionSelector}from"./EnglishCertificationOptionSelector";export{EnglishCertificationAudioPlayer}from"./EnglishCertificationAudioPlayer";export{EnglishCertificationSingleQuestion}from"./EnglishCertificationSingleQuestion";export{EnglishCertificationSingleQuestionList}from"./EnglishCertificationSingleQuestionList";export{ENGLISH_CERT_STICKY_AUDIO_ATTR,englishCertQuestionDomId,scrollToEnglishCertQuestion}from"./english-cert-scroll";export{EnglishCertificationGroupedQuestion}from"./EnglishCertificationGroupedQuestion";export{EnglishCertificationReadingSection}from"./EnglishCertificationReadingSection";export{EnglishCertificationFlagButton}from"./EnglishCertificationFlagButton";export{EnglishCertificationBrand}from"./EnglishCertificationBrand";export{EnglishCertificationPartHeader}from"./EnglishCertificationPartHeader";export{EnglishCertificationInstructionBanner}from"./EnglishCertificationInstructionBanner";export{EcWordFillStructuredForm}from"./EcWordFillStructuredForm";export{EcMatchByWritingAnswer}from"./EcMatchByWritingAnswer";export{EcAnswerTheQuestion}from"./EcAnswerTheQuestion";export{EcWordFillParagraph}from"./EcWordFillParagraph";export{EcWritingTask}from"./EcWritingTask";
|
|
@@ -2,14 +2,12 @@ import type { ComponentType } from 'react';
|
|
|
2
2
|
import type { SpeakingLayoutProps, StandardExamLayoutProps, StandardQuestionCardProps } from './types';
|
|
3
3
|
export * from './cambridge-yle';
|
|
4
4
|
export * from './english-certification';
|
|
5
|
-
export * from './spaceship/SpaceshipLayout';
|
|
6
|
-
export * from './spaceship/SpaceshipAudioPlayer';
|
|
7
5
|
export * from './summer-sky/SummerSkyAudioPlayer';
|
|
8
6
|
export * from './summer-sky/SummerSkyLayout';
|
|
9
7
|
export * from './summer-sky/SummerSkySubmitModal';
|
|
10
8
|
export * from './summer-sky/SummerSkyWaitingRoom';
|
|
11
9
|
export type * from './types';
|
|
12
|
-
export type SpeakingThemeId = '
|
|
10
|
+
export type SpeakingThemeId = 'SUMMER_SKY' | string;
|
|
13
11
|
export declare function getSpeakingLayout(themeId?: SpeakingThemeId): ComponentType<SpeakingLayoutProps>;
|
|
14
12
|
export interface StandardThemeEntry {
|
|
15
13
|
Layout: ComponentType<StandardExamLayoutProps>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{SummerSkyLayout as r}from"./summer-sky/SummerSkyLayout";import{CambridgeYleExamLayout as m}from"./cambridge-yle/CambridgeYleExamLayout";import e from"./cambridge-yle/CambridgeYleQuestionCard";export*from"./cambridge-yle";export*from"./english-certification";export*from"./summer-sky/SummerSkyAudioPlayer";export*from"./summer-sky/SummerSkyLayout";export*from"./summer-sky/SummerSkySubmitModal";export*from"./summer-sky/SummerSkyWaitingRoom";const o={SUMMER_SKY:r},t="SUMMER_SKY";export function getSpeakingLayout(r){return o[r||t]||o[t]}const u={CAMBRIDGE_YLE:{Layout:m,QuestionCard:e}},a="CAMBRIDGE_YLE";export function getStandardExamTheme(r){return u[r||a]||u[a]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Detects whether a CMS string carries HTML markup vs plain text. */
|
|
2
|
+
export declare function isHtmlContent(value: string): boolean;
|
|
3
|
+
interface HtmlOrTextProps {
|
|
4
|
+
value: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
/** Element used for plain-text fallback. Default: `p`. */
|
|
7
|
+
as?: 'p' | 'div' | 'span';
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Renders CMS-authored content as HTML when it contains tags, otherwise as
|
|
11
|
+
* plain text. Content comes from the exam CMS (not end-user input).
|
|
12
|
+
*/
|
|
13
|
+
export declare function HtmlOrText({ value, className, as }: HtmlOrTextProps): import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{cn as l}from"../lib/utils";export function isHtmlContent(t){return/<[a-z][\s\S]*>/i.test(t)}export function HtmlOrText({value:e,className:s,as:i="p"}){if(!e)return null;if(isHtmlContent(e))return t("div",{className:l("[&_p]:mb-2 [&_p:last-child]:mb-0 [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_strong]:font-semibold",s),dangerouslySetInnerHTML:{__html:e}});return t(i,{className:s,children:e})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export var UserRole;!function(E){E.SYSTEM_ADMIN="SYSTEM_ADMIN",E.ADMIN="ADMIN",E.TEACHER="TEACHER",E.STUDENT="STUDENT"}(UserRole||(UserRole={}));export var Gender;!function(E){E.MALE="male",E.FEMALE="female",E.OTHER="other"}(Gender||(Gender={}));export var RoomType;!function(E){E.CONTEST="CONTEST",E.PRACTICE_TEST="PRACTICE_TEST"}(RoomType||(RoomType={}));export var ExamRoomStatus;!function(E){E.SCHEDULED="SCHEDULED",E.IN_PROGRESS="IN_PROGRESS",E.COMPLETED="COMPLETED"}(ExamRoomStatus||(ExamRoomStatus={}));export var StudentSelectionType;!function(E){E.ALL="ALL",E.SPECIFIC="SPECIFIC"}(StudentSelectionType||(StudentSelectionType={}));export var SkillEnum;!function(E){E.LISTENING="LISTENING",E.SPEAKING="SPEAKING",E.READING="READING",E.WRITING="WRITING"}(SkillEnum||(SkillEnum={}));export var ExamTemplateTheme;!function(E){E.CAMBRIDGE_YLE="CAMBRIDGE_YLE",E.FLYER_WOODEN="FLYER_WOODEN",E.
|
|
1
|
+
export var UserRole;!function(E){E.SYSTEM_ADMIN="SYSTEM_ADMIN",E.ADMIN="ADMIN",E.TEACHER="TEACHER",E.STUDENT="STUDENT"}(UserRole||(UserRole={}));export var Gender;!function(E){E.MALE="male",E.FEMALE="female",E.OTHER="other"}(Gender||(Gender={}));export var RoomType;!function(E){E.CONTEST="CONTEST",E.PRACTICE_TEST="PRACTICE_TEST"}(RoomType||(RoomType={}));export var ExamRoomStatus;!function(E){E.SCHEDULED="SCHEDULED",E.IN_PROGRESS="IN_PROGRESS",E.COMPLETED="COMPLETED"}(ExamRoomStatus||(ExamRoomStatus={}));export var StudentSelectionType;!function(E){E.ALL="ALL",E.SPECIFIC="SPECIFIC"}(StudentSelectionType||(StudentSelectionType={}));export var SkillEnum;!function(E){E.LISTENING="LISTENING",E.SPEAKING="SPEAKING",E.READING="READING",E.WRITING="WRITING"}(SkillEnum||(SkillEnum={}));export var ExamTemplateTheme;!function(E){E.CAMBRIDGE_YLE="CAMBRIDGE_YLE",E.FLYER_WOODEN="FLYER_WOODEN",E.SUMMER_SKY="SUMMER_SKY",E.IELTS_LRW="IELTS_LRW"}(ExamTemplateTheme||(ExamTemplateTheme={}));
|
|
@@ -102,6 +102,17 @@ export interface AttemptQuestionsResponse {
|
|
|
102
102
|
} | null;
|
|
103
103
|
questions: any[];
|
|
104
104
|
}
|
|
105
|
+
/** Summary of one exam part for student waiting room / room detail */
|
|
106
|
+
export interface StudentExamPartSummary {
|
|
107
|
+
id: string;
|
|
108
|
+
name: string;
|
|
109
|
+
skill?: string;
|
|
110
|
+
category?: string;
|
|
111
|
+
points: number;
|
|
112
|
+
questionCount: number;
|
|
113
|
+
instructions?: string;
|
|
114
|
+
questionType?: string;
|
|
115
|
+
}
|
|
105
116
|
export interface StudentRoom {
|
|
106
117
|
id: string;
|
|
107
118
|
name: string;
|
|
@@ -127,9 +138,12 @@ export interface StudentRoom {
|
|
|
127
138
|
passScore: number;
|
|
128
139
|
numberOfParts: number | null;
|
|
129
140
|
level?: string;
|
|
141
|
+
theme?: string;
|
|
130
142
|
template?: {
|
|
131
143
|
theme?: string;
|
|
132
144
|
};
|
|
145
|
+
/** Summary parts from exams.template.parts */
|
|
146
|
+
parts?: StudentExamPartSummary[];
|
|
133
147
|
};
|
|
134
148
|
contest?: {
|
|
135
149
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinyweb_dev/oe-exam-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Reusable OceanEdu question components.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build:compile": "tsc -p tsconfig.build.json",
|
|
22
22
|
"build:alias": "tsc-alias -p tsconfig.build.json",
|
|
23
23
|
"build:ts": "npm run build:compile && npm run build:assets && npm run build:alias",
|
|
24
|
-
"build:assets": "for d in cambridge-yle english-certification summer-sky
|
|
24
|
+
"build:assets": "for d in cambridge-yle english-certification summer-sky; do [ -d src/components/themes/$d/assets ] && cp -R src/components/themes/$d/assets dist/components/themes/$d/ || true; done; [ -d src/components/shared/audio/assets ] && cp -R src/components/shared/audio/assets dist/components/shared/audio/ || true; [ -d src/components/results/report/assets ] && mkdir -p dist/components/results/report && cp -R src/components/results/report/assets dist/components/results/report/ || true; (cd src && find . -name '*.module.css' -exec cp --parents {} ../dist/ \\;); cp src/global.d.ts dist/global.d.ts",
|
|
25
25
|
"minify:js": "find dist -name '*.js' -type f -exec sh -c 'for f do terser \"$f\" --compress directives=false --mangle --module --comments false --output \"$f\"; done' sh {} +",
|
|
26
26
|
"build": "npm run clean && npm run build:ts && npm run minify:js",
|
|
27
27
|
"pack:local": "npm pack",
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface SpaceshipAudioPlayerProps {
|
|
2
|
-
audioUrl: string;
|
|
3
|
-
partName?: string;
|
|
4
|
-
onEnded?: () => void;
|
|
5
|
-
onPlayingChange?: (isPlaying: boolean) => void;
|
|
6
|
-
}
|
|
7
|
-
export declare function SpaceshipAudioPlayer({ audioUrl, partName, onEnded, onPlayingChange }: SpaceshipAudioPlayerProps): import("react").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useRef as a,useState as r,useEffect as n}from"react";import s from"next/image";import{Pause as i,Play as l,VolumeX as o}from"lucide-react";import{usePresignedFileUrl as d}from"../../../shared/lib/hooks/usePresignedFileUrl";import c from"./assets/styles/SpaceshipLayout.module.css";import u from"./assets/images/big-blue-badge-sunset.png";import m from"./assets/images/teacher-play-sunset.png";import p from"./assets/images/ic-mute-sunset.png";function v(e){if(isNaN(e)||!isFinite(e))return"0:00";const t=Math.floor(e/60),a=Math.floor(e%60);return`${t}:${String(a).padStart(2,"0")}`}export function SpaceshipAudioPlayer({audioUrl:h,partName:f="Part 1 - Phase 2",onEnded:g,onPlayingChange:N}){const w=a(null),[y,b]=r(!1),[L,E]=r(0),[x,k]=r(0),[C,B]=r(100),{previewUrl:P}=d(h||void 0);n(()=>{const e=w.current;if(!e)return;const t=()=>{e.duration&&!isNaN(e.duration)&&isFinite(e.duration)&&k(e.duration)},a=()=>{E(e.currentTime),t()},r=()=>{b(!0),N?.(!0)},n=()=>{b(!1),N?.(!1)},s=()=>{b(!1),E(0),N?.(!1),g?.()};return t(),e.addEventListener("loadedmetadata",t),e.addEventListener("durationchange",t),e.addEventListener("canplay",t),e.addEventListener("timeupdate",a),e.addEventListener("play",r),e.addEventListener("pause",n),e.addEventListener("ended",s),()=>{e.removeEventListener("loadedmetadata",t),e.removeEventListener("durationchange",t),e.removeEventListener("canplay",t),e.removeEventListener("timeupdate",a),e.removeEventListener("play",r),e.removeEventListener("pause",n),e.removeEventListener("ended",s)}},[P,g]),n(()=>{b(!1),E(0),k(0)},[P]),n(()=>{const e=w.current;if(!e||!P)return;let t=!1;const a=()=>{t||e.play().catch(()=>{if(t)return;const a=()=>{t||(e.play().catch(()=>{}),document.removeEventListener("click",a),document.removeEventListener("keydown",a))};document.addEventListener("click",a,{once:!0}),document.addEventListener("keydown",a,{once:!0})})};return e.readyState>=3?a():e.addEventListener("canplay",a,{once:!0}),()=>{t=!0,e.removeEventListener("canplay",a)}},[P]);const F=x>0?L/x*100:0;return t("div",{className:c.examAudioContainer,children:[e("audio",{ref:w,...P?{src:P}:{},preload:"metadata"}),t("div",{className:c.bigBlueBadge,children:[e(s,{src:u,alt:"Audio Badge",className:c.bigBlueBadgeBg,priority:!0}),e("div",{className:c.audioBarContent,children:t("div",{className:c.audioBarInner,children:[e("span",{className:c.partLabel,children:f}),t("div",{className:c.teacherAvatarContainer,onClick:P?()=>{const e=w.current;e&&(e.paused?e.play().catch(()=>{}):e.pause())}:void 0,children:[e("img",{src:m.src,alt:"Play",className:c.teacherPlayIcon}),e("div",{className:"absolute inset-0 flex items-center justify-center",children:y?e(i,{className:"h-5 w-5 text-white drop-shadow-md",fill:"currentColor"}):e(l,{className:"h-5 w-5 text-white drop-shadow-md ml-1",fill:"currentColor"})})]}),t("div",{className:c.audioControlsWrapper,children:[t("span",{className:c.audioTime,children:[v(L)," / ",v(x)]}),t("div",{className:c.sliderTrack,children:[e("div",{className:c.sliderFill,style:{width:`${F}%`}}),e("input",{type:"range",min:"0",max:x||0,step:"0.1",value:L,onChange:e=>{const t=w.current;if(!t)return;const a=parseFloat(e.target.value);t.currentTime=a,E(a)},className:"absolute inset-0 w-full h-full opacity-0 cursor-pointer disabled:cursor-not-allowed",disabled:!P})]}),t("div",{className:c.volumeContainer,children:[e("div",{className:c.volumeIcon,onClick:()=>{const e=w.current;e&&(C>0?(e.volume=0,B(0)):(e.volume=1,B(100)))},children:0===C?e(o,{className:"text-white w-full h-full"}):e(s,{src:p,alt:"volume",className:"w-full h-full"})}),e("div",{className:"flex-grow items-center flex",style:{width:"60px"},children:e("input",{type:"range",min:"0",max:"100",value:C,onChange:e=>{const t=w.current;if(!t)return;const a=parseFloat(e.target.value);t.volume=a/100,B(a)},className:"w-full h-[3px] appearance-none bg-white/50 rounded cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-2.5 [&::-webkit-slider-thumb]:h-2.5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white"})})]})]})]})})]})]})}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import type { SpeakingLayoutProps } from '../types';
|
|
2
|
-
export declare function SpaceshipLayout({ onExit, partName, headerRight, onPrev, onNext, canGoPrev, canGoNext, audioUrl, onAudioEnded, recorder, children, contentClassName, hideAudioBar, onAudioPlayingChange, }: SpeakingLayoutProps): import("react").JSX.Element;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t,Fragment as s}from"react/jsx-runtime";import a from"next/image";import r from"./assets/styles/SpaceshipLayout.module.css";import{SpaceshipAudioPlayer as i}from"./SpaceshipAudioPlayer";import n from"./assets/images/circle-btn-right-sunset.png";import l from"./assets/images/circle-btn-sunset.png";import c from"./assets/images/next-sunset.png";import o from"./assets/images/X-sunset.png";import m from"./assets/images/button_feedback_vi.png";import d from"./assets/images/blue-wrapper-sunset.png";import p from"./assets/images/timer-badge.png";import h from"./assets/images/micro.png";export function SpaceshipLayout({onExit:g,partName:u,headerRight:f,onPrev:x,onNext:v,canGoPrev:N,canGoNext:b,audioUrl:y,onAudioEnded:B,recorder:w,children:C,contentClassName:S="",hideAudioBar:k,onAudioPlayingChange:I}){return t("div",{id:"exam-main-scroll-area",className:r.pageContainer,children:[e("div",{className:r.examContainer,children:t("div",{className:r.examMainBoard,children:[e("div",{className:r.headerTitleWrapper,children:e("div",{className:r.exitButtonWrapper,children:t("div",{className:r.circleBtn,tabIndex:0,onClick:g,children:[e(a,{src:n,alt:"btn",className:r.circleBtnBg}),e("div",{className:r.circleBtnInner,children:e(a,{src:o,alt:"X",className:r.exitIcon})})]})})}),N&&e("div",{className:r.controlLeft,children:t("div",{className:r.circleBtn,onClick:x,children:[e(a,{src:n,alt:"btn",className:r.circleBtnBg}),e("div",{className:r.circleBtnInner,children:e(a,{src:c,alt:"prev",className:`${r.nextPrevIcon} ${r.rotate}`})})]})}),t("div",{className:r.examContentMainContainer,children:[!k&&e(i,{audioUrl:y,partName:u,onEnded:B,onPlayingChange:I}),t("div",{className:r.examContentSpace,children:[f&&e("div",{className:"absolute top-2 right-6 z-50",children:f}),e("div",{className:`w-full h-full flex flex-col items-center justify-center ${S}`,children:C})]}),w&&t(s,{children:[e("p",{className:"absolute left-1/2 -translate-x-1/2 text-center whitespace-nowrap text-black font-bold m-0",style:{bottom:"115px",fontSize:"16px",fontFamily:'"Open Sans", sans-serif'},children:"uploaded"===w.status?"Đã ghi nhận câu trả lời":"Ấn biểu tượng micro để trả lời"}),e("div",{className:`absolute left-1/2 -translate-x-1/2 flex flex-col items-center z-10 transition-transform ${"recording"===w.status?"scale-[1.05]":"hover:scale-[1.02] active:scale-[0.98]"} ${"uploaded"===w.status?"opacity-80 grayscale-[20%] pointer-events-none":""}`,style:{bottom:"-40px",overflow:"visible"},children:t("div",{className:"block relative",style:{overflow:"visible"},children:[e(a,{src:d,alt:"wrapper",className:"z-0 "+("recording"===w.status?"animate-pulse":""),style:{width:"158px",height:"116px"}}),"uploaded"!==w.status&&t("div",{className:"absolute left-1/2 -translate-x-1/2 z-20",style:{top:"-32px"},children:[e(a,{src:p,alt:"timer",style:{width:"104px",height:"45px"}}),e("div",{className:"absolute inset-0 flex items-center justify-center",children:t("p",{className:"text-white text-center text-[20px] font-normal m-0",style:{margin:0},children:[Math.floor(w.remainingSeconds/60),":",(w.remainingSeconds%60).toString().padStart(2,"0")]})})]}),e("div",{className:"absolute inset-0 flex justify-center items-center w-full h-full",children:e(a,{src:h,alt:"micro",className:"cursor-pointer "+("recording"===w.status?"drop-shadow-[0_0_15px_rgba(0,255,255,0.8)]":""),style:{width:"51px",height:"51px"},onClick:"recording"===w.status?w.stopRecording:"idle"===w.status||"error"===w.status?w.startRecording:void 0})})]})})]})]}),b&&e("div",{className:r.controlRight,children:t("div",{className:r.circleBtn,onClick:v,children:[e(a,{src:l,alt:"btn",className:r.circleBtnBg}),e("div",{className:r.circleBtnInner,children:e(a,{src:c,alt:"next",className:r.nextPrevIcon})})]})})]})}),e("div",{className:r.feedbackButton,children:e("a",{target:"_blank",href:"https://forms.gle/DxdZqfgSirYzf1vW8",rel:"noopener noreferrer",children:e(a,{alt:"feedback",src:m})})})]})}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|