diff --git a/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/[seed].page.tsx b/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/[seed].page.tsx index 3e3883411..fc765c884 100644 --- a/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/[seed].page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/[seed].page.tsx @@ -3,6 +3,7 @@ import { AppHead } from "@chair-flight/react/components"; import { FlashcardTest, LayoutModule } from "@chair-flight/react/containers"; import { ssrHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { NextPage } from "next"; type PageProps = { @@ -17,16 +18,24 @@ type PageParams = { seed: string; }; -const Page: NextPage = ({ questionBank, collectionId, seed }) => ( - - - - -); +const Page: NextPage = ({ questionBank, collectionId, seed }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + ["Flashcards", `/modules/${questionBank}/flashcards`], + collectionId, + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getServerSideProps = ssrHandler( async ({ helper, params }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/index.page.tsx index afaa449e2..cc35fbd76 100644 --- a/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/flashcards/[collectionId]/index.page.tsx @@ -4,6 +4,7 @@ import { AppHead } from "@chair-flight/react/components"; import { FlashcardList, LayoutModule } from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageProps = { @@ -16,12 +17,20 @@ type PageParams = { collectionId: string; }; -const FlashcardsThemePage: NextPage = (props) => ( - - - - -); +const Page: NextPage = ({ questionBank, collectionId }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + ["Flashcards", `/modules/${questionBank}/flashcards`], + collectionId, + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getStaticProps = staticHandler( async ({ params, helper }) => { @@ -51,4 +60,4 @@ export const getStaticPaths: GetStaticPaths = async () => { return { fallback: false, paths }; }; -export default FlashcardsThemePage; +export default Page; diff --git a/apps/next-app/pages/modules/[questionBank]/flashcards/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/flashcards/index.page.tsx index 03ec61217..e4af0f097 100644 --- a/apps/next-app/pages/modules/[questionBank]/flashcards/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/flashcards/index.page.tsx @@ -7,6 +7,7 @@ import { } from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageParams = { @@ -17,41 +18,48 @@ type PageProps = { questionBank: QuestionBankName; }; -const Page: NextPage = ({ questionBank }) => ( - - - - Flash Cards - - Practice for open-ended interview questions. -
- Use these flash cards to practice for your interview. You can review all - flash cards at once, or get 10 random cards to review. Try to answer the - question outloud as you would in an interview. Consider recording your - answer and playing it back to see how you sound. -
- Once you are satisfied with the answer, Flip the card to see if you are - close enough. -
- - Have fun! - -
- -
-); +const Page: NextPage = ({ questionBank }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + "Flashcards", + ] as Breadcrumbs; + + return ( + + + + Flash Cards + + Practice for open-ended interview questions. +
+ Use these flash cards to practice for your interview. You can review + all flash cards at once, or get 10 random cards to review. Try to + answer the question outloud as you would in an interview. Consider + recording your answer and playing it back to see how you sound. +
+ Once you are satisfied with the answer, Flip the card to see if you + are close enough. +
+ + Have fun! + +
+ +
+ ); +}; export const getStaticProps = staticHandler( async ({ params, helper }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/index.page.tsx index 3a2674aef..276b56f2b 100644 --- a/apps/next-app/pages/modules/[questionBank]/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/index.page.tsx @@ -1,9 +1,13 @@ import * as fs from "node:fs/promises"; -import { Divider, Link, Typography } from "@mui/joy"; import { AppHead } from "@chair-flight/react/components"; -import { LayoutModule, OverviewModules } from "@chair-flight/react/containers"; +import { + LayoutModule, + OverviewModule, + OverviewModules, +} from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageProps = { @@ -14,22 +18,22 @@ type PageParams = { questionBank: QuestionBankName; }; -const Page: NextPage = ({ questionBank }) => ( - - - Question Bank - - - Tests - - Create New Test - -); +const Page: NextPage = ({ questionBank }) => { + const crumbs = [questionBank.toUpperCase()] as Breadcrumbs; + + return ( + + + + + ); +}; export const getStaticProps = staticHandler( async ({ params, helper }) => { await OverviewModules.getData({ helper, params }); await LayoutModule.getData({ helper, params }); + await OverviewModule.getData({ helper, params }); return { props: params }; }, fs, diff --git a/apps/next-app/pages/modules/[questionBank]/learning-objectives/[learningObjectiveId].page.tsx b/apps/next-app/pages/modules/[questionBank]/learning-objectives/[learningObjectiveId].page.tsx index 7278bb380..5b90172fd 100644 --- a/apps/next-app/pages/modules/[questionBank]/learning-objectives/[learningObjectiveId].page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/learning-objectives/[learningObjectiveId].page.tsx @@ -5,6 +5,7 @@ import { } from "@chair-flight/react/containers"; import { ssrHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { NextPage } from "next"; type PageParams = { @@ -17,12 +18,27 @@ type PageProps = { learningObjectiveId: string; }; -export const Page: NextPage = (props) => ( - - - - -); +export const Page: NextPage = ({ + questionBank, + learningObjectiveId, +}) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + ["Learning Objectives", `/modules/${questionBank}/learning-objectives`], + learningObjectiveId, + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getServerSideProps = ssrHandler( async ({ helper, params }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/learning-objectives/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/learning-objectives/index.page.tsx index e72b90b50..a8c595e5d 100644 --- a/apps/next-app/pages/modules/[questionBank]/learning-objectives/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/learning-objectives/index.page.tsx @@ -6,6 +6,7 @@ import { } from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageProps = { @@ -16,12 +17,19 @@ type PageParams = { questionBank: QuestionBankName; }; -export const Page: NextPage = (props) => ( - - - - -); +export const Page: NextPage = ({ questionBank }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + "Learning Objectives", + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getStaticProps = staticHandler( async ({ params, helper }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/edit.page.tsx b/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/edit.page.tsx index 94632ab47..a44019792 100644 --- a/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/edit.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/edit.page.tsx @@ -2,6 +2,7 @@ import { AppHead } from "@chair-flight/react/components"; import { LayoutModule, QuestionEditor } from "@chair-flight/react/containers"; import { ssrHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { NextPage } from "next"; type PageProps = { @@ -17,12 +18,26 @@ type PageParams = { export const EditQuestionPage: NextPage = ({ questionBank, questionId, -}) => ( - - - - -); +}) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + ["Questions", `/modules/${questionBank}/questions`], + [questionId, `/modules/${questionBank}/questions/${questionId}`], + "edit", + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getServerSideProps = ssrHandler( async ({ params, helper }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/index.page.tsx index 246dd18ca..26befab3a 100644 --- a/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/questions/[questionId]/index.page.tsx @@ -4,6 +4,7 @@ import { AppHead } from "@chair-flight/react/components"; import { LayoutModule, QuestionOverview } from "@chair-flight/react/containers"; import { ssrHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { NextPage } from "next"; type PageParams = { @@ -14,8 +15,8 @@ type PageParams = { }; type PageProps = { - seed?: string; - variantId?: string; + seed: string; + variantId: string | null; questionBank: QuestionBankName; questionId: string; }; @@ -29,7 +30,7 @@ const Page: NextPage = ({ const router = useRouter(); const query = router.query as PageParams; const seed = query.seed ?? initialSeed; - const variantId = query.variantId ?? initialVariantId; + const variantId = query.variantId ?? initialVariantId ?? undefined; const updateVariantAndSeed = (query: { variantId: string; seed: string }) => { router.push({ pathname: router.pathname, query }, undefined, { @@ -37,13 +38,19 @@ const Page: NextPage = ({ }); }; + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + ["Questions", `/modules/${questionBank}/questions`], + questionId, + ] as Breadcrumbs; + // const linkDescription = getQuestionPreview( // questionTemplate, // initialVariantId, // ); return ( - + = ({ export const getServerSideProps = ssrHandler( async ({ params, helper, context }) => { const seed = (context.query?.["seed"] ?? getRandomId()) as string; - const variantId = context.query?.["variantId"] as string | undefined; + const variantId = (context.query?.["variantId"] as string) ?? null; const allParams = { ...params, seed, variantId }; await Promise.all([ diff --git a/apps/next-app/pages/modules/[questionBank]/questions/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/questions/index.page.tsx index 3329065b9..10e9374a2 100644 --- a/apps/next-app/pages/modules/[questionBank]/questions/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/questions/index.page.tsx @@ -3,6 +3,7 @@ import { AppHead } from "@chair-flight/react/components"; import { LayoutModule, QuestionSearch } from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageProps = { @@ -13,12 +14,19 @@ type PageParams = { questionBank: QuestionBankName; }; -const Page: NextPage = ({ questionBank }) => ( - - - - -); +const Page: NextPage = ({ questionBank }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + "Questions", + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getStaticProps = staticHandler( async ({ params, helper }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/settings/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/settings/index.page.tsx index 06e04b026..b0c7483eb 100644 --- a/apps/next-app/pages/modules/[questionBank]/settings/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/settings/index.page.tsx @@ -4,6 +4,7 @@ import { AppHead } from "@chair-flight/react/components"; import { LayoutModule, UserSettings } from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageProps = { @@ -14,12 +15,19 @@ type PageParams = { questionBank: QuestionBankName; }; -const Page: NextPage = ({ questionBank }) => ( - - - - -); +const Page: NextPage = ({ questionBank }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + "Settings", + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getStaticProps = staticHandler( async ({ params, helper }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/tests/[testId]/exam.page.tsx b/apps/next-app/pages/modules/[questionBank]/tests/[testId]/exam.page.tsx index 7892bb0c3..bbb179540 100644 --- a/apps/next-app/pages/modules/[questionBank]/tests/[testId]/exam.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/tests/[testId]/exam.page.tsx @@ -1,3 +1,4 @@ +import { useRouter } from "next/router"; import { AppHead, ThemeOverrideColorScheme, @@ -17,13 +18,23 @@ type Params = { questionBank: QuestionBankName; }; -export const Page: NextPage = ({ testId, questionBank }) => ( - <> - - - - -); +export const Page: NextPage = ({ testId, questionBank }) => { + const router = useRouter(); + + return ( + <> + + + { + router.push(`/modules/${questionBank}/tests/${testId}/review`); + }} + /> + + ); +}; export const getServerSideProps = ssrHandler( async ({ helper, params }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/tests/[testId]/review.page.tsx b/apps/next-app/pages/modules/[questionBank]/tests/[testId]/review.page.tsx index e7f351950..bbfec2b9f 100644 --- a/apps/next-app/pages/modules/[questionBank]/tests/[testId]/review.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/tests/[testId]/review.page.tsx @@ -3,6 +3,7 @@ import { AppHead } from "@chair-flight/react/components"; import { LayoutModule, TestReview } from "@chair-flight/react/containers"; import { ssrHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { NextPage } from "next"; type Props = { @@ -15,11 +16,17 @@ type Params = { questionBank: QuestionBankName; }; -const ReviewPage: NextPage = ({ testId, questionBank }) => { +const Page: NextPage = ({ testId, questionBank }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + ["Tests", `/modules/${questionBank}/tests`], + testId, + ] as Breadcrumbs; + return ( - + - + ); }; @@ -34,4 +41,4 @@ export const getServerSideProps = ssrHandler( }, ); -export default ReviewPage; +export default Page; diff --git a/apps/next-app/pages/modules/[questionBank]/tests/[testId]/study.page.tsx b/apps/next-app/pages/modules/[questionBank]/tests/[testId]/study.page.tsx index a60076e49..13c74724f 100644 --- a/apps/next-app/pages/modules/[questionBank]/tests/[testId]/study.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/tests/[testId]/study.page.tsx @@ -1,5 +1,9 @@ +import { useRouter } from "next/router"; import { MissingPathParameter } from "@chair-flight/base/errors"; -import { AppHead } from "@chair-flight/react/components"; +import { + AppHead, + ThemeOverrideColorScheme, +} from "@chair-flight/react/components"; import { LayoutModule, TestStudy } from "@chair-flight/react/containers"; import { ssrHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; @@ -15,12 +19,26 @@ type Params = { questionBank: QuestionBankName; }; -export const Page: NextPage = ({ testId, questionBank }) => ( - - - - -); +export const Page: NextPage = ({ testId, questionBank }) => { + const router = useRouter(); + + return ( + <> + + + { + router.push(`/modules/${questionBank}/tests/${testId}/review`); + }} + onTestDismissed={() => { + router.push(`/modules/${questionBank}/tests`); + }} + /> + + ); +}; export const getServerSideProps = ssrHandler( async ({ helper, params }) => { diff --git a/apps/next-app/pages/modules/[questionBank]/tests/create.page.tsx b/apps/next-app/pages/modules/[questionBank]/tests/create.page.tsx index 690270bfd..89906c395 100644 --- a/apps/next-app/pages/modules/[questionBank]/tests/create.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/tests/create.page.tsx @@ -4,6 +4,7 @@ import { AppHead } from "@chair-flight/react/components"; import { LayoutModule, TestMaker } from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageProps = { @@ -17,16 +18,21 @@ type PageParams = { const Page: NextPage = ({ questionBank }) => { const router = useRouter(); + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + ["Tests", `/modules/${questionBank}/tests`], + "Create", + ] as Breadcrumbs; + return ( - + - router.push(`/modules/${questionBank}/tests/${test.id}/${test.mode}`) - } + onSuccessfulTestCreation={(test) => { + router.push(`/modules/${questionBank}/tests/${test.id}/${test.mode}`); + }} /> ); diff --git a/apps/next-app/pages/modules/[questionBank]/tests/index.page.tsx b/apps/next-app/pages/modules/[questionBank]/tests/index.page.tsx index bd7bbaa04..045bd22dc 100644 --- a/apps/next-app/pages/modules/[questionBank]/tests/index.page.tsx +++ b/apps/next-app/pages/modules/[questionBank]/tests/index.page.tsx @@ -3,6 +3,7 @@ import { AppHead } from "@chair-flight/react/components"; import { LayoutModule, TestsOverview } from "@chair-flight/react/containers"; import { staticHandler } from "@chair-flight/trpc/server"; import type { QuestionBankName } from "@chair-flight/base/types"; +import type { Breadcrumbs } from "@chair-flight/react/containers"; import type { GetStaticPaths, NextPage } from "next"; type PageProps = { @@ -13,16 +14,23 @@ type PageParams = { questionBank: QuestionBankName; }; -const Page: NextPage = ({ questionBank }) => ( - - - - -); +const Page: NextPage = ({ questionBank }) => { + const crumbs = [ + [questionBank.toUpperCase(), `/modules/${questionBank}`], + "Tests", + ] as Breadcrumbs; + + return ( + + + + + ); +}; export const getStaticProps = staticHandler( async ({ params, helper }) => { diff --git a/libs/content/question-bank-atpl/questions/010/010.05.json b/libs/content/question-bank-atpl/questions/010/010.05.json index 10643d8b3..fe97b078e 100644 --- a/libs/content/question-bank-atpl/questions/010/010.05.json +++ b/libs/content/question-bank-atpl/questions/010/010.05.json @@ -916,47 +916,6 @@ } } }, - { - "id": "Q5223XCAQR", - "explanation": "", - "learningObjectives": ["010.05.03.01.18"], - "variants": { - "oeTL3pS0": { - "id": "oeTL3pS0", - "type": "simple", - "question": "An IFR-rated pilot wants to fly between two European aerodromes 100 NM apart. Weather conditions are VMC during the flight. According to SERA (Standardized European Rules of the Air), under which rules can the flight be performed?", - "options": [ - { - "id": "APZ7MYA2K2", - "text": "000°(M), FL130", - "correct": true, - "why": "" - }, - { - "id": "A2N90DIEYC", - "text": " 000°(M), FL135", - "correct": false, - "why": "" - }, - { - "id": "ADFWVXLTH9", - "text": "359°(M), FL135", - "correct": false, - "why": "" - }, - { - "id": "A7ED5046U8", - "text": "359°(M), FL130", - "correct": false, - "why": "" - } - ], - "annexes": [], - "externalIds": ["AVEXAM-19428"], - "explanation": "" - } - } - }, { "id": "Q54XWJHS0Y", "explanation": "", @@ -1882,47 +1841,6 @@ } } }, - { - "id": "Q9FXL8O0D4", - "explanation": "", - "learningObjectives": ["010.05.03.01.18"], - "variants": { - "bcHVMrFt": { - "id": "bcHVMrFt", - "type": "simple", - "question": "On a VMC day, can the pilot-in-command, who is holding a current instrument rating, elect to fly in accordance with the instrument flight rules, despite being in visual conditions?", - "options": [ - { - "id": "AANP05LQE0", - "text": "4 000 ft", - "correct": true, - "why": "" - }, - { - "id": "AMTQD2N63X", - "text": "3 000 ft", - "correct": false, - "why": "" - }, - { - "id": "AQZD1LO34F", - "text": "1 500 ft", - "correct": false, - "why": "" - }, - { - "id": "AWGRYIEV2K", - "text": "2 000 ft", - "correct": false, - "why": "" - } - ], - "annexes": [], - "externalIds": ["AVEXAM-58211"], - "explanation": "" - } - } - }, { "id": "Q9RR7AV8HO", "explanation": "", diff --git a/libs/content/question-bank-atpl/questions/022/022.05.json b/libs/content/question-bank-atpl/questions/022/022.05.json index 651342b82..a5b396730 100644 --- a/libs/content/question-bank-atpl/questions/022/022.05.json +++ b/libs/content/question-bank-atpl/questions/022/022.05.json @@ -9100,25 +9100,25 @@ "options": [ { "id": "ACOOAIXMSW", - "text": "the AP, FD and A/T", + "text": "the AP, FD and A/T", "correct": true, "why": "" }, { "id": "ATUPCI880G", - "text": "the Captain's AP", + "text": "the Captain's AP", "correct": false, "why": "" }, { "id": "AJH6QX41WW", - "text": "the FO's instruments", + "text": "the FO's instruments", "correct": false, "why": "" }, { "id": "A9JATLDXH4", - "text": "the Captain's instruments", + "text": "the Captain's instruments", "correct": false, "why": "" } diff --git a/libs/content/question-bank-atpl/questions/050/050.01.json b/libs/content/question-bank-atpl/questions/050/050.01.json index 60e3de4bc..5add8ab89 100644 --- a/libs/content/question-bank-atpl/questions/050/050.01.json +++ b/libs/content/question-bank-atpl/questions/050/050.01.json @@ -28559,7 +28559,7 @@ "tyGJMGSq": { "id": "tyGJMGSq", "type": "simple", - "question": "2.Over PALMA (39° N 003° E) the lowest FL listed which is unaffected by CAT is", + "question": "Over PALMA (39° N 003° E) the lowest FL listed which is unaffected by CAT is", "options": [ { "id": "A40RF5RDF6", diff --git a/libs/content/question-bank-atpl/questions/062/062.02.json b/libs/content/question-bank-atpl/questions/062/062.02.json index dffaed54a..34c79f0c9 100644 --- a/libs/content/question-bank-atpl/questions/062/062.02.json +++ b/libs/content/question-bank-atpl/questions/062/062.02.json @@ -403,7 +403,7 @@ "pFzZabn0": { "id": "pFzZabn0", "type": "simple", - "question": "A radio signal is used to establish voice communications between the ground and an aircraft. ÿThis signal is transmitted in A3E. The number 3 means that the:", + "question": "A radio signal is used to establish voice communications between the ground and an aircraft. This signal is transmitted in A3E. The number 3 means that the:", "options": [ { "id": "APLJKNM2UF", @@ -2023,7 +2023,7 @@ "nuRV62Ue": { "id": "nuRV62Ue", "type": "simple", - "question": "A VOR and DME are co-located. ÿYou want to identify the DME by listening to the callsign. ÿHaving heard the same callsign 4 times in 40 seconds the:", + "question": "A VOR and DME are co-located. You want to identify the DME by listening to the callsign. Having heard the same callsign 4 times in 40 seconds the:", "options": [ { "id": "AQVQL72H4E", @@ -3266,7 +3266,7 @@ "tyjYPaoP": { "id": "tyjYPaoP", "type": "simple", - "question": "Your QUJ is 335° by VDF. ÿThe variation of a VOR at the same location is 12° W. ÿWhat is the phase difference between the reference and variable phase signals being received at the aircraft from that VOR?", + "question": "Your QUJ is 335° by VDF. The variation of a VOR at the same location is 12° W. What is the phase difference between the reference and variable phase signals being received at the aircraft from that VOR?", "options": [ { "id": "A7MIFDUEMX", @@ -3942,7 +3942,7 @@ "AnQM19cC": { "id": "AnQM19cC", "type": "simple", - "question": "A VOR is situated at the far end of a runway on which an aircraft is making an ILS approach. Nav 1 is switched to the localiser frequency and Nav 2 to the VOR frequency. At the moment that the needle of # 1 indicator reaches the outer dot the deflection of the needle of # 2 indicator will be at: ÿ", + "question": "A VOR is situated at the far end of a runway on which an aircraft is making an ILS approach. Nav 1 is switched to the localiser frequency and Nav 2 to the VOR frequency. At the moment that the needle of # 1 indicator reaches the outer dot the deflection of the needle of # 2 indicator will be at: ", "options": [ { "id": "AVZDVOH0F2", diff --git a/libs/content/question-bank-b737/questions/737.01.json b/libs/content/question-bank-b737/questions/737.01.json index cd711329a..847c7fe12 100644 --- a/libs/content/question-bank-b737/questions/737.01.json +++ b/libs/content/question-bank-b737/questions/737.01.json @@ -734,7 +734,7 @@ "zpn3s": { "id": "zpn3s", "type": "simple", - "question": "hen operating the forward airstairs, with the external control, what position must the forward entry door be in?", + "question": "When operating the forward airstairs, with the external control, what position must the forward entry door be in?", "options": [ { "id": "qp37z", diff --git a/libs/content/question-bank-b737/questions/737.11.json b/libs/content/question-bank-b737/questions/737.11.json index aa4416495..cfb0ef485 100644 --- a/libs/content/question-bank-b737/questions/737.11.json +++ b/libs/content/question-bank-b737/questions/737.11.json @@ -686,7 +686,7 @@ "82t4i": { "id": "82t4i", "type": "simple", - "question": "The IntuVue weather radar fitted in aircraft YF662-YF695 and YW001-YW164, gives clutter-free viewing of significant weather out to what range?", + "question": "The IntuVue weather radar fitted in aircraft gives clutter-free viewing of significant weather out to what range?", "options": [ { "id": "srq8t", diff --git a/libs/content/question-bank-b737/questions/737.13.json b/libs/content/question-bank-b737/questions/737.13.json index bf474dc6b..d3d3538e4 100644 --- a/libs/content/question-bank-b737/questions/737.13.json +++ b/libs/content/question-bank-b737/questions/737.13.json @@ -418,7 +418,7 @@ }, { "id": "hrap", - "explanation": "", + "explanation": "**STBY RUD** - activates standby hydraulic system pump and opens standby rudder\nshutoff valve to pressurize standby rudder power control unit.\n\n- **OFF** - closes flight control shutoff valve isolating ailerons, elevators and rudder\nfrom associated hydraulic system pressure.\n- **ON** (guarded position) - normal operating position.", "learningObjectives": ["737.13"], "variants": { "in83r": { @@ -426,6 +426,15 @@ "type": "true-or-false", "question": "Moving the STBY RUD switch to ON activates the standby pump and opens the standby rudder shutoff valve to pressurise the standby power control unit.", "answer": false, + "explanation": "Switching to **OFF** triggers the changes described!", + "annexes": [], + "externalIds": [] + }, + "in83q": { + "id": "in83q", + "type": "true-or-false", + "question": "Moving the STBY RUD switch to OFF activates the standby pump and opens the standby rudder shutoff valve to pressurise the standby power control unit.", + "answer": true, "explanation": "", "annexes": [], "externalIds": [] diff --git a/libs/content/question-bank-b737/questions/737.15.json b/libs/content/question-bank-b737/questions/737.15.json index f320e7806..572caa3b4 100644 --- a/libs/content/question-bank-b737/questions/737.15.json +++ b/libs/content/question-bank-b737/questions/737.15.json @@ -426,7 +426,7 @@ "type": "true-or-false", "question": "The stall warning test can only be carried out on the ground, the No1 and No2 systems must be carried out separately to ensure the clacker sounds when each system is tested.", "answer": false, - "explanation": "", + "explanation": "The Stall warning system consists of a stick shaker. The Clacker is the overspeed warning system.", "annexes": [], "externalIds": [] } diff --git a/libs/content/question-bank-b737/questions/737.json b/libs/content/question-bank-b737/questions/737.json index b77fc1f76..2280ed4bf 100644 --- a/libs/content/question-bank-b737/questions/737.json +++ b/libs/content/question-bank-b737/questions/737.json @@ -7017,7 +7017,7 @@ "why": "" } ], - "explanation": "", + "explanation": "## Passenger Oxygen system\n\nActivating the system causes the masks to drop from the stowage compartments.\nThe oxygen source is activated when any mask in the unit is pulled down. Pulling\none mask down causes all masks in that unit to come down and 100% oxygen\nflows to all masks.\n\nFCOM 1.40.24", "annexes": [], "externalIds": [] } diff --git a/libs/content/question-bank-prep/flashcards/atpl-technical-interview.json b/libs/content/question-bank-prep/flashcards/atpl-technical-interview.json index 875205f71..0a3253d3a 100644 --- a/libs/content/question-bank-prep/flashcards/atpl-technical-interview.json +++ b/libs/content/question-bank-prep/flashcards/atpl-technical-interview.json @@ -252,7 +252,7 @@ }, { "question": "What navigational instruments does the Boeing 737-800 have?", - "answer": "Approximately 6.5 years", + "answer": "IRS / GPS / VOR / DME", "id": "bbfa49bb-2789-4a2b-9d33-e268c8ab24f1" }, { @@ -702,7 +702,7 @@ }, { "question": "What is an MCP and what is an FMA?", - "answer": "IRS / GPS / VOR / DME", + "answer": "The mode control panel is used to select the autothrottle, autopilot, and flight director operating modes. The flight mode annunciator displays current flight modes.", "id": "cad39ac2-9040-4753-8643-9b0a224224a7" }, { diff --git a/libs/react/components/src/app-buttons/app-buttons.tsx b/libs/react/components/src/app-buttons/app-buttons.tsx index 80c66f3de..4406a0ed6 100644 --- a/libs/react/components/src/app-buttons/app-buttons.tsx +++ b/libs/react/components/src/app-buttons/app-buttons.tsx @@ -1,4 +1,6 @@ import { useEffect, useState } from "react"; +import { useRouter } from "next/router"; +import { default as ChevronLeftIcon } from "@mui/icons-material/ChevronLeft"; import { default as DarkModeIcon } from "@mui/icons-material/DarkMode"; import { default as GithubIcon } from "@mui/icons-material/GitHub"; import { default as LightModeIcon } from "@mui/icons-material/LightMode"; @@ -69,6 +71,21 @@ export const ThemeButton: FunctionComponent = (props) => { ); }; +export const BackButton: FunctionComponent = (props) => { + const { back } = useRouter(); + + const onClick: IconButtonProps["onClick"] = (e) => { + props.onClick?.(e); + back(); + }; + + return ( + + + + ); +}; + export const AppButtonsContainer = styled(Box)` position: fixed; top: 0; diff --git a/libs/react/components/src/app-buttons/index.ts b/libs/react/components/src/app-buttons/index.ts index 8d5bbdcfc..8b0701a4c 100644 --- a/libs/react/components/src/app-buttons/index.ts +++ b/libs/react/components/src/app-buttons/index.ts @@ -3,4 +3,5 @@ export { HamburgerButton, ThemeButton, AppButtonsContainer, + BackButton, } from "./app-buttons"; diff --git a/libs/react/components/src/cta-search/cta-search.tsx b/libs/react/components/src/cta-search/cta-search.tsx index b9b2d8f81..14d82d1f2 100644 --- a/libs/react/components/src/cta-search/cta-search.tsx +++ b/libs/react/components/src/cta-search/cta-search.tsx @@ -15,6 +15,7 @@ export type CtaSearchProps = { onChange: (value: string) => void; loading?: boolean; numberOfResults?: number; + disableLabel?: boolean; } & Omit< InputProps, | "value" @@ -32,7 +33,10 @@ export type CtaSearchProps = { * a fake loading spinner as soon as the user starts typing. */ export const CtaSearch = forwardRef( - ({ value, onChange, loading, sx, numberOfResults, ...props }, ref) => { + ( + { value, onChange, loading, sx, numberOfResults, disableLabel, ...props }, + ref, + ) => { const inputRef = useRef(null); const mergedRef = mergeRefs([ref, inputRef]); const [search, setSearch] = useState(value); @@ -91,15 +95,17 @@ export const CtaSearch = forwardRef( isLoading ? : } /> - - {!isLoading ? ( - - Number of Results: {numberOfResults} - - ) : ( - Loading results... - )} - + {!disableLabel && ( + + {!isLoading ? ( + + Number of Results: {numberOfResults} + + ) : ( + Loading results... + )} + + )} ); }, diff --git a/libs/react/components/src/markdown-client/index.ts b/libs/react/components/src/markdown-client/index.ts index 096ce38b0..fa2f4ed79 100644 --- a/libs/react/components/src/markdown-client/index.ts +++ b/libs/react/components/src/markdown-client/index.ts @@ -1,2 +1,7 @@ -export * from "./markdown-client"; -export * from "./markdown-client-demo"; +export { MarkdownClient } from "./markdown-client"; +export { MarkdownClientDemo } from "./markdown-client-demo"; +export { MarkdownClientCompressed } from "./markdown-client-compressed"; + +export type { MarkdownClientProps } from "./markdown-client"; +export type { MarkdownClientDemoProps } from "./markdown-client-demo"; +export type { MarkdownClientCompressedProps } from "./markdown-client-compressed"; diff --git a/libs/react/components/src/markdown-client/markdown-client-compressed.tsx b/libs/react/components/src/markdown-client/markdown-client-compressed.tsx new file mode 100644 index 000000000..3aefe6914 --- /dev/null +++ b/libs/react/components/src/markdown-client/markdown-client-compressed.tsx @@ -0,0 +1,18 @@ +import { styled } from "@mui/joy"; +import { MarkdownClient } from "./markdown-client"; +import type { MarkdownClientProps } from "./markdown-client"; + +/** MarkdownClient styled to remove excessive padding. */ +export const MarkdownClientCompressed = styled(MarkdownClient)` + h1, + h2, + h3, + h4, + h5, + h6, + p { + margin: 0; + } +`; + +export type MarkdownClientCompressedProps = MarkdownClientProps; diff --git a/libs/react/components/src/markdown-client/markdown-client.stories.tsx b/libs/react/components/src/markdown-client/markdown-client.stories.tsx index dbaa3a8a3..dd30637c0 100644 --- a/libs/react/components/src/markdown-client/markdown-client.stories.tsx +++ b/libs/react/components/src/markdown-client/markdown-client.stories.tsx @@ -1,5 +1,6 @@ import { dedent } from "ts-dedent"; import { MarkdownClient } from "./markdown-client"; +import { MarkdownClientCompressed } from "./markdown-client-compressed"; import { MarkdownClientDemo } from "./markdown-client-demo"; import type { Meta, StoryObj } from "@storybook/react"; @@ -10,6 +11,8 @@ const demoMarkdown = dedent` This component allows you to add markdown to pretty much anything you want. It supports GFM features like Emoji :bowtie: :kissing_smiling_eyes: :zzz: :notes: + + A second paragraph just for good measure `; export const Playground: Story = { @@ -28,6 +31,12 @@ export const MarkdownClientDemoStory: Story = { render: () => , }; +export const MarkdownClientCompressedStory: Story = { + ...Playground, + name: "MarkdownClientCompressed", + render: (props) => , +}; + const meta: Meta = { title: "Components/MarkdownClient", component: MarkdownClient, diff --git a/libs/react/components/src/markdown-client/markdown-client.tsx b/libs/react/components/src/markdown-client/markdown-client.tsx index 678aced1f..e8131a252 100644 --- a/libs/react/components/src/markdown-client/markdown-client.tsx +++ b/libs/react/components/src/markdown-client/markdown-client.tsx @@ -3,21 +3,22 @@ import { default as ReactMarkdown } from "react-markdown"; import { default as remarkGemoji } from "remark-gemoji"; import { default as remarkGfm } from "remark-gfm"; import { default as remarkSupersub } from "remark-supersub"; +import type { Options } from "react-markdown"; export type MarkdownClientProps = { children: string; + className?: Options["className"]; }; -export const MarkdownClient = memo(({ children }) => ( +export const MarkdownClient = memo((props) => ( - {children} - + /> )); MarkdownClient.displayName = "MarkdownClient"; diff --git a/libs/react/components/src/sidebar/sidebar.tsx b/libs/react/components/src/sidebar/sidebar.tsx index 0bb1eb980..abf426686 100644 --- a/libs/react/components/src/sidebar/sidebar.tsx +++ b/libs/react/components/src/sidebar/sidebar.tsx @@ -38,7 +38,7 @@ const VAR_SIDEBAR_WIDTH = "--joy-sidebar-width"; const VAR_SIDEBAR_REMAINING_WIDTH = "--joy-sidebar-remaining-width"; const SIDEBAR_EXPANDED_WIDTH = 210; const SIDEBAR_COLLAPSED_WIDTH = 42; -const SIDEBAR_MOBILE_COLLAPSED_WIDTH = 24; +const SIDEBAR_MOBILE_COLLAPSED_WIDTH = 0; const useSidebarStore = create<{ isMobileOpen: boolean; @@ -120,10 +120,10 @@ export const Sidebar = forwardRef( }, [`& .${listItemButtonClasses.root}`]: { - p: { xs: 0.125, sm: 1 }, + p: 1, borderRight: 0, borderBottom: 0, - borderLeftWidth: { xs: 0, sm: 4 }, + borderLeftWidth: 4, borderLeftColor: "transparent", "&:first-of-type": { @@ -187,7 +187,7 @@ export const Sidebar = forwardRef( bottom: 0, left: 0, right: 0, - backgroundColor: "var(--joy-palette-background-backdrop)", + backgroundColor: "background.backdrop", backdropFilter: "blur(8px)", zIndex: (t) => t.zIndex.modal - 1, opacity: 1, diff --git a/libs/react/components/src/test-question-result/test-question-result.stories.tsx b/libs/react/components/src/test-question-result/test-question-result.stories.tsx index 978c7b9e1..8feb31b46 100644 --- a/libs/react/components/src/test-question-result/test-question-result.stories.tsx +++ b/libs/react/components/src/test-question-result/test-question-result.stories.tsx @@ -6,12 +6,23 @@ type Story = StoryObj; export const Playground: Story = { args: { correct: false, + questionTemplateId: "123124", + questionVariantId: "abcbacabc", title: "Question 5", question: "what is the capital of France?", correctOption: "Paris", selectedOption: "Berlin", learningObjectives: ["010.03.01.01"], }, +}; + +export const WithMarkdown: Story = { + args: { + ...Playground.args, + question: "Which option is correct?\n\n- Option a)\n- Option b)", + correctOption: "**Option B**", + selectedOption: "Berlin", + }, argTypes: {}, }; diff --git a/libs/react/components/src/test-question-result/test-question-result.tsx b/libs/react/components/src/test-question-result/test-question-result.tsx index 2aa818dd5..ae35d29b9 100644 --- a/libs/react/components/src/test-question-result/test-question-result.tsx +++ b/libs/react/components/src/test-question-result/test-question-result.tsx @@ -1,8 +1,8 @@ import { forwardRef } from "react"; import { default as CheckIcon } from "@mui/icons-material/Check"; import { default as CrossIcon } from "@mui/icons-material/Close"; -import { Box, Sheet, Typography } from "@mui/joy"; -import { MarkdownClient } from "../markdown-client"; +import { Box, Sheet, Stack, Typography } from "@mui/joy"; +import { MarkdownClient, MarkdownClientCompressed } from "../markdown-client"; import type { SheetProps } from "@mui/joy"; export type TestQuestionResultProps = { @@ -50,28 +50,34 @@ export const TestQuestionResult = forwardRef< {`${questionTemplateId} (${questionVariantId})`} - + {question ?? ""} - - + + {correct && ( )} - - {correctOption} - - + + + {correctOption ?? ""} + + + {!correct && ( - + - - {selectedOption ?? "No option selected"} - - + + {selectedOption ? ( + + ) : ( + + )} + + )} ); diff --git a/libs/react/containers/src/index.ts b/libs/react/containers/src/index.ts index dcbd91195..243023c86 100644 --- a/libs/react/containers/src/index.ts +++ b/libs/react/containers/src/index.ts @@ -15,4 +15,5 @@ export * from "./learning-objectives/learning-objectives-search"; export * from "./learning-objectives/learning-objective-overview"; export * from "./overviews/overview-welcome"; export * from "./overviews/overview-modules"; +export * from "./overviews/overview-module"; export * from "./user/user-settings"; diff --git a/libs/react/containers/src/layouts/layout-module/index.ts b/libs/react/containers/src/layouts/layout-module/index.ts index d9b20e9fc..776a035c8 100644 --- a/libs/react/containers/src/layouts/layout-module/index.ts +++ b/libs/react/containers/src/layouts/layout-module/index.ts @@ -1 +1,2 @@ export { LayoutModule } from "./layout-module"; +export type { Breadcrumbs } from "./layout-module"; diff --git a/libs/react/containers/src/layouts/layout-module/layout-module.tsx b/libs/react/containers/src/layouts/layout-module/layout-module.tsx index 897e285ef..bd7c04afb 100644 --- a/libs/react/containers/src/layouts/layout-module/layout-module.tsx +++ b/libs/react/containers/src/layouts/layout-module/layout-module.tsx @@ -5,23 +5,44 @@ import { default as LearningObjectivesIcon } from "@mui/icons-material/ListOutli import { default as QuestionsIcon } from "@mui/icons-material/QuizOutlined"; import { default as SettingsIcon } from "@mui/icons-material/SettingsOutlined"; import { default as CardIcon } from "@mui/icons-material/StyleOutlined"; -import { Box, LinearProgress, listItemContentClasses } from "@mui/joy"; +import { + Box, + Breadcrumbs, + LinearProgress, + Link, + Stack, + Typography, + listItemContentClasses, +} from "@mui/joy"; import { AppLogo, + BackButton, + GithubButton, + HamburgerButton, Sidebar, SidebarListItem, + ThemeButton, ThemeOverrideColorScheme, + useSidebar, } from "@chair-flight/react/components"; import { trpc } from "@chair-flight/trpc/client"; import { container, getRequiredParam } from "../../wraper/container"; import { usePageTransition } from "../hooks/use-page-transition"; import type { QuestionBankName } from "@chair-flight/base/types"; +const HEADER_HEIGHT = 48; + +export type Breadcrumbs = [ + ...Array<[displayName: string, url: string]>, + string, +]; + type Props = { children: React.ReactNode; + questionBank: QuestionBankName; fixedHeight?: boolean; noPadding?: boolean; - questionBank: QuestionBankName; + breadcrumbs?: Breadcrumbs; }; type Params = { @@ -35,118 +56,162 @@ type Data = { hasMedia: boolean; }; -export const LayoutModule = container((props) => { - const { children, fixedHeight, noPadding, questionBank } = props; - const { isTransitioning } = usePageTransition(); - const router = useRouter(); - const config = LayoutModule.useData(props); +export const LayoutModule = container( + ({ children, fixedHeight, noPadding, questionBank, breadcrumbs }) => { + const { isTransitioning } = usePageTransition(); + const { openSidebar } = useSidebar(); + const router = useRouter(); + const config = LayoutModule.useData({ questionBank }); - const isQuestions = router.asPath.includes("questions"); - const isTests = router.asPath.includes("tests"); - const isSettings = router.asPath.includes("settings"); - const isLearningObjectives = router.asPath.includes("learning-objectives"); - const isFlashcards = router.asPath.includes("flashcards"); - const isHome = !isQuestions && !isTests && !isSettings && !isFlashcards; + const isQuestions = router.asPath.includes("questions"); + const isTests = router.asPath.includes("tests"); + const isSettings = router.asPath.includes("settings"); + const isLearningObjectives = router.asPath.includes("learning-objectives"); + const isFlashcards = router.asPath.includes("flashcards"); + const isHome = !isQuestions && !isTests && !isSettings && !isFlashcards; - return ( - <> - - - t.spacing(6), - pl: 0.5, - svg: { - fill: (t) => t.vars.palette.primary.plainColor, - fontSize: { xs: 18, sm: 24 }, - marginLeft: { xs: "2px", sm: "-2px" }, - }, - [`& .${listItemContentClasses.root}`]: { - fontWeight: 700, - letterSpacing: "0.05rem", - color: (t) => t.vars.palette.text.primary, - }, - }} - /> - - {config.hasQuestions && ( + return ( + <> + + t.spacing(6), + pl: 0.5, + svg: { + fill: (t) => t.vars.palette.primary.plainColor, + fontSize: 24, + marginLeft: "-2px", + }, + [`& .${listItemContentClasses.root}`]: { + fontWeight: 700, + letterSpacing: "0.05rem", + color: (t) => t.vars.palette.text.primary, + }, + }} /> - )} - {config.hasQuestions && ( - )} - {config.hasLearningObjectives && ( + {config.hasQuestions && ( + + )} + {config.hasQuestions && ( + + )} + {config.hasLearningObjectives && ( + + )} + {config.hasFlashcards && ( + + )} - )} - {config.hasFlashcards && ( - + t.spacing(0, 1), + backgroundColor: "background.surface", + borderBottomStyle: "solid", + borderBottomWidth: 1, + borderBottomColor: "divider", + boxSizing: "content-box", + zIndex: 1000, + width: Sidebar.css.remainingWidth, + transition: Sidebar.css.widthTransition, + right: 0, + boxShadow: (t) => t.shadow.md, + }} + > + + {breadcrumbs?.slice(0, -1).map(([name, url]) => ( + + {name} + + ))} + {breadcrumbs && {breadcrumbs?.at(-1)}} + + + + + - )} - + + + - - - - - ); -}); + + ); + }, +); LayoutModule.displayName = "LayoutModule"; diff --git a/libs/react/containers/src/overviews/overview-module/index.ts b/libs/react/containers/src/overviews/overview-module/index.ts new file mode 100644 index 000000000..f6130f52d --- /dev/null +++ b/libs/react/containers/src/overviews/overview-module/index.ts @@ -0,0 +1 @@ +export { OverviewModule } from "./overview-module"; diff --git a/libs/react/containers/src/overviews/overview-module/overview-module.tsx b/libs/react/containers/src/overviews/overview-module/overview-module.tsx new file mode 100644 index 000000000..aff3b245b --- /dev/null +++ b/libs/react/containers/src/overviews/overview-module/overview-module.tsx @@ -0,0 +1,69 @@ +import { useState } from "react"; +import { Button, Divider, Grid, Typography } from "@mui/joy"; +import { CtaSearch } from "@chair-flight/react/components"; +import { trpc } from "@chair-flight/trpc/client"; +import { LayoutModule } from "../../layouts/layout-module"; +import { container, getRequiredParam } from "../../wraper"; +import type { QuestionBankName } from "@chair-flight/base/types"; + +type Props = { + questionBank: QuestionBankName; +}; + +type Params = { + questionBank: QuestionBankName; +}; + +type Data = { + hasFlashcards: boolean; + hasQuestions: boolean; + hasLearningObjectives: boolean; + hasMedia: boolean; +}; + +export const OverviewModule = container( + ({ questionBank, sx, component = "section" }) => { + const config = LayoutModule.useData({ questionBank }); + const [searchQuestion, setQuestionSearch] = useState(""); + + return ( + + {config.hasQuestions && ( + <> + + + + + + + + + + + )} + {config.hasQuestions && ( + + Search Questions + + setQuestionSearch(v)} + /> + + )} + + ); + }, +); + +OverviewModule.getData = async ({ helper, params }) => { + const questionBank = getRequiredParam(params, "questionBank"); + return await helper.questionBank.getConfig.fetch({ questionBank }); +}; + +OverviewModule.useData = (params) => { + const qb = trpc.questionBank; + const questionBank = getRequiredParam(params, "questionBank"); + return qb.getConfig.useSuspenseQuery({ questionBank })[0]; +}; diff --git a/libs/react/containers/src/overviews/overview-modules/overview-modules.tsx b/libs/react/containers/src/overviews/overview-modules/overview-modules.tsx index b28eeac3e..8747bfe10 100644 --- a/libs/react/containers/src/overviews/overview-modules/overview-modules.tsx +++ b/libs/react/containers/src/overviews/overview-modules/overview-modules.tsx @@ -79,6 +79,7 @@ export const OverviewModules = container( return ( ; type Props = { testId: string; + onTestFinished?: () => void; }; export const TestExam = container( - ({ testId, sx, component = "section" }) => { + ({ testId, sx, onTestFinished, component = "section" }) => { useTestHotkeys({ testId }); useTestProgressTime({ testId }); const theme = useTheme(); - const router = useRouter(); const test = useTestProgress((state) => state.tests[testId]); const goToQuestion = useTestProgress((s) => s.goToTestQuestion); const goToPreviousQuestion = useTestProgress((s) => s.goToPreviousQuestion); @@ -222,7 +221,7 @@ export const TestExam = container( children="Finish" onClick={() => { finishTest({ testId: test.id }); - router.push(`../${test.id}/review`); + onTestFinished?.(); }} /> @@ -243,7 +242,7 @@ export const TestExam = container( color="danger" onClick={() => { finishTest({ testId: test.id }); - router.push(`../${test.id}/review`); + onTestFinished?.(); }} /> diff --git a/libs/react/containers/src/tests/test-maker/test-maker.tsx b/libs/react/containers/src/tests/test-maker/test-maker.tsx index c65c487ab..09a4acc70 100644 --- a/libs/react/containers/src/tests/test-maker/test-maker.tsx +++ b/libs/react/containers/src/tests/test-maker/test-maker.tsx @@ -30,7 +30,6 @@ import type { } from "@chair-flight/base/types"; import type { NewTestConfiguration } from "@chair-flight/core/app"; import type { NestedCheckboxSelectProps } from "@chair-flight/react/components"; -import type { BoxProps } from "@mui/joy"; const resolver = zodResolver(newTestConfigurationSchema); @@ -45,9 +44,10 @@ const testMakerPersistence = { createUsePersistenceHook("cf-test-maker-prep"), }; -type Props = Pick & { +type Props = { onSuccessfulTestCreation: (test: Test) => void; questionBank: QuestionBankName; + component?: "form"; }; type Params = { @@ -59,7 +59,7 @@ type Data = { }; export const TestMaker = container( - ({ questionBank, onSuccessfulTestCreation, sx, component = "form" }) => { + ({ questionBank, onSuccessfulTestCreation, sx }) => { const params: Params = { questionBank }; const persistenceKey = `cf-test-maker-${questionBank}` as const; const useTestMakerPersistence = testMakerPersistence[persistenceKey]; @@ -165,7 +165,7 @@ export const TestMaker = container( return ( setPersistedData(form.getValues())} sx={{ diff --git a/libs/react/containers/src/tests/test-study/test-study.tsx b/libs/react/containers/src/tests/test-study/test-study.tsx index a12a08248..0dc14f456 100644 --- a/libs/react/containers/src/tests/test-study/test-study.tsx +++ b/libs/react/containers/src/tests/test-study/test-study.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import { useRouter } from "next/router"; import { default as AccessAlarmsOutlinedIcon } from "@mui/icons-material/AccessAlarmsOutlined"; import { default as AppsOutlinedIcon } from "@mui/icons-material/AppsOutlined"; import { default as ChevronLeftIcon } from "@mui/icons-material/ChevronLeft"; @@ -48,16 +47,24 @@ type DrawingPointsMap = Record; type Props = { testId: string; + onTestDismissed?: () => void; + onTestFinished?: () => void; onMenuClicked?: () => void; }; export const TestStudy = container( - ({ testId, onMenuClicked, component = "section", sx }) => { + ({ + testId, + onTestDismissed, + onTestFinished, + onMenuClicked, + component = "section", + sx, + }) => { useTestHotkeys({ testId }); useTestProgressTime({ testId }); const theme = useTheme(); - const router = useRouter(); const test = useTestProgress((state) => state.tests[testId]); const goToQuestion = useTestProgress((s) => s.goToTestQuestion); const goToPreviousQuestion = useTestProgress((s) => s.goToPreviousQuestion); @@ -266,7 +273,7 @@ export const TestStudy = container( children="Finish" onClick={() => { finishTest({ testId: test.id }); - router.push(`../${test.id}/review`); + onTestDismissed?.(); }} /> @@ -311,9 +318,7 @@ export const TestStudy = container( variant="outlined" children="Exit without finishing" color="warning" - onClick={() => { - router.push(`../`); - }} + onClick={() => onTestDismissed?.()} />