catchup-library-web 1.19.0 → 1.20.1
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.d.mts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +278 -327
- package/dist/index.mjs +298 -347
- package/package.json +1 -1
- package/src/components/activities/ActivityPreviewByAnswerData.tsx +3 -3
- package/src/components/activities/ActivityPreviewByData.tsx +3 -4
- package/src/components/activities/DropdownActivityContent.tsx +3 -9
- package/src/components/activities/FillInTheBlanksActivityContent.tsx +4 -10
- package/src/components/activities/GroupingActivityContent.tsx +3 -3
- package/src/components/activities/MCMAActivityContent.tsx +3 -2
- package/src/components/activities/MCSAActivityContent.tsx +3 -2
- package/src/components/activities/MatchingActivityContent.tsx +3 -3
- package/src/components/activities/OpenEndedActivityContent.tsx +4 -2
- package/src/components/activities/OrderingActivityContent.tsx +3 -2
- package/src/components/activities/TrueFalseActivityContent.tsx +3 -2
- package/src/components/activities/{body-content → body-contents}/ShowBodyMediaByContentType.tsx +1 -1
- package/src/components/activities/{evaluation-rubric-content → evaluation-rubric-contents}/ActivityEvaluationRubricContent.tsx +1 -1
- package/src/components/activities/{material-content → material-contents}/DropdownActivityMaterialContent.tsx +3 -3
- package/src/components/activities/{material-content → material-contents}/FillInTheBlanksActivityMaterialContent.tsx +2 -2
- package/src/components/activities/material-contents/GroupingActivityMaterialContent.tsx +354 -0
- package/src/components/activities/{material-content → material-contents}/MCMAActivityMaterialContent.tsx +2 -2
- package/src/components/activities/{material-content → material-contents}/MCSAActivityMaterialContent.tsx +2 -2
- package/src/components/activities/material-contents/MatchingActivityMaterialContent.tsx +342 -0
- package/src/components/activities/{material-content → material-contents}/OrderingActivityMaterialContent.tsx +9 -7
- package/src/components/activities/{material-content → material-contents}/ShowMaterialMediaByContentType.tsx +6 -6
- package/src/components/activities/{material-content → material-contents}/TrueFalseActivityMaterialContent.tsx +1 -1
- package/src/components/activities/{solution-content → solution-contents}/ActivitySolutionContent.tsx +1 -1
- package/src/index.ts +4 -4
- package/src/properties/ActivityProperties.ts +1 -2
- package/src/components/activities/material-content/GroupingActivityMaterialContent.tsx +0 -359
- package/src/components/activities/material-content/MatchingActivityMaterialContent.tsx +0 -332
- /package/src/components/activities/{body-content → body-contents}/ActivityBodyContent.tsx +0 -0
- /package/src/components/activities/{empty-content → empty-contents}/ActivityEmptyContent.tsx +0 -0
- /package/src/components/activities/{material-content → material-contents}/OpenEndedActivityMaterialContent.tsx +0 -0
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { useDrop } from "react-dnd";
|
|
3
|
-
import ShowMaterialMediaByContentType from "./ShowMaterialMediaByContentType";
|
|
4
|
-
import { InlineMath } from "react-katex";
|
|
5
|
-
import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
|
|
6
|
-
import DividerLine from "../../dividers/DividerLine";
|
|
7
|
-
import { IGroupingActivityMaterialProps } from "../../../properties/ActivityProperties";
|
|
8
|
-
import DraggableItem from "../../dnds/DraggableItem";
|
|
9
|
-
import DroppableItem from "../../dnds/DroppableItem";
|
|
10
|
-
import useScreenSize from "../../../hooks/useScreenSize";
|
|
11
|
-
|
|
12
|
-
const GroupingActivityMaterialContent = ({
|
|
13
|
-
uniqueValue,
|
|
14
|
-
answer,
|
|
15
|
-
materialMap,
|
|
16
|
-
contentMap,
|
|
17
|
-
checkCanAnswerQuestion,
|
|
18
|
-
onChange,
|
|
19
|
-
isPreview,
|
|
20
|
-
showCorrectAnswer,
|
|
21
|
-
}: IGroupingActivityMaterialProps) => {
|
|
22
|
-
const [selectedValue, setSelectedValue] = useState(null);
|
|
23
|
-
const [selectedTargetKey, setSelectedTargetKey] = useState(null);
|
|
24
|
-
const [isShuffled, setIsShuffled] = useState(false);
|
|
25
|
-
const [shuffledMaterialList, setShuffledMaterialList] = useState([]);
|
|
26
|
-
const { screenSize, containerSize } = useScreenSize();
|
|
27
|
-
const [{ isOver, canDrop }, drop] = useDrop({
|
|
28
|
-
accept: "GROUPING",
|
|
29
|
-
drop: () => {},
|
|
30
|
-
collect: (monitor: any) => ({
|
|
31
|
-
isOver: monitor.isOver(),
|
|
32
|
-
canDrop: monitor.canDrop(),
|
|
33
|
-
}),
|
|
34
|
-
});
|
|
35
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
36
|
-
const itemsRef = useRef<HTMLDivElement>(null);
|
|
37
|
-
const [maxWidth, setMaxWidth] = useState<number>(0);
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
if (!ref) return;
|
|
41
|
-
if (!ref.current) return;
|
|
42
|
-
if (!screenSize) return;
|
|
43
|
-
setMaxWidth(ref.current.offsetWidth - 12);
|
|
44
|
-
}, [ref, screenSize]);
|
|
45
|
-
|
|
46
|
-
// useEffect(() => {
|
|
47
|
-
// if (!itemsRef) return;
|
|
48
|
-
// if (!itemsRef.current) return;
|
|
49
|
-
// if (!containerSize) return;
|
|
50
|
-
// itemsRef.current.style.width = `${containerSize.width - 200}px`;
|
|
51
|
-
// }, [itemsRef, containerSize]);
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const shuffleArray = (array: any) => {
|
|
55
|
-
if (!isShuffled) {
|
|
56
|
-
const copyArray = JSON.parse(JSON.stringify(array));
|
|
57
|
-
for (let i = copyArray.length - 1; i > 0; i--) {
|
|
58
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
59
|
-
[copyArray[i], copyArray[j]] = [copyArray[j], copyArray[i]];
|
|
60
|
-
}
|
|
61
|
-
setIsShuffled(true);
|
|
62
|
-
return copyArray;
|
|
63
|
-
}
|
|
64
|
-
return array;
|
|
65
|
-
};
|
|
66
|
-
const materialList: any = [];
|
|
67
|
-
Object.keys(materialMap).forEach((materialKey) => {
|
|
68
|
-
for (const materialValue of materialMap[materialKey]) {
|
|
69
|
-
materialList.push(materialValue);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
setShuffledMaterialList(shuffleArray(materialList));
|
|
73
|
-
}, []);
|
|
74
|
-
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (!showCorrectAnswer) return;
|
|
77
|
-
answer.data.find(
|
|
78
|
-
(answerData: any) => answerData.type === "GROUPING"
|
|
79
|
-
).answerMap = materialMap;
|
|
80
|
-
}, [showCorrectAnswer]);
|
|
81
|
-
|
|
82
|
-
const retrieveAnswerMap = () => {
|
|
83
|
-
const foundIndex = answer.data.findIndex(
|
|
84
|
-
(answerData: any) => answerData.type === "GROUPING"
|
|
85
|
-
);
|
|
86
|
-
const answerMap = answer.data[foundIndex].answerMap;
|
|
87
|
-
return answerMap;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const retrieveFilteredMaterialList = (answerMap: any) => {
|
|
91
|
-
const selectedValueList: any = [];
|
|
92
|
-
Object.keys(answerMap).forEach((key) => {
|
|
93
|
-
answerMap[key].forEach((value: string) => {
|
|
94
|
-
selectedValueList.push(value);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
return shuffledMaterialList.filter(
|
|
98
|
-
(material) =>
|
|
99
|
-
selectedValueList.findIndex((value: string) => material === value) ===
|
|
100
|
-
-1
|
|
101
|
-
);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const checkAnswerState = (correctAnswerList: any, learnerAnswer: string) => {
|
|
105
|
-
if (!isPreview) return null;
|
|
106
|
-
if (!learnerAnswer) return "EMPTY";
|
|
107
|
-
if (!correctAnswerList) return "EMPTY";
|
|
108
|
-
const foundIndex = correctAnswerList.findIndex(
|
|
109
|
-
(correctAnswer: string) => correctAnswer === learnerAnswer
|
|
110
|
-
);
|
|
111
|
-
if (foundIndex !== -1) {
|
|
112
|
-
return "CORRECT";
|
|
113
|
-
}
|
|
114
|
-
return "INCORRECT";
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const handleGroupingActivityItemOnChange = (
|
|
118
|
-
selectedTargetKey: string,
|
|
119
|
-
selectedValue: string
|
|
120
|
-
) => {
|
|
121
|
-
if (checkCanAnswerQuestion()) {
|
|
122
|
-
onChange(answer, selectedTargetKey, selectedValue, null);
|
|
123
|
-
setSelectedValue(null);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const answerMap = retrieveAnswerMap();
|
|
128
|
-
const filteredMaterialList = retrieveFilteredMaterialList(answerMap);
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<>
|
|
132
|
-
<div
|
|
133
|
-
ref={itemsRef}
|
|
134
|
-
className="flex-1 flex flex-row gap-x-4 gap-y-4 overflow-auto py-2"
|
|
135
|
-
>
|
|
136
|
-
{filteredMaterialList.map((materialValue, index) => {
|
|
137
|
-
return (
|
|
138
|
-
<DraggableItem
|
|
139
|
-
key={index}
|
|
140
|
-
item={{ index: materialValue }}
|
|
141
|
-
type={"GROUPING"}
|
|
142
|
-
component={
|
|
143
|
-
<div
|
|
144
|
-
className={`${
|
|
145
|
-
selectedValue === materialValue
|
|
146
|
-
? "border-catchup-blue"
|
|
147
|
-
: "border-catchup-lighter-gray"
|
|
148
|
-
} h-catchup-activity-covering-box-item flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer transition-all duration-300`}
|
|
149
|
-
onMouseDown={() => {
|
|
150
|
-
if (checkCanAnswerQuestion()) {
|
|
151
|
-
setSelectedValue(materialValue);
|
|
152
|
-
}
|
|
153
|
-
}}
|
|
154
|
-
onMouseUp={() => {
|
|
155
|
-
if (checkCanAnswerQuestion()) {
|
|
156
|
-
setSelectedValue(null);
|
|
157
|
-
}
|
|
158
|
-
}}
|
|
159
|
-
>
|
|
160
|
-
{contentMap.type === "TEXT" ? (
|
|
161
|
-
<div
|
|
162
|
-
className={`flex flex-col items-center justify-center m-4 min-h-[64px] min-w-[200px]`}
|
|
163
|
-
>
|
|
164
|
-
<p className="text-xl text-center whitespace-pre-wrap">
|
|
165
|
-
{constructInputWithSpecialExpressionList(
|
|
166
|
-
materialValue
|
|
167
|
-
).map((inputPart, index) => (
|
|
168
|
-
<span
|
|
169
|
-
key={index}
|
|
170
|
-
className={`${
|
|
171
|
-
inputPart.isBold ? "font-bold" : ""
|
|
172
|
-
} ${inputPart.isUnderline ? "underline" : ""}`}
|
|
173
|
-
>
|
|
174
|
-
{inputPart.isEquation ? (
|
|
175
|
-
<span className="text-2xl">
|
|
176
|
-
<InlineMath math={inputPart.value} />
|
|
177
|
-
</span>
|
|
178
|
-
) : (
|
|
179
|
-
inputPart.value
|
|
180
|
-
)}
|
|
181
|
-
</span>
|
|
182
|
-
))}
|
|
183
|
-
</p>
|
|
184
|
-
</div>
|
|
185
|
-
) : (
|
|
186
|
-
<ShowMaterialMediaByContentType
|
|
187
|
-
key={`${uniqueValue}-${index}`}
|
|
188
|
-
contentType={contentMap.type}
|
|
189
|
-
src={materialValue}
|
|
190
|
-
canFullScreen={true}
|
|
191
|
-
/>
|
|
192
|
-
)}
|
|
193
|
-
</div>
|
|
194
|
-
}
|
|
195
|
-
moveCardHandler={() => {
|
|
196
|
-
if (!selectedTargetKey) return;
|
|
197
|
-
if (!selectedValue) return;
|
|
198
|
-
handleGroupingActivityItemOnChange(
|
|
199
|
-
selectedTargetKey,
|
|
200
|
-
selectedValue
|
|
201
|
-
);
|
|
202
|
-
}}
|
|
203
|
-
/>
|
|
204
|
-
);
|
|
205
|
-
})}
|
|
206
|
-
</div>
|
|
207
|
-
{filteredMaterialList.length > 0 ? <DividerLine /> : null}
|
|
208
|
-
{Object.keys(answerMap).map((answerMapKey, index) => (
|
|
209
|
-
<div key={index} className="flex flex-row w-full">
|
|
210
|
-
<div className="w-1/3">
|
|
211
|
-
<div
|
|
212
|
-
className={`border-catchup-blue h-catchup-activity-outer-box-item flex flex-col items-center justify-center border-2 rounded-catchup-xlarge transition-all duration-300 my-3`}
|
|
213
|
-
>
|
|
214
|
-
<div
|
|
215
|
-
className={`flex flex-col items-center justify-center transition-all duration-300 m-4`}
|
|
216
|
-
>
|
|
217
|
-
<p className="text-xl p-5 whitespace-pre-wrap">
|
|
218
|
-
{constructInputWithSpecialExpressionList(answerMapKey).map(
|
|
219
|
-
(inputPart, index) => (
|
|
220
|
-
<span
|
|
221
|
-
key={index}
|
|
222
|
-
className={`${inputPart.isBold ? "font-bold" : ""} ${
|
|
223
|
-
inputPart.isUnderline ? "underline" : ""
|
|
224
|
-
}`}
|
|
225
|
-
>
|
|
226
|
-
{inputPart.isEquation ? (
|
|
227
|
-
<span className="text-2xl">
|
|
228
|
-
<InlineMath math={inputPart.value} />
|
|
229
|
-
</span>
|
|
230
|
-
) : (
|
|
231
|
-
inputPart.value
|
|
232
|
-
)}
|
|
233
|
-
</span>
|
|
234
|
-
)
|
|
235
|
-
)}
|
|
236
|
-
</p>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
</div>
|
|
240
|
-
<div className="mx-4 w-[2px] bg-catchup-lighter-gray"></div>
|
|
241
|
-
<div className="flex-1" ref={ref}>
|
|
242
|
-
<div className="h-full py-3">
|
|
243
|
-
<div
|
|
244
|
-
className={`${
|
|
245
|
-
canDrop
|
|
246
|
-
? selectedTargetKey === answerMapKey
|
|
247
|
-
? "bg-catchup-light-blue"
|
|
248
|
-
: "bg-catchup-light-blue opacity-40"
|
|
249
|
-
: ""
|
|
250
|
-
} flex-1 border-catchup-blue rounded-catchup-xlarge border-2 h-full p-1`}
|
|
251
|
-
>
|
|
252
|
-
<DroppableItem
|
|
253
|
-
key={index}
|
|
254
|
-
item={{ index: answerMapKey }}
|
|
255
|
-
type={"GROUPING"}
|
|
256
|
-
target={selectedTargetKey}
|
|
257
|
-
setTarget={setSelectedTargetKey}
|
|
258
|
-
dropRef={drop}
|
|
259
|
-
component={
|
|
260
|
-
<div
|
|
261
|
-
className="h-full flex-1 flex flex-row items-center overflow-x-auto"
|
|
262
|
-
style={{
|
|
263
|
-
maxWidth: maxWidth,
|
|
264
|
-
}}
|
|
265
|
-
>
|
|
266
|
-
{answerMap[answerMapKey].map(
|
|
267
|
-
(answerMapValue: string, answerMapIndex: number) => {
|
|
268
|
-
const learnerAnswerState = checkAnswerState(
|
|
269
|
-
materialMap[answerMapKey],
|
|
270
|
-
answerMapValue
|
|
271
|
-
);
|
|
272
|
-
return (
|
|
273
|
-
<div className="p-1">
|
|
274
|
-
<div className="h-catchup-activity-box-item">
|
|
275
|
-
<div
|
|
276
|
-
className={`${
|
|
277
|
-
learnerAnswerState === "EMPTY"
|
|
278
|
-
? "border-catchup-lighter-gray"
|
|
279
|
-
: learnerAnswerState === "CORRECT"
|
|
280
|
-
? "border-catchup-green"
|
|
281
|
-
: learnerAnswerState === "INCORRECT"
|
|
282
|
-
? "border-catchup-red"
|
|
283
|
-
: "border-catchup-blue"
|
|
284
|
-
} border-2 rounded-catchup-xlarge h-full flex flex-col items-center justify-center transition-all duration-300 cursor-pointer`}
|
|
285
|
-
onClick={(e) => {
|
|
286
|
-
e.preventDefault();
|
|
287
|
-
if (checkCanAnswerQuestion()) {
|
|
288
|
-
onChange(
|
|
289
|
-
answer,
|
|
290
|
-
answerMapKey,
|
|
291
|
-
null,
|
|
292
|
-
answerMapIndex
|
|
293
|
-
);
|
|
294
|
-
setSelectedValue(null);
|
|
295
|
-
}
|
|
296
|
-
}}
|
|
297
|
-
>
|
|
298
|
-
{contentMap.type === "TEXT" ? (
|
|
299
|
-
<div
|
|
300
|
-
className={`flex flex-col items-center justify-center transition-all duration-300 min-h-[64px] min-w-[200px]`}
|
|
301
|
-
>
|
|
302
|
-
<div className="m-2">
|
|
303
|
-
<p className="text-xl text-center whitespace-pre-wrap">
|
|
304
|
-
{constructInputWithSpecialExpressionList(
|
|
305
|
-
answerMapValue
|
|
306
|
-
).map((inputPart, index) => (
|
|
307
|
-
<span
|
|
308
|
-
key={index}
|
|
309
|
-
className={`${
|
|
310
|
-
inputPart.isBold
|
|
311
|
-
? "font-bold"
|
|
312
|
-
: ""
|
|
313
|
-
} ${
|
|
314
|
-
inputPart.isUnderline
|
|
315
|
-
? "underline"
|
|
316
|
-
: ""
|
|
317
|
-
}`}
|
|
318
|
-
>
|
|
319
|
-
{inputPart.isEquation ? (
|
|
320
|
-
<span className="text-2xl">
|
|
321
|
-
<InlineMath
|
|
322
|
-
math={inputPart.value}
|
|
323
|
-
/>
|
|
324
|
-
</span>
|
|
325
|
-
) : (
|
|
326
|
-
inputPart.value
|
|
327
|
-
)}
|
|
328
|
-
</span>
|
|
329
|
-
))}
|
|
330
|
-
</p>
|
|
331
|
-
</div>
|
|
332
|
-
</div>
|
|
333
|
-
) : (
|
|
334
|
-
<ShowMaterialMediaByContentType
|
|
335
|
-
key={`${uniqueValue}-${index}`}
|
|
336
|
-
contentType={contentMap.type}
|
|
337
|
-
src={answerMapValue}
|
|
338
|
-
canFullScreen={false}
|
|
339
|
-
/>
|
|
340
|
-
)}
|
|
341
|
-
</div>
|
|
342
|
-
</div>
|
|
343
|
-
</div>
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
)}
|
|
347
|
-
</div>
|
|
348
|
-
}
|
|
349
|
-
/>
|
|
350
|
-
</div>
|
|
351
|
-
</div>
|
|
352
|
-
</div>
|
|
353
|
-
</div>
|
|
354
|
-
))}
|
|
355
|
-
</>
|
|
356
|
-
);
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
export default GroupingActivityMaterialContent;
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { useDrop } from "react-dnd";
|
|
3
|
-
import ShowMaterialMediaByContentType from "./ShowMaterialMediaByContentType";
|
|
4
|
-
import { InlineMath } from "react-katex";
|
|
5
|
-
import useScreenSize from "../../../hooks/useScreenSize";
|
|
6
|
-
import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
|
|
7
|
-
import { IMatchingActivityMaterialProps } from "../../../properties/ActivityProperties";
|
|
8
|
-
import DraggableItem from "../../dnds/DraggableItem";
|
|
9
|
-
import DroppableItem from "../../dnds/DroppableItem";
|
|
10
|
-
import DividerLine from "../../dividers/DividerLine";
|
|
11
|
-
|
|
12
|
-
const MatchingActivityMaterialContent = ({
|
|
13
|
-
uniqueValue,
|
|
14
|
-
answer,
|
|
15
|
-
materialMap,
|
|
16
|
-
contentMap,
|
|
17
|
-
checkCanAnswerQuestion,
|
|
18
|
-
onChange,
|
|
19
|
-
isPreview,
|
|
20
|
-
showCorrectAnswer,
|
|
21
|
-
}: IMatchingActivityMaterialProps) => {
|
|
22
|
-
const [selectedValue, setSelectedValue] = useState(null);
|
|
23
|
-
const [selectedTargetKey, setSelectedTargetKey] = useState(null);
|
|
24
|
-
const [isShuffled, setIsShuffled] = useState(false);
|
|
25
|
-
const [shuffledMaterialList, setShuffledMaterialList] = useState([]);
|
|
26
|
-
const [{ isOver, canDrop }, drop] = useDrop({
|
|
27
|
-
accept: "MATCHING",
|
|
28
|
-
drop: () => {},
|
|
29
|
-
collect: (monitor) => ({
|
|
30
|
-
isOver: monitor.isOver(),
|
|
31
|
-
canDrop: monitor.canDrop(),
|
|
32
|
-
}),
|
|
33
|
-
});
|
|
34
|
-
const { containerSize } = useScreenSize();
|
|
35
|
-
const itemsRef = useRef<HTMLDivElement>(null);
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
const shuffleArray = (array: any) => {
|
|
39
|
-
if (!isShuffled) {
|
|
40
|
-
const copyArray = JSON.parse(JSON.stringify(array));
|
|
41
|
-
for (let i = copyArray.length - 1; i > 0; i--) {
|
|
42
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
43
|
-
[copyArray[i], copyArray[j]] = [copyArray[j], copyArray[i]];
|
|
44
|
-
}
|
|
45
|
-
setIsShuffled(true);
|
|
46
|
-
return copyArray;
|
|
47
|
-
}
|
|
48
|
-
return array;
|
|
49
|
-
};
|
|
50
|
-
const materialList: any = [];
|
|
51
|
-
Object.keys(materialMap).forEach((materialKey) => {
|
|
52
|
-
materialList.push(materialMap[materialKey]);
|
|
53
|
-
});
|
|
54
|
-
setShuffledMaterialList(shuffleArray(materialList));
|
|
55
|
-
}, []);
|
|
56
|
-
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
if (!showCorrectAnswer) return;
|
|
59
|
-
answer.data.find(
|
|
60
|
-
(answerData: any) => answerData.type === "MATCHING"
|
|
61
|
-
).answerMap = materialMap;
|
|
62
|
-
}, [showCorrectAnswer]);
|
|
63
|
-
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
if (!itemsRef) return;
|
|
66
|
-
if (!itemsRef.current) return;
|
|
67
|
-
if (!containerSize) return;
|
|
68
|
-
itemsRef.current.style.width = `${containerSize.width - 220}px`;
|
|
69
|
-
}, [itemsRef, containerSize]);
|
|
70
|
-
|
|
71
|
-
const retrieveAnswerMap = () => {
|
|
72
|
-
const foundIndex = answer.data.findIndex(
|
|
73
|
-
(answerData: any) => answerData.type === "MATCHING"
|
|
74
|
-
);
|
|
75
|
-
const answerMap = answer.data[foundIndex].answerMap;
|
|
76
|
-
const sortedAnswerMapKeys = Object.keys(answerMap).sort((a, b) =>
|
|
77
|
-
answerMap[a]
|
|
78
|
-
? answerMap[b]
|
|
79
|
-
? answerMap[a].localeCompare(answerMap[b])
|
|
80
|
-
: 1
|
|
81
|
-
: -1
|
|
82
|
-
);
|
|
83
|
-
const sortedAnswerMap: any = {};
|
|
84
|
-
for (const answerMapKey of sortedAnswerMapKeys) {
|
|
85
|
-
sortedAnswerMap[answerMapKey] = answerMap[answerMapKey];
|
|
86
|
-
}
|
|
87
|
-
return sortedAnswerMap;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const retrieveFilteredMaterialList = (answerMap: any) => {
|
|
91
|
-
const selectedValueList: any = [];
|
|
92
|
-
Object.keys(answerMap).forEach((key) => {
|
|
93
|
-
selectedValueList.push(answerMap[key]);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
return shuffledMaterialList.filter(
|
|
97
|
-
(material) =>
|
|
98
|
-
selectedValueList.findIndex((value: string) => material === value) ===
|
|
99
|
-
-1
|
|
100
|
-
);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const checkAnswerState = (correctAnswer: string, learnerAnswer: string) => {
|
|
104
|
-
if (!isPreview) return null;
|
|
105
|
-
if (!learnerAnswer) return "EMPTY";
|
|
106
|
-
if (correctAnswer === learnerAnswer) {
|
|
107
|
-
return "CORRECT";
|
|
108
|
-
}
|
|
109
|
-
return "INCORRECT";
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const handleMatchingActivityItemOnChange = (
|
|
113
|
-
selectedTargetKey: string,
|
|
114
|
-
selectedValue: string | null
|
|
115
|
-
) => {
|
|
116
|
-
if (checkCanAnswerQuestion()) {
|
|
117
|
-
onChange(answer, selectedTargetKey, selectedValue);
|
|
118
|
-
setSelectedValue(null);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const answerMap = retrieveAnswerMap();
|
|
123
|
-
const filteredMaterialList = retrieveFilteredMaterialList(answerMap);
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<>
|
|
127
|
-
<div
|
|
128
|
-
ref={itemsRef}
|
|
129
|
-
className="flex-1 flex flex-row gap-x-4 gap-y-4 overflow-auto py-2"
|
|
130
|
-
>
|
|
131
|
-
{filteredMaterialList.map((materialValue, index) => (
|
|
132
|
-
<DraggableItem
|
|
133
|
-
key={index}
|
|
134
|
-
item={{ index: materialValue }}
|
|
135
|
-
type={"MATCHING"}
|
|
136
|
-
component={
|
|
137
|
-
<div
|
|
138
|
-
className={`${
|
|
139
|
-
selectedValue === materialValue
|
|
140
|
-
? "border-catchup-blue"
|
|
141
|
-
: "border-catchup-lighter-gray"
|
|
142
|
-
} h-catchup-activity-covering-box-item flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer transition-all duration-300`}
|
|
143
|
-
onMouseDown={() => {
|
|
144
|
-
if (checkCanAnswerQuestion()) {
|
|
145
|
-
setSelectedValue(materialValue);
|
|
146
|
-
}
|
|
147
|
-
}}
|
|
148
|
-
onMouseUp={() => {
|
|
149
|
-
if (checkCanAnswerQuestion()) {
|
|
150
|
-
setSelectedValue(null);
|
|
151
|
-
}
|
|
152
|
-
}}
|
|
153
|
-
>
|
|
154
|
-
{contentMap.type === "TEXT" ? (
|
|
155
|
-
<div
|
|
156
|
-
className={`flex flex-col items-center justify-center m-4 min-h-[64px] min-w-[200px]`}
|
|
157
|
-
>
|
|
158
|
-
<p className="text-xl p-5 whitespace-pre-wrap">
|
|
159
|
-
{constructInputWithSpecialExpressionList(
|
|
160
|
-
materialValue
|
|
161
|
-
).map((inputPart, index) => (
|
|
162
|
-
<span
|
|
163
|
-
key={index}
|
|
164
|
-
className={`${inputPart.isBold ? "font-bold" : ""} ${
|
|
165
|
-
inputPart.isUnderline ? "underline" : ""
|
|
166
|
-
}`}
|
|
167
|
-
>
|
|
168
|
-
{inputPart.isEquation ? (
|
|
169
|
-
<span className="text-2xl">
|
|
170
|
-
<InlineMath math={inputPart.value} />
|
|
171
|
-
</span>
|
|
172
|
-
) : (
|
|
173
|
-
inputPart.value
|
|
174
|
-
)}
|
|
175
|
-
</span>
|
|
176
|
-
))}
|
|
177
|
-
</p>
|
|
178
|
-
</div>
|
|
179
|
-
) : (
|
|
180
|
-
<ShowMaterialMediaByContentType
|
|
181
|
-
key={`${uniqueValue}-${index}`}
|
|
182
|
-
contentType={contentMap.type}
|
|
183
|
-
src={materialValue}
|
|
184
|
-
canFullScreen={true}
|
|
185
|
-
/>
|
|
186
|
-
)}
|
|
187
|
-
</div>
|
|
188
|
-
}
|
|
189
|
-
moveCardHandler={() => {
|
|
190
|
-
if (!selectedTargetKey) return;
|
|
191
|
-
if (!selectedValue) return;
|
|
192
|
-
handleMatchingActivityItemOnChange(
|
|
193
|
-
selectedTargetKey,
|
|
194
|
-
selectedValue
|
|
195
|
-
);
|
|
196
|
-
}}
|
|
197
|
-
/>
|
|
198
|
-
))}
|
|
199
|
-
</div>
|
|
200
|
-
{filteredMaterialList.length > 0 ? <DividerLine /> : null}
|
|
201
|
-
{Object.keys(answerMap).map((answerMapKey, index) => {
|
|
202
|
-
const learnerAnswerState = checkAnswerState(
|
|
203
|
-
materialMap[answerMapKey],
|
|
204
|
-
answerMap[answerMapKey]
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
return (
|
|
208
|
-
<div key={index} className="flex flex-row w-full">
|
|
209
|
-
<div className="w-1/3">
|
|
210
|
-
<div
|
|
211
|
-
className={`h-catchup-activity-outer-box-item flex flex-col items-center justify-center border-2 rounded-catchup-xlarge transition-all duration-300 my-3 ${
|
|
212
|
-
learnerAnswerState === "EMPTY"
|
|
213
|
-
? "border-catchup-blue"
|
|
214
|
-
: learnerAnswerState === "CORRECT"
|
|
215
|
-
? "border-catchup-green"
|
|
216
|
-
: learnerAnswerState === "INCORRECT"
|
|
217
|
-
? "border-catchup-red"
|
|
218
|
-
: "border-catchup-blue"
|
|
219
|
-
}`}
|
|
220
|
-
>
|
|
221
|
-
<div
|
|
222
|
-
className={`flex flex-col items-center justify-center transition-all duration-300 m-4`}
|
|
223
|
-
>
|
|
224
|
-
<p className="text-xl p-5 whitespace-pre-wrap">
|
|
225
|
-
{constructInputWithSpecialExpressionList(answerMapKey).map(
|
|
226
|
-
(inputPart, index) => (
|
|
227
|
-
<span
|
|
228
|
-
key={index}
|
|
229
|
-
className={`${inputPart.isBold ? "font-bold" : ""} ${
|
|
230
|
-
inputPart.isUnderline ? "underline" : ""
|
|
231
|
-
}`}
|
|
232
|
-
>
|
|
233
|
-
{inputPart.isEquation ? (
|
|
234
|
-
<span className="text-2xl">
|
|
235
|
-
<InlineMath math={inputPart.value} />
|
|
236
|
-
</span>
|
|
237
|
-
) : (
|
|
238
|
-
inputPart.value
|
|
239
|
-
)}
|
|
240
|
-
</span>
|
|
241
|
-
)
|
|
242
|
-
)}
|
|
243
|
-
</p>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
247
|
-
<div className="mx-4 w-[2px] bg-catchup-lighter-gray"></div>
|
|
248
|
-
<div className="flex-1">
|
|
249
|
-
<div
|
|
250
|
-
className={`${
|
|
251
|
-
canDrop
|
|
252
|
-
? selectedTargetKey === answerMapKey
|
|
253
|
-
? "bg-catchup-light-blue"
|
|
254
|
-
: "bg-catchup-light-blue opacity-40"
|
|
255
|
-
: ""
|
|
256
|
-
} h-catchup-activity-outer-box-item flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer transition-all duration-300 my-3 ${
|
|
257
|
-
learnerAnswerState === "EMPTY"
|
|
258
|
-
? "border-catchup-blue"
|
|
259
|
-
: learnerAnswerState === "CORRECT"
|
|
260
|
-
? "border-catchup-green"
|
|
261
|
-
: learnerAnswerState === "INCORRECT"
|
|
262
|
-
? "border-catchup-red"
|
|
263
|
-
: "border-catchup-blue"
|
|
264
|
-
}`}
|
|
265
|
-
onClick={() => {
|
|
266
|
-
if (checkCanAnswerQuestion()) {
|
|
267
|
-
setSelectedValue(null);
|
|
268
|
-
}
|
|
269
|
-
}}
|
|
270
|
-
>
|
|
271
|
-
<DroppableItem
|
|
272
|
-
key={index}
|
|
273
|
-
item={{ index: answerMapKey }}
|
|
274
|
-
type={"MATCHING"}
|
|
275
|
-
target={selectedTargetKey}
|
|
276
|
-
setTarget={setSelectedTargetKey}
|
|
277
|
-
dropRef={drop}
|
|
278
|
-
component={
|
|
279
|
-
<div
|
|
280
|
-
className={`h-full flex-1 flex flex-row items-center justify-center `} // w-[calc((100vw_-_214px)_/_2)]
|
|
281
|
-
onClick={(e) => {
|
|
282
|
-
e.preventDefault();
|
|
283
|
-
if (checkCanAnswerQuestion()) {
|
|
284
|
-
handleMatchingActivityItemOnChange(
|
|
285
|
-
answerMapKey,
|
|
286
|
-
null
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
}}
|
|
290
|
-
>
|
|
291
|
-
{contentMap.type === "TEXT" ? (
|
|
292
|
-
<p className="text-xl p-5 whitespace-pre-wrap">
|
|
293
|
-
{constructInputWithSpecialExpressionList(
|
|
294
|
-
answerMap[answerMapKey]
|
|
295
|
-
).map((inputPart, index) => (
|
|
296
|
-
<span
|
|
297
|
-
key={index}
|
|
298
|
-
className={`${
|
|
299
|
-
inputPart.isBold ? "font-bold" : ""
|
|
300
|
-
} ${inputPart.isUnderline ? "underline" : ""}`}
|
|
301
|
-
>
|
|
302
|
-
{inputPart.isEquation ? (
|
|
303
|
-
<span className="text-2xl">
|
|
304
|
-
<InlineMath math={inputPart.value} />
|
|
305
|
-
</span>
|
|
306
|
-
) : (
|
|
307
|
-
inputPart.value
|
|
308
|
-
)}
|
|
309
|
-
</span>
|
|
310
|
-
))}
|
|
311
|
-
</p>
|
|
312
|
-
) : (
|
|
313
|
-
<ShowMaterialMediaByContentType
|
|
314
|
-
key={`${uniqueValue}-${index}`}
|
|
315
|
-
contentType={contentMap.type}
|
|
316
|
-
src={answerMap[answerMapKey]}
|
|
317
|
-
canFullScreen={false}
|
|
318
|
-
/>
|
|
319
|
-
)}
|
|
320
|
-
</div>
|
|
321
|
-
}
|
|
322
|
-
/>
|
|
323
|
-
</div>
|
|
324
|
-
</div>
|
|
325
|
-
</div>
|
|
326
|
-
);
|
|
327
|
-
})}
|
|
328
|
-
</>
|
|
329
|
-
);
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
export default MatchingActivityMaterialContent;
|
|
File without changes
|
/package/src/components/activities/{empty-content → empty-contents}/ActivityEmptyContent.tsx
RENAMED
|
File without changes
|
|
File without changes
|