Skip to content

Commit 837906a

Browse files
committed
Fix mcq UI
1 parent cb0952e commit 837906a

File tree

3 files changed

+96
-56
lines changed

3 files changed

+96
-56
lines changed

src/utils/messageHandler.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { setWebviewContent } from "./webview";
1212
import { Editor } from "./editor";
1313
import { client } from "../extension";
1414
import _ from "lodash";
15-
import { McqPanelWithLogging as McqPanel } from "../webview/components/McqPanel";
15+
import McqPanel from "../webview/components/McqPanel";
1616

1717
/*
1818
* MessageHandler is a singleton class that handles messages from the frontend

src/webview/components/McqPanel.tsx

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import React, { useState } from "react";
2-
import Messages from "../../utils/messages";
3-
import { sendToFrontendWrapped } from "../../commands/showPanel";
1+
import React from "react";
2+
import markdownToHtml from "../../utils/markdown";
43

54
export interface McqData {
65
assessmentName: string;
@@ -11,60 +10,67 @@ export interface McqData {
1110

1211
interface McqPanelProps {
1312
data: McqData;
14-
onAnswer: (choiceIndex: number) => void;
1513
}
1614

17-
const McqPanel: React.FC<McqPanelProps> = ({ data, onAnswer }) => {
18-
const [selected, setSelected] = useState<number | null>(null);
15+
const panelStyle: React.CSSProperties = {
16+
padding: "2rem",
17+
backgroundColor: "#1e293b",
18+
borderRadius: "0.5rem",
19+
height: "100vh",
20+
width: "100vw",
21+
boxSizing: "border-box",
22+
display: "flex",
23+
alignItems: "center",
24+
justifyContent: "center",
25+
};
1926

20-
return (
21-
<div style={{ padding: "1rem" }}>
22-
<ul style={{ listStyle: "none", paddingLeft: 0 }}>
23-
{data.choices.map((c, idx) => (
24-
<li key={idx} style={{ marginBottom: "0.5rem" }}>
25-
<label style={{ cursor: "pointer" }}>
26-
<input
27-
type="radio"
28-
name="mcq-choice"
29-
value={idx}
30-
data-choice={idx}
31-
data-ws={data.workspaceLocation ?? "assessment"}
32-
data-assessment={data.assessmentName}
33-
data-qid={data.questionId}
34-
checked={selected === idx}
35-
onChange={() => {
36-
setSelected(idx);
37-
onAnswer(idx);
38-
}}
39-
style={{ marginRight: "0.5rem" }}
40-
/>
41-
{c}
42-
</label>
43-
</li>
44-
))}
45-
</ul>
46-
</div>
47-
);
27+
const listStyle: React.CSSProperties = {
28+
listStyle: "none",
29+
paddingLeft: 0,
30+
width: "100%",
31+
maxWidth: "600px",
32+
display: "flex",
33+
flexDirection: "column",
34+
alignItems: "center",
35+
gap: "2rem",
4836
};
4937

50-
export default McqPanel;
38+
const labelBaseStyle: React.CSSProperties = {
39+
display: "block",
40+
width: "100%",
41+
padding: "1.25rem",
42+
backgroundColor: "transparent",
43+
borderRadius: "0.375rem",
44+
cursor: "pointer",
45+
color: "white",
46+
fontSize: "1.25rem",
47+
textAlign: "center",
48+
transition: "background-color 0.3s ease",
49+
border: "1px solid transparent",
50+
};
5151

52-
export const McqPanelWithLogging: React.FC<{ data: McqData }> = ({ data }) => (
53-
<McqPanel
54-
data={data}
55-
onAnswer={(choiceIndex) => {
56-
const wsLoc = data.workspaceLocation ?? "assessment";
57-
console.log(
58-
`MCQ Answer: ${data.assessmentName}, Question ID: ${data.questionId}, Choice Index: ${choiceIndex}`,
59-
);
60-
sendToFrontendWrapped(
61-
Messages.McqAnswer(
62-
wsLoc,
63-
data.assessmentName,
64-
data.questionId,
65-
choiceIndex,
66-
),
67-
);
68-
}}
69-
/>
52+
const McqPanel: React.FC<McqPanelProps> = ({ data }) => (
53+
<div style={panelStyle}>
54+
<ul style={listStyle}>
55+
{data.choices.map((c, idx) => (
56+
<li key={idx} style={{ width: "100%" }}>
57+
<label style={labelBaseStyle}>
58+
<input
59+
type="radio"
60+
name="mcq-choice"
61+
value={idx}
62+
data-choice={idx}
63+
data-ws={data.workspaceLocation ?? "assessment"}
64+
data-assessment={data.assessmentName}
65+
data-qid={data.questionId}
66+
style={{ display: "none" }}
67+
/>
68+
<span dangerouslySetInnerHTML={{ __html: markdownToHtml(c) }} />
69+
</label>
70+
</li>
71+
))}
72+
</ul>
73+
</div>
7074
);
75+
76+
export default McqPanel;

src/webview/components/SourceAcademy.tsx

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,28 @@ const SourceAcademy: React.FC = () => {
6060
}, []);
6161

6262
useEffect(() => {
63+
// TODO: Hacky way to update mcq panel, standard onClick handlers don't work
64+
const highlightSelection = (
65+
assessment: string,
66+
qid: number,
67+
choiceIdx: number,
68+
) => {
69+
const inputs = document.querySelectorAll<HTMLInputElement>(
70+
`input[name="mcq-choice"][data-assessment="${assessment}"][data-qid="${qid}"]`,
71+
);
72+
inputs.forEach((input) => {
73+
const label = input.parentElement as HTMLElement | null;
74+
if (!label) return;
75+
if (parseInt(input.dataset.choice ?? "-1", 10) === choiceIdx) {
76+
label.style.backgroundColor = "#475569";
77+
label.style.border = "1px solid #94a3b8";
78+
} else {
79+
label.style.backgroundColor = "transparent";
80+
label.style.border = "1px solid transparent";
81+
}
82+
});
83+
};
84+
6385
const handleChoiceChange = (e: Event) => {
6486
const target = e.target as HTMLInputElement;
6587
if (!target || target.name !== "mcq-choice") {
@@ -77,6 +99,9 @@ const SourceAcademy: React.FC = () => {
7799
) {
78100
return;
79101
}
102+
103+
highlightSelection(assessmentName, questionId, choice);
104+
80105
console.log("[MCQPanel] choice selected", {
81106
workspaceLocation,
82107
assessmentName,
@@ -89,8 +114,11 @@ const SourceAcademy: React.FC = () => {
89114
`mcq_${assessmentName}_${questionId}`,
90115
String(choice),
91116
);
92-
} catch (e) {
93-
console.warn("[Webview] Failed to save MCQ answer to localStorage", e);
117+
} catch (err) {
118+
console.warn(
119+
"[Webview] Failed to save MCQ answer to localStorage",
120+
err,
121+
);
94122
}
95123

96124
const message = Messages.McqAnswer(
@@ -115,6 +143,12 @@ const SourceAcademy: React.FC = () => {
115143
const stored = localStorage.getItem(`mcq_${assess}_${qid}`);
116144
if (stored !== null && stored === el.dataset.choice) {
117145
el.checked = true;
146+
// apply visual highlight on restore
147+
const label = el.parentElement as HTMLElement | null;
148+
if (label) {
149+
label.style.backgroundColor = "#475569";
150+
label.style.border = "1px solid #94a3b8";
151+
}
118152
}
119153
});
120154
};

0 commit comments

Comments
 (0)