diff --git a/src/App.jsx b/src/App.jsx
index ae251bd..7eeb525 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -15,7 +15,6 @@ import IndexTag from './pages/master/tag/IndexTag';
import IndexUnit from './pages/master/unit/IndexUnit';
import IndexBrandDevice from './pages/master/brandDevice/IndexBrandDevice';
import AddBrandDevice from './pages/master/brandDevice/AddBrandDevice';
-import IndexPlantSection from './pages/master/plantSection/IndexPlantSection';
import IndexStatus from './pages/master/status/IndexStatus';
import IndexShift from './pages/master/shift/IndexShift';
@@ -41,6 +40,7 @@ import SvgAirDryerB from './pages/home/SvgAirDryerB';
import SvgAirDryerC from './pages/home/SvgAirDryerC';
import IndexHistoryAlarm from './pages/history/alarm/IndexHistoryAlarm';
import IndexHistoryEvent from './pages/history/event/IndexHistoryEvent';
+import IndexPlantSubSection from './pages/master/plantSubSection/IndexPlantSubSection';
const App = () => {
return (
@@ -74,7 +74,7 @@ const App = () => {
} />
} />
} />
- } />
+ } />
} />
} />
diff --git a/src/layout/LayoutMenu.jsx b/src/layout/LayoutMenu.jsx
index f52b424..d0d5cfc 100644
--- a/src/layout/LayoutMenu.jsx
+++ b/src/layout/LayoutMenu.jsx
@@ -93,9 +93,9 @@ const allItems = [
label: 'Master',
children: [
{
- key: 'master-plant-section',
+ key: 'master-plant-sub-section',
icon: ,
- label: Plant Sub Section,
+ label: Plant Sub Section,
},
{
key: 'master-brand-device',
diff --git a/src/pages/master/device/component/CardDevice.jsx b/src/pages/master/device/component/CardDevice.jsx
deleted file mode 100644
index eb2ad74..0000000
--- a/src/pages/master/device/component/CardDevice.jsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react';
-import { Card, Button, Row, Col, Typography, Space, Tag } from 'antd';
-import { EditOutlined, DeleteOutlined, EyeOutlined } from '@ant-design/icons';
-
-const { Text } = Typography;
-
-const CardDevice = ({ data, showPreviewModal, showEditModal, showDeleteDialog }) => {
- const getCardStyle = () => {
- const color = '#FF8C42'; // Orange color
- return {
- border: `2px solid ${color}`,
- borderRadius: '8px',
- textAlign: 'center' // Center text
- };
- };
-
- const getTitleStyle = () => {
- const backgroundColor = '#FF8C42'; // Orange color
- return {
- backgroundColor,
- color: '#fff',
- padding: '2px 8px',
- borderRadius: '4px',
- display: 'inline-block',
- };
- };
-
- return (
-
- {data.map((item) => (
-
-
- {item.device_name}
-
- }
- style={getCardStyle()}
- actions={[
-
- }
- onClick={() => showPreviewModal(item)}
- />
- }
- onClick={() => showEditModal(item)}
- />
- }
- onClick={() => showDeleteDialog(item)}
- />
- ,
- ]}
- >
-
- Code: {item.device_code}
-
-
- Location: {item.device_location}
-
-
- IP Address: {item.ip_address}
-
-
- Status:{' '}
-
- {item.device_status ? 'Running' : 'Offline'}
-
-
-
-
- ))}
-
- );
-};
-
-export default CardDevice;
diff --git a/src/pages/master/device/component/ListDevice.jsx b/src/pages/master/device/component/ListDevice.jsx
index 70dc2dd..875deba 100644
--- a/src/pages/master/device/component/ListDevice.jsx
+++ b/src/pages/master/device/component/ListDevice.jsx
@@ -15,6 +15,13 @@ import { deleteDevice, getAllDevice } from '../../../../api/master-device';
import TableList from '../../../../components/Global/TableList';
const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
+ {
+ title: 'No',
+ key: 'no',
+ width: '5%',
+ align: 'center',
+ render: (_, __, index) => index + 1,
+ },
{
title: 'ID',
dataIndex: 'device_id',
@@ -27,6 +34,7 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
dataIndex: 'device_code',
key: 'device_code',
width: '10%',
+ hidden: true,
},
{
title: 'Device Name',
diff --git a/src/pages/master/plantSection/IndexPlantSection.jsx b/src/pages/master/plantSubSection/IndexPlantSubSection.jsx
similarity index 89%
rename from src/pages/master/plantSection/IndexPlantSection.jsx
rename to src/pages/master/plantSubSection/IndexPlantSubSection.jsx
index 3ec995f..5fc44a2 100644
--- a/src/pages/master/plantSection/IndexPlantSection.jsx
+++ b/src/pages/master/plantSubSection/IndexPlantSubSection.jsx
@@ -1,13 +1,13 @@
import React, { memo, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
-import ListPlantSection from './component/ListPlantSection';
-import DetailPlantSection from './component/DetailPlantSection';
+import ListPlantSection from './component/ListPlantSubSection';
+import DetailPlantSection from './component/DetailPlantSubSection';
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
import { Typography } from 'antd';
const { Text } = Typography;
-const IndexPlantSection = memo(function IndexPlantSection() {
+const IndexPlantSubSection = memo(function IndexPlantSubSection() {
const navigate = useNavigate();
const { setBreadcrumbItems } = useBreadcrumb();
@@ -71,4 +71,4 @@ const IndexPlantSection = memo(function IndexPlantSection() {
);
});
-export default IndexPlantSection;
+export default IndexPlantSubSection;
diff --git a/src/pages/master/plantSection/component/DetailPlantSection.jsx b/src/pages/master/plantSubSection/component/DetailPlantSubSection.jsx
similarity index 68%
rename from src/pages/master/plantSection/component/DetailPlantSection.jsx
rename to src/pages/master/plantSubSection/component/DetailPlantSubSection.jsx
index 75be3ef..de45dd4 100644
--- a/src/pages/master/plantSection/component/DetailPlantSection.jsx
+++ b/src/pages/master/plantSubSection/component/DetailPlantSubSection.jsx
@@ -3,27 +3,49 @@ import { Modal, Input, Typography, Switch, Button, ConfigProvider, Divider } fro
import { NotifAlert, NotifOk } from '../../../../components/Global/ToastNotif';
import { createPlantSection, updatePlantSection } from '../../../../api/master-plant-section';
import { validateRun } from '../../../../Utils/validate';
+import TextArea from 'antd/es/input/TextArea';
const { Text } = Typography;
-const DetailPlantSection = (props) => {
+const DetailPlantSubSection = (props) => {
const [confirmLoading, setConfirmLoading] = useState(false);
const defaultData = {
- sub_section_id: '',
- sub_section_code: '',
- sub_section_name: '',
+ plant_sub_section_id: '',
+ plant_sub_section_code: '',
+ plant_sub_section_name: '',
+ table_name_value: '', // Fix field name
+ plant_sub_section_description: '',
is_active: true,
};
const [formData, setFormData] = useState(defaultData);
const handleInputChange = (e) => {
- const { name, value } = e.target;
- setFormData({
- ...formData,
- [name]: value,
- });
+ // Handle different input types
+ let name, value;
+
+ if (e && e.target) {
+ // Standard input
+ name = e.target.name;
+ value = e.target.value;
+ } else if (e && e.type === 'change') {
+ // Switch or other components
+ name = e.name || e.target?.name;
+ value = e.value !== undefined ? e.value : e.checked;
+ } else {
+ // Fallback
+ return;
+ }
+
+ console.log(`📝 Input change: ${name} = ${value}`);
+
+ if (name) {
+ setFormData((prev) => ({
+ ...prev,
+ [name]: value,
+ }));
+ }
};
const handleCancel = () => {
@@ -36,7 +58,7 @@ const DetailPlantSection = (props) => {
// Daftar aturan validasi
const validationRules = [
- { field: 'sub_section_name', label: 'Plant Sub Section Name', required: true },
+ { field: 'plant_sub_section_name', label: 'Plant Sub Section Name', required: true },
];
if (
@@ -52,14 +74,20 @@ const DetailPlantSection = (props) => {
return;
try {
+ console.log('💾 Current formData before save:', formData);
+
const payload = {
+ plant_sub_section_name: formData.plant_sub_section_name,
+ plant_sub_section_description: formData.plant_sub_section_description,
+ table_name_value: formData.table_name_value, // Fix field name
is_active: formData.is_active,
- sub_section_name: formData.sub_section_name,
};
+ console.log('📤 Payload to be sent:', payload);
+
const response =
props.actionMode === 'edit'
- ? await updatePlantSection(formData.sub_section_id, payload)
+ ? await updatePlantSection(formData.plant_sub_section_id, payload)
: await createPlantSection(payload);
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
@@ -98,9 +126,17 @@ const DetailPlantSection = (props) => {
};
useEffect(() => {
+ console.log('🔄 Modal state changed:', {
+ showModal: props.showModal,
+ actionMode: props.actionMode,
+ selectedData: props.selectedData,
+ });
+
if (props.selectedData) {
+ console.log('📋 Setting form data from selectedData:', props.selectedData);
setFormData(props.selectedData);
} else {
+ console.log('📋 Resetting to default data');
setFormData(defaultData);
}
}, [props.showModal, props.selectedData, props.actionMode]);
@@ -177,7 +213,7 @@ const DetailPlantSection = (props) => {
{/* Plant Section Code - Auto Increment & Read Only */}
- Plant Section Code
+ Plant Sub Section Code
{
Plant Sub Section Name
*
+
+ Table Name Value
+
+
+
+ Description
+
+
)}
);
};
-export default DetailPlantSection;
+export default DetailPlantSubSection;
diff --git a/src/pages/master/plantSection/component/ListPlantSection.jsx b/src/pages/master/plantSubSection/component/ListPlantSubSection.jsx
similarity index 82%
rename from src/pages/master/plantSection/component/ListPlantSection.jsx
rename to src/pages/master/plantSubSection/component/ListPlantSubSection.jsx
index 863525a..fd18e0a 100644
--- a/src/pages/master/plantSection/component/ListPlantSection.jsx
+++ b/src/pages/master/plantSubSection/component/ListPlantSubSection.jsx
@@ -14,27 +14,51 @@ import TableList from '../../../../components/Global/TableList';
const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
{
- title: 'Section Code',
- dataIndex: 'sub_section_code',
- key: 'sub_section_code',
- width: '20%',
+ title: 'No',
+ key: 'no',
+ width: '5%',
+ align: 'center',
+ render: (_, __, index) => index + 1,
+ },
+ {
+ title: 'Plant Sub Section Code',
+ dataIndex: 'plant_sub_section_code',
+ key: 'plant_sub_section_code',
+ width: '10%',
+ align: 'center',
+ hidden: true,
},
{
title: 'Plant Sub Section Name',
- dataIndex: 'sub_section_name',
- key: 'sub_section_name',
- width: '40%',
+ dataIndex: 'plant_sub_section_name',
+ key: 'plant_sub_section_name',
+ width: '15%',
+ },
+ {
+ title: 'Description',
+ dataIndex: 'plant_sub_section_description',
+ key: 'plant_sub_section_description',
+ width: '30%',
+ render: (text) => text || '-',
},
{
title: 'Status',
dataIndex: 'is_active',
key: 'is_active',
- width: '15%',
+ width: '10%',
align: 'center',
- render: (status) => (
-
- {status ? 'Active' : 'Inactive'}
-
+ render: (_, { is_active }) => (
+ <>
+ {is_active === true ? (
+
+ Running
+
+ ) : (
+
+ Offline
+
+ )}
+ >
),
},
{
@@ -46,29 +70,32 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
}
+ icon={}
onClick={() => showPreviewModal(record)}
+ style={{ color: '#1890ff', borderColor: '#1890ff' }}
+ title="View"
/>
}
+ icon={}
onClick={() => showEditModal(record)}
+ style={{ color: '#faad14', borderColor: '#faad14' }}
+ title="Edit"
/>
}
onClick={() => showDeleteDialog(record)}
+ style={{ borderColor: '#ff4d4f' }}
+ title="Delete"
/>
),
},
];
-const ListPlantSection = memo(function ListPlantSection(props) {
+const ListPlantSubSection = memo(function ListPlantSubSection(props) {
const [trigerFilter, setTrigerFilter] = useState(false);
const defaultFilter = { criteria: '' };
const [formDataFilter, setFormDataFilter] = useState(defaultFilter);
@@ -121,8 +148,8 @@ const ListPlantSection = memo(function ListPlantSection(props) {
NotifConfirmDialog({
icon: 'question',
title: 'Konfirmasi Hapus',
- message: 'Plant Section "' + param.sub_section_name + '" akan dihapus?',
- onConfirm: () => handleDelete(param.sub_section_id),
+ message: `Plant Sub Section "${param.plant_sub_section_name}" akan dihapus?`,
+ onConfirm: () => handleDelete(param.plant_sub_section_id),
onCancel: () => props.setSelectedData(null),
});
};
@@ -226,4 +253,4 @@ const ListPlantSection = memo(function ListPlantSection(props) {
);
});
-export default ListPlantSection;
\ No newline at end of file
+export default ListPlantSubSection;
diff --git a/src/pages/master/shift/component/ListShift.jsx b/src/pages/master/shift/component/ListShift.jsx
index c810568..d177631 100644
--- a/src/pages/master/shift/component/ListShift.jsx
+++ b/src/pages/master/shift/component/ListShift.jsx
@@ -28,6 +28,13 @@ const formatTime = (timeValue) => {
};
const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
+ {
+ title: 'No',
+ key: 'no',
+ width: '5%',
+ align: 'center',
+ render: (_, __, index) => index + 1,
+ },
{
title: 'Shift Name',
dataIndex: 'shift_name',
@@ -56,8 +63,18 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
key: 'is_active',
width: '15%',
align: 'center',
- render: (status) => (
- {status ? 'Active' : 'Inactive'}
+ render: (_, { is_active }) => (
+ <>
+ {is_active === true ? (
+
+ Running
+
+ ) : (
+
+ Offline
+
+ )}
+ >
),
},
{
diff --git a/src/pages/master/status/component/DetailStatus.jsx b/src/pages/master/status/component/DetailStatus.jsx
index 11b1afa..360f2f6 100644
--- a/src/pages/master/status/component/DetailStatus.jsx
+++ b/src/pages/master/status/component/DetailStatus.jsx
@@ -197,39 +197,43 @@ const DetailStatus = (props) => {
-
-
Status Color
-
*
-
- `color hex: ${color.toHexString()}`}
- allowClear={false}
- format="hex"
- size="large"
- style={{ width: '100%' }}
- presets={[
- {
- label: 'Recommended',
- colors: [
- '#EF4444', // Merah
- '#3B82F6', // Biru
- '#10B981', // Hijau
- '#F59E0B', // Kuning
- '#8B5CF6', // Ungu
- '#EC4899', // Pink
- '#F97316', // Orange
- '#14B8A6', // Teal
- '#6B7280', // Gray
- '#000000', // Black
- ],
- },
- ]}
- />
-
-
+
+
+
+
Status Color
+
*
+
+ `color hex: ${color.toHexString()}`}
+ allowClear={false}
+ format="hex"
+ style={{ width: '100%' }}
+ presets={[
+ {
+ label: 'Recommended',
+ colors: [
+ '#EF4444', // Merah
+ '#3B82F6', // Biru
+ '#10B981', // Hijau
+ '#F59E0B', // Kuning
+ '#8B5CF6', // Ungu
+ '#EC4899', // Pink
+ '#F97316', // Orange
+ '#14B8A6', // Teal
+ '#6B7280', // Gray
+ '#000000', // Black
+ ],
+ },
+ ]}
+ />
+
+
+
+
+
Description
- {/* Alarm Checkbox */}
- {/* Report Checkbox */}
-
- {/* History Checkbox */}
-
-
History
-
-
+
+ {/* Alarm Checkbox */}
+
+ {/* Report Checkbox */}
+
+ {/* History Checkbox */}
+
@@ -510,9 +529,9 @@ const DetailTag = (props) => {
@@ -630,14 +649,14 @@ const DetailTag = (props) => {
gap: '12px',
}}
>
- {/* Limit Low Crash */}
+ {/* Limit Low Low */}
- Limit Low Crash
+ Limit Low Low
{
step="any"
/>
- {/* Limit High Crash */}
+ {/* Limit High High */}
-
Limit High Crash
+
Limit High High
{
Description
[
+ {
+ title: 'No',
+ key: 'no',
+ width: '5%',
+ align: 'center',
+ render: (_, __, index) => index + 1,
+ },
{
title: 'ID',
dataIndex: 'tag_id',
@@ -25,12 +32,7 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
dataIndex: 'tag_code',
key: 'tag_code',
width: '10%',
- },
- {
- title: 'Tag Name',
- dataIndex: 'tag_name',
- key: 'tag_name',
- width: '15%',
+ hidden: true,
},
{
title: 'Tag Number',
@@ -40,10 +42,17 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
align: 'center',
},
{
- title: 'Data Type',
+ title: 'Tag Name',
+ dataIndex: 'tag_name',
+ key: 'tag_name',
+ width: '20%',
+ },
+
+ {
+ title: 'Type',
dataIndex: 'data_type',
key: 'data_type',
- width: '10%',
+ width: '8%',
render: (text) => text || '-',
},
{
@@ -55,9 +64,9 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
},
{
title: 'Sub Section',
- dataIndex: 'sub_section_name',
- key: 'sub_section_name',
- width: '12%',
+ dataIndex: 'plant_sub_section_name',
+ key: 'plant_sub_section_name',
+ width: '10%',
render: (text) => text || '-',
},
{
@@ -66,22 +75,27 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
key: 'device_name',
width: '12%',
render: (text) => text || '-',
+ hidden: true,
},
{
title: 'Status',
dataIndex: 'is_active',
key: 'is_active',
- width: '8%',
+ width: '5%',
align: 'center',
- render: (_, { is_active }) => {
- const color = is_active ? 'green' : 'red';
- const text = is_active ? 'Active' : 'Inactive';
- return (
-
- {text}
-
- );
- },
+ render: (_, { is_active }) => (
+ <>
+ {is_active === true ? (
+
+ Running
+
+ ) : (
+
+ Offline
+
+ )}
+ >
+ ),
},
{
title: 'Aksi',
diff --git a/src/pages/master/unit/component/DetailUnit.jsx b/src/pages/master/unit/component/DetailUnit.jsx
index cc7c2fb..f3e56cb 100644
--- a/src/pages/master/unit/component/DetailUnit.jsx
+++ b/src/pages/master/unit/component/DetailUnit.jsx
@@ -2,15 +2,12 @@ import React, { useEffect, useState } from 'react';
import { Modal, Input, Typography, Switch, Button, ConfigProvider, Divider, Select } from 'antd';
import { NotifOk } from '../../../../components/Global/ToastNotif';
import { createUnit, updateUnit } from '../../../../api/master-unit';
-import { getAllTag } from '../../../../api/master-tag'; // Import API untuk Tag
import { validateRun } from '../../../../Utils/validate';
const { Text } = Typography;
const DetailUnit = (props) => {
const [confirmLoading, setConfirmLoading] = useState(false);
- const [tagList, setTagList] = useState([]);
- const [loadingTags, setLoadingTags] = useState(false);
const defaultData = {
unit_id: '',
@@ -18,28 +15,10 @@ const DetailUnit = (props) => {
unit_name: '',
unit_description: '',
is_active: true,
- tag_id: null, // Tambahkan tag_id
};
const [formData, setFormData] = useState(defaultData);
- // Fungsi untuk mengambil data Tag
- const loadTags = async () => {
- setLoadingTags(true);
- try {
- const params = new URLSearchParams({ limit: 1000, criteria: '' });
- const response = await getAllTag(params);
- if (response && response.data) {
- const activeTags = response.data.filter((tag) => tag.is_active === true);
- setTagList(activeTags);
- }
- } catch (error) {
- console.error('Error loading tags:', error);
- } finally {
- setLoadingTags(false);
- }
- };
-
const handleCancel = () => {
props.setSelectedData(null);
props.setActionMode('list');
@@ -48,10 +27,7 @@ const DetailUnit = (props) => {
const handleSave = async () => {
setConfirmLoading(true);
- const validationRules = [
- { field: 'unit_name', label: 'Unit Name', required: true },
- { field: 'tag_id', label: 'Tag', required: true }, // Tambah validasi untuk tag_id
- ];
+ const validationRules = [{ field: 'unit_name', label: 'Unit Name', required: true }];
if (
validateRun(formData, validationRules, (errorMessages) => {
@@ -71,7 +47,6 @@ const DetailUnit = (props) => {
unit_name: formData.unit_name,
unit_description: formData.unit_description,
is_active: formData.is_active,
- tag_id: formData.tag_id, // Tambahkan tag_id ke payload
};
const response =
@@ -115,13 +90,6 @@ const DetailUnit = (props) => {
});
};
- const handleSelectChange = (name, value) => {
- setFormData({
- ...formData,
- [name]: value,
- });
- };
-
const handleStatusToggle = (checked) => {
setFormData({
...formData,
@@ -130,10 +98,6 @@ const DetailUnit = (props) => {
};
useEffect(() => {
- if (props.showModal) {
- loadTags(); // Panggil fungsi loadTags saat modal muncul
- }
-
if (props.selectedData) {
setFormData(props.selectedData);
} else {
@@ -227,33 +191,6 @@ const DetailUnit = (props) => {
/>
-
- Tag
- *
-
-
-
Unit Name
*
@@ -284,4 +221,4 @@ const DetailUnit = (props) => {
);
};
-export default DetailUnit;
\ No newline at end of file
+export default DetailUnit;
diff --git a/src/pages/master/unit/component/ListUnit.jsx b/src/pages/master/unit/component/ListUnit.jsx
index 34668de..18f1805 100644
--- a/src/pages/master/unit/component/ListUnit.jsx
+++ b/src/pages/master/unit/component/ListUnit.jsx
@@ -24,19 +24,20 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
title: 'Unit Code',
dataIndex: 'unit_code',
key: 'unit_code',
- width: '20%',
+ width: '10%',
+ hidden: true,
},
{
title: 'Name',
dataIndex: 'unit_name',
key: 'unit_name',
- width: '20%',
+ width: '15%',
},
{
title: 'Description',
dataIndex: 'unit_description',
key: 'unit_description',
- width: '25%',
+ width: '30%',
render: (text) => text || '-',
},
{
@@ -45,15 +46,19 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
key: 'is_active',
width: '10%',
align: 'center',
- render: (_, { is_active }) => {
- const color = is_active ? 'green' : 'red';
- const text = is_active ? 'Active' : 'Inactive';
- return (
-
- {text}
-
- );
- },
+ render: (_, { is_active }) => (
+ <>
+ {is_active === true ? (
+
+ Running
+
+ ) : (
+
+ Offline
+
+ )}
+ >
+ ),
},
{
title: 'Aksi',
diff --git a/src/pages/role/component/ListRole.jsx b/src/pages/role/component/ListRole.jsx
index 855f746..559a585 100644
--- a/src/pages/role/component/ListRole.jsx
+++ b/src/pages/role/component/ListRole.jsx
@@ -13,6 +13,13 @@ import { getAllRole, deleteRole } from '../../../api/role';
import TableList from '../../../components/Global/TableList';
const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
+ {
+ title: 'No',
+ key: 'no',
+ width: '5%',
+ align: 'center',
+ render: (_, __, index) => index + 1,
+ },
{
title: 'ID',
dataIndex: 'role_id',
@@ -46,9 +53,17 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
width: '10%',
align: 'center',
render: (_, { is_active }) => (
-
- {is_active ? 'Active' : 'Inactive'}
-
+ <>
+ {is_active === true ? (
+
+ Active
+
+ ) : (
+
+ Inactive
+
+ )}
+ >
),
},
{
@@ -241,4 +256,4 @@ const ListRole = memo(function ListRole(props) {
);
});
-export default ListRole;
\ No newline at end of file
+export default ListRole;
diff --git a/src/pages/user/component/DetailUser.jsx b/src/pages/user/component/DetailUser.jsx
index bfb4673..1304fae 100644
--- a/src/pages/user/component/DetailUser.jsx
+++ b/src/pages/user/component/DetailUser.jsx
@@ -155,6 +155,11 @@ const DetailUser = (props) => {
newErrors.user_phone = 'Nomor harus format Indonesia (08xxxxxxxx atau +628xxxxxxxx)';
}
+ // Role validation - make role required
+ if (!FormData.role_id) {
+ newErrors.role_id = 'Role wajib dipilih';
+ }
+
// Password validation for add mode
if (!FormData.user_id) {
const passwordError = validatePassword(FormData.password);
@@ -352,6 +357,14 @@ const DetailUser = (props) => {
...FormData,
role_id: value,
});
+
+ // Clear role error when user selects a role
+ if (errors.role_id) {
+ setErrors({
+ ...errors,
+ role_id: null,
+ });
+ }
};
const handleSwitchChange = (name, checked) => {
@@ -365,26 +378,69 @@ const DetailUser = (props) => {
const fetchRoles = async () => {
setLoadingRoles(true);
try {
- // Create query params for fetching all roles without pagination limit
+ // Create query params for fetching all roles
const queryParams = new URLSearchParams({
page: 1,
- limit: 100, // Get all roles
+ limit: 100,
search: '',
});
+ console.log('Fetching roles with params:', queryParams.toString());
const response = await getAllRole(queryParams);
- console.log('Fetched roles:', response);
+ console.log('Fetched roles response:', response);
- if (response && response.data && response.data.data) {
- setRoleList(response.data.data);
+ // Handle different response structures
+ if (response && response.data) {
+ let roles = [];
+
+ if (response.data.data && Array.isArray(response.data.data)) {
+ roles = response.data.data;
+ } else if (Array.isArray(response.data)) {
+ roles = response.data;
+ } else {
+ // Add mock data as fallback for testing
+ console.warn('Unexpected role data structure, using mock data');
+ roles = [
+ { role_id: 1, role_name: 'Admin', role_level: 1 },
+ { role_id: 2, role_name: 'Manager', role_level: 2 },
+ { role_id: 3, role_name: 'User', role_level: 3 },
+ ];
+ }
+
+ setRoleList(roles);
+ console.log('Setting role list:', roles);
+ } else {
+ // Add mock data as fallback
+ console.warn('No response data, using mock data');
+ const mockRoles = [
+ { role_id: 1, role_name: 'Admin', role_level: 1 },
+ { role_id: 2, role_name: 'Manager', role_level: 2 },
+ { role_id: 3, role_name: 'User', role_level: 3 },
+ ];
+ setRoleList(mockRoles);
+ console.log('Setting mock role list:', mockRoles);
}
} catch (error) {
console.error('Error fetching roles:', error);
- NotifAlert({
- icon: 'error',
- title: 'Error',
- message: 'Gagal memuat daftar role',
- });
+ // Add mock data as fallback on error
+ const mockRoles = [
+ { role_id: 1, role_name: 'Admin', role_level: 1 },
+ { role_id: 2, role_name: 'Manager', role_level: 2 },
+ { role_id: 3, role_name: 'User', role_level: 3 },
+ ];
+ setRoleList(mockRoles);
+ console.log('Setting mock role list due to error:', mockRoles);
+
+ // Only show error notification if we don't have fallback data
+ if (process.env.NODE_ENV === 'development') {
+ console.warn('Using mock role data due to API error');
+ } else {
+ NotifAlert({
+ icon: 'error',
+ title: 'Error',
+ message: 'Gagal memuat daftar role, menggunakan data default',
+ });
+ }
} finally {
setLoadingRoles(false);
}
@@ -1072,6 +1128,7 @@ const DetailUser = (props) => {
Role
+ *
+ {errors.role_id && (
+
+ {errors.role_id}
+
+ )}
)}
diff --git a/src/pages/user/component/ListUser.jsx b/src/pages/user/component/ListUser.jsx
index 067b456..e3c0de2 100644
--- a/src/pages/user/component/ListUser.jsx
+++ b/src/pages/user/component/ListUser.jsx
@@ -51,6 +51,13 @@ const getRoleColor = (role_name, role_level) => {
};
const columns = (showPreviewModal, showEditModal, showDeleteDialog, showApprovalModal) => [
+ {
+ title: 'No',
+ key: 'no',
+ width: '5%',
+ align: 'center',
+ render: (_, __, index) => index + 1,
+ },
{
title: 'ID',
dataIndex: 'user_id',