@omniumretail/component-library 1.0.65 → 1.0.66

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 (176) hide show
  1. package/.storybook/main.js +16 -16
  2. package/.storybook/preview-head.html +20 -20
  3. package/.storybook/preview.js +27 -27
  4. package/README.md +54 -54
  5. package/bitbucket-pipelines.yml +94 -94
  6. package/package.json +198 -198
  7. package/src/assets/scss/_global.scss +89 -89
  8. package/src/assets/scss/index.scss +2 -2
  9. package/src/components/AnalyticsBar/AnalyticsBar.stories.tsx +236 -236
  10. package/src/components/AnalyticsBar/helpers/codeMutation.tsx +19 -19
  11. package/src/components/AnalyticsBar/index.tsx +76 -76
  12. package/src/components/AnalyticsBar/interfaces/analyticsBar.tsx +13 -13
  13. package/src/components/AnalyticsBar/styles.module.scss +108 -108
  14. package/src/components/Button/Button.stories.tsx +26 -26
  15. package/src/components/Button/index.tsx +24 -24
  16. package/src/components/Button/styles.module.scss +65 -65
  17. package/src/components/Category/Category.stories.tsx +88 -88
  18. package/src/components/Category/CategoryContent/index.tsx +188 -188
  19. package/src/components/Category/CategoryContent/styles.module.scss +51 -51
  20. package/src/components/Category/CategorySidebar/index.tsx +268 -268
  21. package/src/components/Category/CategorySidebar/styles.module.scss +28 -28
  22. package/src/components/Category/index.tsx +76 -76
  23. package/src/components/Category/styles.module.scss +13 -13
  24. package/src/components/CategoryReadOnly/CategoryReadOnly.stories.tsx +270 -270
  25. package/src/components/CategoryReadOnly/evaluationOptions.tsx +81 -81
  26. package/src/components/CategoryReadOnly/index.tsx +254 -254
  27. package/src/components/CategoryReadOnly/styles.module.scss +184 -184
  28. package/src/components/CategoryResponse/CategoryResponse.stories.tsx +251 -251
  29. package/src/components/CategoryResponse/evaluationOptions.tsx +81 -81
  30. package/src/components/CategoryResponse/index.tsx +277 -277
  31. package/src/components/CategoryResponse/styles.module.scss +160 -160
  32. package/src/components/DatePicker/DatePicker.stories.tsx +16 -16
  33. package/src/components/DatePicker/index.tsx +38 -38
  34. package/src/components/DatePicker/styles.module.scss +3 -3
  35. package/src/components/DatePickerTag/DatePickerTag.stories.tsx +19 -19
  36. package/src/components/DatePickerTag/index.tsx +89 -89
  37. package/src/components/DatePickerTag/styles.module.scss +31 -31
  38. package/src/components/Footer/Footer.stories.tsx +14 -14
  39. package/src/components/Footer/index.tsx +38 -38
  40. package/src/components/Footer/styles.module.scss +38 -38
  41. package/src/components/Input/Input.stories.tsx +13 -13
  42. package/src/components/Input/index.tsx +31 -31
  43. package/src/components/Input/styles.module.scss +8 -8
  44. package/src/components/InputCountryCode/index.tsx +75 -75
  45. package/src/components/InputCountryCode/inputCountryCode.stories.tsx +55 -55
  46. package/src/components/InputCountryCode/styles.module.scss +3 -3
  47. package/src/components/Label/Label.stories.tsx +21 -21
  48. package/src/components/Label/index.tsx +19 -19
  49. package/src/components/Label/styles.module.scss +16 -16
  50. package/src/components/Link/Link.stories.tsx +30 -30
  51. package/src/components/Link/index.tsx +21 -21
  52. package/src/components/Link/styles.module.scss +24 -24
  53. package/src/components/Menu/Menu.stories.tsx +178 -178
  54. package/src/components/Menu/helpers/codeMutation.tsx +19 -19
  55. package/src/components/Menu/index.tsx +23 -23
  56. package/src/components/ModalConfirmation/ModalConfirmation.stories.tsx +40 -40
  57. package/src/components/ModalConfirmation/ModalStatusList.tsx +5 -5
  58. package/src/components/ModalConfirmation/index.tsx +70 -70
  59. package/src/components/ModalConfirmation/styles.module.scss +62 -62
  60. package/src/components/ModalWithTable/ModalWithTable.stories.tsx +96 -96
  61. package/src/components/ModalWithTable/index.tsx +232 -232
  62. package/src/components/ModalWithTable/styles.module.scss +77 -77
  63. package/src/components/Navigation/Navigation.stories.tsx +17 -17
  64. package/src/components/Navigation/index.tsx +33 -33
  65. package/src/components/Navigation/styles.module.scss +42 -42
  66. package/src/components/Notification/Notification.stories.tsx +29 -29
  67. package/src/components/Notification/index.tsx +21 -21
  68. package/src/components/Questions/Questions.stories.tsx +37 -37
  69. package/src/components/Questions/SingleQuestion/index.tsx +84 -84
  70. package/src/components/Questions/SingleQuestion/styles.module.scss +81 -81
  71. package/src/components/Questions/index.tsx +78 -78
  72. package/src/components/Radio/Radio.stories.tsx +43 -43
  73. package/src/components/Radio/index.tsx +26 -26
  74. package/src/components/Radio/styles.module.scss +23 -23
  75. package/src/components/Select/Select.stories.tsx +39 -39
  76. package/src/components/Select/index.tsx +27 -27
  77. package/src/components/Select/styles.module.scss +13 -13
  78. package/src/components/Separator/Separator.stories.tsx +22 -22
  79. package/src/components/Separator/index.tsx +27 -27
  80. package/src/components/Separator/styles.module.scss +25 -25
  81. package/src/components/Sidebar/Sidebar.stories.tsx +85 -61
  82. package/src/components/Sidebar/index.tsx +104 -58
  83. package/src/components/Sidebar/styles.module.scss +86 -73
  84. package/src/components/Switch/Switch.stories.tsx +14 -14
  85. package/src/components/Switch/index.tsx +8 -8
  86. package/src/components/Switch/styles.module.scss +7 -7
  87. package/src/components/Table/Table.stories.tsx +221 -221
  88. package/src/components/Table/index.tsx +271 -271
  89. package/src/components/Table/styles.module.scss +75 -75
  90. package/src/components/Tag/Tag.stories.tsx +22 -22
  91. package/src/components/Tag/index.tsx +189 -189
  92. package/src/components/Tag/styles.module.scss +60 -60
  93. package/src/components/Upload/Upload.stories.tsx +45 -45
  94. package/src/components/Upload/index.tsx +91 -91
  95. package/src/components/UserInfo/UserInfo.stories.tsx +37 -37
  96. package/src/components/UserInfo/index.tsx +62 -62
  97. package/src/components/UserInfo/styles.module.scss +29 -29
  98. package/src/components/index.tsx +25 -25
  99. package/src/constants/i18n.ts +25 -25
  100. package/src/constants/translationHelper.ts +7 -7
  101. package/src/index.ts +2 -2
  102. package/src/locales/en.json +86 -86
  103. package/src/locales/es.json +86 -86
  104. package/src/locales/pt.json +86 -86
  105. package/src/types/Global.d.ts +4 -4
  106. package/tsconfig.json +29 -29
  107. package/webpack.config.js +51 -51
  108. package/dist/bundle.js +0 -12047
  109. package/dist/main.css +0 -1199
  110. package/dist/types/components/AnalyticsBar/AnalyticsBar.stories.d.ts +0 -5
  111. package/dist/types/components/AnalyticsBar/helpers/codeMutation.d.ts +0 -4
  112. package/dist/types/components/AnalyticsBar/index.d.ts +0 -2
  113. package/dist/types/components/AnalyticsBar/interfaces/analyticsBar.d.ts +0 -12
  114. package/dist/types/components/Button/Button.stories.d.ts +0 -6
  115. package/dist/types/components/Button/index.d.ts +0 -7
  116. package/dist/types/components/Category/Category.stories.d.ts +0 -4
  117. package/dist/types/components/Category/CategoryContent/index.d.ts +0 -7
  118. package/dist/types/components/Category/CategorySidebar/index.d.ts +0 -26
  119. package/dist/types/components/Category/index.d.ts +0 -7
  120. package/dist/types/components/CategoryReadOnly/CategoryReadOnly.stories.d.ts +0 -4
  121. package/dist/types/components/CategoryReadOnly/evaluationOptions.d.ts +0 -10
  122. package/dist/types/components/CategoryReadOnly/index.d.ts +0 -9
  123. package/dist/types/components/CategoryResponse/CategoryResponse.stories.d.ts +0 -4
  124. package/dist/types/components/CategoryResponse/evaluationOptions.d.ts +0 -10
  125. package/dist/types/components/CategoryResponse/index.d.ts +0 -9
  126. package/dist/types/components/DatePicker/DatePicker.stories.d.ts +0 -5
  127. package/dist/types/components/DatePicker/index.d.ts +0 -8
  128. package/dist/types/components/DatePickerTag/DatePickerTag.stories.d.ts +0 -5
  129. package/dist/types/components/DatePickerTag/index.d.ts +0 -6
  130. package/dist/types/components/Footer/Footer.stories.d.ts +0 -5
  131. package/dist/types/components/Footer/index.d.ts +0 -4
  132. package/dist/types/components/Input/Input.stories.d.ts +0 -5
  133. package/dist/types/components/Input/index.d.ts +0 -10
  134. package/dist/types/components/InputCountryCode/index.d.ts +0 -10
  135. package/dist/types/components/InputCountryCode/inputCountryCode.stories.d.ts +0 -5
  136. package/dist/types/components/Label/Label.stories.d.ts +0 -6
  137. package/dist/types/components/Label/index.d.ts +0 -7
  138. package/dist/types/components/Link/Link.stories.d.ts +0 -7
  139. package/dist/types/components/Link/index.d.ts +0 -7
  140. package/dist/types/components/Menu/Menu.stories.d.ts +0 -5
  141. package/dist/types/components/Menu/helpers/codeMutation.d.ts +0 -4
  142. package/dist/types/components/Menu/index.d.ts +0 -2
  143. package/dist/types/components/ModalConfirmation/ModalConfirmation.stories.d.ts +0 -5
  144. package/dist/types/components/ModalConfirmation/ModalStatusList.d.ts +0 -5
  145. package/dist/types/components/ModalConfirmation/index.d.ts +0 -9
  146. package/dist/types/components/ModalWithTable/ModalWithTable.stories.d.ts +0 -5
  147. package/dist/types/components/ModalWithTable/index.d.ts +0 -13
  148. package/dist/types/components/Navigation/Navigation.stories.d.ts +0 -5
  149. package/dist/types/components/Navigation/index.d.ts +0 -10
  150. package/dist/types/components/Notification/Notification.stories.d.ts +0 -5
  151. package/dist/types/components/Notification/index.d.ts +0 -9
  152. package/dist/types/components/Questions/Questions.stories.d.ts +0 -4
  153. package/dist/types/components/Questions/SingleQuestion/index.d.ts +0 -1
  154. package/dist/types/components/Questions/index.d.ts +0 -5
  155. package/dist/types/components/Radio/Radio.stories.d.ts +0 -5
  156. package/dist/types/components/Radio/index.d.ts +0 -10
  157. package/dist/types/components/Select/Select.stories.d.ts +0 -6
  158. package/dist/types/components/Select/index.d.ts +0 -5
  159. package/dist/types/components/Separator/Separator.stories.d.ts +0 -6
  160. package/dist/types/components/Separator/index.d.ts +0 -11
  161. package/dist/types/components/Sidebar/Sidebar.stories.d.ts +0 -6
  162. package/dist/types/components/Sidebar/index.d.ts +0 -13
  163. package/dist/types/components/Switch/Switch.stories.d.ts +0 -5
  164. package/dist/types/components/Switch/index.d.ts +0 -2
  165. package/dist/types/components/Table/Table.stories.d.ts +0 -9
  166. package/dist/types/components/Table/index.d.ts +0 -36
  167. package/dist/types/components/Tag/Tag.stories.d.ts +0 -5
  168. package/dist/types/components/Tag/index.d.ts +0 -8
  169. package/dist/types/components/Upload/Upload.stories.d.ts +0 -4
  170. package/dist/types/components/Upload/index.d.ts +0 -8
  171. package/dist/types/components/UserInfo/UserInfo.stories.d.ts +0 -4
  172. package/dist/types/components/UserInfo/index.d.ts +0 -8
  173. package/dist/types/components/index.d.ts +0 -25
  174. package/dist/types/constants/i18n.d.ts +0 -1
  175. package/dist/types/constants/translationHelper.d.ts +0 -2
  176. package/dist/types/index.d.ts +0 -2
