catchup-library-web 1.20.29 → 1.20.31

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.
@@ -1,18 +1,13 @@
1
1
  import { InlineMath } from "react-katex";
2
- import InputGroup from "../../groups/InputGroup";
3
- import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
4
- import i18n from "../../../language/i18n";
5
- import { useState } from "react";
6
- import { useEffect } from "react";
7
- import { useDrop } from "react-dnd";
2
+ import { useState, useEffect } from "react";
8
3
  import BaseImage from "../../images/BaseImage";
9
4
  import { shuffleArray } from "../../../utilization/AppUtilization";
10
- import DraggableItem from "../../dnds/DraggableItem";
11
- import DroppableItem from "../../dnds/DroppableItem";
12
5
  import ShowMaterialMediaByContentType from "./ShowMaterialMediaByContentType";
13
6
  import DividerLine from "../../dividers/DividerLine";
14
7
  import { IFillInTheBlanksActivityMaterialProps } from "../../../properties/ActivityProperties";
15
8
  import InputWithSpecialExpression from "../../texts/InputWithSpecialExpression";
9
+ import i18n from "../../../language/i18n";
10
+ import { constructInputWithSpecialExpressionList } from "../../../utilization/CatchtivityUtilization";
16
11
 
17
12
  const FillInTheBlanksActivityMaterialContent = ({
18
13
  uniqueValue,
@@ -27,15 +22,8 @@ const FillInTheBlanksActivityMaterialContent = ({
27
22
  }: IFillInTheBlanksActivityMaterialProps) => {
28
23
  const [shuffleOptionList, setShuffleOptionList] = useState([]);
29
24
  const [selectedOption, setSelectedOption] = useState(null);
30
- const [pasteOptionIndex, setPasteOptionIndex] = useState(null);
31
- const [{ isOver, canDrop }, drop] = useDrop({
32
- accept: "FILL_IN_THE_BLANKS",
33
- drop: () => {},
34
- collect: (monitor) => ({
35
- isOver: monitor.isOver(),
36
- canDrop: monitor.canDrop(),
37
- }),
38
- });
25
+ const [draggedOption, setDraggedOption] = useState(null);
26
+ const [dropTargetIndex, setDropTargetIndex] = useState(null);
39
27
 
40
28
  useEffect(() => {
41
29
  setShuffleOptionList(shuffleArray(optionList));
@@ -80,14 +68,41 @@ const FillInTheBlanksActivityMaterialContent = ({
80
68
  );
81
69
  };
82
70
 
71
+ const handleSelectOption = (option: any) => {
72
+ setSelectedOption(option);
73
+ };
74
+
75
+ const handleDragStart = (option: any) => {
76
+ setDraggedOption(option);
77
+ };
78
+
79
+ const handleDragEnd = () => {
80
+ if (dropTargetIndex !== null && draggedOption !== null) {
81
+ onChange(answer, dropTargetIndex, draggedOption);
82
+ }
83
+ setDraggedOption(null);
84
+ setDropTargetIndex(null);
85
+ };
86
+
87
+ const handleDropZoneEnter = (index: any) => {
88
+ setDropTargetIndex(index);
89
+ };
90
+
91
+ const handleDropZoneDrop = (index: any) => {
92
+ if (selectedOption !== null) {
93
+ onChange(answer, index, selectedOption);
94
+ setSelectedOption(null);
95
+ } else if (draggedOption !== null) {
96
+ onChange(answer, index, draggedOption);
97
+ setDraggedOption(null);
98
+ }
99
+ setDropTargetIndex(null);
100
+ };
101
+
83
102
  const answerMap = retrieveAnswerMap();
84
103
 
85
104
  return (
86
- <div
87
- className="flex flex-row flex-wrap items-center"
88
- onMouseUp={() => {}}
89
- onTouchStart={() => {}}
90
- >
105
+ <div className="flex flex-row flex-wrap items-center">
91
106
  <div className="hidden md:block">
92
107
  <span className="font-semibold text-xl opacity-60">
93
108
  {i18n.t("please_select_fill_in_the_blanks_text")}
@@ -109,55 +124,43 @@ const FillInTheBlanksActivityMaterialContent = ({
109
124
  />
110
125
  </div>
111
126
  ) : (
112
- <DraggableItem
127
+ <div
113
128
  key={index}
114
- item={{ index: option }}
115
- type={"FILL_IN_THE_BLANKS"}
116
- component={
117
- contentMap.type === "TEXT" ? (
118
- <div
119
- className="border-catchup-blue border-2 px-2 rounded-catchup-xlarge cursor-pointer"
120
- onMouseDown={() => {
121
- setSelectedOption(option);
122
- setPasteOptionIndex(null);
123
- }}
124
- onTouchEnd={() => {
125
- setSelectedOption(option);
126
- setPasteOptionIndex(null);
127
- }}
128
- >
129
- <p className="italic whitespace-pre-wrap">
130
- <InputWithSpecialExpression
131
- value={option}
132
- showSpecialOnly={false}
133
- />
134
- </p>
135
- </div>
136
- ) : (
137
- <div
138
- className="border-catchup-blue border-2 px-2 py-1 rounded-catchup-xlarge cursor-pointer"
139
- onMouseDown={() => {
140
- setSelectedOption(option);
141
- setPasteOptionIndex(null);
142
- }}
143
- onTouchEnd={() => {
144
- setSelectedOption(option);
145
- setPasteOptionIndex(null);
146
- }}
147
- >
148
- <ShowMaterialMediaByContentType
149
- key={`${uniqueValue}-${index}`}
150
- contentType={contentMap.type}
151
- src={option}
152
- canFullScreen={true}
129
+ draggable
130
+ onDragStart={() => handleDragStart(option)}
131
+ onDragEnd={handleDragEnd}
132
+ className={`${
133
+ draggedOption === option ? "opacity-40" : "opacity-100"
134
+ } transition-opacity duration-200`}
135
+ >
136
+ {contentMap.type === "TEXT" ? (
137
+ <div
138
+ className="border-catchup-blue border-2 px-2 rounded-catchup-xlarge cursor-pointer select-none touch-none"
139
+ onClick={() => handleSelectOption(option)}
140
+ onTouchEnd={() => handleSelectOption(option)}
141
+ >
142
+ <p className="italic whitespace-pre-wrap">
143
+ <InputWithSpecialExpression
144
+ value={option}
145
+ showSpecialOnly={false}
153
146
  />
154
- </div>
155
- )
156
- }
157
- moveCardHandler={() => {
158
- onChange(answer, pasteOptionIndex, selectedOption);
159
- }}
160
- />
147
+ </p>
148
+ </div>
149
+ ) : (
150
+ <div
151
+ className="border-catchup-blue border-2 px-2 py-1 rounded-catchup-xlarge cursor-pointer select-none touch-none"
152
+ onClick={() => handleSelectOption(option)}
153
+ onTouchEnd={() => handleSelectOption(option)}
154
+ >
155
+ <ShowMaterialMediaByContentType
156
+ key={`${uniqueValue}-${index}`}
157
+ contentType={contentMap.type}
158
+ src={option}
159
+ canFullScreen={true}
160
+ />
161
+ </div>
162
+ )}
163
+ </div>
161
164
  )
162
165
  )}
163
166
  </div>
@@ -170,123 +173,133 @@ const FillInTheBlanksActivityMaterialContent = ({
170
173
  return (
171
174
  <div key={index} className="w-full md:w-1/2">
172
175
  <div className="mx-2">
173
- <DroppableItem
174
- key={index}
175
- item={{ index }}
176
- type={"FILL_IN_THE_BLANKS"}
177
- target={pasteOptionIndex}
178
- setTarget={setPasteOptionIndex}
179
- dropRef={drop}
180
- component={
181
- <div className="w-full flex flex-row my-2 gap-x-2">
182
- <div className="my-auto">
183
- <p className="text-xl">
184
- {parseFloat(materialKey) + 1}.
185
- </p>
186
- </div>
187
- <div className="flex-1">
188
- {checkCanAnswerQuestion() ? (
189
- contentMap.type === "TEXT" ? (
190
- <div className="relative">
191
- <div className="flex-1">
192
- <div
193
- className={`w-full min-h-[44px] border rounded-lg ${
194
- answerMap[materialKey]
195
- ? "border-catchup-blue-400 px-2"
196
- : "bg-catchup-gray-50 border-catchup-gray-200 border-dashed py-2 px-4"
197
- }`}
198
- onClick={() => {
199
- if (answerMap[materialKey]) {
200
- onChange(answer, materialKey, "");
201
- }
202
- }}
203
- >
204
- {answerMap[materialKey] ? (
205
- <InputWithSpecialExpression
206
- value={answerMap[materialKey]}
207
- showSpecialOnly={false}
208
- />
209
- ) : (
210
- <p className="text-gray-400 italic"></p>
211
- )}
212
- </div>
213
- </div>
214
-
215
- {learnerAnswerState === "CORRECT" ? (
216
- <div className="absolute -top-[10px] right-4 bg-catchup-white">
217
- <BaseImage
218
- src="/icons/checkbox.webp"
219
- alt="checkbox"
220
- size="small"
221
- />
222
- </div>
223
- ) : learnerAnswerState === "INCORRECT" ? (
224
- <div className="absolute -top-[10px] right-4 bg-catchup-white">
225
- <BaseImage
226
- src="/icons/cross-red.webp"
227
- alt="cross-red"
228
- size="small"
176
+ <div
177
+ onDragOver={(e) => {
178
+ e.preventDefault();
179
+ handleDropZoneEnter(materialKey);
180
+ }}
181
+ onDragLeave={() => setDropTargetIndex(null)}
182
+ onDrop={(e) => {
183
+ e.preventDefault();
184
+ handleDropZoneDrop(materialKey);
185
+ }}
186
+ onClick={() => {
187
+ if (selectedOption !== null) {
188
+ handleDropZoneDrop(materialKey);
189
+ }
190
+ }}
191
+ className={`${
192
+ dropTargetIndex === materialKey
193
+ ? "ring-2 ring-blue-400"
194
+ : ""
195
+ }`}
196
+ >
197
+ <div className="w-full flex flex-row my-2 gap-x-2">
198
+ <div className="my-auto">
199
+ <p className="text-xl">{parseFloat(materialKey) + 1}.</p>
200
+ </div>
201
+ <div className="flex-1">
202
+ {checkCanAnswerQuestion() ? (
203
+ contentMap.type === "TEXT" ? (
204
+ <div className="relative">
205
+ <div className="flex-1">
206
+ <div
207
+ className={`w-full min-h-[44px] border rounded-lg ${
208
+ answerMap[materialKey]
209
+ ? "border-catchup-blue-400 px-2"
210
+ : "bg-catchup-gray-50 border-catchup-gray-200 border-dashed py-2 px-4"
211
+ }`}
212
+ onClick={() => {
213
+ if (answerMap[materialKey]) {
214
+ onChange(answer, materialKey, "");
215
+ }
216
+ }}
217
+ >
218
+ {answerMap[materialKey] ? (
219
+ <InputWithSpecialExpression
220
+ value={answerMap[materialKey]}
221
+ showSpecialOnly={false}
229
222
  />
230
- </div>
231
- ) : null}
232
- </div>
233
- ) : answerMap[materialKey] === "" ? (
234
- <div
235
- className={`w-catchup-activity-media-box-item h-catchup-activity-media-box-item border rounded-catchup-xlarge border-dashed ${
236
- learnerAnswerState === "CORRECT"
237
- ? "border-catchup-green"
238
- : learnerAnswerState === "INCORRECT"
239
- ? "border-catchup-red"
240
- : "border-catchup-blue"
241
- }`}
242
- >
243
- <div className="h-full flex flex-col items-center justify-center px-4 py-2">
244
- <span className="italic">
245
- {i18n.t("please_drop_here")}
246
- </span>
223
+ ) : (
224
+ <p className="text-gray-400 italic"></p>
225
+ )}
247
226
  </div>
248
227
  </div>
249
- ) : (
250
- <div
251
- className="flex-1 cursor-pointer"
252
- onClick={() => {
253
- onChange(answer, materialKey, "");
254
- }}
255
- >
256
- <ShowMaterialMediaByContentType
257
- key={`${uniqueValue}-${index}`}
258
- contentType={contentMap.type}
259
- src={answerMap[materialKey]}
260
- canFullScreen={true}
261
- />
228
+
229
+ {learnerAnswerState === "CORRECT" ? (
230
+ <div className="absolute -top-[10px] right-4 bg-catchup-white">
231
+ <BaseImage
232
+ src="/icons/checkbox.webp"
233
+ alt="checkbox"
234
+ size="small"
235
+ />
236
+ </div>
237
+ ) : learnerAnswerState === "INCORRECT" ? (
238
+ <div className="absolute -top-[10px] right-4 bg-catchup-white">
239
+ <BaseImage
240
+ src="/icons/cross-red.webp"
241
+ alt="cross-red"
242
+ size="small"
243
+ />
244
+ </div>
245
+ ) : null}
246
+ </div>
247
+ ) : answerMap[materialKey] === "" ? (
248
+ <div
249
+ className={`w-catchup-activity-media-box-item h-catchup-activity-media-box-item border rounded-catchup-xlarge border-dashed ${
250
+ learnerAnswerState === "CORRECT"
251
+ ? "border-catchup-green"
252
+ : learnerAnswerState === "INCORRECT"
253
+ ? "border-catchup-red"
254
+ : "border-catchup-blue"
255
+ }`}
256
+ >
257
+ <div className="h-full flex flex-col items-center justify-center px-4 py-2">
258
+ <span className="italic">
259
+ {i18n.t("please_drop_here")}
260
+ </span>
262
261
  </div>
263
- )
262
+ </div>
264
263
  ) : (
265
- <p key={materialKey} className="text-xl">
266
- {constructInputWithSpecialExpressionList(
267
- answerMap[materialKey]
268
- ).map((inputPart, index) => (
269
- <span
270
- key={index}
271
- className={`${
272
- inputPart.isBold ? "font-bold" : ""
273
- } ${inputPart.isUnderline ? "underline" : ""}`}
274
- >
275
- {inputPart.isEquation ? (
276
- <span className="text-xl">
277
- <InlineMath math={inputPart.value} />
278
- </span>
279
- ) : (
280
- inputPart.value
281
- )}
282
- </span>
283
- ))}
284
- </p>
285
- )}
286
- </div>
264
+ <div
265
+ className="flex-1 cursor-pointer"
266
+ onClick={() => {
267
+ onChange(answer, materialKey, "");
268
+ }}
269
+ >
270
+ <ShowMaterialMediaByContentType
271
+ key={`${uniqueValue}-${index}`}
272
+ contentType={contentMap.type}
273
+ src={answerMap[materialKey]}
274
+ canFullScreen={true}
275
+ />
276
+ </div>
277
+ )
278
+ ) : (
279
+ <p key={materialKey} className="text-xl">
280
+ {constructInputWithSpecialExpressionList(
281
+ answerMap[materialKey]
282
+ ).map((inputPart, index) => (
283
+ <span
284
+ key={index}
285
+ className={`${
286
+ inputPart.isBold ? "font-bold" : ""
287
+ } ${inputPart.isUnderline ? "underline" : ""}`}
288
+ >
289
+ {inputPart.isEquation ? (
290
+ <span className="text-xl">
291
+ <InlineMath math={inputPart.value} />
292
+ </span>
293
+ ) : (
294
+ inputPart.value
295
+ )}
296
+ </span>
297
+ ))}
298
+ </p>
299
+ )}
287
300
  </div>
288
- }
289
- />
301
+ </div>
302
+ </div>
290
303
  </div>
291
304
  </div>
292
305
  );