From ea3adf40cc5a6d55f4c97c5dba43e4c6baf721c6 Mon Sep 17 00:00:00 2001 From: Antony Kurniawan Date: Fri, 12 Dec 2025 16:54:30 +0700 Subject: [PATCH] repair: brandDevice add edit page --- src/App.jsx | 4 - .../master/brandDevice/AddBrandDevice.jsx | 41 +- .../master/brandDevice/AddEditErrorCode.jsx | 467 ------------------ .../master/brandDevice/EditBrandDevice.jsx | 103 +++- .../brandDevice/component/FormActions.jsx | 70 --- 5 files changed, 107 insertions(+), 578 deletions(-) delete mode 100644 src/pages/master/brandDevice/AddEditErrorCode.jsx delete mode 100644 src/pages/master/brandDevice/component/FormActions.jsx diff --git a/src/App.jsx b/src/App.jsx index 9b585d4..b976b45 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -21,7 +21,6 @@ import IndexShift from './pages/master/shift/IndexShift'; // Brand device import AddBrandDevice from './pages/master/brandDevice/AddBrandDevice'; import EditBrandDevice from './pages/master/brandDevice/EditBrandDevice'; -import AddEditErrorCode from './pages/master/brandDevice/AddEditErrorCode'; import ViewBrandDevice from './pages/master/brandDevice/ViewBrandDevice'; import ViewFilePage from './pages/master/brandDevice/ViewFilePage'; @@ -118,9 +117,6 @@ const App = () => { path="brand-device/view/temp/files/:fileName" element={} /> - } /> - } /> - } /> }> diff --git a/src/pages/master/brandDevice/AddBrandDevice.jsx b/src/pages/master/brandDevice/AddBrandDevice.jsx index 27ab08f..53d50b2 100644 --- a/src/pages/master/brandDevice/AddBrandDevice.jsx +++ b/src/pages/master/brandDevice/AddBrandDevice.jsx @@ -10,22 +10,18 @@ import { Col, Card, Spin, - Tag, Space, - Input, + ConfigProvider, } from 'antd'; -import { EyeOutlined, EditOutlined, DeleteOutlined, SearchOutlined } from '@ant-design/icons'; +import { EyeOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons'; import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif'; import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; import { getBrandById, createBrand, createErrorCode, getErrorCodesByBrandId, updateErrorCode, deleteErrorCode, deleteBrand } from '../../../api/master-brand'; -import { getFileUrl } from '../../../api/file-uploads'; -import { SendRequest } from '../../../components/Global/ApiRequest'; import BrandForm from './component/BrandForm'; import ErrorCodeForm from './component/ErrorCodeForm'; import SolutionForm from './component/SolutionForm'; import SparepartSelect from './component/SparepartSelect'; import ListErrorCode from './component/ListErrorCode'; -import FormActions from './component/FormActions'; const { Title } = Typography; const { Step } = Steps; @@ -129,7 +125,7 @@ const AddBrandDevice = () => { const isFileType = solution.type_solution && solution.type_solution !== 'text'; newSolutionTypes[fieldKey] = isFileType ? 'file' : 'text'; - newSolutionStatuses[fieldKey] = solution.is_active !== false; + newSolutionStatuses[fieldKey] = solution.is_active; let fileObject = null; if (isFileType && (solution.path_solution || solution.path_document)) { @@ -149,7 +145,7 @@ const AddBrandDevice = () => { name: solution.solution_name || '', type: isFileType ? 'file' : 'text', text: solution.text_solution || '', - status: solution.is_active !== false, + status: solution.is_active, file: fileObject, fileUpload: fileObject, path_solution: solution.path_solution || solution.path_document || null, @@ -311,7 +307,7 @@ const AddBrandDevice = () => { error_code_name: record.error_code_name || '', error_code_description: record.error_code_description || '', error_code_color: record.error_code_color || '#000000', - status: record.is_active !== false, + status: record.is_active, }); if (record.path_icon) { @@ -1129,13 +1125,23 @@ const AddBrandDevice = () => { return ( - - - - - -
- {loading && ( + + + + + + +
+ {loading && (
{ )}
-
+ +
); }; diff --git a/src/pages/master/brandDevice/AddEditErrorCode.jsx b/src/pages/master/brandDevice/AddEditErrorCode.jsx deleted file mode 100644 index b721c64..0000000 --- a/src/pages/master/brandDevice/AddEditErrorCode.jsx +++ /dev/null @@ -1,467 +0,0 @@ -import { useEffect, useState } from 'react'; -import { useNavigate, useParams, useLocation } from 'react-router-dom'; -import { - Card, - Typography, - Button, - Form, - Row, - Col, - Spin, - Upload, -} from 'antd'; -import { ArrowLeftOutlined } from '@ant-design/icons'; -import { getErrorCodeById, createErrorCode, updateErrorCode } from '../../../api/master-brand'; -import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; -import ErrorCodeForm from './component/ErrorCodeForm'; -import SolutionForm from './component/SolutionForm'; -import { useSolutionLogic } from './hooks/solution'; -import SparepartSelect from './component/SparepartSelect'; -import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif'; - -const { Title } = Typography; - -const AddEditErrorCode = () => { - const navigate = useNavigate(); - const { brandId: routeBrandId, errorCodeId } = useParams(); - const { setBreadcrumbItems } = useBreadcrumb(); - const location = useLocation(); - - const currentBrandId = routeBrandId; - - const isFromAddBrand = location.pathname.includes('/master/brand-device/') && location.pathname.includes('/error-code/') && - (location.pathname.includes('/add') || (location.pathname.includes('/edit/') && !location.pathname.includes('/edit/'))); - - const [errorCodeForm] = Form.useForm(); - const [solutionForm] = Form.useForm(); - - const [loading, setLoading] = useState(false); - const [confirmLoading, setConfirmLoading] = useState(false); - const [errorCodeIcon, setErrorCodeIcon] = useState(null); - const [selectedSparepartIds, setSelectedSparepartIds] = useState([]); - const [isEdit, setIsEdit] = useState(false); - const [fileList, setFileList] = useState([]); - - const { - solutionFields, - solutionTypes, - solutionStatuses, - solutionsToDelete, - firstSolutionValid, - handleAddSolutionField, - handleRemoveSolutionField, - handleSolutionTypeChange, - handleSolutionStatusChange, - resetSolutionFields, - getSolutionData, - setSolutionsForExistingRecord, - } = useSolutionLogic(solutionForm); - - useEffect(() => { - const isEditMode = errorCodeId && errorCodeId !== 'add'; - setIsEdit(isEditMode); - - if (!isEditMode) { - resetSolutionFields(); - } - - setBreadcrumbItems([ - { - title: • Master - }, - { - title: ( - navigate('/master/brand-device')} - > - Brand Device - - ), - }, - { - title: ( - navigate(`/master/brand-device/edit/${currentBrandId}?tab=error-codes`)} - > - Edit Brand Device - - ), - }, - { - title: ( - - {isEditMode ? 'Edit Error Code' : 'Add Error Code'} - - ), - }, - ]); - - if (isEditMode && errorCodeId) { - const tempId = errorCodeId.startsWith('existing_') ? errorCodeId : `existing_${errorCodeId}`; - loadExistingErrorCode(tempId); - } - }, [currentBrandId, errorCodeId, navigate, setBreadcrumbItems]); - - const loadExistingErrorCode = async (tempId) => { - try { - setLoading(true); - - let errorIdToUse = tempId; - if (tempId.startsWith('existing_')) { - errorIdToUse = tempId.replace('existing_', ''); - } - - const errorCodeResponse = await getErrorCodeById(errorIdToUse); - - if (errorCodeResponse && errorCodeResponse.statusCode === 200) { - const errorData = errorCodeResponse.data; - - if (errorData) { - errorCodeForm.setFieldsValue({ - error_code: errorData.error_code, - error_code_name: errorData.error_code_name || '', - error_code_description: errorData.error_code_description || '', - error_code_color: errorData.error_code_color || '#000000', - status: errorData.is_active !== false, - }); - - if (errorData.path_icon) { - setErrorCodeIcon({ - name: errorData.path_icon.split('/').pop(), - uploadPath: errorData.path_icon, - url: errorData.path_icon, - }); - } - - if (errorData.solution && errorData.solution.length > 0) { - setSolutionsForExistingRecord(errorData.solution, solutionForm); - } - - if (errorData.spareparts && errorData.spareparts.length > 0) { - const sparepartIds = errorData.spareparts.map(sp => sp.sparepart_id); - setSelectedSparepartIds(sparepartIds); - } - } - } else { - errorCodeForm.setFieldsValue({ - error_code: '', - error_code_name: '', - error_code_description: '', - error_code_color: '#000000', - status: true, - }); - - NotifAlert({ - icon: 'warning', - title: 'Peringatan', - message: 'Error code not found. Creating new error code.', - }); - } - } catch (error) { - NotifAlert({ - icon: 'error', - title: 'Error', - message: 'Failed to load error code data', - }); - } finally { - setLoading(false); - } - }; - - const handleSave = async () => { - try { - await errorCodeForm.validateFields(); - - const solutionData = getSolutionData(); - - - if (!solutionData || solutionData.length === 0) { - NotifAlert({ - icon: 'warning', - title: 'Perhatian', - message: 'Harap lengkapi minimal 1 solution', - }); - return; - } - - const invalidSolutions = solutionData.filter(solution => { - if (solution.type_solution === 'text') { - return !solution.text_solution || solution.text_solution.trim() === ''; - } else if (solution.type_solution !== 'text') { - return !solution.path_solution || solution.path_solution.trim() === ''; - } - return false; - }); - - - if (invalidSolutions.length > 0) { - const invalidNames = invalidSolutions.map(s => s.solution_name).join(', '); - NotifAlert({ - icon: 'warning', - title: 'Perhatian', - message: `Harap lengkapi solution berikut:\n${invalidSolutions.map(s => - `- ${s.solution_name}: ${s.type_solution === 'text' ? 'Text solution wajib diisi' : 'File wajib diupload'}` - ).join('\n')}`, - }); - return; - } - - const errorCodeValues = errorCodeForm.getFieldsValue(); - - setConfirmLoading(true); - - try { - const payload = { - 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?.path_icon || errorCodeIcon?.uploadPath || '', - is_active: errorCodeValues.status !== undefined ? errorCodeValues.status : true, - solution: solutionData || [], - spareparts: selectedSparepartIds || [] - }; - - if (!isEdit) { - payload.error_code = errorCodeValues.error_code; - } - - - let response; - - if (isEdit && errorCodeId) { - let cleanErrorCodeId = errorCodeId; - if (errorCodeId.startsWith('existing_')) { - cleanErrorCodeId = errorCodeId.replace('existing_', ''); - } - response = await updateErrorCode(currentBrandId, cleanErrorCodeId, payload); - } else { - response = await createErrorCode(currentBrandId, payload); - } - - - if (response && (response.statusCode === 200 || response.statusCode === 201)) { - NotifOk({ - icon: 'success', - title: 'Berhasil', - message: isEdit ? 'Error Code berhasil diupdate!' : 'Error Code berhasil ditambahkan!', - }); - - if (isFromAddBrand) { - navigate(`/master/brand-device/add`); - } else { - navigate(`/master/brand-device/edit/${currentBrandId}?tab=error-codes`, { - state: { refreshErrorCodes: true } - }); - } - } else { - NotifAlert({ - icon: 'error', - title: 'Gagal', - message: response?.message || 'Gagal menyimpan error code', - }); - } - } catch (error) { - NotifAlert({ - icon: 'error', - title: 'Gagal', - message: error.message || 'Gagal menyimpan error code. Silakan coba lagi.', - }); - } finally { - setConfirmLoading(false); - } - - } catch (error) { - NotifAlert({ - icon: 'error', - title: 'Error', - message: 'Gagal menyimpan error code. Silakan coba lagi.', - }); - } - }; - - const handleCancel = () => { - if (isFromAddBrand) { - navigate(`/master/brand-device/add`); - } else { - navigate(`/master/brand-device/edit/${currentBrandId}?tab=error-codes`); - } - }; - - const handleErrorCodeIconUpload = (iconData) => { - if (!iconData || !iconData.uploadPath) { - return null; - } - - const formattedIconData = { - name: iconData.name, - uploadPath: iconData.uploadPath, - url: iconData.uploadPath, - }; - - setErrorCodeIcon(formattedIconData); - return formattedIconData; - }; - - const handleErrorCodeIconRemove = () => { - setErrorCodeIcon(null); - }; - - const handleSolutionFileUpload = (fileObject) => { - }; - - const resetForm = () => { - errorCodeForm.resetFields(); - errorCodeForm.setFieldsValue({ - status: true, - }); - setErrorCodeIcon(null); - resetSolutionFields(); - setSelectedSparepartIds([]); - }; - - return ( - - {/* Header */} -
- - {isEdit ? 'Edit Error Code' : 'Add Error Code'} - - -
- - {/* Content */} -
- {loading && ( -
- -
- )} - - - {/* Error Code Form */} - - -
- - -
- - - {/* Solutions Form */} - - -
- { - return checkFirstSolutionValid(); - }} - onAddSolutionField={handleAddSolutionField} - onRemoveSolutionField={handleRemoveSolutionField} - onSolutionTypeChange={handleSolutionTypeChange} - onSolutionStatusChange={handleSolutionStatusChange} - onSolutionFileUpload={handleSolutionFileUpload} - onFileView={(fileData) => { - if (fileData && fileData.url) { - window.open(fileData.url, '_blank'); - } - }} - isReadOnly={false} - /> - -
- - - {/* Sparepart Selection */} - - - - - -
- - {/* Save Button */} -
- -
-
- -
- ); -}; - -export default AddEditErrorCode; \ No newline at end of file diff --git a/src/pages/master/brandDevice/EditBrandDevice.jsx b/src/pages/master/brandDevice/EditBrandDevice.jsx index f3402a8..d5190e4 100644 --- a/src/pages/master/brandDevice/EditBrandDevice.jsx +++ b/src/pages/master/brandDevice/EditBrandDevice.jsx @@ -13,17 +13,17 @@ import { Tag, Space, Input, + ConfigProvider } from 'antd'; import { EyeOutlined, EditOutlined, DeleteOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons'; import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif'; import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; -import { getBrandById, getErrorCodesByBrandId, getErrorCodeById, deleteErrorCode, updateErrorCode as updateErrorCodeAPI, createErrorCode as createErrorCodeAPI } from '../../../api/master-brand'; +import { getBrandById, updateBrand, getErrorCodesByBrandId, getErrorCodeById, deleteErrorCode, updateErrorCode as updateErrorCodeAPI, createErrorCode as createErrorCodeAPI } from '../../../api/master-brand'; import { getFileUrl } from '../../../api/file-uploads'; import { SendRequest } from '../../../components/Global/ApiRequest'; import BrandForm from './component/BrandForm'; import ErrorCodeForm from './component/ErrorCodeForm'; import SolutionForm from './component/SolutionForm'; -import FormActions from './component/FormActions'; import SparepartSelect from './component/SparepartSelect'; import ListErrorCode from './component/ListErrorCode'; @@ -57,6 +57,7 @@ const EditBrandDevice = () => { const [solutionTypes, setSolutionTypes] = useState({ 0: 'text' }); const [solutionStatuses, setSolutionStatuses] = useState({ 0: true }); const [currentSolutionData, setCurrentSolutionData] = useState([]); + const [confirmLoading, setConfirmLoading] = useState(false); const getSolutionData = () => { if (!solutionForm) return []; @@ -115,7 +116,7 @@ const EditBrandDevice = () => { const isFileType = solution.type_solution && solution.type_solution !== 'text'; newSolutionTypes[fieldKey] = isFileType ? 'file' : 'text'; - newSolutionStatuses[fieldKey] = solution.is_active !== false; + newSolutionStatuses[fieldKey] = solution.is_active; let fileObject = null; if (isFileType && (solution.path_solution || solution.path_document)) { @@ -135,7 +136,7 @@ const EditBrandDevice = () => { name: solution.solution_name || '', type: isFileType ? 'file' : 'text', text: solution.text_solution || '', - status: solution.is_active !== false, + status: solution.is_active, file: fileObject, fileUpload: fileObject, path_solution: solution.path_solution || solution.path_document || null, @@ -387,17 +388,64 @@ const EditBrandDevice = () => { const handleNextStep = async () => { try { - await brandForm.validateFields(); - const currentBrandId = id; - if (currentBrandId) { - navigate(`/master/brand-device/edit/${currentBrandId}?tab=error-codes`); + setConfirmLoading(true); + + const brandValues = brandForm.getFieldsValue(); + + if (!brandValues.brand_name || brandValues.brand_name.trim() === '') { + NotifAlert({ + icon: 'warning', + title: 'Perhatian', + message: 'Brand Name wajib diisi!', + }); + return; + } + + if (!brandValues.brand_manufacture || brandValues.brand_manufacture.trim() === '') { + NotifAlert({ + icon: 'warning', + title: 'Perhatian', + message: 'Manufacturer wajib diisi!', + }); + return; + } + + const brandApiData = { + brand_name: brandValues.brand_name.trim(), + brand_type: brandValues.brand_type || '', + brand_manufacture: brandValues.brand_manufacture.trim(), + brand_model: brandValues.brand_model || '', + is_active: brandValues.is_active !== undefined ? brandValues.is_active : true + }; + + const response = await updateBrand(id, brandApiData); + + if (response && (response.statusCode === 200 || response.statusCode === 201)) { + NotifOk({ + icon: 'success', + title: 'Berhasil', + message: 'Brand device berhasil diupdate.', + }); + + const currentBrandId = id; + if (currentBrandId) { + navigate(`/master/brand-device/edit/${currentBrandId}?tab=error-codes`); + } + } else { + NotifAlert({ + icon: 'error', + title: 'Gagal', + message: response?.message || 'Gagal mengupdate brand device', + }); } } catch (error) { NotifAlert({ - icon: 'warning', - title: 'Perhatian', - message: 'Harap isi semua kolom wajib untuk brand device!', + icon: 'error', + title: 'Gagal', + message: error.message || 'Gagal mengupdate brand device', }); + } finally { + setConfirmLoading(false); } }; @@ -433,6 +481,7 @@ const EditBrandDevice = () => { const handleSaveErrorCode = async () => { try { + setConfirmLoading(true); const errorCodeValues = await errorCodeForm.validateFields(); const solutionData = getSolutionData(); @@ -542,6 +591,8 @@ const EditBrandDevice = () => { title: 'Perhatian', message: error.message || 'Harap isi semua kolom wajib!', }); + } finally { + setConfirmLoading(false); } }; @@ -1165,6 +1216,7 @@ const EditBrandDevice = () => { type="primary" size="large" onClick={handleSaveErrorCode} + loading={confirmLoading} style={{ backgroundColor: '#23A55A', borderColor: '#23A55A', @@ -1197,13 +1249,23 @@ const EditBrandDevice = () => { }; return ( - - - - - - {renderStepContent()} - + + + + + + + {renderStepContent()} +
{currentStep === 1 && ( @@ -1220,7 +1282,7 @@ const EditBrandDevice = () => {
-
+
+ ); }; diff --git a/src/pages/master/brandDevice/component/FormActions.jsx b/src/pages/master/brandDevice/component/FormActions.jsx deleted file mode 100644 index e3f8280..0000000 --- a/src/pages/master/brandDevice/component/FormActions.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import { Button, ConfigProvider } from 'antd'; -import { ArrowLeftOutlined } from '@ant-design/icons'; - -const FormActions = ({ - currentStep, - onPreviousStep, - onNextStep, - onSave, - onCancel, - confirmLoading, - isEditMode = false, - showCancelButton = true -}) => { - return ( -
- - {showCancelButton && ( - - )} - {currentStep > 0 && ( - - )} - - - - {currentStep < 1 && ( - - )} - {currentStep === 1 && ( - - )} - -
- ); -}; - -export default FormActions; \ No newline at end of file