diff --git a/src/components/questionStructure/Task/variants/HandwritingTask/Canvas.tsx b/src/components/questionStructure/Task/variants/HandwritingTask/Canvas.tsx index 14080d6..d130cf8 100644 --- a/src/components/questionStructure/Task/variants/HandwritingTask/Canvas.tsx +++ b/src/components/questionStructure/Task/variants/HandwritingTask/Canvas.tsx @@ -1,5 +1,6 @@ import { Excalidraw, MainMenu } from '@excalidraw/excalidraw' import { ClipboardData } from '@excalidraw/excalidraw/types/clipboard' +import { ExcalidrawElement } from '@excalidraw/excalidraw/types/element/types' import { AppState, ExcalidrawImperativeAPI } from '@excalidraw/excalidraw/types/types' import { Box } from '@radix-ui/themes' import React, { @@ -13,6 +14,7 @@ import React, { import { ConfirmDialog } from '../../../../ConfirmDialog' import useLiveUpdates from './live-updates.hook' +import { HandwritingAnswer } from './types' const stopEvent = (e: SyntheticEvent | Event) => { e.preventDefault() @@ -22,6 +24,10 @@ const stopEvent = (e: SyntheticEvent | Event) => { interface CanvasProps { username: string onAnswerChange: (value: string) => void + initialData: { + elements?: readonly ExcalidrawElement[] + appState?: AppState + } } // Excalidraw keyboard shortcuts we allow in the canvas: @@ -44,11 +50,25 @@ const ALLOWED_TOOL_SHORTCUTS = [ 'Digit7', // pen ] -const Canvas: React.FC = ({ username, onAnswerChange }) => { - const { updateStrokes } = useLiveUpdates(username, onAnswerChange) +const Canvas: React.FC = ({ username, onAnswerChange, initialData }) => { const [excalidrawAPI, setExcalidrawAPI] = useState(null) const [clearDialogOpen, setClearDialogOpen] = useState(false) + const updateHandwriting = useCallback( + (latex: string) => { + const result: HandwritingAnswer = { + latex, + raw: { + elements: excalidrawAPI?.getSceneElements() ?? [], + appState: excalidrawAPI?.getAppState(), + }, + } + onAnswerChange(JSON.stringify(result)) + }, + [excalidrawAPI, onAnswerChange] + ) + const { updateStrokes } = useLiveUpdates(username, updateHandwriting) + const clearCanvas = useCallback(() => { updateStrokes({ elements: [] }) excalidrawAPI?.updateScene({ elements: [] }) @@ -128,7 +148,10 @@ const Canvas: React.FC = ({ username, onAnswerChange }) => { UIOptions={{ tools: { image: false } }} gridModeEnabled excalidrawAPI={setExcalidrawAPI} - // initialData={excalidrawData} + initialData={{ + ...initialData, + appState: { ...initialData.appState, collaborators: new Map() }, + }} onPaste={pasteHandler} > diff --git a/src/components/questionStructure/Task/variants/HandwritingTask/HandwritingEditor.tsx b/src/components/questionStructure/Task/variants/HandwritingTask/HandwritingEditor.tsx index 86ca382..763ba2b 100644 --- a/src/components/questionStructure/Task/variants/HandwritingTask/HandwritingEditor.tsx +++ b/src/components/questionStructure/Task/variants/HandwritingTask/HandwritingEditor.tsx @@ -5,27 +5,33 @@ import React from 'react' import Markdown from '../../../../Markdown' import Canvas from './Canvas' import './handwritingEditor.css' +import { HandwritingAnswer } from './types' interface HandwritingEditorProps { username: string - latex: string + answer?: HandwritingAnswer onAnswerChange: (value: string) => void } const HandwritingEditor: React.FC = ({ username, - latex, + answer, onAnswerChange, }) => { return ( - {`\\( ${latex} \\)`} + {`\\( ${answer?.latex ?? ''} \\)`} - + ) diff --git a/src/components/questionStructure/Task/variants/HandwritingTask/ViewOnlyCanvas.tsx b/src/components/questionStructure/Task/variants/HandwritingTask/ViewOnlyCanvas.tsx index 5a1780f..af3a710 100644 --- a/src/components/questionStructure/Task/variants/HandwritingTask/ViewOnlyCanvas.tsx +++ b/src/components/questionStructure/Task/variants/HandwritingTask/ViewOnlyCanvas.tsx @@ -1,31 +1,38 @@ import { Excalidraw } from '@excalidraw/excalidraw' -import { - ExcalidrawImperativeAPI, - ExcalidrawInitialDataState, -} from '@excalidraw/excalidraw/types/types' +import { ExcalidrawElement } from '@excalidraw/excalidraw/types/element/types' +import { ExcalidrawImperativeAPI } from '@excalidraw/excalidraw/types/types' import { Box, Card } from '@radix-ui/themes' import React, { useEffect, useState } from 'react' interface ViewOnlyCanvasProps { - initialData: ExcalidrawInitialDataState + initialData: readonly ExcalidrawElement[] } export const ViewOnlyCanvas: React.FC = ({ initialData }) => { const [excalidrawAPI, setExcalidrawAPI] = useState(null) useEffect(() => { + if (excalidrawAPI && initialData) { + excalidrawAPI.updateScene({ + elements: initialData, + }) + } setTimeout(() => { excalidrawAPI?.scrollToContent(undefined, { fitToContent: true, }) }) - }, [excalidrawAPI]) + }, [excalidrawAPI, initialData]) - return initialData && initialData.elements?.length ? ( + return ( - + - ) : null + ) } diff --git a/src/components/questionStructure/Task/variants/HandwritingTask/index.scss b/src/components/questionStructure/Task/variants/HandwritingTask/index.scss index 278437c..4d69fce 100644 --- a/src/components/questionStructure/Task/variants/HandwritingTask/index.scss +++ b/src/components/questionStructure/Task/variants/HandwritingTask/index.scss @@ -62,7 +62,7 @@ } .excalidraw-box { - margin: '2px'; + margin: 2px; height: calc(100% - 4px); } diff --git a/src/components/questionStructure/Task/variants/HandwritingTask/index.tsx b/src/components/questionStructure/Task/variants/HandwritingTask/index.tsx index fef2c58..abc8e48 100644 --- a/src/components/questionStructure/Task/variants/HandwritingTask/index.tsx +++ b/src/components/questionStructure/Task/variants/HandwritingTask/index.tsx @@ -1,6 +1,7 @@ import { Pencil2Icon } from '@radix-ui/react-icons' import { Button, Card, Dialog, Flex } from '@radix-ui/themes' import { MathJax } from 'better-react-mathjax' +import { isEmpty } from 'lodash' import { FC } from 'react' import { useParams } from 'react-router-dom' @@ -10,8 +11,9 @@ import { TaskBaseProps } from '../../types' import HandwritingEditor from './HandwritingEditor' import { ViewOnlyCanvas } from './ViewOnlyCanvas' import './index.scss' +import { HandwritingAnswer } from './types' -export interface HandwritingTaskProps extends TaskBaseProps { +export interface HandwritingTaskProps extends TaskBaseProps { type: TaskType.PROCESSED_HANDWRITING } @@ -24,13 +26,15 @@ export const HandwritingTask: FC = ({ return ( - - - + {!isEmpty(answer?.raw?.elements) && ( + + + + )} - {answer ? `\\( ${answer} \\)` : 'No Answer'} + {answer?.latex ? `\\( ${answer.latex} \\)` : 'No Answer'} @@ -42,11 +46,7 @@ export const HandwritingTask: FC = ({ - + diff --git a/src/components/questionStructure/Task/variants/HandwritingTask/types.ts b/src/components/questionStructure/Task/variants/HandwritingTask/types.ts new file mode 100644 index 0000000..b7298c1 --- /dev/null +++ b/src/components/questionStructure/Task/variants/HandwritingTask/types.ts @@ -0,0 +1,10 @@ +import { ExcalidrawElement } from '@excalidraw/excalidraw/types/element/types' +import { AppState } from '@excalidraw/excalidraw/types/types' + +export interface HandwritingAnswer { + raw: { + elements: readonly ExcalidrawElement[] + appState?: Omit + } + latex: string +} diff --git a/src/utils/answers.ts b/src/utils/answers.ts index a01384d..84becc9 100644 --- a/src/utils/answers.ts +++ b/src/utils/answers.ts @@ -26,6 +26,8 @@ export function parseAnswer(answer: string, targetTaskType: TaskType) { return answer === '' ? answer : Number(answer) case TaskType.MULTIPLE_CHOICE_SELECT_SEVERAL: return answer === '' ? [] : answer.split(',') + case TaskType.PROCESSED_HANDWRITING: + return answer === '' ? { excalidraw: null, latex: '' } : JSON.parse(answer) default: return answer }