feat: enhance error code management with table display and action buttons

This commit is contained in:
2025-11-24 13:05:33 +07:00
parent 899695f548
commit 908788f41d
3 changed files with 239 additions and 128 deletions

View File

@@ -1,6 +1,19 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Divider, Typography, Button, Steps, Form, Row, Col, Card, ConfigProvider } from 'antd'; import {
Divider,
Typography,
Button,
Steps,
Form,
Row,
Col,
Card,
ConfigProvider,
Table,
Tag,
Space,
} from 'antd';
import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif'; import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif';
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
import { createBrand } from '../../../api/master-brand'; import { createBrand } from '../../../api/master-brand';
@@ -11,6 +24,7 @@ import FormActions from './component/FormActions';
import SolutionForm from './component/SolutionForm'; import SolutionForm from './component/SolutionForm';
import { useSolutionLogic } from './hooks/solution'; import { useSolutionLogic } from './hooks/solution';
import { uploadFile, getFolderFromFileType } from '../../../api/file-uploads'; import { uploadFile, getFolderFromFileType } from '../../../api/file-uploads';
import { EditOutlined, DeleteOutlined, EyeOutlined } from '@ant-design/icons';
const { Title } = Typography; const { Title } = Typography;
const { Step } = Steps; const { Step } = Steps;
@@ -39,7 +53,6 @@ const AddBrandDevice = () => {
const [formData, setFormData] = useState(defaultData); const [formData, setFormData] = useState(defaultData);
const [errorCodes, setErrorCodes] = useState([]); const [errorCodes, setErrorCodes] = useState([]);
const [errorCodeIcon, setErrorCodeIcon] = useState(null); const [errorCodeIcon, setErrorCodeIcon] = useState(null);
const [showErrorCodeModal, setShowErrorCodeModal] = useState(false);
const { const {
solutionFields, solutionFields,
@@ -57,7 +70,6 @@ const AddBrandDevice = () => {
setSolutionsForExistingRecord, setSolutionsForExistingRecord,
} = useSolutionLogic(solutionForm); } = useSolutionLogic(solutionForm);
useEffect(() => { useEffect(() => {
setBreadcrumbItems([ setBreadcrumbItems([
{ title: <span style={{ fontSize: '14px', fontWeight: 'bold' }}> Master</span> }, { title: <span style={{ fontSize: '14px', fontWeight: 'bold' }}> Master</span> },
@@ -427,7 +439,7 @@ const AddBrandDevice = () => {
<> <>
<Row gutter={16} style={{ marginBottom: 24 }}> <Row gutter={16} style={{ marginBottom: 24 }}>
{/* Error Code Form Column */} {/* Error Code Form Column */}
<Col span={12}> <Col span={6}>
<Card size="small" title="Error Code"> <Card size="small" title="Error Code">
<Form <Form
form={errorCodeForm} form={errorCodeForm}
@@ -449,7 +461,7 @@ const AddBrandDevice = () => {
</Col> </Col>
{/* Solution Form Column */} {/* Solution Form Column */}
<Col span={12}> <Col span={8}>
<Card size="small" title="Solutions"> <Card size="small" title="Solutions">
<Form <Form
form={solutionForm} form={solutionForm}
@@ -479,49 +491,106 @@ const AddBrandDevice = () => {
</Form> </Form>
</Card> </Card>
</Col> </Col>
</Row>
{/* Error Codes List Button */} {/* Error Codes Table Column */}
<Row justify="center"> <Col span={10}>
<Col> <Card size="small" title={`Error Codes (${errorCodes.length})`}>
<ConfigProvider <Table
theme={{ dataSource={errorCodes}
token: { colorBgContainer: '#23a55ade' }, columns={[
components: { {
Button: { title: 'Error Code',
defaultBg: '#23a55a', dataIndex: 'error_code',
defaultColor: '#FFFFFF', key: 'error_code',
defaultBorderColor: '#23a55a', width: '25%',
defaultHoverBg: '#209652',
defaultHoverColor: '#FFFFFF',
defaultHoverBorderColor: '#23a55a',
}, },
}, {
}} title: 'Sol',
> key: 'Sol',
<Button width: '10%',
type="primary" align: 'center',
size="large" render: (_, record) => {
onClick={() => setShowErrorCodeModal(true)} const solutionCount = record.solution
style={{ minWidth: '200px' }} ? record.solution.length
> : 0;
View All Error Codes ({errorCodes.length}) return (
</Button> <Tag
</ConfigProvider> color={solutionCount > 0 ? 'green' : 'red'}
>
{solutionCount} Sol
</Tag>
);
},
},
{
title: 'Status',
dataIndex: 'status',
key: 'status',
width: '20%',
align: 'center',
render: (_, { status }) => (
<Tag color={status ? 'green' : 'red'}>
{status ? 'Active' : 'Inactive'}
</Tag>
),
},
{
title: 'Action',
key: 'action',
align: 'center',
width: '15%',
render: (_, record) => (
<Space>
<Button
type="text"
style={{ borderColor: '#1890ff' }}
size="small"
icon={
<EyeOutlined
style={{ color: '#1890ff' }}
/>
}
onClick={() =>
handlePreviewErrorCode(record)
}
/>
<Button
type="text"
style={{ borderColor: '#faad14' }}
size="small"
icon={
<EditOutlined
style={{ color: '#faad14' }}
/>
}
onClick={() => handleEditErrorCode(record)}
/>
<Button
type="text"
danger
style={{ borderColor: 'red' }}
size="small"
icon={<DeleteOutlined />}
onClick={() =>
handleDeleteErrorCode(record.key)
}
/>
</Space>
),
},
]}
rowKey="key"
pagination={{
pageSize: 10,
showSizeChanger: false,
hideOnSinglePage: true,
}}
size="small"
scroll={{ y: 300 }}
/>
</Card>
</Col> </Col>
</Row> </Row>
{/* Error Codes List Modal */}
<ErrorCodeListModal
visible={showErrorCodeModal}
onClose={() => setShowErrorCodeModal(false)}
errorCodes={errorCodes}
loading={loading}
onPreview={handlePreviewErrorCode}
onEdit={handleEditErrorCode}
onDelete={handleDeleteErrorCode}
onAddNew={handleCreateNewErrorCode}
/>
</> </>
); );
} }

View File

@@ -12,6 +12,9 @@ import {
Spin, Spin,
Modal, Modal,
ConfigProvider, ConfigProvider,
Table,
Tag,
Space,
} from 'antd'; } from 'antd';
import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif'; import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif';
import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb'; import { useBreadcrumb } from '../../../layout/LayoutBreadcrumb';
@@ -24,6 +27,7 @@ import ErrorCodeListModal from './component/ErrorCodeListModal';
import FormActions from './component/FormActions'; import FormActions from './component/FormActions';
import { useErrorCodeLogic } from './hooks/errorCode'; import { useErrorCodeLogic } from './hooks/errorCode';
import { useSolutionLogic } from './hooks/solution'; import { useSolutionLogic } from './hooks/solution';
import { EditOutlined, DeleteOutlined, EyeOutlined } from '@ant-design/icons';
const { Title } = Typography; const { Title } = Typography;
const { Step } = Steps; const { Step } = Steps;
@@ -53,7 +57,6 @@ const EditBrandDevice = () => {
const [formData, setFormData] = useState(defaultData); const [formData, setFormData] = useState(defaultData);
const [errorCodes, setErrorCodes] = useState([]); const [errorCodes, setErrorCodes] = useState([]);
const [errorCodeIcon, setErrorCodeIcon] = useState(null); const [errorCodeIcon, setErrorCodeIcon] = useState(null);
const [showErrorCodeModal, setShowErrorCodeModal] = useState(false);
const [solutionForm] = Form.useForm(); const [solutionForm] = Form.useForm();
const { errorCodeFields, addErrorCode, removeErrorCode, editErrorCode } = useErrorCodeLogic( const { errorCodeFields, addErrorCode, removeErrorCode, editErrorCode } = useErrorCodeLogic(
@@ -493,7 +496,7 @@ const EditBrandDevice = () => {
return ( return (
<> <>
<Row gutter={24}> <Row gutter={24}>
<Col span={12}> <Col span={6}>
<Card <Card
title={ title={
<Title level={5} style={{ margin: 0 }}> <Title level={5} style={{ margin: 0 }}>
@@ -503,7 +506,7 @@ const EditBrandDevice = () => {
: 'Error Code Form' : 'Error Code Form'
: editingErrorCodeKey : editingErrorCodeKey
? 'Edit Error Code' ? 'Edit Error Code'
: 'Tambah Error Code'} : 'Error Code'}
</Title> </Title>
} }
size="small" size="small"
@@ -526,7 +529,7 @@ const EditBrandDevice = () => {
</Form> </Form>
</Card> </Card>
</Col> </Col>
<Col span={12}> <Col span={8}>
<Card <Card
title={ title={
<Title level={5} style={{ margin: 0 }}> <Title level={5} style={{ margin: 0 }}>
@@ -559,49 +562,104 @@ const EditBrandDevice = () => {
</Form> </Form>
</Card> </Card>
</Col> </Col>
</Row> <Col span={10}>
<Card size="small" title={`Error Codes (${errorCodes.length})`}>
{/* Error Codes List Button */} <Table
<Row justify="center"> dataSource={errorCodes}
<Col> columns={[
<ConfigProvider {
theme={{ title: 'Error Code',
token: { colorBgContainer: '#23a55ade' }, dataIndex: 'error_code',
components: { key: 'error_code',
Button: { width: '25%',
defaultBg: '#23a55a',
defaultColor: '#FFFFFF',
defaultBorderColor: '#23a55a',
defaultHoverBg: '#209652',
defaultHoverColor: '#FFFFFF',
defaultHoverBorderColor: '#23a55a',
}, },
}, {
}} title: 'Sol',
> key: 'Sol',
<Button width: '10%',
type="primary" align: 'center',
size="large" render: (_, record) => {
onClick={() => setShowErrorCodeModal(true)} const solutionCount = record.solution
style={{ minWidth: '200px' }} ? record.solution.length
> : 0;
View All Error Codes ({errorCodes.length}) return (
</Button> <Tag
</ConfigProvider> color={solutionCount > 0 ? 'green' : 'red'}
>
{solutionCount} Sol
</Tag>
);
},
},
{
title: 'Status',
dataIndex: 'status',
key: 'status',
width: '20%',
align: 'center',
render: (_, { status }) => (
<Tag color={status ? 'green' : 'red'}>
{status ? 'Active' : 'Inactive'}
</Tag>
),
},
{
title: 'Action',
key: 'action',
align: 'center',
width: '15%',
render: (_, record) => (
<Space>
<Button
type="text"
style={{ borderColor: '#1890ff' }}
size="small"
icon={
<EyeOutlined
style={{ color: '#1890ff' }}
/>
}
onClick={() =>
handlePreviewErrorCode(record)
}
/>
<Button
type="text"
style={{ borderColor: '#faad14' }}
size="small"
icon={
<EditOutlined
style={{ color: '#faad14' }}
/>
}
onClick={() => handleEditErrorCode(record)}
/>
<Button
type="text"
danger
style={{ borderColor: 'red' }}
size="small"
icon={<DeleteOutlined />}
onClick={() =>
handleDeleteErrorCode(record.key)
}
/>
</Space>
),
},
]}
rowKey="key"
pagination={{
pageSize: 10,
showSizeChanger: false,
hideOnSinglePage: true,
}}
size="small"
scroll={{ y: 300 }}
/>
</Card>
</Col> </Col>
</Row> </Row>
{/* Error Codes List Modal */}
<ErrorCodeListModal
visible={showErrorCodeModal}
onClose={() => setShowErrorCodeModal(false)}
errorCodes={errorCodes}
loading={loading}
onPreview={handlePreviewErrorCode}
onEdit={handleEditErrorCode}
onDelete={handleDeleteErrorCode}
onAddNew={handleCreateNewErrorCode}
/>
</> </>
); );
} }

View File

@@ -1,13 +1,4 @@
import { import { Form, Input, Switch, Upload, Button, Typography, message, ConfigProvider } from 'antd';
Form,
Input,
Switch,
Upload,
Button,
Typography,
message,
ConfigProvider,
} from 'antd';
import { UploadOutlined } from '@ant-design/icons'; import { UploadOutlined } from '@ant-design/icons';
import { uploadFile } from '../../../../api/file-uploads'; import { uploadFile } from '../../../../api/file-uploads';
@@ -47,7 +38,8 @@ const ErrorCodeSimpleForm = ({
const folder = 'images'; const folder = 'images';
const uploadResponse = await uploadFile(file, folder); const uploadResponse = await uploadFile(file, folder);
const iconPath = uploadResponse.data?.path_icon || uploadResponse.data?.path_solution || ''; const iconPath =
uploadResponse.data?.path_icon || uploadResponse.data?.path_solution || '';
if (iconPath) { if (iconPath) {
onErrorCodeIconUpload({ onErrorCodeIconUpload({
@@ -82,9 +74,7 @@ const ErrorCodeSimpleForm = ({
style={{ backgroundColor: statusValue ? '#23A55A' : '#bfbfbf' }} style={{ backgroundColor: statusValue ? '#23A55A' : '#bfbfbf' }}
/> />
</Form.Item> </Form.Item>
<Text style={{ marginLeft: 8 }}> <Text style={{ marginLeft: 8 }}>{statusValue ? 'Active' : 'Inactive'}</Text>
{statusValue ? 'Active' : 'Inactive'}
</Text>
</div> </div>
</Form.Item> </Form.Item>
@@ -94,10 +84,7 @@ const ErrorCodeSimpleForm = ({
name="error_code" name="error_code"
rules={[{ required: true, message: 'Error code wajib diisi!' }]} rules={[{ required: true, message: 'Error code wajib diisi!' }]}
> >
<Input <Input placeholder="Enter error code" disabled={isErrorCodeFormReadOnly} />
placeholder="Enter error code"
disabled={isErrorCodeFormReadOnly}
/>
</Form.Item> </Form.Item>
{/* Error Name */} {/* Error Name */}
@@ -106,17 +93,11 @@ const ErrorCodeSimpleForm = ({
name="error_code_name" name="error_code_name"
rules={[{ required: true, message: 'Error name wajib diisi!' }]} rules={[{ required: true, message: 'Error name wajib diisi!' }]}
> >
<Input <Input placeholder="Enter error name" disabled={isErrorCodeFormReadOnly} />
placeholder="Enter error name"
disabled={isErrorCodeFormReadOnly}
/>
</Form.Item> </Form.Item>
{/* Error Description */} {/* Error Description */}
<Form.Item <Form.Item label="Description" name="error_code_description">
label="Description"
name="error_code_description"
>
<Input.TextArea <Input.TextArea
placeholder="Enter error description" placeholder="Enter error description"
rows={3} rows={3}
@@ -127,14 +108,16 @@ const ErrorCodeSimpleForm = ({
{/* Color and Icon in same row */} {/* Color and Icon in same row */}
<Form.Item label="Color & Icon"> <Form.Item label="Color & Icon">
<Input.Group compact> <Input.Group compact>
<Form.Item <Form.Item name="error_code_color" noStyle>
name="error_code_color"
noStyle
>
<input <input
type="color" type="color"
disabled={isErrorCodeFormReadOnly} disabled={isErrorCodeFormReadOnly}
style={{ width: '30%', height: '40px', border: '1px solid #d9d9d9', borderRadius: 4 }} style={{
width: '30%',
height: '40px',
border: '1px solid #d9d9d9',
borderRadius: 4,
}}
defaultValue="#000000" defaultValue="#000000"
/> />
</Form.Item> </Form.Item>
@@ -152,7 +135,13 @@ const ErrorCodeSimpleForm = ({
</Button> </Button>
</Upload> </Upload>
) : ( ) : (
<div style={{ padding: '8px 12px', border: '1px solid #d9d9d9', borderRadius: 4 }}> <div
style={{
padding: '8px 12px',
border: '1px solid #d9d9d9',
borderRadius: 4,
}}
>
<Text type="secondary">No upload allowed</Text> <Text type="secondary">No upload allowed</Text>
</div> </div>
)} )}
@@ -181,12 +170,7 @@ const ErrorCodeSimpleForm = ({
</Text> </Text>
</div> </div>
{!isErrorCodeFormReadOnly && ( {!isErrorCodeFormReadOnly && (
<Button <Button type="text" danger size="small" onClick={handleIconRemove}>
type="text"
danger
size="small"
onClick={handleIconRemove}
>
Remove Remove
</Button> </Button>
)} )}
@@ -221,7 +205,7 @@ const ErrorCodeSimpleForm = ({
}} }}
style={{ width: '100%' }} style={{ width: '100%' }}
> >
+ Add Error Code Simpan Error Code
</Button> </Button>
</ConfigProvider> </ConfigProvider>
</Form.Item> </Form.Item>
@@ -230,4 +214,4 @@ const ErrorCodeSimpleForm = ({
); );
}; };
export default ErrorCodeSimpleForm; export default ErrorCodeSimpleForm;