trithuc-mvc-react 1.1.0 → 1.2.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.
@@ -28,11 +28,12 @@ export const TableRowRender = ({ index, row, selected, onSelect, onChangeStatus,
28
28
  valueGetter = (row) => {
29
29
  return row[field];
30
30
  },
31
+ renderCell,
31
32
  valueFormat = (e) => e
32
33
  }) => {
33
34
  return (
34
35
  <TableCell key={`${row[selectedField]}-${field}`} align={alignRight ? "right" : "left"}>
35
- {valueFormat(valueGetter(row))}
36
+ {renderCell ? renderCell(row) : valueFormat(valueGetter(row))}
36
37
  </TableCell>
37
38
  );
38
39
  }
@@ -32,7 +32,9 @@ DataManagement.propTypes = {
32
32
  validationSchema: PropTypes.object,
33
33
  disableStatus: PropTypes.bool,
34
34
  statusKey: PropTypes.string,
35
- tableActions: PropTypes.array
35
+ tableActions: PropTypes.array,
36
+ disableEditor: PropTypes.bool,
37
+ onAddClick: PropTypes.func
36
38
  };
37
39
 
38
40
  function DataManagement({
@@ -41,11 +43,15 @@ function DataManagement({
41
43
  tableName,
42
44
  selectedField = "Id",
43
45
  filters,
44
- editorFields,
46
+ editorFields = [],
45
47
  validationSchema = {},
46
48
  statusKey = "Status",
47
49
  disableStatus = false,
48
- tableActions = []
50
+ tableActions = [],
51
+ disableEditor = false,
52
+ onAddClick = () => {
53
+
54
+ }
49
55
  }) {
50
56
  const [openEditorDialog, setOpenEditorDialog] = useState(false);
51
57
  const [selectedEditItem, setSelectedEditItem] = useState(null);
@@ -65,6 +71,7 @@ function DataManagement({
65
71
  validationSchema,
66
72
  statusKey,
67
73
  disableStatus,
74
+
68
75
  tableActions
69
76
  };
70
77
  }, [tableName, selectedField, columns, selectedEditItem, dataSearch, setDataSearch, validationSchema, tableActions]);
@@ -107,9 +114,12 @@ function DataManagement({
107
114
  <Button
108
115
  variant="contained"
109
116
  startIcon={<Add />}
110
- onClick={() => {
111
- setOpenEditorDialog(true);
112
- setSelectedEditItem(null);
117
+ onClick={(e) => {
118
+ if (!disableEditor) {
119
+ setOpenEditorDialog(true);
120
+ setSelectedEditItem(null);
121
+ }
122
+ onAddClick(e);
113
123
  }}
114
124
  >
115
125
  Thêm
@@ -120,7 +130,9 @@ function DataManagement({
120
130
  <FilterGod filters={filters} />
121
131
  <DataTable />
122
132
  </FormProvider>
123
- <EditorDialog open={openEditorDialog} onClose={() => setOpenEditorDialog(false)} defaultValues={selectedEditItem} fields={editorFields} />
133
+ {disableEditor || (
134
+ <EditorDialog open={openEditorDialog} onClose={() => setOpenEditorDialog(false)} defaultValues={selectedEditItem} fields={editorFields} />
135
+ )}
124
136
  </PermissionContext.Provider>
125
137
  </DataTableContext.Provider>
126
138
  </>
@@ -0,0 +1,99 @@
1
+ import { Box } from "@mui/material";
2
+ import { FormProvider, useForm } from "react-hook-form";
3
+ import Grid from "@mui/material/Unstable_Grid2"; // Grid version 2
4
+ import PropTypes from "prop-types";
5
+
6
+ import { useEffect } from "react";
7
+ import moment from "moment/moment";
8
+
9
+ import { useMutation, useQueryClient } from "react-query";
10
+ import { saveDataToTable } from "../../api";
11
+ import { toast } from "react-toastify";
12
+
13
+ import FormField from "./FormField";
14
+ import { yupResolver } from "@hookform/resolvers/yup";
15
+ EditorForm.propTypes = {
16
+ fields: PropTypes.array
17
+ };
18
+ function EditorForm({ fields, elementSize = "medium", submitRef, validationSchema, onSubmit }) {
19
+
20
+ const methods = useForm({ defaultValues: {}, resolver: yupResolver(validationSchema) });
21
+
22
+ const handleSubmit = (data) => {
23
+ fields
24
+ .filter(({ type }) => type === "date")
25
+ .forEach(({ field }) => {
26
+ if (data[field]) {
27
+ data[field] = moment(data[field]).toDate();
28
+ }
29
+ });
30
+ fields
31
+ .filter(({ type }) => type === "autocomplete")
32
+ .forEach(({ field, datas, keyValueLabel, keyValue, keyLabel }) => {
33
+ if (data[field] && !data[keyValueLabel] && keyValueLabel) {
34
+ data[keyValueLabel] = datas.find((item) => item[keyValue] == data[field])?.[keyLabel];
35
+ }
36
+ });
37
+
38
+ onSubmit(data);
39
+ };
40
+
41
+ return (
42
+ <FormProvider {...methods}>
43
+ <Box component={"form"} sx={{ pt: 2 }} onSubmit={methods.handleSubmit(handleSubmit)}>
44
+ <Grid container spacing={2}>
45
+ {fields.map(
46
+ ({
47
+ field,
48
+ type = "text",
49
+ label,
50
+ childrenFields,
51
+ datas,
52
+ loading = false,
53
+ onChange = () => {},
54
+ keyLabel,
55
+ keyValue,
56
+ keyValueLabel,
57
+ required
58
+ }) => {
59
+ let sizes = {
60
+ xs: 12,
61
+ sm: 6,
62
+ md: 4
63
+ };
64
+ if (type == "textarea") {
65
+ sizes = {
66
+ xs: 12,
67
+ sm: 12,
68
+ md: 12
69
+ };
70
+ }
71
+ return (
72
+ <Grid {...sizes} key={field}>
73
+ <FormField
74
+ type={type}
75
+ label={label}
76
+ control={methods.control}
77
+ name={field}
78
+ loading={loading}
79
+ onChange={onChange}
80
+ keyLabel={keyLabel}
81
+ keyValueLabel={keyValueLabel}
82
+ datas={datas}
83
+ childrenFields={childrenFields}
84
+ keyValue={keyValue}
85
+ size={elementSize}
86
+ required={required}
87
+ />
88
+ </Grid>
89
+ );
90
+ }
91
+ )}
92
+ </Grid>
93
+ <button ref={submitRef} type="submit" style={{ display: "none" }} />
94
+ </Box>
95
+ </FormProvider>
96
+ );
97
+ }
98
+
99
+ export default EditorForm;
@@ -0,0 +1,241 @@
1
+ import {
2
+ Autocomplete,
3
+ Checkbox,
4
+ FormControl,
5
+ FormControlLabel,
6
+ FormLabel,
7
+ InputLabel,
8
+ MenuItem,
9
+ Radio,
10
+ RadioGroup,
11
+ Select,
12
+ Switch,
13
+ TextField
14
+ } from "@mui/material";
15
+ import { Controller, useFormContext } from "react-hook-form";
16
+ // Grid version 2
17
+ import PropTypes from "prop-types";
18
+ import { DatePicker } from "@mui/x-date-pickers";
19
+ import { useCallback, useEffect, } from "react";
20
+ import moment from "moment/moment";
21
+ import { DEFAULT_DATE_FORMAT } from "../../constants";
22
+
23
+
24
+ FormField.propTypes = {
25
+ datas: PropTypes.array,
26
+ loading: PropTypes.bool
27
+ };
28
+ function FormField({
29
+ type = "text",
30
+ control,
31
+ label,
32
+ name,
33
+ loading,
34
+ datas = [],
35
+ onChange,
36
+ keyLabel,
37
+ keyValue,
38
+ keyValueLabel,
39
+ childrenFields,
40
+ size,
41
+ required = false
42
+ }) {
43
+ const { setValue, register } = useFormContext();
44
+ const getValueObject = useCallback(
45
+ (value) => {
46
+ if (!value) return null;
47
+ const result = [...datas].find((item) => item[keyValue] == value);
48
+
49
+ return result;
50
+ },
51
+ [datas]
52
+ );
53
+
54
+ useEffect(() => {
55
+ if (keyValueLabel) {
56
+ register(keyValueLabel);
57
+ }
58
+ }, []);
59
+
60
+
61
+ switch (type) {
62
+ case "textarea":
63
+ return (
64
+ <Controller
65
+ name={name}
66
+ control={control}
67
+ render={({ field, fieldState: { error } }) => {
68
+ return (
69
+ <TextField
70
+ {...field}
71
+ multiline
72
+ label={label + (required ? "*" : "")}
73
+ error={Boolean(error)}
74
+ helperText={error?.message}
75
+ fullWidth
76
+ placeholder={label}
77
+ size={size}
78
+ />
79
+ );
80
+ }}
81
+ />
82
+ );
83
+
84
+ case "text":
85
+ case "number":
86
+ return (
87
+ <Controller
88
+ name={name}
89
+ control={control}
90
+ render={({ field, fieldState: { error } }) => {
91
+ return (
92
+ <TextField
93
+ {...field}
94
+ type={type}
95
+ label={label + (required ? "*" : "")}
96
+ error={Boolean(error)}
97
+ helperText={error?.message}
98
+ fullWidth
99
+ placeholder={label}
100
+ size={size}
101
+ />
102
+ );
103
+ }}
104
+ />
105
+ );
106
+
107
+ case "autocomplete": {
108
+ if (keyValueLabel) {
109
+ register(keyValueLabel);
110
+ }
111
+ return (
112
+ <Controller
113
+ name={name}
114
+ control={control}
115
+ render={({ field: { onChange: onFieldChange, value }, fieldState: { error } }) => {
116
+ return (
117
+ <Autocomplete
118
+ disablePortal
119
+ noOptionsText="Không có dữ liệu"
120
+ loading={loading}
121
+ size={size}
122
+ options={datas ?? []}
123
+ onChange={(event, newValue) => {
124
+ onFieldChange(newValue?.[keyValue]);
125
+ onChange(newValue);
126
+ if (keyValueLabel) {
127
+ setValue(keyValueLabel, newValue?.[keyLabel]);
128
+ }
129
+ }}
130
+ value={getValueObject(value)}
131
+ fullWidth
132
+ getOptionLabel={(option) => option[keyLabel]}
133
+ renderInput={(params) => <TextField {...params} label={label} error={Boolean(error)} helperText={error?.message} />}
134
+ />
135
+ );
136
+ }}
137
+ />
138
+ );
139
+ }
140
+
141
+ case "select":
142
+ return (
143
+ <Controller
144
+ name={name}
145
+ control={control}
146
+ render={({ field }) => (
147
+ <FormControl sx={{ minWidth: 160 }} fullWidth size={size}>
148
+ <InputLabel>{label}</InputLabel>
149
+ <Select {...field} label={label}>
150
+ {[...datas].map(({ label, value }) => (
151
+ <MenuItem key={value} value={value}>
152
+ {label}
153
+ </MenuItem>
154
+ ))}
155
+ </Select>
156
+ </FormControl>
157
+ )}
158
+ />
159
+ );
160
+ case "radios":
161
+ return (
162
+ <Controller
163
+ name={name}
164
+ control={control}
165
+ defaultValue={null}
166
+ render={({ field }) => {
167
+ return (
168
+ <FormControl fullWidth size={size}>
169
+ <FormLabel>{label}</FormLabel>
170
+ <RadioGroup row {...field}>
171
+ {[...datas].map(({ label, value }) => (
172
+ <FormControlLabel key={value} value={value} control={<Radio />} label={label} />
173
+ ))}
174
+ </RadioGroup>
175
+ </FormControl>
176
+ );
177
+ }}
178
+ />
179
+ );
180
+ case "checkbox":
181
+ return (
182
+ <>
183
+ <Controller
184
+ name={name}
185
+ control={control}
186
+ render={({ field }) => <FormControlLabel control={<Checkbox {...field} checked={field.value} />} label={label} />}
187
+ />
188
+
189
+ {/* {errors.terms && (
190
+ <FormHelperText sx={{ px: 2 }} error>
191
+ {errors.terms.message}
192
+ </FormHelperText>
193
+ )} */}
194
+ </>
195
+ );
196
+ case "switch":
197
+ return (
198
+ <Controller
199
+ name={name}
200
+ control={control}
201
+ defaultValue={true}
202
+ render={({ field }) => <FormControlLabel control={<Switch {...field} checked={field.value} />} label={label} />}
203
+ />
204
+ );
205
+ case "date":
206
+ return (
207
+ <Controller
208
+ name={name}
209
+ control={control}
210
+ render={({ field, fieldState: { error } }) => {
211
+ if (field.value && typeof field.value === "string") {
212
+ field.value = moment(field.value);
213
+ }
214
+ return (
215
+ <DatePicker
216
+ label={label + (required ? "*" : "")}
217
+ {...field}
218
+ format={DEFAULT_DATE_FORMAT}
219
+ slotProps={{
220
+ textField: {
221
+ fullWidth: true, error: Boolean(error),
222
+ helperText: error?.message
223
+ },
224
+ popper: {
225
+ disablePortal: false,
226
+ popperOptions: {
227
+ strategy: 'fixed'
228
+ },
229
+ }
230
+ }}
231
+
232
+
233
+ />
234
+ );
235
+ }}
236
+ />
237
+ );
238
+ }
239
+ }
240
+
241
+ export default FormField;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trithuc-mvc-react",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"