catchup-library-web 1.11.0 → 1.11.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.
@@ -0,0 +1,301 @@
1
+ import { useEffect, useState } from "react";
2
+ import DropdownActivityContent from "./DropdownActivityContent";
3
+ import FillInTheBlanksActivityContent from "./FillInTheBlanksActivityContent";
4
+ import GroupingActivityContent from "./GroupingActivityContent";
5
+ import MatchingActivityContent from "./MatchingActivityContent";
6
+ import MCMAActivityContent from "./MCMAActivityContent";
7
+ import MCSAActivityContent from "./MCSAActivityContent";
8
+ import OpenEndedActivityContent from "./OpenEndedActivityContent";
9
+ import OrderingActivityContent from "./OrderingActivityContent";
10
+ import SelectionBox from "../boxes/SelectionBox";
11
+ import TrueFalseActivityContent from "./TrueFalseActivityContent";
12
+ import ActivitySolutionContent from "./solution-content/ActivitySolutionContent";
13
+ import ActivityEvaluationRubricContent from "./evaluation-rubric-content/ActivityEvaluationRubricContent";
14
+ import DividerLine from "../dividers/DividerLine";
15
+ import i18n from "../../language/i18n";
16
+ import { constructActivityAnswerMap } from "../../utilization/CatchtivityUtilization";
17
+ import { IActivityPreviewByAnswerDataProps } from "../../properties/ActivityProperties";
18
+ import ActivityEmptyContent from "./empty-content/ActivityEmptyContent";
19
+
20
+ const ActivityPreviewByAnswerData = ({
21
+ data,
22
+ showType = true,
23
+ showDescription = true,
24
+ lockedType = null,
25
+ typeOptionList = [],
26
+ showSolution = false,
27
+ showEvaluationRubric = false,
28
+ showTaxonomy = true,
29
+ isFullScreen = false,
30
+ showCorrectAnswer = false,
31
+ }: IActivityPreviewByAnswerDataProps) => {
32
+ const [key, setKey] = useState(new Date().getTime());
33
+ const [selectedType, setSelectedType] = useState<string | null>(null);
34
+ const [optionList, setOptionList] = useState<any[]>([]);
35
+ // Define proper types for answer data
36
+ interface AnswerItem {
37
+ type: string;
38
+ isEmpty?: boolean;
39
+ answerMap?: any;
40
+ [key: string]: any;
41
+ }
42
+
43
+ interface Answer {
44
+ data: AnswerItem[];
45
+ }
46
+
47
+ const [answer, setAnswer] = useState<Answer>({ data: [] });
48
+
49
+ // Reset component when data changes
50
+ useEffect(() => {
51
+ if (!data) return;
52
+ setKey(new Date().getTime());
53
+ }, [data]);
54
+
55
+ // Helper function to check if answer map exists for a specific type
56
+ const checkAnswerMapExists = (type: string): AnswerItem | null => {
57
+ if (data && data.answerMap && Array.isArray(data.answerMap)) {
58
+ const foundAnswer = data.answerMap.find(
59
+ (answer: any) => answer.type === type
60
+ );
61
+ return foundAnswer || null;
62
+ }
63
+ return null;
64
+ };
65
+
66
+ // Helper function to retrieve taxonomy name from activity type
67
+ const retrieveTaxonomyNameFromActivityType = (type: string) => {
68
+ if (!data) return "";
69
+
70
+ let taxonomyMap = { name: "" };
71
+
72
+ const taxonomyMapNames: { [key: string]: string } = {
73
+ ORDERING: "orderingTaxonomyMap",
74
+ DROPDOWN: "dropdownTaxonomyMap",
75
+ MCSA: "MCSATaxonomyMap",
76
+ MCMA: "MCMATaxonomyMap",
77
+ MATCHING: "matchingTaxonomyMap",
78
+ GROUPING: "groupingTaxonomyMap",
79
+ FILL_IN_THE_BLANKS: "fillInTheBlanksTaxonomyMap",
80
+ OPEN_ENDED: "openEndedTaxonomyMap",
81
+ TRUE_FALSE: "trueFalseTaxonomyMap",
82
+ };
83
+
84
+ const mapName = taxonomyMapNames[type];
85
+ if (mapName && data[mapName]) {
86
+ try {
87
+ taxonomyMap = JSON.parse(data[mapName]);
88
+ } catch (error) {
89
+ console.error(`Error parsing taxonomy map for ${type}:`, error);
90
+ }
91
+ }
92
+
93
+ return taxonomyMap.name || "";
94
+ };
95
+
96
+ // Construct answer data based on available activity types
97
+ useEffect(() => {
98
+ if (!data) return;
99
+
100
+ const constructAnswerBasedOnData = () => {
101
+ const newAnswer: Answer = { data: [] };
102
+
103
+ const activityTypes = [
104
+ { type: "ORDERING", materialMap: "orderingMaterialMap" },
105
+ { type: "DROPDOWN", materialMap: "dropdownMaterialMap" },
106
+ { type: "MCSA", materialMap: "MCSAMaterialMap" },
107
+ { type: "MCMA", materialMap: "MCMAMaterialMap" },
108
+ { type: "MATCHING", materialMap: "matchingMaterialMap" },
109
+ { type: "GROUPING", materialMap: "groupingMaterialMap" },
110
+ {
111
+ type: "FILL_IN_THE_BLANKS",
112
+ materialMap: "fillInTheBlanksMaterialMap",
113
+ },
114
+ { type: "OPEN_ENDED", materialMap: "openEndedMaterialMap" },
115
+ { type: "TRUE_FALSE", materialMap: "trueFalseMaterialMap" },
116
+ ];
117
+
118
+ activityTypes.forEach(({ type, materialMap }) => {
119
+ if (data[materialMap]) {
120
+ const foundAnswer = checkAnswerMapExists(type);
121
+ const answerItem: AnswerItem =
122
+ foundAnswer ||
123
+ constructActivityAnswerMap(
124
+ { type },
125
+ JSON.parse(JSON.stringify(data))
126
+ );
127
+ newAnswer.data.push(answerItem);
128
+ }
129
+ });
130
+
131
+ setAnswer(newAnswer);
132
+
133
+ // Set initial selected type
134
+ if (newAnswer.data.length > 0) {
135
+ if (
136
+ lockedType &&
137
+ newAnswer.data.find((item: AnswerItem) => item.type === lockedType)
138
+ ) {
139
+ setSelectedType(lockedType);
140
+ } else {
141
+ setSelectedType(newAnswer.data[0].type);
142
+ }
143
+ }
144
+ };
145
+
146
+ constructAnswerBasedOnData();
147
+ }, [data, lockedType]);
148
+
149
+ // Set up option list for type selection
150
+ useEffect(() => {
151
+ if (!data || !answer.data.length) return;
152
+
153
+ let currentTypeOptionList =
154
+ typeOptionList ||
155
+ answer.data.map((item) => ({
156
+ id: item.type,
157
+ text: i18n.t(item.type),
158
+ }));
159
+
160
+ if (lockedType) {
161
+ currentTypeOptionList = currentTypeOptionList.filter(
162
+ (typeOption: any) => typeOption.id === lockedType
163
+ );
164
+ }
165
+
166
+ if (showTaxonomy) {
167
+ setOptionList(
168
+ currentTypeOptionList.map((typeOption: any) => ({
169
+ ...typeOption,
170
+ subText: i18n.t(retrieveTaxonomyNameFromActivityType(typeOption.id)),
171
+ }))
172
+ );
173
+ } else {
174
+ setOptionList(currentTypeOptionList);
175
+ }
176
+ }, [data, answer.data, lockedType, typeOptionList, showTaxonomy]);
177
+
178
+ // Render the appropriate activity content based on selected type
179
+ const RenderSelectedActivityContent = () => {
180
+ const commonProps = {
181
+ answer,
182
+ data,
183
+ canAnswerQuestion: () => true,
184
+ changeAnswer: (newAnswer: Answer) =>
185
+ setAnswer(JSON.parse(JSON.stringify(newAnswer))),
186
+ isPreview: true,
187
+ showCorrectAnswer,
188
+ isFullScreen,
189
+ };
190
+
191
+ switch (selectedType) {
192
+ case "ORDERING":
193
+ return data.orderingBodyMap && data.orderingMaterialMap ? (
194
+ <OrderingActivityContent {...commonProps} />
195
+ ) : null;
196
+
197
+ case "DROPDOWN":
198
+ return data.dropdownBodyMap && data.dropdownMaterialMap ? (
199
+ <DropdownActivityContent {...commonProps} />
200
+ ) : null;
201
+
202
+ case "MCSA":
203
+ return data.MCSABodyMap && data.MCSAMaterialMap ? (
204
+ <MCSAActivityContent {...commonProps} />
205
+ ) : null;
206
+
207
+ case "MCMA":
208
+ return data.MCMABodyMap && data.MCMAMaterialMap ? (
209
+ <MCMAActivityContent {...commonProps} />
210
+ ) : null;
211
+
212
+ case "MATCHING":
213
+ return data.matchingBodyMap && data.matchingMaterialMap ? (
214
+ <MatchingActivityContent {...commonProps} />
215
+ ) : null;
216
+
217
+ case "GROUPING":
218
+ return data.groupingBodyMap && data.groupingMaterialMap ? (
219
+ <GroupingActivityContent {...commonProps} />
220
+ ) : null;
221
+
222
+ case "FILL_IN_THE_BLANKS":
223
+ return data.fillInTheBlanksBodyMap &&
224
+ data.fillInTheBlanksMaterialMap ? (
225
+ <FillInTheBlanksActivityContent {...commonProps} />
226
+ ) : null;
227
+
228
+ case "OPEN_ENDED":
229
+ return data.openEndedBodyMap ? (
230
+ <OpenEndedActivityContent
231
+ {...commonProps}
232
+ showMaterialContent={true}
233
+ />
234
+ ) : null;
235
+
236
+ case "TRUE_FALSE":
237
+ return data.trueFalseBodyMap && data.trueFalseMaterialMap ? (
238
+ <TrueFalseActivityContent {...commonProps} />
239
+ ) : null;
240
+
241
+ default:
242
+ return null;
243
+ }
244
+ };
245
+
246
+ if (!data) return null;
247
+
248
+ return (
249
+ <div key={key}>
250
+ {showType && optionList.length > 0 ? (
251
+ <div className="mb-4">
252
+ {showDescription ? (
253
+ <div className="my-2">
254
+ <p className="font-semibold text-lg">
255
+ {i18n.t("activity_template")}
256
+ </p>
257
+ </div>
258
+ ) : null}
259
+
260
+ <SelectionBox
261
+ optionList={optionList}
262
+ selectedId={selectedType}
263
+ handleSelectOnClick={(itemId) => {
264
+ setSelectedType(itemId);
265
+ }}
266
+ />
267
+ </div>
268
+ ) : null}
269
+
270
+ <DividerLine />
271
+
272
+ <div className="flex flex-col my-2 w-full p-5">
273
+ {answer?.data[0]?.isEmpty ? <ActivityEmptyContent /> : null}
274
+
275
+ {selectedType ? (
276
+ <div key={selectedType}>{RenderSelectedActivityContent()}</div>
277
+ ) : null}
278
+ </div>
279
+
280
+ {selectedType && showSolution ? (
281
+ <div className="my-4">
282
+ <ActivitySolutionContent
283
+ activityTemplateType={selectedType}
284
+ data={data}
285
+ />
286
+ </div>
287
+ ) : null}
288
+
289
+ {selectedType && showEvaluationRubric ? (
290
+ <div className="my-4">
291
+ <ActivityEvaluationRubricContent
292
+ activityTemplateType={selectedType}
293
+ data={data}
294
+ />
295
+ </div>
296
+ ) : null}
297
+ </div>
298
+ );
299
+ };
300
+
301
+ export default ActivityPreviewByAnswerData;
package/src/index.ts CHANGED
@@ -26,6 +26,7 @@ export { default as TrueFalseActivityContent } from "./components/activities/Tru
26
26
  export { default as ActivitySolutionContent } from "./components/activities/solution-content/ActivitySolutionContent";
27
27
  export { default as ActivityEvaluationRubricContent } from "./components/activities/evaluation-rubric-content/ActivityEvaluationRubricContent";
28
28
  export { default as ActivityPreviewByData } from "./components/activities/ActivityPreviewByData";
29
+ export { default as ActivityPreviewByAnswerData } from "./components/activities/ActivityPreviewByAnswerData";
29
30
 
30
31
  export { default as BlueVerticalDividerLine } from "./components/dividers/BlueVerticalDividerLine";
31
32
  export { default as DividerLine } from "./components/dividers/DividerLine";
@@ -228,3 +228,16 @@ export interface IActivityPreviewByDataProps {
228
228
  showEvaluationRubric: boolean;
229
229
  isFullScreen: boolean;
230
230
  }
231
+
232
+ export interface IActivityPreviewByAnswerDataProps {
233
+ data: any;
234
+ showType?: boolean;
235
+ showDescription?: boolean;
236
+ lockedType?: string | null;
237
+ typeOptionList?: any[];
238
+ showSolution?: boolean;
239
+ showEvaluationRubric?: boolean;
240
+ showTaxonomy?: boolean;
241
+ isFullScreen?: boolean;
242
+ showCorrectAnswer?: boolean;
243
+ }