diff --git a/src/pages/master/brandDevice/AddBrandDevice.jsx b/src/pages/master/brandDevice/AddBrandDevice.jsx
index c43345d..2bdde88 100644
--- a/src/pages/master/brandDevice/AddBrandDevice.jsx
+++ b/src/pages/master/brandDevice/AddBrandDevice.jsx
@@ -1,4 +1,4 @@
-import { useEffect, useState, useCallback, useMemo } from 'react';
+import { useEffect, useState } from 'react';
import { useNavigate, useParams, useSearchParams, useLocation } from 'react-router-dom';
import {
Divider,
@@ -13,7 +13,10 @@ import {
Space,
ConfigProvider,
} from 'antd';
-import { EyeOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
+import {
+ 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';
@@ -55,8 +58,6 @@ const AddBrandDevice = () => {
const [solutionStatuses, setSolutionStatuses] = useState({ 0: true });
const [currentSolutionData, setCurrentSolutionData] = useState([]);
const [confirmLoading, setConfirmLoading] = useState(false);
- const [currentPage, setCurrentPage] = useState(1);
- const [pageSize, setPageSize] = useState(10);
const [temporaryBrandId, setTemporaryBrandId] = useState(null);
const [isTemporaryBrand, setIsTemporaryBrand] = useState(false);
const [isAddingNewErrorCode, setIsAddingNewErrorCode] = useState(false);
@@ -65,16 +66,35 @@ const AddBrandDevice = () => {
if (!solutionForm) return [];
try {
const values = solutionForm.getFieldsValue(true);
+ const solutions = [];
- let solutions = [];
+ solutionFields.forEach(fieldKey => {
+ let solution = null;
- if (values.solution_items) {
- if (Array.isArray(values.solution_items)) {
- solutions = values.solution_items.filter(Boolean);
- } else if (typeof values.solution_items === 'object') {
- solutions = Object.values(values.solution_items).filter(Boolean);
+ if (values.solution_items && values.solution_items[fieldKey]) {
+ solution = values.solution_items[fieldKey];
}
- }
+
+ if (!solution || !solution.name || solution.name.trim() === '') {
+ return;
+ }
+
+ const solutionType = solutionTypes[fieldKey] || solution.type || 'text';
+ let isValid = true;
+
+ if (solutionType === 'text') {
+ isValid = solution.text && solution.text.trim() !== '';
+ } else if (solutionType === 'file') {
+ const hasPathSolution = solution.path_solution && solution.path_solution.trim() !== '';
+ const hasFileUpload = (solution.fileUpload && typeof solution.fileUpload === 'object' && Object.keys(solution.fileUpload).length > 0);
+ const hasFile = (solution.file && typeof solution.file === 'object' && Object.keys(solution.file).length > 0);
+ isValid = hasPathSolution || hasFileUpload || hasFile;
+ }
+
+ if (isValid) {
+ solutions.push(solution);
+ }
+ });
return solutions;
} catch (error) {
@@ -83,26 +103,27 @@ const AddBrandDevice = () => {
};
const resetSolutionFields = () => {
- if (solutionForm && solutionForm.resetFields) {
- solutionForm.resetFields();
- solutionForm.setFieldsValue({
- solution_items: {
- 0: {
- name: '',
- type: 'text',
- text: '',
- status: true,
- fileUpload: null,
- file: null,
- path_solution: null,
- fileName: null
- }
- }
- });
- }
setSolutionFields([0]);
setSolutionTypes({ 0: 'text' });
setSolutionStatuses({ 0: true });
+
+ if (solutionForm && solutionForm.resetFields) {
+ solutionForm.resetFields();
+ setTimeout(() => {
+ solutionForm.setFieldsValue({
+ solution_items: {
+ 0: {
+ name: '',
+ type: 'text',
+ text: '',
+ status: true,
+ file: null,
+ fileUpload: null
+ }
+ }
+ });
+ }, 100);
+ }
setCurrentSolutionData([]);
};
@@ -300,7 +321,8 @@ const AddBrandDevice = () => {
const loadErrorCodeData = (record) => {
setIsErrorCodeFormReadOnly(false);
- setEditingErrorCodeKey(record.error_code_id);
+ const editingKey = record.tempId || `existing_${record.error_code_id}`;
+ setEditingErrorCodeKey(editingKey);
errorCodeForm.setFieldsValue({
error_code: record.error_code,
@@ -327,49 +349,6 @@ const AddBrandDevice = () => {
}
};
- const handleEditErrorCode = (record) => {
- loadErrorCodeData(record);
- };
-
- const handleDeleteErrorCode = (record) => {
- NotifConfirmDialog({
- icon: 'question',
- title: 'Konfirmasi Hapus',
- message: `Apakah Anda yakin ingin menghapus error code "${record.error_code}"?`,
- onConfirm: async () => {
- try {
- const errorCodeToDelete = record.error_code_id;
- const response = await deleteErrorCode(brandInfo.brand_id || id, errorCodeToDelete);
-
- if (response && (response.statusCode === 200 || response.statusCode === 201)) {
- NotifOk({
- icon: 'success',
- title: 'Berhasil',
- message: 'Error code berhasil dihapus!',
- });
- setTrigerFilter(prev => !prev);
- } else {
- NotifAlert({
- icon: 'error',
- title: 'Gagal',
- message: response?.message || 'Gagal menghapus error code',
- });
- }
- } catch (error) {
- NotifAlert({
- icon: 'error',
- title: 'Gagal',
- message: error.message || 'Gagal menghapus error code',
- });
- }
- },
- onCancel: () => { }
- });
- };
-
- const handlePreviewErrorCode = (record) => {
- };
-
const handleSearch = () => {
setSearchText(searchValue);
setTrigerFilter((prev) => !prev);
@@ -381,154 +360,7 @@ const AddBrandDevice = () => {
setTrigerFilter((prev) => !prev);
};
- const handleBrandFormValuesChange = useCallback((changedValues, allValues) => {
- }, []);
- const getErrorCodesData = async (params) => {
- try {
- const search = params.get('search') || '';
- const page = parseInt(params.get('page')) || currentPage;
- const limit = parseInt(params.get('limit')) || pageSize;
-
- let allErrorCodes = [];
- let paginationData = {
- current_page: page,
- current_limit: limit,
- total_limit: 0,
- total_page: 0,
- };
-
- if (brandInfo.brand_id) {
- const queryParams = new URLSearchParams({
- page: page.toString(),
- limit: limit.toString(),
- ...(search && { search })
- });
-
- const response = await getErrorCodesByBrandId(brandInfo.brand_id, queryParams);
- if (response && response.statusCode === 200) {
- const apiErrorData = response.data || [];
- allErrorCodes = apiErrorData.map(ec => ({
- ...ec,
- tempId: `existing_${ec.error_code_id}`,
- status: 'existing'
- }));
-
- if (response.paging) {
- paginationData = {
- current_page: response.paging.current_page || page,
- current_limit: response.paging.current_limit || limit,
- total_limit: response.paging.total_limit || 0,
- total_page: response.paging.total_page || 0,
- };
- }
- }
- }
-
- allErrorCodes = [...allErrorCodes, ...tempErrorCodes.filter(ec => ec.status !== 'deleted')];
-
- if (searchText) {
- allErrorCodes = allErrorCodes.filter(ec =>
- ec.error_code.toLowerCase().includes(searchText.toLowerCase()) ||
- ec.error_code_name.toLowerCase().includes(searchText.toLowerCase())
- );
- paginationData.total_limit = allErrorCodes.length;
- paginationData.total_page = Math.ceil(allErrorCodes.length / limit);
- }
-
- return {
- data: allErrorCodes,
- paging: paginationData
- };
- } catch (error) {
- return {
- data: [],
- paging: {
- current_page: 1,
- current_limit: pageSize,
- total_limit: 0,
- total_page: 0,
- }
- };
- }
- };
-
- const errorCodeColumns = (showPreviewModal, showEditModal, showDeleteDialog) => [
- {
- title: 'No',
- key: 'no',
- width: '5%',
- align: 'center',
- render: (_, __, index) => index + 1,
- },
- {
- title: 'Error Code',
- dataIndex: 'error_code',
- key: 'error_code',
- width: '20%',
- render: (text, record) => (
-
- {text}
-
- ),
- },
- {
- title: 'Error Name',
- dataIndex: 'error_code_name',
- key: 'error_code_name',
- width: '25%',
- },
- {
- title: 'Description',
- dataIndex: 'error_code_description',
- key: 'error_code_description',
- width: '30%',
- ellipsis: true,
- },
- {
- title: 'Actions',
- key: 'actions',
- width: '20%',
- render: (_, record) => (
-
- }
- onClick={() => showPreviewModal(record)}
- size="small"
- />
- }
- onClick={() => showEditModal(record)}
- size="small"
- />
- }
- onClick={() => showDeleteDialog(record)}
- size="small"
- />
-
- ),
- },
- ];
-
- const queryParams = useMemo(() => {
- const params = new URLSearchParams();
- params.set('page', currentPage.toString());
- params.set('limit', pageSize.toString());
- if (searchValue) {
- params.set('search', searchValue);
- }
- return params;
- }, [searchValue, currentPage, pageSize]);
-
- const handlePaginationChange = (page, size) => {
- setCurrentPage(page);
- setPageSize(size);
- };
const resetErrorCodeForm = () => {
errorCodeForm.resetFields();
@@ -763,7 +595,6 @@ const AddBrandDevice = () => {
)}
diff --git a/src/pages/master/brandDevice/EditBrandDevice.jsx b/src/pages/master/brandDevice/EditBrandDevice.jsx
index c836527..e41dfe8 100644
--- a/src/pages/master/brandDevice/EditBrandDevice.jsx
+++ b/src/pages/master/brandDevice/EditBrandDevice.jsx
@@ -1,4 +1,4 @@
-import { useEffect, useState, useCallback, useMemo } from 'react';
+import { useEffect, useState } from 'react';
import { useNavigate, useParams, useSearchParams, useLocation } from 'react-router-dom';
import {
Divider,
@@ -15,10 +15,9 @@ import {
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, updateBrand, getErrorCodesByBrandId, getErrorCodeById, deleteErrorCode, updateErrorCode as updateErrorCodeAPI, createErrorCode as createErrorCodeAPI } from '../../../api/master-brand';
+import { getBrandById, updateBrand, getErrorCodesByBrandId, 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';
@@ -63,16 +62,35 @@ const EditBrandDevice = () => {
if (!solutionForm) return [];
try {
const values = solutionForm.getFieldsValue(true);
+ const solutions = [];
- let solutions = [];
+ solutionFields.forEach(fieldKey => {
+ let solution = null;
- if (values.solution_items) {
- if (Array.isArray(values.solution_items)) {
- solutions = values.solution_items.filter(Boolean);
- } else if (typeof values.solution_items === 'object') {
- solutions = Object.values(values.solution_items).filter(Boolean);
+ if (values.solution_items && values.solution_items[fieldKey]) {
+ solution = values.solution_items[fieldKey];
}
- }
+
+ if (!solution || !solution.name || solution.name.trim() === '') {
+ return;
+ }
+
+ const solutionType = solutionTypes[fieldKey] || solution.type || 'text';
+ let isValid = true;
+
+ if (solutionType === 'text') {
+ isValid = solution.text && solution.text.trim() !== '';
+ } else if (solutionType === 'file') {
+ const hasPathSolution = solution.path_solution && solution.path_solution.trim() !== '';
+ const hasFileUpload = (solution.fileUpload && typeof solution.fileUpload === 'object' && Object.keys(solution.fileUpload).length > 0);
+ const hasFile = (solution.file && typeof solution.file === 'object' && Object.keys(solution.file).length > 0);
+ isValid = hasPathSolution || hasFileUpload || hasFile;
+ }
+
+ if (isValid) {
+ solutions.push(solution);
+ }
+ });
return solutions;
} catch (error) {
@@ -81,18 +99,26 @@ const EditBrandDevice = () => {
};
const resetSolutionFields = () => {
+ setSolutionFields([0]);
+ setSolutionTypes({ 0: 'text' });
+ setSolutionStatuses({ 0: true });
+
if (solutionForm && solutionForm.resetFields) {
solutionForm.resetFields();
- solutionForm.setFieldsValue({
- solution_items: {
- 0: {
- name: '',
- type: 'text',
- text: '',
- status: true
+ setTimeout(() => {
+ solutionForm.setFieldsValue({
+ solution_items: {
+ 0: {
+ name: '',
+ type: 'text',
+ text: '',
+ status: true,
+ file: null,
+ fileUpload: null
+ }
}
- }
- });
+ });
+ }, 100);
}
setCurrentSolutionData([]);
};
@@ -344,47 +370,9 @@ const EditBrandDevice = () => {
}
}, [location, navigate]);
- const addErrorCode = (newErrorCode) => {
- const uniqueId = `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
- const errorCodeWithId = {
- ...newErrorCode,
- tempId: uniqueId,
- status: 'new'
- };
- setTempErrorCodes(prev => [...prev, errorCodeWithId]);
- };
- const updateErrorCode = (tempId, updatedData) => {
- setTempErrorCodes(prev =>
- prev.map(ec => ec.tempId === tempId ? { ...ec, ...updatedData, status: 'modified' } : ec)
- );
- setExistingErrorCodes(prev =>
- prev.map(ec => ec.tempId === tempId ? { ...ec, ...updatedData, status: 'modified' } : ec)
- );
- };
- const deleteLocalErrorCode = (tempId, permanent = false) => {
- if (permanent) {
- setTempErrorCodes(prev => prev.filter(ec => ec.tempId !== tempId));
- setExistingErrorCodes(prev => prev.filter(ec => ec.tempId !== tempId));
- } else {
- setTempErrorCodes(prev =>
- prev.map(ec => ec.tempId === tempId ? { ...ec, status: 'deleted' } : ec)
- );
- setExistingErrorCodes(prev =>
- prev.map(ec => ec.tempId === tempId ? { ...ec, status: 'deleted' } : ec)
- );
- }
- };
-
- const getErrorCodeById = (tempId) => {
- const inTemp = tempErrorCodes.find(ec => ec.tempId === tempId);
- if (inTemp) return inTemp;
-
- const inExisting = existingErrorCodes.find(ec => ec.tempId === tempId);
- return inExisting;
- };
const handleNextStep = async () => {
try {
@@ -454,6 +442,7 @@ const EditBrandDevice = () => {
};
+
const handleErrorCodeIconUpload = (iconData) => {
setErrorCodeIcon(iconData);
};
@@ -474,11 +463,6 @@ const EditBrandDevice = () => {
setSelectedSparepartIds([]);
};
- const handleCreateNewErrorCode = () => {
- resetErrorCodeForm();
- setCurrentSolutionData([]);
- };
-
const handleSaveErrorCode = async () => {
try {
setConfirmLoading(true);
@@ -566,16 +550,6 @@ const EditBrandDevice = () => {
message: editingErrorCodeKey ? 'Error code berhasil diupdate!' : 'Error code berhasil ditambahkan!',
});
-
- setTempErrorCodes(prev => prev.filter(ec => {
-
- if (ec.status === 'existing' || ec.tempId.startsWith('existing_')) {
- return true;
- }
-
- return ec.tempId !== editingErrorCodeKey;
- }));
-
setTrigerFilter(prev => !prev);
resetErrorCodeForm();
} else {
@@ -627,157 +601,6 @@ const EditBrandDevice = () => {
}
};
- const handlePreviewErrorCode = (record) => {
- const errorCode = getErrorCodeById(record.tempId || record.error_code_id);
- loadErrorCodeData(errorCode, true);
- };
-
- const handleEditErrorCode = (record) => {
- const errorCode = getErrorCodeById(record.tempId || record.error_code_id);
- loadErrorCodeData(errorCode, false);
- };
-
-
- const handleDeleteErrorCode = async (record) => {
- NotifConfirmDialog({
- icon: 'question',
- title: 'Konfirmasi Hapus',
- message: `Apakah Anda yakin ingin menghapus error code "${record.error_code}"?`,
- onConfirm: async () => {
- try {
- if (record.status === 'existing' && record.error_code_id) {
- const response = await deleteErrorCode(id, record.error_code_id);
- if (response && response.statusCode === 200) {
- NotifOk({
- icon: 'success',
- title: 'Berhasil',
- message: 'Error code berhasil dihapus!',
- });
- setTrigerFilter(prev => !prev);
- } else {
- NotifAlert({
- icon: 'error',
- title: 'Error',
- message: response?.message || 'Failed to delete error code',
- });
- }
- } else {
- const tempId = record.tempId;
- deleteLocalErrorCode(tempId, true);
- NotifOk({
- icon: 'success',
- title: 'Berhasil',
- message: 'Error code berhasil dihapus!',
- });
- setTrigerFilter(prev => !prev);
- }
- } catch (error) {
- NotifAlert({
- icon: 'error',
- title: 'Error',
- message: error.message || 'Failed to delete error code',
- });
- }
- },
- onCancel: () => { }
- });
- };
-
- const mergedErrorCodes = useMemo(() => {
- const allErrorCodes = [
- ...existingErrorCodes.map(ec => ({ ...ec, status: 'existing' })),
- ...tempErrorCodes
- ];
-
- const activeErrorCodes = allErrorCodes.filter(ec => ec.status !== 'deleted');
-
- if (searchText) {
- return activeErrorCodes.filter(ec =>
- ec.error_code.toLowerCase().includes(searchText.toLowerCase()) ||
- ec.error_code_name.toLowerCase().includes(searchText.toLowerCase())
- );
- }
-
- return activeErrorCodes;
- }, [existingErrorCodes, tempErrorCodes, searchText]);
-
- const errorCodeColumns = (showPreviewModal, showEditModal, showDeleteDialog) => [
- {
- title: 'No',
- key: 'no',
- width: '5%',
- align: 'center',
- render: (_, __, index) => index + 1,
- },
- {
- title: 'Error Code',
- dataIndex: 'error_code',
- key: 'error_code',
- width: '20%',
- render: (text, record) => (
-
- {text}
-
- ),
- },
- {
- title: 'Error Name',
- dataIndex: 'error_code_name',
- key: 'error_code_name',
- width: '25%',
- },
- {
- title: 'Status',
- dataIndex: 'is_active',
- key: 'is_active',
- width: '10%',
- align: 'center',
- render: (_, { is_active }) => (
-
- {is_active ? 'Active' : 'Inactive'}
-
- ),
- },
- {
- title: 'Action',
- key: 'action',
- align: 'center',
- width: '15%',
- render: (_, record) => (
-
- }
- onClick={() => showPreviewModal(record)}
- style={{
- color: '#1890ff',
- borderColor: '#1890ff',
- }}
- />
- }
- onClick={() => showEditModal(record)}
- style={{
- color: '#faad14',
- borderColor: '#faad14',
- }}
- />
- }
- onClick={() => showDeleteDialog(record)}
- style={{
- borderColor: '#ff4d4f',
- }}
- />
-
- ),
- },
- ];
-
- const handleBrandFormValuesChange = useCallback((changedValues, allValues) => {
- setBrandInfo(allValues);
- }, [setBrandInfo]);
-
const handleSearch = () => {
setTrigerFilter((prev) => !prev);
};
@@ -787,113 +610,6 @@ const EditBrandDevice = () => {
setTrigerFilter((prev) => !prev);
};
- const getErrorCodesData = async (params) => {
- try {
- const criteria = params.get('criteria') || '';
- const page = parseInt(params.get('page')) || 1;
- const limit = parseInt(params.get('limit')) || 10;
- const currentBrandId = id;
-
- if (!currentBrandId) {
- return {
- data: [],
- pagination: {
- current_page: page,
- current_limit: limit,
- total_limit: 0,
- total_page: 0,
- }
- };
- }
-
- const queryParams = new URLSearchParams({
- page: page.toString(),
- limit: limit.toString(),
- ...(criteria && { criteria })
- });
-
- const response = await getErrorCodesByBrandId(currentBrandId, queryParams);
-
- if (response && response.statusCode === 200) {
- const apiData = response.data || [];
-
- const contextExistingMap = new Map();
- existingErrorCodes.forEach(ec => {
- if (ec.status === 'modified' || ec.status === 'deleted') {
- contextExistingMap.set(ec.error_code_id, ec);
- }
- });
-
- const existingCodes = apiData.map(ec => {
- const contextModified = contextExistingMap.get(ec.error_code_id);
- if (contextModified) {
- return {
- ...contextModified,
- tempId: `existing_${ec.error_code_id}`,
- solution: contextModified.solution || ec.solution || [],
- spareparts: contextModified.spareparts || ec.spareparts || []
- };
- } else {
- return {
- ...ec,
- tempId: `existing_${ec.error_code_id}`,
- status: 'existing',
- solution: ec.solution || [],
- spareparts: ec.spareparts || []
- };
- }
- });
-
- const activeExistingCodes = existingCodes.filter(ec => ec.status !== 'deleted');
-
- const allErrorCodes = [...activeExistingCodes, ...tempErrorCodes.filter(ec => ec.status !== 'deleted')];
-
- let filteredData = allErrorCodes;
-
- if (search) {
- filteredData = allErrorCodes.filter(ec =>
- ec.error_code.toLowerCase().includes(search.toLowerCase()) ||
- ec.error_code_name.toLowerCase().includes(search.toLowerCase())
- );
- }
-
- const startIndex = 0;
- const endIndex = startIndex + limit;
- const paginatedData = filteredData.slice(startIndex, endIndex);
-
- return {
- data: paginatedData,
- pagination: {
- current_page: page,
- current_limit: limit,
- total_limit: filteredData.length,
- total_page: Math.ceil(filteredData.length / limit),
- }
- };
- }
-
- return {
- data: [],
- pagination: {
- current_page: page,
- current_limit: limit,
- total_limit: 0,
- total_page: 0,
- }
- };
- } catch (error) {
- return {
- data: [],
- pagination: {
- current_page: 1,
- current_limit: 10,
- total_limit: 0,
- total_page: 0,
- }
- };
- }
- };
-
const renderStepContent = () => {
if (currentStep === 0) {
return (
@@ -919,7 +635,6 @@ const EditBrandDevice = () => {
)}
@@ -1186,7 +901,10 @@ const EditBrandDevice = () => {
{editingErrorCodeKey && (