catchup-library-web 1.0.0 → 1.0.2

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.
Files changed (51) hide show
  1. package/dist/index.d.mts +239 -2
  2. package/dist/index.d.ts +239 -2
  3. package/dist/index.js +4686 -2
  4. package/dist/index.mjs +4621 -1
  5. package/package.json +10 -2
  6. package/src/components/activities/DropdownActivityContent.tsx +73 -0
  7. package/src/components/activities/FillInTheBlanksActivityContent.tsx +102 -0
  8. package/src/components/activities/GroupingActivityContent.tsx +62 -0
  9. package/src/components/activities/MCMAActivityContent.tsx +65 -0
  10. package/src/components/activities/MCSAActivityContent.tsx +58 -0
  11. package/src/components/activities/MatchingActivityContent.tsx +57 -0
  12. package/src/components/activities/OpenEndedActivityContent.tsx +92 -0
  13. package/src/components/activities/OrderingActivityContent.tsx +59 -0
  14. package/src/components/activities/TrueFalseActivityContent.tsx +98 -0
  15. package/src/components/activities/body-content/ActivityBodyContent.tsx +108 -0
  16. package/src/components/activities/body-content/ShowBodyMediaByContentType.tsx +404 -0
  17. package/src/components/activities/empty-content/ActivityEmptyContent.tsx +15 -0
  18. package/src/components/activities/material-content/DropdownActivityMaterialContent.tsx +227 -0
  19. package/src/components/activities/material-content/FillInTheBlanksActivityMaterialContent.tsx +270 -0
  20. package/src/components/activities/material-content/GroupingActivityMaterialContent.tsx +359 -0
  21. package/src/components/activities/material-content/MCMAActivityMaterialContent.tsx +166 -0
  22. package/src/components/activities/material-content/MCSAActivityMaterialContent.tsx +165 -0
  23. package/src/components/activities/material-content/MatchingActivityMaterialContent.tsx +332 -0
  24. package/src/components/activities/material-content/OpenEndedActivityMaterialContent.tsx +818 -0
  25. package/src/components/activities/material-content/OrderingActivityMaterialContent.tsx +216 -0
  26. package/src/components/activities/material-content/ShowMaterialMediaByContentType.tsx +172 -0
  27. package/src/components/activities/material-content/TrueFalseActivityMaterialContent.tsx +217 -0
  28. package/src/components/activities/solution-content/ActivitySolutionContent.tsx +86 -0
  29. package/src/components/dividers/BlueVerticalDividerLine.tsx +13 -0
  30. package/src/components/dividers/DividerLine.tsx +5 -0
  31. package/src/components/dividers/VerticalDividerLine.tsx +5 -0
  32. package/src/components/dnds/DraggableDroppableItem.tsx +62 -0
  33. package/src/components/dnds/DraggableItem.tsx +41 -0
  34. package/src/components/dnds/DroppableItem.tsx +38 -0
  35. package/src/components/dropdowns/MediaDropdown.tsx +51 -0
  36. package/src/components/groups/InputGroup.tsx +330 -0
  37. package/src/hooks/useScreenSize.ts +40 -0
  38. package/src/index.ts +24 -0
  39. package/src/language/i18n.ts +10 -0
  40. package/src/properties/ActivityProperties.ts +204 -0
  41. package/src/properties/ButtonProperties.ts +1 -1
  42. package/src/properties/CommonProperties.ts +1 -1
  43. package/src/properties/DividerLineProperties.ts +3 -0
  44. package/src/properties/DnDProperties.ts +28 -0
  45. package/src/properties/DropdownProperties.ts +5 -0
  46. package/src/properties/EnumProperties.ts +11 -0
  47. package/src/properties/GroupProperties.ts +19 -0
  48. package/src/utilization/AppUtilization.ts +56 -0
  49. package/src/utilization/CatchtivityUtilization.ts +1566 -0
  50. package/src/utilization/StorageUtilization.ts +35 -0
  51. package/tsconfig.json +2 -1
