catchup-library-web 1.20.35 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1056 -823
- package/dist/index.mjs +971 -738
- package/package.json +2 -6
- package/src/components/activities/material-contents/FillInTheBlanksActivityMaterialContent.tsx +62 -2
- package/src/components/activities/material-contents/GroupingActivityMaterialContent.tsx +363 -203
- package/src/components/activities/material-contents/MatchingActivityMaterialContent.tsx +318 -172
- package/src/components/activities/material-contents/OrderingActivityMaterialContent.tsx +76 -2
- package/src/components/activities/material-contents/FillInTheBlanksActivityMaterialContent2.tsx +0 -306
- package/src/components/activities/material-contents/OrderingActivityMaterialContent2.tsx +0 -231
- package/src/components/dnds/DraggableDroppableItem.tsx +0 -60
- package/src/components/dnds/DraggableItem.tsx +0 -39
- package/src/components/dnds/DroppableItem.tsx +0 -33
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { useDrop } from "react-dnd";
|
|
3
2
|
import ShowMaterialMediaByContentType from "./ShowMaterialMediaByContentType";
|
|
4
3
|
import { InlineMath } from "react-katex";
|
|
5
4
|
import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
|
|
6
5
|
import DividerLine from "../../dividers/DividerLine";
|
|
7
6
|
import { IGroupingActivityMaterialProps } from "../../../properties/ActivityProperties";
|
|
8
|
-
import DraggableItem from "../../dnds/DraggableItem";
|
|
9
|
-
import DroppableItem from "../../dnds/DroppableItem";
|
|
10
7
|
|
|
11
8
|
const GroupingActivityMaterialContent = ({
|
|
12
9
|
uniqueValue,
|
|
@@ -18,17 +15,22 @@ const GroupingActivityMaterialContent = ({
|
|
|
18
15
|
isPreview,
|
|
19
16
|
showCorrectAnswer,
|
|
20
17
|
}: IGroupingActivityMaterialProps) => {
|
|
21
|
-
const [selectedValue, setSelectedValue] = useState(null);
|
|
22
|
-
const [
|
|
18
|
+
const [selectedValue, setSelectedValue] = useState<string | null>(null);
|
|
19
|
+
const [draggedValue, setDraggedValue] = useState<string | null>(null);
|
|
20
|
+
const [dropTargetKey, setDropTargetKey] = useState<string | null>(null);
|
|
21
|
+
const [draggedElement, setDraggedElement] = useState<HTMLElement | null>(
|
|
22
|
+
null
|
|
23
|
+
);
|
|
23
24
|
const [isShuffled, setIsShuffled] = useState(false);
|
|
24
|
-
const [shuffledMaterialList, setShuffledMaterialList] = useState([]);
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
const [shuffledMaterialList, setShuffledMaterialList] = useState<any[]>([]);
|
|
26
|
+
const dragElementRef = useRef<HTMLDivElement>(null);
|
|
27
|
+
const [mousePosition, setMousePosition] = useState<{ x: number; y: number }>({
|
|
28
|
+
x: 0,
|
|
29
|
+
y: 0,
|
|
30
|
+
});
|
|
31
|
+
const [touchPosition, setTouchPosition] = useState<{ x: number; y: number }>({
|
|
32
|
+
x: 0,
|
|
33
|
+
y: 0,
|
|
32
34
|
});
|
|
33
35
|
const ref = useRef<HTMLDivElement>(null);
|
|
34
36
|
|
|
@@ -52,14 +54,14 @@ const GroupingActivityMaterialContent = ({
|
|
|
52
54
|
}
|
|
53
55
|
});
|
|
54
56
|
setShuffledMaterialList(shuffleArray(materialList));
|
|
55
|
-
}, []);
|
|
57
|
+
}, [materialMap, isShuffled]);
|
|
56
58
|
|
|
57
59
|
useEffect(() => {
|
|
58
60
|
if (!showCorrectAnswer) return;
|
|
59
61
|
answer.data.find(
|
|
60
62
|
(answerData: any) => answerData.type === "GROUPING"
|
|
61
63
|
).answerMap = materialMap;
|
|
62
|
-
}, [showCorrectAnswer]);
|
|
64
|
+
}, [showCorrectAnswer, answer, materialMap]);
|
|
63
65
|
|
|
64
66
|
const retrieveAnswerMap = () => {
|
|
65
67
|
const foundIndex = answer.data.findIndex(
|
|
@@ -96,12 +98,99 @@ const GroupingActivityMaterialContent = ({
|
|
|
96
98
|
return "INCORRECT";
|
|
97
99
|
};
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
// Mouse drag handlers
|
|
102
|
+
const handleMouseDown = (
|
|
103
|
+
e: React.MouseEvent,
|
|
104
|
+
materialValue: string
|
|
105
|
+
): void => {
|
|
106
|
+
if (!checkCanAnswerQuestion()) return;
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
setDraggedValue(materialValue);
|
|
109
|
+
setSelectedValue(null);
|
|
110
|
+
setMousePosition({ x: e.clientX, y: e.clientY });
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const handleMouseMove = (e: React.MouseEvent): void => {
|
|
114
|
+
if (!draggedValue) return;
|
|
115
|
+
|
|
116
|
+
setMousePosition({ x: e.clientX, y: e.clientY });
|
|
117
|
+
|
|
118
|
+
// Find the element under the mouse point
|
|
119
|
+
const elementUnder = document.elementFromPoint(e.clientX, e.clientY);
|
|
120
|
+
const dropZone = elementUnder?.closest("[data-grouping-drop-zone]");
|
|
121
|
+
|
|
122
|
+
if (dropZone) {
|
|
123
|
+
const dropKey = dropZone.getAttribute("data-grouping-drop-zone");
|
|
124
|
+
setDropTargetKey(dropKey);
|
|
125
|
+
} else {
|
|
126
|
+
setDropTargetKey(null);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const handleMouseUp = (): void => {
|
|
131
|
+
if (dropTargetKey !== null && draggedValue !== null) {
|
|
132
|
+
onChange(answer, dropTargetKey, draggedValue, null);
|
|
133
|
+
}
|
|
134
|
+
setDraggedValue(null);
|
|
135
|
+
setDropTargetKey(null);
|
|
136
|
+
setMousePosition({ x: 0, y: 0 });
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Touch drag handlers
|
|
140
|
+
const handleTouchStart = (
|
|
141
|
+
e: React.TouchEvent,
|
|
142
|
+
materialValue: string,
|
|
143
|
+
element: HTMLElement
|
|
144
|
+
): void => {
|
|
145
|
+
if (!checkCanAnswerQuestion()) return;
|
|
146
|
+
const touch = e.touches[0];
|
|
147
|
+
setDraggedValue(materialValue);
|
|
148
|
+
setDraggedElement(element);
|
|
149
|
+
setTouchPosition({ x: touch.clientX, y: touch.clientY });
|
|
150
|
+
setSelectedValue(null);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const handleTouchMove = (e: React.TouchEvent): void => {
|
|
154
|
+
if (!draggedValue) return;
|
|
155
|
+
|
|
156
|
+
const touch = e.touches[0];
|
|
157
|
+
setTouchPosition({ x: touch.clientX, y: touch.clientY });
|
|
158
|
+
|
|
159
|
+
// Find the element under the touch point
|
|
160
|
+
const elementUnder = document.elementFromPoint(
|
|
161
|
+
touch.clientX,
|
|
162
|
+
touch.clientY
|
|
163
|
+
);
|
|
164
|
+
const dropZone = elementUnder?.closest("[data-grouping-drop-zone]");
|
|
165
|
+
|
|
166
|
+
if (dropZone) {
|
|
167
|
+
const dropKey = dropZone.getAttribute("data-grouping-drop-zone");
|
|
168
|
+
setDropTargetKey(dropKey);
|
|
169
|
+
} else {
|
|
170
|
+
setDropTargetKey(null);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const handleTouchEnd = (): void => {
|
|
175
|
+
if (dropTargetKey !== null && draggedValue !== null) {
|
|
176
|
+
onChange(answer, dropTargetKey, draggedValue, null);
|
|
177
|
+
}
|
|
178
|
+
setDraggedValue(null);
|
|
179
|
+
setDropTargetKey(null);
|
|
180
|
+
setDraggedElement(null);
|
|
181
|
+
setTouchPosition({ x: 0, y: 0 });
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Click/tap to select (for easier mobile interaction)
|
|
185
|
+
const handleSelectItem = (materialValue: string): void => {
|
|
186
|
+
if (!checkCanAnswerQuestion()) return;
|
|
187
|
+
setSelectedValue(materialValue);
|
|
188
|
+
setDraggedValue(null);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const handleDropZoneClick = (answerMapKey: string): void => {
|
|
192
|
+
if (selectedValue !== null) {
|
|
193
|
+
onChange(answer, answerMapKey, selectedValue, null);
|
|
105
194
|
setSelectedValue(null);
|
|
106
195
|
}
|
|
107
196
|
};
|
|
@@ -110,90 +199,170 @@ const GroupingActivityMaterialContent = ({
|
|
|
110
199
|
const filteredMaterialList = retrieveFilteredMaterialList(answerMap);
|
|
111
200
|
|
|
112
201
|
return (
|
|
113
|
-
|
|
202
|
+
<div onMouseMove={handleMouseMove} onMouseUp={handleMouseUp}>
|
|
203
|
+
{/* Floating drag preview for mouse */}
|
|
204
|
+
{draggedValue && mousePosition.x > 0 && (
|
|
205
|
+
<div
|
|
206
|
+
className="fixed pointer-events-none z-50 opacity-80"
|
|
207
|
+
style={{
|
|
208
|
+
left: `${mousePosition.x}px`,
|
|
209
|
+
top: `${mousePosition.y}px`,
|
|
210
|
+
transform: "translate(-50%, -50%)",
|
|
211
|
+
}}
|
|
212
|
+
>
|
|
213
|
+
{contentMap.type === "TEXT" ? (
|
|
214
|
+
<div className="border-catchup-blue border-2 rounded-catchup-xlarge bg-white shadow-lg">
|
|
215
|
+
<div className="flex flex-col items-center justify-center m-2 min-w-[200px]">
|
|
216
|
+
<p className="text-xl text-center whitespace-pre-wrap">
|
|
217
|
+
{constructInputWithSpecialExpressionList(draggedValue).map(
|
|
218
|
+
(inputPart, index) => (
|
|
219
|
+
<span
|
|
220
|
+
key={index}
|
|
221
|
+
className={`${inputPart.isBold ? "font-bold" : ""} ${
|
|
222
|
+
inputPart.isUnderline ? "underline" : ""
|
|
223
|
+
}`}
|
|
224
|
+
>
|
|
225
|
+
{inputPart.isEquation ? (
|
|
226
|
+
<span className="text-2xl">
|
|
227
|
+
<InlineMath math={inputPart.value} />
|
|
228
|
+
</span>
|
|
229
|
+
) : (
|
|
230
|
+
inputPart.value
|
|
231
|
+
)}
|
|
232
|
+
</span>
|
|
233
|
+
)
|
|
234
|
+
)}
|
|
235
|
+
</p>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
) : (
|
|
239
|
+
<div className="border-catchup-blue border-2 rounded-catchup-xlarge bg-white shadow-lg">
|
|
240
|
+
<ShowMaterialMediaByContentType
|
|
241
|
+
key={`${uniqueValue}-drag-mouse`}
|
|
242
|
+
contentType={contentMap.type}
|
|
243
|
+
src={draggedValue}
|
|
244
|
+
canFullScreen={false}
|
|
245
|
+
/>
|
|
246
|
+
</div>
|
|
247
|
+
)}
|
|
248
|
+
</div>
|
|
249
|
+
)}
|
|
250
|
+
|
|
251
|
+
{/* Floating drag preview for touch */}
|
|
252
|
+
{draggedValue && touchPosition.x > 0 && (
|
|
253
|
+
<div
|
|
254
|
+
className="fixed pointer-events-none z-50 opacity-80"
|
|
255
|
+
style={{
|
|
256
|
+
left: `${touchPosition.x}px`,
|
|
257
|
+
top: `${touchPosition.y}px`,
|
|
258
|
+
transform: "translate(-50%, -50%)",
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
{contentMap.type === "TEXT" ? (
|
|
262
|
+
<div className="border-catchup-blue border-2 rounded-catchup-xlarge bg-white shadow-lg">
|
|
263
|
+
<div className="flex flex-col items-center justify-center m-2 min-w-[200px]">
|
|
264
|
+
<p className="text-xl text-center whitespace-pre-wrap">
|
|
265
|
+
{constructInputWithSpecialExpressionList(draggedValue).map(
|
|
266
|
+
(inputPart, index) => (
|
|
267
|
+
<span
|
|
268
|
+
key={index}
|
|
269
|
+
className={`${inputPart.isBold ? "font-bold" : ""} ${
|
|
270
|
+
inputPart.isUnderline ? "underline" : ""
|
|
271
|
+
}`}
|
|
272
|
+
>
|
|
273
|
+
{inputPart.isEquation ? (
|
|
274
|
+
<span className="text-2xl">
|
|
275
|
+
<InlineMath math={inputPart.value} />
|
|
276
|
+
</span>
|
|
277
|
+
) : (
|
|
278
|
+
inputPart.value
|
|
279
|
+
)}
|
|
280
|
+
</span>
|
|
281
|
+
)
|
|
282
|
+
)}
|
|
283
|
+
</p>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
) : (
|
|
287
|
+
<div className="border-catchup-blue border-2 rounded-catchup-xlarge bg-white shadow-lg">
|
|
288
|
+
<ShowMaterialMediaByContentType
|
|
289
|
+
key={`${uniqueValue}-drag-touch`}
|
|
290
|
+
contentType={contentMap.type}
|
|
291
|
+
src={draggedValue}
|
|
292
|
+
canFullScreen={false}
|
|
293
|
+
/>
|
|
294
|
+
</div>
|
|
295
|
+
)}
|
|
296
|
+
</div>
|
|
297
|
+
)}
|
|
298
|
+
|
|
114
299
|
{filteredMaterialList.length > 0 ? (
|
|
115
300
|
<>
|
|
116
301
|
<div className="flex-1 flex flex-row gap-x-4 overflow-x-auto py-2">
|
|
117
302
|
{filteredMaterialList.map((materialValue, index) => {
|
|
118
303
|
return (
|
|
119
|
-
<
|
|
304
|
+
<div
|
|
120
305
|
key={index}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
: "h-catchup-activity-media-box-item"
|
|
133
|
-
} flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer transition-all duration-300`}
|
|
134
|
-
onMouseDown={() => {
|
|
135
|
-
if (checkCanAnswerQuestion()) {
|
|
136
|
-
setSelectedValue(materialValue);
|
|
137
|
-
}
|
|
138
|
-
}}
|
|
139
|
-
onTouchEnd={() => {
|
|
140
|
-
if (checkCanAnswerQuestion()) {
|
|
141
|
-
setSelectedValue(materialValue);
|
|
142
|
-
}
|
|
143
|
-
}}
|
|
144
|
-
onMouseUp={() => {
|
|
145
|
-
if (checkCanAnswerQuestion()) {
|
|
146
|
-
setSelectedValue(null);
|
|
147
|
-
}
|
|
148
|
-
}}
|
|
149
|
-
onTouchStart={() => {
|
|
150
|
-
if (checkCanAnswerQuestion()) {
|
|
151
|
-
setSelectedValue(null);
|
|
152
|
-
}
|
|
153
|
-
}}
|
|
154
|
-
>
|
|
155
|
-
{contentMap.type === "TEXT" ? (
|
|
156
|
-
<div className="flex flex-col items-center justify-center m-2 min-w-[200px] overflow-y-auto">
|
|
157
|
-
<p className="text-xl text-center whitespace-pre-wrap">
|
|
158
|
-
{constructInputWithSpecialExpressionList(
|
|
159
|
-
materialValue
|
|
160
|
-
).map((inputPart, index) => (
|
|
161
|
-
<span
|
|
162
|
-
key={index}
|
|
163
|
-
className={`${
|
|
164
|
-
inputPart.isBold ? "font-bold" : ""
|
|
165
|
-
} ${inputPart.isUnderline ? "underline" : ""}`}
|
|
166
|
-
>
|
|
167
|
-
{inputPart.isEquation ? (
|
|
168
|
-
<span className="text-2xl">
|
|
169
|
-
<InlineMath math={inputPart.value} />
|
|
170
|
-
</span>
|
|
171
|
-
) : (
|
|
172
|
-
inputPart.value
|
|
173
|
-
)}
|
|
174
|
-
</span>
|
|
175
|
-
))}
|
|
176
|
-
</p>
|
|
177
|
-
</div>
|
|
178
|
-
) : (
|
|
179
|
-
<ShowMaterialMediaByContentType
|
|
180
|
-
key={`${uniqueValue}-${index}`}
|
|
181
|
-
contentType={contentMap.type}
|
|
182
|
-
src={materialValue}
|
|
183
|
-
canFullScreen={true}
|
|
184
|
-
/>
|
|
185
|
-
)}
|
|
186
|
-
</div>
|
|
306
|
+
ref={draggedValue === materialValue ? dragElementRef : null}
|
|
307
|
+
className={`${
|
|
308
|
+
draggedValue === materialValue
|
|
309
|
+
? "opacity-40"
|
|
310
|
+
: selectedValue === materialValue
|
|
311
|
+
? "ring-2 ring-blue-500"
|
|
312
|
+
: "opacity-100"
|
|
313
|
+
} transition-all duration-200`}
|
|
314
|
+
onMouseDown={(e) => handleMouseDown(e, materialValue)}
|
|
315
|
+
onTouchStart={(e) =>
|
|
316
|
+
handleTouchStart(e, materialValue, e.currentTarget)
|
|
187
317
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
selectedValue
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
318
|
+
onTouchMove={handleTouchMove}
|
|
319
|
+
onTouchEnd={handleTouchEnd}
|
|
320
|
+
>
|
|
321
|
+
<div
|
|
322
|
+
className={`${
|
|
323
|
+
selectedValue === materialValue
|
|
324
|
+
? "border-catchup-blue"
|
|
325
|
+
: "border-catchup-lighter-gray"
|
|
326
|
+
} ${
|
|
327
|
+
contentMap.type === "TEXT"
|
|
328
|
+
? "h-catchup-activity-text-box-item"
|
|
329
|
+
: "h-catchup-activity-media-box-item"
|
|
330
|
+
} flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer transition-all duration-300`}
|
|
331
|
+
onClick={() => handleSelectItem(materialValue)}
|
|
332
|
+
>
|
|
333
|
+
{contentMap.type === "TEXT" ? (
|
|
334
|
+
<div className="flex flex-col items-center justify-center m-2 min-w-[200px] overflow-y-auto">
|
|
335
|
+
<p className="text-xl text-center whitespace-pre-wrap">
|
|
336
|
+
{constructInputWithSpecialExpressionList(
|
|
337
|
+
materialValue
|
|
338
|
+
).map((inputPart, index) => (
|
|
339
|
+
<span
|
|
340
|
+
key={index}
|
|
341
|
+
className={`${
|
|
342
|
+
inputPart.isBold ? "font-bold" : ""
|
|
343
|
+
} ${inputPart.isUnderline ? "underline" : ""}`}
|
|
344
|
+
>
|
|
345
|
+
{inputPart.isEquation ? (
|
|
346
|
+
<span className="text-2xl">
|
|
347
|
+
<InlineMath math={inputPart.value} />
|
|
348
|
+
</span>
|
|
349
|
+
) : (
|
|
350
|
+
inputPart.value
|
|
351
|
+
)}
|
|
352
|
+
</span>
|
|
353
|
+
))}
|
|
354
|
+
</p>
|
|
355
|
+
</div>
|
|
356
|
+
) : (
|
|
357
|
+
<ShowMaterialMediaByContentType
|
|
358
|
+
key={`${uniqueValue}-${index}`}
|
|
359
|
+
contentType={contentMap.type}
|
|
360
|
+
src={materialValue}
|
|
361
|
+
canFullScreen={true}
|
|
362
|
+
/>
|
|
363
|
+
)}
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
197
366
|
);
|
|
198
367
|
})}
|
|
199
368
|
</div>
|
|
@@ -239,123 +408,114 @@ const GroupingActivityMaterialContent = ({
|
|
|
239
408
|
<div className="flex-1 min-w-0" ref={ref}>
|
|
240
409
|
<div className="h-full py-3">
|
|
241
410
|
<div
|
|
411
|
+
data-grouping-drop-zone={answerMapKey}
|
|
412
|
+
onMouseEnter={() =>
|
|
413
|
+
draggedValue && setDropTargetKey(answerMapKey)
|
|
414
|
+
}
|
|
415
|
+
onMouseLeave={() => setDropTargetKey(null)}
|
|
416
|
+
onClick={() => handleDropZoneClick(answerMapKey)}
|
|
242
417
|
className={`${
|
|
243
|
-
|
|
244
|
-
?
|
|
245
|
-
? "bg-catchup-light-blue"
|
|
246
|
-
: "bg-catchup-light-blue opacity-40"
|
|
418
|
+
dropTargetKey === answerMapKey
|
|
419
|
+
? "bg-catchup-light-blue ring-2 ring-blue-400"
|
|
247
420
|
: ""
|
|
248
|
-
} flex-1 border-catchup-blue rounded-catchup-xlarge border-2 h-full p-1`}
|
|
421
|
+
} flex-1 border-catchup-blue rounded-catchup-xlarge border-2 h-full p-1 transition-all duration-200`}
|
|
249
422
|
>
|
|
250
|
-
<
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
} ${
|
|
315
|
-
inputPart.isUnderline
|
|
316
|
-
? "underline"
|
|
317
|
-
: ""
|
|
318
|
-
}`}
|
|
319
|
-
>
|
|
320
|
-
{inputPart.isEquation ? (
|
|
321
|
-
<span className="text-2xl">
|
|
322
|
-
<InlineMath
|
|
323
|
-
math={inputPart.value}
|
|
324
|
-
/>
|
|
325
|
-
</span>
|
|
326
|
-
) : (
|
|
327
|
-
inputPart.value
|
|
328
|
-
)}
|
|
423
|
+
<div className="h-full w-full overflow-x-auto">
|
|
424
|
+
<div className="flex flex-row items-center gap-2 w-max h-full">
|
|
425
|
+
{answerMap[answerMapKey].map(
|
|
426
|
+
(answerMapValue: string, answerMapIndex: number) => {
|
|
427
|
+
const learnerAnswerState = checkAnswerState(
|
|
428
|
+
materialMap[answerMapKey],
|
|
429
|
+
answerMapValue
|
|
430
|
+
);
|
|
431
|
+
return (
|
|
432
|
+
<div key={answerMapIndex} className="p-1">
|
|
433
|
+
<div
|
|
434
|
+
className={`${
|
|
435
|
+
contentMap.type === "TEXT"
|
|
436
|
+
? "h-catchup-activity-text-box-item"
|
|
437
|
+
: "h-catchup-activity-media-box-item"
|
|
438
|
+
}`}
|
|
439
|
+
>
|
|
440
|
+
<div
|
|
441
|
+
className={`${
|
|
442
|
+
learnerAnswerState === "EMPTY"
|
|
443
|
+
? "border-catchup-lighter-gray"
|
|
444
|
+
: learnerAnswerState === "CORRECT"
|
|
445
|
+
? "border-catchup-green"
|
|
446
|
+
: learnerAnswerState === "INCORRECT"
|
|
447
|
+
? "border-catchup-red"
|
|
448
|
+
: "border-catchup-blue"
|
|
449
|
+
} border-2 rounded-catchup-xlarge h-full flex flex-col items-center justify-center transition-all duration-300 cursor-pointer`}
|
|
450
|
+
onClick={(e) => {
|
|
451
|
+
e.stopPropagation();
|
|
452
|
+
if (checkCanAnswerQuestion()) {
|
|
453
|
+
onChange(
|
|
454
|
+
answer,
|
|
455
|
+
answerMapKey,
|
|
456
|
+
null,
|
|
457
|
+
answerMapIndex
|
|
458
|
+
);
|
|
459
|
+
setSelectedValue(null);
|
|
460
|
+
}
|
|
461
|
+
}}
|
|
462
|
+
>
|
|
463
|
+
{contentMap.type === "TEXT" ? (
|
|
464
|
+
<div className="flex flex-col items-center justify-center transition-all duration-300 min-w-[200px] overflow-y-auto">
|
|
465
|
+
<div className="m-2">
|
|
466
|
+
<p className="text-xl text-center whitespace-pre-wrap">
|
|
467
|
+
{constructInputWithSpecialExpressionList(
|
|
468
|
+
answerMapValue
|
|
469
|
+
).map((inputPart, index) => (
|
|
470
|
+
<span
|
|
471
|
+
key={index}
|
|
472
|
+
className={`${
|
|
473
|
+
inputPart.isBold
|
|
474
|
+
? "font-bold"
|
|
475
|
+
: ""
|
|
476
|
+
} ${
|
|
477
|
+
inputPart.isUnderline
|
|
478
|
+
? "underline"
|
|
479
|
+
: ""
|
|
480
|
+
}`}
|
|
481
|
+
>
|
|
482
|
+
{inputPart.isEquation ? (
|
|
483
|
+
<span className="text-2xl">
|
|
484
|
+
<InlineMath
|
|
485
|
+
math={inputPart.value}
|
|
486
|
+
/>
|
|
329
487
|
</span>
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
contentType={contentMap.type}
|
|
338
|
-
src={answerMapValue}
|
|
339
|
-
canFullScreen={false}
|
|
340
|
-
/>
|
|
341
|
-
)}
|
|
488
|
+
) : (
|
|
489
|
+
inputPart.value
|
|
490
|
+
)}
|
|
491
|
+
</span>
|
|
492
|
+
))}
|
|
493
|
+
</p>
|
|
494
|
+
</div>
|
|
342
495
|
</div>
|
|
343
|
-
|
|
496
|
+
) : (
|
|
497
|
+
<ShowMaterialMediaByContentType
|
|
498
|
+
key={`${uniqueValue}-${answerMapIndex}`}
|
|
499
|
+
contentType={contentMap.type}
|
|
500
|
+
src={answerMapValue}
|
|
501
|
+
canFullScreen={false}
|
|
502
|
+
/>
|
|
503
|
+
)}
|
|
344
504
|
</div>
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
505
|
+
</div>
|
|
506
|
+
</div>
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
)}
|
|
510
|
+
</div>
|
|
511
|
+
</div>
|
|
352
512
|
</div>
|
|
353
513
|
</div>
|
|
354
514
|
</div>
|
|
355
515
|
</div>
|
|
356
516
|
))}
|
|
357
517
|
</div>
|
|
358
|
-
|
|
518
|
+
</div>
|
|
359
519
|
);
|
|
360
520
|
};
|
|
361
521
|
|