catchup-library-web 1.15.3 → 1.15.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "catchup-library-web",
3
- "version": "1.15.3",
3
+ "version": "1.15.4",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -22,6 +22,7 @@
22
22
  "react-katex": "^3.0.1",
23
23
  "react-loader-spinner": "^6.1.6",
24
24
  "react-modal": "^3.16.3",
25
+ "react-pdf": "^10.0.1",
25
26
  "react-select": "^5.10.0"
26
27
  },
27
28
  "devDependencies": {
@@ -206,6 +206,7 @@ const ActivityPreviewByData = ({
206
206
  data["openEndedBodyMap"] != null ? (
207
207
  <OpenEndedActivityContent
208
208
  answer={answer}
209
+ canAnswerQuestion={() => false}
209
210
  changeAnswer={() => {}}
210
211
  showMaterialContent={true}
211
212
  data={data}
@@ -12,27 +12,12 @@ const OpenEndedActivityContent = ({
12
12
  answer,
13
13
  data,
14
14
  changeAnswer,
15
+ canAnswerQuestion,
15
16
  showMaterialContent,
16
17
  isFullScreen,
17
18
  }: IOpenEndedActivityProps) => {
18
- // const {
19
- // answer,
20
- // data,
21
- // canAnswerQuestion,
22
- // changeAnswer,
23
- // userId,
24
- // userProfileId,
25
- // catchtivityApplicationId,
26
- // catchxamApplicationId,
27
- // etudeId,
28
- // activityId,
29
- // activityTemplateId,
30
- // showMaterialContent,
31
- // storageStompClient,
32
- // } = props;
33
19
  const contentMap = parseContentMapFromData(data);
34
20
  const openEndedBodyMap = parseBodyMapFromData(data, "OPEN_ENDED");
35
- // const openEndedMaterialMap = JSON.parse(data.openEndedMaterialMap);
36
21
 
37
22
  const handleOpenEndedAnswerOnChange = (answer: any, value: string) => {
38
23
  let foundIndex = answer.data.findIndex(
@@ -74,23 +59,9 @@ const OpenEndedActivityContent = ({
74
59
  <OpenEndedActivityMaterialContent
75
60
  answer={answer}
76
61
  contentMap={contentMap}
77
- onChange={handleOpenEndedAnswerOnChange}
78
- />
79
- {/* <OpenEndedActivityMaterialContent
80
- answer={answer}
81
- bodyMap={openEndedBodyMap}
82
- contentMap={contentMap}
83
62
  checkCanAnswerQuestion={canAnswerQuestion}
84
63
  onChange={handleOpenEndedAnswerOnChange}
85
- userId={userId}
86
- userProfileId={userProfileId}
87
- catchtivityApplicationId={catchtivityApplicationId}
88
- catchxamApplicationId={catchxamApplicationId}
89
- etudeId={etudeId}
90
- activityId={activityId}
91
- activityTemplateId={activityTemplateId}
92
- storageStompClient={storageStompClient}
93
- /> */}
64
+ />
94
65
  </div>
95
66
  </>
96
67
  ) : null}
@@ -109,7 +109,6 @@ const ShowBodyMediaByContentType = ({
109
109
  const firstIndex = copyValue.indexOf(checkText);
110
110
  const textBeforeTag = copyValue.substring(0, firstIndex);
111
111
 
112
- // Handle text before the tag if it's not empty
113
112
  if (textBeforeTag.trim() !== "") {
114
113
  const balancedText = balanceSpecialChars(textBeforeTag);
115
114
  currentIndex++;
@@ -117,10 +116,9 @@ const ShowBodyMediaByContentType = ({
117
116
  valuePartList.push(renderTextContent(balancedText, itemKey));
118
117
  }
119
118
 
120
- // Process the text inside the tags
121
119
  const subValue = copyValue.substring(firstIndex + checkText.length);
122
120
  const secondIndex = subValue.indexOf(checkText);
123
- if (secondIndex === -1) break; // Safety check for malformed tags
121
+ if (secondIndex === -1) break;
124
122
 
125
123
  const textInsideTag = copyValue.substring(
126
124
  firstIndex + checkText.length,
@@ -138,26 +136,22 @@ const ShowBodyMediaByContentType = ({
138
136
  </span>
139
137
  );
140
138
 
141
- // Update copyValue to process the next occurrence
142
139
  copyValue = copyValue.substring(
143
140
  firstIndex + checkText.length + secondIndex + checkText.length
144
141
  );
145
142
 
146
- // Balance backticks in remaining text if needed
147
143
  if ((copyValue.split("`").length - 1) % 2 === 1) {
148
144
  copyValue = "`" + copyValue;
149
145
  }
150
146
  }
151
147
  };
152
148
 
153
- // Process IMAGE tags
154
149
  const processImageTags = () => {
155
150
  const checkText = "--IMAGE--";
156
151
  while (copyValue.includes(checkText)) {
157
152
  const firstIndex = copyValue.indexOf(checkText);
158
153
  const textBeforeTag = copyValue.substring(0, firstIndex);
159
154
 
160
- // Handle text before the tag if it's not empty
161
155
  if (textBeforeTag.trim() !== "") {
162
156
  currentIndex++;
163
157
  valuePartList.push(
@@ -170,10 +164,9 @@ const ShowBodyMediaByContentType = ({
170
164
  );
171
165
  }
172
166
 
173
- // Process the image source inside the tags
174
167
  const subValue = copyValue.substring(firstIndex + checkText.length);
175
168
  const secondIndex = subValue.indexOf(checkText);
176
- if (secondIndex === -1) break; // Safety check for malformed tags
169
+ if (secondIndex === -1) break;
177
170
 
178
171
  const imageSource = copyValue.substring(
179
172
  firstIndex + checkText.length,
@@ -206,21 +199,18 @@ const ShowBodyMediaByContentType = ({
206
199
  </div>
207
200
  );
208
201
 
209
- // Update copyValue to process the next occurrence
210
202
  copyValue = copyValue.substring(
211
203
  firstIndex + checkText.length + secondIndex + checkText.length
212
204
  );
213
205
  }
214
206
  };
215
207
 
216
- // Process VIDEO tags
217
208
  const processVideoTags = () => {
218
209
  const checkText = "--VIDEO--";
219
210
  while (copyValue.includes(checkText)) {
220
211
  const firstIndex = copyValue.indexOf(checkText);
221
212
  const textBeforeTag = copyValue.substring(0, firstIndex);
222
213
 
223
- // Handle text before the tag if it's not empty
224
214
  if (textBeforeTag.trim() !== "") {
225
215
  currentIndex++;
226
216
  valuePartList.push(
@@ -233,10 +223,9 @@ const ShowBodyMediaByContentType = ({
233
223
  );
234
224
  }
235
225
 
236
- // Process the video source inside the tags
237
226
  const subValue = copyValue.substring(firstIndex + checkText.length);
238
227
  const secondIndex = subValue.indexOf(checkText);
239
- if (secondIndex === -1) break; // Safety check for malformed tags
228
+ if (secondIndex === -1) break;
240
229
 
241
230
  const videoSource = copyValue.substring(
242
231
  firstIndex + checkText.length,
@@ -253,21 +242,18 @@ const ShowBodyMediaByContentType = ({
253
242
  />
254
243
  );
255
244
 
256
- // Update copyValue to process the next occurrence
257
245
  copyValue = copyValue.substring(
258
246
  firstIndex + checkText.length + secondIndex + checkText.length
259
247
  );
260
248
  }
261
249
  };
262
250
 
263
- // Process AUDIO tags
264
251
  const processAudioTags = () => {
265
252
  const checkText = "--AUDIO--";
266
253
  while (copyValue.includes(checkText)) {
267
254
  const firstIndex = copyValue.indexOf(checkText);
268
255
  const textBeforeTag = copyValue.substring(0, firstIndex);
269
256
 
270
- // Handle text before the tag if it's not empty
271
257
  if (textBeforeTag.trim() !== "") {
272
258
  currentIndex++;
273
259
  valuePartList.push(
@@ -280,10 +266,9 @@ const ShowBodyMediaByContentType = ({
280
266
  );
281
267
  }
282
268
 
283
- // Process the audio source inside the tags
284
269
  const subValue = copyValue.substring(firstIndex + checkText.length);
285
270
  const secondIndex = subValue.indexOf(checkText);
286
- if (secondIndex === -1) break; // Safety check for malformed tags
271
+ if (secondIndex === -1) break;
287
272
 
288
273
  const audioSource = copyValue.substring(
289
274
  firstIndex + checkText.length,
@@ -300,25 +285,21 @@ const ShowBodyMediaByContentType = ({
300
285
  />
301
286
  );
302
287
 
303
- // Update copyValue to process the next occurrence
304
288
  copyValue = copyValue.substring(
305
289
  firstIndex + checkText.length + secondIndex + checkText.length
306
290
  );
307
291
  }
308
292
  };
309
293
 
310
- // Process all types of tags
311
294
  processTextTags();
312
295
  processImageTags();
313
296
  processVideoTags();
314
297
  processAudioTags();
315
298
 
316
- // Handle any remaining text
317
299
  if (copyValue.trim() !== "") {
318
300
  currentIndex++;
319
301
  copyValue = balanceSpecialChars(copyValue);
320
302
 
321
- // Check for image description markup
322
303
  const regexMatchImageText = copyValue.match(/<image>([\s\S]*?)<\/image>/);
323
304
  if (regexMatchImageText) {
324
305
  const imageText = regexMatchImageText[1];
@@ -334,7 +315,6 @@ const ShowBodyMediaByContentType = ({
334
315
  </div>
335
316
  );
336
317
  } else {
337
- // Handle normal remaining text
338
318
  const itemKey = `remaining-${index}-${currentIndex}`;
339
319
  valuePartList.push(renderTextContent(copyValue, itemKey));
340
320
  }
@@ -2,10 +2,14 @@ import InputGroup from "../../groups/InputGroup";
2
2
  import i18n from "../../../language/i18n";
3
3
  import DividerLine from "../../dividers/DividerLine";
4
4
  import { IOpenEndedActivityMaterialProps } from "../../../properties/ActivityProperties";
5
+ import { retrieveDocumentTypeFromExtension } from "../../../utilization/StorageUtilization";
6
+ import BaseImage from "../../images/BaseImage";
7
+ import BasePDF from "../../pdfs/BasePDF";
5
8
 
6
9
  const OpenEndedActivityMaterialContent = ({
7
10
  answer,
8
11
  contentMap,
12
+ checkCanAnswerQuestion,
9
13
  onChange,
10
14
  }: IOpenEndedActivityMaterialProps) => {
11
15
  const retrieveAnswer = () => {
@@ -33,12 +37,52 @@ const OpenEndedActivityMaterialContent = ({
33
37
  value={answerMapAnswer}
34
38
  useMinHeight={true}
35
39
  onChange={(e) => {
36
- onChange(answer, e.target.value);
40
+ if (checkCanAnswerQuestion()) {
41
+ onChange(answer, e.target.value);
42
+ }
37
43
  }}
38
44
  />
39
45
  );
40
46
  };
41
47
 
48
+ const RenderImageContent = (answerMap: any) => {
49
+ const answerMapAnswer = answerMap["ANSWER"];
50
+ const extension = answerMapAnswer.split(".").pop();
51
+ const documentType = retrieveDocumentTypeFromExtension(extension);
52
+ return (
53
+ <>
54
+ {documentType === "IMAGE" ? (
55
+ <div className="flex flex-col justify-center items-center my-5">
56
+ <BaseImage
57
+ src={answerMapAnswer}
58
+ alt="document"
59
+ size="custom"
60
+ className="w-[80%] rounded-catchup-xlarge"
61
+ />
62
+ </div>
63
+ ) : documentType === "PDF" ? (
64
+ <div className="flex flex-col justify-center items-center my-5">
65
+ <BasePDF file={answerMapAnswer} />
66
+ </div>
67
+ ) : null}
68
+ </>
69
+ );
70
+ };
71
+
72
+ const RenderAudioContent = (answerMap: any) => {
73
+ const answerMapAnswer = answerMap["ANSWER"];
74
+ return (
75
+ <div className="h-[56px]">
76
+ <audio
77
+ className="h-full w-full rounded-catchup-xlarge"
78
+ src={answerMapAnswer}
79
+ controls
80
+ onClick={() => {}}
81
+ />
82
+ </div>
83
+ );
84
+ };
85
+
42
86
  const answerMap = retrieveAnswerMap();
43
87
 
44
88
  return (
@@ -52,7 +96,13 @@ const OpenEndedActivityMaterialContent = ({
52
96
  <div className="hidden md:contents">
53
97
  <DividerLine />
54
98
  </div>
55
- {contentMap.type === "TEXT" ? RenderTextContent(answerMap) : null}
99
+ {contentMap.type === "TEXT"
100
+ ? RenderTextContent(answerMap)
101
+ : contentMap.type === "IMAGE"
102
+ ? RenderImageContent(answerMap)
103
+ : contentMap.type === "AUDIO"
104
+ ? RenderAudioContent(answerMap)
105
+ : null}
56
106
  </div>
57
107
  </>
58
108
  );
@@ -0,0 +1,69 @@
1
+ import { useState } from "react";
2
+ import { Document, Page } from "react-pdf";
3
+ import BaseImage from "../images/BaseImage";
4
+ import { IBasePDFProps } from "../../properties/PDFProperties";
5
+
6
+ const BasePDF = ({ file }: IBasePDFProps) => {
7
+ const [pageNumber, setPageNumber] = useState(1);
8
+ const [numberOfPages, setNumberOfPages] = useState(0);
9
+
10
+ const handleOnDocumentLoadSuccess = ({ numPages }: any) => {
11
+ setPageNumber(1);
12
+ setNumberOfPages(numPages);
13
+ };
14
+
15
+ return (
16
+ <Document file={file} onLoadSuccess={handleOnDocumentLoadSuccess}>
17
+ <Page pageNumber={pageNumber} />
18
+ <div className="flex flex-row items-center justify-center">
19
+ {pageNumber === 1 ? null : (
20
+ <div className="px-2">
21
+ <div className="cursor-pointer">
22
+ <BaseImage
23
+ alt="arrow-left"
24
+ src="/icons/arrow-left.webp"
25
+ size="small"
26
+ onClick={() => {
27
+ setPageNumber(pageNumber - 1);
28
+ }}
29
+ />
30
+ </div>
31
+ </div>
32
+ )}
33
+ {Array.from(Array(numberOfPages).keys())
34
+ .filter((index) => index < pageNumber + 5)
35
+ .filter((index) => index > pageNumber - 5)
36
+ .map((index) => (
37
+ <div key={index} className="px-2">
38
+ <p
39
+ className={`${
40
+ pageNumber === index + 1 ? "text-2xl" : "text-md"
41
+ } cursor-pointer`}
42
+ onClick={() => {
43
+ setPageNumber(index + 1);
44
+ }}
45
+ >
46
+ {index + 1}
47
+ </p>
48
+ </div>
49
+ ))}
50
+ {numberOfPages === 0 || pageNumber === numberOfPages ? null : (
51
+ <div className="px-2">
52
+ <div className="cursor-pointer">
53
+ <BaseImage
54
+ src="/icons/arrow-right.webp"
55
+ alt="arrow-right"
56
+ size="small"
57
+ onClick={() => {
58
+ setPageNumber(pageNumber + 1);
59
+ }}
60
+ />
61
+ </div>
62
+ </div>
63
+ )}
64
+ </div>
65
+ </Document>
66
+ );
67
+ };
68
+
69
+ export default BasePDF;
package/src/index.ts CHANGED
@@ -18,6 +18,8 @@ export { default as BaseLoadingWithText } from "./components/loading/BaseLoading
18
18
 
19
19
  export { default as BaseModal } from "./components/modals/BaseModal";
20
20
 
21
+ export { default as BasePDF } from "./components/pdfs/BasePDF";
22
+
21
23
  export { default as ActivityEmptyContent } from "./components/activities/empty-content/ActivityEmptyContent";
22
24
  export { default as ActivityBodyContent } from "./components/activities/body-content/ActivityBodyContent";
23
25
  export { default as DropdownActivityContent } from "./components/activities/DropdownActivityContent";
@@ -169,6 +169,7 @@ export interface IOpenEndedActivityProps {
169
169
  answer: any;
170
170
  data: any;
171
171
  changeAnswer: (e: any) => void;
172
+ canAnswerQuestion: () => boolean;
172
173
  showMaterialContent: boolean;
173
174
  isFullScreen: boolean;
174
175
  }
@@ -176,6 +177,7 @@ export interface IOpenEndedActivityProps {
176
177
  export interface IOpenEndedActivityMaterialProps {
177
178
  answer: any;
178
179
  contentMap: any;
180
+ checkCanAnswerQuestion: () => boolean;
179
181
  onChange: (e1: any, e2: any) => void;
180
182
  }
181
183
 
@@ -0,0 +1,3 @@
1
+ export interface IBasePDFProps {
2
+ file: string;
3
+ }