From dbcd5a736a01d2e681b6a9708ceb14f2fe8f04fe Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Jan 2025 18:45:14 +0700 Subject: [PATCH] usermanagement, role, etc --- package-lock.json | 88 ++++++++ package.json | 3 + public/index.html | 6 +- public/logo.jpeg | Bin 0 -> 19199 bytes src/components/Header.js | 4 +- src/components/SideBar.js | 20 +- src/components/WarningDialog.js | 46 ++++ src/config/axios.js | 20 +- src/index.js | 14 +- src/pages/Login.js | 55 ++++- src/pages/MasterData.js | 133 ++++++++++++ src/pages/Profile.js | 362 ++++++++++++++++++++++++++++++++ src/pages/RoleManagement.js | 173 ++++++++++----- src/pages/Setting.js | 4 + src/pages/UserManagement.js | 300 +++++++++++++++++++++----- src/routes/routes.js | 18 +- src/store/store.js | 9 + 17 files changed, 1121 insertions(+), 134 deletions(-) create mode 100644 public/logo.jpeg create mode 100644 src/components/WarningDialog.js create mode 100644 src/pages/MasterData.js create mode 100644 src/pages/Profile.js create mode 100644 src/store/store.js diff --git a/package-lock.json b/package-lock.json index 8b161f3..a2de86d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@emotion/styled": "^11.14.0", "@mui/icons-material": "^6.2.1", "@mui/material": "^6.2.1", + "@reduxjs/toolkit": "^2.5.0", "@testing-library/jest-dom": "^5.17.0", "@testing-library/user-event": "^13.5.0", "ajv": "^8.17.1", @@ -23,8 +24,10 @@ "react-chartjs-2": "^5.2.0", "react-circular-progressbar": "^2.1.0", "react-dom": "^18.3.1", + "react-redux": "^9.2.0", "react-router-dom": "^7.1.1", "react-scripts": "5.0.1", + "redux": "^5.0.1", "web-vitals": "^2.1.4" }, "devDependencies": { @@ -3370,6 +3373,38 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.5.0.tgz", + "integrity": "sha512-awNe2oTodsZ6LmRqmkFhtb/KH03hUhxOamEQy411m3Njj3BbFvoBovxo4Q1cBWnV1ErprVj9MlF0UPXkng0eyg==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4309,6 +4344,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==" + }, "node_modules/@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", @@ -13665,6 +13705,28 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -13861,6 +13923,19 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz", @@ -14017,6 +14092,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -16070,6 +16150,14 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 3d22a2a..216e2da 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@emotion/styled": "^11.14.0", "@mui/icons-material": "^6.2.1", "@mui/material": "^6.2.1", + "@reduxjs/toolkit": "^2.5.0", "@testing-library/jest-dom": "^5.17.0", "@testing-library/user-event": "^13.5.0", "ajv": "^8.17.1", @@ -18,8 +19,10 @@ "react-chartjs-2": "^5.2.0", "react-circular-progressbar": "^2.1.0", "react-dom": "^18.3.1", + "react-redux": "^9.2.0", "react-router-dom": "^7.1.1", "react-scripts": "5.0.1", + "redux": "^5.0.1", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/public/index.html b/public/index.html index a82a2e7..ae4285e 100644 --- a/public/index.html +++ b/public/index.html @@ -2,14 +2,14 @@ - + - + - T-Pay Dashboard + T-Pay| Dashboard diff --git a/public/logo.jpeg b/public/logo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..5f2edf383344d2c82d52e770cb7a13f9c858a202 GIT binary patch literal 19199 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