@@ -1,277 +1,277 @@
1
- import styles from './styles.module.scss';
2
- import { useEffect, useImperativeHandle, useState } from 'react';
3
- import { Form } from 'antd';
4
- import { useForm } from 'antd/es/form/Form';
5
- import { Button } from '../Button';
6
- import classNames from 'classnames';
7
- import TextArea from 'antd/es/input/TextArea';
8
- import { Select } from '../Select';
9
- import { evaluationOptions } from './evaluationOptions';
10
- import React from 'react';
11
- import { t } from 'i18next';
12
-
13
- interface CategoryResponse {
14
- data: any;
15
- serverReadyData: any;
16
- onNextCategoryAvailabilityChange: (hasNext: boolean) => void;
17
- onPreviousCategoryAvailabilityChange: (hasPrevious: boolean) => void;
18
- };
19
-
20
- type Category = {
21
- Title: string;
22
- Key: string;
23
- Data: any;
24
- Children?: Category[];
25
- };
26
-
27
- const updateCategoryAnswers = (CategoryAnswers: any[], categoryToUpdate: any, updatedQuestions: any) => {
28
- CategoryAnswers.forEach((category: any) => {
29
- if (category.Data.CategoryId === categoryToUpdate.CategoryId) {
30
- category.Data.Questions = category.Data.Questions.map((question: any, index: any) => {
31
- return {
32
- ...question,
33
- Answer: updatedQuestions[index].Answer
34
- };
35
- });
36
- }
37
- else if (category.Children && category.Children.length > 0) {
38
- updateCategoryAnswers(category.Children, categoryToUpdate, updatedQuestions);
39
- }
40
- });
41
- return CategoryAnswers;
42
- };
43
-
44
- const findCategoryWithQuestions = (currentKey: string, categories: Category[], direction: 'next' | 'prev'): Category | null => {
45
- let foundCurrent = false;
46
-
47
- const searchCategories = (categoryList: Category[], direction: 'next' | 'prev'): Category | null => {
48
- const iterable = direction === 'next' ? categoryList : [...categoryList].reverse();
49
-
50
- for (const category of iterable) {
51
- if (foundCurrent) {
52
- if (category.Data.Questions.length > 0) {
53
- return category;
54
- }
55
- } else if (category.Key === currentKey) {
56
- foundCurrent = true;
57
- }
58
-
59
- if (category.Children) {
60
- const result = searchCategories(category.Children, direction);
61
- if (result) {
62
- return result;
63
- }
64
- }
65
- }
66
- return null;
67
- };
68
-
69
- return searchCategories(categories, direction);
70
- };
71
-
72
- const getCategoryObject = (currentKey: string, categories: Category[], direction: 'next' | 'prev'): any => {
73
- const category = findCategoryWithQuestions(currentKey, categories, direction);
74
- return category ? category.Data : null;
75
- };
76
-
77
- const hasCategory = (currentKey: string, categories: Category[], direction: 'next' | 'prev'): boolean => {
78
- const category = findCategoryWithQuestions(currentKey, categories, direction);
79
- return !!category;
80
- };
81
-
82
- const getTitleWithQuestionCount = (category: any): string => {
83
- const questionCount = category?.Data?.Questions?.length;
84
- const answeredQuestions = category?.Data?.Questions?.filter((question: any) => question.Answer !== null && question.Answer !== undefined && question.Answer !== '').length;
85
-
86
- return questionCount
87
- ? `${category.Title} - ${answeredQuestions} / ${questionCount}`
88
- : category.Title ;
89
- };
90
-
91
- export const CategoryResponse = React.forwardRef((props: CategoryResponse, ref) => {
92
- const { data } = props;
93
-
94
- const [currentKey, setCurrentKey] = useState(data.CategoryAnswers[0].Key);
95
- const [localData, setLocalData] = useState<any>(data);
96
- // Setting first set of questions as default open
97
- const [selectedCategory, setSelectedCategory] = useState<any>(data.CategoryAnswers[0]);
98
- const [initialValues, setInitialValues] = useState<any>(data.CategoryAnswers[0].Data);
99
- const [form] = useForm();
100
-
101
-
102
- const updateInitialValues = (data: any) => {
103
- const {
104
- Questions,
105
- OpenAnswer
106
- } = data;
107
-
108
- const initial = {
109
- Questions: Questions.map((question: any) => ({
110
- Subject: question.Subject,
111
- Description: question.Description,
112
- Answer: question.Answer || ""
113
- })),
114
- OpenAnswer: OpenAnswer
115
- };
116
-
117
- setInitialValues(initial);
118
- form.setFieldsValue(initial);
119
- };
120
-
121
- const handleLabelClick = (category: any, index: number) => {
122
- setSelectedCategory(category);
123
- updateInitialValues(category.Data);
124
- setCurrentKey(index);
125
- };
126
-
127
- const onFinish = (values: any) => {
128
- const updatedQuestions = initialValues.Questions.map((question: any, index: number) => {
129
- return {
130
- ...question,
131
- Answer: values.Questions[index].Answer
132
- };
133
- });
134
-
135
- const updatedCategory = updateCategoryAnswers(localData.CategoryAnswers, selectedCategory.Data, updatedQuestions);
136
-
137
- const updatedLocalData = { ...localData, CategoryAnswers: updatedCategory };
138
-
139
- setLocalData(updatedLocalData);
140
- };
141
-
142
- const renderCategories = (categories: any) => {
143
- return categories.map((category: any, index: number) => {
144
- const labelClasses = classNames({
145
- [styles.cursorPointer]: category.Data.Questions.length > 0
146
- }, [styles.label]);
147
-
148
- const indexCheck = category.Data.Questions.length > 0 && category.Key;
149
-
150
- return (
151
- <div
152
- className={`${styles.labelWrapper} ${category.Data.CategoryId === selectedCategory.Data.CategoryId ? styles.active : ""}`}
153
- key={index}
154
- >
155
- <div
156
- className={labelClasses}
157
- data-index={indexCheck}
158
- onClick={() => category.Data.Questions.length > 0 && handleLabelClick(category, indexCheck)}
159
- >
160
- {getTitleWithQuestionCount(category)}
161
- </div>
162
- {category.Children && (
163
- <div className={styles.subCategory}>
164
- {renderCategories(category.Children)}
165
- </div>
166
- )}
167
- </div>
168
- )
169
- });
170
- };
171
-
172
- const handleNextClick = () => {
173
- const nextCategory = findCategoryWithQuestions(currentKey, localData.CategoryAnswers, 'next');
174
- if (nextCategory) {
175
- setCurrentKey(nextCategory.Key);
176
- setSelectedCategory(nextCategory);
177
- }
178
-
179
- const nextCategoryData = getCategoryObject(currentKey, localData.CategoryAnswers, 'next');
180
- setSelectedCategory(nextCategoryData ? { ...nextCategory, data: nextCategoryData } : null);
181
- updateInitialValues(nextCategoryData);
182
- };
183
-
184
- const handlePreviousClick = () => {
185
- const prevCategory = findCategoryWithQuestions(currentKey, localData.CategoryAnswers, 'prev');
186
- if (prevCategory) {
187
- setCurrentKey(prevCategory.Key);
188
- setSelectedCategory(prevCategory);
189
- }
190
-
191
- const prevCategoryData = getCategoryObject(currentKey, localData.CategoryAnswers, 'prev');
192
- setSelectedCategory(prevCategoryData ? { ...prevCategory, data: prevCategoryData } : null);
193
- updateInitialValues(prevCategoryData);
194
- };
195
-
196
- useImperativeHandle(ref, () => ({
197
- handleNextClick,
198
- handlePreviousClick,
199
- }));
200
-
201
- useEffect(() => {
202
- props.serverReadyData(localData);
203
- }, [localData]);
204
-
205
- useEffect(() => {
206
- const hasNext = hasCategory(currentKey, localData.CategoryAnswers, 'next');
207
- props.onNextCategoryAvailabilityChange(hasNext);
208
-
209
- const hasPrevious = hasCategory(currentKey, localData.CategoryAnswers, 'prev');
210
- props.onPreviousCategoryAvailabilityChange(hasPrevious);
211
- }, [currentKey, localData.CategoryAnswers, props]);
212
-
213
- const questionWrapper = classNames({
214
- [styles.questionWrapperOpenAnswer]: selectedCategory.Data.OpenAnswer,
215
- }, [styles.questionWrapper]);
216
-
217
- // This gets the scale we use for each select from the database using a key based variable,if
218
- // any new generalEvaluationLevel is added to the backend we need to update our own without
219
- // deleting any of the previous so we dont mess up the project history.
220
- const selectedEvaluationOption = `scale_${selectedCategory?.Data?.GeneralEvaluationLevel}` as keyof typeof evaluationOptions;
221
-
222
- return (
223
- <div className={styles.categoryResponse}>
224
- <div className={styles.sidebarWrapper}>
225
- <div className={styles.title}>Categorias</div>
226
- {renderCategories(localData.CategoryAnswers)}
227
- </div>
228
- <div className={styles.contentWrapper}>
229
- <Form
230
- initialValues={initialValues}
231
- name="dynamic_form_nest_item"
232
- onFinish={onFinish}
233
- autoComplete="off"
234
- form={form}
235
- onValuesChange={(_, allValues) => onFinish(allValues)}
236
- >
237
- <div className={styles.details}>
238
- <div className={styles.categoryName}>
239
- {selectedCategory?.Data?.CategoryName}
240
- </div>
241
- <div className={styles.categoryDescription}>
242
- {selectedCategory?.Data?.Description}
243
- </div>
244
- </div>
245
- {selectedCategory?.Data?.Questions.map((question: any, index: number) => (
246
- <div className={questionWrapper} key={index}>
247
- <div className={styles.question}>
248
- <div className={styles.subject}>
249
- {question.Subject}
250
- </div>
251
- <div className={styles.description}>
252
- {question.Description}
253
- </div>
254
- </div>
255
- <div className={styles.answer}>
256
- {selectedCategory.Data.OpenAnswer
257
- ? <Form.Item
258
- name={["Questions", index, "Answer"]}
259
- >
260
- <TextArea />
261
- </Form.Item>
262
- : <Form.Item
263
- name={["Questions", index, "Answer"]}
264
- >
265
- <Select options={evaluationOptions[selectedEvaluationOption]}
266
- style={{ minWidth: '100%' }}
267
- />
268
- </Form.Item>
269
- }
270
- </div>
271
- </div>
272
- ))}
273
- </Form>
274
- </div>
275
- </div>
276
- );
277
- });
1
+ import styles from './styles.module.scss';
2
+ import { useEffect, useImperativeHandle, useState } from 'react';
3
+ import { Form } from 'antd';
4
+ import { useForm } from 'antd/es/form/Form';
5
+ import { Button } from '../Button';
6
+ import classNames from 'classnames';
7
+ import TextArea from 'antd/es/input/TextArea';
8
+ import { Select } from '../Select';
9
+ import { evaluationOptions } from './evaluationOptions';
10
+ import React from 'react';
11
+ import { t } from 'i18next';
12
+
13
+ interface CategoryResponse {
14
+ data: any;
15
+ serverReadyData: any;
16
+ onNextCategoryAvailabilityChange: (hasNext: boolean) => void;
17
+ onPreviousCategoryAvailabilityChange: (hasPrevious: boolean) => void;
18
+ };
19
+
20
+ type Category = {
21
+ Title: string;
22
+ Key: string;
23
+ Data: any;
24
+ Children?: Category[];
25
+ };
26
+
27
+ const updateCategoryAnswers = (CategoryAnswers: any[], categoryToUpdate: any, updatedQuestions: any) => {
28
+ CategoryAnswers.forEach((category: any) => {
29
+ if (category.Data.CategoryId === categoryToUpdate.CategoryId) {
30
+ category.Data.Questions = category.Data.Questions.map((question: any, index: any) => {
31
+ return {
32
+ ...question,
33
+ Answer: updatedQuestions[index].Answer
34
+ };
35
+ });
36
+ }
37
+ else if (category.Children && category.Children.length > 0) {
38
+ updateCategoryAnswers(category.Children, categoryToUpdate, updatedQuestions);
39
+ }
40
+ });
41
+ return CategoryAnswers;
42
+ };
43
+
44
+ const findCategoryWithQuestions = (currentKey: string, categories: Category[], direction: 'next' | 'prev'): Category | null => {
45
+ let foundCurrent = false;
46
+
47
+ const searchCategories = (categoryList: Category[], direction: 'next' | 'prev'): Category | null => {
48
+ const iterable = direction === 'next' ? categoryList : [...categoryList].reverse();
49
+
50
+ for (const category of iterable) {
51
+ if (foundCurrent) {
52
+ if (category.Data.Questions.length > 0) {
53
+ return category;
54
+ }
55
+ } else if (category.Key === currentKey) {
56
+ foundCurrent = true;
57
+ }
58
+
59
+ if (category.Children) {
60
+ const result = searchCategories(category.Children, direction);
61
+ if (result) {
62
+ return result;
63
+ }
64
+ }
65
+ }
66
+ return null;
67
+ };
68
+
69
+ return searchCategories(categories, direction);
70
+ };
71
+
72
+ const getCategoryObject = (currentKey: string, categories: Category[], direction: 'next' | 'prev'): any => {
73
+ const category = findCategoryWithQuestions(currentKey, categories, direction);
74
+ return category ? category.Data : null;
75
+ };
76
+
77
+ const hasCategory = (currentKey: string, categories: Category[], direction: 'next' | 'prev'): boolean => {
78
+ const category = findCategoryWithQuestions(currentKey, categories, direction);
79
+ return !!category;
80
+ };
81
+
82
+ const getTitleWithQuestionCount = (category: any): string => {
83
+ const questionCount = category?.Data?.Questions?.length;
84
+ const answeredQuestions = category?.Data?.Questions?.filter((question: any) => question.Answer !== null && question.Answer !== undefined && question.Answer !== '').length;
85
+
86
+ return questionCount
87
+ ? `${category.Title} - ${answeredQuestions} / ${questionCount}`
88
+ : category.Title ;
89
+ };
90
+
91
+ export const CategoryResponse = React.forwardRef((props: CategoryResponse, ref) => {
92
+ const { data } = props;
93
+
94
+ const [currentKey, setCurrentKey] = useState(data.CategoryAnswers[0].Key);
95
+ const [localData, setLocalData] = useState<any>(data);
96
+ // Setting first set of questions as default open
97
+ const [selectedCategory, setSelectedCategory] = useState<any>(data.CategoryAnswers[0]);
98
+ const [initialValues, setInitialValues] = useState<any>(data.CategoryAnswers[0].Data);
99
+ const [form] = useForm();
100
+
101
+
102
+ const updateInitialValues = (data: any) => {
103
+ const {
104
+ Questions,
105
+ OpenAnswer
106
+ } = data;
107
+
108
+ const initial = {
109
+ Questions: Questions.map((question: any) => ({
110
+ Subject: question.Subject,
111
+ Description: question.Description,
112
+ Answer: question.Answer || ""
113
+ })),
114
+ OpenAnswer: OpenAnswer
115
+ };
116
+
117
+ setInitialValues(initial);
118
+ form.setFieldsValue(initial);
119
+ };
120
+
121
+ const handleLabelClick = (category: any, index: number) => {
122
+ setSelectedCategory(category);
123
+ updateInitialValues(category.Data);
124
+ setCurrentKey(index);
125
+ };
126
+
127
+ const onFinish = (values: any) => {
128
+ const updatedQuestions = initialValues.Questions.map((question: any, index: number) => {
129
+ return {
130
+ ...question,
131
+ Answer: values.Questions[index].Answer
132
+ };
133
+ });
134
+
135
+ const updatedCategory = updateCategoryAnswers(localData.CategoryAnswers, selectedCategory.Data, updatedQuestions);
136
+
137
+ const updatedLocalData = { ...localData, CategoryAnswers: updatedCategory };
138
+
139
+ setLocalData(updatedLocalData);
140
+ };
141
+
142
+ const renderCategories = (categories: any) => {
143
+ return categories.map((category: any, index: number) => {
144
+ const labelClasses = classNames({
145
+ [styles.cursorPointer]: category.Data.Questions.length > 0
146
+ }, [styles.label]);
147
+
148
+ const indexCheck = category.Data.Questions.length > 0 && category.Key;
149
+
150
+ return (
151
+ <div
152
+ className={`${styles.labelWrapper} ${category.Data.CategoryId === selectedCategory.Data.CategoryId ? styles.active : ""}`}
153
+ key={index}
154
+ >
155
+ <div
156
+ className={labelClasses}
157
+ data-index={indexCheck}
158
+ onClick={() => category.Data.Questions.length > 0 && handleLabelClick(category, indexCheck)}
159
+ >
160
+ {getTitleWithQuestionCount(category)}
161
+ </div>
162
+ {category.Children && (
163
+ <div className={styles.subCategory}>
164
+ {renderCategories(category.Children)}
165
+ </div>
166
+ )}
167
+ </div>
168
+ )
169
+ });
170
+ };
171
+
172
+ const handleNextClick = () => {
173
+ const nextCategory = findCategoryWithQuestions(currentKey, localData.CategoryAnswers, 'next');
174
+ if (nextCategory) {
175
+ setCurrentKey(nextCategory.Key);
176
+ setSelectedCategory(nextCategory);
177
+ }
178
+
179
+ const nextCategoryData = getCategoryObject(currentKey, localData.CategoryAnswers, 'next');
180
+ setSelectedCategory(nextCategoryData ? { ...nextCategory, data: nextCategoryData } : null);
181
+ updateInitialValues(nextCategoryData);
182
+ };
183
+
184
+ const handlePreviousClick = () => {
185
+ const prevCategory = findCategoryWithQuestions(currentKey, localData.CategoryAnswers, 'prev');
186
+ if (prevCategory) {
187
+ setCurrentKey(prevCategory.Key);
188
+ setSelectedCategory(prevCategory);
189
+ }
190
+
191
+ const prevCategoryData = getCategoryObject(currentKey, localData.CategoryAnswers, 'prev');
192
+ setSelectedCategory(prevCategoryData ? { ...prevCategory, data: prevCategoryData } : null);
193
+ updateInitialValues(prevCategoryData);
194
+ };
195
+
196
+ useImperativeHandle(ref, () => ({
197
+ handleNextClick,
198
+ handlePreviousClick,
199
+ }));
200
+
201
+ useEffect(() => {
202
+ props.serverReadyData(localData);
203
+ }, [localData]);
204
+
205
+ useEffect(() => {
206
+ const hasNext = hasCategory(currentKey, localData.CategoryAnswers, 'next');
207
+ props.onNextCategoryAvailabilityChange(hasNext);
208
+
209
+ const hasPrevious = hasCategory(currentKey, localData.CategoryAnswers, 'prev');
210
+ props.onPreviousCategoryAvailabilityChange(hasPrevious);
211
+ }, [currentKey, localData.CategoryAnswers, props]);
212
+
213
+ const questionWrapper = classNames({
214
+ [styles.questionWrapperOpenAnswer]: selectedCategory.Data.OpenAnswer,
215
+ }, [styles.questionWrapper]);
216
+
217
+ // This gets the scale we use for each select from the database using a key based variable,if
218
+ // any new generalEvaluationLevel is added to the backend we need to update our own without
219
+ // deleting any of the previous so we dont mess up the project history.
220
+ const selectedEvaluationOption = `scale_${selectedCategory?.Data?.GeneralEvaluationLevel}` as keyof typeof evaluationOptions;
221
+
222
+ return (
223
+ <div className={styles.categoryResponse}>
224
+ <div className={styles.sidebarWrapper}>
225
+ <div className={styles.title}>Categorias</div>
226
+ {renderCategories(localData.CategoryAnswers)}
227
+ </div>
228
+ <div className={styles.contentWrapper}>
229
+ <Form
230
+ initialValues={initialValues}
231
+ name="dynamic_form_nest_item"
232
+ onFinish={onFinish}
233
+ autoComplete="off"
234
+ form={form}
235
+ onValuesChange={(_, allValues) => onFinish(allValues)}
236
+ >
237
+ <div className={styles.details}>
238
+ <div className={styles.categoryName}>
239
+ {selectedCategory?.Data?.CategoryName}
240
+ </div>
241
+ <div className={styles.categoryDescription}>
242
+ {selectedCategory?.Data?.Description}
243
+ </div>
244
+ </div>
245
+ {selectedCategory?.Data?.Questions.map((question: any, index: number) => (
246
+ <div className={questionWrapper} key={index}>
247
+ <div className={styles.question}>
248
+ <div className={styles.subject}>
249
+ {question.Subject}
250
+ </div>
251
+ <div className={styles.description}>
252
+ {question.Description}
253
+ </div>
254
+ </div>
255
+ <div className={styles.answer}>
256
+ {selectedCategory.Data.OpenAnswer
257
+ ? <Form.Item
258
+ name={["Questions", index, "Answer"]}
259
+ >
260
+ <TextArea />
261
+ </Form.Item>
262
+ : <Form.Item
263
+ name={["Questions", index, "Answer"]}
264
+ >
265
+ <Select options={evaluationOptions[selectedEvaluationOption]}
266
+ style={{ minWidth: '100%' }}
267
+ />
268
+ </Form.Item>
269
+ }
270
+ </div>
271
+ </div>
272
+ ))}
273
+ </Form>
274
+ </div>
275
+ </div>
276
+ );
277
+ });