repair: add edit brand device
This commit is contained in:
@@ -19,10 +19,9 @@ import TableList from '../../../components/Global/TableList';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif';
|
||||
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
|
||||
import { createBrand } from '../../../api/master-brand';
|
||||
import { createBrand, createErrorCode, getErrorCodesByBrandId, updateErrorCode, deleteErrorCode } from '../../../api/master-brand';
|
||||
import BrandForm from './component/BrandForm';
|
||||
import { useSolutionLogic } from './hooks/solution';
|
||||
import { useBrandForm } from '../../../context/BrandFormContext';
|
||||
|
||||
const { Title } = Typography;
|
||||
const { Step } = Steps;
|
||||
@@ -32,32 +31,24 @@ const AddBrandDevice = () => {
|
||||
const [searchParams] = useSearchParams();
|
||||
const { setBreadcrumbItems } = useBreadcrumb();
|
||||
const [brandForm] = Form.useForm();
|
||||
const [solutionForm] = Form.useForm();
|
||||
const [errorCodeIcon, setErrorCodeIcon] = useState(null);
|
||||
const [selectedSparepartIds, setSelectedSparepartIds] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [confirmLoading, setConfirmLoading] = useState(false);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [searchText, setSearchText] = useState('');
|
||||
const [trigerFilter, setTrigerFilter] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
const [createdBrandId, setCreatedBrandId] = useState(null);
|
||||
const [brandData, setBrandData] = useState({});
|
||||
const [tempErrorCodes, setTempErrorCodes] = useState([]);
|
||||
|
||||
// Context integration
|
||||
const {
|
||||
brandId,
|
||||
brandInfo,
|
||||
setBrandInfo,
|
||||
tempErrorCodes,
|
||||
addErrorCode,
|
||||
updateErrorCode,
|
||||
deleteErrorCode,
|
||||
prepareSubmissionData,
|
||||
validateForm,
|
||||
resetForm,
|
||||
} = useBrandForm();
|
||||
|
||||
// Use step from query parameter or context
|
||||
const tab = searchParams.get('tab');
|
||||
const [currentStep, setCurrentStep] = useState(tab === 'error-codes' ? 1 : 0);
|
||||
// Error code management states
|
||||
const [errorCodeForm] = Form.useForm();
|
||||
const [solutionForm] = Form.useForm();
|
||||
const [errorCodeIcon, setErrorCodeIcon] = useState(null);
|
||||
const [selectedSparepartIds, setSelectedSparepartIds] = useState([]);
|
||||
const [editingErrorCodeKey, setEditingErrorCodeKey] = useState(null);
|
||||
const [isErrorCodeFormReadOnly, setIsErrorCodeFormReadOnly] = useState(false);
|
||||
const [isAddingNewErrorCode, setIsAddingNewErrorCode] = useState(false);
|
||||
|
||||
const {
|
||||
solutionFields,
|
||||
@@ -77,14 +68,54 @@ const AddBrandDevice = () => {
|
||||
// Navigation functions
|
||||
const handleNextStep = async () => {
|
||||
try {
|
||||
await brandForm.validateFields();
|
||||
setCurrentStep(1);
|
||||
setConfirmLoading(true);
|
||||
const brandValues = await brandForm.validateFields();
|
||||
const userId = JSON.parse(localStorage.getItem('user') || '{}').user_id || 1;
|
||||
|
||||
// Prepare brand data for API
|
||||
const brandApiData = {
|
||||
brand_name: brandValues.brand_name,
|
||||
brand_type: brandValues.brand_type || '',
|
||||
brand_manufacture: brandValues.brand_manufacture || '',
|
||||
brand_model: brandValues.brand_model || '',
|
||||
is_active: brandValues.is_active !== undefined ? brandValues.is_active : true
|
||||
};
|
||||
|
||||
// Create brand via API
|
||||
const response = await createBrand(brandApiData);
|
||||
|
||||
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
|
||||
const createdBrand = response.data;
|
||||
setCreatedBrandId(createdBrand.brand_id);
|
||||
setBrandData(createdBrand);
|
||||
|
||||
|
||||
NotifOk({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
message: 'Brand device berhasil dibuat. Silakan tambahkan error codes.',
|
||||
});
|
||||
|
||||
setCurrentStep(1);
|
||||
// Trigger refresh untuk error codes table di fase 2
|
||||
setTimeout(() => {
|
||||
setTrigerFilter(prev => !prev);
|
||||
}, 100);
|
||||
} else {
|
||||
NotifAlert({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
message: response?.message || 'Gagal membuat 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 membuat brand device',
|
||||
});
|
||||
} finally {
|
||||
setConfirmLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -97,13 +128,50 @@ const AddBrandDevice = () => {
|
||||
};
|
||||
|
||||
const handleAddErrorCode = () => {
|
||||
navigate(`/master/brand-device/add/error-code/add`);
|
||||
if (createdBrandId) {
|
||||
resetErrorCodeForm();
|
||||
setIsAddingNewErrorCode(true);
|
||||
setIsErrorCodeFormReadOnly(false);
|
||||
setEditingErrorCodeKey(null);
|
||||
} else {
|
||||
NotifAlert({
|
||||
icon: 'warning',
|
||||
title: 'Perhatian',
|
||||
message: 'Brand device harus dibuat terlebih dahulu.',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditErrorCodeNavigate = (record) => {
|
||||
const errorCodeId = record.status === 'existing' ? record.error_code_id : record.tempId;
|
||||
if (errorCodeId) {
|
||||
navigate(`/master/brand-device/add/error-code/edit/${errorCodeId}`);
|
||||
const handleEditErrorCode = (record) => {
|
||||
if (createdBrandId) {
|
||||
setIsAddingNewErrorCode(false);
|
||||
setIsErrorCodeFormReadOnly(false);
|
||||
setEditingErrorCodeKey(record.error_code_id);
|
||||
|
||||
// Load error code data into form
|
||||
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 || '#000000',
|
||||
status: record.is_active !== false,
|
||||
});
|
||||
|
||||
if (record.path_icon) {
|
||||
setErrorCodeIcon({
|
||||
name: record.path_icon.split('/').pop(),
|
||||
uploadPath: record.path_icon,
|
||||
url: record.path_icon,
|
||||
});
|
||||
}
|
||||
|
||||
if (record.solution && record.solution.length > 0) {
|
||||
setSolutionsForExistingRecord(record.solution, solutionForm);
|
||||
}
|
||||
|
||||
if (record.spareparts && record.spareparts.length > 0) {
|
||||
setSelectedSparepartIds(record.spareparts);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,15 +180,33 @@ const AddBrandDevice = () => {
|
||||
icon: 'question',
|
||||
title: 'Konfirmasi Hapus',
|
||||
message: `Apakah Anda yakin ingin menghapus error code "${record.error_code}"?`,
|
||||
onConfirm: () => {
|
||||
const tempId = record.tempId || `existing_${record.error_code_id}`;
|
||||
deleteErrorCode(tempId, false); // false = soft delete
|
||||
NotifOk({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
message: 'Error code berhasil dihapus!',
|
||||
});
|
||||
setTrigerFilter(prev => !prev);
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
const errorCodeToDelete = record.error_code_id;
|
||||
const response = await deleteErrorCode(createdBrandId, 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) {
|
||||
console.error('Error deleting error code:', error);
|
||||
NotifAlert({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
message: error.message || 'Gagal menghapus error code',
|
||||
});
|
||||
}
|
||||
},
|
||||
onCancel: () => {}
|
||||
});
|
||||
@@ -142,8 +228,8 @@ const AddBrandDevice = () => {
|
||||
};
|
||||
|
||||
const handleBrandFormValuesChange = useCallback((changedValues, allValues) => {
|
||||
setBrandInfo(allValues);
|
||||
}, [setBrandInfo]);
|
||||
setBrandData(allValues);
|
||||
}, []);
|
||||
|
||||
const getErrorCodesData = async (params) => {
|
||||
try {
|
||||
@@ -151,12 +237,33 @@ const AddBrandDevice = () => {
|
||||
const page = parseInt(params.get('page')) || 1;
|
||||
const limit = parseInt(params.get('limit')) || 10;
|
||||
|
||||
const allErrorCodes = tempErrorCodes.filter(ec => ec.status !== 'deleted');
|
||||
let allErrorCodes = [];
|
||||
|
||||
let filteredData = allErrorCodes;
|
||||
// Get error codes from API if brand is created
|
||||
if (createdBrandId) {
|
||||
const queryParams = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
limit: limit.toString(),
|
||||
...(search && { search })
|
||||
});
|
||||
|
||||
const response = await getErrorCodesByBrandId(createdBrandId, queryParams);
|
||||
if (response && response.statusCode === 200) {
|
||||
const apiErrorData = response.data || [];
|
||||
allErrorCodes = apiErrorData.map(ec => ({
|
||||
...ec,
|
||||
tempId: `existing_${ec.error_code_id}`,
|
||||
status: 'existing'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Add temp error codes
|
||||
allErrorCodes = [...allErrorCodes, ...tempErrorCodes.filter(ec => ec.status !== 'deleted')];
|
||||
|
||||
// Filter by search text if needed
|
||||
if (searchText) {
|
||||
filteredData = allErrorCodes.filter(ec =>
|
||||
allErrorCodes = allErrorCodes.filter(ec =>
|
||||
ec.error_code.toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
ec.error_code_name.toLowerCase().includes(searchText.toLowerCase())
|
||||
);
|
||||
@@ -164,15 +271,15 @@ const AddBrandDevice = () => {
|
||||
|
||||
const startIndex = 0;
|
||||
const endIndex = startIndex + limit;
|
||||
const paginatedData = filteredData.slice(startIndex, endIndex);
|
||||
const paginatedData = allErrorCodes.slice(startIndex, endIndex);
|
||||
|
||||
return {
|
||||
data: paginatedData,
|
||||
pagination: {
|
||||
current_page: page,
|
||||
current_limit: limit,
|
||||
total_limit: filteredData.length,
|
||||
total_page: Math.ceil(filteredData.length / limit),
|
||||
total_limit: allErrorCodes.length,
|
||||
total_page: Math.ceil(allErrorCodes.length / limit),
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -264,39 +371,120 @@ const AddBrandDevice = () => {
|
||||
return params;
|
||||
}, [searchValue]);
|
||||
|
||||
const handleFinish = async () => {
|
||||
setConfirmLoading(true);
|
||||
const resetErrorCodeForm = () => {
|
||||
errorCodeForm.resetFields();
|
||||
errorCodeForm.setFieldsValue({
|
||||
status: true,
|
||||
});
|
||||
setErrorCodeIcon(null);
|
||||
resetSolutionFields();
|
||||
setIsErrorCodeFormReadOnly(false);
|
||||
setEditingErrorCodeKey(null);
|
||||
setSelectedSparepartIds([]);
|
||||
setIsAddingNewErrorCode(false);
|
||||
};
|
||||
|
||||
const handleSaveErrorCode = async () => {
|
||||
try {
|
||||
// Validate form using context
|
||||
const validation = validateForm();
|
||||
if (!validation.isValid) {
|
||||
await errorCodeForm.validateFields();
|
||||
|
||||
const solutionValues = solutionForm.getFieldsValue();
|
||||
const commaPath = `solution_items,${solutionFields[0]?.key || 0}`;
|
||||
const dotPath = `solution_items.${solutionFields[0]?.key || 0}`;
|
||||
const firstSolution = solutionValues[commaPath] || solutionValues[dotPath];
|
||||
|
||||
let isValid = false;
|
||||
if (firstSolution && firstSolution.name && firstSolution.name.trim() !== '') {
|
||||
const firstSolutionType = solutionTypes[solutionFields[0]?.key || 0];
|
||||
if (firstSolutionType === 'text') {
|
||||
isValid = firstSolution.text && firstSolution.text.trim() !== '';
|
||||
} else {
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
NotifAlert({
|
||||
icon: 'warning',
|
||||
title: 'Perhatian',
|
||||
message: 'Harap lengkapi minimal 1 solution',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const submissionData = prepareSubmissionData(1);
|
||||
const errorCodeValues = errorCodeForm.getFieldsValue();
|
||||
const solutionData = getSolutionData();
|
||||
|
||||
const response = await createBrand(submissionData);
|
||||
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?.uploadPath || '',
|
||||
is_active: errorCodeValues.status !== undefined ? errorCodeValues.status : true,
|
||||
solution: solutionData || [],
|
||||
spareparts: selectedSparepartIds || []
|
||||
};
|
||||
|
||||
// For create, include error_code field (required)
|
||||
if (isAddingNewErrorCode) {
|
||||
payload.error_code = errorCodeValues.error_code;
|
||||
}
|
||||
|
||||
let response;
|
||||
|
||||
if (isAddingNewErrorCode) {
|
||||
response = await createErrorCode(createdBrandId, payload);
|
||||
} else {
|
||||
response = await updateErrorCode(createdBrandId, editingErrorCodeKey, payload);
|
||||
}
|
||||
|
||||
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
|
||||
NotifOk({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
message: response.message || 'Brand Device berhasil ditambahkan.',
|
||||
message: isAddingNewErrorCode ? 'Error Code berhasil ditambahkan!' : 'Error Code berhasil diupdate!',
|
||||
});
|
||||
resetForm();
|
||||
navigate('/master/brand-device');
|
||||
|
||||
resetErrorCodeForm();
|
||||
setTrigerFilter(prev => !prev);
|
||||
} else {
|
||||
NotifAlert({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
message: response?.message || 'Gagal menambahkan Brand Device',
|
||||
message: response?.message || 'Gagal menyimpan error code',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error saving error code:', error);
|
||||
NotifAlert({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
message: error.message || 'Gagal menyimpan error code. Silakan coba lagi.',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleErrorCodeIconRemove = () => {
|
||||
setErrorCodeIcon(null);
|
||||
};
|
||||
|
||||
|
||||
const handleFinish = async () => {
|
||||
setConfirmLoading(true);
|
||||
try {
|
||||
// Fase 2 completion - brand sudah dibuat di fase 1
|
||||
NotifOk({
|
||||
icon: 'success',
|
||||
title: 'Brand Device Tersimpan',
|
||||
message: 'Brand device telah berhasil disimpan dengan error codes yang ditambahkan.',
|
||||
});
|
||||
navigate('/master/brand-device');
|
||||
} catch (error) {
|
||||
NotifAlert({
|
||||
icon: 'error',
|
||||
title: 'Gagal',
|
||||
message: error.message || 'Gagal menyimpan data. Silakan coba lagi.',
|
||||
message: error.message || 'Terjadi kesalahan. Silakan coba lagi.',
|
||||
});
|
||||
} finally {
|
||||
setConfirmLoading(false);
|
||||
@@ -391,7 +579,7 @@ const AddBrandDevice = () => {
|
||||
>
|
||||
<Button
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleAddErrorCode}
|
||||
onClick={() => navigate(`/master/brand-device/${createdBrandId}/error-code/add`)}
|
||||
size="large"
|
||||
>
|
||||
Add Error Code
|
||||
@@ -407,11 +595,11 @@ const AddBrandDevice = () => {
|
||||
cardColor={'#42AAFF'}
|
||||
header={'error_code'}
|
||||
showPreviewModal={handlePreviewErrorCode}
|
||||
showEditModal={handleEditErrorCodeNavigate}
|
||||
showEditModal={(record) => navigate(`/master/brand-device/${createdBrandId}/error-code/edit/${record.error_code_id}`)}
|
||||
showDeleteDialog={handleDeleteErrorCode}
|
||||
getData={getErrorCodesData}
|
||||
queryParams={queryParams}
|
||||
columns={errorCodeColumns(handlePreviewErrorCode, handleEditErrorCodeNavigate, handleDeleteErrorCode)}
|
||||
columns={errorCodeColumns(handlePreviewErrorCode, (record) => navigate(`/master/brand-device/${createdBrandId}/error-code/edit/${record.error_code_id}`), handleDeleteErrorCode)}
|
||||
triger={trigerFilter}
|
||||
/>
|
||||
</Col>
|
||||
@@ -447,6 +635,12 @@ const AddBrandDevice = () => {
|
||||
]);
|
||||
}, [setBreadcrumbItems, navigate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (createdBrandId && currentStep === 1) {
|
||||
setTrigerFilter(prev => !prev);
|
||||
}
|
||||
}, [createdBrandId, currentStep]);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Title level={4} style={{ margin: '0 0 24px 0' }}>
|
||||
@@ -525,7 +719,7 @@ const AddBrandDevice = () => {
|
||||
borderColor: '#23A55A',
|
||||
}}
|
||||
>
|
||||
Save Brand Device
|
||||
Selesai
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user