catchup-library-web 1.20.33 → 1.20.35
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 +351 -347
- package/dist/index.mjs +294 -290
- package/package.json +1 -1
- package/src/components/activities/material-contents/FillInTheBlanksActivityMaterialContent.tsx +1 -5
- package/src/components/activities/material-contents/OrderingActivityMaterialContent.tsx +214 -115
- package/src/components/activities/material-contents/OrderingActivityMaterialContent2.tsx +231 -0
package/package.json
CHANGED
package/src/components/activities/material-contents/FillInTheBlanksActivityMaterialContent.tsx
CHANGED
|
@@ -303,11 +303,7 @@ const FillInTheBlanksActivityMaterialContent = ({
|
|
|
303
303
|
value={answerMap[materialKey]}
|
|
304
304
|
showSpecialOnly={false}
|
|
305
305
|
/>
|
|
306
|
-
) :
|
|
307
|
-
<p className="text-gray-400 italic">
|
|
308
|
-
{i18n.t("please_drop_here")}
|
|
309
|
-
</p>
|
|
310
|
-
)}
|
|
306
|
+
) : null}
|
|
311
307
|
</div>
|
|
312
308
|
</div>
|
|
313
309
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import { useDrop } from "react-dnd";
|
|
1
|
+
import { useEffect, useState, useRef } from "react";
|
|
3
2
|
import ShowMaterialMediaByContentType from "./ShowMaterialMediaByContentType";
|
|
4
3
|
import { InlineMath } from "react-katex";
|
|
5
4
|
import useScreenSize from "../../../hooks/useScreenSize";
|
|
6
5
|
import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
|
|
7
6
|
import { IOrderingActivityMaterialProps } from "../../../properties/ActivityProperties";
|
|
8
|
-
import DraggableDroppableItem from "../../dnds/DraggableDroppableItem";
|
|
9
7
|
|
|
10
8
|
const OrderingActivityMaterialContent = ({
|
|
11
9
|
uniqueValue,
|
|
@@ -17,18 +15,19 @@ const OrderingActivityMaterialContent = ({
|
|
|
17
15
|
isPreview,
|
|
18
16
|
showCorrectAnswer,
|
|
19
17
|
}: IOrderingActivityMaterialProps) => {
|
|
20
|
-
const [selectedTargetKey, setSelectedTargetKey] = useState(null);
|
|
21
18
|
const [selectedKey, setSelectedKey] = useState<string | null>(null);
|
|
19
|
+
const [draggedKey, setDraggedKey] = useState<string | null>(null);
|
|
20
|
+
const [dropTargetKey, setDropTargetKey] = useState<string | null>(null);
|
|
21
|
+
const [draggedElement, setDraggedElement] = useState<HTMLElement | null>(
|
|
22
|
+
null
|
|
23
|
+
);
|
|
24
|
+
const dragElementRef = useRef<HTMLDivElement>(null);
|
|
25
|
+
const [touchPosition, setTouchPosition] = useState<{ x: number; y: number }>({
|
|
26
|
+
x: 0,
|
|
27
|
+
y: 0,
|
|
28
|
+
});
|
|
22
29
|
const { screenSize } = useScreenSize();
|
|
23
30
|
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
31
|
|
|
33
32
|
useEffect(() => {
|
|
34
33
|
if (!screenSize) return;
|
|
@@ -64,27 +63,9 @@ const OrderingActivityMaterialContent = ({
|
|
|
64
63
|
return "INCORRECT";
|
|
65
64
|
};
|
|
66
65
|
|
|
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
66
|
const calculateMarginTop = (index: number) => {
|
|
82
67
|
if (index === 0) {
|
|
83
|
-
|
|
84
|
-
return 0;
|
|
85
|
-
} else {
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
68
|
+
return 0;
|
|
88
69
|
} else if (index === 1) {
|
|
89
70
|
if (contentMap.type === "TEXT") {
|
|
90
71
|
return 65;
|
|
@@ -98,19 +79,144 @@ const OrderingActivityMaterialContent = ({
|
|
|
98
79
|
return -130;
|
|
99
80
|
}
|
|
100
81
|
} else if (index % 2 === 1) {
|
|
101
|
-
|
|
102
|
-
return 0;
|
|
103
|
-
} else {
|
|
104
|
-
return 0;
|
|
105
|
-
}
|
|
82
|
+
return 0;
|
|
106
83
|
}
|
|
107
84
|
return 0;
|
|
108
85
|
};
|
|
109
86
|
|
|
87
|
+
// Mouse drag handlers
|
|
88
|
+
const handleMouseDown = (e: React.MouseEvent, materialKey: string): void => {
|
|
89
|
+
if (!checkCanAnswerQuestion()) return;
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
setDraggedKey(materialKey);
|
|
92
|
+
setSelectedKey(null);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const handleMouseUp = (): void => {
|
|
96
|
+
if (
|
|
97
|
+
dropTargetKey !== null &&
|
|
98
|
+
draggedKey !== null &&
|
|
99
|
+
dropTargetKey !== draggedKey
|
|
100
|
+
) {
|
|
101
|
+
onChange(answer, draggedKey, dropTargetKey);
|
|
102
|
+
}
|
|
103
|
+
setDraggedKey(null);
|
|
104
|
+
setDropTargetKey(null);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Touch drag handlers
|
|
108
|
+
const handleTouchStart = (
|
|
109
|
+
e: React.TouchEvent,
|
|
110
|
+
materialKey: string,
|
|
111
|
+
element: HTMLElement
|
|
112
|
+
): void => {
|
|
113
|
+
if (!checkCanAnswerQuestion()) return;
|
|
114
|
+
const touch = e.touches[0];
|
|
115
|
+
setDraggedKey(materialKey);
|
|
116
|
+
setDraggedElement(element);
|
|
117
|
+
setTouchPosition({ x: touch.clientX, y: touch.clientY });
|
|
118
|
+
setSelectedKey(null);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const handleTouchMove = (e: React.TouchEvent): void => {
|
|
122
|
+
if (!draggedKey) return;
|
|
123
|
+
|
|
124
|
+
const touch = e.touches[0];
|
|
125
|
+
setTouchPosition({ x: touch.clientX, y: touch.clientY });
|
|
126
|
+
|
|
127
|
+
// Find the element under the touch point
|
|
128
|
+
const elementUnder = document.elementFromPoint(
|
|
129
|
+
touch.clientX,
|
|
130
|
+
touch.clientY
|
|
131
|
+
);
|
|
132
|
+
const dropZone = elementUnder?.closest("[data-ordering-drop-zone]");
|
|
133
|
+
|
|
134
|
+
if (dropZone) {
|
|
135
|
+
const dropKey = dropZone.getAttribute("data-ordering-drop-zone");
|
|
136
|
+
setDropTargetKey(dropKey);
|
|
137
|
+
} else {
|
|
138
|
+
setDropTargetKey(null);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const handleTouchEnd = (): void => {
|
|
143
|
+
if (
|
|
144
|
+
dropTargetKey !== null &&
|
|
145
|
+
draggedKey !== null &&
|
|
146
|
+
dropTargetKey !== draggedKey
|
|
147
|
+
) {
|
|
148
|
+
onChange(answer, draggedKey, dropTargetKey);
|
|
149
|
+
}
|
|
150
|
+
setDraggedKey(null);
|
|
151
|
+
setDropTargetKey(null);
|
|
152
|
+
setDraggedElement(null);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Click/tap to select (for easier mobile interaction)
|
|
156
|
+
const handleSelectItem = (materialKey: string): void => {
|
|
157
|
+
if (!checkCanAnswerQuestion()) return;
|
|
158
|
+
|
|
159
|
+
if (selectedKey === null) {
|
|
160
|
+
setSelectedKey(materialKey);
|
|
161
|
+
} else if (selectedKey === materialKey) {
|
|
162
|
+
setSelectedKey(null);
|
|
163
|
+
} else {
|
|
164
|
+
onChange(answer, selectedKey, materialKey);
|
|
165
|
+
setSelectedKey(null);
|
|
166
|
+
}
|
|
167
|
+
setDraggedKey(null);
|
|
168
|
+
};
|
|
169
|
+
|
|
110
170
|
const answerMap = retrieveAnswerMap();
|
|
111
171
|
|
|
112
172
|
return (
|
|
113
|
-
<div className="flex flex-row flex-wrap">
|
|
173
|
+
<div className="flex flex-row flex-wrap" onMouseUp={handleMouseUp}>
|
|
174
|
+
{/* Floating drag preview for touch */}
|
|
175
|
+
{draggedKey && touchPosition.x > 0 && (
|
|
176
|
+
<div
|
|
177
|
+
className="fixed pointer-events-none z-50 opacity-80"
|
|
178
|
+
style={{
|
|
179
|
+
left: `${touchPosition.x}px`,
|
|
180
|
+
top: `${touchPosition.y}px`,
|
|
181
|
+
transform: "translate(-50%, -50%)",
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
184
|
+
{contentMap.type === "TEXT" ? (
|
|
185
|
+
<div className="border-catchup-blue border-2 px-3 py-2 rounded-catchup-xlarge bg-white shadow-lg">
|
|
186
|
+
<p className="text-xl whitespace-pre-wrap">
|
|
187
|
+
{constructInputWithSpecialExpressionList(
|
|
188
|
+
materialMap[answerMap[draggedKey]]
|
|
189
|
+
).map((inputPart, index) => (
|
|
190
|
+
<span
|
|
191
|
+
key={index}
|
|
192
|
+
className={`${inputPart.isBold ? "font-bold" : ""} ${
|
|
193
|
+
inputPart.isUnderline ? "underline" : ""
|
|
194
|
+
}`}
|
|
195
|
+
>
|
|
196
|
+
{inputPart.isEquation ? (
|
|
197
|
+
<span className="text-xl">
|
|
198
|
+
<InlineMath math={inputPart.value} />
|
|
199
|
+
</span>
|
|
200
|
+
) : (
|
|
201
|
+
inputPart.value
|
|
202
|
+
)}
|
|
203
|
+
</span>
|
|
204
|
+
))}
|
|
205
|
+
</p>
|
|
206
|
+
</div>
|
|
207
|
+
) : (
|
|
208
|
+
<div className="border-catchup-blue border-2 px-2 py-1 rounded-catchup-xlarge bg-white shadow-lg">
|
|
209
|
+
<ShowMaterialMediaByContentType
|
|
210
|
+
key={`${uniqueValue}-drag`}
|
|
211
|
+
contentType={contentMap.type}
|
|
212
|
+
src={materialMap[answerMap[draggedKey]]}
|
|
213
|
+
canFullScreen={false}
|
|
214
|
+
/>
|
|
215
|
+
</div>
|
|
216
|
+
)}
|
|
217
|
+
</div>
|
|
218
|
+
)}
|
|
219
|
+
|
|
114
220
|
{Object.keys(answerMap).map((materialKey, index) => {
|
|
115
221
|
const learnerAnswerState = checkAnswerState(
|
|
116
222
|
answerMap[materialKey] + "",
|
|
@@ -141,85 +247,78 @@ const OrderingActivityMaterialContent = ({
|
|
|
141
247
|
</div>
|
|
142
248
|
</div>
|
|
143
249
|
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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>
|
|
250
|
+
<div
|
|
251
|
+
ref={draggedKey === materialKey ? dragElementRef : null}
|
|
252
|
+
data-ordering-drop-zone={materialKey}
|
|
253
|
+
className={`flex-1 ${
|
|
254
|
+
draggedKey === materialKey
|
|
255
|
+
? "opacity-40"
|
|
256
|
+
: selectedKey === materialKey
|
|
257
|
+
? "ring-2 ring-blue-500"
|
|
258
|
+
: "opacity-100"
|
|
259
|
+
} ${
|
|
260
|
+
dropTargetKey === materialKey && draggedKey !== materialKey
|
|
261
|
+
? "ring-2 ring-blue-400 bg-blue-50"
|
|
262
|
+
: ""
|
|
263
|
+
} transition-all duration-200`}
|
|
264
|
+
onMouseDown={(e) => handleMouseDown(e, materialKey)}
|
|
265
|
+
onMouseEnter={() =>
|
|
266
|
+
draggedKey &&
|
|
267
|
+
draggedKey !== materialKey &&
|
|
268
|
+
setDropTargetKey(materialKey)
|
|
211
269
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
270
|
+
onMouseLeave={() => setDropTargetKey(null)}
|
|
271
|
+
onTouchStart={(e) =>
|
|
272
|
+
handleTouchStart(e, materialKey, e.currentTarget)
|
|
273
|
+
}
|
|
274
|
+
onTouchMove={handleTouchMove}
|
|
275
|
+
onTouchEnd={handleTouchEnd}
|
|
276
|
+
>
|
|
277
|
+
<div
|
|
278
|
+
className={`${
|
|
279
|
+
contentMap.type === "TEXT"
|
|
280
|
+
? "h-catchup-activity-text-box-item"
|
|
281
|
+
: "h-catchup-activity-media-box-item"
|
|
282
|
+
} flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer p-3 ${
|
|
283
|
+
learnerAnswerState === "CORRECT"
|
|
284
|
+
? "border-catchup-green"
|
|
285
|
+
: learnerAnswerState === "INCORRECT"
|
|
286
|
+
? "border-catchup-red"
|
|
287
|
+
: "border-catchup-blue"
|
|
288
|
+
}`}
|
|
289
|
+
onClick={() => handleSelectItem(materialKey)}
|
|
290
|
+
>
|
|
291
|
+
{contentMap.type === "TEXT" ? (
|
|
292
|
+
<p className="text-xl whitespace-pre-wrap">
|
|
293
|
+
{constructInputWithSpecialExpressionList(
|
|
294
|
+
materialMap[answerMap[materialKey]]
|
|
295
|
+
).map((inputPart, index) => (
|
|
296
|
+
<span
|
|
297
|
+
key={index}
|
|
298
|
+
className={`${inputPart.isBold ? "font-bold" : ""} ${
|
|
299
|
+
inputPart.isUnderline ? "underline" : ""
|
|
300
|
+
}`}
|
|
301
|
+
>
|
|
302
|
+
{inputPart.isEquation ? (
|
|
303
|
+
<span className="text-xl">
|
|
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={materialMap[answerMap[materialKey]]}
|
|
317
|
+
canFullScreen={true}
|
|
318
|
+
/>
|
|
319
|
+
)}
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
223
322
|
</div>
|
|
224
323
|
</div>
|
|
225
324
|
);
|
|
@@ -0,0 +1,231 @@
|
|
|
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;
|