diff --git a/apps/nextjs/src/components/AppComponents/Chat/chat-lessonPlanDisplay.tsx b/apps/nextjs/src/components/AppComponents/Chat/chat-lessonPlanDisplay.tsx index a09bea2d5..4119fdd70 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/chat-lessonPlanDisplay.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/chat-lessonPlanDisplay.tsx @@ -24,7 +24,7 @@ function basedOnTitle(basedOn: string | BasedOnOptional) { } const displayStyles = cva( - "relative flex flex-col space-y-10 px-14 pb-28 opacity-100 sm:px-24 ", + "relative flex flex-col space-y-10 px-14 pb-28 opacity-100 sm:px-24", ); export type LessonPlanDisplayProps = Readonly<{ @@ -143,7 +143,7 @@ export const LessonPlanDisplay = ({ return ( | string | Array; + sectionValue: LessonPlanSectionWhileStreaming; options: ModifyOptions | AdditionalMaterialOptions; buttonText: string; actionButtonLabel: string; @@ -59,7 +60,7 @@ const ActionButtonWrapper = ({ chatId: id, messageId: lastAssistantMessage.id, sectionPath, - sectionValue, + sectionValue: String(sectionValue), action: selectedRadio.enumValue, actionOtherText: userFeedbackText || null, }; diff --git a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/add-additional-materials-button.tsx b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/add-additional-materials-button.tsx index 23a0353b3..8b2e58468 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/add-additional-materials-button.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/add-additional-materials-button.tsx @@ -1,3 +1,4 @@ +import type { LessonPlanSectionWhileStreaming } from "@oakai/aila/src/protocol/schema"; import type { AilaUserModificationAction } from "@prisma/client"; import ActionButtonWrapper from "./action-button-wrapper"; @@ -7,7 +8,7 @@ import type { FeedbackOption } from "./drop-down-form-wrapper"; export type AdditionalMaterialsProps = Readonly<{ sectionTitle: string; sectionPath: string; - sectionValue: Record | string | Array; + sectionValue: LessonPlanSectionWhileStreaming; }>; const AddAdditionalMaterialsButton = ({ diff --git a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/chat-section.tsx b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/chat-section.tsx index e999b74c6..7e1d8b207 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/chat-section.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/chat-section.tsx @@ -1,3 +1,7 @@ +import type { + LessonPlanKeys, + LessonPlanSectionWhileStreaming, +} from "@oakai/aila/src/protocol/schema"; import { sectionToMarkdown } from "@oakai/aila/src/protocol/sectionToMarkdown"; import { OakFlex } from "@oaknational/oak-components"; import { lessonSectionTitlesAndMiniDescriptions } from "data/lessonSectionTitlesAndMiniDescriptions"; @@ -9,17 +13,18 @@ import FlagButton from "./flag-button"; import ModifyButton from "./modify-button"; export type ChatSectionProps = Readonly<{ - objectKey: string; - value: Record | string | Array; + section: LessonPlanKeys; + value: LessonPlanSectionWhileStreaming; }>; -const ChatSection = ({ objectKey, value }: ChatSectionProps) => { + +const ChatSection = ({ section, value }: ChatSectionProps) => { return ( { $position="relative" $display={["none", "flex"]} > - {objectKey === "additionalMaterials" && value === "None" ? ( + {section === "additionalMaterials" && value === "None" ? ( ) : ( )} diff --git a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/flag-button.tsx b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/flag-button.tsx index 0254d8ef4..2a98e3c3a 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/flag-button.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/flag-button.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useState } from "react"; import { getLastAssistantMessage } from "@oakai/aila/src/helpers/chat/getLastAssistantMessage"; +import type { LessonPlanSectionWhileStreaming } from "@oakai/aila/src/protocol/schema"; import type { AilaUserFlagType } from "@oakai/db"; import { OakBox, OakP, OakRadioGroup } from "@oaknational/oak-components"; import styled from "styled-components"; @@ -26,7 +27,7 @@ type FlagButtonOptions = typeof flagOptions; export type FlagButtonProps = Readonly<{ sectionTitle: string; sectionPath: string; - sectionValue: Record | string | Array; + sectionValue: LessonPlanSectionWhileStreaming; }>; const FlagButton = ({ @@ -48,6 +49,25 @@ const FlagButton = ({ const { mutateAsync } = trpc.chat.chatFeedback.flagSection.useMutation(); + const isPlainObject = (value: unknown): value is Record => { + return typeof value === "object" && value !== null && !Array.isArray(value); + }; + + const prepareSectionValue = ( + value: LessonPlanSectionWhileStreaming, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ): string | any[] | Record => { + if ( + typeof value === "string" || + Array.isArray(value) || + isPlainObject(value) + ) { + return value; + } + // For numbers or any other types, convert to string + return String(value); + }; + const flagSectionContent = async () => { if (selectedRadio && lastAssistantMessage) { const payload = { @@ -56,7 +76,7 @@ const FlagButton = ({ flagType: selectedRadio.enumValue, userComment: userFeedbackText, sectionPath, - sectionValue, + sectionValue: prepareSectionValue(sectionValue), }; await mutateAsync(payload); } @@ -93,7 +113,7 @@ const FlagButton = ({ > {flagOptions.map((option) => ( = { component: DropDownSection, tags: ["autodocs"], args: { - objectKey: "learningOutcome", + section: "learningOutcome", value: "I can explain the reasons why frogs are so important to British society and culture", documentContainerRef: { current: null }, @@ -89,7 +89,7 @@ export const Closed: Story = { export const AdditionalMaterials: Story = { args: { - objectKey: "additionalMaterials", + section: "additionalMaterials", value: "None", }, }; @@ -116,7 +116,7 @@ export const ModifyAdditionalMaterials: Story = { }, }, args: { - objectKey: "additionalMaterials", + section: "additionalMaterials", value: "None", }, play: async ({ canvasElement }) => { diff --git a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/index.tsx b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/index.tsx index aac7f06e6..de23ece61 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/index.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/index.tsx @@ -1,5 +1,6 @@ import { useEffect, useRef, useState } from "react"; +import type { LessonPlanKeys } from "@oakai/aila/src/protocol/schema"; import { camelCaseToSentenceCase } from "@oakai/core/src/utils/camelCaseConversion"; import { OakBox, OakFlex, OakP } from "@oaknational/oak-components"; import { equals } from "ramda"; @@ -15,7 +16,7 @@ import ChatSection from "./chat-section"; const HALF_SECOND = 500; export type DropDownSectionProps = Readonly<{ - objectKey: string; + section: LessonPlanKeys; sectionRefs: Record>; // eslint-disable-next-line @typescript-eslint/no-explicit-any value: any; @@ -26,7 +27,7 @@ export type DropDownSectionProps = Readonly<{ }>; const DropDownSection = ({ - objectKey, + section, sectionRefs, value, documentContainerRef, @@ -35,7 +36,7 @@ const DropDownSection = ({ streamingTimeout = HALF_SECOND, }: DropDownSectionProps) => { const sectionRef = useRef(null); - if (sectionRefs) sectionRefs[objectKey] = sectionRef; + if (sectionRefs) sectionRefs[section] = sectionRef; const [isOpen, setIsOpen] = useState(false); const [status, setStatus] = useState<"empty" | "isStreaming" | "isLoaded">( "empty", @@ -56,7 +57,7 @@ const DropDownSection = ({ setStatus("isStreaming"); if (sectionRef && sectionHasFired === false && status === "isStreaming") { - if (objectKey && value) { + if (section && value) { function scrollToSection() { if (!userHasCancelledAutoScroll) { scrollToRef({ @@ -86,7 +87,7 @@ const DropDownSection = ({ sectionRef, sectionHasFired, status, - objectKey, + section, setIsOpen, prevValue, documentContainerRef, @@ -109,7 +110,7 @@ const DropDownSection = ({ setIsOpen(!isOpen)} aria-label="toggle"> - {sectionTitle(objectKey)} + {sectionTitle(section)} @@ -118,7 +119,7 @@ const DropDownSection = ({ {isOpen && (
{status === "isLoaded" ? ( - + ) : (

Loading

diff --git a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/modify-button.tsx b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/modify-button.tsx index 427042a61..b3ee39a57 100644 --- a/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/modify-button.tsx +++ b/apps/nextjs/src/components/AppComponents/Chat/drop-down-section/modify-button.tsx @@ -1,3 +1,4 @@ +import type { LessonPlanSectionWhileStreaming } from "@oakai/aila/src/protocol/schema"; import type { AilaUserModificationAction } from "@prisma/client"; import ActionButtonWrapper from "./action-button-wrapper"; @@ -7,7 +8,7 @@ import type { FeedbackOption } from "./drop-down-form-wrapper"; export type ModifyButtonProps = Readonly<{ sectionTitle: string; sectionPath: string; - sectionValue: Record | string | Array; + sectionValue: LessonPlanSectionWhileStreaming; }>; const ModifyButton = ({ diff --git a/apps/nextjs/src/data/lessonSectionTitlesAndMiniDescriptions.ts b/apps/nextjs/src/data/lessonSectionTitlesAndMiniDescriptions.ts index ac9d00013..5f3622c26 100644 --- a/apps/nextjs/src/data/lessonSectionTitlesAndMiniDescriptions.ts +++ b/apps/nextjs/src/data/lessonSectionTitlesAndMiniDescriptions.ts @@ -1,4 +1,24 @@ -export const lessonSectionTitlesAndMiniDescriptions = { +import type { LessonPlanKeys } from "@oakai/aila/src/protocol/schema"; + +export const lessonSectionTitlesAndMiniDescriptions: Record< + LessonPlanKeys, + { description: string } +> = { + title: { + description: "The name of the lesson.", + }, + keyStage: { + description: "The educational stage for which the lesson is intended.", + }, + subject: { + description: "The subject area of the lesson.", + }, + topic: { + description: "An optional topic that this lesson is part of.", + }, + basedOn: { + description: "An Oak lesson that this lesson is based on.", + }, learningOutcome: { description: "A short summary of the knowledge, skills and understanding students are expected to acquire by the end of the lesson.", @@ -47,8 +67,8 @@ export const lessonSectionTitlesAndMiniDescriptions = { description: "Extra resources for further study or practice, including worksheets, readings, and interactive activities.", }, - slides: { - description: - "Visual aids and presentations used throughout the lesson to support teaching and learning.", - }, + // slides: { + // description: + // "Visual aids and presentations used throughout the lesson to support teaching and learning.", + // }, };