@omniumretail/component-library 1.0.20 → 1.0.22
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/dist/bundle.js +660 -2
- package/dist/main.css +160 -0
- package/dist/types/components/Category/Category.stories.d.ts +4 -0
- package/dist/types/components/Category/CategoryContent/index.d.ts +7 -0
- package/dist/types/components/Category/CategorySidebar/index.d.ts +25 -0
- package/dist/types/components/Category/index.d.ts +6 -0
- package/dist/types/components/Questions/SingleQuestion/index.d.ts +0 -1
- package/dist/types/components/Questions/index.d.ts +0 -1
- package/dist/types/components/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/Category/Category.stories.tsx +14 -0
- package/src/components/Category/CategoryContent/index.tsx +159 -0
- package/src/components/Category/CategoryContent/styles.module.scss +51 -0
- package/src/components/Category/CategorySidebar/index.tsx +246 -0
- package/src/components/Category/CategorySidebar/styles.module.scss +24 -0
- package/src/components/Category/index.tsx +58 -0
- package/src/components/Category/styles.module.scss +12 -0
- package/src/components/Questions/index.tsx +1 -1
- package/src/components/Radio/index.tsx +0 -1
- package/src/components/index.tsx +1 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Tree } from 'antd';
|
|
3
|
+
import type { TreeProps } from 'antd/es/tree';
|
|
4
|
+
import styles from './styles.module.scss';
|
|
5
|
+
import { PlusOutlined } from '@ant-design/icons';
|
|
6
|
+
import { Button } from '../../Button';
|
|
7
|
+
|
|
8
|
+
export interface Questions {
|
|
9
|
+
grade: string;
|
|
10
|
+
questions: string;
|
|
11
|
+
info: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Data {
|
|
14
|
+
categoryName: string;
|
|
15
|
+
generalEvaluationLevel: string;
|
|
16
|
+
grade: string;
|
|
17
|
+
openAnswer: boolean;
|
|
18
|
+
questions: Questions[];
|
|
19
|
+
}
|
|
20
|
+
export interface DataNode {
|
|
21
|
+
title: string;
|
|
22
|
+
key: string;
|
|
23
|
+
data?: Data;
|
|
24
|
+
children?: DataNode[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface SidebarProps {
|
|
28
|
+
categoryContentData: any;
|
|
29
|
+
categorySidebarInfo: any;
|
|
30
|
+
data: DataNode[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function get_element_by_index(data: DataNode[], index: string | number): DataNode | null {
|
|
34
|
+
for (const item of data) {
|
|
35
|
+
if (item.key === index) {
|
|
36
|
+
return item;
|
|
37
|
+
} else if (item.children) {
|
|
38
|
+
const result = get_element_by_index(item.children, index);
|
|
39
|
+
if (result !== null) {
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function addPropertyByIndex(data: DataNode[], index: string | number, property: string, value: any): DataNode[] {
|
|
48
|
+
return data.map((item: DataNode) => {
|
|
49
|
+
if (item.key === index) {
|
|
50
|
+
return { ...item, [property]: value };
|
|
51
|
+
}
|
|
52
|
+
else if (item.children) {
|
|
53
|
+
return { ...item, children: addPropertyByIndex(item.children, index, property, value) };
|
|
54
|
+
}
|
|
55
|
+
return item;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const CategorySidebar = (props: SidebarProps) => {
|
|
60
|
+
const {
|
|
61
|
+
categoryContentData,
|
|
62
|
+
data
|
|
63
|
+
} = props;
|
|
64
|
+
|
|
65
|
+
const [gData, setGData] = useState(data);
|
|
66
|
+
const [expandedKeys] = useState([]);
|
|
67
|
+
const [sidebarInfo, setSidebarInfo] = useState<any>();
|
|
68
|
+
|
|
69
|
+
const onDragEnter: TreeProps['onDragEnter'] = (info) => {
|
|
70
|
+
// expandedKeys
|
|
71
|
+
// setExpandedKeys(info.expandedKeys)
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const onDrop: TreeProps['onDrop'] = (info) => {
|
|
75
|
+
const dropKey = info.node.key;
|
|
76
|
+
const dragKey = info.dragNode.key;
|
|
77
|
+
const dropPos = info.node.pos.split('-');
|
|
78
|
+
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
|
|
79
|
+
const { data: nodeData } = info.node as DataNode;
|
|
80
|
+
const questions: Questions[] | undefined = nodeData?.questions;
|
|
81
|
+
|
|
82
|
+
if(questions && questions.length > 0) {
|
|
83
|
+
console.log('you cant add a subcategory to a category with questions');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (dropPos.length >= 4) {
|
|
88
|
+
console.log('cant have more than 3 levels');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const loop = (
|
|
93
|
+
data: DataNode[],
|
|
94
|
+
key: React.Key,
|
|
95
|
+
callback: (node: DataNode, i: number, data: DataNode[]) => void,
|
|
96
|
+
) => {
|
|
97
|
+
for (let i = 0; i < data.length; i++) {
|
|
98
|
+
if (data[i].key === key) {
|
|
99
|
+
return callback(data[i], i, data);
|
|
100
|
+
}
|
|
101
|
+
if (data[i].children) {
|
|
102
|
+
loop(data[i].children!, key, callback);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const data = [...gData];
|
|
107
|
+
|
|
108
|
+
// Find dragObject
|
|
109
|
+
let dragObj: DataNode;
|
|
110
|
+
loop(data, dragKey, (item, index, arr) => {
|
|
111
|
+
arr.splice(index, 1);
|
|
112
|
+
dragObj = item;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (!info.dropToGap) {
|
|
116
|
+
// Drop on the content
|
|
117
|
+
loop(data, dropKey, (item) => {
|
|
118
|
+
item.children = item.children || [];
|
|
119
|
+
// where to insert
|
|
120
|
+
item.children.unshift(dragObj);
|
|
121
|
+
// {...dragObj, key: `${item.key}-${item.children.length}`}
|
|
122
|
+
});
|
|
123
|
+
} else if (
|
|
124
|
+
((info.node as any).props.children || []).length > 0 && // Has children
|
|
125
|
+
(info.node as any).props.expanded && // Is expanded
|
|
126
|
+
dropPosition === 1 // On the bottom gap
|
|
127
|
+
) {
|
|
128
|
+
loop(data, dropKey, (item) => {
|
|
129
|
+
item.children = item.children || [];
|
|
130
|
+
// where to insert
|
|
131
|
+
item.children.unshift(dragObj);
|
|
132
|
+
// in previous version, we use item.children.push(dragObj) to insert the
|
|
133
|
+
// item to the tail of the children
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
let ar: DataNode[] = [];
|
|
137
|
+
let i: number;
|
|
138
|
+
loop(data, dropKey, (_item, index, arr) => {
|
|
139
|
+
ar = arr;
|
|
140
|
+
i = index;
|
|
141
|
+
});
|
|
142
|
+
if (dropPosition === -1) {
|
|
143
|
+
ar.splice(i!, 0, dragObj!);
|
|
144
|
+
} else {
|
|
145
|
+
ar.splice(i! + 1, 0, dragObj!);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let newData: any = {};
|
|
150
|
+
|
|
151
|
+
// TODO: create a recursive function that does the same
|
|
152
|
+
// This code changes the indexes on the fly while dragging and dropping
|
|
153
|
+
|
|
154
|
+
let keyCounter = 0;
|
|
155
|
+
data.forEach((category: any) => {
|
|
156
|
+
const categoryKey = `${keyCounter++}`;
|
|
157
|
+
let children: any = [];
|
|
158
|
+
if (category.children) {
|
|
159
|
+
category.children.forEach((subcategory: any, subcategoryindex: number) => {
|
|
160
|
+
const subcategoryKey = `${categoryKey}.${subcategoryindex}`;
|
|
161
|
+
let subChildren: any = [];
|
|
162
|
+
if (subcategory.children) {
|
|
163
|
+
subcategory.children.forEach((lastSubcategory: any, lastSubCategoryIndex: number) => {
|
|
164
|
+
const lastSubcategoryKey = `${subcategoryKey}.${lastSubCategoryIndex}`;
|
|
165
|
+
subChildren.push({ ...lastSubcategory, key: lastSubcategoryKey });
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
children.push({ ...subcategory, children: subChildren, key: subcategoryKey });
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
newData[categoryKey] = { ...category, children };
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// TODO: update this code if possible once the TODO before is done
|
|
175
|
+
/*
|
|
176
|
+
This code removes the property that was assigned to the object ex: 0: {}, 1: {} changes to {}, {}
|
|
177
|
+
*/
|
|
178
|
+
const checkedData = Object.values(newData).map((category: any, index: number) => {
|
|
179
|
+
return { ...category, key: index };
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
setGData(checkedData);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
|
|
186
|
+
setSidebarInfo(selectedKeys);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const addCategory = () => {
|
|
190
|
+
setGData((prevCategories: DataNode[]) => [
|
|
191
|
+
...prevCategories,
|
|
192
|
+
{ title: `New category`, key: `${gData.length}` },
|
|
193
|
+
])
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
props.categorySidebarInfo({
|
|
198
|
+
selectKey: sidebarInfo,
|
|
199
|
+
data: get_element_by_index(gData, sidebarInfo && sidebarInfo[0]),
|
|
200
|
+
});
|
|
201
|
+
}, [sidebarInfo]);
|
|
202
|
+
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
const newGData = addPropertyByIndex(gData, sidebarInfo && sidebarInfo[0], "data", categoryContentData);
|
|
205
|
+
|
|
206
|
+
const updatedGData = newGData.map((category: any, index) => {
|
|
207
|
+
if(category?.data) {
|
|
208
|
+
return {...category, title: `${category.data.categoryName} ${category.data.questions ? '(Q: ' + category.data.questions.length + ')' : ''} ${category.data.grade ? '(G: ' +category.data.grade + ')' : ''}`}
|
|
209
|
+
}
|
|
210
|
+
return category;
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
setGData(updatedGData);
|
|
214
|
+
}, [categoryContentData]);
|
|
215
|
+
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
props.categorySidebarInfo({
|
|
218
|
+
selectKey: sidebarInfo,
|
|
219
|
+
data: get_element_by_index(gData, sidebarInfo && sidebarInfo[0])
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
console.log(gData);
|
|
223
|
+
}, [gData]);
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<div className={styles.categorySidebar}>
|
|
227
|
+
<div className={styles.title}>Categorias</div>
|
|
228
|
+
<Button icon={<PlusOutlined />} onClick={addCategory}>
|
|
229
|
+
Adicionar Categoria
|
|
230
|
+
</Button>
|
|
231
|
+
|
|
232
|
+
<div className={styles.categoryViewer}>
|
|
233
|
+
<Tree
|
|
234
|
+
className="draggable-tree"
|
|
235
|
+
defaultExpandedKeys={expandedKeys}
|
|
236
|
+
draggable
|
|
237
|
+
blockNode
|
|
238
|
+
onDragEnter={onDragEnter}
|
|
239
|
+
onDrop={onDrop}
|
|
240
|
+
treeData={gData}
|
|
241
|
+
onSelect={onSelect}
|
|
242
|
+
/>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.categorySidebar {
|
|
2
|
+
:global {
|
|
3
|
+
.ant-tree-title {
|
|
4
|
+
font-weight: var(--font-weight-semibold);
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.title {
|
|
10
|
+
font-size: var(--font-size-body-4);
|
|
11
|
+
font-weight: 600;
|
|
12
|
+
line-height: 100%;
|
|
13
|
+
color: var(--color-blue);
|
|
14
|
+
text-transform: uppercase;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
button {
|
|
18
|
+
margin-top: 32px;
|
|
19
|
+
width: 100%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.categoryViewer {
|
|
23
|
+
margin-top: 20px;
|
|
24
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import styles from './styles.module.scss';
|
|
2
|
+
import { CategorySidebar, DataNode } from './CategorySidebar';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { CategoryContent } from './CategoryContent';
|
|
5
|
+
|
|
6
|
+
interface Category {
|
|
7
|
+
data: DataNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const fakeData: any = {
|
|
11
|
+
data: [
|
|
12
|
+
{
|
|
13
|
+
"title": "21 (G: 2)",
|
|
14
|
+
"key": "0",
|
|
15
|
+
"data": {
|
|
16
|
+
"categoryName": "21",
|
|
17
|
+
"grade": "2"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"title": "asda (G: 5)",
|
|
22
|
+
"key": "1",
|
|
23
|
+
"data": {
|
|
24
|
+
"categoryName": "asda",
|
|
25
|
+
"grade": "5"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
noData: []
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const Category = (props: Category) => {
|
|
33
|
+
const {
|
|
34
|
+
data = fakeData.noData
|
|
35
|
+
} = props;
|
|
36
|
+
|
|
37
|
+
const [categoryContentInfo, setCategoryContentInfo] = useState<any>();
|
|
38
|
+
const [categorySidebarInfo, setCategorySidebarInfo] = useState<any>();
|
|
39
|
+
const [showContent, setShowContent] = useState<boolean>(false);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
}, [categoryContentInfo]);
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
setShowContent(categorySidebarInfo?.selectKey?.length > 0);
|
|
46
|
+
}, [categorySidebarInfo]);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className={styles.category}>
|
|
50
|
+
<div className={styles.sidebarWrapper}>
|
|
51
|
+
<CategorySidebar categorySidebarInfo={setCategorySidebarInfo} categoryContentData={categoryContentInfo} data={data} />
|
|
52
|
+
</div>
|
|
53
|
+
<div className={styles.contentWrapper}>
|
|
54
|
+
<CategoryContent categoryContentInfo={setCategoryContentInfo} categoryContentShow={showContent} categorySidebarData={categorySidebarInfo} />
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
)
|
|
58
|
+
};
|
|
@@ -3,7 +3,7 @@ import { PlusOutlined } from '@ant-design/icons';
|
|
|
3
3
|
import { Form } from 'antd';
|
|
4
4
|
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
|
|
5
5
|
import { SingleQuestion } from "./SingleQuestion";
|
|
6
|
-
import { Link } from '
|
|
6
|
+
import { Link } from '../Link';
|
|
7
7
|
import { FieldContext } from 'rc-field-form';
|
|
8
8
|
import { t } from 'i18next';
|
|
9
9
|
|
package/src/components/index.tsx
CHANGED