Skip to content

Commit 9699703

Browse files
committed
removed error handling in Prompt, using ErrorBoundary instead in extension
1 parent 3fa6570 commit 9699703

1 file changed

Lines changed: 161 additions & 193 deletions

File tree

client/src/elements/Prompt.jsx

Lines changed: 161 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,161 @@
1-
import {
2-
usePlayer,
3-
useGame,
4-
useStageTimer,
5-
} from "@empirica/core/player/classic/react";
6-
import React from "react";
7-
import { load as loadYaml } from "js-yaml";
8-
import { Markdown } from "../components/Markdown";
9-
import { RadioGroup } from "../components/RadioGroup";
10-
import { CheckboxGroup } from "../components/CheckboxGroup";
11-
import { TextArea } from "../components/TextArea";
12-
import { useText, usePermalink } from "../components/hooks";
13-
import { SharedNotepad } from "../components/SharedNotepad";
14-
import { ListSorter } from "../components/ListSorter";
15-
16-
// Checking equality for two sets - used for setting new responses
17-
function setEquality(a, b) {
18-
if (a.size !== b.size) return false;
19-
for (const item of a) {
20-
if (!b.has(item)) {
21-
return false;
22-
}
23-
}
24-
return true;
25-
}
26-
27-
export function Prompt({ file, name, shared }) {
28-
const player = usePlayer();
29-
const game = useGame();
30-
const stageTimer = useStageTimer();
31-
32-
const progressLabel = player.get("progressLabel");
33-
const { text: promptString, error: fetchError } = useText({ file });
34-
console.log("Text after useText", promptString);
35-
const permalink = usePermalink(file);
36-
37-
const [responses, setResponses] = React.useState([]);
38-
39-
if (fetchError) {
40-
return <p>Error loading prompt, retrying...</p>;
41-
}
42-
43-
if (!promptString) return <p>Loading...</p>;
44-
45-
// Parse the prompt string into its sections
46-
const [, metaDataString, prompt, responseString] =
47-
promptString.split(/^-{3,}$/gm);
48-
49-
// Could maybe extract into a different file, but would require reading from said file
50-
const errorMetadataFormat = `
51-
---
52-
name:
53-
type:
54-
---
55-
56-
Prompt text
57-
58-
---
59-
60-
Response text`;
61-
62-
// Check if each section is present
63-
if (metaDataString === undefined || prompt === undefined || responseString === undefined) {
64-
return (
65-
<>
66-
<p>Error: at least one of metadata, prompt, or response sections are missing. Please verify the formatting of the prompt markdown file with the sample formatting below.</p>
67-
{/* pre to preserve whitespace and newlines */}<pre>{errorMetadataFormat}</pre>
68-
</>);
69-
}
70-
71-
let metaData;
72-
73-
// Handling for YAMLException from loadYaml
74-
try {
75-
metaData = loadYaml(metaDataString);
76-
} catch (e) {
77-
console.log(e);
78-
return (
79-
<>
80-
<p>Error in metadata section of prompt. Please verify that metadata section is correctly formatted as first section of markdown file, following the sample formatting below.</p>
81-
<pre>{errorMetadataFormat}</pre>
82-
</>);
83-
}
84-
85-
const promptType = metaData?.type;
86-
const promptName = name || `${progressLabel}_${metaData?.name || file}`;
87-
const rows = metaData?.rows || 5;
88-
89-
if (promptType !== "noResponse" && responseString.trim() !== '') {
90-
const responseItems = responseString
91-
.split(/\r?\n|\r|\n/g)
92-
.filter((i) => i)
93-
.map((i) => i.substring(2));
94-
95-
// If responses is not initialized or new response items are different from current responses, reset
96-
if (!responses.length || !(setEquality(new Set(responseItems), new Set(responses)))) {
97-
if (metaData?.shuffleOptions) {
98-
setResponses(responseItems.sort(() => 0.5 - Math.random())); // shuffle
99-
} else {
100-
setResponses(responseItems);
101-
}
102-
}
103-
}
104-
105-
const record = {
106-
...metaData,
107-
permalink, // TODO: test permalink in cypress
108-
name: promptName,
109-
shared,
110-
step: progressLabel,
111-
prompt,
112-
responses,
113-
};
114-
115-
// Coordinate saving the data
116-
const saveData = (newValue) => {
117-
record.value = newValue;
118-
const stageElapsed = (stageTimer?.elapsed || 0) / 1000;
119-
record.stageTimeElapsed = stageElapsed;
120-
121-
if (shared) {
122-
game.set(`prompt_${promptName}`, record);
123-
console.log(
124-
`Save game.set(prompt_${promptName}`,
125-
game.get(`prompt_${promptName}`)
126-
);
127-
} else {
128-
player.set(`prompt_${promptName}`, record);
129-
}
130-
};
131-
132-
const value = shared
133-
? game.get(`prompt_${promptName}`)?.value
134-
: player.get(`prompt_${promptName}`)?.value;
135-
136-
return (
137-
<>
138-
<Markdown text={prompt} />
139-
{promptType === "multipleChoice" &&
140-
(metaData.select === "single" || metaData.select === undefined) && (
141-
<RadioGroup
142-
options={responses.map((choice) => ({
143-
key: choice,
144-
value: choice,
145-
}))}
146-
selected={value}
147-
onChange={(e) => saveData(e.target.value)}
148-
testId={metaData?.name}
149-
/>
150-
)}
151-
152-
{promptType === "multipleChoice" && metaData.select === "multiple" && (
153-
<CheckboxGroup
154-
options={responses.map((choice) => ({
155-
key: choice,
156-
value: choice,
157-
}))}
158-
selected={value}
159-
onChange={(newSelection) => saveData(newSelection)}
160-
testId={metaData?.name}
161-
/>
162-
)}
163-
164-
{promptType === "openResponse" && !shared && (
165-
<TextArea
166-
defaultText={responses.join("\n")}
167-
onChange={(e) => saveData(e.target.value)}
168-
value={value}
169-
testId={metaData?.name}
170-
rows={rows}
171-
/>
172-
)}
173-
174-
{promptType === "openResponse" && shared && (
175-
<SharedNotepad
176-
padName={promptName}
177-
defaultText={responses.join("\n")}
178-
record={record}
179-
arg="test"
180-
rows={rows}
181-
/>
182-
)}
183-
184-
{promptType === "listSorter" && (
185-
<ListSorter
186-
list={value || responses}
187-
onChange={(newOrder) => saveData(newOrder)}
188-
testId={metaData?.name}
189-
/>
190-
)}
191-
</>
192-
);
193-
}
1+
import {
2+
usePlayer,
3+
useGame,
4+
useStageTimer,
5+
} from "@empirica/core/player/classic/react";
6+
import React from "react";
7+
import { load as loadYaml } from "js-yaml";
8+
import { Markdown } from "../components/Markdown";
9+
import { RadioGroup } from "../components/RadioGroup";
10+
import { CheckboxGroup } from "../components/CheckboxGroup";
11+
import { TextArea } from "../components/TextArea";
12+
import { useText, usePermalink } from "../components/hooks";
13+
import { SharedNotepad } from "../components/SharedNotepad";
14+
import { ListSorter } from "../components/ListSorter";
15+
16+
// Checking equality for two sets - used for setting new responses
17+
function setEquality(a, b) {
18+
if (a.size !== b.size) return false;
19+
for (const item of a) {
20+
if (!b.has(item)) {
21+
return false;
22+
}
23+
}
24+
return true;
25+
}
26+
27+
export function Prompt({ file, name, shared }) {
28+
const player = usePlayer();
29+
const game = useGame();
30+
const stageTimer = useStageTimer();
31+
32+
const progressLabel = player.get("progressLabel");
33+
const { text: promptString, error: fetchError } = useText({ file });
34+
console.log("Text after useText", promptString);
35+
const permalink = usePermalink(file);
36+
37+
const [responses, setResponses] = React.useState([]);
38+
39+
if (fetchError) {
40+
return <p>Error loading prompt, retrying...</p>;
41+
}
42+
43+
if (!promptString) return <p>Loading...</p>;
44+
45+
// Parse the prompt string into its sections
46+
const [, metaDataString, prompt, responseString] =
47+
promptString.split(/^-{3,}$/gm);
48+
49+
const metaData = loadYaml(metaDataString);
50+
51+
console.log("Prompt info", metaData, metaDataString, prompt, responseString);
52+
53+
const promptType = metaData?.type;
54+
const promptName = name || `${progressLabel}_${metaData?.name || file}`;
55+
const rows = metaData?.rows || 5;
56+
57+
if (promptType !== "noResponse" && responseString.trim() !== '') {
58+
const responseItems = responseString
59+
.split(/\r?\n|\r|\n/g)
60+
.filter((i) => i)
61+
.map((i) => i.substring(2));
62+
63+
// If responses is not initialized or new response items are different from current responses, reset
64+
if (!responses.length || !(setEquality(new Set(responseItems), new Set(responses)))) {
65+
if (metaData?.shuffleOptions) {
66+
setResponses(responseItems.sort(() => 0.5 - Math.random())); // shuffle
67+
} else {
68+
setResponses(responseItems);
69+
}
70+
}
71+
}
72+
73+
const record = {
74+
...metaData,
75+
permalink, // TODO: test permalink in cypress
76+
name: promptName,
77+
shared,
78+
step: progressLabel,
79+
prompt,
80+
responses,
81+
};
82+
83+
// Coordinate saving the data
84+
const saveData = (newValue) => {
85+
record.value = newValue;
86+
const stageElapsed = (stageTimer?.elapsed || 0) / 1000;
87+
record.stageTimeElapsed = stageElapsed;
88+
89+
if (shared) {
90+
game.set(`prompt_${promptName}`, record);
91+
console.log(
92+
`Save game.set(prompt_${promptName}`,
93+
game.get(`prompt_${promptName}`)
94+
);
95+
} else {
96+
player.set(`prompt_${promptName}`, record);
97+
}
98+
};
99+
100+
const value = shared
101+
? game.get(`prompt_${promptName}`)?.value
102+
: player.get(`prompt_${promptName}`)?.value;
103+
104+
return (
105+
<>
106+
<Markdown text={prompt} />
107+
{promptType === "multipleChoice" &&
108+
(metaData.select === "single" || metaData.select === undefined) && (
109+
<RadioGroup
110+
options={responses.map((choice) => ({
111+
key: choice,
112+
value: choice,
113+
}))}
114+
selected={value}
115+
onChange={(e) => saveData(e.target.value)}
116+
testId={metaData?.name}
117+
/>
118+
)}
119+
120+
{promptType === "multipleChoice" && metaData.select === "multiple" && (
121+
<CheckboxGroup
122+
options={responses.map((choice) => ({
123+
key: choice,
124+
value: choice,
125+
}))}
126+
selected={value}
127+
onChange={(newSelection) => saveData(newSelection)}
128+
testId={metaData?.name}
129+
/>
130+
)}
131+
132+
{promptType === "openResponse" && !shared && (
133+
<TextArea
134+
defaultText={responses.join("\n")}
135+
onChange={(e) => saveData(e.target.value)}
136+
value={value}
137+
testId={metaData?.name}
138+
rows={rows}
139+
/>
140+
)}
141+
142+
{promptType === "openResponse" && shared && (
143+
<SharedNotepad
144+
padName={promptName}
145+
defaultText={responses.join("\n")}
146+
record={record}
147+
arg="test"
148+
rows={rows}
149+
/>
150+
)}
151+
152+
{promptType === "listSorter" && (
153+
<ListSorter
154+
list={value || responses}
155+
onChange={(newOrder) => saveData(newOrder)}
156+
testId={metaData?.name}
157+
/>
158+
)}
159+
</>
160+
);
161+
}

0 commit comments

Comments
 (0)