import React, { useState, useEffect } from 'react'; 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'; 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 [fileList, setFileList] = useState([]); const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(''); const [previewTitle, setPreviewTitle] = useState(''); const defaultData = { sparepart_id: '', sparepart_name: '', sparepart_description: '', sparepart_model: '', sparepart_item_type: '', sparepart_unit: '', sparepart_merk: '', sparepart_stok: '0', sparepart_foto: '', }; const [formData, setFormData] = useState(defaultData); const handleCancel = () => { props.setSelectedData(null); props.setActionMode('list'); 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 }, ]; if ( validateRun(formData, validationRules, (errorMessages) => { NotifOk({ icon: 'warning', title: 'Peringatan', message: errorMessages }); setConfirmLoading(false); }) ) return; try { let imageUrl = formData.sparepart_foto; const newFile = fileList.length > 0 ? fileList[0] : null; if (newFile && newFile.originFileObj) { console.log('Uploading file:', newFile.originFileObj); const uploadResponse = await uploadFile(newFile.originFileObj, 'images'); // Log untuk debugging console.log('Upload response:', uploadResponse); // Cek berbagai kemungkinan struktur respons dari API let uploadedUrl = null; // Cek berbagai kemungkinan struktur respons dari API // Cek langsung properti file_url atau url if (uploadResponse && typeof uploadResponse === 'object') { // Cek jika uploadResponse langsung memiliki file_url if (uploadResponse.file_url) { uploadedUrl = uploadResponse.file_url; } // Cek jika uploadResponse memiliki data yang berisi file_url else if (uploadResponse.data && uploadResponse.data.file_url) { uploadedUrl = uploadResponse.data.file_url; } // Cek jika uploadResponse memiliki data yang berisi url else if (uploadResponse.data && uploadResponse.data.url) { uploadedUrl = uploadResponse.data.url; } // Cek jika uploadResponse langsung memiliki url else if (uploadResponse.url) { uploadedUrl = uploadResponse.url; } // Cek jika uploadResponse.data adalah string URL else if (uploadResponse.data && typeof uploadResponse.data === 'string') { uploadedUrl = uploadResponse.data; } // Cek jika uploadResponse.data adalah objek yang berisi file URL dalam format berbeda else if (uploadResponse.data && typeof uploadResponse.data === 'object') { // Cek kemungkinan nama field lain if (uploadResponse.data.file) { uploadedUrl = uploadResponse.data.file; } else if (uploadResponse.data.filename) { // Jika hanya nama file dikembalikan, bangun URL const baseUrl = import.meta.env.VITE_API_SERVER || ''; uploadedUrl = `${baseUrl}/uploads/images/${uploadResponse.data.filename}`; } else if (uploadResponse.data.path) { uploadedUrl = uploadResponse.data.path; } else if (uploadResponse.data.location) { uploadedUrl = uploadResponse.data.location; } // Tambahkan kemungkinan lain berdasarkan struktur respons umum else if (uploadResponse.data.filePath) { uploadedUrl = uploadResponse.data.filePath; } else if (uploadResponse.data.file_path) { uploadedUrl = uploadResponse.data.file_path; } else if (uploadResponse.data.publicUrl) { uploadedUrl = uploadResponse.data.publicUrl; } else if (uploadResponse.data.public_url) { uploadedUrl = uploadResponse.data.public_url; } // Berdasarkan log yang ditampilkan, API mengembalikan path_document atau path_solution else if (uploadResponse.data.path_document) { uploadedUrl = uploadResponse.data.path_document; } else if (uploadResponse.data.path_solution) { uploadedUrl = uploadResponse.data.path_solution; } else if (uploadResponse.data.file_upload_name) { // Jika hanya nama file dikembalikan, bangun URL const baseUrl = import.meta.env.VITE_API_SERVER || ''; uploadedUrl = `${baseUrl}/uploads/images/${uploadResponse.data.file_upload_name}`; } } } // Jika respons adalah string, mungkin itu adalah URL else if (uploadResponse && typeof uploadResponse === 'string') { uploadedUrl = uploadResponse; } if (uploadedUrl) { console.log('Successfully extracted image URL:', uploadedUrl); imageUrl = uploadedUrl; } else { console.error('Upload response structure:', uploadResponse); console.error('Available properties:', Object.keys(uploadResponse || {})); console.error('Response type:', typeof uploadResponse); console.error( 'Is response an object?', uploadResponse && typeof uploadResponse === 'object' ); if (uploadResponse && typeof uploadResponse === 'object') { console.error('Response keys:', Object.keys(uploadResponse)); console.error( 'Response data keys:', uploadResponse.data ? Object.keys(uploadResponse.data) : 'No data property' ); } // Tampilkan notifikasi bahwa upload gagal tapi lanjutkan penyimpanan NotifOk({ icon: 'warning', title: 'Peringatan', message: 'Upload gambar gagal. Data akan disimpan tanpa gambar.', }); // Gunakan URL gambar yang sebelumnya jika ada, atau kosongkan imageUrl = formData.sparepart_foto || ''; } } else if (fileList.length === 0) { // Jika tidak ada file di fileList (termasuk saat user menghapus file), gunakan gambar default imageUrl = '/assets/defaultSparepartImg.jpg'; } // Payload hanya berisi field yang tidak kosong untuk menghindari error validasi const payload = { sparepart_name: formData.sparepart_name, // Wajib }; // Tambahkan field-field secara kondisional hanya jika nilainya tidak kosong if (formData.sparepart_description && formData.sparepart_description.trim() !== '') { payload.sparepart_description = formData.sparepart_description; } if (formData.sparepart_model && formData.sparepart_model.trim() !== '') { payload.sparepart_model = formData.sparepart_model; } if (formData.sparepart_item_type && formData.sparepart_item_type.trim() !== '') { payload.sparepart_item_type = formData.sparepart_item_type; } if (formData.sparepart_unit && formData.sparepart_unit.trim() !== '') { payload.sparepart_unit = formData.sparepart_unit; } if (formData.sparepart_merk && formData.sparepart_merk.trim() !== '') { payload.sparepart_merk = formData.sparepart_merk; } if (formData.sparepart_stok && formData.sparepart_stok.trim() !== '') { payload.sparepart_stok = formData.sparepart_stok.toString(); } else { payload.sparepart_stok = '0'; // Set default value jika tidak diisi } // Sertakan sparepart_foto hanya jika nilainya tidak kosong, agar tidak memicu validasi if (imageUrl && imageUrl.trim() !== '') { payload.sparepart_foto = imageUrl; } console.log('Sending payload:', payload); const response = formData.sparepart_id ? await updateSparepart(formData.sparepart_id, payload) : await createSparepart(payload); console.log('API response:', response); if (response && (response.statusCode === 200 || response.statusCode === 201)) { NotifOk({ icon: 'success', title: 'Berhasil', message: `Data Sparepart berhasil ${ formData.sparepart_id ? 'diubah' : 'ditambahkan' }.`, }); props.setActionMode('list'); setFileList([]); } else { NotifAlert({ icon: 'error', title: 'Gagal', message: response?.message || 'Terjadi kesalahan saat menyimpan data.', }); } } catch (error) { console.error('Save Sparepart Error:', error); NotifAlert({ icon: 'error', title: 'Error', message: error.message || 'Terjadi kesalahan pada server. Coba lagi nanti.', }); } setConfirmLoading(false); }; const handleInputChange = (e) => { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); }; const handleSelectChange = (name, value) => { setFormData({ ...formData, [name]: value }); }; useEffect(() => { if (props.selectedData) { setFormData(props.selectedData); if (props.selectedData.sparepart_foto) { // Buat URL lengkap dengan token untuk file yang sudah ada const fileName = props.selectedData.sparepart_foto.split('/').pop(); const token = localStorage.getItem('token'); const baseURL = import.meta.env.VITE_API_SERVER || ''; const fullUrl = `${baseURL}/file-uploads/images/${encodeURIComponent(fileName)}${token ? `?token=${encodeURIComponent(token)}` : ''}`; setFileList([ { uid: '-1', name: fileName, status: 'done', url: fullUrl, }, ]); } else { setFileList([]); } } else { setFormData(defaultData); setFileList([]); } }, [props.showModal, props.selectedData, props.actionMode]); const uploadButton = (
Upload
); return ( {!props.readOnly && ( )} , ]} > {formData && (
Sparepart Name * Item Type Stock Unit Foto false} maxCount={1} disabled={props.readOnly} > {fileList.length >= 1 ? null : uploadButton} preview Brand Model Description