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