diff --git a/src/pages/role/IndexRole.jsx b/src/pages/role/IndexRole.jsx
index 91d9735..218a79e 100644
--- a/src/pages/role/IndexRole.jsx
+++ b/src/pages/role/IndexRole.jsx
@@ -1,29 +1,108 @@
-import React, { memo, useEffect } from 'react';
+import React, { memo, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useBreadcrumb } from '../../layout/LayoutBreadcrumb';
-import { Typography } from 'antd';
+import { Form, Typography } from 'antd';
+import ListRole from './component/ListRole';
+import DetailRole from './component/DetailRole';
+
+import { NotifAlert } from '../../components/Global/ToastNotif';
const { Text } = Typography;
const IndexRole = memo(function IndexRole() {
const navigate = useNavigate();
const { setBreadcrumbItems } = useBreadcrumb();
+ const [form] = Form.useForm();
+
+ const [actionMode, setActionMode] = useState('list');
+ const [selectedData, setSelectedData] = useState(null);
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [readOnly, setReadOnly] = useState(false);
useEffect(() => {
const token = localStorage.getItem('token');
if (token) {
setBreadcrumbItems([
- { title: • Role }
+ {
+ title: (
+
+ • Role
+
+ ),
+ },
]);
} else {
navigate('/signin');
}
- }, []);
+ }, [navigate, setBreadcrumbItems]);
+
+ useEffect(() => {
+ if (actionMode === 'add' || actionMode === 'edit' || actionMode === 'preview') {
+ setIsModalVisible(true);
+ setReadOnly(actionMode === 'preview');
+
+ if (actionMode === 'add') {
+ form.resetFields();
+ } else if (selectedData) {
+ form.setFieldsValue(selectedData);
+ }
+ } else {
+ setIsModalVisible(false);
+ form.resetFields();
+ }
+ }, [actionMode, selectedData, form]);
+
+ const handleCancel = () => {
+ setActionMode('list');
+ setSelectedData(null);
+ form.resetFields();
+ };
+
+ const handleOk = () => {
+ if (readOnly) {
+ handleCancel();
+ return;
+ }
+
+ 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.`,
+ });
+ }
+ handleCancel();
+ })
+ .catch((info) => {
+ console.log('Validate Failed:', info);
+ });
+ };
return (
-
-
Role Page
-
+
+
+
+
);
});
diff --git a/src/pages/role/component/DetailRole.jsx b/src/pages/role/component/DetailRole.jsx
new file mode 100644
index 0000000..4195c2e
--- /dev/null
+++ b/src/pages/role/component/DetailRole.jsx
@@ -0,0 +1,95 @@
+import React, { memo } from 'react';
+import { Modal, Form, Input, Select, Row, Col } from 'antd';
+
+const { TextArea } = Input;
+const { Option } = Select;
+
+const DetailRole = memo(function DetailRole({ visible, onCancel, onOk, form, editingKey, readOnly }) {
+ const getModalTitle = () => {
+ if (readOnly) return 'Detail Role';
+ if (editingKey) return 'Edit Role';
+ return 'Tambah Role';
+ };
+
+ return (
+
+
+
+ );
+});
+
+export default DetailRole;
diff --git a/src/pages/role/component/ListRole.jsx b/src/pages/role/component/ListRole.jsx
new file mode 100644
index 0000000..6185f70
--- /dev/null
+++ b/src/pages/role/component/ListRole.jsx
@@ -0,0 +1,336 @@
+import React, { memo, useState, useEffect } from 'react';
+import { Space, ConfigProvider, Button, Row, Col, Card, Input } from 'antd';
+import {
+ PlusOutlined,
+ EditOutlined,
+ DeleteOutlined,
+ EyeOutlined,
+ SearchOutlined,
+} from '@ant-design/icons';
+import { NotifAlert, NotifConfirmDialog } from '../../../components/Global/ToastNotif';
+import { useNavigate } from 'react-router-dom';
+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',
+ key: 'no',
+ width: '5%',
+ align: 'center',
+ render: (_, __, index) => index + 1,
+ },
+ {
+ title: 'Nama Role',
+ dataIndex: 'role_name',
+ key: 'role_name',
+ width: '20%',
+ },
+ {
+ title: 'Level',
+ dataIndex: 'role_level',
+ key: 'role_level',
+ width: '10%',
+ align: 'center',
+ },
+ {
+ title: 'Deskripsi',
+ dataIndex: 'role_description',
+ key: 'role_description',
+ width: '40%',
+ },
+ {
+ title: 'Aksi',
+ key: 'aksi',
+ align: 'center',
+ width: '15%',
+ render: (_, record) => (
+
+ }
+ onClick={() => showPreviewModal(record)}
+ style={{
+ color: '#1890ff',
+ borderColor: '#1890ff',
+ }}
+ />
+ }
+ onClick={() => showEditModal(record)}
+ style={{
+ color: '#faad14',
+ borderColor: '#faad14',
+ }}
+ />
+ }
+ onClick={() => showDeleteDialog(record)}
+ style={{
+ borderColor: '#ff4d4f',
+ }}
+ />
+
+ ),
+ },
+];
+
+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);
+ const [searchValue, setSearchValue] = useState('');
+
+ 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) {
+ if (props.actionMode == 'list') {
+ setFormDataFilter(defaultFilter);
+ doFilter();
+ }
+ } else {
+ navigate('/signin');
+ }
+ }, [props.actionMode, rolesData]);
+
+ const toggleFilter = () => {
+ setFormDataFilter(defaultFilter);
+ setShowFilter((prev) => !prev);
+ };
+
+ const doFilter = () => {
+ setTrigerFilter((prev) => !prev);
+ };
+
+ const handleSearch = () => {
+ setFormDataFilter({ search: searchValue });
+ setTrigerFilter((prev) => !prev);
+ };
+
+ const handleSearchClear = () => {
+ setSearchValue('');
+ setFormDataFilter({ search: '' });
+ setTrigerFilter((prev) => !prev);
+ };
+
+ const showPreviewModal = (param) => {
+ props.setSelectedData(param);
+ props.setActionMode('preview');
+ };
+
+ const showEditModal = (param = null) => {
+ props.setSelectedData(param);
+ props.setActionMode('edit');
+ };
+
+ const showAddModal = (param = null) => {
+ props.setSelectedData(param);
+ props.setActionMode('add');
+ };
+
+ const showDeleteDialog = (param) => {
+ NotifConfirmDialog({
+ icon: 'question',
+ title: 'Konfirmasi',
+ message: 'Apakah anda yakin hapus data "' + param.role_name + '" ?',
+ onConfirm: () => handleDelete(param.role_id),
+ onCancel: () => props.setSelectedData(null),
+ });
+ };
+
+ const handleDelete = async (role_id) => {
+ // Find role name before deleting
+ const roleToDelete = rolesData.find((role) => role.role_id === role_id);
+
+ // 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.`,
+ });
+ };
+
+ return (
+
+
+
+
+
+
+ {
+ const value = e.target.value;
+ setSearchValue(value);
+ // Auto search when clearing by backspace/delete
+ if (value === '') {
+ setFormDataFilter({ search: '' });
+ setTrigerFilter((prev) => !prev);
+ }
+ }}
+ onSearch={handleSearch}
+ allowClear={{
+ clearIcon: ✕,
+ }}
+ enterButton={
+ }
+ style={{
+ backgroundColor: '#23A55A',
+ borderColor: '#23A55A',
+ }}
+ >
+ Search
+
+ }
+ size="large"
+ />
+
+
+
+
+ }
+ onClick={() => showAddModal()}
+ size="large"
+ >
+ Tambah Data
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+});
+
+export default ListRole;