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,342 @@
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
+ onMouseUp={() => {
146
+ if (checkCanAnswerQuestion()) {
147
+ setSelectedValue(null);
148
+ }
149
+ }}
150
+ >
151
+ {contentMap.type === "TEXT" ? (
152
+ <div
153
+ className={`flex flex-col items-center justify-center m-2 min-w-[200px] overflow-y-auto`}
154
+ >
155
+ <p className="text-lg whitespace-pre-wrap">
156
+ {constructInputWithSpecialExpressionList(
157
+ materialValue
158
+ ).map((inputPart, index) => (
159
+ <span
160
+ key={index}
161
+ className={`${
162
+ inputPart.isBold ? "font-bold" : ""
163
+ } ${inputPart.isUnderline ? "underline" : ""}`}
164
+ >
165
+ {inputPart.isEquation ? (
166
+ <span className="text-xl">
167
+ <InlineMath math={inputPart.value} />
168
+ </span>
169
+ ) : (
170
+ inputPart.value
171
+ )}
172
+ </span>
173
+ ))}
174
+ </p>
175
+ </div>
176
+ ) : (
177
+ <ShowMaterialMediaByContentType
178
+ key={`${uniqueValue}-${index}`}
179
+ contentType={contentMap.type}
180
+ src={materialValue}
181
+ canFullScreen={true}
182
+ />
183
+ )}
184
+ </div>
185
+ }
186
+ moveCardHandler={() => {
187
+ if (!selectedTargetKey) return;
188
+ if (!selectedValue) return;
189
+ handleMatchingActivityItemOnChange(
190
+ selectedTargetKey,
191
+ selectedValue
192
+ );
193
+ }}
194
+ />
195
+ ))}
196
+ </div>
197
+ <div className="flex-shrink-0">
198
+ <DividerLine />
199
+ </div>
200
+ </>
201
+ ) : null}
202
+
203
+ <div className="overflow-y-auto max-h-[600px]">
204
+ {Object.keys(answerMap).map((answerMapKey, index) => {
205
+ const learnerAnswerState = checkAnswerState(
206
+ materialMap[answerMapKey],
207
+ answerMap[answerMapKey]
208
+ );
209
+
210
+ return (
211
+ <div key={index} className="flex flex-row w-full">
212
+ <div className="w-1/3">
213
+ <div
214
+ className={`${
215
+ contentMap.type === "TEXT"
216
+ ? "h-catchup-activity-text-box-item"
217
+ : "h-catchup-activity-media-box-item"
218
+ } flex flex-col items-center justify-center border-2 rounded-catchup-xlarge transition-all duration-300 my-3 ${
219
+ learnerAnswerState === "EMPTY"
220
+ ? "border-catchup-blue"
221
+ : learnerAnswerState === "CORRECT"
222
+ ? "border-catchup-green"
223
+ : learnerAnswerState === "INCORRECT"
224
+ ? "border-catchup-red"
225
+ : "border-catchup-blue"
226
+ }`}
227
+ >
228
+ <div className="flex flex-col items-center justify-center transition-all duration-300 m-4">
229
+ <p className="text-lg whitespace-pre-wrap">
230
+ {constructInputWithSpecialExpressionList(
231
+ answerMapKey
232
+ ).map((inputPart, index) => (
233
+ <span
234
+ key={index}
235
+ className={`${inputPart.isBold ? "font-bold" : ""} ${
236
+ inputPart.isUnderline ? "underline" : ""
237
+ }`}
238
+ >
239
+ {inputPart.isEquation ? (
240
+ <span className="text-xl">
241
+ <InlineMath math={inputPart.value} />
242
+ </span>
243
+ ) : (
244
+ inputPart.value
245
+ )}
246
+ </span>
247
+ ))}
248
+ </p>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ <div className="mx-4 w-[2px] bg-catchup-lighter-gray"></div>
253
+ <div className="flex-1">
254
+ <div
255
+ className={`${
256
+ canDrop
257
+ ? selectedTargetKey === answerMapKey
258
+ ? "bg-catchup-light-blue"
259
+ : "bg-catchup-light-blue opacity-40"
260
+ : ""
261
+ } ${
262
+ contentMap.type === "TEXT"
263
+ ? "h-catchup-activity-text-box-item"
264
+ : "h-catchup-activity-media-box-item"
265
+ } flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer transition-all duration-300 my-3 ${
266
+ learnerAnswerState === "EMPTY"
267
+ ? "border-catchup-blue"
268
+ : learnerAnswerState === "CORRECT"
269
+ ? "border-catchup-green"
270
+ : learnerAnswerState === "INCORRECT"
271
+ ? "border-catchup-red"
272
+ : "border-catchup-blue"
273
+ }`}
274
+ onClick={() => {
275
+ if (checkCanAnswerQuestion()) {
276
+ setSelectedValue(null);
277
+ }
278
+ }}
279
+ >
280
+ <DroppableItem
281
+ key={index}
282
+ item={{ index: answerMapKey }}
283
+ type={"MATCHING"}
284
+ target={selectedTargetKey}
285
+ setTarget={setSelectedTargetKey}
286
+ dropRef={drop}
287
+ component={
288
+ <div
289
+ className="h-full flex-1 flex flex-row items-center justify-center"
290
+ onClick={(e) => {
291
+ e.preventDefault();
292
+ if (checkCanAnswerQuestion()) {
293
+ handleMatchingActivityItemOnChange(
294
+ answerMapKey,
295
+ null
296
+ );
297
+ }
298
+ }}
299
+ >
300
+ {contentMap.type === "TEXT" ? (
301
+ <p className="text-lg whitespace-pre-wrap">
302
+ {constructInputWithSpecialExpressionList(
303
+ answerMap[answerMapKey]
304
+ ).map((inputPart, index) => (
305
+ <span
306
+ key={index}
307
+ className={`${
308
+ inputPart.isBold ? "font-bold" : ""
309
+ } ${inputPart.isUnderline ? "underline" : ""}`}
310
+ >
311
+ {inputPart.isEquation ? (
312
+ <span className="text-xl">
313
+ <InlineMath math={inputPart.value} />
314
+ </span>
315
+ ) : (
316
+ inputPart.value
317
+ )}
318
+ </span>
319
+ ))}
320
+ </p>
321
+ ) : (
322
+ <ShowMaterialMediaByContentType
323
+ key={`${uniqueValue}-${index}`}
324
+ contentType={contentMap.type}
325
+ src={answerMap[answerMapKey]}
326
+ canFullScreen={false}
327
+ />
328
+ )}
329
+ </div>
330
+ }
331
+ />
332
+ </div>
333
+ </div>
334
+ </div>
335
+ );
336
+ })}
337
+ </div>
338
+ </>
339
+ );
340
+ };
341
+
342
+ export default MatchingActivityMaterialContent;
@@ -82,9 +82,9 @@ const OrderingActivityMaterialContent = ({
82
82
  if (index === 0) {
83
83
  return 0;
84
84
  } else if (index === 1) {
85
- return 150;
85
+ return 65;
86
86
  } else if (index % 2 === 0) {
87
- return -150;
87
+ return -65;
88
88
  } else if (index % 2 === 1) {
89
89
  return 0;
90
90
  }
@@ -112,9 +112,7 @@ const OrderingActivityMaterialContent = ({
112
112
  }}
113
113
  >
114
114
  <div className="mr-3">
115
- <div
116
- className={`min-h-catchup-activity-outer-box-item w-catchup-activity-box-item flex flex-col items-center justify-center cursor-pointer transition-all duration-300`}
117
- >
115
+ <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">
118
116
  <div
119
117
  className={`${
120
118
  selectedKey === materialKey
@@ -142,7 +140,11 @@ const OrderingActivityMaterialContent = ({
142
140
  : "bg-catchup-light-blue rounded-catchup-xlarge opacity-40"
143
141
  : ""
144
142
  : ""
145
- } flex-1 min-h-catchup-activity-outer-box-item flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer p-3 ${
143
+ } ${
144
+ contentMap.type === "TEXT"
145
+ ? "h-catchup-activity-text-box-item"
146
+ : "h-catchup-activity-media-box-item"
147
+ } flex flex-col items-center justify-center border-2 rounded-catchup-xlarge cursor-pointer p-3 ${
146
148
  learnerAnswerState === "CORRECT"
147
149
  ? "border-catchup-green"
148
150
  : learnerAnswerState === "INCORRECT"
@@ -167,7 +169,7 @@ const OrderingActivityMaterialContent = ({
167
169
  } ${inputPart.isUnderline ? "underline" : ""}`}
168
170
  >
169
171
  {inputPart.isEquation ? (
170
- <span className="text-2xl">
172
+ <span className="text-xl">
171
173
  <InlineMath math={inputPart.value} />
172
174
  </span>
173
175
  ) : (
@@ -92,15 +92,15 @@ const ShowMaterialMediaByContentType = ({
92
92
  };
93
93
 
94
94
  return contentType === "IMAGE" ? (
95
- <div key={key}>
95
+ <>
96
96
  {RenderShowFullScreenItem()}
97
97
  <div className="my-2">
98
98
  <div className="h-full flex flex-row flex-wrap items-center">
99
99
  <div
100
100
  className={`${
101
101
  isFullHeight
102
- ? "h-catchup-activity-box-item"
103
- : "max-w-catchup-activity-box-item"
102
+ ? "h-catchup-activity-media-box-item"
103
+ : "max-w-catchup-activity-media-box-item"
104
104
  } flex flex-col justify-center items-center relative`}
105
105
  >
106
106
  <BaseImage
@@ -139,13 +139,13 @@ const ShowMaterialMediaByContentType = ({
139
139
  </div>
140
140
  </div>
141
141
  </div>
142
- </div>
142
+ </>
143
143
  ) : contentType === "VIDEO" ? (
144
144
  <div className="my-2">
145
145
  <div className="h-full flex flex-row flex-wrap items-center">
146
146
  <div className="h-full flex flex-col justify-center items-center">
147
147
  <video
148
- className="h-catchup-activity-box-item rounded-catchup-xlarge"
148
+ className="h-catchup-activity-media-box-item rounded-catchup-xlarge"
149
149
  src={src}
150
150
  controls
151
151
  onClick={() => {}}
@@ -158,7 +158,7 @@ const ShowMaterialMediaByContentType = ({
158
158
  <div className="h-full flex flex-row flex-wrap items-center">
159
159
  <div className="h-full flex flex-col justify-center items-center">
160
160
  <audio
161
- className="h-catchup-activity-box-item rounded-catchup-xlarge"
161
+ className="h-catchup-activity-media-box-item rounded-catchup-xlarge"
162
162
  src={src}
163
163
  controls
164
164
  onClick={() => {}}
@@ -130,7 +130,7 @@ const TrueFalseActivityMaterialContent = ({
130
130
  }`}
131
131
  >
132
132
  {inputPart.isEquation ? (
133
- <span className="text-2xl">
133
+ <span className="text-xl">
134
134
  <InlineMath math={inputPart.value} />
135
135
  </span>
136
136
  ) : (
@@ -68,7 +68,7 @@ const ActivitySolutionContent = ({
68
68
  }`}
69
69
  >
70
70
  {inputPart.isEquation ? (
71
- <span className="text-2xl">
71
+ <span className="text-xl">
72
72
  <InlineMath math={inputPart.value} />
73
73
  </span>
74
74
  ) : (
package/src/index.ts CHANGED
@@ -21,8 +21,8 @@ export { default as BaseModal } from "./components/modals/BaseModal";
21
21
 
22
22
  export { default as BasePDF } from "./components/pdfs/BasePDF";
23
23
 
24
- export { default as ActivityEmptyContent } from "./components/activities/empty-content/ActivityEmptyContent";
25
- export { default as ActivityBodyContent } from "./components/activities/body-content/ActivityBodyContent";
24
+ export { default as ActivityEmptyContent } from "./components/activities/empty-contents/ActivityEmptyContent";
25
+ export { default as ActivityBodyContent } from "./components/activities/body-contents/ActivityBodyContent";
26
26
  export { default as DropdownActivityContent } from "./components/activities/DropdownActivityContent";
27
27
  export { default as FillInTheBlanksActivityContent } from "./components/activities/FillInTheBlanksActivityContent";
28
28
  export { default as GroupingActivityContent } from "./components/activities/GroupingActivityContent";
@@ -32,8 +32,8 @@ export { default as MCSAActivityContent } from "./components/activities/MCSAActi
32
32
  export { default as OpenEndedActivityContent } from "./components/activities/OpenEndedActivityContent";
33
33
  export { default as OrderingActivityContent } from "./components/activities/OrderingActivityContent";
34
34
  export { default as TrueFalseActivityContent } from "./components/activities/TrueFalseActivityContent";
35
- export { default as ActivitySolutionContent } from "./components/activities/solution-content/ActivitySolutionContent";
36
- export { default as ActivityEvaluationRubricContent } from "./components/activities/evaluation-rubric-content/ActivityEvaluationRubricContent";
35
+ export { default as ActivitySolutionContent } from "./components/activities/solution-contents/ActivitySolutionContent";
36
+ export { default as ActivityEvaluationRubricContent } from "./components/activities/evaluation-rubric-contents/ActivityEvaluationRubricContent";
37
37
  export { default as ActivityPreviewByData } from "./components/activities/ActivityPreviewByData";
38
38
  export { default as ActivityPreviewByAnswerData } from "./components/activities/ActivityPreviewByAnswerData";
39
39
 
@@ -108,7 +108,6 @@ export interface IGroupingActivityProps {
108
108
  changeAnswer: (e: any) => void;
109
109
  isPreview: boolean;
110
110
  showCorrectAnswer: boolean;
111
- isFullScreen: boolean;
112
111
  }
113
112
 
114
113
  export interface IGroupingActivityMaterialProps {
@@ -129,7 +128,6 @@ export interface IMatchingActivityProps {
129
128
  changeAnswer: (e: any) => void;
130
129
  isPreview: boolean;
131
130
  showCorrectAnswer: boolean;
132
- isFullScreen: boolean;
133
131
  }
134
132
 
135
133
  export interface IMatchingActivityMaterialProps {
@@ -171,6 +169,7 @@ export interface IOpenEndedActivityProps {
171
169
  changeAnswer: (e: any) => void;
172
170
  canAnswerQuestion: () => boolean;
173
171
  showMaterialContent: boolean;
172
+ isPreview: boolean;
174
173
  isFullScreen: boolean;
175
174
  }
176
175