lavoce #3
@@ -12,7 +12,7 @@ import {
|
||||
} from 'antd';
|
||||
import { NotifAlert, NotifOk } from '../../../../components/Global/ToastNotif';
|
||||
import { createApd, getJenisPermit, updateApd } from '../../../../api/master-apd';
|
||||
import { createDevice, updateDevice } from '../../../../api/master-device';
|
||||
import { createDevice, updateDevice, getAllDevice } from '../../../../api/master-device';
|
||||
import { Checkbox } from 'antd';
|
||||
const CheckboxGroup = Checkbox.Group;
|
||||
|
||||
@@ -33,6 +33,7 @@ const DetailDevice = (props) => {
|
||||
};
|
||||
|
||||
const [FormData, setFormData] = useState(defaultData);
|
||||
const [nextDeviceCode, setNextDeviceCode] = useState('Auto-fill');
|
||||
|
||||
const [jenisPermit, setJenisPermit] = useState([]);
|
||||
const [checkedList, setCheckedList] = useState([]);
|
||||
@@ -215,12 +216,55 @@ const DetailDevice = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
const generateNextDeviceCode = async () => {
|
||||
try {
|
||||
const params = new URLSearchParams({ limit: 10000 });
|
||||
const response = await getAllDevice(params);
|
||||
|
||||
if (response && response.data && response.data.data) {
|
||||
const devices = response.data.data;
|
||||
|
||||
if (devices.length === 0) {
|
||||
setNextDeviceCode('DVC001');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract numeric part from device codes and find the maximum
|
||||
const deviceNumbers = devices
|
||||
.map((device) => {
|
||||
const match = device.device_code?.match(/dvc(\d+)/i);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
})
|
||||
.filter((num) => !isNaN(num));
|
||||
|
||||
const maxNumber = deviceNumbers.length > 0 ? Math.max(...deviceNumbers) : 0;
|
||||
const nextNumber = maxNumber + 1;
|
||||
|
||||
// Format with leading zeros (DVC001, DVC002, etc.)
|
||||
const nextCode = `DVC${String(nextNumber).padStart(3, '0')}`;
|
||||
setNextDeviceCode(nextCode);
|
||||
} else {
|
||||
setNextDeviceCode('DVC001');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error generating next device code:', error);
|
||||
setNextDeviceCode('Auto-fill');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
// Only call getDataJenisPermit if permitDefault is enabled
|
||||
if (props.permitDefault) {
|
||||
getDataJenisPermit();
|
||||
if (props.showModal) {
|
||||
// Only call getDataJenisPermit if permitDefault is enabled
|
||||
if (props.permitDefault) {
|
||||
getDataJenisPermit();
|
||||
}
|
||||
|
||||
// Generate next device code only for add mode
|
||||
if (props.actionMode === 'add' && !props.selectedData) {
|
||||
generateNextDeviceCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (props.selectedData != null) {
|
||||
@@ -234,7 +278,7 @@ const DetailDevice = (props) => {
|
||||
} else {
|
||||
// navigate('/signin'); // Uncomment if useNavigate is imported
|
||||
}
|
||||
}, [props.showModal]);
|
||||
}, [props.showModal, props.actionMode]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -332,17 +376,21 @@ const DetailDevice = (props) => {
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
{/* <div style={{ marginBottom: 12 }}>
|
||||
{/* Device Code - Auto Increment & Read Only */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Device Code</Text>
|
||||
<Text style={{ color: 'red' }}> *</Text>
|
||||
<Input
|
||||
name="device_code"
|
||||
value={FormData.device_code}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter Device Code"
|
||||
readOnly={props.readOnly}
|
||||
value={FormData.device_code || nextDeviceCode}
|
||||
placeholder={nextDeviceCode}
|
||||
disabled
|
||||
style={{
|
||||
backgroundColor: '#f5f5f5',
|
||||
cursor: 'not-allowed',
|
||||
color: FormData.device_code ? '#000000' : '#bfbfbf'
|
||||
}}
|
||||
/>
|
||||
</div> */}
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Device Name</Text>
|
||||
<Text style={{ color: 'red' }}> *</Text>
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
Divider,
|
||||
} from 'antd';
|
||||
import { NotifAlert, NotifOk } from '../../../../components/Global/ToastNotif';
|
||||
import { createPlantSection, updatePlantSection } from '../../../../api/master-plant-section';
|
||||
import { createPlantSection, updatePlantSection, getAllPlantSection } from '../../../../api/master-plant-section';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
@@ -24,6 +24,7 @@ const DetailPlantSection = (props) => {
|
||||
};
|
||||
|
||||
const [FormData, setFormData] = useState(defaultData);
|
||||
const [nextPlantSectionCode, setNextPlantSectionCode] = useState('Auto-fill');
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
@@ -103,14 +104,56 @@ const DetailPlantSection = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
const generateNextPlantSectionCode = async () => {
|
||||
try {
|
||||
const params = new URLSearchParams({ limit: 10000 });
|
||||
const response = await getAllPlantSection(params);
|
||||
|
||||
if (response && response.data && response.data.data) {
|
||||
const sections = response.data.data;
|
||||
|
||||
if (sections.length === 0) {
|
||||
setNextPlantSectionCode('SUB001');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract numeric part from plant section codes and find the maximum
|
||||
const sectionNumbers = sections
|
||||
.map((section) => {
|
||||
const match = section.sub_section_code?.match(/sub(\d+)/i);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
})
|
||||
.filter((num) => !isNaN(num));
|
||||
|
||||
const maxNumber = sectionNumbers.length > 0 ? Math.max(...sectionNumbers) : 0;
|
||||
const nextNumber = maxNumber + 1;
|
||||
|
||||
// Format with leading zeros (SUB001, SUB002, etc.)
|
||||
const nextCode = `SUB${String(nextNumber).padStart(3, '0')}`;
|
||||
setNextPlantSectionCode(nextCode);
|
||||
} else {
|
||||
setNextPlantSectionCode('SUB001');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error generating next plant section code:', error);
|
||||
setNextPlantSectionCode('Auto-fill');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (props.showModal) {
|
||||
// Generate next plant section code only for add mode
|
||||
if (props.actionMode === 'add' && !props.selectedData) {
|
||||
generateNextPlantSectionCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (props.selectedData) {
|
||||
setFormData(props.selectedData);
|
||||
} else {
|
||||
setFormData(defaultData);
|
||||
}
|
||||
}, [props.showModal, props.selectedData]);
|
||||
}, [props.showModal, props.selectedData, props.actionMode]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -184,16 +227,21 @@ const DetailPlantSection = (props) => {
|
||||
</div>
|
||||
<Divider style={{ margin: '12px 0' }} />
|
||||
|
||||
{props.actionMode !== 'add' && (
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Plant Section Code</Text>
|
||||
<Input
|
||||
name="sub_section_code"
|
||||
value={FormData.sub_section_code}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Plant Section Code - Auto Increment & Read Only */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Plant Section Code</Text>
|
||||
<Input
|
||||
name="sub_section_code"
|
||||
value={FormData.sub_section_code || nextPlantSectionCode}
|
||||
placeholder={nextPlantSectionCode}
|
||||
disabled
|
||||
style={{
|
||||
backgroundColor: '#f5f5f5',
|
||||
cursor: 'not-allowed',
|
||||
color: FormData.sub_section_code ? '#000000' : '#bfbfbf'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Plant Sub Section Name</Text>
|
||||
|
||||
@@ -26,12 +26,19 @@ const DetailTag = (props) => {
|
||||
unit: '',
|
||||
is_active: true,
|
||||
is_alarm: false,
|
||||
is_report: false,
|
||||
is_history: false,
|
||||
lim_low_crash: '',
|
||||
lim_low: '',
|
||||
lim_high: '',
|
||||
lim_high_crash: '',
|
||||
device_id: null,
|
||||
|
||||
sub_section_id: null,
|
||||
};
|
||||
|
||||
const [FormData, setFormData] = useState(defaultData);
|
||||
const [nextTagCode, setNextTagCode] = useState('Auto-fill');
|
||||
|
||||
const handleCancel = () => {
|
||||
props.setSelectedData(null);
|
||||
@@ -120,13 +127,13 @@ const DetailTag = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validasi data type harus Diskrit atau Analog
|
||||
const validDataTypes = ['Diskrit', 'Analog'];
|
||||
// Validasi data type harus Discrete atau Analog
|
||||
const validDataTypes = ['Discrete', 'Analog'];
|
||||
if (!validDataTypes.includes(FormData.data_type)) {
|
||||
NotifOk({
|
||||
icon: 'warning',
|
||||
title: 'Peringatan',
|
||||
message: `Data Type harus "Diskrit" atau "Analog". Nilai "${FormData.data_type}" tidak valid. Silakan pilih dari dropdown.`,
|
||||
message: `Data Type harus "Discrete" atau "Analog". Nilai "${FormData.data_type}" tidak valid. Silakan pilih dari dropdown.`,
|
||||
});
|
||||
setConfirmLoading(false);
|
||||
return;
|
||||
@@ -153,6 +160,17 @@ const DetailTag = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Plant Sub Section validation
|
||||
if (!FormData.sub_section_id) {
|
||||
NotifOk({
|
||||
icon: 'warning',
|
||||
title: 'Peringatan',
|
||||
message: 'Plant Sub Section harus dipilih',
|
||||
});
|
||||
setConfirmLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare payload berdasarkan backend validation schema
|
||||
const payload = {
|
||||
tag_name: FormData.tag_name.trim(),
|
||||
@@ -161,9 +179,25 @@ const DetailTag = (props) => {
|
||||
unit: FormData.unit.trim(),
|
||||
is_active: FormData.is_active,
|
||||
is_alarm: FormData.is_alarm,
|
||||
is_report: FormData.is_report,
|
||||
is_history: FormData.is_history,
|
||||
device_id: parseInt(FormData.device_id),
|
||||
};
|
||||
|
||||
// Add limit fields only if they have values
|
||||
if (FormData.lim_low_crash !== '' && FormData.lim_low_crash !== null) {
|
||||
payload.lim_low_crash = parseFloat(FormData.lim_low_crash);
|
||||
}
|
||||
if (FormData.lim_low !== '' && FormData.lim_low !== null) {
|
||||
payload.lim_low = parseFloat(FormData.lim_low);
|
||||
}
|
||||
if (FormData.lim_high !== '' && FormData.lim_high !== null) {
|
||||
payload.lim_high = parseFloat(FormData.lim_high);
|
||||
}
|
||||
if (FormData.lim_high_crash !== '' && FormData.lim_high_crash !== null) {
|
||||
payload.lim_high_crash = parseFloat(FormData.lim_high_crash);
|
||||
}
|
||||
|
||||
// Add sub_section_id only if it's selected
|
||||
if (FormData.sub_section_id) {
|
||||
payload.sub_section_id = parseInt(FormData.sub_section_id);
|
||||
@@ -184,14 +218,17 @@ const DetailTag = (props) => {
|
||||
|
||||
// Check if response is successful
|
||||
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
|
||||
// response.data is already an object (converted in master-tag.jsx API)
|
||||
const tagCode = response.data?.tag_code || '';
|
||||
const tagName = response.data?.tag_name || FormData.tag_name || '';
|
||||
const tagDisplay = tagCode ? `${tagCode} - ${tagName}` : tagName;
|
||||
|
||||
NotifOk({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
message:
|
||||
response.message ||
|
||||
`Data Tag "${response.data?.tag_name || FormData.tag_name}" berhasil ${
|
||||
FormData.tag_id ? 'diubah' : 'ditambahkan'
|
||||
}.`,
|
||||
message: `Data Tag "${tagDisplay}" berhasil ${
|
||||
FormData.tag_id ? 'diubah' : 'ditambahkan'
|
||||
}.`,
|
||||
});
|
||||
|
||||
props.setActionMode('list');
|
||||
@@ -252,6 +289,20 @@ const DetailTag = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleReportToggle = (isChecked) => {
|
||||
setFormData({
|
||||
...FormData,
|
||||
is_report: isChecked,
|
||||
});
|
||||
};
|
||||
|
||||
const handleHistoryToggle = (isChecked) => {
|
||||
setFormData({
|
||||
...FormData,
|
||||
is_history: isChecked,
|
||||
});
|
||||
};
|
||||
|
||||
const loadDevices = async () => {
|
||||
setLoadingDevices(true);
|
||||
try {
|
||||
@@ -314,6 +365,42 @@ const DetailTag = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const generateNextTagCode = async () => {
|
||||
try {
|
||||
const params = new URLSearchParams({ limit: 10000 });
|
||||
const response = await getAllTag(params);
|
||||
|
||||
if (response && response.data && response.data.data) {
|
||||
const tags = response.data.data;
|
||||
|
||||
if (tags.length === 0) {
|
||||
setNextTagCode('TAG001');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract numeric part from tag codes and find the maximum
|
||||
const tagNumbers = tags
|
||||
.map((tag) => {
|
||||
const match = tag.tag_code?.match(/tag(\d+)/i);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
})
|
||||
.filter((num) => !isNaN(num));
|
||||
|
||||
const maxNumber = tagNumbers.length > 0 ? Math.max(...tagNumbers) : 0;
|
||||
const nextNumber = maxNumber + 1;
|
||||
|
||||
// Format with leading zeros (TAG001, TAG002, etc.)
|
||||
const nextCode = `TAG${String(nextNumber).padStart(3, '0')}`;
|
||||
setNextTagCode(nextCode);
|
||||
} else {
|
||||
setNextTagCode('TAG001');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error generating next tag code:', error);
|
||||
setNextTagCode('Auto-fill');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
@@ -322,6 +409,11 @@ const DetailTag = (props) => {
|
||||
loadDevices();
|
||||
loadPlantSubSections();
|
||||
loadUnits();
|
||||
|
||||
// Generate next tag code only for add mode
|
||||
if (props.actionMode === 'add' && !props.selectedData) {
|
||||
generateNextTagCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (props.selectedData != null) {
|
||||
@@ -335,6 +427,12 @@ const DetailTag = (props) => {
|
||||
unit: props.selectedData.unit || '',
|
||||
is_active: props.selectedData.is_active ?? true,
|
||||
is_alarm: props.selectedData.is_alarm ?? false,
|
||||
is_report: props.selectedData.is_report ?? false,
|
||||
is_history: props.selectedData.is_history ?? false,
|
||||
lim_low_crash: props.selectedData.lim_low_crash ?? '',
|
||||
lim_low: props.selectedData.lim_low ?? '',
|
||||
lim_high: props.selectedData.lim_high ?? '',
|
||||
lim_high_crash: props.selectedData.lim_high_crash ?? '',
|
||||
device_id: props.selectedData.device_id || null,
|
||||
device_code: props.selectedData.device_code || '',
|
||||
device_name: props.selectedData.device_name || '',
|
||||
@@ -347,7 +445,7 @@ const DetailTag = (props) => {
|
||||
} else {
|
||||
// navigate('/signin'); // Uncomment if useNavigate is imported
|
||||
}
|
||||
}, [props.showModal]);
|
||||
}, [props.showModal, props.actionMode]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -360,6 +458,7 @@ const DetailTag = (props) => {
|
||||
} Tag`}
|
||||
open={props.showModal}
|
||||
onCancel={handleCancel}
|
||||
width={800}
|
||||
footer={[
|
||||
<>
|
||||
<ConfigProvider
|
||||
@@ -413,19 +512,6 @@ const DetailTag = (props) => {
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
{/* Tag Code hanya ditampilkan saat EDIT atau PREVIEW */}
|
||||
{(props.actionMode === 'edit' || props.actionMode === 'preview') && (
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Tag Code</Text>
|
||||
<Input
|
||||
name="tag_code"
|
||||
value={FormData.tag_code}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Auto Generate"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Status dan Alarm dalam satu baris */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<div
|
||||
@@ -500,6 +586,94 @@ const DetailTag = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Report dan History dalam satu baris */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
gap: '16px',
|
||||
}}
|
||||
>
|
||||
{/* Report Toggle */}
|
||||
<div style={{ flex: 1 }}>
|
||||
<div>
|
||||
<Text strong>Report</Text>
|
||||
<Text style={{ color: 'red' }}> *</Text>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginTop: '8px',
|
||||
}}
|
||||
>
|
||||
<div style={{ marginRight: '8px' }}>
|
||||
<Switch
|
||||
disabled={props.readOnly}
|
||||
style={{
|
||||
backgroundColor:
|
||||
FormData.is_report === true
|
||||
? '#23A55A'
|
||||
: '#bfbfbf',
|
||||
}}
|
||||
checked={FormData.is_report === true}
|
||||
onChange={handleReportToggle}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Text>{FormData.is_report === true ? 'Yes' : 'No'}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* History Toggle */}
|
||||
<div style={{ flex: 1 }}>
|
||||
<div>
|
||||
<Text strong>History</Text>
|
||||
<Text style={{ color: 'red' }}> *</Text>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginTop: '8px',
|
||||
}}
|
||||
>
|
||||
<div style={{ marginRight: '8px' }}>
|
||||
<Switch
|
||||
disabled={props.readOnly}
|
||||
style={{
|
||||
backgroundColor:
|
||||
FormData.is_history === true
|
||||
? '#23A55A'
|
||||
: '#bfbfbf',
|
||||
}}
|
||||
checked={FormData.is_history === true}
|
||||
onChange={handleHistoryToggle}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Text>{FormData.is_history === true ? 'Yes' : 'No'}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Tag Code - Auto Increment & Read Only */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Tag Code</Text>
|
||||
<Input
|
||||
name="tag_code"
|
||||
value={FormData.tag_code || nextTagCode}
|
||||
placeholder={nextTagCode}
|
||||
disabled
|
||||
style={{
|
||||
backgroundColor: '#f5f5f5',
|
||||
cursor: 'not-allowed',
|
||||
color: FormData.tag_code ? '#000000' : '#bfbfbf',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Tag Number</Text>
|
||||
<Text style={{ color: 'red' }}> *</Text>
|
||||
@@ -532,7 +706,7 @@ const DetailTag = (props) => {
|
||||
onChange={(value) => handleSelectChange('data_type', value)}
|
||||
disabled={props.readOnly}
|
||||
>
|
||||
<Select.Option value="Diskrit">Diskrit</Select.Option>
|
||||
<Select.Option value="Discrete">Discrete</Select.Option>
|
||||
<Select.Option value="Analog">Analog</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
@@ -562,8 +736,58 @@ const DetailTag = (props) => {
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
{/* Limit Fields */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Limit Low Crash</Text>
|
||||
<Input
|
||||
name="lim_low_crash"
|
||||
value={FormData.lim_low_crash}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter Limit Low Crash"
|
||||
readOnly={props.readOnly}
|
||||
type="number"
|
||||
step="any"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Limit Low</Text>
|
||||
<Input
|
||||
name="lim_low"
|
||||
value={FormData.lim_low}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter Limit Low"
|
||||
readOnly={props.readOnly}
|
||||
type="number"
|
||||
step="any"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Limit High</Text>
|
||||
<Input
|
||||
name="lim_high"
|
||||
value={FormData.lim_high}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter Limit High"
|
||||
readOnly={props.readOnly}
|
||||
type="number"
|
||||
step="any"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Limit High Crash</Text>
|
||||
<Input
|
||||
name="lim_high_crash"
|
||||
value={FormData.lim_high_crash}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter Limit High Crash"
|
||||
readOnly={props.readOnly}
|
||||
type="number"
|
||||
step="any"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Plant Sub Section</Text>
|
||||
<Text style={{ color: 'red' }}> *</Text>
|
||||
<Select
|
||||
style={{ width: '100%' }}
|
||||
placeholder="Select Plant Sub Section"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Modal, Input, Typography, Button, ConfigProvider, Switch } from 'antd';
|
||||
import { NotifAlert, NotifOk } from '../../../../components/Global/ToastNotif';
|
||||
import { createUnit, updateUnit } from '../../../../api/master-unit';
|
||||
import { createUnit, updateUnit, getAllUnit } from '../../../../api/master-unit';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
@@ -16,6 +16,7 @@ const DetailUnit = (props) => {
|
||||
};
|
||||
|
||||
const [FormData, setFormData] = useState(defaultData);
|
||||
const [nextUnitCode, setNextUnitCode] = useState('Auto-fill');
|
||||
|
||||
const handleCancel = () => {
|
||||
props.setSelectedData(null);
|
||||
@@ -117,9 +118,52 @@ const DetailUnit = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
const generateNextUnitCode = async () => {
|
||||
try {
|
||||
const params = new URLSearchParams({ limit: 10000 });
|
||||
const response = await getAllUnit(params);
|
||||
|
||||
if (response && response.data && response.data.data) {
|
||||
const units = response.data.data;
|
||||
|
||||
if (units.length === 0) {
|
||||
setNextUnitCode('UNT001');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract numeric part from unit codes and find the maximum
|
||||
const unitNumbers = units
|
||||
.map((unit) => {
|
||||
const match = unit.unit_code?.match(/unt(\d+)/i);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
})
|
||||
.filter((num) => !isNaN(num));
|
||||
|
||||
const maxNumber = unitNumbers.length > 0 ? Math.max(...unitNumbers) : 0;
|
||||
const nextNumber = maxNumber + 1;
|
||||
|
||||
// Format with leading zeros (UNT001, UNT002, etc.)
|
||||
const nextCode = `UNT${String(nextNumber).padStart(3, '0')}`;
|
||||
setNextUnitCode(nextCode);
|
||||
} else {
|
||||
setNextUnitCode('UNT001');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error generating next unit code:', error);
|
||||
setNextUnitCode('Auto-fill');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
if (props.showModal) {
|
||||
// Generate next unit code only for add mode
|
||||
if (props.actionMode === 'add' && !props.selectedData) {
|
||||
generateNextUnitCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (props.selectedData != null) {
|
||||
// Only set fields that are in defaultData
|
||||
const filteredData = {
|
||||
@@ -133,7 +177,7 @@ const DetailUnit = (props) => {
|
||||
setFormData(defaultData);
|
||||
}
|
||||
}
|
||||
}, [props.showModal]);
|
||||
}, [props.showModal, props.actionMode]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -222,17 +266,21 @@ const DetailUnit = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Unit Code - Display only for edit/preview */}
|
||||
{FormData.unit_code && (
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Unit Code</Text>
|
||||
<Input
|
||||
name="unit_code"
|
||||
value={FormData.unit_code}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* Unit Code - Auto Increment & Read Only */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Unit Code</Text>
|
||||
<Input
|
||||
name="unit_code"
|
||||
value={FormData.unit_code || nextUnitCode}
|
||||
placeholder={nextUnitCode}
|
||||
disabled
|
||||
style={{
|
||||
backgroundColor: '#f5f5f5',
|
||||
cursor: 'not-allowed',
|
||||
color: FormData.unit_code ? '#000000' : '#bfbfbf'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Text strong>Name</Text>
|
||||
<Text style={{ color: 'red' }}> *</Text>
|
||||
|
||||
Reference in New Issue
Block a user