drf-react-by-schema 0.0.2 → 0.1.0
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/.eslintrc.js +11 -0
- package/dist/index.js +8 -0
- package/package.json +33 -5
- package/src/api.ts +526 -0
- package/src/components/DataGridBySchemaEditable.tsx +1401 -0
- package/src/index.ts +3 -0
- package/src/styles/index.ts +3 -0
- package/src/styles/layout.ts +104 -0
- package/src/styles/theme.ts +190 -0
- package/src/utils.ts +321 -0
- package/tsconfig.json +104 -0
- package/src/index.js +0 -5
package/src/index.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import theme from './theme';
|
|
2
|
+
|
|
3
|
+
export const content = {
|
|
4
|
+
flexGrow: 1,
|
|
5
|
+
pr: 3,
|
|
6
|
+
pl: 3,
|
|
7
|
+
pt: 2,
|
|
8
|
+
pb: 0
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const main = {
|
|
12
|
+
...content,
|
|
13
|
+
ml: 4
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const flexRow = {
|
|
17
|
+
display: 'flex',
|
|
18
|
+
flexDirection: 'row',
|
|
19
|
+
justifyContent: 'space-between',
|
|
20
|
+
alignItems: 'center'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const topBar = {
|
|
24
|
+
...flexRow,
|
|
25
|
+
width: '100%',
|
|
26
|
+
pl: 3,
|
|
27
|
+
pr: 6
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const loadingBox = {
|
|
31
|
+
...flexRow,
|
|
32
|
+
height: '100%',
|
|
33
|
+
backgroundColor: '#ccc',
|
|
34
|
+
justifyContent: 'center'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const actionButtons = {
|
|
38
|
+
...flexRow,
|
|
39
|
+
width: '100%',
|
|
40
|
+
alignItems: 'flex-start'
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const inLineForm = {
|
|
44
|
+
...flexRow,
|
|
45
|
+
width: '100%',
|
|
46
|
+
justifyContent: 'flex-start'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const flexColumn = {
|
|
50
|
+
...flexRow,
|
|
51
|
+
flexDirection: 'column'
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const flexRowGrow = {
|
|
55
|
+
...flexRow,
|
|
56
|
+
flexGrow: 1
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const topBarOverList = {
|
|
60
|
+
...flexRowGrow,
|
|
61
|
+
mb: 2
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const dataGrid = {
|
|
65
|
+
height: 'calc(100vh - 180px)',
|
|
66
|
+
mt: 2
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const dataGridWithTabs = {
|
|
70
|
+
...dataGrid,
|
|
71
|
+
mt: 0
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const dataGridFixedHeight = {
|
|
75
|
+
...dataGrid,
|
|
76
|
+
height: 400
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const fullWidthButton = {
|
|
80
|
+
mt: 3,
|
|
81
|
+
width: '100%'
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const formCard = {
|
|
85
|
+
width: '100%',
|
|
86
|
+
backgroundColor: theme.palette.formCard.main,
|
|
87
|
+
mt: 2,
|
|
88
|
+
mb: 2
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const formCardContent = {
|
|
92
|
+
maxHeight: 350,
|
|
93
|
+
overflow: 'scroll'
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const metabaseAppEmbed = {
|
|
97
|
+
height: 1700
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const geoPicker = {
|
|
101
|
+
height: 350,
|
|
102
|
+
width: '100%',
|
|
103
|
+
mt: 0
|
|
104
|
+
};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type {} from '@mui/x-data-grid/themeAugmentation';
|
|
2
|
+
import { createTheme } from '@mui/material/styles';
|
|
3
|
+
import { ptBR as corePtBR } from '@mui/material/locale';
|
|
4
|
+
import { ptBR } from '@mui/x-data-grid';
|
|
5
|
+
import { ptBR as pickersPtBR } from '@mui/x-date-pickers';
|
|
6
|
+
|
|
7
|
+
declare module '@mui/material/styles' {
|
|
8
|
+
// interface Theme {
|
|
9
|
+
// status: {
|
|
10
|
+
// danger: React.CSSProperties['color'];
|
|
11
|
+
// };
|
|
12
|
+
// }
|
|
13
|
+
interface Palette {
|
|
14
|
+
avatars: string[];
|
|
15
|
+
avatarsMore: string[];
|
|
16
|
+
topBarButton: Palette['primary'];
|
|
17
|
+
producao: Palette['primary'];
|
|
18
|
+
empreendimento: Palette['primary'];
|
|
19
|
+
comercializacao: Palette['primary'];
|
|
20
|
+
credito: Palette['primary'];
|
|
21
|
+
certificacao: Palette['primary'];
|
|
22
|
+
successButton: Palette['primary'];
|
|
23
|
+
selectedItem: Palette['primary'];
|
|
24
|
+
tableColumnHeader: Palette['primary'];
|
|
25
|
+
formCard: Palette['primary'];
|
|
26
|
+
}
|
|
27
|
+
// interface PaletteOptions {
|
|
28
|
+
// neutral: PaletteOptions['primary'];
|
|
29
|
+
// }
|
|
30
|
+
//
|
|
31
|
+
interface PaletteColor {
|
|
32
|
+
semaphoric?: string;
|
|
33
|
+
}
|
|
34
|
+
// interface SimplePaletteColorOptions {
|
|
35
|
+
// darker?: string;
|
|
36
|
+
// }
|
|
37
|
+
// interface ThemeOptions {
|
|
38
|
+
// status: {
|
|
39
|
+
// danger: React.CSSProperties['color'];
|
|
40
|
+
// };
|
|
41
|
+
// }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
ptBR.components.MuiDataGrid.defaultProps.localeText = {
|
|
46
|
+
...ptBR.components.MuiDataGrid.defaultProps.localeText,
|
|
47
|
+
toolbarQuickFilterPlaceholder: 'Buscar...',
|
|
48
|
+
toolbarQuickFilterLabel: 'Buscar',
|
|
49
|
+
toolbarQuickFilterDeleteIconLabel: 'Limpar busca'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const palette = {
|
|
53
|
+
avatars: ['#e60049', '#0bb4ff', '#50e991', '#e6d800', '#9b19f5', '#ffa300', '#dc0ab4', '#b3d4ff', '#00bfa0'],
|
|
54
|
+
avatarsMore: ['#023fa5', '#8e063b', '#d33f6a', '#11c638', '#ef9708', '#0fcfc0', '#f79cd4', '#7d87b9', '#bb7784', '#4a6fe3', '#8595e1', '#b5bbe3', '#e6afb9', '#e07b91', '#8dd593', '#c6dec7', '#ead3c6', '#f0b98d', '#9cded6', '#d5eae7', '#f3e1eb', '#f6c4e1', '#bec1d4', '#d6bcc0'],
|
|
55
|
+
topBarButton: {
|
|
56
|
+
main: '#ffffff'
|
|
57
|
+
},
|
|
58
|
+
producao: {
|
|
59
|
+
main: '#e60049',
|
|
60
|
+
contrastText: '#fff'
|
|
61
|
+
},
|
|
62
|
+
empreendimento: {
|
|
63
|
+
main: '#0bb4ff',
|
|
64
|
+
contrastText: '#fff'
|
|
65
|
+
},
|
|
66
|
+
comercializacao: {
|
|
67
|
+
main: '#ffa300',
|
|
68
|
+
contrastText: '#fff'
|
|
69
|
+
},
|
|
70
|
+
credito: {
|
|
71
|
+
main: '#dc0ab4',
|
|
72
|
+
contrastText: '#fff'
|
|
73
|
+
},
|
|
74
|
+
certificacao: {
|
|
75
|
+
main: '#9b19f5',
|
|
76
|
+
contrastText: '#fff'
|
|
77
|
+
},
|
|
78
|
+
background: {
|
|
79
|
+
default: '#D9D9D9'
|
|
80
|
+
},
|
|
81
|
+
primary: {
|
|
82
|
+
main: '#3949AB'
|
|
83
|
+
},
|
|
84
|
+
secondary: {
|
|
85
|
+
main: '#9ca4d5',
|
|
86
|
+
contrastText: '#fff'
|
|
87
|
+
},
|
|
88
|
+
successButton: {
|
|
89
|
+
main: '#CDDC39',
|
|
90
|
+
contrastText: '#fff'
|
|
91
|
+
},
|
|
92
|
+
success: {
|
|
93
|
+
main: '#0e0',
|
|
94
|
+
contrastText: '#fff',
|
|
95
|
+
semaphoric: '#0e0'
|
|
96
|
+
},
|
|
97
|
+
error: {
|
|
98
|
+
main: '#d32f2f',
|
|
99
|
+
semaphoric: '#f66'
|
|
100
|
+
},
|
|
101
|
+
warning: {
|
|
102
|
+
main: '#ee0',
|
|
103
|
+
semaphoric: '#ee0'
|
|
104
|
+
},
|
|
105
|
+
selectedItem: {
|
|
106
|
+
main: '#2962FF'
|
|
107
|
+
},
|
|
108
|
+
tableColumnHeader: {
|
|
109
|
+
main: '#ECEFF1'
|
|
110
|
+
},
|
|
111
|
+
formCard: {
|
|
112
|
+
main: '#FFF'
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const theme = createTheme(
|
|
117
|
+
{
|
|
118
|
+
palette,
|
|
119
|
+
components: {
|
|
120
|
+
MuiButton: {
|
|
121
|
+
styleOverrides: {
|
|
122
|
+
contained: {
|
|
123
|
+
// borderRadius: 50
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
MuiTextField: {
|
|
128
|
+
styleOverrides: {
|
|
129
|
+
root: {
|
|
130
|
+
'&.Mui-required .MuiFormLabel-asterisk': {
|
|
131
|
+
// color: '#F00'
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
MuiListItemButton: {
|
|
137
|
+
styleOverrides: {
|
|
138
|
+
root: {
|
|
139
|
+
'&.Mui-selected, :hover': {
|
|
140
|
+
color: palette.selectedItem.main,
|
|
141
|
+
'& .MuiListItemIcon-root': {
|
|
142
|
+
color: palette.selectedItem.main
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
'&.Mui-selected:hover': {
|
|
146
|
+
color: palette.selectedItem.main,
|
|
147
|
+
'& .MuiListItemIcon-root': {
|
|
148
|
+
color: palette.selectedItem.main
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
'&.disabled': {
|
|
152
|
+
opacity: 0.5
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
MuiDataGrid: {
|
|
158
|
+
styleOverrides: {
|
|
159
|
+
root: {
|
|
160
|
+
backgroundColor: palette.formCard.main,
|
|
161
|
+
'& .MuiDataGrid-columnHeaderTitle': {
|
|
162
|
+
overflow: 'visible',
|
|
163
|
+
lineHeight: '1.43rem',
|
|
164
|
+
whiteSpace: 'normal'
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
cell: {
|
|
168
|
+
// backgroundColor: 'yellow'
|
|
169
|
+
},
|
|
170
|
+
columnHeader: {
|
|
171
|
+
backgroundColor: palette.tableColumnHeader.main
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
MuiTabs: {
|
|
176
|
+
styleOverrides: {
|
|
177
|
+
root: {
|
|
178
|
+
backgroundColor: palette.formCard.main,
|
|
179
|
+
marginTop: 20
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
corePtBR,
|
|
186
|
+
ptBR,
|
|
187
|
+
pickersPtBR
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
export default theme;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import * as Yup from 'yup';
|
|
2
|
+
import { GridActionsColDef, GridColDef } from '@mui/x-data-grid';
|
|
3
|
+
|
|
4
|
+
export type Id = string | number;
|
|
5
|
+
export type Item = Record<string, any>;
|
|
6
|
+
export type Schema = Record<string, Field>;
|
|
7
|
+
export interface Choice {
|
|
8
|
+
value: string | number,
|
|
9
|
+
display_name: string
|
|
10
|
+
};
|
|
11
|
+
type FieldChild = Record<string, Schema>;
|
|
12
|
+
export interface Field {
|
|
13
|
+
type: string,
|
|
14
|
+
child?: FieldChild,
|
|
15
|
+
children?: Schema,
|
|
16
|
+
model_default?: any,
|
|
17
|
+
model_required?: boolean
|
|
18
|
+
choices?: Choice[],
|
|
19
|
+
max_length?: number | string,
|
|
20
|
+
label: string,
|
|
21
|
+
read_only?: boolean
|
|
22
|
+
};
|
|
23
|
+
interface GridBySchemaColDef extends GridColDef {
|
|
24
|
+
isIndexField?: boolean,
|
|
25
|
+
creatable?: boolean,
|
|
26
|
+
orderable?: boolean,
|
|
27
|
+
patternFormat?: string
|
|
28
|
+
};
|
|
29
|
+
interface GridActionsBySchemaColDef extends GridActionsColDef {
|
|
30
|
+
isIndexField?: boolean,
|
|
31
|
+
creatable?: boolean,
|
|
32
|
+
orderable?: boolean,
|
|
33
|
+
patternFormat?: string
|
|
34
|
+
};
|
|
35
|
+
export type GridEnrichedBySchemaColDef = GridBySchemaColDef | GridActionsBySchemaColDef;
|
|
36
|
+
|
|
37
|
+
export const emptyByType: any = (field:Field, forDatabase:boolean = false) => {
|
|
38
|
+
if (field.model_default) {
|
|
39
|
+
return field.model_default;
|
|
40
|
+
}
|
|
41
|
+
switch (field.type) {
|
|
42
|
+
case 'nested object':
|
|
43
|
+
// emptyByType must be an empty object for the database, but must be null for the mui-autocomplete component. So I had to make this ugly hack here, when we're preparing to sendo to the database:
|
|
44
|
+
return forDatabase ? {} : null;
|
|
45
|
+
case 'field':
|
|
46
|
+
if (field.child) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
return (forDatabase)
|
|
50
|
+
? undefined
|
|
51
|
+
: null;
|
|
52
|
+
case 'string':
|
|
53
|
+
case 'email':
|
|
54
|
+
return '';
|
|
55
|
+
case 'integer':
|
|
56
|
+
return 0;
|
|
57
|
+
case 'array':
|
|
58
|
+
return [];
|
|
59
|
+
default:
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const getChoiceByValue = (
|
|
65
|
+
value:number | string,
|
|
66
|
+
choices:Choice[] | undefined
|
|
67
|
+
) => {
|
|
68
|
+
if (!choices) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
for (const choice of choices) {
|
|
72
|
+
if (choice.value === value) {
|
|
73
|
+
return choice.display_name;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const populateValues = ({
|
|
79
|
+
model,
|
|
80
|
+
data,
|
|
81
|
+
schema
|
|
82
|
+
}: {
|
|
83
|
+
model:string,
|
|
84
|
+
data:Item,
|
|
85
|
+
schema:Schema
|
|
86
|
+
}) => {
|
|
87
|
+
const values:Record<string, any> = {};
|
|
88
|
+
for (const entry of Object.entries(schema)) {
|
|
89
|
+
const [key, field] = entry;
|
|
90
|
+
if (key === 'id' && isTmpId(data[key])) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!data[key]) {
|
|
95
|
+
values[key] = emptyByType(field);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (field.type === 'field' && field.child) {
|
|
100
|
+
if (Array.isArray(data[key])) {
|
|
101
|
+
const arValues = [];
|
|
102
|
+
for (const row of data[key]) {
|
|
103
|
+
const value = populateValues({
|
|
104
|
+
model,
|
|
105
|
+
data: row,
|
|
106
|
+
schema: field.child.children
|
|
107
|
+
});
|
|
108
|
+
arValues.push(value);
|
|
109
|
+
}
|
|
110
|
+
values[key] = arValues;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
values[key] = populateValues({
|
|
115
|
+
model,
|
|
116
|
+
data: data[key],
|
|
117
|
+
schema: field.child.children
|
|
118
|
+
});
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (field.type === 'choice') {
|
|
123
|
+
values[key] = data[key]
|
|
124
|
+
? {
|
|
125
|
+
value: data[key],
|
|
126
|
+
display_name: getChoiceByValue(data[key], field.choices)
|
|
127
|
+
}
|
|
128
|
+
: emptyByType(field);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
values[key] = data[key];
|
|
133
|
+
}
|
|
134
|
+
// console.log(values);
|
|
135
|
+
return values;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const getYupValidator = (type:string) => {
|
|
139
|
+
let yupFunc;
|
|
140
|
+
try {
|
|
141
|
+
switch (type) {
|
|
142
|
+
case 'slug':
|
|
143
|
+
yupFunc = Yup.string();
|
|
144
|
+
break;
|
|
145
|
+
case 'email':
|
|
146
|
+
yupFunc = Yup.string().email('Este campo deve ser um e-mail válido.');
|
|
147
|
+
break;
|
|
148
|
+
case 'integer':
|
|
149
|
+
yupFunc = Yup.number().integer('Este campo deve ser um número inteiro');
|
|
150
|
+
break;
|
|
151
|
+
case 'choice':
|
|
152
|
+
yupFunc = Yup.object();
|
|
153
|
+
break;
|
|
154
|
+
case 'field':
|
|
155
|
+
yupFunc = Yup.mixed();
|
|
156
|
+
break;
|
|
157
|
+
case 'nested object':
|
|
158
|
+
yupFunc = Yup.object();
|
|
159
|
+
break;
|
|
160
|
+
case 'date':
|
|
161
|
+
yupFunc = Yup.date();
|
|
162
|
+
break;
|
|
163
|
+
case 'string':
|
|
164
|
+
yupFunc = Yup.string();
|
|
165
|
+
break;
|
|
166
|
+
case 'number':
|
|
167
|
+
yupFunc = Yup.number();
|
|
168
|
+
break;
|
|
169
|
+
case 'boolean':
|
|
170
|
+
yupFunc = Yup.boolean();
|
|
171
|
+
break;
|
|
172
|
+
case 'array':
|
|
173
|
+
yupFunc = Yup.array();
|
|
174
|
+
break;
|
|
175
|
+
case 'object':
|
|
176
|
+
yupFunc = Yup.object();
|
|
177
|
+
break;
|
|
178
|
+
default:
|
|
179
|
+
yupFunc = Yup.string();
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
} catch (e) {
|
|
183
|
+
yupFunc = Yup.string();
|
|
184
|
+
}
|
|
185
|
+
return yupFunc.nullable();
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const buildGenericYupValidationSchema = ({
|
|
189
|
+
data,
|
|
190
|
+
schema,
|
|
191
|
+
many = false,
|
|
192
|
+
skipFields = [],
|
|
193
|
+
extraValidators = {}
|
|
194
|
+
}:{
|
|
195
|
+
data:Item,
|
|
196
|
+
schema:Schema,
|
|
197
|
+
many?:boolean,
|
|
198
|
+
skipFields?: string[],
|
|
199
|
+
extraValidators?:Item
|
|
200
|
+
}) => {
|
|
201
|
+
const yupValidator:Record<string, any> = {};
|
|
202
|
+
for (const entry of Object.entries(schema)) {
|
|
203
|
+
const [key, field] = entry;
|
|
204
|
+
|
|
205
|
+
if (!data || !(key in data) || key === 'id' || skipFields.includes(key)) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// console.log({ key, field, data: data[key] });
|
|
210
|
+
|
|
211
|
+
// OneToMany or ManyToMany:
|
|
212
|
+
if (field.type === 'field' && field.child) {
|
|
213
|
+
yupValidator[key] = buildGenericYupValidationSchema({
|
|
214
|
+
schema: field.child.children,
|
|
215
|
+
many: true,
|
|
216
|
+
data: data[key],
|
|
217
|
+
extraValidators: Object.prototype.hasOwnProperty.call(extraValidators, key)
|
|
218
|
+
? extraValidators[key]
|
|
219
|
+
: {}
|
|
220
|
+
});
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Nested Object:
|
|
225
|
+
if (field.type === 'nested object' && field.children) {
|
|
226
|
+
// yupValidator[key] = buildGenericYupValidationSchema({
|
|
227
|
+
// schema: field.children,
|
|
228
|
+
// many: false,
|
|
229
|
+
// data: data[key],
|
|
230
|
+
// extraValidators: Object.prototype.hasOwnProperty.call(extraValidators, key)
|
|
231
|
+
// ? extraValidators[key]
|
|
232
|
+
// : {}
|
|
233
|
+
// });
|
|
234
|
+
// if (!field.model_required) {
|
|
235
|
+
// yupValidator[key] = yupValidator[key].nullable();
|
|
236
|
+
// }
|
|
237
|
+
// continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
yupValidator[key] = Object.prototype.hasOwnProperty.call(extraValidators, key)
|
|
241
|
+
? extraValidators[key]
|
|
242
|
+
: getYupValidator(field.type);
|
|
243
|
+
|
|
244
|
+
if (field.model_required) {
|
|
245
|
+
yupValidator[key] = yupValidator[key].required('Este campo é obrigatório');
|
|
246
|
+
}
|
|
247
|
+
if (field.max_length) {
|
|
248
|
+
yupValidator[key] = yupValidator[key].max(parseInt(field.max_length as string), `Este campo só pode ter no máximo ${field.max_length} caracteres`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// console.log({ yupValidator });
|
|
252
|
+
return (many)
|
|
253
|
+
? Yup.array().of(Yup.object().shape(yupValidator))
|
|
254
|
+
: Yup.object().shape(yupValidator);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
export const errorProps = ({
|
|
258
|
+
type,
|
|
259
|
+
errors,
|
|
260
|
+
fieldKey,
|
|
261
|
+
fieldKeyProp,
|
|
262
|
+
index
|
|
263
|
+
}: {
|
|
264
|
+
type:string,
|
|
265
|
+
errors:Item,
|
|
266
|
+
fieldKey:string,
|
|
267
|
+
fieldKeyProp:string,
|
|
268
|
+
index?:number
|
|
269
|
+
}) => {
|
|
270
|
+
let error;
|
|
271
|
+
let helperText;
|
|
272
|
+
if (index) {
|
|
273
|
+
const hasErrors = errors && errors[fieldKey] && errors[fieldKey][index] && Boolean(errors[fieldKey][index][fieldKeyProp]);
|
|
274
|
+
error = hasErrors;
|
|
275
|
+
helperText = hasErrors ? errors[fieldKey][index][fieldKeyProp].message : null;
|
|
276
|
+
return { error, helperText };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const hasErrors = errors && errors[fieldKey] && Boolean(errors[fieldKey][fieldKeyProp]);
|
|
280
|
+
error = hasErrors;
|
|
281
|
+
helperText = hasErrors ? errors[fieldKey][fieldKeyProp].message : null;
|
|
282
|
+
return { error, helperText };
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export const getTmpId = () => {
|
|
286
|
+
return 'tmp' + Math.floor(Math.random() * 1000000);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export const isTmpId = (id:string | number | undefined | null) => {
|
|
290
|
+
if (!id) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
return id.toString().substr(0, 3) === 'tmp';
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
export const reducer = (state:Record<string, any>, newState:Record<string, any>) => {
|
|
297
|
+
return { ...state, ...newState };
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
export const getPatternFormat = (type:string) => {
|
|
301
|
+
let format = '';
|
|
302
|
+
switch (type) {
|
|
303
|
+
case 'telefone':
|
|
304
|
+
case 'fone':
|
|
305
|
+
case 'phone':
|
|
306
|
+
case 'contact':
|
|
307
|
+
case 'contato':
|
|
308
|
+
format = '(##)#####-####';
|
|
309
|
+
break;
|
|
310
|
+
case 'cpf':
|
|
311
|
+
format = '###.###.###-##';
|
|
312
|
+
break;
|
|
313
|
+
case 'cnpj':
|
|
314
|
+
format = '##.###.###/####-##';
|
|
315
|
+
break;
|
|
316
|
+
case 'cep':
|
|
317
|
+
format = '##.###-###';
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
return format;
|
|
321
|
+
};
|