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