-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathPseudocode.component.tsx
More file actions
136 lines (120 loc) · 4.5 KB
/
Pseudocode.component.tsx
File metadata and controls
136 lines (120 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { foldGutter, foldService, syntaxHighlighting } from '@codemirror/language';
import { EditorState } from '@codemirror/state';
import { placeholder } from '@codemirror/view';
import { EditorView, basicSetup } from 'codemirror';
import { useEffect, useRef, useState } from 'react';
import { BaseResponseAreaProps } from '../base-props.type';
import { PseudocodeFeedbackPanel } from './components/PseudocodeFeedbackPanel';
import { autoIndentAfterColon } from './plugins/autoIndent';
import { pseudocodeFoldFunc } from './plugins/fold';
import { pseudocodeHighlightStyle } from './plugins/highlight';
import { pseudocodeLanguage } from './plugins/language';
import { pseudocodeTheme } from './plugins/pseudocode.theme';
import { StudentResponse } from './types/input';
// import { defaultStudentResponse } from './utils/consts';
import { EvaluationResult } from './types/output';
import { usePseudocodeStyles } from './utils/styles';
type PseudocodeInputProps = Omit<BaseResponseAreaProps, 'handleChange' | 'answer' | 'feedback'> & {
handleChange: (val: StudentResponse) => void;
feedback: EvaluationResult | null;
answer: StudentResponse
};
export const PseudocodeInput: React.FC<PseudocodeInputProps> = ({
handleChange,
feedback,
answer
}) => {
console.log(answer)
const { classes } = usePseudocodeStyles();
// Internal state fully managed in this component
const [internalAnswer, setInternalAnswer] = useState<StudentResponse>(answer);
const editorRef = useRef<HTMLDivElement | null>(null);
const viewRef = useRef<EditorView | null>(null);
// Initialize CodeMirror once
useEffect(() => {
if (!editorRef.current) return;
const state = EditorState.create({
doc: internalAnswer.pseudocode,
extensions: [
foldGutter(),
foldService.of(pseudocodeFoldFunc),
autoIndentAfterColon,
basicSetup,
pseudocodeLanguage,
syntaxHighlighting(pseudocodeHighlightStyle),
pseudocodeTheme,
placeholder('Write your pseudocode here...'),
EditorView.updateListener.of((update) => {
if (!update.docChanged) return;
const newCode = update.state.doc.toString();
setInternalAnswer((prev) => {
const updated = { ...prev, pseudocode: newCode };
handleChange(updated); // notify parent immediately
return updated;
});
}),
EditorView.theme({
'&': { height: '100%' },
'.cm-scroller': { overflow: 'auto' },
}),
],
});
const view = new EditorView({
state,
parent: editorRef.current,
});
viewRef.current = view;
return () => {
view.destroy();
viewRef.current = null;
};
}, []); // only runs once
// Report change for complexity/explanation fields
const handleFieldChange = (field: keyof StudentResponse, value: string) => {
setInternalAnswer((prev) => {
const updated = { ...prev, [field]: value };
handleChange(updated); // immediate update to parent
return updated;
});
};
return (
<div className={classes.root}>
{/* ================= Editor ================= */}
<div className={classes.editorWrapper}>
<div ref={editorRef} className={classes.editor} />
</div>
{/* ================= Complexity Inputs ================= */}
<div className={classes.complexityRow}>
<input
className={classes.field}
value={internalAnswer.time_complexity ?? ''}
placeholder="Time Complexity (e.g. O(n log n))"
onChange={(e) => handleFieldChange('time_complexity', e.target.value)}
/>
<input
className={classes.field}
value={internalAnswer.space_complexity ?? ''}
placeholder="Space Complexity (e.g. O(n))"
onChange={(e) => handleFieldChange('space_complexity', e.target.value)}
/>
</div>
{/* ================= Explanation ================= */}
<textarea
className={classes.textarea}
value={internalAnswer.explanation ?? ''}
placeholder="Explain your reasoning (optional)"
onChange={(e) => handleFieldChange('explanation', e.target.value)}
/>
{/* ================= Action =================
<button onClick={callAPI}>
Check Answer
</button> */}
{/* ================= Feedback ================= */}
{feedback && (
<div className={classes.feedbackPanel}>
<PseudocodeFeedbackPanel result={feedback} />
</div>
)}
</div>
);
};