@@ -0,0 +1,359 @@
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 "HIDDEN";
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;
@@ -0,0 +1,166 @@
1
+ import { InlineMath } from "react-katex";
2
+ import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
3
+ import ShowMaterialMediaByContentType from "./ShowMaterialMediaByContentType";
4
+ import i18n from "../../../language/i18n";
5
+ import BaseImage from "../../images/BaseImage";
6
+ import { IMCMAActivityMaterialProps } from "../../../properties/ActivityProperties";
7
+ import DividerLine from "../../dividers/DividerLine";
8
+
9
+ const MCMAActivityMaterialContent = ({
10
+ uniqueValue,
11
+ answer,
12
+ materialMap,
13
+ contentMap,
14
+ checkCanAnswerQuestion,
15
+ onChange,
16
+ isPreview,
17
+ }: IMCMAActivityMaterialProps) => {
18
+ const retrieveAnswerMap = () => {
19
+ const foundIndex = answer.data.findIndex(
20
+ (answerData: any) => answerData.type === "MCMA"
21
+ );
22
+ return answer.data[foundIndex].answerMap;
23
+ };
24
+
25
+ const retrieveCorrectAnswerList = () => {
26
+ return JSON.parse(Object.keys(materialMap)[0]);
27
+ };
28
+
29
+ const checkAnswerState = (
30
+ correctAnswerList: any,
31
+ currentAnswer: string,
32
+ learnerAnswer: string
33
+ ) => {
34
+ if (!isPreview) return "HIDDEN";
35
+ if (currentAnswer !== learnerAnswer) return "EMPTY";
36
+ const foundIndex = correctAnswerList.findIndex(
37
+ (correctAnswer: string) => correctAnswer === learnerAnswer
38
+ );
39
+ if (foundIndex !== -1) {
40
+ return "CORRECT";
41
+ }
42
+ return "INCORRECT";
43
+ };
44
+
45
+ const answerMap = retrieveAnswerMap();
46
+ const correctAnswerList = retrieveCorrectAnswerList();
47
+
48
+ return Object.keys(materialMap).map((materialKey, index) => {
49
+ return (
50
+ <div key={index} className="flex flex-row items-center my-1">
51
+ <div className="flex-1 flex flex-col justify-center border-catchup-lighter-gray rounded-catchup-xlarge px-5">
52
+ <div className="hidden md:block">
53
+ <span className="font-semibold text-xl opacity-60">
54
+ {i18n.t("please_select_mcma_text")}
55
+ </span>
56
+ </div>
57
+ <div className="hidden md:contents">
58
+ <DividerLine />
59
+ </div>
60
+ {checkCanAnswerQuestion() ? (
61
+ <div className="flex flex-row w-full flex-wrap ">
62
+ {materialMap[materialKey].map(
63
+ (materialSubKey: string, index: number) => {
64
+ const foundAnswer = answerMap[materialKey].find(
65
+ (learnerAnswer: string) => learnerAnswer === materialSubKey
66
+ );
67
+ const learnerAnswerState = checkAnswerState(
68
+ correctAnswerList,
69
+ materialSubKey,
70
+ foundAnswer
71
+ );
72
+ const foundIndex = correctAnswerList.findIndex(
73
+ (correctAnswer: string) => correctAnswer === materialSubKey
74
+ );
75
+ return (
76
+ <div
77
+ key={index}
78
+ className={`w-full flex flex-row items-center justify-center cursor-pointer my-2 gap-x-2 ${
79
+ (learnerAnswerState === "EMPTY" && foundIndex !== -1) ||
80
+ learnerAnswerState === "CORRECT"
81
+ ? "border-2 border-catchup-green rounded-catchup-xlarge"
82
+ : learnerAnswerState === "INCORRECT"
83
+ ? "border-2 border-catchup-red rounded-catchup-xlarge"
84
+ : ""
85
+ }`}
86
+ onClick={() => {
87
+ onChange(answer, materialKey, materialSubKey);
88
+ }}
89
+ >
90
+ <div className="">
91
+ <BaseImage
92
+ src={
93
+ answerMap[materialKey].includes(materialSubKey)
94
+ ? "/icons/checkbox.png"
95
+ : "/icons/empty-checkbox.png"
96
+ }
97
+ alt="checkbox-empty-checkbox"
98
+ size="small"
99
+ onClick={() => {}}
100
+ />
101
+ </div>
102
+ <div className="flex-1">
103
+ {contentMap.type === "TEXT" ? (
104
+ <p className="text-xl whitespace-pre-wrap">
105
+ {constructInputWithSpecialExpressionList(
106
+ materialSubKey
107
+ ).map((inputPart, index) => (
108
+ <span
109
+ key={index}
110
+ className={`${
111
+ inputPart.isBold ? "font-bold" : ""
112
+ } ${inputPart.isUnderline ? "underline" : ""}`}
113
+ >
114
+ {inputPart.isEquation ? (
115
+ <span className="text-2xl">
116
+ <InlineMath math={inputPart.value} />
117
+ </span>
118
+ ) : (
119
+ inputPart.value
120
+ )}
121
+ </span>
122
+ ))}
123
+ </p>
124
+ ) : (
125
+ <ShowMaterialMediaByContentType
126
+ key={`${uniqueValue}-${index}`}
127
+ contentType={contentMap.type}
128
+ src={materialSubKey}
129
+ canFullScreen={true}
130
+ />
131
+ )}
132
+ </div>
133
+ </div>
134
+ );
135
+ }
136
+ )}
137
+ </div>
138
+ ) : (
139
+ <p key={materialKey} className="text-xl">
140
+ {constructInputWithSpecialExpressionList(
141
+ answerMap[materialKey]
142
+ ).map((inputPart, index) => (
143
+ <span
144
+ key={index}
145
+ className={`${inputPart.isBold ? "font-bold" : ""} ${
146
+ inputPart.isUnderline ? "underline" : ""
147
+ }`}
148
+ >
149
+ {inputPart.isEquation ? (
150
+ <span className="text-2xl">
151
+ <InlineMath math={inputPart.value} />
152
+ </span>
153
+ ) : (
154
+ inputPart.value
155
+ )}
156
+ </span>
157
+ ))}
158
+ </p>
159
+ )}
160
+ </div>
161
+ </div>
162
+ );
163
+ });
164
+ };
165
+
166
+ export default MCMAActivityMaterialContent;
@@ -0,0 +1,165 @@
1
+ import { InlineMath } from "react-katex";
2
+ import ShowMaterialMediaByContentType from "./ShowMaterialMediaByContentType";
3
+ import i18n from "../../../language/i18n";
4
+ import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
5
+ import BaseImage from "../../images/BaseImage";
6
+ import { IMCSAActivityMaterialProps } from "../../../properties/ActivityProperties";
7
+ import DividerLine from "../../dividers/DividerLine";
8
+
9
+ const MCSAActivityMaterialContent = ({
10
+ uniqueValue,
11
+ answer,
12
+ materialMap,
13
+ contentMap,
14
+ checkCanAnswerQuestion,
15
+ onChange,
16
+ isPreview,
17
+ }: IMCSAActivityMaterialProps) => {
18
+ const retrieveAnswerMap = () => {
19
+ const foundIndex = answer.data.findIndex(
20
+ (answerData: any) => answerData.type === "MCSA"
21
+ );
22
+ return answer.data[foundIndex].answerMap;
23
+ };
24
+
25
+ const retrieveCorrectAnswer = () => {
26
+ return Object.keys(materialMap)[0];
27
+ };
28
+
29
+ const checkAnswerState = (
30
+ correctAnswer: string,
31
+ currentAnswer: string,
32
+ learnerAnswer: string
33
+ ) => {
34
+ if (!isPreview) return "HIDDEN";
35
+ if (currentAnswer !== learnerAnswer) return "EMPTY";
36
+ if (correctAnswer === learnerAnswer) {
37
+ return "CORRECT";
38
+ }
39
+ return "INCORRECT";
40
+ };
41
+
42
+ const answerMap = retrieveAnswerMap();
43
+ const correctAnswer = retrieveCorrectAnswer();
44
+
45
+ return Object.keys(materialMap).map((materialKey, index) => {
46
+ return (
47
+ <div className="flex flex-row items-center my-1" key={index}>
48
+ <div className="flex-1 flex flex-col justify-center border-catchup-lighter-gray rounded-catchup-xlarge px-5">
49
+ <div className="hidden md:block">
50
+ <span className="font-semibold text-xl opacity-60">
51
+ {i18n.t("please_select_mcsa_text")}
52
+ </span>
53
+ </div>
54
+ <div className="hidden md:contents">
55
+ <DividerLine />
56
+ </div>
57
+ {checkCanAnswerQuestion() ? (
58
+ <div
59
+ className={`flex flex-row w-full ${
60
+ Object.keys(materialMap[materialKey]).length <= 4
61
+ ? "justify-center"
62
+ : ""
63
+ } flex-wrap`}
64
+ >
65
+ {materialMap[materialKey].map(
66
+ (materialSubKey: string, index: number) => {
67
+ const learnerAnswerState = checkAnswerState(
68
+ correctAnswer,
69
+ materialSubKey,
70
+ answerMap[materialKey]
71
+ );
72
+
73
+ return (
74
+ <div
75
+ key={index}
76
+ className={`w-full flex flex-row items-center justify-center cursor-pointer my-2 gap-x-2 ${
77
+ (learnerAnswerState === "EMPTY" &&
78
+ materialSubKey === correctAnswer) ||
79
+ learnerAnswerState === "CORRECT"
80
+ ? "border-2 border-catchup-green rounded-catchup-xlarge"
81
+ : learnerAnswerState === "INCORRECT"
82
+ ? "border-2 border-catchup-red rounded-catchup-xlarge"
83
+ : ""
84
+ }`}
85
+ onClick={() => {
86
+ onChange(answer, materialKey, materialSubKey);
87
+ }}
88
+ >
89
+ <div className="">
90
+ <BaseImage
91
+ src={
92
+ answerMap[materialKey] === materialSubKey
93
+ ? "/icons/item-element.png"
94
+ : "/icons/not-selected-item-element.png"
95
+ }
96
+ alt="circle"
97
+ size="small"
98
+ onClick={() => {}}
99
+ />
100
+ </div>
101
+ <div className="flex-1">
102
+ {contentMap.type === "TEXT" ? (
103
+ <p className="text-xl whitespace-pre-wrap">
104
+ {constructInputWithSpecialExpressionList(
105
+ materialSubKey
106
+ ).map((inputPart, index) => (
107
+ <span
108
+ key={index}
109
+ className={`${
110
+ inputPart.isBold ? "font-bold" : ""
111
+ } ${inputPart.isUnderline ? "underline" : ""}`}
112
+ >
113
+ {inputPart.isEquation ? (
114
+ <span className="text-2xl">
115
+ <InlineMath math={inputPart.value} />
116
+ </span>
117
+ ) : (
118
+ inputPart.value
119
+ )}
120
+ </span>
121
+ ))}
122
+ </p>
123
+ ) : (
124
+ <ShowMaterialMediaByContentType
125
+ key={`${uniqueValue}-${index}`}
126
+ contentType={contentMap.type}
127
+ src={materialSubKey}
128
+ canFullScreen={true}
129
+ />
130
+ )}
131
+ </div>
132
+ </div>
133
+ );
134
+ }
135
+ )}
136
+ </div>
137
+ ) : (
138
+ <p className="text-xl whitespace-pre-wrap">
139
+ {constructInputWithSpecialExpressionList(
140
+ answerMap[materialKey]
141
+ ).map((inputPart, index) => (
142
+ <span
143
+ key={index}
144
+ className={`${inputPart.isBold ? "font-bold" : ""} ${
145
+ inputPart.isUnderline ? "underline" : ""
146
+ }`}
147
+ >
148
+ {inputPart.isEquation ? (
149
+ <span className="text-2xl">
150
+ <InlineMath math={inputPart.value} />
151
+ </span>
152
+ ) : (
153
+ inputPart.value
154
+ )}
155
+ </span>
156
+ ))}
157
+ </p>
158
+ )}
159
+ </div>
160
+ </div>
161
+ );
162
+ });
163
+ };
164
+
165
+ export default MCSAActivityMaterialContent;