diff --git a/src/pages/master/brandDevice/AddBrandDevice.jsx b/src/pages/master/brandDevice/AddBrandDevice.jsx
index cec0645..5d368ad 100644
--- a/src/pages/master/brandDevice/AddBrandDevice.jsx
+++ b/src/pages/master/brandDevice/AddBrandDevice.jsx
@@ -1,14 +1,19 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
-import { Divider, Typography, Button, Steps, Form, Row, Col, Card } from 'antd';
+import { Divider, Typography, Button, Steps, Form, Row, Col, Card, ConfigProvider } from 'antd';
import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif';
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
import { createBrand } from '../../../api/master-brand';
import BrandForm from './component/BrandForm';
import ErrorCodeForm from './component/ErrorCodeForm';
+import ErrorCodeSimpleForm from './component/ErrorCodeSimpleForm';
import ErrorCodeTable from './component/ListErrorCode';
+import ErrorCodeListModal from './component/ErrorCodeListModal';
import FormActions from './component/FormActions';
-import { useErrorCodeLogic } from './hooks/errorCode';
+import SparepartForm from './component/SparepartForm';
+import SolutionForm from './component/SolutionForm';
+import { useSolutionLogic } from './hooks/solution';
+import { useSparepartLogic } from './hooks/sparepart';
import { uploadFile, getFolderFromFileType } from '../../../api/file-uploads';
const { Title } = Typography;
@@ -28,6 +33,8 @@ const AddBrandDevice = () => {
const { setBreadcrumbItems } = useBreadcrumb();
const [brandForm] = Form.useForm();
const [errorCodeForm] = Form.useForm();
+ const [solutionForm] = Form.useForm();
+ const [sparepartForm] = Form.useForm();
const [confirmLoading, setConfirmLoading] = useState(false);
const [currentStep, setCurrentStep] = useState(0);
const [fileList, setFileList] = useState([]);
@@ -37,21 +44,53 @@ const AddBrandDevice = () => {
const [formData, setFormData] = useState(defaultData);
const [errorCodes, setErrorCodes] = useState([]);
const [errorCodeIcon, setErrorCodeIcon] = useState(null);
+ const [showErrorCodeModal, setShowErrorCodeModal] = useState(false);
+ const [sparepartImages, setSparepartImages] = useState({});
const {
solutionFields,
solutionTypes,
solutionStatuses,
- firstSolutionValid,
solutionsToDelete,
+ firstSolutionValid,
handleAddSolutionField,
handleRemoveSolutionField,
handleSolutionTypeChange,
handleSolutionStatusChange,
resetSolutionFields,
checkFirstSolutionValid,
+ getSolutionData,
setSolutionsForExistingRecord,
- } = useErrorCodeLogic(errorCodeForm, fileList);
+ } = useSolutionLogic(solutionForm);
+
+ const {
+ sparepartFields,
+ sparepartTypes,
+ sparepartStatuses,
+ handleAddSparepartField,
+ handleRemoveSparepartField,
+ handleSparepartTypeChange,
+ handleSparepartStatusChange,
+ resetSparepartFields,
+ getSparepartData,
+ setSparepartForExistingRecord,
+ } = useSparepartLogic(sparepartForm);
+
+ // Handlers for sparepart image upload
+ const handleSparepartImageUpload = (fieldKey, imageData) => {
+ setSparepartImages(prev => ({
+ ...prev,
+ [fieldKey]: imageData
+ }));
+ };
+
+ const handleSparepartImageRemove = (fieldKey) => {
+ setSparepartImages(prev => {
+ const newImages = { ...prev };
+ delete newImages[fieldKey];
+ return newImages;
+ });
+ };
useEffect(() => {
setBreadcrumbItems([
@@ -96,6 +135,17 @@ const AddBrandDevice = () => {
const handleFinish = async () => {
setConfirmLoading(true);
try {
+ // Validation: Ensure at least one error code
+ if (errorCodes.length === 0) {
+ NotifAlert({
+ icon: 'warning',
+ title: 'Perhatian',
+ message: 'Setidaknya tambahkan 1 error code!',
+ });
+ setConfirmLoading(false);
+ return;
+ }
+
const transformedErrorCodes = errorCodes.map((ec) => ({
error_code: ec.error_code,
error_code_name: ec.error_code_name || '',
@@ -110,6 +160,13 @@ const AddBrandDevice = () => {
path_solution: sol.path_solution || '',
is_active: sol.is_active !== false,
})),
+ // Note: Sparepart data is collected but not sent to backend yet
+ // sparepart: (ec.sparepart || []).map((sp) => ({
+ // type: sp.type || 'required',
+ // name: sp.name || '',
+ // quantity: sp.quantity || 1,
+ // is_active: sp.is_active !== false,
+ // })),
}));
const finalFormData = {
@@ -118,30 +175,11 @@ const AddBrandDevice = () => {
brand_model: formData.brand_model || '',
brand_manufacture: formData.brand_manufacture,
is_active: formData.is_active,
- error_code:
- transformedErrorCodes.length > 0
- ? transformedErrorCodes
- : [
- {
- error_code: 'DEFAULT',
- error_code_name: 'Default Error Code',
- error_code_description: 'Default error description',
- error_code_color: '#000000',
- path_icon: '',
- is_active: true,
- solution: [
- {
- solution_name: 'Default Solution',
- type_solution: 'text',
- text_solution: 'Default solution text',
- path_solution: '',
- is_active: true,
- },
- ],
- },
- ],
+ error_code: transformedErrorCodes,
};
+ console.log('Final form data:', finalFormData); // Debug log
+
const response = await createBrand(finalFormData);
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
@@ -159,6 +197,7 @@ const AddBrandDevice = () => {
});
}
} catch (error) {
+ console.error('Finish Error:', error);
NotifAlert({
icon: 'error',
title: 'Gagal',
@@ -183,17 +222,26 @@ const AddBrandDevice = () => {
setEditingErrorCodeKey(null);
if (record.solution && record.solution.length > 0) {
- setSolutionsForExistingRecord(record.solution, errorCodeForm);
+ setSolutionsForExistingRecord(record.solution, solutionForm);
+ }
+
+ if (record.sparepart && record.sparepart.length > 0) {
+ setSparepartForExistingRecord(record.sparepart, sparepartForm);
}
};
const handleEditErrorCode = (record) => {
+ // Prevent infinite loop
+ if (editingErrorCodeKey === record.key) {
+ return;
+ }
+
errorCodeForm.setFieldsValue({
error_code: record.error_code,
error_code_name: record.error_code_name,
error_code_description: record.error_code_description,
- error_code_color: record.error_code_color,
- status: record.status,
+ error_code_color: record.error_code_color || '#000000',
+ status: record.status !== false,
});
setFileList(record.fileList || []);
setErrorCodeIcon(record.errorCodeIcon || null);
@@ -201,38 +249,102 @@ const AddBrandDevice = () => {
setEditingErrorCodeKey(record.key);
if (record.solution && record.solution.length > 0) {
- setSolutionsForExistingRecord(record.solution, errorCodeForm);
+ // Reset solution fields first
+ resetSolutionFields();
+ // Then load new solutions
+ setTimeout(() => {
+ setSolutionsForExistingRecord(record.solution, solutionForm);
+ }, 0);
+ } else {
+ resetSolutionFields();
+ }
+
+ if (record.sparepart && record.sparepart.length > 0) {
+ // Reset sparepart fields first
+ resetSparepartFields();
+ // Then load new spareparts
+ setTimeout(() => {
+ setSparepartForExistingRecord(record.sparepart, sparepartForm);
+ }, 0);
+ } else {
+ resetSparepartFields();
}
};
- const handleAddErrorCode = async (newErrorCode) => {
- // Include the current icon in the error code
- const errorCodeWithIcon = {
- ...newErrorCode,
- errorCodeIcon: errorCodeIcon
- };
+ const handleAddErrorCode = async () => {
+ try {
+ const formValues = errorCodeForm.getFieldsValue();
- if (editingErrorCodeKey) {
- const updatedCodes = errorCodes.map((item) =>
- item.key === editingErrorCodeKey ? errorCodeWithIcon : item
- );
- setErrorCodes(updatedCodes);
- NotifOk({
- icon: 'success',
- title: 'Berhasil',
- message: 'Error code berhasil diupdate!',
- });
- } else {
- const updatedCodes = [...errorCodes, errorCodeWithIcon];
- setErrorCodes(updatedCodes);
- NotifOk({
- icon: 'success',
- title: 'Berhasil',
- message: 'Error code berhasil ditambahkan!',
+ // Validation
+ if (!formValues.error_code || !formValues.error_code_name) {
+ NotifAlert({
+ icon: 'warning',
+ title: 'Perhatian',
+ message: 'Error code dan error name wajib diisi!',
+ });
+ return;
+ }
+
+ // Validate at least 1 solution
+ const solutions = getSolutionData();
+
+ if (solutions.length === 0) {
+ NotifAlert({
+ icon: 'warning',
+ title: 'Perhatian',
+ message: 'Setiap error code harus memiliki minimal 1 solution!',
+ });
+ return;
+ }
+
+ // Get sparepart data (optional, no backend yet)
+ const spareparts = getSparepartData() || [];
+
+ const newErrorCode = {
+ key: Date.now(),
+ error_code: formValues.error_code,
+ error_code_name: formValues.error_code_name || '',
+ error_code_description: formValues.error_code_description || '',
+ error_code_color: formValues.error_code_color || '#000000',
+ path_icon: errorCodeIcon?.uploadPath || '',
+ status: formValues.status !== false,
+ errorCodeIcon: errorCodeIcon,
+ solution: solutions,
+ sparepart: spareparts,
+ };
+
+ if (editingErrorCodeKey) {
+ const updatedCodes = errorCodes.map((item) =>
+ item.key === editingErrorCodeKey ? newErrorCode : item
+ );
+ setErrorCodes(updatedCodes);
+ NotifOk({
+ icon: 'success',
+ title: 'Berhasil',
+ message: 'Error code berhasil diupdate!',
+ });
+ } else {
+ const updatedCodes = [...errorCodes, newErrorCode];
+ setErrorCodes(updatedCodes);
+ NotifOk({
+ icon: 'success',
+ title: 'Berhasil',
+ message: 'Error code berhasil ditambahkan!',
+ });
+ }
+
+ // Reset all forms
+ resetErrorCodeForm();
+ resetSolutionFields();
+ resetSparepartFields();
+ } catch (error) {
+ console.error('Error adding error code:', error);
+ NotifAlert({
+ icon: 'error',
+ title: 'Error',
+ message: 'Gagal menambahkan error code',
});
}
-
- resetErrorCodeForm();
};
const resetErrorCodeForm = () => {
@@ -366,62 +478,132 @@ const AddBrandDevice = () => {
if (currentStep === 1) {
return (
-
-
-
- {isErrorCodeFormReadOnly
- ? 'View Error Code'
- : editingErrorCodeKey
- ? 'Edit Error Code'
- : 'Tambah Error Code'}
-
-
-
-
-
-
-
+ <>
+
+ {/* Error Code Form Column */}
+
+
+
+
+
+
+ {/* Solution Form Column */}
+
+
+
+
+
+
+ {/* Sparepart Form Column */}
+
+
+
+
+
+
+
+ {/* Error Codes List Button */}
+
+
+
+
+
+
+
+
+ {/* Error Codes List Modal */}
+ setShowErrorCodeModal(false)}
+ errorCodes={errorCodes}
+ loading={loading}
+ onPreview={handlePreviewErrorCode}
+ onEdit={handleEditErrorCode}
+ onDelete={handleDeleteErrorCode}
+ onAddNew={handleCreateNewErrorCode}
+ />
+ >
);
}
return null;
@@ -434,7 +616,7 @@ const AddBrandDevice = () => {
-
+
{renderStepContent()}
diff --git a/src/pages/master/brandDevice/EditBrandDevice.jsx b/src/pages/master/brandDevice/EditBrandDevice.jsx
index c379b98..b0e392e 100644
--- a/src/pages/master/brandDevice/EditBrandDevice.jsx
+++ b/src/pages/master/brandDevice/EditBrandDevice.jsx
@@ -1,15 +1,19 @@
import { useEffect, useState } from 'react';
import { useNavigate, useParams, useLocation } from 'react-router-dom';
-import { Divider, Typography, Button, Steps, Form, Row, Col, Card, Spin, Modal } from 'antd';
+import { Divider, Typography, Button, Steps, Form, Row, Col, Card, Spin, Modal, ConfigProvider } from 'antd';
import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif';
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
import { getBrandById, updateBrand } from '../../../api/master-brand';
import { getFileUrl } from '../../../api/file-uploads';
import BrandForm from './component/BrandForm';
-import ErrorCodeForm from './component/ErrorCodeForm';
-import ErrorCodeTable from './component/ListErrorCode';
+import ErrorCodeSimpleForm from './component/ErrorCodeSimpleForm';
+import SolutionForm from './component/SolutionForm';
+import SparepartForm from './component/SparepartForm';
+import ErrorCodeListModal from './component/ErrorCodeListModal';
import FormActions from './component/FormActions';
import { useErrorCodeLogic } from './hooks/errorCode';
+import { useSolutionLogic } from './hooks/solution';
+import { useSparepartLogic } from './hooks/sparepart';
const { Title } = Typography;
const { Step } = Steps;
@@ -39,21 +43,59 @@ const EditBrandDevice = () => {
const [formData, setFormData] = useState(defaultData);
const [errorCodes, setErrorCodes] = useState([]);
const [errorCodeIcon, setErrorCodeIcon] = useState(null);
+ const [showErrorCodeModal, setShowErrorCodeModal] = useState(false);
+ const [sparepartImages, setSparepartImages] = useState({});
+ const [solutionForm] = Form.useForm();
+ const [sparepartForm] = Form.useForm();
+
+ const {
+ errorCodeFields,
+ addErrorCode,
+ removeErrorCode,
+ editErrorCode,
+ } = useErrorCodeLogic(errorCodeForm, fileList);
const {
solutionFields,
solutionTypes,
solutionStatuses,
- firstSolutionValid,
- solutionsToDelete,
handleAddSolutionField,
handleRemoveSolutionField,
handleSolutionTypeChange,
handleSolutionStatusChange,
resetSolutionFields,
- checkFirstSolutionValid,
+ getSolutionData,
setSolutionsForExistingRecord,
- } = useErrorCodeLogic(errorCodeForm, fileList);
+ } = useSolutionLogic(solutionForm);
+
+ const {
+ sparepartFields,
+ sparepartTypes,
+ sparepartStatuses,
+ handleAddSparepartField,
+ handleRemoveSparepartField,
+ handleSparepartTypeChange,
+ handleSparepartStatusChange,
+ resetSparepartFields,
+ getSparepartData,
+ setSparepartForExistingRecord,
+ } = useSparepartLogic(sparepartForm);
+
+ // Handlers for sparepart image upload
+ const handleSparepartImageUpload = (fieldKey, imageData) => {
+ setSparepartImages(prev => ({
+ ...prev,
+ [fieldKey]: imageData
+ }));
+ };
+
+ const handleSparepartImageRemove = (fieldKey) => {
+ setSparepartImages(prev => {
+ const newImages = { ...prev };
+ delete newImages[fieldKey];
+ return newImages;
+ });
+ };
useEffect(() => {
const fetchBrandData = async () => {
@@ -176,27 +218,65 @@ const EditBrandDevice = () => {
const handleFinish = async () => {
setConfirmLoading(true);
try {
+ // Get current solution and sparepart data from forms
+ const currentSolutionData = getSolutionData();
+ const currentSparepartData = getSparepartData();
+
const finalFormData = {
brand_name: formData.brand_name,
brand_type: formData.brand_type || '',
brand_model: formData.brand_model || '',
brand_manufacture: formData.brand_manufacture,
is_active: formData.is_active,
- error_code: errorCodes.map((ec) => ({
- error_code: ec.error_code,
- error_code_name: ec.error_code_name || '',
- error_code_description: ec.error_code_description || '',
- error_code_color: ec.error_code_color || '#000000',
- path_icon: ec.errorCodeIcon?.uploadPath || ec.path_icon || '',
- is_active: ec.status !== undefined ? ec.status : true,
- solution: (ec.solution || []).map((sol) => ({
- solution_name: sol.solution_name,
- type_solution: sol.type_solution,
- text_solution: sol.text_solution || '',
- path_solution: sol.path_solution || '',
- is_active: sol.is_active !== false,
- })),
- })),
+ error_code: errorCodes.map((ec) => {
+ // If editing current error code, get latest data from forms
+ if (ec.key === editingErrorCodeKey) {
+ return {
+ error_code: ec.error_code,
+ error_code_name: ec.error_code_name || '',
+ error_code_description: ec.error_code_description || '',
+ error_code_color: ec.error_code_color || '#000000',
+ path_icon: ec.errorCodeIcon?.uploadPath || ec.path_icon || '',
+ is_active: ec.status !== undefined ? ec.status : true,
+ solution: currentSolutionData.map((sol) => ({
+ solution_name: sol.solution_name,
+ type_solution: sol.type_solution,
+ text_solution: sol.text_solution || '',
+ path_solution: sol.path_solution || '',
+ is_active: sol.is_active !== false,
+ })),
+ sparepart: currentSparepartData.map((sp) => ({
+ name: sp.name,
+ description: sp.description || '',
+ is_active: sp.is_active !== false,
+ sparepart_image: sparepartImages[sp.key || sp.id] || null,
+ })),
+ };
+ }
+
+ // Return existing data for other error codes
+ return {
+ error_code: ec.error_code,
+ error_code_name: ec.error_code_name || '',
+ error_code_description: ec.error_code_description || '',
+ error_code_color: ec.error_code_color || '#000000',
+ path_icon: ec.errorCodeIcon?.uploadPath || ec.path_icon || '',
+ is_active: ec.status !== undefined ? ec.status : true,
+ solution: (ec.solution || []).map((sol) => ({
+ solution_name: sol.solution_name,
+ type_solution: sol.type_solution,
+ text_solution: sol.text_solution || '',
+ path_solution: sol.path_solution || '',
+ is_active: sol.is_active !== false,
+ })),
+ sparepart: (ec.sparepart || []).map((sp) => ({
+ name: sp.name,
+ description: sp.description || '',
+ is_active: sp.is_active !== false,
+ sparepart_image: sp.sparepart_image || null,
+ })),
+ };
+ }),
};
const response = await updateBrand(id, finalFormData);
@@ -256,8 +336,23 @@ const EditBrandDevice = () => {
setIsErrorCodeFormReadOnly(false);
setEditingErrorCodeKey(record.key);
+ // Load solutions to solution form
if (record.solution && record.solution.length > 0) {
- setSolutionsForExistingRecord(record.solution, errorCodeForm);
+ setSolutionsForExistingRecord(record.solution, solutionForm);
+ }
+
+ // Load spareparts to sparepart form
+ if (record.sparepart && record.sparepart.length > 0) {
+ setSparepartForExistingRecord(record.sparepart, sparepartForm);
+
+ // Load sparepart images
+ const newSparepartImages = {};
+ record.sparepart.forEach(sparepart => {
+ if (sparepart.sparepart_image) {
+ newSparepartImages[sparepart.id || sparepart.key] = sparepart.sparepart_image;
+ }
+ });
+ setSparepartImages(newSparepartImages);
}
const formElement = document.querySelector('.ant-form');
@@ -331,6 +426,12 @@ const EditBrandDevice = () => {
const handleCreateNewErrorCode = () => {
resetErrorCodeForm();
+ resetSolutionFields();
+ resetSparepartFields();
+ setErrorCodeIcon(null);
+ setSparepartImages({});
+ setIsErrorCodeFormReadOnly(false);
+ setEditingErrorCodeKey(null);
};
const handleErrorCodeIconUpload = (iconData) => {
@@ -394,73 +495,142 @@ const EditBrandDevice = () => {
if (currentStep === 1) {
return (
-
-
-
- {isErrorCodeFormReadOnly
- ? editingErrorCodeKey
- ? 'View Error Code'
- : 'Error Code Form'
- : editingErrorCodeKey
- ? 'Edit Error Code'
- : 'Tambah Error Code'}
-
-
-
-
- ({
- key: `loading-${index}`,
- error_code: 'Loading...',
- error_code_name: 'Loading...',
- solution: [],
- }))
- : errorCodes
- }
- loading={loading}
- onPreview={handlePreviewErrorCode}
- onEdit={handleEditErrorCode}
- onDelete={handleDeleteErrorCode}
- onFileView={handleFileView}
- />
-
-
+ <>
+
+
+
+ {isErrorCodeFormReadOnly
+ ? editingErrorCodeKey
+ ? 'View Error Code'
+ : 'Error Code Form'
+ : editingErrorCodeKey
+ ? 'Edit Error Code'
+ : 'Tambah Error Code'}
+
+ }
+ size="small"
+ >
+
+
+
+
+ Solutions}
+ size="small"
+ >
+
+
+
+
+ Spareparts}
+ size="small"
+ >
+
+
+
+
+
+ {/* Error Codes List Button */}
+
+
+
+
+
+
+
+
+ {/* Error Codes List Modal */}
+ setShowErrorCodeModal(false)}
+ errorCodes={errorCodes}
+ loading={loading}
+ onPreview={handlePreviewErrorCode}
+ onEdit={handleEditErrorCode}
+ onDelete={handleDeleteErrorCode}
+ onAddNew={handleCreateNewErrorCode}
+ />
+ >
);
}
return null;