Merge pull request 'lavoce' (#20) from lavoce into main
Reviewed-on: #20
This commit is contained in:
9
src/api/notification.jsx
Normal file
9
src/api/notification.jsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { SendRequest } from '../components/Global/ApiRequest';
|
||||||
|
|
||||||
|
export const getAllNotification = async () => {
|
||||||
|
const response = await SendRequest({
|
||||||
|
method: 'get',
|
||||||
|
prefix: 'notification',
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useParams, useLocation } from 'react-router-dom';
|
import { useNavigate, useParams, useLocation } from 'react-router-dom';
|
||||||
import { Divider, Typography, Button, Steps, Form, Row, Col, Card, Spin, Modal, ConfigProvider } from 'antd';
|
import {
|
||||||
|
Divider,
|
||||||
|
Typography,
|
||||||
|
Button,
|
||||||
|
Steps,
|
||||||
|
Form,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Card,
|
||||||
|
Spin,
|
||||||
|
Modal,
|
||||||
|
ConfigProvider,
|
||||||
|
} from 'antd';
|
||||||
import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif';
|
import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif';
|
||||||
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
||||||
import { getBrandById, updateBrand } from '../../../api/master-brand';
|
import { getBrandById, updateBrand } from '../../../api/master-brand';
|
||||||
@@ -48,12 +60,10 @@ const EditBrandDevice = () => {
|
|||||||
const [solutionForm] = Form.useForm();
|
const [solutionForm] = Form.useForm();
|
||||||
const [sparepartForm] = Form.useForm();
|
const [sparepartForm] = Form.useForm();
|
||||||
|
|
||||||
const {
|
const { errorCodeFields, addErrorCode, removeErrorCode, editErrorCode } = useErrorCodeLogic(
|
||||||
errorCodeFields,
|
errorCodeForm,
|
||||||
addErrorCode,
|
fileList
|
||||||
removeErrorCode,
|
);
|
||||||
editErrorCode,
|
|
||||||
} = useErrorCodeLogic(errorCodeForm, fileList);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
solutionFields,
|
solutionFields,
|
||||||
@@ -83,14 +93,14 @@ const EditBrandDevice = () => {
|
|||||||
|
|
||||||
// Handlers for sparepart image upload
|
// Handlers for sparepart image upload
|
||||||
const handleSparepartImageUpload = (fieldKey, imageData) => {
|
const handleSparepartImageUpload = (fieldKey, imageData) => {
|
||||||
setSparepartImages(prev => ({
|
setSparepartImages((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[fieldKey]: imageData
|
[fieldKey]: imageData,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSparepartImageRemove = (fieldKey) => {
|
const handleSparepartImageRemove = (fieldKey) => {
|
||||||
setSparepartImages(prev => {
|
setSparepartImages((prev) => {
|
||||||
const newImages = { ...prev };
|
const newImages = { ...prev };
|
||||||
delete newImages[fieldKey];
|
delete newImages[fieldKey];
|
||||||
return newImages;
|
return newImages;
|
||||||
@@ -159,17 +169,19 @@ const EditBrandDevice = () => {
|
|||||||
path_icon: ec.path_icon || '',
|
path_icon: ec.path_icon || '',
|
||||||
status: ec.is_active,
|
status: ec.is_active,
|
||||||
solution: ec.solution || [],
|
solution: ec.solution || [],
|
||||||
errorCodeIcon: ec.path_icon ? {
|
errorCodeIcon: ec.path_icon
|
||||||
name: 'icon',
|
? {
|
||||||
uploadPath: ec.path_icon,
|
name: 'icon',
|
||||||
url: (() => {
|
uploadPath: ec.path_icon,
|
||||||
const pathParts = ec.path_icon.split('/');
|
url: (() => {
|
||||||
const folder = pathParts[0];
|
const pathParts = ec.path_icon.split('/');
|
||||||
const filename = pathParts.slice(1).join('/');
|
const folder = pathParts[0];
|
||||||
return getFileUrl(folder, filename);
|
const filename = pathParts.slice(1).join('/');
|
||||||
})(),
|
return getFileUrl(folder, filename);
|
||||||
type_solution: 'image'
|
})(),
|
||||||
} : null,
|
type_solution: 'image',
|
||||||
|
}
|
||||||
|
: null,
|
||||||
}))
|
}))
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
@@ -332,7 +344,7 @@ const EditBrandDevice = () => {
|
|||||||
|
|
||||||
// Load sparepart images
|
// Load sparepart images
|
||||||
const newSparepartImages = {};
|
const newSparepartImages = {};
|
||||||
record.sparepart.forEach(sparepart => {
|
record.sparepart.forEach((sparepart) => {
|
||||||
if (sparepart.sparepart_image) {
|
if (sparepart.sparepart_image) {
|
||||||
newSparepartImages[sparepart.id || sparepart.key] = sparepart.sparepart_image;
|
newSparepartImages[sparepart.id || sparepart.key] = sparepart.sparepart_image;
|
||||||
}
|
}
|
||||||
@@ -367,7 +379,7 @@ const EditBrandDevice = () => {
|
|||||||
|
|
||||||
// Load sparepart images
|
// Load sparepart images
|
||||||
const newSparepartImages = {};
|
const newSparepartImages = {};
|
||||||
record.sparepart.forEach(sparepart => {
|
record.sparepart.forEach((sparepart) => {
|
||||||
if (sparepart.sparepart_image) {
|
if (sparepart.sparepart_image) {
|
||||||
newSparepartImages[sparepart.id || sparepart.key] = sparepart.sparepart_image;
|
newSparepartImages[sparepart.id || sparepart.key] = sparepart.sparepart_image;
|
||||||
}
|
}
|
||||||
@@ -381,34 +393,81 @@ const EditBrandDevice = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddErrorCode = (newErrorCode) => {
|
const handleAddErrorCode = async () => {
|
||||||
// Include the current icon in the error code
|
try {
|
||||||
const errorCodeWithIcon = {
|
// Validate error code form
|
||||||
...newErrorCode,
|
const errorCodeValues = await errorCodeForm.validateFields();
|
||||||
errorCodeIcon: errorCodeIcon
|
|
||||||
};
|
|
||||||
|
|
||||||
let updatedErrorCodes;
|
// Get solution data from solution form
|
||||||
if (editingErrorCodeKey) {
|
const solutionData = getSolutionData();
|
||||||
updatedErrorCodes = errorCodes.map((item) =>
|
|
||||||
item.key === editingErrorCodeKey ? errorCodeWithIcon : item
|
// Get sparepart data from sparepart form
|
||||||
);
|
const sparepartData = getSparepartData();
|
||||||
NotifOk({
|
|
||||||
icon: 'success',
|
if (solutionData.length === 0) {
|
||||||
title: 'Berhasil',
|
NotifAlert({
|
||||||
message: 'Error code berhasil diupdate!',
|
icon: 'warning',
|
||||||
});
|
title: 'Perhatian',
|
||||||
} else {
|
message: 'Setiap error code harus memiliki minimal 1 solution!',
|
||||||
updatedErrorCodes = [...errorCodes, errorCodeWithIcon];
|
});
|
||||||
NotifOk({
|
return;
|
||||||
icon: 'success',
|
}
|
||||||
title: 'Berhasil',
|
|
||||||
message: 'Error code berhasil ditambahkan!',
|
// Create complete error code object
|
||||||
|
const newErrorCode = {
|
||||||
|
error_code: errorCodeValues.error_code,
|
||||||
|
error_code_name: errorCodeValues.error_code_name,
|
||||||
|
error_code_description: errorCodeValues.error_code_description,
|
||||||
|
error_code_color: errorCodeValues.error_code_color || '#000000',
|
||||||
|
path_icon: errorCodeIcon?.uploadPath || '',
|
||||||
|
status: errorCodeValues.status === undefined ? true : errorCodeValues.status,
|
||||||
|
solution: solutionData,
|
||||||
|
sparepart: sparepartData,
|
||||||
|
errorCodeIcon: errorCodeIcon,
|
||||||
|
key: editingErrorCodeKey || `temp-${Date.now()}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
let updatedErrorCodes;
|
||||||
|
if (editingErrorCodeKey) {
|
||||||
|
// Update existing error code
|
||||||
|
updatedErrorCodes = errorCodes.map((item) => {
|
||||||
|
if (item.key === editingErrorCodeKey) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
...newErrorCode,
|
||||||
|
error_code_id: item.error_code_id || newErrorCode.error_code_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
NotifOk({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Berhasil',
|
||||||
|
message: 'Error code berhasil diupdate!',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Add new error code
|
||||||
|
updatedErrorCodes = [...errorCodes, newErrorCode];
|
||||||
|
NotifOk({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Berhasil',
|
||||||
|
message: 'Error code berhasil ditambahkan!',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrorCodes(updatedErrorCodes);
|
||||||
|
|
||||||
|
// Delay form reset to prevent data loss
|
||||||
|
setTimeout(() => {
|
||||||
|
resetErrorCodeForm();
|
||||||
|
}, 100);
|
||||||
|
} catch (error) {
|
||||||
|
NotifAlert({
|
||||||
|
icon: 'warning',
|
||||||
|
title: 'Perhatian',
|
||||||
|
message: 'Harap isi semua kolom wajib (error code + minimal 1 solution)!',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setErrorCodes(updatedErrorCodes);
|
|
||||||
resetErrorCodeForm();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetErrorCodeForm = () => {
|
const resetErrorCodeForm = () => {
|
||||||
@@ -552,7 +611,11 @@ const EditBrandDevice = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Card
|
<Card
|
||||||
title={<Title level={5} style={{ margin: 0 }}>Solutions</Title>}
|
title={
|
||||||
|
<Title level={5} style={{ margin: 0 }}>
|
||||||
|
Solutions
|
||||||
|
</Title>
|
||||||
|
}
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
@@ -581,7 +644,11 @@ const EditBrandDevice = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Card
|
<Card
|
||||||
title={<Title level={5} style={{ margin: 0 }}>Spareparts</Title>}
|
title={
|
||||||
|
<Title level={5} style={{ margin: 0 }}>
|
||||||
|
Spareparts
|
||||||
|
</Title>
|
||||||
|
}
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ const BrandForm = ({ form, formData, onValuesChange, isEdit = false }) => {
|
|||||||
|
|
||||||
<Form.Item label="Brand Code" name="brand_code">
|
<Form.Item label="Brand Code" name="brand_code">
|
||||||
<Input
|
<Input
|
||||||
placeholder={isEdit ? 'Brand Code Auto Fill' : 'Brand Code'}
|
placeholder={'Auto Fill Brand Code'}
|
||||||
disabled={isEdit}
|
disabled={true}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: isEdit ? '#f5f5f5' : 'white',
|
backgroundColor: '#f5f5f5',
|
||||||
cursor: isEdit ? 'not-allowed' : 'text'
|
cursor: 'not-allowed'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -157,12 +157,12 @@ const ListBrandDevice = memo(function ListBrandDevice(props) {
|
|||||||
icon: 'question',
|
icon: 'question',
|
||||||
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),
|
onConfirm: () => handleDelete(param.brand_id, param.brand_name),
|
||||||
onCancel: () => {},
|
onCancel: () => {},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (brand_id) => {
|
const handleDelete = async (brand_id, brand_name) => {
|
||||||
try {
|
try {
|
||||||
const response = await deleteBrand(brand_id);
|
const response = await deleteBrand(brand_id);
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ const ListBrandDevice = memo(function ListBrandDevice(props) {
|
|||||||
NotifOk({
|
NotifOk({
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
title: 'Berhasil',
|
title: 'Berhasil',
|
||||||
message: response.message || 'Data Brand Device berhasil dihapus.',
|
message: `Brand ${brand_name} deleted successfully.`,
|
||||||
});
|
});
|
||||||
doFilter(); // Refresh data
|
doFilter(); // Refresh data
|
||||||
} else {
|
} else {
|
||||||
@@ -278,4 +278,4 @@ const ListBrandDevice = memo(function ListBrandDevice(props) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default ListBrandDevice;
|
export default ListBrandDevice;
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Form, Input, Button, Divider, Typography, Switch, Space, Card, Upload, message } from 'antd';
|
import {
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Typography,
|
||||||
|
Switch,
|
||||||
|
Space,
|
||||||
|
Card,
|
||||||
|
Upload,
|
||||||
|
message,
|
||||||
|
} from 'antd';
|
||||||
import { PlusOutlined, DeleteOutlined, UploadOutlined } from '@ant-design/icons';
|
import { PlusOutlined, DeleteOutlined, UploadOutlined } from '@ant-design/icons';
|
||||||
import { uploadFile } from '../../../../api/file-uploads';
|
import { uploadFile } from '../../../../api/file-uploads';
|
||||||
|
|
||||||
@@ -15,7 +26,7 @@ const SparepartForm = ({
|
|||||||
onSparepartImageUpload,
|
onSparepartImageUpload,
|
||||||
onSparepartImageRemove,
|
onSparepartImageRemove,
|
||||||
sparepartImages = {},
|
sparepartImages = {},
|
||||||
isReadOnly = false
|
isReadOnly = false,
|
||||||
}) => {
|
}) => {
|
||||||
const [fieldStatuses, setFieldStatuses] = useState({});
|
const [fieldStatuses, setFieldStatuses] = useState({});
|
||||||
|
|
||||||
@@ -32,7 +43,7 @@ const SparepartForm = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Update field statuses when form changes
|
// Update field statuses when form changes
|
||||||
const newStatuses = {};
|
const newStatuses = {};
|
||||||
sparepartFields.forEach(field => {
|
sparepartFields.forEach((field) => {
|
||||||
newStatuses[field.key] = getFieldValue(field.key);
|
newStatuses[field.key] = getFieldValue(field.key);
|
||||||
});
|
});
|
||||||
setFieldStatuses(newStatuses);
|
setFieldStatuses(newStatuses);
|
||||||
@@ -55,21 +66,25 @@ const SparepartForm = ({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const fileExtension = file.name.split('.').pop().toLowerCase();
|
const fileExtension = file.name.split('.').pop().toLowerCase();
|
||||||
const isImageFile = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'].includes(fileExtension);
|
const isImageFile = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'].includes(
|
||||||
|
fileExtension
|
||||||
|
);
|
||||||
const fileType = isImageFile ? 'image' : 'pdf';
|
const fileType = isImageFile ? 'image' : 'pdf';
|
||||||
const folder = 'images';
|
const folder = 'images';
|
||||||
|
|
||||||
const uploadResponse = await uploadFile(file, folder);
|
const uploadResponse = await uploadFile(file, folder);
|
||||||
const imagePath = uploadResponse.data?.path_icon || uploadResponse.data?.path_solution || '';
|
const imagePath =
|
||||||
|
uploadResponse.data?.path_icon || uploadResponse.data?.path_solution || '';
|
||||||
|
|
||||||
if (imagePath) {
|
if (imagePath) {
|
||||||
onSparepartImageUpload && onSparepartImageUpload(fieldKey, {
|
onSparepartImageUpload &&
|
||||||
name: file.name,
|
onSparepartImageUpload(fieldKey, {
|
||||||
uploadPath: imagePath,
|
name: file.name,
|
||||||
fileExtension,
|
uploadPath: imagePath,
|
||||||
isImage: isImageFile,
|
fileExtension,
|
||||||
size: file.size,
|
isImage: isImageFile,
|
||||||
});
|
size: file.size,
|
||||||
|
});
|
||||||
message.success(`${file.name} uploaded successfully!`);
|
message.success(`${file.name} uploaded successfully!`);
|
||||||
} else {
|
} else {
|
||||||
message.error(`Failed to upload ${file.name}`);
|
message.error(`Failed to upload ${file.name}`);
|
||||||
@@ -106,48 +121,40 @@ const SparepartForm = ({
|
|||||||
size="small"
|
size="small"
|
||||||
style={{ marginBottom: 16 }}
|
style={{ marginBottom: 16 }}
|
||||||
title={
|
title={
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Text strong>Sparepart {index + 1}</Text>
|
<Text strong>Sparepart {index + 1}</Text>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
||||||
<Form.Item name={[field.name, 'status']} valuePropName="checked" noStyle>
|
{!isReadOnly && sparepartFields.length > 1 && (
|
||||||
<Switch
|
<div style={{ textAlign: 'right' }}>
|
||||||
disabled={isReadOnly}
|
<Button
|
||||||
size="small"
|
type="text"
|
||||||
onChange={(checked) => {
|
danger
|
||||||
onSparepartStatusChange && onSparepartStatusChange(field.key, checked);
|
icon={<DeleteOutlined />}
|
||||||
setFieldStatuses(prev => ({ ...prev, [field.key]: checked }));
|
onClick={() => onRemoveSparepartField(field.key)}
|
||||||
}}
|
/>
|
||||||
style={{
|
</div>
|
||||||
backgroundColor: fieldStatuses[field.key] ? '#23A55A' : '#bfbfbf'
|
)}
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Text style={{ fontSize: 12, color: '#666' }}>
|
|
||||||
{fieldStatuses[field.key] ? 'Active' : 'Inactive'}
|
|
||||||
</Text>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Form
|
<Form layout="vertical" style={{ border: 'none' }}>
|
||||||
layout="vertical"
|
|
||||||
style={{ border: 'none' }}
|
|
||||||
>
|
|
||||||
{/* Sparepart Name */}
|
{/* Sparepart Name */}
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={[field.name, 'name']}
|
name={[field.name, 'name']}
|
||||||
rules={[{ required: true, message: 'Sparepart name wajib diisi!' }]}
|
rules={[{ required: true, message: 'Sparepart name wajib diisi!' }]}
|
||||||
>
|
>
|
||||||
<Input
|
<Input placeholder="Enter sparepart name" disabled={isReadOnly} />
|
||||||
placeholder="Enter sparepart name"
|
|
||||||
disabled={isReadOnly}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<Form.Item
|
<Form.Item name={[field.name, 'description']}>
|
||||||
name={[field.name, 'description']}
|
|
||||||
>
|
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
placeholder="Enter sparepart description (optional)"
|
placeholder="Enter sparepart description (optional)"
|
||||||
rows={2}
|
rows={2}
|
||||||
@@ -169,14 +176,26 @@ const SparepartForm = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</Upload>
|
</Upload>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ padding: '8px 12px', border: '1px solid #d9d9d9', borderRadius: 4 }}>
|
<div
|
||||||
|
style={{
|
||||||
|
padding: '8px 12px',
|
||||||
|
border: '1px solid #d9d9d9',
|
||||||
|
borderRadius: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Text type="secondary">No upload allowed</Text>
|
<Text type="secondary">No upload allowed</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{sparepartImages[field.key] && (
|
{sparepartImages[field.key] && (
|
||||||
<div style={{ marginTop: 8 }}>
|
<div style={{ marginTop: 8 }}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
src={sparepartImages[field.key].uploadPath}
|
src={sparepartImages[field.key].uploadPath}
|
||||||
alt="Sparepart Image"
|
alt="Sparepart Image"
|
||||||
@@ -189,10 +208,16 @@ const SparepartForm = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<Text style={{ fontSize: 12 }}>{sparepartImages[field.key].name}</Text>
|
<Text style={{ fontSize: 12 }}>
|
||||||
|
{sparepartImages[field.key].name}
|
||||||
|
</Text>
|
||||||
<br />
|
<br />
|
||||||
<Text type="secondary" style={{ fontSize: 10 }}>
|
<Text type="secondary" style={{ fontSize: 10 }}>
|
||||||
Size: {(sparepartImages[field.key].size / 1024).toFixed(1)} KB
|
Size:{' '}
|
||||||
|
{(
|
||||||
|
sparepartImages[field.key].size / 1024
|
||||||
|
).toFixed(1)}{' '}
|
||||||
|
KB
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
@@ -209,24 +234,6 @@ const SparepartForm = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{/* Delete Button */}
|
|
||||||
{!isReadOnly && sparepartFields.length > 1 && (
|
|
||||||
<div style={{ textAlign: 'right' }}>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
danger
|
|
||||||
icon={<DeleteOutlined />}
|
|
||||||
onClick={() => onRemoveSparepartField(field.key)}
|
|
||||||
style={{
|
|
||||||
borderColor: '#ff4d4f',
|
|
||||||
color: '#ff4d4f'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Remove
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
@@ -243,17 +250,9 @@ const SparepartForm = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isReadOnly && (
|
|
||||||
<div style={{ marginTop: 16 }}>
|
|
||||||
<Text type="secondary">
|
|
||||||
* Add at least one sparepart for this error code.
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SparepartForm;
|
export default SparepartForm;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { memo, useState, useEffect } from 'react';
|
import React, { memo, useState, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useBreadcrumb } from '../../layout/LayoutBreadcrumb';
|
import { useBreadcrumb } from '../../layout/LayoutBreadcrumb';
|
||||||
import { Form, Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import ListNotification from './component/ListNotification';
|
import ListNotification from './component/ListNotification';
|
||||||
import DetailNotification from './component/DetailNotification';
|
import DetailNotification from './component/DetailNotification';
|
||||||
|
|
||||||
@@ -10,7 +10,6 @@ const { Text } = Typography;
|
|||||||
const IndexNotification = memo(function IndexNotification() {
|
const IndexNotification = memo(function IndexNotification() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { setBreadcrumbItems } = useBreadcrumb();
|
const { setBreadcrumbItems } = useBreadcrumb();
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const [actionMode, setActionMode] = useState('list');
|
const [actionMode, setActionMode] = useState('list');
|
||||||
const [selectedData, setSelectedData] = useState(null);
|
const [selectedData, setSelectedData] = useState(null);
|
||||||
@@ -36,19 +35,14 @@ const IndexNotification = memo(function IndexNotification() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (actionMode === 'preview') {
|
if (actionMode === 'preview') {
|
||||||
setIsModalVisible(true);
|
setIsModalVisible(true);
|
||||||
if (selectedData) {
|
|
||||||
form.setFieldsValue(selectedData);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setIsModalVisible(false);
|
setIsModalVisible(false);
|
||||||
form.resetFields();
|
|
||||||
}
|
}
|
||||||
}, [actionMode, selectedData, form]);
|
}, [actionMode]);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
setActionMode('list');
|
setActionMode('list');
|
||||||
setSelectedData(null);
|
setSelectedData(null);
|
||||||
form.resetFields();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -62,7 +56,6 @@ const IndexNotification = memo(function IndexNotification() {
|
|||||||
<DetailNotification
|
<DetailNotification
|
||||||
visible={isModalVisible}
|
visible={isModalVisible}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
form={form}
|
|
||||||
selectedData={selectedData}
|
selectedData={selectedData}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user