trithuc-mvc-react 3.3.6 → 3.3.8

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.
@@ -27,25 +27,47 @@ const ExportExcelButton = ({ tableName, data, size = "small" }) => {
27
27
  onClick={() => {
28
28
  handleExportExcel(tableName, data);
29
29
  }}
30
- sx={{ ml: 0.5, mr: 0.5, minWidth: isSmallScreen ? "73px" : "100px", textTransform: "none" }}
30
+ sx={{
31
+ ml: 0.5,
32
+ mr: 0.5
33
+ // fontSize: {
34
+ // xs: "0.75rem",
35
+ // sm: "0.85rem",
36
+ // md: "0.95rem"
37
+ // },
38
+ // textAlign: "center",
39
+ // textTransform: "none"
40
+ }}
31
41
  >
32
42
  <Typography
33
43
  noWrap
34
44
  sx={{
35
45
  width: "100%",
36
46
  fontSize: {
37
- xs: "0.75rem",
38
- sm: "0.875rem",
39
- md: "1rem"
47
+ xs: "0.65rem",
48
+ sm: "0.75rem",
49
+ md: "0.95rem"
40
50
  },
41
51
  textAlign: "center",
42
- textTransform: "none" // ✅ Đảm bảo chữ gốc giữ nguyên
52
+ textTransform: "none"
43
53
  }}
44
54
  >
45
55
  Excel
46
56
  </Typography>
47
57
  </Button>
48
58
  ) : (
59
+ // <Tooltip title="Excel">
60
+ // <IconButton
61
+ // variant="outlined"
62
+ // color="primary"
63
+ // size={size}
64
+ // onClick={() => {
65
+ // handleExportExcel(tableName, data);
66
+ // }}
67
+ // >
68
+ // <Download fontSize="inherit" />
69
+ // </IconButton>
70
+ // </Tooltip>
49
71
  <Button
50
72
  size={size}
51
73
  variant="outlined"
@@ -53,7 +75,17 @@ const ExportExcelButton = ({ tableName, data, size = "small" }) => {
53
75
  onClick={() => {
54
76
  handleExportExcel(tableName, data);
55
77
  }}
56
- sx={{ ml: 0.5, mr: 0.5, minWidth: isSmallScreen ? "73px" : "100px", textTransform: "none" }}
78
+ sx={{
79
+ ml: 0.5,
80
+ mr: 0.5,
81
+ fontSize: {
82
+ xs: "0.75rem",
83
+ sm: "0.875rem",
84
+ md: "1rem"
85
+ },
86
+ textAlign: "center",
87
+ textTransform: "none"
88
+ }}
57
89
  >
58
90
  <Typography
59
91
  noWrap
@@ -1,12 +1,13 @@
1
1
  import { EditOutlined } from "@mui/icons-material";
2
2
  import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
3
3
  import RemoveRedEyeOutlinedIcon from "@mui/icons-material/RemoveRedEyeOutlined";
4
- import { Box, Button, Grid, Switch, TableCell, TableRow, Toolbar, useMediaQuery } from "@mui/material";
4
+ import { Box, Button, Grid, Switch, TableCell, TableRow, Toolbar, Typography, useMediaQuery } from "@mui/material";
5
5
  import { styled, useTheme } from "@mui/material/styles";
6
6
  import { useMemo } from "react";
7
7
  import { usePermission } from "../../hooks";
8
8
  import MoreMenu from "../MoreMenu";
9
9
  import { useDataTable } from "./hooks";
10
+ import { fontSize } from "@mui/system";
10
11
 
11
12
  export const TableRowRenderSM = ({
12
13
  index,
@@ -56,105 +57,139 @@ export const TableRowRenderSM = ({
56
57
  overflowWrap: "break-word"
57
58
  }}
58
59
  >
59
- {/* Hiển thị các cột dữ liệu */}
60
- {columns.map(({ field, label, type = "text", valueGetter = (row) => row[field], renderCell, valueFormat = (e) => e }) => {
61
- const value = renderCell ? renderCell(row) : valueFormat(valueGetter(row));
62
- return (
63
- <div key={`${row[selectedField]}-${field}`}>
64
- <strong>{label}: </strong>
65
- {value}
66
- </div>
67
- );
68
- })}
69
-
70
- {/* Công tắc trạng thái */}
71
- {!disableStatus && canEdit && (
72
- <Box sx={{ mt: 1 }}>
73
- <Switch
74
- checked={row[statusKey]}
75
- onChange={() => onChangeStatus(row[selectedField])}
76
- inputProps={{ "aria-label": "controlled" }}
77
- />
78
- </Box>
79
- )}
60
+ <Box
61
+ display="flex"
62
+ flexDirection="column"
63
+ gap={1}
64
+ border="1px solid"
65
+ borderColor="divider"
66
+ borderRadius={2}
67
+ boxShadow={1}
68
+ p={2}
69
+ bgcolor="background.paper"
70
+ sx={{
71
+ transition: "all 0.2s ease",
72
+ "&:hover": {
73
+ boxShadow: 3,
74
+ borderColor: "primary.light"
75
+ }
76
+ }}
77
+ >
78
+ {/* Hiển thị các cột dữ liệu */}
79
+ <Grid container spacing={1}>
80
+ {columns.map(
81
+ ({ field, label, type = "text", valueGetter = (row) => row[field], renderCell, valueFormat = (e) => e }) => {
82
+ const value = renderCell ? renderCell(row) : valueFormat(valueGetter(row));
83
+ return (
84
+ <Grid size={12} key={`${row[selectedField]}-${field}`}>
85
+ <strong>{label}: </strong> {value}
86
+ </Grid>
87
+ );
88
+ }
89
+ )}
90
+ </Grid>
91
+ {/* Công tắc trạng thái */}
92
+ {!disableStatus && canEdit && (
93
+ <Box sx={{ mt: 1 }}>
94
+ <Switch
95
+ checked={row[statusKey]}
96
+ onChange={() => onChangeStatus(row[selectedField])}
97
+ inputProps={{ "aria-label": "controlled" }}
98
+ />
99
+ </Box>
100
+ )}
80
101
 
81
- {/* Các nút thao tác */}
82
- <Grid container spacing={0.5} sx={{ width: "100%", pt: 2, pb: 2 }}>
83
- {!disableCellThaoTac && (
84
- <>
85
- {!disableEdit && canEdit && (
86
- <Grid size={4}>
102
+ {/* Các nút thao tác */}
103
+ <Box
104
+ mt={2}
105
+ pt={1}
106
+ display="flex"
107
+ gap={1}
108
+ flexWrap="wrap"
109
+ justifyContent="flex-end"
110
+ borderTop="1px solid"
111
+ borderColor="divider"
112
+ >
113
+ {!disableCellThaoTac && (
114
+ <>
115
+ {!disableEdit && canEdit && (
87
116
  <Button
88
- fullWidth
89
117
  size="small"
90
- variant="outlined"
118
+ variant="contained"
91
119
  color="primary"
92
120
  onClick={() => onEdit(row)}
93
- startIcon={<EditOutlined fontSize="inherit" />}
94
- sx={buttonStyle}
121
+ startIcon={<EditOutlined />}
122
+ sx={modernButtonStyle}
95
123
  >
96
124
  Cập nhật
97
125
  </Button>
98
- </Grid>
99
- )}
100
- {canView && !tableActions?.some(({ permissionType }) => permissionType === "view") && (
101
- <Grid size={4}>
126
+ )}
127
+
128
+ {canView && !tableActions?.some(({ permissionType }) => permissionType === "view") && (
102
129
  <Button
103
- fullWidth
104
130
  size="small"
105
131
  variant="outlined"
106
132
  color="info"
107
133
  onClick={() => onView(row)}
108
134
  startIcon={<RemoveRedEyeOutlinedIcon />}
109
- sx={buttonStyle}
135
+ sx={modernButtonStyle}
110
136
  >
111
137
  Xem
112
138
  </Button>
113
- </Grid>
114
- )}
115
- {!disableDelete && canDelete && (
116
- <Grid size={4}>
139
+ )}
140
+
141
+ {!disableDelete && canDelete && (
117
142
  <Button
118
- fullWidth
119
143
  size="small"
120
144
  variant="outlined"
121
145
  color="error"
122
146
  onClick={() => onDelete(row[selectedField])}
123
- startIcon={<DeleteOutlineIcon fontSize="inherit" />}
124
- sx={buttonStyle}
147
+ startIcon={<DeleteOutlineIcon />}
148
+ sx={modernButtonStyle}
125
149
  >
126
150
  Xóa
127
151
  </Button>
128
- </Grid>
129
- )}
130
- {tableActionsOnTable.map(
131
- ({ title, size, onClick, element, visible = true }, idx) =>
132
- (typeof visible === "function" ? visible(row) : visible) && (
133
- <Grid key={row.Id} size={4}>
152
+ )}
153
+
154
+ {tableActionsOnTable.map(
155
+ ({ title, size, onClick, element, visible = true }, idx) =>
156
+ (typeof visible === "function" ? visible(row) : visible) && (
134
157
  <Button
135
- fullWidth
136
158
  key={idx}
137
159
  size="small"
138
160
  variant="outlined"
139
161
  onClick={() => onClick(row)}
140
162
  startIcon={element}
141
- sx={{
142
- ...buttonStyle
143
- }}
163
+ sx={modernButtonStyle}
144
164
  >
145
165
  {title === "xem chi tiết" ? "Xem" : title}
146
166
  </Button>
147
- </Grid>
148
- )
149
- )}
150
- <MoreMenu actions={tableActionsOnMoreMenu} data={row} />
151
- </>
152
- )}
153
- </Grid>
167
+ )
168
+ )}
169
+
170
+ <MoreMenu actions={tableActionsOnMoreMenu} data={row} />
171
+ </>
172
+ )}
173
+ </Box>
174
+ </Box>
154
175
  </TableCell>
155
176
  </TableRow>
156
177
  );
157
178
  };
179
+ const modernButtonStyle = {
180
+ fontWeight: 400,
181
+ fontSize: "0.7rem",
182
+ borderRadius: 2,
183
+ minWidth: 90,
184
+ textTransform: "none",
185
+ px: 1,
186
+ py: 0.5,
187
+ boxShadow: "none",
188
+ transition: "all 0.2s ease-in-out",
189
+ "&:hover": {
190
+ boxShadow: "0px 2px 6px rgba(0,0,0,0.1)"
191
+ }
192
+ };
158
193
 
159
194
  // Button style dùng chung
160
195
  const buttonStyle = {
@@ -1,6 +1,6 @@
1
1
  import { Box, Button, Card, Grid, IconButton, Stack, Tooltip, Typography, useMediaQuery, useTheme } from "@mui/material";
2
2
 
3
- import { useEffect, useMemo, useState } from "react";
3
+ import { useEffect, useLayoutEffect, useMemo, useState } from "react";
4
4
 
5
5
  import { Add, Refresh } from "@mui/icons-material";
6
6
  import BarChartIcon from "@mui/icons-material/BarChart";
@@ -20,6 +20,7 @@ import ExportExcelButton from "./ExportExcelButton";
20
20
  import { FilterGod } from "./FilterGod";
21
21
  import HuongDanButton from "./HuongDanButton";
22
22
  import { useRef } from "react";
23
+ import { debounce } from "lodash";
23
24
 
24
25
  DataManagement.propTypes = {
25
26
  columns: PropTypes.array,
@@ -134,6 +135,7 @@ function DataManagement({
134
135
 
135
136
  const theme = useTheme();
136
137
  const upXL = useMediaQuery(theme.breakpoints.up("xl"));
138
+ const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm"));
137
139
  const elementSize = useMemo(() => {
138
140
  const elementSize = upXL ? "medium" : "small";
139
141
  return elementSize;
@@ -211,239 +213,215 @@ function DataManagement({
211
213
  bieuDo,
212
214
  disableHead
213
215
  ]);
214
- const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm")); // Xác định màn hình nhỏ
215
216
  const methods = useForm({ defaultValues: getDefaultValues(filters) });
216
217
  const { reset, setValue } = methods;
217
218
 
219
+ const titleRef = useRef(null);
218
220
  const titleText = title || "";
219
221
  const [titleWidth, setTitleWidth] = useState(0);
220
- const [minWidthValue, setMinWidthValue] = useState(0); // Thêm state cho minWidthValue
222
+ const [minWidthValue, setMinWidthValue] = useState(0);
221
223
 
222
- // Đo chiều rộng của titleText khi render lần đầu
223
- useEffect(() => {
224
- const titleElement = document.createElement("span");
225
- titleElement.style.font = "normal 14px Arial"; // Đảm bảo phông chữ và kích thước giống như bạn dùng trong UI
226
- titleElement.style.visibility = "hidden"; // Ẩn element tạm thời
227
- titleElement.textContent = titleText;
224
+ const leftBoxRef = useRef(null);
225
+ const rightBoxRef = useRef(null);
226
+ const [isFullRow, setIsFullRow] = useState(false);
228
227
 
229
- document.body.appendChild(titleElement);
230
- setTitleWidth(titleElement.offsetWidth); // Lấy chiều rộng của title
231
- document.body.removeChild(titleElement); // Xóa element sau khi đo xong
232
- }, [titleText]);
228
+ const checkLayout = () => {
229
+ if (titleRef.current && rightBoxRef.current) {
230
+ const titleTextWidth = titleRef.current.scrollWidth;
233
231
 
234
- // Khi titleWidth thay đổi, tính toán minWidthValue
235
- useEffect(() => {
236
- if (titleWidth > 0) {
237
- const calculatedMinWidth = Math.max(titleWidth, 150); // Đảm bảo minWidthValue không nhỏ hơn 150px
238
- setMinWidthValue(calculatedMinWidth);
239
- }
240
- }, [titleWidth]); // Phụ thuộc vào titleWidth để đảm bảo minWidthValue được cập nhật khi chiều rộng title thay đổi
232
+ // Tính tổng độ rộng thật của tất cả các phần tử bên trong rightBox
233
+ const rightChildren = Array.from(rightBoxRef.current.children);
234
+ const totalRightWidth = rightChildren.reduce((acc, child) => {
235
+ const childWidth = child.scrollWidth || 0;
236
+ const style = window.getComputedStyle(child);
237
+ const marginLeft = parseFloat(style.marginLeft) || 0;
238
+ const marginRight = parseFloat(style.marginRight) || 0;
239
+ return acc + childWidth + marginLeft + marginRight;
240
+ }, 0);
241
241
 
242
- const rightBoxRef = useRef(null); // Tham chiếu đến khối phải
243
- const [rightBoxMinWidth, setRightBoxMinWidth] = useState(0); // Lưu chiều rộng của khối phải
242
+ const containerWidth = window.innerWidth - 32; // padding 16px trái/phải
243
+ const spacing = 16; // khoảng cách giữa 2 Box
244
244
 
245
- // Đo chiều rộng của khối phải khi component render và khi thay đổi kích thước cửa sổ
246
- useEffect(() => {
247
- // Hàm xử lý resize
248
- const handleResize = () => {
249
- const currentWindowWidth = window.innerWidth;
250
-
251
- // Đo chiều rộng của khối phải trực tiếp từ ref
252
- const rightBoxWidth = rightBoxRef.current ? rightBoxRef.current.offsetWidth : 0;
253
-
254
- // Cập nhật chiều rộng khối phải (rightBoxMinWidth) tùy theo kích thước của cửa sổ và khối
255
- if (currentWindowWidth - (minWidthValue + 30) < rightBoxWidth) {
256
- // console.log(
257
- // `currentWindowWidth - minWidthValue 1: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
258
- // );
259
- setRightBoxMinWidth(currentWindowWidth - 30); // Điều chỉnh chiều rộng khối phải nếu không đủ không gian
260
- } else {
261
- // console.log(
262
- // `currentWindowWidth - minWidthValue 2: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
263
- // );
264
- setRightBoxMinWidth(rightBoxWidth); // Nếu đủ không gian, dùng chiều rộng khối phải
265
- }
266
- };
245
+ const totalContentWidth = titleTextWidth + totalRightWidth + spacing;
267
246
 
268
- // Lần render đầu tiên, tính toán chiều rộng khối phải
269
- const initialResize = () => {
270
- const rightBoxWidth = rightBoxRef.current ? rightBoxRef.current.offsetWidth : 0;
271
- const currentWindowWidth = window.innerWidth;
272
-
273
- // Cập nhật giá trị minWidth ngay khi render lần đầu
274
- if (currentWindowWidth - (minWidthValue + 30) < rightBoxWidth) {
275
- // console.log(
276
- // `currentWindowWidth - minWidthValue 3: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
277
- // );
278
- setRightBoxMinWidth(currentWindowWidth - 30); // Điều chỉnh chiều rộng khối phải nếu không đủ không gian
279
- } else {
280
- // console.log(
281
- // `currentWindowWidth - minWidthValue 4: ${currentWindowWidth - minWidthValue} - rightBoxWidth: ${rightBoxWidth}`
282
- // );
283
- setRightBoxMinWidth(rightBoxWidth); // Nếu đủ không gian, dùng chiều rộng của khối phải
284
- }
285
- };
286
-
287
- // Gọi hàm tính toán ngay khi render lần đầu
288
- if (minWidthValue > 0) {
289
- initialResize();
247
+ setIsFullRow(totalContentWidth > containerWidth);
290
248
  }
249
+ };
250
+
251
+ useEffect(() => {
252
+ const observer = new ResizeObserver(() => {
253
+ checkLayout();
254
+ });
291
255
 
292
- // Lắng nghe sự kiện thay đổi kích thước cửa sổ
293
- window.addEventListener("resize", handleResize);
256
+ if (titleRef.current) observer.observe(titleRef.current);
257
+ if (rightBoxRef.current) observer.observe(rightBoxRef.current);
258
+
259
+ window.addEventListener("resize", checkLayout);
294
260
 
295
- // Dọn dẹp sự kiện khi component bị hủy
296
261
  return () => {
297
- window.removeEventListener("resize", handleResize);
262
+ observer.disconnect();
263
+ window.removeEventListener("resize", checkLayout);
298
264
  };
299
- }, [minWidthValue]); // Phụ thuộc vào minWidthValue để tính toán khi nó được cập nhật
300
-
301
- // In các giá trị trong console để kiểm tra
302
- // useEffect(() => {
303
- // console.log("minWidthValue:", minWidthValue);
304
- // console.log("rightBoxMinWidth:", rightBoxMinWidth);
305
- // }, [rightBoxMinWidth]);
265
+ }, []);
306
266
 
307
267
  return (
308
268
  <>
309
269
  <DataTableContext.Provider value={values}>
310
270
  <FormProvider {...methods}>
311
271
  {!disableHead && (
312
- <Stack
313
- direction="row"
314
- sx={{
315
- mb: upXL ? 1 : 1,
316
- flexWrap: "wrap",
317
- alignItems: "center",
318
- gap: 1,
319
- ...slotProps?.header?.sx
320
- }}
321
- >
322
- {/* Khối trái */}
323
- <Box
324
- sx={{
325
- flexGrow: 1,
326
- Width: `${minWidthValue}px`,
327
- textAlign: "left",
328
- whiteSpace: "normal",
329
- wordBreak: "break-word"
330
- }}
331
- >
332
- <Typography variant={isSmallScreen ? "body2" : "subtitle1"}>{titleText}</Typography>
333
- </Box>
334
-
335
- {/* Khối phải */}
336
- <Box
337
- ref={rightBoxRef} // Tham chiếu đến phần tử này
272
+ <Card sx={{ p: 0, mb: 0 }}>
273
+ <Stack
274
+ direction={isFullRow ? "column" : "row"}
338
275
  sx={{
339
- display: "flex",
340
- flexWrap: "nowrap",
341
- justifyContent: "flex-end",
342
- alignItems: "center",
343
- flexShrink: 0,
344
- // minWidth: "300px", // Đảm bảo chiều rộng tối thiểu
345
- width: rightBoxMinWidth ? `${rightBoxMinWidth}px` : "auto" // Sử dụng chiều rộng đo được
276
+ // mb: upXL ? 1 : 1,
277
+ flexWrap: isFullRow ? "nowrap" : "wrap",
278
+ alignItems: isFullRow ? "stretch" : "center",
279
+ gap: 1,
280
+ ...slotProps?.header?.sx
346
281
  }}
347
282
  >
348
- {(viewMode === "thongke" || viewMode === "bieudo") && (
349
- <Tooltip title="Danh sách dữ liệu">
350
- <IconButton size={elementSize} color="primary" onClick={() => setViewMode("table")} sx={{ ml: 0.5, mr: 0.5 }}>
351
- <TableChartIcon fontSize="inherit" />
352
- </IconButton>
353
- </Tooltip>
354
- )}
355
-
356
- {canThongKe && (
357
- <Tooltip title="Thống kê">
283
+ {/* Left side */}
284
+ <Box
285
+ ref={leftBoxRef}
286
+ sx={{
287
+ flexGrow: isFullRow ? 0 : 1,
288
+ width: isFullRow ? "100%" : `${minWidthValue}px`,
289
+ textAlign: "left",
290
+ whiteSpace: "normal",
291
+ wordBreak: "break-word"
292
+ }}
293
+ >
294
+ <Typography
295
+ ref={titleRef}
296
+ noWrap
297
+ sx={{
298
+ width: "100%",
299
+ fontSize: {
300
+ xs: "0.85rem",
301
+ sm: "0.95rem",
302
+ md: "1rem"
303
+ },
304
+ textAlign: "left",
305
+ textTransform: "none"
306
+ }}
307
+ >
308
+ {titleText}
309
+ </Typography>
310
+ </Box>
311
+
312
+ {/* Right side */}
313
+ <Box
314
+ ref={rightBoxRef}
315
+ sx={{
316
+ display: "flex",
317
+ flexWrap: "wrap",
318
+ justifyContent: isFullRow ? "flex-end" : "flex-end",
319
+ alignItems: "center",
320
+ width: isFullRow ? "100%" : "auto",
321
+ flexShrink: 0
322
+ }}
323
+ >
324
+ {(viewMode === "thongke" || viewMode === "bieudo") && (
325
+ <Tooltip title="Danh sách dữ liệu">
326
+ <IconButton
327
+ size={elementSize}
328
+ color="primary"
329
+ onClick={() => setViewMode("table")}
330
+ sx={{ ml: 0.5, mr: 0.5 }}
331
+ >
332
+ <TableChartIcon fontSize="inherit" />
333
+ </IconButton>
334
+ </Tooltip>
335
+ )}
336
+
337
+ {canThongKe && (
338
+ <Tooltip title="Thống kê">
339
+ <IconButton
340
+ size={elementSize}
341
+ color={viewMode === "thongke" ? "secondary" : "primary"}
342
+ onClick={() => setViewMode("thongke")}
343
+ sx={{ ml: 0.5, mr: 0.5 }}
344
+ >
345
+ <BarChartIcon fontSize="inherit" />
346
+ </IconButton>
347
+ </Tooltip>
348
+ )}
349
+
350
+ {canBieuDo && (
351
+ <Tooltip title="Biểu đồ">
352
+ <IconButton
353
+ size={elementSize}
354
+ color={viewMode === "bieudo" ? "secondary" : "primary"}
355
+ onClick={() => setViewMode("bieudo")}
356
+ sx={{ ml: 0.5, mr: 0.5 }}
357
+ >
358
+ <PieChartIcon fontSize="inherit" />
359
+ </IconButton>
360
+ </Tooltip>
361
+ )}
362
+
363
+ <HuongDanButton tableName={tableName} size={elementSize} />
364
+ <Tooltip title="Làm mới">
358
365
  <IconButton
366
+ variant="outlined"
367
+ color="primary"
359
368
  size={elementSize}
360
- color={viewMode === "thongke" ? "secondary" : "primary"}
361
- onClick={() => setViewMode("thongke")}
362
- sx={{ ml: 0.5, mr: 0.5 }}
369
+ onClick={() => {
370
+ setDataSearch({ ...defaults });
371
+ [...filters].forEach((filter) => {
372
+ filter?.onChange?.();
373
+ });
374
+ reset();
375
+ setValue("Search");
376
+ }}
363
377
  >
364
- <BarChartIcon fontSize="inherit" />
378
+ <Refresh fontSize="inherit" />
365
379
  </IconButton>
366
380
  </Tooltip>
367
- )}
368
381
 
369
- {canBieuDo && (
370
- <Tooltip title="Biểu đồ">
371
- <IconButton
372
- size={elementSize}
373
- color={viewMode === "bieudo" ? "secondary" : "primary"}
374
- onClick={() => setViewMode("bieudo")}
375
- sx={{ ml: 0.5, mr: 0.5 }}
376
- >
377
- <PieChartIcon fontSize="inherit" />
378
- </IconButton>
379
- </Tooltip>
380
- )}
382
+ {titleButtons?.map((button, index) => (
383
+ <div key={index}>{button}</div>
384
+ ))}
381
385
 
382
- <HuongDanButton tableName={tableName} size={elementSize} />
383
- <Tooltip title="Làm mới">
384
- <IconButton
385
- variant="outlined"
386
- color="primary"
387
- size={elementSize}
388
- onClick={() => {
389
- setDataSearch({ ...defaults });
390
- [...filters].forEach((filter) => {
391
- filter?.onChange?.();
392
- });
393
- reset();
394
- setValue("Search");
395
- }}
396
- >
397
- <Refresh fontSize="inherit" />
398
- </IconButton>
399
- </Tooltip>
400
-
401
- {titleButtons?.map((button, index) => (
402
- <div key={index}>{button}</div>
403
- ))}
404
-
405
- <ExportExcelButton tableName={tableName} data={dataSearch} size={elementSize} />
406
-
407
- {canCreate && !disableAdd && (
408
- <Button
409
- size={elementSize}
410
- variant="contained"
411
- startIcon={<Add fontSize="inherit" />}
412
- onClick={(e) => {
413
- if (!disableEditor) {
414
- setOpenEditorDialog(true);
415
- setSelectedEditItem(null);
416
- }
417
- onAddClick(e);
418
- }}
419
- sx={{
420
- ml: 0.5,
421
- mr: 0.5,
422
- minWidth: isSmallScreen ? "100px" : "130px",
423
- textTransform: "none" // ✅ Không viết hoa tự động
424
- }}
425
- >
426
- <Typography
427
- noWrap
386
+ <ExportExcelButton tableName={tableName} data={dataSearch} size={elementSize} />
387
+
388
+ {canCreate && !disableAdd && (
389
+ <Button
390
+ size={elementSize}
391
+ variant="contained"
392
+ startIcon={<Add fontSize="inherit" />}
393
+ onClick={(e) => {
394
+ if (!disableEditor) {
395
+ setOpenEditorDialog(true);
396
+ setSelectedEditItem(null);
397
+ }
398
+ onAddClick(e);
399
+ }}
428
400
  sx={{
429
- width: "100%",
430
- fontSize: {
431
- xs: "0.75rem",
432
- sm: "0.875rem",
433
- md: "1rem"
434
- },
435
- textAlign: "center",
436
- textTransform: "none" // ✅ Đảm bảo chữ gốc giữ nguyên
401
+ ml: 0.5
437
402
  }}
438
403
  >
439
- {titleAddButton}
440
- </Typography>
441
- </Button>
442
- )}
443
- </Box>
444
- </Stack>
404
+ <Typography
405
+ noWrap
406
+ sx={{
407
+ width: "100%",
408
+ fontSize: {
409
+ xs: "0.65rem",
410
+ sm: "0.75rem",
411
+ md: "0.85rem"
412
+ },
413
+ textAlign: "center",
414
+ textTransform: "none"
415
+ }}
416
+ >
417
+ {titleAddButton}
418
+ </Typography>
419
+ </Button>
420
+ )}
421
+ </Box>
422
+ </Stack>
423
+ </Card>
445
424
  )}
446
-
447
425
  <Card className="custom-card-DataManagement">
448
426
  {tabPanel}
449
427
  {viewMode === "table" && (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trithuc-mvc-react",
3
- "version": "3.3.6",
3
+ "version": "3.3.8",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"