lavoce #27
@@ -982,7 +982,7 @@ const AddBrandDevice = () => {
|
|||||||
borderTop: '1px solid #f0f0f0',
|
borderTop: '1px solid #f0f0f0',
|
||||||
marginTop: '12px'
|
marginTop: '12px'
|
||||||
}}>
|
}}>
|
||||||
{/* Cancel Button - Only show when editing existing error code */}
|
|
||||||
{editingErrorCodeKey && (
|
{editingErrorCodeKey && (
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
@@ -1010,7 +1010,7 @@ const AddBrandDevice = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Save Button - Always show on right */}
|
|
||||||
<div style={{ marginLeft: editingErrorCodeKey ? '0' : 'auto' }}>
|
<div style={{ marginLeft: editingErrorCodeKey ? '0' : 'auto' }}>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -1142,79 +1142,79 @@ const AddBrandDevice = () => {
|
|||||||
</Steps>
|
</Steps>
|
||||||
<div style={{ position: 'relative' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
{loading && (
|
{loading && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.6)',
|
||||||
|
backdropFilter: 'blur(0.8px)',
|
||||||
|
filter: 'blur(0.5px)',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
zIndex: 10,
|
||||||
|
borderRadius: '8px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Spin size="large" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
filter: loading ? 'blur(0.5px)' : 'none',
|
||||||
top: 0,
|
transition: 'filter 0.3s ease',
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
backgroundColor: 'rgba(255, 255, 255, 0.6)',
|
|
||||||
backdropFilter: 'blur(0.8px)',
|
|
||||||
filter: 'blur(0.5px)',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
zIndex: 10,
|
|
||||||
borderRadius: '8px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Spin size="large" />
|
{renderStepContent()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
filter: loading ? 'blur(0.5px)' : 'none',
|
|
||||||
transition: 'filter 0.3s ease',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{renderStepContent()}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Divider />
|
||||||
<Divider />
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
<div>
|
||||||
<div>
|
<Button onClick={handleCancel}>
|
||||||
<Button onClick={handleCancel}>
|
Cancel
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
{currentStep === 1 && (
|
|
||||||
<Button
|
|
||||||
onClick={handlePrevStep}
|
|
||||||
style={{ marginLeft: 8 }}
|
|
||||||
>
|
|
||||||
Kembali ke Brand Info
|
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
{currentStep === 1 && (
|
||||||
|
<Button
|
||||||
|
onClick={handlePrevStep}
|
||||||
|
style={{ marginLeft: 8 }}
|
||||||
|
>
|
||||||
|
Kembali ke Brand Info
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{currentStep === 0 && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={handleNextStep}
|
||||||
|
loading={confirmLoading}
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#23A55A',
|
||||||
|
borderColor: '#23A55A',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Lanjut
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{currentStep === 1 && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={handleFinish}
|
||||||
|
loading={confirmLoading}
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#23A55A',
|
||||||
|
borderColor: '#23A55A',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Selesai
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
{currentStep === 0 && (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleNextStep}
|
|
||||||
loading={confirmLoading}
|
|
||||||
style={{
|
|
||||||
backgroundColor: '#23A55A',
|
|
||||||
borderColor: '#23A55A',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Lanjut
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{currentStep === 1 && (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleFinish}
|
|
||||||
loading={confirmLoading}
|
|
||||||
style={{
|
|
||||||
backgroundColor: '#23A55A',
|
|
||||||
borderColor: '#23A55A',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Selesai
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
</Card>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -328,13 +328,13 @@ const EditBrandDevice = () => {
|
|||||||
}
|
}
|
||||||
}, [currentStep, id]);
|
}, [currentStep, id]);
|
||||||
|
|
||||||
// Auto refresh error codes when returning from add/edit error code
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (location.state?.refreshErrorCodes) {
|
if (location.state?.refreshErrorCodes) {
|
||||||
// Trigger refresh of error codes list
|
|
||||||
setTrigerFilter(prev => !prev);
|
setTrigerFilter(prev => !prev);
|
||||||
|
|
||||||
// Clear the state to prevent infinite refresh
|
|
||||||
const state = { ...location.state };
|
const state = { ...location.state };
|
||||||
delete state.refreshErrorCodes;
|
delete state.refreshErrorCodes;
|
||||||
navigate(location.pathname + location.search, {
|
navigate(location.pathname + location.search, {
|
||||||
@@ -345,7 +345,7 @@ const EditBrandDevice = () => {
|
|||||||
}, [location, navigate]);
|
}, [location, navigate]);
|
||||||
|
|
||||||
const addErrorCode = (newErrorCode) => {
|
const addErrorCode = (newErrorCode) => {
|
||||||
// Generate unique tempId with timestamp and random number
|
|
||||||
const uniqueId = `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
const uniqueId = `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
const errorCodeWithId = {
|
const errorCodeWithId = {
|
||||||
...newErrorCode,
|
...newErrorCode,
|
||||||
@@ -566,13 +566,13 @@ const EditBrandDevice = () => {
|
|||||||
message: editingErrorCodeKey ? 'Error code berhasil diupdate!' : 'Error code berhasil ditambahkan!',
|
message: editingErrorCodeKey ? 'Error code berhasil diupdate!' : 'Error code berhasil ditambahkan!',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear temp error codes after successful save to prevent duplication
|
|
||||||
setTempErrorCodes(prev => prev.filter(ec => {
|
setTempErrorCodes(prev => prev.filter(ec => {
|
||||||
// Keep existing error codes that weren't just saved
|
|
||||||
if (ec.status === 'existing' || ec.tempId.startsWith('existing_')) {
|
if (ec.status === 'existing' || ec.tempId.startsWith('existing_')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Remove the newly saved error code to prevent duplication
|
|
||||||
return ec.tempId !== editingErrorCodeKey;
|
return ec.tempId !== editingErrorCodeKey;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -1182,7 +1182,7 @@ const EditBrandDevice = () => {
|
|||||||
borderTop: '1px solid #f0f0f0',
|
borderTop: '1px solid #f0f0f0',
|
||||||
marginTop: '12px'
|
marginTop: '12px'
|
||||||
}}>
|
}}>
|
||||||
{/* Cancel Button - Only show when editing existing error code */}
|
|
||||||
{editingErrorCodeKey && (
|
{editingErrorCodeKey && (
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
@@ -1210,7 +1210,7 @@ const EditBrandDevice = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Save Button - Always show on right */}
|
|
||||||
<div style={{ marginLeft: editingErrorCodeKey ? '0' : 'auto' }}>
|
<div style={{ marginLeft: editingErrorCodeKey ? '0' : 'auto' }}>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -1266,45 +1266,45 @@ const EditBrandDevice = () => {
|
|||||||
</Steps>
|
</Steps>
|
||||||
{renderStepContent()}
|
{renderStepContent()}
|
||||||
<Divider />
|
<Divider />
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<div>
|
<div>
|
||||||
{currentStep === 1 && (
|
{currentStep === 1 && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => navigate(`/master/brand-device/edit/${id}?tab=brand`)}
|
onClick={() => navigate(`/master/brand-device/edit/${id}?tab=brand`)}
|
||||||
style={{ marginLeft: 8 }}
|
style={{ marginLeft: 8 }}
|
||||||
>
|
>
|
||||||
Back to Brand Info
|
Back to Brand Info
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{currentStep === 0 && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={handleNextStep}
|
||||||
|
loading={confirmLoading}
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#23A55A',
|
||||||
|
borderColor: '#23A55A',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Error Code
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{currentStep === 1 && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={handleCancel}
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#23A55A',
|
||||||
|
borderColor: '#23A55A',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Selesai
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
{currentStep === 0 && (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleNextStep}
|
|
||||||
loading={confirmLoading}
|
|
||||||
style={{
|
|
||||||
backgroundColor: '#23A55A',
|
|
||||||
borderColor: '#23A55A',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Error Code
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{currentStep === 1 && (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleCancel}
|
|
||||||
style={{
|
|
||||||
backgroundColor: '#23A55A',
|
|
||||||
borderColor: '#23A55A',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Selesai
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
</Card>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,10 +6,10 @@ import { ArrowLeftOutlined, FilePdfOutlined, FileImageOutlined, DownloadOutlined
|
|||||||
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
||||||
import { getBrandById } from '../../../api/master-brand';
|
import { getBrandById } from '../../../api/master-brand';
|
||||||
import {
|
import {
|
||||||
downloadFile,
|
downloadFile,
|
||||||
getFile,
|
getFile,
|
||||||
getFileUrl,
|
getFileUrl,
|
||||||
getFolderFromFileType,
|
getFolderFromFileType,
|
||||||
} from '../../../api/file-uploads';
|
} from '../../../api/file-uploads';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
@@ -412,7 +412,7 @@ const ViewFilePage = () => {
|
|||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* File type indicator */}
|
|
||||||
<div style={{ marginBottom: '16px' }}>
|
<div style={{ marginBottom: '16px' }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
@@ -429,7 +429,7 @@ const ViewFilePage = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ position: 'relative' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
{/* Overlay with blur effect during loading */}
|
|
||||||
{loading && (
|
{loading && (
|
||||||
<div style={{
|
<div style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const BrandForm = ({
|
|||||||
onValuesChange,
|
onValuesChange,
|
||||||
isEdit = false,
|
isEdit = false,
|
||||||
brandInfo = null,
|
brandInfo = null,
|
||||||
|
readOnly = false,
|
||||||
}) => {
|
}) => {
|
||||||
const isActive = Form.useWatch('is_active', form) ?? true;
|
const isActive = Form.useWatch('is_active', form) ?? true;
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ const BrandForm = ({
|
|||||||
<Form.Item name="is_active" valuePropName="checked" noStyle>
|
<Form.Item name="is_active" valuePropName="checked" noStyle>
|
||||||
<Switch
|
<Switch
|
||||||
style={{ backgroundColor: isActive ? '#23A55A' : '#bfbfbf' }}
|
style={{ backgroundColor: isActive ? '#23A55A' : '#bfbfbf' }}
|
||||||
|
disabled={readOnly}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Text style={{ marginLeft: 8 }}>
|
<Text style={{ marginLeft: 8 }}>
|
||||||
@@ -61,18 +63,18 @@ const BrandForm = ({
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
label="Brand Name"
|
label="Brand Name"
|
||||||
name="brand_name"
|
name="brand_name"
|
||||||
rules={[{ required: true, message: 'Brand Name wajib diisi!' }]}
|
rules={[{ required: !readOnly, message: 'Brand Name wajib diisi!' }]}
|
||||||
>
|
>
|
||||||
<Input />
|
<Input disabled={readOnly} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="Manufacturer"
|
label="Manufacturer"
|
||||||
name="brand_manufacture"
|
name="brand_manufacture"
|
||||||
rules={[{ required: true, message: 'Manufacturer wajib diisi!' }]}
|
rules={[{ required: !readOnly, message: 'Manufacturer wajib diisi!' }]}
|
||||||
>
|
>
|
||||||
<Input placeholder="Enter Manufacturer" />
|
<Input placeholder="Enter Manufacturer" disabled={readOnly} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -80,12 +82,12 @@ const BrandForm = ({
|
|||||||
<Row gutter={16}>
|
<Row gutter={16}>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item label="Brand Type" name="brand_type">
|
<Form.Item label="Brand Type" name="brand_type">
|
||||||
<Input placeholder="Enter Brand Type (Optional)" />
|
<Input placeholder="Enter Brand Type (Optional)" disabled={readOnly} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item label="Model" name="brand_model">
|
<Form.Item label="Model" name="brand_model">
|
||||||
<Input placeholder="Enter Model (Optional)" />
|
<Input placeholder="Enter Model (Optional)" disabled={readOnly} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ const CustomSparepartCard = ({
|
|||||||
onClick={handleCardClick}
|
onClick={handleCardClick}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', height: '100%' }}>
|
<div style={{ display: 'flex', height: '100%' }}>
|
||||||
{/* Image Section */}
|
|
||||||
<div style={{
|
<div style={{
|
||||||
width: size === 'small' ? '90px' : '110px',
|
width: size === 'small' ? '90px' : '110px',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
@@ -192,7 +192,7 @@ const CustomSparepartCard = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Selection Indicator */}
|
|
||||||
{isSelected && (
|
{isSelected && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -215,7 +215,7 @@ const CustomSparepartCard = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content Section */}
|
|
||||||
<div style={{
|
<div style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
padding: size === 'small' ? '12px' : '16px',
|
padding: size === 'small' ? '12px' : '16px',
|
||||||
@@ -242,9 +242,9 @@ const CustomSparepartCard = ({
|
|||||||
{sparepart.sparepart_name || sparepart.name || 'Unnamed'}
|
{sparepart.sparepart_name || sparepart.name || 'Unnamed'}
|
||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
{/* Stock and Quantity Information */}
|
|
||||||
<div style={{ marginBottom: size === 'small' ? '6px' : '8px' }}>
|
<div style={{ marginBottom: size === 'small' ? '6px' : '8px' }}>
|
||||||
{/* Stock Status Tag */}
|
|
||||||
<div style={{ marginBottom: '4px' }}>
|
<div style={{ marginBottom: '4px' }}>
|
||||||
<Tag
|
<Tag
|
||||||
color={sparepart.sparepart_stok === 'Available' ? 'green' : 'red'}
|
color={sparepart.sparepart_stok === 'Available' ? 'green' : 'red'}
|
||||||
@@ -259,7 +259,7 @@ const CustomSparepartCard = ({
|
|||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Quantity */}
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
@@ -330,7 +330,7 @@ const CustomSparepartCard = ({
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Preview Modal */}
|
|
||||||
<Modal
|
<Modal
|
||||||
title="Sparepart Details"
|
title="Sparepart Details"
|
||||||
open={previewModalVisible}
|
open={previewModalVisible}
|
||||||
@@ -374,7 +374,7 @@ const CustomSparepartCard = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Item Type Tag */}
|
|
||||||
{sparepart.sparepart_item_type && (
|
{sparepart.sparepart_item_type && (
|
||||||
<div style={{ marginBottom: '12px' }}>
|
<div style={{ marginBottom: '12px' }}>
|
||||||
<Tag color="blue" style={{ fontSize: '14px', padding: '4px 12px' }}>
|
<Tag color="blue" style={{ fontSize: '14px', padding: '4px 12px' }}>
|
||||||
@@ -383,7 +383,7 @@ const CustomSparepartCard = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Stock Status and Quantity */}
|
|
||||||
<div style={{
|
<div style={{
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
background: '#f8f9fa',
|
background: '#f8f9fa',
|
||||||
@@ -412,12 +412,12 @@ const CustomSparepartCard = ({
|
|||||||
|
|
||||||
<Col span={14}>
|
<Col span={14}>
|
||||||
<div>
|
<div>
|
||||||
{/* Sparepart Name */}
|
|
||||||
<Title level={3} style={{ marginBottom: '20px', color: '#262626' }}>
|
<Title level={3} style={{ marginBottom: '20px', color: '#262626' }}>
|
||||||
{sparepart.sparepart_name || 'Unnamed'}
|
{sparepart.sparepart_name || 'Unnamed'}
|
||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
{/* Basic Information */}
|
|
||||||
<div style={{ marginBottom: '24px' }}>
|
<div style={{ marginBottom: '24px' }}>
|
||||||
<Row gutter={[16, 12]}>
|
<Row gutter={[16, 12]}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
@@ -480,7 +480,7 @@ const CustomSparepartCard = ({
|
|||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Timeline Information */}
|
|
||||||
{sparepart.created_at && (
|
{sparepart.created_at && (
|
||||||
<div>
|
<div>
|
||||||
<Row gutter={16}>
|
<Row gutter={16}>
|
||||||
|
|||||||
@@ -232,15 +232,16 @@ const ErrorCodeForm = ({
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
label="Error Name"
|
label="Error Name"
|
||||||
name="error_code_name"
|
name="error_code_name"
|
||||||
rules={[{ required: true, message: 'Error name wajib diisi!' }]}
|
rules={[{ required: !isErrorCodeFormReadOnly, message: 'Error name wajib diisi!' }]}
|
||||||
>
|
>
|
||||||
<Input placeholder="Enter error name" />
|
<Input placeholder="Enter error name" disabled={isErrorCodeFormReadOnly} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="Description" name="error_code_description">
|
<Form.Item label="Description" name="error_code_description">
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
placeholder="Enter error description"
|
placeholder="Enter error description"
|
||||||
rows={3}
|
rows={3}
|
||||||
|
disabled={isErrorCodeFormReadOnly}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@@ -260,7 +261,9 @@ const ErrorCodeForm = ({
|
|||||||
height: '40px',
|
height: '40px',
|
||||||
border: '1px solid #d9d9d9',
|
border: '1px solid #d9d9d9',
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
|
cursor: isErrorCodeFormReadOnly ? 'not-allowed' : 'pointer',
|
||||||
}}
|
}}
|
||||||
|
disabled={isErrorCodeFormReadOnly}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
|||||||
@@ -394,9 +394,7 @@ const FileUploadHandler = ({
|
|||||||
</Upload>
|
</Upload>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* renderExistingFile() is disabled because SolutionField.jsx already handles file card rendering */}
|
|
||||||
{/* This prevents duplicate card rendering */}
|
|
||||||
{/* {renderExistingFile()} */}
|
|
||||||
|
|
||||||
{showPreview && (
|
{showPreview && (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ const ListBrandDevice = memo(function ListBrandDevice(props) {
|
|||||||
title: 'Konfirmasi',
|
title: 'Konfirmasi',
|
||||||
message: 'Apakah anda yakin hapus data "' + param.brand_name + '" ?',
|
message: 'Apakah anda yakin hapus data "' + param.brand_name + '" ?',
|
||||||
onConfirm: () => handleDelete(param.brand_id, param.brand_name),
|
onConfirm: () => handleDelete(param.brand_id, param.brand_name),
|
||||||
onCancel: () => {},
|
onCancel: () => { },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ const ListBrandDevice = memo(function ListBrandDevice(props) {
|
|||||||
title: 'Berhasil',
|
title: 'Berhasil',
|
||||||
message: `Brand ${brand_name} deleted successfully.`,
|
message: `Brand ${brand_name} deleted successfully.`,
|
||||||
});
|
});
|
||||||
doFilter(); // Refresh data
|
doFilter();
|
||||||
} else {
|
} else {
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ const ListErrorCode = ({
|
|||||||
searchText,
|
searchText,
|
||||||
onSearchChange,
|
onSearchChange,
|
||||||
onSearch,
|
onSearch,
|
||||||
onSearchClear
|
onSearchClear,
|
||||||
|
isReadOnly = false,
|
||||||
|
errorCodes: propErrorCodes = null
|
||||||
}) => {
|
}) => {
|
||||||
const [errorCodes, setErrorCodes] = useState([]);
|
const [errorCodes, setErrorCodes] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -25,7 +27,7 @@ const ListErrorCode = ({
|
|||||||
total_page: 0,
|
total_page: 0,
|
||||||
});
|
});
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const pageSize = 15; // Fixed limit 15 items per page
|
const pageSize = 15;
|
||||||
|
|
||||||
const queryParams = useMemo(() => {
|
const queryParams = useMemo(() => {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
@@ -79,8 +81,15 @@ const ListErrorCode = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchErrorCodes();
|
if (isReadOnly && propErrorCodes) {
|
||||||
}, [brandId, queryParams, tempErrorCodes, trigerFilter]);
|
|
||||||
|
setErrorCodes(propErrorCodes);
|
||||||
|
setLoading(false);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
fetchErrorCodes();
|
||||||
|
}
|
||||||
|
}, [brandId, queryParams, tempErrorCodes, trigerFilter, isReadOnly, propErrorCodes]);
|
||||||
|
|
||||||
const handlePrevious = () => {
|
const handlePrevious = () => {
|
||||||
if (pagination.current_page > 1) {
|
if (pagination.current_page > 1) {
|
||||||
@@ -117,7 +126,7 @@ const ListErrorCode = ({
|
|||||||
title: 'Hapus Error Code',
|
title: 'Hapus Error Code',
|
||||||
message: `Apakah Anda yakin ingin menghapus error code ${item.error_code}?`,
|
message: `Apakah Anda yakin ingin menghapus error code ${item.error_code}?`,
|
||||||
onConfirm: () => performDelete(item),
|
onConfirm: () => performDelete(item),
|
||||||
onCancel: () => {},
|
onCancel: () => { },
|
||||||
confirmButtonText: 'Hapus'
|
confirmButtonText: 'Hapus'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -125,7 +134,7 @@ const ListErrorCode = ({
|
|||||||
|
|
||||||
const performDelete = async (item) => {
|
const performDelete = async (item) => {
|
||||||
try {
|
try {
|
||||||
// Additional validation
|
|
||||||
if (!item.error_code_id || item.error_code_id === 'undefined') {
|
if (!item.error_code_id || item.error_code_id === 'undefined') {
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
@@ -144,7 +153,7 @@ const ListErrorCode = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await deleteErrorCode(item.brand_id, item.error_code_id);
|
const response = await deleteErrorCode(item.brand_id, item.error_code_id);
|
||||||
|
|
||||||
if (response && response.statusCode === 200) {
|
if (response && response.statusCode === 200) {
|
||||||
NotifOk({
|
NotifOk({
|
||||||
|
|||||||
@@ -30,18 +30,7 @@ const SolutionFieldNew = ({
|
|||||||
|
|
||||||
const fileUpload = Form.useWatch(['solution_items', fieldKey, 'fileUpload'], form);
|
const fileUpload = Form.useWatch(['solution_items', fieldKey, 'fileUpload'], form);
|
||||||
const file = Form.useWatch(['solution_items', fieldKey, 'file'], form);
|
const file = Form.useWatch(['solution_items', fieldKey, 'file'], form);
|
||||||
|
|
||||||
const getSolutionData = () => {
|
|
||||||
try {
|
|
||||||
return form.getFieldValue(['solution_items', fieldKey]) || {};
|
|
||||||
} catch (error) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const nameValue = Form.useWatch(['solution_items', fieldKey, 'name'], form);
|
const nameValue = Form.useWatch(['solution_items', fieldKey, 'name'], form);
|
||||||
const typeValue = Form.useWatch(['solution_items', fieldKey, 'type'], form);
|
|
||||||
const textValue = Form.useWatch(['solution_items', fieldKey, 'text'], form);
|
|
||||||
const fileNameValue = Form.useWatch(['solution_items', fieldKey, 'fileName'], form);
|
const fileNameValue = Form.useWatch(['solution_items', fieldKey, 'fileName'], form);
|
||||||
const statusValue = Form.useWatch(['solution_items', fieldKey, 'status'], form) ?? true;
|
const statusValue = Form.useWatch(['solution_items', fieldKey, 'status'], form) ?? true;
|
||||||
|
|
||||||
@@ -49,9 +38,7 @@ const SolutionFieldNew = ({
|
|||||||
|
|
||||||
const [deleteCounter, setDeleteCounter] = useState(0);
|
const [deleteCounter, setDeleteCounter] = useState(0);
|
||||||
|
|
||||||
// Reset internal state when form is reset to initial values
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
// Check if form is in initial/reset state (name is empty)
|
|
||||||
if (!nameValue || nameValue === '') {
|
if (!nameValue || nameValue === '') {
|
||||||
setCurrentFile(null);
|
setCurrentFile(null);
|
||||||
setIsDeleted(false);
|
setIsDeleted(false);
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ const SparepartSelect = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Fixed Search Section */}
|
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
<div style={{
|
<div style={{
|
||||||
marginBottom: 16,
|
marginBottom: 16,
|
||||||
@@ -156,7 +156,7 @@ const SparepartSelect = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Scrollable Selected Items Section */}
|
|
||||||
<div>
|
<div>
|
||||||
{selectedSpareparts.length > 0 ? (
|
{selectedSpareparts.length > 0 ? (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user