You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

189 lines
6.9 KiB

  1. // material-ui
  2. import * as React from 'react';
  3. import {
  4. DataGrid,
  5. GridActionsCellItem,
  6. GridRowModes,
  7. GridRowEditStopReasons,
  8. } from "@mui/x-data-grid";
  9. import EditIcon from '@mui/icons-material/Edit';
  10. import DeleteIcon from '@mui/icons-material/Delete';
  11. import SaveIcon from '@mui/icons-material/Save';
  12. import CancelIcon from '@mui/icons-material/Cancel';
  13. import {useContext, useEffect} from "react";
  14. import {CustomNoRowsOverlay, dateComparator, getDateString} from "../../../utils/CommonFunction";
  15. import AbilityContext from "../../../components/AbilityProvider";
  16. import {LIONER_BUTTON_THEME} from "../../../themes/colorConst";
  17. import {ThemeProvider} from "@emotion/react";
  18. import axios from "axios"; // Add this
  19. import {apiPath} from "../../../auth/utils"; // Add this (same as in index.js)
  20. // ==============================|| Consultant TABLE ||============================== //
  21. export default function ConsultantTable({recordList, applySearch}) {
  22. const [rows, setRows] = React.useState([]);
  23. const [rowModesModel, setRowModesModel] = React.useState({});
  24. const ability = useContext(AbilityContext);
  25. const [paginationModel, setPaginationModel] = React.useState({
  26. page: 0,
  27. pageSize: 10
  28. });
  29. useEffect(() => {
  30. setPaginationModel({page: 0, pageSize: 10});
  31. // Ensure each row has a unique 'id' field (required by DataGrid)
  32. setRows(recordList.map(row => ({ ...row, id: row.id || row.someUniqueKey })));
  33. }, [recordList]);
  34. const handleRowEditStop = (params, event) => {
  35. if (params.reason === GridRowEditStopReasons.rowFocusOut) {
  36. event.defaultMuiPrevented = true;
  37. }
  38. };
  39. const handleEditClick = (id) => () => {
  40. setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.Edit } });
  41. };
  42. const handleSaveClick = (id) => () => {
  43. setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } });
  44. };
  45. const handleCancelClick = (id) => () => {
  46. setRowModesModel({
  47. ...rowModesModel,
  48. [id]: { mode: GridRowModes.View, ignoreModifications: true },
  49. });
  50. };
  51. const handleDeleteClick = (id) => async () => {
  52. if (window.confirm("Are you sure you want to delete this consultant? This action cannot be undone.")) {
  53. try {
  54. const response = await axios.post(`${apiPath}/consultant/delete`, { id });
  55. if (response.status === 200 || response.status === 204) {
  56. applySearch(); // Refresh the table
  57. }
  58. } catch (err) {
  59. console.error("Delete error:", err);
  60. alert("Failed to delete consultant. Please try again.");
  61. }
  62. }
  63. };
  64. const processRowUpdate = async (newRow) => {
  65. // Optimistically update UI
  66. const updatedRow = { ...newRow };
  67. try {
  68. const response = await axios.post(`${apiPath}/consultant/save`, newRow);
  69. if (response.status === 200) {
  70. // If backend returns updated data, use it
  71. return response.data || updatedRow;
  72. }
  73. } catch (err) {
  74. console.error("Save error:", err);
  75. alert("Failed to save changes. Please try again.");
  76. // On failure, you could revert, but here we keep the edited value
  77. }
  78. return updatedRow;
  79. };
  80. const columns = [
  81. {
  82. field: 'actions',
  83. type: 'actions',
  84. headerName: 'Actions',
  85. width: 150,
  86. getActions: ({ id }) => {
  87. const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
  88. if (isInEditMode) {
  89. return [
  90. <ThemeProvider key="save" theme={LIONER_BUTTON_THEME}>
  91. <GridActionsCellItem
  92. icon={<SaveIcon />}
  93. label="Save"
  94. onClick={handleSaveClick(id)}
  95. color="save"
  96. />
  97. </ThemeProvider>,
  98. <ThemeProvider key="cancel" theme={LIONER_BUTTON_THEME}>
  99. <GridActionsCellItem
  100. icon={<CancelIcon />}
  101. label="Cancel"
  102. onClick={handleCancelClick(id)}
  103. color="cancel"
  104. />
  105. </ThemeProvider>,
  106. ];
  107. }
  108. return [
  109. <ThemeProvider key="edit" theme={LIONER_BUTTON_THEME}>
  110. <GridActionsCellItem
  111. icon={<EditIcon sx={{fontSize: 25}}/>}
  112. label="Edit"
  113. onClick={handleEditClick(id)}
  114. color="edit"
  115. />
  116. </ThemeProvider>,
  117. <ThemeProvider key="delete" theme={LIONER_BUTTON_THEME}>
  118. <GridActionsCellItem
  119. icon={<DeleteIcon />}
  120. label="Delete"
  121. onClick={handleDeleteClick(id)}
  122. color="error" // Use "error" if no 'delete' color defined
  123. />
  124. </ThemeProvider>,
  125. ];
  126. },
  127. },
  128. {
  129. field: 'name',
  130. headerName: 'Name',
  131. flex: 2,
  132. editable: true, // Enables inline editing
  133. renderCell: (params) => (
  134. <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}>
  135. {params.value}
  136. </div>
  137. ),
  138. },
  139. {
  140. field: 'createDate',
  141. headerName: 'Create Datetime',
  142. flex: 1,
  143. sortComparator: dateComparator,
  144. renderCell: (params) => (
  145. <div>
  146. {getDateString(params.row.created, 'dd/MM/yyyy HH:mm:ss')}
  147. </div>
  148. ),
  149. },
  150. ];
  151. return (
  152. <div style={{ width: '100%' }}>
  153. <DataGrid
  154. rows={rows}
  155. columns={columns}
  156. editMode="row"
  157. rowModesModel={rowModesModel}
  158. onRowModesModelChange={setRowModesModel}
  159. onRowEditStop={handleRowEditStop}
  160. processRowUpdate={processRowUpdate}
  161. onProcessRowUpdateError={(error) => console.error(error)}
  162. getRowHeight={() => 'auto'}
  163. paginationModel={paginationModel}
  164. onPaginationModelChange={setPaginationModel}
  165. slots={{ noRowsOverlay: CustomNoRowsOverlay }}
  166. pageSizeOptions={[10]}
  167. autoHeight
  168. />
  169. </div>
  170. );
  171. }