feat: integration CRUD
parent
9cd4d7f1a0
commit
e150e9e416
|
@ -1,27 +1,58 @@
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { App, Button, Card, Col, Flex, List, notification, Pagination, Row, Tag, Tooltip } from 'antd';
|
import { Fragment, useEffect, useState } from 'react';
|
||||||
import { useEffect, useState } from 'react';
|
import {
|
||||||
import { makeColorStatus, STATUS_DATA } from '@pos/base';
|
App,
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Col,
|
||||||
|
DatePicker,
|
||||||
|
Divider,
|
||||||
|
Flex,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
InputNumber,
|
||||||
|
List,
|
||||||
|
Modal,
|
||||||
|
notification,
|
||||||
|
Pagination,
|
||||||
|
Row,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
|
} from 'antd';
|
||||||
|
import { capitalizeEachWord, makeColorStatus, STATUS_DATA } from '@pos/base';
|
||||||
|
|
||||||
import { DeleteOutlined, EditOutlined, LockOutlined, UnlockOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, EditOutlined, LockOutlined, PlusOutlined, UnlockOutlined } from '@ant-design/icons';
|
||||||
import { makeColorTextValue } from '../helpers';
|
import { makeColorTextValue } from '../helpers';
|
||||||
|
|
||||||
export default function SchedulingData() {
|
export default function SchedulingData() {
|
||||||
|
const [formModal] = Form.useForm();
|
||||||
const { modal } = App.useApp();
|
const { modal } = App.useApp();
|
||||||
|
const [openModalForm, setOpenModalForm] = useState(false);
|
||||||
|
|
||||||
const [loadingTable, setLoadingTable] = useState(false);
|
const [loadingTable, setLoadingTable] = useState(false);
|
||||||
const [schedulingData, setSchedulingData] = useState<any[]>([]);
|
const [schedulingData, setSchedulingData] = useState<any[]>([]);
|
||||||
const [meta, setMeta] = useState<any>();
|
const [schedulingMeta, setSchedulingMeta] = useState<any>();
|
||||||
|
|
||||||
|
const [loadingForm, setLoadingForm] = useState(false);
|
||||||
|
|
||||||
const handleGetData = async (page: number) => {
|
const handleGetData = async (page: number) => {
|
||||||
setLoadingTable(true);
|
setLoadingTable(true);
|
||||||
await axios
|
await axios
|
||||||
.get('v1/data-scheduling', { params: { page: page, limit: 10 } })
|
.get('v1/data-scheduling', {
|
||||||
|
params: {
|
||||||
|
page: page,
|
||||||
|
limit: 10,
|
||||||
|
order_type: 'ASC',
|
||||||
|
order_by: 'schedule_date_from',
|
||||||
|
schedule_date_from: dayjs().format('YYYY-MM-DD'),
|
||||||
|
},
|
||||||
|
})
|
||||||
.then((resp: any) => {
|
.then((resp: any) => {
|
||||||
const data = resp?.data?.data ?? [];
|
const data = resp?.data?.data ?? [];
|
||||||
const meta = resp?.data?.meta;
|
const meta = resp?.data?.meta;
|
||||||
setMeta(meta);
|
setSchedulingMeta(meta);
|
||||||
setSchedulingData(data);
|
setSchedulingData(data);
|
||||||
setLoadingTable(false);
|
setLoadingTable(false);
|
||||||
})
|
})
|
||||||
|
@ -34,7 +65,7 @@ export default function SchedulingData() {
|
||||||
await axios
|
await axios
|
||||||
.patch(`v1/data-scheduling/${id}/active`)
|
.patch(`v1/data-scheduling/${id}/active`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
handleGetData(meta?.currentPage);
|
handleGetData(schedulingMeta?.currentPage);
|
||||||
})
|
})
|
||||||
.catch((err: any) => {
|
.catch((err: any) => {
|
||||||
notification.error({
|
notification.error({
|
||||||
|
@ -49,7 +80,7 @@ export default function SchedulingData() {
|
||||||
await axios
|
await axios
|
||||||
.patch(`v1/data-scheduling/${id}/inactive`)
|
.patch(`v1/data-scheduling/${id}/inactive`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
handleGetData(meta?.currentPage);
|
handleGetData(schedulingMeta?.currentPage);
|
||||||
})
|
})
|
||||||
.catch((err: any) => {
|
.catch((err: any) => {
|
||||||
notification.error({
|
notification.error({
|
||||||
|
@ -64,7 +95,7 @@ export default function SchedulingData() {
|
||||||
await axios
|
await axios
|
||||||
.delete(`v1/data-scheduling/${id}`)
|
.delete(`v1/data-scheduling/${id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
handleGetData(meta?.currentPage);
|
handleGetData(schedulingMeta?.currentPage);
|
||||||
})
|
})
|
||||||
.catch((err: any) => {
|
.catch((err: any) => {
|
||||||
notification.error({
|
notification.error({
|
||||||
|
@ -74,13 +105,193 @@ export default function SchedulingData() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClickUpdate = async (item: any) => {
|
||||||
|
await formModal.setFieldsValue({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name,
|
||||||
|
indexing_key: item.indexing_key,
|
||||||
|
schedule_date_from: dayjs(item.schedule_date_from),
|
||||||
|
schedule_date_to: dayjs(item.schedule_date_from),
|
||||||
|
});
|
||||||
|
setOpenModalForm(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickCreate = async () => {
|
||||||
|
await formModal.resetFields();
|
||||||
|
setOpenModalForm(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseModal = async () => {
|
||||||
|
await formModal.resetFields();
|
||||||
|
setOpenModalForm(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmitModal = async () => {
|
||||||
|
const formValues = await formModal.validateFields();
|
||||||
|
const dataID = formValues.id;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
name: formValues.name,
|
||||||
|
indexing_key: formValues.indexing_key,
|
||||||
|
schedule_date_from: formValues.schedule_date_from && dayjs(formValues.schedule_date_from).format('YYYY-MM-DD'),
|
||||||
|
schedule_date_to: formValues.schedule_date_from && dayjs(formValues.schedule_date_from).format('YYYY-MM-DD'),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dataID) handleEdit(dataID, payload);
|
||||||
|
else handleCreate(payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreate = async (payload: any) => {
|
||||||
|
setLoadingForm(true);
|
||||||
|
await axios
|
||||||
|
.post(`v1/data-scheduling`, payload)
|
||||||
|
.then(async () => {
|
||||||
|
await handleGetData(1);
|
||||||
|
await handleCloseModal();
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
notification.error({
|
||||||
|
message: 'Gagal menyimpan data.',
|
||||||
|
description:
|
||||||
|
err?.message ?? err?.response?.data?.message ?? 'Terjadi kesalahan saat mengaktifkan konfigurasi',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoadingForm(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = async (id: string, payload: any) => {
|
||||||
|
setLoadingForm(true);
|
||||||
|
await axios
|
||||||
|
.put(`v1/data-scheduling/${id}`, payload)
|
||||||
|
.then(async () => {
|
||||||
|
await handleGetData(schedulingMeta?.currentPage);
|
||||||
|
await handleCloseModal();
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
notification.error({
|
||||||
|
message: 'Gagal menyimpan data.',
|
||||||
|
description:
|
||||||
|
err?.message ?? err?.response?.data?.message ?? 'Terjadi kesalahan saat mengaktifkan konfigurasi',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoadingForm(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleGetData(1);
|
handleGetData(1);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button>Tambah Jadwal</Button>
|
<Modal
|
||||||
|
open={openModalForm}
|
||||||
|
onCancel={handleCloseModal}
|
||||||
|
cancelButtonProps={{ disabled: loadingForm }}
|
||||||
|
okText="Simpan"
|
||||||
|
okButtonProps={{ loading: loadingForm }}
|
||||||
|
onOk={handleSubmitModal}
|
||||||
|
title="FORM KONFIGURASI PENJADWALAN"
|
||||||
|
>
|
||||||
|
<Form form={formModal} layout="vertical">
|
||||||
|
<Form.Item name={['id']} noStyle></Form.Item>
|
||||||
|
<Row gutter={[12, 1]}>
|
||||||
|
<Col xs={24} sm={12} span={12}>
|
||||||
|
<Form.Item name={['name']} label="Label" rules={[{ required: true, message: 'Label harus diisi!' }]}>
|
||||||
|
<Input placeholder="Input label" size="large" />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name={['indexing_key']}
|
||||||
|
label="Total Data"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: 'Total data harus diisi!' },
|
||||||
|
{ type: 'number', max: 100, message: 'Total data maksimal 100%!' },
|
||||||
|
{
|
||||||
|
validator(_, value) {
|
||||||
|
if (value <= 0) return Promise.reject(new Error('Total data harus lebih dari 0!'));
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber style={{ width: '100%' }} addonAfter="%" placeholder="Input value" size="large" />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} span={12}>
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{({ getFieldsValue }) => {
|
||||||
|
const values = getFieldsValue();
|
||||||
|
const endDate = values?.schedule_date_to;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label="Start Date"
|
||||||
|
name={'schedule_date_from'}
|
||||||
|
rules={[{ required: true, message: 'Start date harus diisi!' }]}
|
||||||
|
>
|
||||||
|
<DatePicker
|
||||||
|
showNow={false}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
size="large"
|
||||||
|
disabledDate={(date) => {
|
||||||
|
if (endDate)
|
||||||
|
return (
|
||||||
|
(!date.isBefore(endDate) && !date.isSame(endDate)) ||
|
||||||
|
date.isBefore(dayjs().subtract(1, 'day'))
|
||||||
|
);
|
||||||
|
else return date.isBefore(dayjs().subtract(1, 'day'));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} span={12}>
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{({ getFieldsValue }) => {
|
||||||
|
const values = getFieldsValue();
|
||||||
|
const startDate = values?.schedule_date_from;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label="End Date"
|
||||||
|
name={'schedule_date_to'}
|
||||||
|
rules={[{ required: true, message: 'End date harus diisi!' }]}
|
||||||
|
>
|
||||||
|
<DatePicker
|
||||||
|
showNow={false}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
size="large"
|
||||||
|
disabledDate={(date) => {
|
||||||
|
if (startDate) return !date.isAfter(startDate) && !date.isSame(startDate);
|
||||||
|
else return date.isBefore(dayjs().subtract(1, 'day'));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
<div>
|
||||||
|
<Flex justify="end">
|
||||||
|
<Button type="primary" onClick={handleClickCreate} icon={<PlusOutlined />}>
|
||||||
|
Tambah Jadwal
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
{schedulingData?.length > 0 && (
|
||||||
|
<Fragment>
|
||||||
|
<Divider style={{ margin: 10 }} />
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
<div style={{ marginBottom: 10 }}></div>
|
<div style={{ marginBottom: 10 }}></div>
|
||||||
<List
|
<List
|
||||||
bordered={!schedulingData || schedulingData?.length <= 0}
|
bordered={!schedulingData || schedulingData?.length <= 0}
|
||||||
|
@ -89,29 +300,31 @@ export default function SchedulingData() {
|
||||||
loading={loadingTable}
|
loading={loadingTable}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => (
|
||||||
<List.Item key={item.id} style={{ borderBlockEnd: 'none', padding: 5 }}>
|
<List.Item key={item.id} style={{ borderBlockEnd: 'none', padding: 5 }}>
|
||||||
<Card style={{ width: '100%' }}>
|
<Card className="w-full">
|
||||||
<Flex justify="space-between" style={{ width: '100%' }}>
|
<Flex className="w-full" justify="space-between">
|
||||||
<Row className="w-full" gutter={[4, 4]}>
|
<Row className="w-full" gutter={[4, 8]}>
|
||||||
<Col xs={18} sm={12} span={12}>
|
<Col xs={18} sm={12} span={12}>
|
||||||
<Flex align="center" className="h-full" gap={4}>
|
<Flex align="center" className="h-full" gap={4}>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-[#00000066]">{item.name}</div>
|
<div className="text-xs mb-2" style={{ color: makeColorStatus(item.status) }}>
|
||||||
<div className="font-normal mt-1">{`${dayjs(item?.schedule_date_from).format('DD MMM YYYY')} - ${dayjs(item?.schedule_date_to).format('DD MMM YYYY')}`}</div>
|
{capitalizeEachWord(item.status)}
|
||||||
|
</div>
|
||||||
|
<div className="text-[#00000099]">{item.name}</div>
|
||||||
|
<div className="text-[#00000099]">{`${dayjs(item?.schedule_date_from).format('DD MMM YYYY')} - ${dayjs(item?.schedule_date_to).format('DD MMM YYYY')}`}</div>
|
||||||
</div>
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={18} sm={12} span={12}>
|
<Col xs={18} sm={12} span={12}>
|
||||||
<Flex align="center" className="h-full" gap={8}>
|
<Flex align="center" className="h-full" gap={8}>
|
||||||
<div
|
<div
|
||||||
className={`text-2xl font-bold ${makeColorTextValue(item.indexing_key)}`}
|
className={`text-xl font-bold ${makeColorTextValue(item.indexing_key)}`}
|
||||||
>{`${item.indexing_key} %`}</div>
|
>{`${item.indexing_key} %`}</div>
|
||||||
<Tag color={makeColorStatus(item.status)}>{item.status}</Tag>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Flex align="center" gap={4}>
|
<Flex align="center" gap={4}>
|
||||||
<Tooltip title="Edit" trigger={'hover'} placement="bottom">
|
<Tooltip title="Edit" trigger={'hover'} placement="bottom">
|
||||||
<Button icon={<EditOutlined />} />
|
<Button icon={<EditOutlined />} onClick={() => handleClickUpdate(item)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
{item.status === STATUS_DATA.ACTIVE && (
|
{item.status === STATUS_DATA.ACTIVE && (
|
||||||
|
@ -190,9 +403,28 @@ export default function SchedulingData() {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div style={{ marginBottom: 10 }}></div>
|
<div style={{ marginBottom: 10 }}></div>
|
||||||
<Flex justify="end">
|
{schedulingData?.length > 0 && (
|
||||||
<Pagination current={meta?.currentPage} total={meta?.totalPages} />
|
<Fragment>
|
||||||
|
<Divider style={{}} />
|
||||||
|
<Flex justify="end" className="mt-2">
|
||||||
|
<Pagination
|
||||||
|
current={schedulingMeta?.currentPage}
|
||||||
|
total={schedulingMeta?.totalItems}
|
||||||
|
pageSize={10}
|
||||||
|
onChange={async (page) => {
|
||||||
|
await handleGetData(page);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
<div className="mt-2">
|
||||||
|
<div className="italic font-semibold">Informasi Penting: </div>
|
||||||
|
<div className="italic text-[#00000066]">
|
||||||
|
{`Daftar konfigurasi penjadwalan diurutkan otomatis berdasarkan Waktu Mulai. Konfigurasi baru akan muncul sesuai urutan tanggalnya, dan jadwal yang sudah terlewat tidak akan ditampilkan.`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue