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.
 
 
 

345 rivejä
12 KiB

  1. // material-ui
  2. import * as React from 'react';
  3. import {
  4. Button,
  5. } from '@mui/material';
  6. import {
  7. DataGrid,
  8. GridActionsCellItem,
  9. GridRowEditStopReasons,
  10. GridRowModes,
  11. GridToolbarContainer
  12. } from "@mui/x-data-grid";
  13. import EditIcon from '@mui/icons-material/Edit';
  14. import DeleteIcon from '@mui/icons-material/DeleteOutlined';
  15. import SaveIcon from '@mui/icons-material/Save';
  16. import CancelIcon from '@mui/icons-material/Close';
  17. import AddIcon from '@mui/icons-material/Add';
  18. import {useContext, useEffect} from "react";
  19. import axios from "axios";
  20. import {apiPath} from "../../auth/utils";
  21. import {
  22. CHECK_APPRECIATION_CATEGORY_DUPLICATE,
  23. GET_APPRECIATION_CATEGORY_LIST,
  24. UPDATE_APPRECIATION_CATEGORY_PATH
  25. } from "../../utils/ApiPathConst";
  26. import {
  27. CustomNoRowsOverlay,
  28. GeneralConfirmWindow,
  29. notifyDeleteError,
  30. notifyDeleteSuccess,
  31. notifySaveSuccess,
  32. removeObjectWithId
  33. } from "../../utils/CommonFunction";
  34. import UploadContext from "../../components/UploadProvider";
  35. import {LIONER_BUTTON_THEME} from "../../themes/colorConst";
  36. import {ThemeProvider} from "@emotion/react";
  37. let customerCount = -1;
  38. function EditToolbar(props) {
  39. const {setRows, setRowModesModel} = props;
  40. const handleClick = (id) => {
  41. setRows((oldRows) => [
  42. {
  43. id,
  44. isNew:true
  45. }
  46. ,...oldRows
  47. ]);
  48. setRowModesModel((oldModel) => ({
  49. ...oldModel,
  50. [id]: {mode: GridRowModes.Edit, fieldToFocus: 'name'},
  51. }));
  52. };
  53. return (
  54. <GridToolbarContainer sx={{ml: 1}}>
  55. <Button color="primary" startIcon={<AddIcon/>}
  56. onClick={()=> handleClick(customerCount--)}
  57. >
  58. Add Category
  59. </Button>
  60. </GridToolbarContainer>
  61. );
  62. }
  63. // ==============================|| CATEGORY TABLE ||============================== //
  64. export default function AppreciationCategoryTable({recordList}) {
  65. const [rows, setRows] = React.useState([]);
  66. const [rowModesModel, setRowModesModel] = React.useState({});
  67. const { setIsUploading } = useContext(UploadContext);
  68. // ==============================|| DELETE WINDOW RELATED ||============================== //
  69. const [isWindowOpen, setIsWindowOpen] = React.useState(false);
  70. const [selectedId, setSelectedId] = React.useState(null);
  71. const handleClose = () => {
  72. setIsWindowOpen(false);
  73. };
  74. const [paginationModel, setPaginationModel] = React.useState({
  75. page: 0,
  76. pageSize:10
  77. });
  78. useEffect(() => {
  79. setPaginationModel({page:0,pageSize:10});
  80. setRows(recordList);
  81. }, [recordList]);
  82. const handleDeleteClick = (id) => () => {
  83. setIsWindowOpen(true);
  84. setSelectedId(id);
  85. };
  86. function updateData(){
  87. setIsUploading(true);
  88. axios.delete(`${apiPath}${GET_APPRECIATION_CATEGORY_LIST}/${selectedId}`,
  89. )
  90. .then((response) => {
  91. if (response.status === 204) {
  92. notifyDeleteSuccess();
  93. const newList =removeObjectWithId(rows,selectedId);
  94. setIsWindowOpen(false);
  95. setRows(newList);
  96. }
  97. setIsUploading(false);
  98. })
  99. .catch(error => {
  100. console.log(error);
  101. setIsUploading(false);
  102. return false;
  103. });
  104. }
  105. // ==============================|| DELETE WINDOW RELATED ||============================== //
  106. useEffect(()=>{
  107. setRows(recordList);
  108. },[recordList]);
  109. const handleRowEditStop = (params, event) => {
  110. if (params.reason === GridRowEditStopReasons.rowFocusOut) {
  111. event.defaultMuiPrevented = true;
  112. }
  113. };
  114. const handleEditClick = (id) => () => {
  115. setRowModesModel({...rowModesModel, [id]: {mode: GridRowModes.Edit, fieldToFocus: 'name'}});
  116. };
  117. const handleSaveClick = (id) => () => {
  118. setRowModesModel({...rowModesModel, [id]: {mode: GridRowModes.View, fieldToFocus: 'name'}});
  119. };
  120. const handleCancelClick = (id) => () => {
  121. setRowModesModel({
  122. ...rowModesModel,
  123. [id]: {mode: GridRowModes.View, ignoreModifications: true},
  124. });
  125. const editedRow = rows.find((row) => row.id === id);
  126. if (editedRow.isNew) {
  127. setRows(rows.filter((row) => row.id !== id));
  128. }
  129. };
  130. function updateCategory(data) {
  131. if(data.name.trim().length === 0){
  132. notifyDeleteError(`Name cannot be null`);
  133. handleEditClick(data.id);
  134. }
  135. else{
  136. axios.get(`${apiPath}${CHECK_APPRECIATION_CATEGORY_DUPLICATE}`,
  137. {
  138. params: {
  139. "name": data.name.trim(),
  140. "id": data.id
  141. },
  142. })
  143. .then((response) => {
  144. if (response.status === 200) {
  145. if(response.data.isTaken){
  146. notifyDeleteError(`${data.name} already exists.`)
  147. handleEditClick(data.id);
  148. }
  149. else if(!response.data.isTaken){
  150. processUpload(data);
  151. }
  152. }
  153. })
  154. .catch(error => {
  155. console.log(error);
  156. return true;
  157. });
  158. }
  159. }
  160. function processUpload(data){
  161. setIsUploading(true);
  162. axios.post(`${apiPath}${UPDATE_APPRECIATION_CATEGORY_PATH}`,
  163. {
  164. "id": data.id,
  165. "name": data.name.trim(),
  166. },
  167. )
  168. .then((response) => {
  169. if (response.status === 200) {
  170. const updatedRow = { ...data };
  171. updatedRow.id = response.data.id;
  172. setIsUploading(false);
  173. if(data.id === -1){
  174. setRows(rows.map((row) => (row.id === -1 ? updatedRow : row)));
  175. }
  176. else{
  177. setRows(rows.map((row) => (row.id === data.id ? updatedRow : row)));
  178. }
  179. notifySaveSuccess();
  180. }
  181. })
  182. .catch(error => {
  183. console.log(error);
  184. setIsUploading(false);
  185. return false;
  186. });
  187. }
  188. const processRowUpdate = (newRow) => {
  189. return new Promise((resolve, reject) => {
  190. const updatedRow = { ...newRow, isNew: false };
  191. if (updatedRow.name.trim().length === 0) {
  192. const error = new Error('Name cannot be null');
  193. reject(error);
  194. return;
  195. }
  196. setRows(rows.map((row) => (row.id === newRow.id ? updatedRow : row)));
  197. updateCategory(updatedRow);
  198. resolve(updatedRow); // Resolve the Promise with the updated row
  199. });
  200. };
  201. const handleRowModesModelChange = (newRowModesModel) => {
  202. setRowModesModel(newRowModesModel);
  203. };
  204. const columns = [
  205. {
  206. field: 'actions',
  207. type: 'actions',
  208. headerName: 'Actions',
  209. width: 100,
  210. cellClassName: 'actions',
  211. getActions: ({id}) => {
  212. const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
  213. if (isInEditMode) {
  214. return [
  215. <ThemeProvider key="OutSave" theme={LIONER_BUTTON_THEME}>
  216. <GridActionsCellItem
  217. key="InCancel"
  218. icon={<CancelIcon sx={{fontSize: 25}}/>}
  219. label="Cancel"
  220. className="textPrimary"
  221. onClick={handleCancelClick(id)}
  222. color="error"
  223. />
  224. </ThemeProvider>,
  225. <ThemeProvider key="OutSave" theme={LIONER_BUTTON_THEME}>
  226. <GridActionsCellItem
  227. key="InSave"
  228. icon={<SaveIcon sx={{fontSize: 25}}/>}
  229. label="Save"
  230. // sx={{
  231. // color: 'primary.main',
  232. // }}
  233. color="save"
  234. onClick={handleSaveClick(id)}
  235. />
  236. </ThemeProvider>,
  237. ];
  238. }
  239. return [
  240. <ThemeProvider key="OutSave" theme={LIONER_BUTTON_THEME}>
  241. <GridActionsCellItem
  242. key="OutDelete"
  243. icon={<DeleteIcon sx={{fontSize: 25}}/>}
  244. label="Delete"
  245. onClick={handleDeleteClick(id)}
  246. color="delete"
  247. />
  248. </ThemeProvider>
  249. ,
  250. <ThemeProvider key="OutSave" theme={LIONER_BUTTON_THEME}>
  251. <GridActionsCellItem
  252. key="OutSave"
  253. icon={<EditIcon sx={{fontSize: 25}}/>}
  254. label="Edit"
  255. className="textPrimary"
  256. onClick={handleEditClick(id)}
  257. color="edit"
  258. />
  259. </ThemeProvider>,
  260. ];
  261. },
  262. },
  263. {
  264. id: 'categoryName',
  265. field: 'name',
  266. headerName: 'Category Name',
  267. flex: 1,
  268. editable: true,
  269. preProcessEditCellProps: (params) => {
  270. if(params.props.value !== undefined){
  271. const hasError = params.props.value.length > 50;
  272. if (hasError) {
  273. notifyDeleteError("Input has reached the length limit (50)");
  274. }
  275. return { ...params.props, error: hasError };
  276. }
  277. },
  278. },
  279. ];
  280. return (
  281. <div style={{/*height: '66vh',*/ width: '100%'}}>
  282. <DataGrid
  283. rows={rows}
  284. columns={columns}
  285. columnHeaderHeight={45}
  286. editMode="row"
  287. rowModesModel={rowModesModel}
  288. onRowModesModelChange={handleRowModesModelChange}
  289. onRowEditStop={handleRowEditStop}
  290. onProcessRowUpdateError={(error) => {
  291. console.log(error);
  292. notifyDeleteError(`Name cannot be null`);
  293. }}
  294. getRowHeight={() => 'auto'}
  295. processRowUpdate={processRowUpdate}
  296. paginationModel={paginationModel}
  297. onPaginationModelChange={setPaginationModel}
  298. slots={{
  299. toolbar: EditToolbar,
  300. noRowsOverlay: () => (
  301. CustomNoRowsOverlay()
  302. )
  303. }}
  304. pageSizeOptions={[15]}
  305. slotProps={{
  306. toolbar: {setRows, setRowModesModel},
  307. }}
  308. autoHeight
  309. />
  310. <GeneralConfirmWindow
  311. isWindowOpen={isWindowOpen}
  312. title={"Attention"}
  313. //content={`Confirm to delete Category ${getObjectById(rows,selectedId) === null? "" : '"' + getObjectById(rows,selectedId).name + '"'} ?`}
  314. content={`Are you sure to delete this appreciation category?`}
  315. onNormalClose={handleClose}
  316. onConfirmClose={updateData}
  317. />
  318. </div>
  319. );
  320. }