From a6e8c39ed8a5e54067e892b128b26ace3af6433a Mon Sep 17 00:00:00 2001 From: vinix Date: Fri, 10 Oct 2025 11:39:31 +0700 Subject: [PATCH] integrasi role --- src/api/role.jsx | 161 ++++++++++++++++++++++++++ src/pages/role/IndexRole.jsx | 65 ++++++++--- src/pages/role/component/ListRole.jsx | 129 +++------------------ 3 files changed, 230 insertions(+), 125 deletions(-) create mode 100644 src/api/role.jsx diff --git a/src/api/role.jsx b/src/api/role.jsx new file mode 100644 index 0000000..17ace06 --- /dev/null +++ b/src/api/role.jsx @@ -0,0 +1,161 @@ +import { SendRequest } from '../components/Global/ApiRequest'; + +const getAllRole = async (queryParams) => { + const response = await SendRequest({ + method: 'get', + prefix: `roles/roles?${queryParams.toString()}`, + }); + + console.log('Role API Response:', response); + + // Parse query params to get page and limit + const params = Object.fromEntries(queryParams); + const currentPage = parseInt(params.page) || 1; + const currentLimit = parseInt(params.limit) || 10; + + // Backend returns all data, so we need to do client-side pagination + const allData = response.data || []; + const totalData = allData.length; + + // Calculate start and end index for current page + const startIndex = (currentPage - 1) * currentLimit; + const endIndex = startIndex + currentLimit; + + // Slice data for current page + const paginatedData = allData.slice(startIndex, endIndex); + + // Transform response to match TableList expected structure + return { + status: response.statusCode || 200, + data: { + data: paginatedData, + paging: { + page: currentPage, + limit: currentLimit, + total: totalData, + page_total: Math.ceil(totalData / currentLimit), + }, + total: totalData, + }, + }; +}; + +const getRoleById = async (id) => { + const response = await SendRequest({ + method: 'get', + prefix: `roles/roles/${id}`, + }); + return response.data; +}; + +const createRole = async (queryParams) => { + const response = await SendRequest({ + method: 'post', + prefix: `roles/roles`, + params: queryParams, + }); + + console.log('Create Role API Response:', response); + + // Check for error status (not 200, 201, or success) + const isSuccess = + response.statusCode === 200 || response.statusCode === 201 || response.status === 'success'; + + if (!isSuccess && response.statusCode >= 400) { + let errorMessage = response.message || 'Gagal menambahkan role'; + + // Handle SQL unique constraint violation + if ( + errorMessage.includes('UNIQUE KEY constraint') || + errorMessage.includes('duplicate key') + ) { + errorMessage = `Role dengan nama "${queryParams.role_name}" sudah ada. Silakan gunakan nama lain.`; + } + + return { + statusCode: response.statusCode, + data: response.data, + message: errorMessage, + }; + } + + // Return full response with statusCode + return { + statusCode: response.statusCode || 200, + data: response.data, + message: response.message || 'Berhasil menambahkan role', + }; +}; + +const updateRole = async (role_id, queryParams) => { + const response = await SendRequest({ + method: 'put', + prefix: `roles/roles/${role_id}`, + params: queryParams, + }); + + console.log('Update Role API Response:', response); + + // Check for error status (not 200, 201, or success) + const isSuccess = + response.statusCode === 200 || response.statusCode === 201 || response.status === 'success'; + + if (!isSuccess && response.statusCode >= 400) { + let errorMessage = response.message || 'Gagal mengubah role'; + + // Handle SQL unique constraint violation + if ( + errorMessage.includes('UNIQUE KEY constraint') || + errorMessage.includes('duplicate key') + ) { + errorMessage = `Role dengan nama "${queryParams.role_name}" sudah ada. Silakan gunakan nama lain.`; + } + + return { + statusCode: response.statusCode, + data: response.data, + message: errorMessage, + }; + } + + // Return full response with statusCode + return { + statusCode: response.statusCode || 200, + data: response.data, + message: response.message || 'Berhasil mengubah role', + }; +}; + +const deleteRole = async (queryParams) => { + const response = await SendRequest({ + method: 'delete', + prefix: `roles/roles/${queryParams}`, + }); + + console.log('Delete API Response:', response); + + // Check for errors + if (response.statusCode !== 200) { + let errorMessage = response.message || 'Gagal menghapus role'; + + // Handle foreign key constraint + if (errorMessage.includes('REFERENCE constraint') || errorMessage.includes('foreign key')) { + errorMessage = 'Role tidak dapat dihapus karena masih digunakan oleh user.'; + } + + return { + statusCode: response.statusCode, + data: response.data, + message: errorMessage, + }; + } + + // Return full response with statusCode + return { + statusCode: response.statusCode || 200, + data: response.data, + message: response.message, + }; +}; + +export { getAllRole, getRoleById, createRole, updateRole, deleteRole }; diff --git a/src/pages/role/IndexRole.jsx b/src/pages/role/IndexRole.jsx index 218a79e..0829656 100644 --- a/src/pages/role/IndexRole.jsx +++ b/src/pages/role/IndexRole.jsx @@ -4,8 +4,8 @@ import { useBreadcrumb } from '../../layout/LayoutBreadcrumb'; import { Form, Typography } from 'antd'; import ListRole from './component/ListRole'; import DetailRole from './component/DetailRole'; - -import { NotifAlert } from '../../components/Global/ToastNotif'; +import { createRole, updateRole } from '../../api/role'; +import { NotifAlert, NotifOk } from '../../components/Global/ToastNotif'; const { Text } = Typography; @@ -65,21 +65,56 @@ const IndexRole = memo(function IndexRole() { } form.validateFields() - .then((values) => { - if (actionMode === 'edit') { - NotifAlert({ - icon: 'success', - title: 'Berhasil', - message: `Data Role "${values.role_name}" berhasil diubah.`, - }); - } else if (actionMode === 'add') { - NotifAlert({ - icon: 'success', - title: 'Berhasil', - message: `Data Role "${values.role_name}" berhasil ditambahkan.`, + .then(async (values) => { + try { + let response; + if (actionMode === 'edit') { + response = await updateRole(selectedData.role_id, values); + console.log('Update Response:', response); + + const isSuccess = response.statusCode === 200 || response.statusCode === 201; + if (isSuccess) { + NotifAlert({ + icon: 'success', + title: 'Berhasil', + message: `Data Role "${values.role_name}" berhasil diubah.`, + }); + handleCancel(); + } else { + NotifOk({ + icon: 'error', + title: 'Gagal', + message: response.message || 'Gagal mengubah data Role', + }); + } + } else if (actionMode === 'add') { + response = await createRole(values); + console.log('Create Response:', response); + + const isSuccess = response.statusCode === 200 || response.statusCode === 201; + if (isSuccess) { + NotifAlert({ + icon: 'success', + title: 'Berhasil', + message: `Data Role "${values.role_name}" berhasil ditambahkan.`, + }); + handleCancel(); + } else { + NotifOk({ + icon: 'error', + title: 'Gagal', + message: response.message || 'Gagal menambahkan data Role', + }); + } + } + } catch (error) { + console.error('Error:', error); + NotifOk({ + icon: 'error', + title: 'Error', + message: 'Terjadi kesalahan saat menyimpan data', }); } - handleCancel(); }) .catch((info) => { console.log('Validate Failed:', info); diff --git a/src/pages/role/component/ListRole.jsx b/src/pages/role/component/ListRole.jsx index 6185f70..60a6bf2 100644 --- a/src/pages/role/component/ListRole.jsx +++ b/src/pages/role/component/ListRole.jsx @@ -7,56 +7,11 @@ import { EyeOutlined, SearchOutlined, } from '@ant-design/icons'; -import { NotifAlert, NotifConfirmDialog } from '../../../components/Global/ToastNotif'; +import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif'; import { useNavigate } from 'react-router-dom'; +import { getAllRole, deleteRole } from '../../../api/role'; import TableList from '../../../components/Global/TableList'; -// Dummy data -const initialRolesData = [ - { - role_id: 1, - role_name: 'Administrator', - role_level: 1, - role_description: 'tes administrator', - }, - { - role_id: 2, - role_name: 'Operator', - role_level: 2, - role_description: 'tes operator', - }, - { - role_id: 3, - role_name: 'Engineer', - role_level: 2, - role_description: 'tes engineer', - }, - { - role_id: 4, - role_name: 'Operator', - role_level: 3, - role_description: 'tes operator', - }, - { - role_id: 5, - role_name: 'Administrator', - role_level: 1, - role_description: 'tes administrator', - }, - { - role_id: 6, - role_name: 'Guest', - role_level: 3, - role_description: 'tes guest', - }, - { - role_id: 7, - role_name: 'Engineering', - role_level: 2, - role_description: 'tes engineering', - }, -]; - const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [ { title: 'No', @@ -123,7 +78,6 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [ const ListRole = memo(function ListRole(props) { const [showFilter, setShowFilter] = useState(false); const [trigerFilter, setTrigerFilter] = useState(false); - const [rolesData, setRolesData] = useState(initialRolesData); const defaultFilter = { search: '' }; const [formDataFilter, setFormDataFilter] = useState(defaultFilter); @@ -131,53 +85,6 @@ const ListRole = memo(function ListRole(props) { const navigate = useNavigate(); - // Dummy data function to simulate API call - const getAllRole = async (params) => { - // Simulate API delay - await new Promise((resolve) => setTimeout(resolve, 300)); - - // Extract URLSearchParams - const searchParam = params.get('search') || ''; - const page = parseInt(params.get('page')) || 1; - const limit = parseInt(params.get('limit')) || 10; - - console.log('getAllRole called with:', { searchParam, page, limit }); - - // Filter by search - let filteredRoles = rolesData; - if (searchParam) { - const searchLower = searchParam.toLowerCase(); - filteredRoles = rolesData.filter( - (role) => - role.role_name.toLowerCase().includes(searchLower) || - role.role_description.toLowerCase().includes(searchLower) || - role.role_level.toString().includes(searchLower) - ); - } - - // Pagination logic - const totalData = filteredRoles.length; - const totalPages = Math.ceil(totalData / limit); - const startIndex = (page - 1) * limit; - const endIndex = startIndex + limit; - const paginatedData = filteredRoles.slice(startIndex, endIndex); - - return { - status: 200, - statusCode: 200, - data: { - data: paginatedData, - total: totalData, - paging: { - page: page, - limit: limit, - total: totalData, - page_total: totalPages, - }, - }, - }; - }; - useEffect(() => { const token = localStorage.getItem('token'); if (token) { @@ -188,7 +95,7 @@ const ListRole = memo(function ListRole(props) { } else { navigate('/signin'); } - }, [props.actionMode, rolesData]); + }, [props.actionMode]); const toggleFilter = () => { setFormDataFilter(defaultFilter); @@ -236,21 +143,23 @@ const ListRole = memo(function ListRole(props) { }; const handleDelete = async (role_id) => { - // Find role name before deleting - const roleToDelete = rolesData.find((role) => role.role_id === role_id); + const response = await deleteRole(role_id); + console.log('Delete Role Response:', response); - // Simulate delete API call - await new Promise((resolve) => setTimeout(resolve, 300)); - - // Remove from state - const updatedRoles = rolesData.filter((role) => role.role_id !== role_id); - setRolesData(updatedRoles); - - NotifAlert({ - icon: 'success', - title: 'Berhasil', - message: `Data Role "${roleToDelete?.role_name || ''}" berhasil dihapus.`, - }); + if (response.statusCode == 200) { + NotifAlert({ + icon: 'success', + title: 'Berhasil', + message: 'Data Role "' + (response.data?.role_name || '') + '" berhasil dihapus.', + }); + doFilter(); + } else { + NotifOk({ + icon: 'error', + title: 'Gagal', + message: response.message || 'Gagal Menghapus Data Role', + }); + } }; return (