2n;+I*&BZWXA=F9C%gY2kiQwEv^x)mt$ zA?-<(jSt~nCgE7u5E{TIJz!6slgHlI=xQccJx9ReMPUV~(nJn{TEr7V%8Oh#uCz#q z=p$iC>kwe#)VZvFZwiQQ-?&f#1&{KT6x7$=o>FqWaB5NFW7gF=UN=}2!aQR+vRd9g z^}MNeRJG|_#+B9g*cAa?0%$77TA&?jXyryljNlfzDt(bX z`zlYn8O>a|_)(k;QKoA}zxz-zF9MGf+5Z5*)(_xcK~ZR|{>msaP{AhmiJ$-gFc1DW K|Na020RP$4RNd$R literal 0 HcmV?d00001 diff --git a/src/components/Header.js b/src/components/Header.js index 1d1ea4d..1928297 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -34,7 +34,9 @@ const Header = () => { function logoutBtn() { Cookies.remove('token'); Cookies.remove('role'); + Cookies.remove('userId'); Cookies.remove('username'); + localStorage.removeItem('roles_list'); navigate('/login') } @@ -77,7 +79,7 @@ const Header = () => { 'aria-labelledby': 'basic-button', }} > - + navigate('/profile')}> Profile diff --git a/src/components/SideBar.js b/src/components/SideBar.js index 5c1d320..ed74bf3 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.js @@ -131,10 +131,6 @@ const Sidebar = () => { { title: 'Setting', options: [ - { - title: 'Setting', - path: '/setting' - }, { title: 'User Management', path: '/user-management' @@ -142,7 +138,19 @@ const Sidebar = () => { { title: 'Role Management', path: '/role-management' - } + }, + { + title: 'Profile', + path: '/profile' + }, + { + title: 'Setting', + path: '/setting' + }, + { + title: 'Master Data', + path: '/master-data' + }, ], }, ]; @@ -275,7 +283,9 @@ const Sidebar = () => { function logoutBtn() { Cookies.remove('token'); Cookies.remove('role'); + Cookies.remove('userId'); Cookies.remove('username'); + localStorage.removeItem('roles_list'); navigate('/login'); } diff --git a/src/components/WarningDialog.js b/src/components/WarningDialog.js new file mode 100644 index 0000000..eb80a0e --- /dev/null +++ b/src/components/WarningDialog.js @@ -0,0 +1,46 @@ +// ErrorModal.js +import React from "react"; +import { Modal, Box, Typography, Button } from "@mui/material"; + +const ErrorModal = ({ open, onClose, errorMessage }) => { + const style = { + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: 400, + bgcolor: "background.paper", + border: "2px solid #000", + boxShadow: 24, + p: 4, + borderRadius: 2, + }; + + return ( + + + + Error + + + {errorMessage} + + + + + ); +}; + +export default ErrorModal; diff --git a/src/config/axios.js b/src/config/axios.js index 38553d5..677fa0f 100644 --- a/src/config/axios.js +++ b/src/config/axios.js @@ -1,18 +1,26 @@ import axios from 'axios'; +import Cookies from "js-cookie"; + +const token = Cookies.get(`token`) || null; +const headers = { + "Access-Control-Allow-Origin": "*", + "content-type":"application/json", +}; +if (token) headers["Authorization"] = `Bearer ${token}`; const instance = axios.create({ baseURL: 'https://api.telkomcel.tl/tpay-stg-dash-api/', - headers: { - "Access-Control-Allow-Origin": "*", - "content-type":"application/json", - }, + headers: headers }) -export async function fetchApi(path, method, data) { +export async function fetchApi(path, method, data, params) { + let query = params || {}; + query.token = token let response = await instance({ method: method, url: path, - data: data + data: data, + params: query }); return response } \ No newline at end of file diff --git a/src/index.js b/src/index.js index 0f58506..7d78253 100644 --- a/src/index.js +++ b/src/index.js @@ -4,14 +4,18 @@ import "./index.css"; import App from "./routes/routes"; import reportWebVitals from "./reportWebVitals"; import { BrowserRouter } from "react-router-dom"; +import { Provider } from 'react-redux'; +import store from './store/store'; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - - - - - + + + + + + + ); // If you want to start measuring performance in your app, pass a function diff --git a/src/pages/Login.js b/src/pages/Login.js index e9eb9af..3408aa0 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,8 +1,9 @@ import React, { useState } from "react"; -import { TextField, Button, Box, Typography, Grid, Paper } from "@mui/material"; +import { TextField, Button, Box, Typography, Grid, Paper, Avatar, Divider } from "@mui/material"; import {Link, useNavigate } from 'react-router-dom'; import Cookies from "js-cookie"; import { fetchApi } from '../config/axios'; +import logo from '../logo/logo.jpeg'; const LoginPage = () => { // State for email and password @@ -18,17 +19,24 @@ const LoginPage = () => { // GET CREDIENTIAL let user = await fetchApi('/api/login', 'POST', { username, password }); if (user.data && user.data.data) { - let userLogin = user.data.data; - Cookies.set('token', userLogin.token.access_token, { expires: 7, path: '/' }); - Cookies.set('role', userLogin.role_name); - Cookies.set('username', userLogin.user.username); - // localStorage.setItem('token', userLogin.token.access_token) + let resUserLogin = user.data.data; + console.log('resUserLogin', resUserLogin); + let roleList = JSON.stringify(resUserLogin.roles_list); + Cookies.set('token', resUserLogin.token.access_token, { expires: 1, path: '/' }); + Cookies.set('role', resUserLogin.role_name, { expires: 1, path: '/' }); + Cookies.set('userId', resUserLogin.user.id, { expires: 1, path: '/' }); + Cookies.set('username', resUserLogin.user.username, { expires: 1, path: '/' }); + // Cookies.set('roles_list', roleList, { expires: 1, path: '/' }); + localStorage.setItem('roles_list', roleList) + navigate('/'); + } else { + alert(user.response.data.message); } - navigate('/'); } else { alert("Please fill in both fields."); } } catch (error) { + alert(error.response.data.message); console.log(error); } }; @@ -84,6 +92,39 @@ const LoginPage = () => { + + {/* Divider (Horizontal Line) */} + + + {/* Content */} + + + T-PAY + + + © 2025 TelinDigital Solution + + ); }; diff --git a/src/pages/MasterData.js b/src/pages/MasterData.js new file mode 100644 index 0000000..f5f31e2 --- /dev/null +++ b/src/pages/MasterData.js @@ -0,0 +1,133 @@ +import React, { useState } from "react"; +import { Grid, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Box, Typography } from '@mui/material'; +import ReusableTable from '../components/Table'; + +const MasterDataPage = () => { + const tableData1 = [ + { id: 1, name: 'John Doe', age: 25 }, + { id: 2, name: 'Jane Smith', age: 30 }, + { id: 3, name: 'John Doe', age: 25 }, + { id: 4, name: 'Jane Smith', age: 30 }, + { id: 5, name: 'John Doe', age: 25 }, + ]; + + const tableData2 = [ + { id: 1, product: 'Laptop', price: '$1000' }, + { id: 2, product: 'Phone', price: '$600' }, + ]; + + return ( + + + Master Data + + + + {/* First Table */} + + {/* */} + + + Kecamatan + + + + + ID + Name + Age + + + + {tableData1.map((row) => ( + + {row.id} + {row.name} + {row.age} + + ))} + +
+
+
+ + {/* Second Table */} + + Kelurahan + + + + + ID + Product + Price + + + + {tableData2.map((row) => ( + + {row.id} + {row.product} + {row.price} + + ))} + +
+
+
+ {/* 3rd Table */} + + Kabupaten + + + + + ID + Name + Age + + + + {tableData1.map((row) => ( + + {row.id} + {row.name} + {row.age} + + ))} + +
+
+
+ + {/* 4th Table */} + + Kota + + + + + ID + Product + Price + + + + {tableData2.map((row) => ( + + {row.id} + {row.product} + {row.price} + + ))} + +
+
+
+
+
+
+ ); +}; + +export default MasterDataPage; \ No newline at end of file diff --git a/src/pages/Profile.js b/src/pages/Profile.js new file mode 100644 index 0000000..a924733 --- /dev/null +++ b/src/pages/Profile.js @@ -0,0 +1,362 @@ +import React, { useState, useEffect } from 'react'; +import { + TextField, + Button, + Box, + Typography, + Paper, + FormControl, + Select, + InputLabel, + MenuItem, + FormControlLabel, + Checkbox, + FormLabel +} from "@mui/material"; +import { fetchApi } from '../config/axios'; +import WarningDialog from '../components/WarningDialog'; +import Cookies from "js-cookie"; + +const ProfilePage = () => { + // State for form fields + const [formData, setFormData] = useState({ + username: '', + name: '', + email: '', + status: '', + idRole: '', + password: '', + oldPassword: '', + confirmPassword: '', + newPassword: '' + // nik: '', + // position: '', + // telp: '', + // address: '', + // organisasi: '', + // devisi: '', + // unit: '', + }); + const [roles, setRoles] = useState([]); + const [isModalOpen, setIsModalOpen] = useState(false); // ERROR MSG + const [error, setError] = useState(""); // ERROR MSG + + useEffect(() => { + fetchUser() + fetchUserRoles() + // eslint-disable-next-line + }, []); + + async function fetchUser(params) { + try { + let userId = Cookies.get(`userId`); + let token = Cookies.get(`token`); + + let fetchUsers = await fetchApi(`/api/user/detail/${userId}`, 'GET', null, { token: token }); + // setFormData({}) + console.log(fetchUsers); + setFormData(fetchUsers.data.data) + } catch (error) { + console.log(error); + handleError(`${error.message}. \n ${error.response.data.error}`) + } + } + + async function fetchUserRoles(params) { + try { + let userRoles = await fetchApi('/api/user_role/list', 'GET', null, { + limit: 10, + page: 1, + with_deleted: true, + order_field: 'id', + order_direction: 'ASC' + }); + console.log(userRoles); + + if (userRoles.data && userRoles.data.data) setRoles(userRoles.data.data.list) + } catch (error) { + console.log(error); + handleError(`${error.message}. \n ${error.response.data.error}`) + } + } + + // Handle form submission + const handleSubmit = (e) => { + e.preventDefault(); + // if (name && email) { + // // Handle registration logic, like calling an API to create the user + // console.log("Registered with:", { name, email }); + // } else { + // alert("Please fill in all fields."); + // } + }; + + const handleChange = (e) => { + let { name, value } = e.target; + if (name === 'status' && value === "Y") value = "N" + else if (name === 'status' && value === "N") value = "Y" + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const handleError = (msg) => { // ERROR MSG + setError(msg); + setIsModalOpen(true); + }; + + const closeModal = () => { // ERROR MSG + setIsModalOpen(false); + setError(""); + }; + + async function updatePassword() { + try { + let updatePassword = await fetchApi(`/api/user/update_password`, 'PUT', { + password: formData.password, + retype_password: formData.confirmPassword + }); + console.log(updatePassword); + + } catch (error) { + console.log(error); + } + } + + return ( + + + + User Profile + + + + +

+ + + + + + + + + + + Status : + + }/> + + + {/* + + + + + + + + + + + + + + Organization + + + + + + Devision + + + + + + Unit + + + */} + + + Role + + + + + + + + + + + +
+ + + + + + + User Password + + + + + + + + + + + + + + + + + + + + ); +}; + +export default ProfilePage; \ No newline at end of file diff --git a/src/pages/RoleManagement.js b/src/pages/RoleManagement.js index 7b9e49e..7d98ef4 100644 --- a/src/pages/RoleManagement.js +++ b/src/pages/RoleManagement.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { Container, Typography, @@ -20,58 +20,127 @@ import { Box } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; +import { fetchApi } from '../config/axios'; // Initial list of roles and menus -const initialRoles = ['Admin', 'Escrow', 'Agent']; -const menus = [ - 'Dashboard', - 'Users', - 'Reports', - 'Settings', - 'Notifications', - 'Profile', - 'Help', - 'Logs', - 'Analytics', - 'Billing', -]; +// const initialRoles = ['Admin', 'Escrow', 'Agent']; +// const menus = [ +// 'Dashboard', +// 'Users', +// 'Reports', +// 'Settings', +// 'Notifications', +// 'Profile', +// 'Help', +// 'Logs', +// 'Analytics', +// 'Billing', +// ]; const RoleMenuTable = () => { - const [roles, setRoles] = useState(initialRoles); - const [roleMenus, setRoleMenus] = useState( - initialRoles.reduce((acc, role) => ({ ...acc, [role]: [] }), {}) - ); + const [roles, setRoles] = useState([]); + // const [roleMenus, setRoleMenus] = useState([]); + const [menus, setMenus] = useState([]); const [openDialog, setOpenDialog] = useState(false); const [newRole, setNewRole] = useState(''); - const [confirmDialog, setConfirmDialog] = useState({ open: false, role: '', menu: '' }); + const [confirmDialog, setConfirmDialog] = useState({ + open: false, roleName: '', menuData: [], roleId: '', menuId: '', status: null, menuName: '' + }); + + useEffect(() => { + fetchData() + // eslint-disable-next-line + }, []); - const handleCheckboxChange = (role, menu) => { - setConfirmDialog({ open: true, role, menu }); - }; - - const handleConfirm = (confirm) => { - const { role, menu } = confirmDialog; - if (confirm) { - setRoleMenus((prev) => { - const isChecked = prev[role].includes(menu); - const updatedMenus = isChecked - ? prev[role].filter((m) => m !== menu) - : [...prev[role], menu]; - return { ...prev, [role]: updatedMenus }; + async function fetchData(params) { + try { + let userRole = await fetchApi('/api/user_role/list', 'GET', null, { + limit: 5, + page: 1, + with_deleted: true, + order_field: 'id', + order_direction: 'ASC' }); + let userMenu = await fetchApi('/api/menus/list', 'GET', null, { + limit: 50, + page: 1, + with_deleted: true, + order_field: 'id', + order_direction: 'ASC' + }); + setMenus(userMenu.data.data.list) + + console.log('role',userRole); + console.log('menu',userMenu); + if (userRole.data && userRole.data.data) setRoles(userRole.data.data.list) + } catch (error) { + console.log(error); } - setConfirmDialog({ open: false, role: '', menu: '' }); + } + + const handleCheckboxChange = (roleName, menuData, roleId, menuId, status, menuName) => { + setConfirmDialog({ open: true, roleName, menuData, roleId, menuId, status, menuName }); }; - const handleAddRole = () => { - if (newRole.trim() && !roles.includes(newRole)) { - setRoles((prevRoles) => [...prevRoles, newRole]); - setRoleMenus((prevMenus) => ({ ...prevMenus, [newRole]: [] })); + const handleConfirm = async (confirm) => { + const { roleName, menuData, roleId, menuId, status } = confirmDialog; + try { + if (confirm) { + console.log(confirm,confirmDialog); + if (status) { + let generateRoles = menuData.filter(el => +el !== +menuId); + console.log(generateRoles); + let userMenu = await fetchApi(`/api/user_role/update/${roleId}`, 'PUT', { + name: roleName, + roles: generateRoles, + status: "Y" + }) + console.log(userMenu); + await fetchData() + } else { + let generateRoles = menuData.filter(el => +el !== +menuId); + generateRoles.push(`${menuId}`) + console.log(generateRoles); + let userMenu = await fetchApi(`/api/user_role/update/${roleId}`, 'PUT', { + name: roleName, + roles: generateRoles, + status: "Y" + }) + console.log(userMenu); + await fetchData() + } + } + setConfirmDialog({ open: false, role: '', menu: '' }); + } catch (error) { + console.log(error); + } + }; + + const handleAddRole = async () => { + try { + await fetchApi('/api/user_role/create', 'POST', { + "name": newRole, + "roles": [], + "status": "Y" + }); + await fetchData(); + } catch (error) { + console.log(error); } setNewRole(''); setOpenDialog(false); }; + const deleteRole = async (role) => { + try { + let resDeleteRole = await fetchApi(`/api/user_role/delete/${role.id}/true`, 'DELETE'); + console.log(resDeleteRole); + await fetchData(); + } catch (error) { + console.log(error); + } + } + return ( @@ -85,9 +154,9 @@ const RoleMenuTable = () => { - - - + + + {/* Table for roles and menus */} @@ -95,26 +164,28 @@ const RoleMenuTable = () => { Role - {menus.map((menu) => ( - {menu} + {menus.map((menu, idx) => ( + {menu.name} ))} Action {roles.map((role) => ( - - {role} - {menus.map((menu) => ( - + + {role.name} + {menus.map((menu, idx) => ( + handleCheckboxChange(role, menu)} + checked={(role.roles.find(el => +el === menu.id)) ? true : false} + onChange={() => handleCheckboxChange( + role.name, role.roles, role.id, menu.id, (role.roles.find(el => +el === menu.id)) ? true : false, menu.name + )} /> ))} - + ))} @@ -150,8 +221,8 @@ const RoleMenuTable = () => { handleConfirm(false)}> Confirm Menu Selection - Are you sure you want to {roleMenus[confirmDialog.role]?.includes(confirmDialog.menu) ? 'remove' : 'add'} - the menu {confirmDialog.menu} for role {confirmDialog.role}? + Are you sure you want to {confirmDialog.status ? 'remove ' : 'add '} + the menu {confirmDialog.menuName} for role {confirmDialog.roleName}? + @@ -133,16 +216,16 @@ export default function UserManagement() { Add Roles to {selectedUser?.name} - {availableRoles.map((role) => ( + {roles.map((role) => ( handleRoleChange(role)} + checked={selectedRoles.includes(role.name)} + onChange={() => handleRoleChange(role.name)} /> } - label={role} + label={role.name} /> ))} @@ -158,9 +241,20 @@ export default function UserManagement() { setOpenDialog(false)} maxWidth="sm" fullWidth> - Create User + {labelDialog} + + + + + Status + } label="Aktif" /> + + {/* + + + + + + + + Organization + + + + + + Devision + + + + + + Unit + + + */} + + + Role + + + Submit diff --git a/src/routes/routes.js b/src/routes/routes.js index cfe80f0..3cdb5c5 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -1,13 +1,15 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { Routes, Route, useLocation, Navigate } from 'react-router-dom'; import "../pages/Dashboard.css"; import Sidebar from "../components/SideBar"; import Header from "../components/Header"; import { Box, Toolbar } from "@mui/material"; +import Cookies from "js-cookie"; // GENERAL import Dasboard from '../pages/Dashboard'; import LoginPage from '../pages/Login'; import RegisterPage from '../pages/Register'; +import ProfilePage from '../pages/Profile'; // ADMIN import ManageTransfers from '../pages/ManageTransfers'; import ManageNotifications from '../pages/ManageNotifications'; @@ -23,6 +25,7 @@ import ManageWebservice from '../pages/ManageWebservice'; import SettingPage from '../pages/Setting'; import UserManagement from '../pages/UserManagement'; import RoleMenus from '../pages/RoleManagement'; +import MasterDataPage from '../pages/MasterData'; // ESCROW import TransactionHistory from '../escrowPages/TransactionHistory'; import TransferPage from '../escrowPages/Transfer'; @@ -36,7 +39,6 @@ import TopUpRequest from '../tdsPages/TopUpRequest'; import OperationTransfer from '../tdsPages/Transfer'; import RegisteredAgent from '../tdsPages/RegisteredAgent'; import RegisteredSupervisor from '../tdsPages/RegisteredSupervisor'; -import Cookies from "js-cookie"; // Mock Authentication Function const isAuthenticated = () => { @@ -80,12 +82,23 @@ const Layout = ({ children }) => { }; function App() { + let roles_list = JSON.parse(localStorage.getItem('roles_list')); + const location = useLocation(); + + useEffect(() => { + console.log(roles_list); + console.log(location); + + }, [roles_list, location]); + return ( {/* GENERAL */} } /> } /> } /> + {/* GENERAL AFTER LOGIN */} + } /> {/* ADMIN */} } /> } /> @@ -101,6 +114,7 @@ function App() { } /> } /> } /> + } /> {/* ESCROW */} } /> } /> diff --git a/src/store/store.js b/src/store/store.js new file mode 100644 index 0000000..ac85160 --- /dev/null +++ b/src/store/store.js @@ -0,0 +1,9 @@ +import { configureStore } from '@reduxjs/toolkit'; + +export default configureStore({ + reducer: { + users: () => { + return {} + } + }, +}) \ No newline at end of file