diff --git a/src/pages/master/sparepart/component/DetailSparepart.jsx b/src/pages/master/sparepart/component/DetailSparepart.jsx index e1e7f77..7f86231 100644 --- a/src/pages/master/sparepart/component/DetailSparepart.jsx +++ b/src/pages/master/sparepart/component/DetailSparepart.jsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; -import { Modal, Input, Select, Divider, Typography, Switch, Button, ConfigProvider, Upload, message, Row, Col } from 'antd'; -import { UploadOutlined } from '@ant-design/icons'; +import { Modal, Input, Select, Divider, Typography, Button, ConfigProvider, Upload, Row, Col, Image } from 'antd'; +import { PlusOutlined } from '@ant-design/icons'; import { NotifAlert, NotifOk } from '../../../../components/Global/ToastNotif'; import { createSparepart, updateSparepart } from '../../../../api/sparepart'; import { uploadFile } from '../../../../api/file-uploads'; @@ -9,9 +9,20 @@ import { validateRun } from '../../../../Utils/validate'; const { Text } = Typography; const { TextArea } = Input; +const getBase64 = (file) => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result); + reader.onerror = (error) => reject(error); + }); + const DetailSparepart = (props) => { const [confirmLoading, setConfirmLoading] = useState(false); - const [imageFile, setImageFile] = useState(null); + const [fileList, setFileList] = useState([]); + const [previewOpen, setPreviewOpen] = useState(false); + const [previewImage, setPreviewImage] = useState(''); + const [previewTitle, setPreviewTitle] = useState(''); const defaultData = { sparepart_id: '', @@ -30,38 +41,48 @@ const DetailSparepart = (props) => { const handleCancel = () => { props.setSelectedData(null); props.setActionMode('list'); - setImageFile(null); + setFileList([]); }; + const handlePreviewCancel = () => setPreviewOpen(false); + + const handlePreview = async (file) => { + if (!file.url && !file.preview) { + file.preview = await getBase64(file.originFileObj); + } + setPreviewImage(file.url || file.preview); + setPreviewOpen(true); + setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)); + }; + + const handleChange = ({ fileList: newFileList }) => setFileList(newFileList); + const handleSave = async () => { setConfirmLoading(true); - const validationRules = [ - { field: 'sparepart_name', label: 'Sparepart Name', required: true }, - ]; + const validationRules = [{ field: 'sparepart_name', label: 'Sparepart Name', required: true }]; if ( validateRun(formData, validationRules, (errorMessages) => { - NotifOk({ - icon: 'warning', - title: 'Peringatan', - message: errorMessages, - }); + NotifOk({ icon: 'warning', title: 'Peringatan', message: errorMessages }); setConfirmLoading(false); }) ) return; try { - let imageUrl = formData.image_url; // Keep existing image url if not changed + let imageUrl = formData.image_url; + const newFile = fileList.length > 0 ? fileList[0] : null; - if (imageFile) { - const uploadResponse = await uploadFile(imageFile, 'images'); + if (newFile && newFile.originFileObj) { + const uploadResponse = await uploadFile(newFile.originFileObj, 'images'); if (uploadResponse && uploadResponse.file_url) { imageUrl = uploadResponse.file_url; } else { throw new Error('Image upload failed or did not return a URL.'); } + } else if (fileList.length === 0 && formData.sparepart_id) { + imageUrl = ''; } const payload = { @@ -72,7 +93,7 @@ const DetailSparepart = (props) => { sparepart_merk: formData.sparepart_merk, sparepart_model: formData.sparepart_model, sparepart_description: formData.sparepart_description, - sparepart_unit: formData.sparepart_unit, // This field was in the old form, keep it + sparepart_unit: formData.sparepart_unit, }; const response = formData.sparepart_id @@ -83,12 +104,10 @@ const DetailSparepart = (props) => { NotifOk({ icon: 'success', title: 'Berhasil', - message: `Data Sparepart berhasil ${ - formData.sparepart_id ? 'diubah' : 'ditambahkan' - }.`, + message: `Data Sparepart berhasil ${formData.sparepart_id ? 'diubah' : 'ditambahkan'}.`, }); props.setActionMode('list'); - setImageFile(null); + setFileList([]); } else { NotifAlert({ icon: 'error', @@ -110,59 +129,45 @@ const DetailSparepart = (props) => { const handleInputChange = (e) => { const { name, value } = e.target; - setFormData({ - ...formData, - [name]: value, - }); + setFormData({ ...formData, [name]: value }); }; const handleSelectChange = (name, value) => { - setFormData({ - ...formData, - [name]: value, - }); + setFormData({ ...formData, [name]: value }); }; useEffect(() => { if (props.selectedData) { setFormData(props.selectedData); + if (props.selectedData.image_url) { + setFileList([ + { + uid: '-1', + name: props.selectedData.image_url.split('/').pop(), + status: 'done', + url: props.selectedData.image_url, + }, + ]); + } else { + setFileList([]); + } } else { setFormData(defaultData); + setFileList([]); } - setImageFile(null); }, [props.showModal, props.selectedData, props.actionMode]); - - const uploadProps = { - beforeUpload: file => { - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; - if (!isJpgOrPng) { - message.error('You can only upload JPG/PNG file!'); - } - const isLt2M = file.size / 1024 / 1024 < 2; - if (!isLt2M) { - message.error('Image must smaller than 2MB!'); - } - if(isJpgOrPng && isLt2M) { - setImageFile(file); - } - - return false; // Prevent auto-upload - }, - onRemove: () => { - setImageFile(null); - }, - maxCount: 1, - }; + const uploadButton = ( +