From 537d574af7af6c11a8214f087448f3d6a1307781 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani Date: Wed, 30 Apr 2025 11:55:46 +0700 Subject: [PATCH 01/13] feat: setup config local data --- .../components/local-data-configuration.tsx | 111 ++++++++++++++++++ src/apps/admin/layout/index.tsx | 73 ++++++++---- src/apps/index.tsx | 34 +++--- 3 files changed, 180 insertions(+), 38 deletions(-) create mode 100644 src/apps/admin/layout/components/local-data-configuration.tsx diff --git a/src/apps/admin/layout/components/local-data-configuration.tsx b/src/apps/admin/layout/components/local-data-configuration.tsx new file mode 100644 index 0000000..6315d5d --- /dev/null +++ b/src/apps/admin/layout/components/local-data-configuration.tsx @@ -0,0 +1,111 @@ +import { App, Button, Col, InputNumber, InputNumberProps, Modal, ModalProps, Row, Slider } from 'antd'; +import { set } from 'lodash'; +import { useEffect, useState } from 'react'; + +export default function LocalDataConfiguration(modalProps: ModalProps) { + const { modal } = App.useApp(); + + const [inputValue, setInputValue] = useState(0); + const [loadingGet, setLoadingGet] = useState(false); + const [loadingSave, setLoadingSave] = useState(false); + + const onChange: InputNumberProps['onChange'] = (newValue) => { + setInputValue(newValue as number); + }; + + function makeColorText(value: number) { + if (value <= 30) { + return 'text-red-500'; + } else if (value > 30 && value <= 80) { + return 'text-yellow-500'; + } else if (value > 80 && value <= 100) { + return 'text-green-500'; + } + } + + async function handleSave(value: number) { + console.log('Konfigurasi disimpan:', value); + setLoadingSave(true); + setLoadingSave(false); + } + + async function handleGetData() { + console.log('Get data konfigurasi:'); + setLoadingGet(true); + setLoadingGet(false); + } + + useEffect(() => { + if (modalProps.open) handleGetData(); + }, [modalProps.open]); + return ( + + Batal + , + , + ]} + > +
{`Gunakan slider atau input number dibawah ini untuk menentukan persentase data yang ingin ditampilkan di aplikasi lokal Anda. Semakin tinggi persentasenya, semakin banyak data yang akan ditampilkan. Sesuaikan dengan kebutuhan untuk memastikan performa aplikasi tetap optimal.`}
+
+ + + + + + + + +
+
+ ); +} diff --git a/src/apps/admin/layout/index.tsx b/src/apps/admin/layout/index.tsx index 1d4c1c5..b084785 100644 --- a/src/apps/admin/layout/index.tsx +++ b/src/apps/admin/layout/index.tsx @@ -1,4 +1,4 @@ -import { Avatar, Flex, Image, Layout, Popconfirm, Tooltip } from 'antd'; +import { App, Avatar, Dropdown, Flex, Image, Layout } from 'antd'; import { ReactNode, useState } from 'react'; import { Content, Header } from 'antd/es/layout/layout'; import { API_URL, getInitialName, handleLogout, UserDataState } from '@pos/base'; @@ -6,25 +6,30 @@ import { FaUser } from 'react-icons/fa'; import axios from 'axios'; import Logo from '../../../base/presentation/assets/images/we-logo.png'; import { useRecoilValue } from 'recoil'; +import LocalDataConfiguration from './components/local-data-configuration'; +import { LogoutOutlined, SettingOutlined } from '@ant-design/icons'; interface AdminLayoutProps { children: ReactNode; } export default function AdminLayout(props: AdminLayoutProps) { + const { modal } = App.useApp(); + const { children } = props; - const [_loadingLogout, setLoadingLogout] = useState(false); const user = useRecoilValue(UserDataState); const initialName = getInitialName(user?.name ?? ''); + const [openModalConfig, setOpenModalConfig] = useState(false); + const onCancelModalConfig = () => setOpenModalConfig(false); + const onOpenModalConfig = () => setOpenModalConfig(true); + async function handleClickLogout() { - setLoadingLogout(true); try { await axios({ url: `${API_URL.LOGOUT}`, method: 'delete' }); - setLoadingLogout(false); await handleLogout(); } catch (err: any) { - setLoadingLogout(false); + console.error(err); } } @@ -38,7 +43,6 @@ export default function AdminLayout(props: AdminLayoutProps) { width: '100%', display: 'flex', alignItems: 'center', - // background: token.colorPrimary, background: '#fff', borderBottom: '1px solid #ddd', }} @@ -46,27 +50,52 @@ export default function AdminLayout(props: AdminLayoutProps) { - {/*
WE POS
*/}
- - handleClickLogout()} + + , + onClick: () => onOpenModalConfig(), + }, + { + type: 'divider', + }, + { + key: '2', + label: 'Logout', + icon: , + onClick: () => { + modal.confirm({ + icon: null, + cancelText: 'Batal', + cancelButtonProps: { style: { width: 100 } }, + okButtonProps: { style: { width: 100 } }, + content:
Apakah anda yakin ingin keluar dari aplikasi?
, + onOk: () => handleClickLogout(), + }); + }, + }, + ], + }} > - - - {initialName ? ( -
{initialName?.toUpperCase()}
- ) : ( - - )} -
-
-
+ + {initialName ? ( +
{initialName?.toUpperCase()}
+ ) : ( + + )} +
+
+ {children} ); diff --git a/src/apps/index.tsx b/src/apps/index.tsx index ac691a3..d095cbe 100644 --- a/src/apps/index.tsx +++ b/src/apps/index.tsx @@ -1,6 +1,6 @@ import { Suspense, lazy } from 'react'; import { RecoilRoot } from 'recoil'; -import { ConfigProvider, Flex, Spin } from 'antd'; +import { ConfigProvider, Flex, Spin, App as AntdApp } from 'antd'; import { DebugObserver, ForbiddenAccessPage, NotFoundPage } from '@pos/base'; import { Navigate, Route, Routes } from 'react-router-dom'; import { APP_THEME } from '@pos/base/presentation/assets/themes'; @@ -14,21 +14,23 @@ export default function App() { - - } /> - - } - > - - } /> - } /> - } /> - } /> - } /> - - + + + } /> + + } + > + + } /> + } /> + } /> + } /> + } /> + + + ); -- 2.40.1 From d49c487e618045407d9f3c04a180633177d5d7fe Mon Sep 17 00:00:00 2001 From: Firman Ramdhani Date: Wed, 30 Apr 2025 11:57:30 +0700 Subject: [PATCH 02/13] feat: setup config local data --- src/apps/admin/layout/components/local-data-configuration.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/apps/admin/layout/components/local-data-configuration.tsx b/src/apps/admin/layout/components/local-data-configuration.tsx index 6315d5d..fe54bec 100644 --- a/src/apps/admin/layout/components/local-data-configuration.tsx +++ b/src/apps/admin/layout/components/local-data-configuration.tsx @@ -1,6 +1,5 @@ -import { App, Button, Col, InputNumber, InputNumberProps, Modal, ModalProps, Row, Slider } from 'antd'; -import { set } from 'lodash'; import { useEffect, useState } from 'react'; +import { App, Button, Col, InputNumber, InputNumberProps, Modal, ModalProps, Row, Slider } from 'antd'; export default function LocalDataConfiguration(modalProps: ModalProps) { const { modal } = App.useApp(); -- 2.40.1 From 685d14a7dfbc228af3b3c9bb2b88fe097362cde9 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani Date: Fri, 2 May 2025 10:14:53 +0700 Subject: [PATCH 03/13] feat: create feature local data configuration --- .../components/local-data-configuration.tsx | 46 ++++++++++++++++--- .../infrastructure/constants/api-url/index.ts | 3 ++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/apps/admin/layout/components/local-data-configuration.tsx b/src/apps/admin/layout/components/local-data-configuration.tsx index fe54bec..883b00c 100644 --- a/src/apps/admin/layout/components/local-data-configuration.tsx +++ b/src/apps/admin/layout/components/local-data-configuration.tsx @@ -1,13 +1,15 @@ +import axios from 'axios'; import { useEffect, useState } from 'react'; import { App, Button, Col, InputNumber, InputNumberProps, Modal, ModalProps, Row, Slider } from 'antd'; +import { API_URL } from '@pos/base'; export default function LocalDataConfiguration(modalProps: ModalProps) { - const { modal } = App.useApp(); + const { modal, notification } = App.useApp(); + const [configData, setConfigData] = useState(); const [inputValue, setInputValue] = useState(0); const [loadingGet, setLoadingGet] = useState(false); const [loadingSave, setLoadingSave] = useState(false); - const onChange: InputNumberProps['onChange'] = (newValue) => { setInputValue(newValue as number); }; @@ -23,15 +25,47 @@ export default function LocalDataConfiguration(modalProps: ModalProps) { } async function handleSave(value: number) { - console.log('Konfigurasi disimpan:', value); setLoadingSave(true); - setLoadingSave(false); + await axios + .put(API_URL.EDIT_TRANSACTION_SETTING, { id: configData?.id, value }) + .then(() => { + notification.success({ + message: 'Sukses', + description: 'Konfigurasi berhasil disimpan', + }); + + if (modalProps.onCancel) modalProps.onCancel(null as any); + }) + .catch((err) => { + notification.error({ + message: 'Gagal', + description: err?.message ?? err?.response?.data?.message ?? 'Terjadi kesalahan saat menyimpan konfigurasi', + }); + }) + .finally(() => { + setLoadingSave(false); + }); } async function handleGetData() { - console.log('Get data konfigurasi:'); setLoadingGet(true); - setLoadingGet(false); + await axios + .get(API_URL.GET_TRANSACTION_SETTING) + .then((res) => { + const data = res.data.data; + const respValue = data?.value; + setInputValue(Number(respValue ?? '0')); + setConfigData(data); + }) + .catch((err) => { + notification.error({ + message: 'Gagal', + description: err?.message ?? err?.response?.data?.message ?? 'Terjadi kesalahan saat mengambil konfigurasi', + }); + }) + .finally(() => { + setLoadingGet(false); + }); } useEffect(() => { diff --git a/src/base/infrastructure/constants/api-url/index.ts b/src/base/infrastructure/constants/api-url/index.ts index d5855d7..774e89b 100644 --- a/src/base/infrastructure/constants/api-url/index.ts +++ b/src/base/infrastructure/constants/api-url/index.ts @@ -5,4 +5,7 @@ export const API_URL = { REPORT_SUMMARY_INCOME_ITEM: '/v1/report-summary/income-item', REPORT_SUMMARY_INCOME_ITEM_MASTER: '/v1/report-summary/income-item-master', + + EDIT_TRANSACTION_SETTING: '/v1/transaction-setting', + GET_TRANSACTION_SETTING: '/v1/transaction-setting/detail', }; -- 2.40.1 From 01913a739f79f12a51156f3a2f36c110869967b5 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani Date: Fri, 2 May 2025 10:22:32 +0700 Subject: [PATCH 04/13] faet: setup base url local --- env/env.cloud | 2 ++ env/env.development | 2 ++ env/env.production-offline | 2 ++ env/env.production-online | 2 ++ .../admin/layout/components/local-data-configuration.tsx | 6 +++--- src/base/infrastructure/constants/environment/index.ts | 2 ++ 6 files changed, 13 insertions(+), 3 deletions(-) diff --git a/env/env.cloud b/env/env.cloud index 6b72a4b..19b975f 100644 --- a/env/env.cloud +++ b/env/env.cloud @@ -1,3 +1,5 @@ VITE_APP_MODE=production VITE_BASE_API_URL=http://103.187.147.241:30050/api VITE_BASE_API_REPORT_URL=http://103.187.147.241:30050/api + +VITE_BASE_API_URL_LOCAL=https://api.sky.eigen.co.id/api \ No newline at end of file diff --git a/env/env.development b/env/env.development index e9c0373..8f8e928 100644 --- a/env/env.development +++ b/env/env.development @@ -1,3 +1,5 @@ VITE_APP_MODE=production VITE_BASE_API_URL=https://api.sky.eigen.co.id/api VITE_BASE_API_REPORT_URL=https://api.sky.eigen.co.id/api + +VITE_BASE_API_URL_LOCAL=https://api.sky.eigen.co.id/api diff --git a/env/env.production-offline b/env/env.production-offline index 2c6687b..1050e15 100644 --- a/env/env.production-offline +++ b/env/env.production-offline @@ -1,3 +1,5 @@ VITE_APP_MODE=production VITE_BASE_API_URL=http://172.16.2.101:30050/api VITE_BASE_API_REPORT_URL=http://172.16.2.101:30050/api + +VITE_BASE_API_URL_LOCAL=http://172.16.2.101:30050/api \ No newline at end of file diff --git a/env/env.production-online b/env/env.production-online index 4dbed92..c9a3d6f 100644 --- a/env/env.production-online +++ b/env/env.production-online @@ -1,3 +1,5 @@ VITE_APP_MODE=production VITE_BASE_API_URL=https://api.office.weplayground.id/api VITE_BASE_API_REPORT_URL=https://api.office.weplayground.id/api + +VITE_BASE_API_URL_LOCAL=https://api.office.weplayground.id/api \ No newline at end of file diff --git a/src/apps/admin/layout/components/local-data-configuration.tsx b/src/apps/admin/layout/components/local-data-configuration.tsx index 883b00c..46280c8 100644 --- a/src/apps/admin/layout/components/local-data-configuration.tsx +++ b/src/apps/admin/layout/components/local-data-configuration.tsx @@ -1,7 +1,7 @@ import axios from 'axios'; import { useEffect, useState } from 'react'; import { App, Button, Col, InputNumber, InputNumberProps, Modal, ModalProps, Row, Slider } from 'antd'; -import { API_URL } from '@pos/base'; +import { API_URL, BASE_API_URL_LOCAL } from '@pos/base'; export default function LocalDataConfiguration(modalProps: ModalProps) { const { modal, notification } = App.useApp(); @@ -27,7 +27,7 @@ export default function LocalDataConfiguration(modalProps: ModalProps) { async function handleSave(value: number) { setLoadingSave(true); await axios - .put(API_URL.EDIT_TRANSACTION_SETTING, { id: configData?.id, value }) + .put(API_URL.EDIT_TRANSACTION_SETTING, { id: configData?.id, value }, { baseURL: BASE_API_URL_LOCAL }) .then(() => { notification.success({ message: 'Sukses', @@ -50,7 +50,7 @@ export default function LocalDataConfiguration(modalProps: ModalProps) { async function handleGetData() { setLoadingGet(true); await axios - .get(API_URL.GET_TRANSACTION_SETTING) + .get(API_URL.GET_TRANSACTION_SETTING, { baseURL: BASE_API_URL_LOCAL }) .then((res) => { const data = res.data.data; const respValue = data?.value; diff --git a/src/base/infrastructure/constants/environment/index.ts b/src/base/infrastructure/constants/environment/index.ts index edadee5..64f6e2d 100644 --- a/src/base/infrastructure/constants/environment/index.ts +++ b/src/base/infrastructure/constants/environment/index.ts @@ -8,3 +8,5 @@ export const EMBED_DASHBOARD_ID = import.meta.env.VITE_EMBED_DASHBOARD_ID; export const DOWLOAD_POS_WINDOWS_URL = import.meta.env.VITE_DOWLOAD_POS_WINDOWS_URL; export const DOWLOAD_POS_LINUX_DEB_URL = import.meta.env.VITE_DOWLOAD_POS_LINUX_DEB_URL; export const DOWLOAD_POS_LINUX_SNAP_URL = import.meta.env.VITE_DOWLOAD_POS_LINUX_SNAP_URL; + +export const BASE_API_URL_LOCAL = import.meta.env.VITE_BASE_API_URL_LOCAL; -- 2.40.1 From 7330e38296e477b95ac52cdbb547ed0f31ede56a Mon Sep 17 00:00:00 2001 From: irfan Date: Tue, 13 May 2025 04:50:20 +0000 Subject: [PATCH 05/13] Update env/env.production-online --- env/env.production-online | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/env/env.production-online b/env/env.production-online index c9a3d6f..664a215 100644 --- a/env/env.production-online +++ b/env/env.production-online @@ -1,5 +1,5 @@ VITE_APP_MODE=production -VITE_BASE_API_URL=https://api.office.weplayground.id/api -VITE_BASE_API_REPORT_URL=https://api.office.weplayground.id/api +VITE_BASE_API_URL=http://103.187.147.241:30050/api +VITE_BASE_API_REPORT_URL=http://103.187.147.241:30050/api -VITE_BASE_API_URL_LOCAL=https://api.office.weplayground.id/api \ No newline at end of file +VITE_BASE_API_URL_LOCAL=http://103.187.147.241:30050/api \ No newline at end of file -- 2.40.1 From e6481aa60642901981bb1e80f84224681fcbb814 Mon Sep 17 00:00:00 2001 From: irfan Date: Tue, 13 May 2025 04:52:55 +0000 Subject: [PATCH 06/13] Update env/env.cloud --- env/env.cloud | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env/env.cloud b/env/env.cloud index 19b975f..0f597d3 100644 --- a/env/env.cloud +++ b/env/env.cloud @@ -2,4 +2,4 @@ VITE_APP_MODE=production VITE_BASE_API_URL=http://103.187.147.241:30050/api VITE_BASE_API_REPORT_URL=http://103.187.147.241:30050/api -VITE_BASE_API_URL_LOCAL=https://api.sky.eigen.co.id/api \ No newline at end of file +VITE_BASE_API_URL_LOCAL=https://api.office.weplayground.id/api \ No newline at end of file -- 2.40.1 From 29ff09d3aa76a458c30c0f16c256376f4989786d Mon Sep 17 00:00:00 2001 From: Firman Ramdhani Date: Fri, 16 May 2025 10:07:20 +0700 Subject: [PATCH 07/13] feat: add setting access to change setting data --- src/apps/admin/layout/index.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/apps/admin/layout/index.tsx b/src/apps/admin/layout/index.tsx index b084785..81b81cb 100644 --- a/src/apps/admin/layout/index.tsx +++ b/src/apps/admin/layout/index.tsx @@ -33,6 +33,13 @@ export default function AdminLayout(props: AdminLayoutProps) { } } + function checkAllowAccessSetting() { + const username = user?.username; + const allowList = ['Endy', 'superadmin']; + if (allowList.includes(username)) return true; + return false; + } + return (
{ + const isAllowSetting = checkAllowAccessSetting(); + if (!isAllowSetting && (item.key === '1' || item.type === 'divider')) { + return undefined; + } + return item; + }) + .filter(Boolean) as any, }} > -- 2.40.1 From 4a08abe0b51102283bf1180a681d76835df8d5b1 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani Date: Thu, 3 Jul 2025 17:48:54 +0700 Subject: [PATCH 08/13] feat: setup setting page --- env/env.cloud | 3 +- env/env.development | 1 + env/env.production-offline | 3 +- env/env.production-online | 3 +- src/apps/admin/index.tsx | 280 +----------------- src/apps/admin/layout/index.tsx | 42 ++- src/apps/admin/pages/report.tsx | 276 +++++++++++++++++ src/apps/admin/pages/setting.tsx | 26 ++ src/apps/index.tsx | 4 +- .../constants/environment/index.ts | 1 + 10 files changed, 356 insertions(+), 283 deletions(-) create mode 100644 src/apps/admin/pages/report.tsx create mode 100644 src/apps/admin/pages/setting.tsx diff --git a/env/env.cloud b/env/env.cloud index 0f597d3..828fa71 100644 --- a/env/env.cloud +++ b/env/env.cloud @@ -2,4 +2,5 @@ VITE_APP_MODE=production VITE_BASE_API_URL=http://103.187.147.241:30050/api VITE_BASE_API_REPORT_URL=http://103.187.147.241:30050/api -VITE_BASE_API_URL_LOCAL=https://api.office.weplayground.id/api \ No newline at end of file +VITE_BASE_API_URL_LOCAL=https://api.office.weplayground.id/api +VITE_BASE_ACCESS_SETTING=Endy|dev \ No newline at end of file diff --git a/env/env.development b/env/env.development index 8f8e928..1df931e 100644 --- a/env/env.development +++ b/env/env.development @@ -3,3 +3,4 @@ VITE_BASE_API_URL=https://api.sky.eigen.co.id/api VITE_BASE_API_REPORT_URL=https://api.sky.eigen.co.id/api VITE_BASE_API_URL_LOCAL=https://api.sky.eigen.co.id/api +VITE_BASE_ACCESS_SETTING=Endy|dev \ No newline at end of file diff --git a/env/env.production-offline b/env/env.production-offline index 1050e15..f6a4172 100644 --- a/env/env.production-offline +++ b/env/env.production-offline @@ -2,4 +2,5 @@ VITE_APP_MODE=production VITE_BASE_API_URL=http://172.16.2.101:30050/api VITE_BASE_API_REPORT_URL=http://172.16.2.101:30050/api -VITE_BASE_API_URL_LOCAL=http://172.16.2.101:30050/api \ No newline at end of file +VITE_BASE_API_URL_LOCAL=http://172.16.2.101:30050/api +VITE_BASE_ACCESS_SETTING=Endy|dev \ No newline at end of file diff --git a/env/env.production-online b/env/env.production-online index 664a215..8d1c0b9 100644 --- a/env/env.production-online +++ b/env/env.production-online @@ -2,4 +2,5 @@ VITE_APP_MODE=production VITE_BASE_API_URL=http://103.187.147.241:30050/api VITE_BASE_API_REPORT_URL=http://103.187.147.241:30050/api -VITE_BASE_API_URL_LOCAL=http://103.187.147.241:30050/api \ No newline at end of file +VITE_BASE_API_URL_LOCAL=http://103.187.147.241:30050/api +VITE_BASE_ACCESS_SETTING=Endy|dev \ No newline at end of file diff --git a/src/apps/admin/index.tsx b/src/apps/admin/index.tsx index 56d2981..c67900b 100644 --- a/src/apps/admin/index.tsx +++ b/src/apps/admin/index.tsx @@ -1,277 +1,19 @@ -import axios from 'axios'; +import { lazy } from 'react'; import AdminLayout from './layout'; -import { API_URL, currencyFormatter } from '@pos/base'; -import { useEffect, useState } from 'react'; -import { Card, Col, DatePicker, notification, Row, Table } from 'antd'; -import dayjs from 'dayjs'; -import lodash from 'lodash'; -import { v4 } from 'uuid'; +import { Navigate, Route, Routes } from 'react-router-dom'; -export default function Admin() { - const [dataItem, setDataItem] = useState([]); - const [dataItemKeys, setDataItemKeys] = useState([]); - const [loadingDataItem, setLoadingDataItem] = useState(false); - const [dataItemTotalPax, setDataItemTotalPax] = useState(0); - const [dataItemTotalRevenue, setDataItemTotalRevenue] = useState(0); - - const [dataItemMaster, setDataItemMaster] = useState([]); - const [dataItemMasterKeys, setDataItemMasterKeys] = useState([]); - const [loadingDataItemMaster, setLoadingDataItemMaster] = useState(false); - const [dataItemMasterTotalPax, setDataItemMasterTotalPax] = useState(0); - const [dataItemMasterTotalRevenue, setDataItemMasterTotalRevenue] = useState(0); - - const [filterDate, setFilerDate] = useState(dayjs()); - - async function getDataItem(params: any) { - setLoadingDataItem(true); - await axios - .get(API_URL.REPORT_SUMMARY_INCOME_ITEM, { params: params }) - .then((resp) => { - const data = resp.data.data; - - const groupedData = lodash(data) - .groupBy('item_owner') // Group by item_owner - .map((items, owner) => ({ - // Map over each group to sum values and keep children - title: owner, - tr_item__qty: lodash.sumBy(items, (item) => Number(item.tr_item__qty)), // Convert to number - tr_item__total_net_price: lodash.sumBy(items, (item) => Number(item.tr_item__total_net_price)), // Convert to number - children: items.map((item) => { - return { ...item, title: item.tr_item__item_name }; - }), // Include the original data as children - })) - .value() - .map((item) => { - return { - key: v4(), - ...item, - }; - }); - - const totalPax = lodash.sumBy(data, (item: any) => Number(item.tr_item__qty)); - const totalRevenue = lodash.sumBy(data, (item: any) => Number(item.tr_item__total_net_price)); - setDataItemTotalPax(totalPax); - setDataItemTotalRevenue(totalRevenue); - - setDataItemKeys(groupedData.map((item) => item.key)); - setDataItem(groupedData); - }) - .catch((err) => { - notification.error({ message: err?.message }); - }) - .finally(() => { - setLoadingDataItem(false); - }); - } - - async function getDataItemMaster(params: any) { - setLoadingDataItemMaster(true); - await axios - .get(API_URL.REPORT_SUMMARY_INCOME_ITEM_MASTER, { params: params }) - .then((resp) => { - const data = resp.data.data; - const groupedData = lodash(data) - .groupBy('item_owner') // Group by item_owner - .map((items, owner) => ({ - // Map over each group to sum values and keep children - title: owner, - tr_item__qty: lodash.sumBy(items, (item) => Number(item.tr_item__qty)), // Convert to number - tr_item_bundling__total_net_price: lodash.sumBy(items, (item) => - Number(item.tr_item_bundling__total_net_price), - ), // Convert to number - children: items.map((item) => { - let title = ''; - if (item.tr_item_bundling__item_name) { - title = `${item.tr_item_bundling__item_name} / ${item.tr_item__item_name}`; - } else { - title = item.tr_item__item_name; - } - return { ...item, title: title }; - }), // Include the original data as children - })) - .value() - .map((item) => { - return { - key: v4(), - ...item, - }; - }); - - const totalPax = lodash.sumBy(data, (item: any) => Number(item.tr_item__qty)); - const totalRevenue = lodash.sumBy(data, (item: any) => Number(item.tr_item_bundling__total_net_price)); - setDataItemMasterTotalPax(totalPax); - setDataItemMasterTotalRevenue(totalRevenue); - - setDataItemMasterKeys(groupedData.map((item) => item.key)); - setDataItemMaster(groupedData); - }) - .catch((err) => { - notification.error({ message: err?.message }); - }) - .finally(() => { - setLoadingDataItemMaster(false); - }); - } - - function handleGetDate(date: any) { - getDataItem({ date }); - getDataItemMaster({ date }); - } - - useEffect(() => { - if (filterDate) { - handleGetDate(filterDate.format('DD-MM-YYYY')); - } - }, [filterDate]); +const ReportModule = lazy(() => import('./pages/report')); +const SettingModule = lazy(() => import('./pages/setting')); +export default function AppModule() { return ( - - - - - -
- - - - - -
{`Pendapatan Per Item ${filterDate.format('DD-MM-YYYY')}`}
- - -
{`Total revenue mungkin berbeda dengan pendapatan per item master disebabkan pengambilan harga kepada harga bundling.`}
- -
- } - > - - - -
-
TOTAL PAX
-
{dataItemTotalPax}
-
-
- - - -
-
TOTAL REVENUE
-
- {currencyFormatter({ value: dataItemTotalRevenue })} -
-
-
- -
-
- child.key} // Make sure each child row has a unique key - expandable={{ expandedRowKeys: dataItemKeys, showExpandColumn: false }} - rowClassName={(row) => (row.key ? 'row-group' : '')} - rowHoverable={false} - columns={[ - { key: 'title', dataIndex: 'title', title: 'TITLE', width: 170 }, - { key: 'tr_item__qty', dataIndex: 'tr_item__qty', title: 'PAX', width: 70 }, - { - key: 'tr_item__total_net_price', - dataIndex: 'tr_item__total_net_price', - title: 'REVENUE', - width: 120, - render: (value) => currencyFormatter({ value }), - }, - ]} - /> - - - - - -
{`Pendapatan Per Item Master ${filterDate.format('DD-MM-YYYY')}`}
- - -
{`Total revenue mungkin berbeda dengan pendapatan per item disebabkan harga item master mengambil harga jual standard item.`}
- - - } - > - - - -
-
TOTAL PAX
-
- {dataItemMasterTotalPax} -
-
-
- - - -
-
TOTAL REVENUE
-
- {currencyFormatter({ value: dataItemMasterTotalRevenue })} -
-
-
- - -
-
child.key} // Make sure each child row has a unique key - expandable={{ expandedRowKeys: dataItemMasterKeys, showExpandColumn: false }} - rowClassName={(row) => (row.key ? 'row-group' : '')} - rowHoverable={false} - columns={[ - { key: 'title', dataIndex: 'title', title: 'TITLE', width: 170 }, - - { key: 'tr_item__qty', dataIndex: 'tr_item__qty', title: 'PAX', width: 70 }, - { - key: 'tr_item_bundling__total_net_price', - dataIndex: 'tr_item_bundling__total_net_price', - title: 'REVENUE', - width: 120, - render: (value) => currencyFormatter({ value }), - }, - ]} - /> - - - + + } /> + } /> + } /> + } /> + ); } diff --git a/src/apps/admin/layout/index.tsx b/src/apps/admin/layout/index.tsx index 81b81cb..34af951 100644 --- a/src/apps/admin/layout/index.tsx +++ b/src/apps/admin/layout/index.tsx @@ -1,19 +1,21 @@ import { App, Avatar, Dropdown, Flex, Image, Layout } from 'antd'; import { ReactNode, useState } from 'react'; import { Content, Header } from 'antd/es/layout/layout'; -import { API_URL, getInitialName, handleLogout, UserDataState } from '@pos/base'; +import { ACCESS_SETTING, API_URL, getInitialName, handleLogout, UserDataState } from '@pos/base'; import { FaUser } from 'react-icons/fa'; import axios from 'axios'; import Logo from '../../../base/presentation/assets/images/we-logo.png'; import { useRecoilValue } from 'recoil'; import LocalDataConfiguration from './components/local-data-configuration'; -import { LogoutOutlined, SettingOutlined } from '@ant-design/icons'; +import { FileTextOutlined, LogoutOutlined, SettingOutlined } from '@ant-design/icons'; +import { useNavigate } from 'react-router-dom'; interface AdminLayoutProps { children: ReactNode; } export default function AdminLayout(props: AdminLayoutProps) { + const navigate = useNavigate(); const { modal } = App.useApp(); const { children } = props; @@ -22,7 +24,7 @@ export default function AdminLayout(props: AdminLayoutProps) { const [openModalConfig, setOpenModalConfig] = useState(false); const onCancelModalConfig = () => setOpenModalConfig(false); - const onOpenModalConfig = () => setOpenModalConfig(true); + // const onOpenModalConfig = () => setOpenModalConfig(true); async function handleClickLogout() { try { @@ -35,11 +37,22 @@ export default function AdminLayout(props: AdminLayoutProps) { function checkAllowAccessSetting() { const username = user?.username; - const allowList = ['Endy', 'superadmin']; + const accessSetting = ACCESS_SETTING ?? ''; + + const allowList = accessSetting.split('|'); if (allowList.includes(username)) return true; return false; } + function gotoHome() { + navigate('/app'); + } + + function gotoSetting() { + // onOpenModalConfig(); + navigate('/app/setting'); + } + return (
- + , - onClick: () => onOpenModalConfig(), + label: 'Report', + icon: , + onClick: () => gotoHome(), }, { type: 'divider', + key: 'divider_1', }, { key: '2', + label: 'Settings', + icon: , + onClick: () => gotoSetting(), + }, + { + type: 'divider', + key: 'divider_2', + }, + { + key: '3', label: 'Logout', icon: , onClick: () => { @@ -91,7 +115,7 @@ export default function AdminLayout(props: AdminLayoutProps) { ] .map((item) => { const isAllowSetting = checkAllowAccessSetting(); - if (!isAllowSetting && (item.key === '1' || item.type === 'divider')) { + if (!isAllowSetting && ['1', '2', 'divider_1', 'divider_2'].includes(item.key)) { return undefined; } return item; diff --git a/src/apps/admin/pages/report.tsx b/src/apps/admin/pages/report.tsx new file mode 100644 index 0000000..b9832d6 --- /dev/null +++ b/src/apps/admin/pages/report.tsx @@ -0,0 +1,276 @@ +import axios from 'axios'; +import { API_URL, currencyFormatter } from '@pos/base'; +import { Fragment, useEffect, useState } from 'react'; +import { Card, Col, DatePicker, notification, Row, Table } from 'antd'; +import dayjs from 'dayjs'; +import lodash from 'lodash'; +import { v4 } from 'uuid'; + +export default function ReportModule() { + const [dataItem, setDataItem] = useState([]); + const [dataItemKeys, setDataItemKeys] = useState([]); + const [loadingDataItem, setLoadingDataItem] = useState(false); + const [dataItemTotalPax, setDataItemTotalPax] = useState(0); + const [dataItemTotalRevenue, setDataItemTotalRevenue] = useState(0); + + const [dataItemMaster, setDataItemMaster] = useState([]); + const [dataItemMasterKeys, setDataItemMasterKeys] = useState([]); + const [loadingDataItemMaster, setLoadingDataItemMaster] = useState(false); + const [dataItemMasterTotalPax, setDataItemMasterTotalPax] = useState(0); + const [dataItemMasterTotalRevenue, setDataItemMasterTotalRevenue] = useState(0); + + const [filterDate, setFilerDate] = useState(dayjs()); + + async function getDataItem(params: any) { + setLoadingDataItem(true); + await axios + .get(API_URL.REPORT_SUMMARY_INCOME_ITEM, { params: params }) + .then((resp) => { + const data = resp.data.data; + + const groupedData = lodash(data) + .groupBy('item_owner') // Group by item_owner + .map((items, owner) => ({ + // Map over each group to sum values and keep children + title: owner, + tr_item__qty: lodash.sumBy(items, (item) => Number(item.tr_item__qty)), // Convert to number + tr_item__total_net_price: lodash.sumBy(items, (item) => Number(item.tr_item__total_net_price)), // Convert to number + children: items.map((item) => { + return { ...item, title: item.tr_item__item_name }; + }), // Include the original data as children + })) + .value() + .map((item) => { + return { + key: v4(), + ...item, + }; + }); + + const totalPax = lodash.sumBy(data, (item: any) => Number(item.tr_item__qty)); + const totalRevenue = lodash.sumBy(data, (item: any) => Number(item.tr_item__total_net_price)); + setDataItemTotalPax(totalPax); + setDataItemTotalRevenue(totalRevenue); + + setDataItemKeys(groupedData.map((item) => item.key)); + setDataItem(groupedData); + }) + .catch((err) => { + notification.error({ message: err?.message }); + }) + .finally(() => { + setLoadingDataItem(false); + }); + } + + async function getDataItemMaster(params: any) { + setLoadingDataItemMaster(true); + await axios + .get(API_URL.REPORT_SUMMARY_INCOME_ITEM_MASTER, { params: params }) + .then((resp) => { + const data = resp.data.data; + const groupedData = lodash(data) + .groupBy('item_owner') // Group by item_owner + .map((items, owner) => ({ + // Map over each group to sum values and keep children + title: owner, + tr_item__qty: lodash.sumBy(items, (item) => Number(item.tr_item__qty)), // Convert to number + tr_item_bundling__total_net_price: lodash.sumBy(items, (item) => + Number(item.tr_item_bundling__total_net_price), + ), // Convert to number + children: items.map((item) => { + let title = ''; + if (item.tr_item_bundling__item_name) { + title = `${item.tr_item_bundling__item_name} / ${item.tr_item__item_name}`; + } else { + title = item.tr_item__item_name; + } + return { ...item, title: title }; + }), // Include the original data as children + })) + .value() + .map((item) => { + return { + key: v4(), + ...item, + }; + }); + + const totalPax = lodash.sumBy(data, (item: any) => Number(item.tr_item__qty)); + const totalRevenue = lodash.sumBy(data, (item: any) => Number(item.tr_item_bundling__total_net_price)); + setDataItemMasterTotalPax(totalPax); + setDataItemMasterTotalRevenue(totalRevenue); + + setDataItemMasterKeys(groupedData.map((item) => item.key)); + setDataItemMaster(groupedData); + }) + .catch((err) => { + notification.error({ message: err?.message }); + }) + .finally(() => { + setLoadingDataItemMaster(false); + }); + } + + function handleGetDate(date: any) { + getDataItem({ date }); + getDataItemMaster({ date }); + } + + useEffect(() => { + if (filterDate) { + handleGetDate(filterDate.format('DD-MM-YYYY')); + } + }, [filterDate]); + + return ( + + +
+ + + +
+ + +
+ + +
{`Pendapatan Per Item ${filterDate.format('DD-MM-YYYY')}`}
+ + +
{`Total revenue mungkin berbeda dengan pendapatan per item master disebabkan pengambilan harga kepada harga bundling.`}
+ + + } + > + + + +
+
TOTAL PAX
+
{dataItemTotalPax}
+
+
+ + + +
+
TOTAL REVENUE
+
+ {currencyFormatter({ value: dataItemTotalRevenue })} +
+
+
+ + +
+
child.key} // Make sure each child row has a unique key + expandable={{ expandedRowKeys: dataItemKeys, showExpandColumn: false }} + rowClassName={(row) => (row.key ? 'row-group' : '')} + rowHoverable={false} + columns={[ + { key: 'title', dataIndex: 'title', title: 'TITLE', width: 170 }, + { key: 'tr_item__qty', dataIndex: 'tr_item__qty', title: 'PAX', width: 70 }, + { + key: 'tr_item__total_net_price', + dataIndex: 'tr_item__total_net_price', + title: 'REVENUE', + width: 120, + render: (value) => currencyFormatter({ value }), + }, + ]} + /> + + + + + +
{`Pendapatan Per Item Master ${filterDate.format('DD-MM-YYYY')}`}
+ + +
{`Total revenue mungkin berbeda dengan pendapatan per item disebabkan harga item master mengambil harga jual standard item.`}
+ + + } + > + + + +
+
TOTAL PAX
+
+ {dataItemMasterTotalPax} +
+
+
+ + + +
+
TOTAL REVENUE
+
+ {currencyFormatter({ value: dataItemMasterTotalRevenue })} +
+
+
+ + +
+
child.key} // Make sure each child row has a unique key + expandable={{ expandedRowKeys: dataItemMasterKeys, showExpandColumn: false }} + rowClassName={(row) => (row.key ? 'row-group' : '')} + rowHoverable={false} + columns={[ + { key: 'title', dataIndex: 'title', title: 'TITLE', width: 170 }, + + { key: 'tr_item__qty', dataIndex: 'tr_item__qty', title: 'PAX', width: 70 }, + { + key: 'tr_item_bundling__total_net_price', + dataIndex: 'tr_item_bundling__total_net_price', + title: 'REVENUE', + width: 120, + render: (value) => currencyFormatter({ value }), + }, + ]} + /> + + + + + ); +} diff --git a/src/apps/admin/pages/setting.tsx b/src/apps/admin/pages/setting.tsx new file mode 100644 index 0000000..bb5ebc0 --- /dev/null +++ b/src/apps/admin/pages/setting.tsx @@ -0,0 +1,26 @@ +import { ACCESS_SETTING, UserDataState } from '@pos/base'; +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useRecoilValue } from 'recoil'; + +export default function SettingModule() { + const user = useRecoilValue(UserDataState); + const navigate = useNavigate(); + + function checkAllowAccessSetting() { + const username = user?.username; + const accessSetting = ACCESS_SETTING ?? ''; + + const allowList = accessSetting.split('|'); + if (allowList.includes(username)) return true; + return false; + } + + useEffect(() => { + if (!checkAllowAccessSetting()) { + navigate('/app'); + } + }, []); + + return
Setting
; +} diff --git a/src/apps/index.tsx b/src/apps/index.tsx index d095cbe..627aaa0 100644 --- a/src/apps/index.tsx +++ b/src/apps/index.tsx @@ -7,7 +7,7 @@ import { APP_THEME } from '@pos/base/presentation/assets/themes'; import { LoadingOutlined } from '@ant-design/icons'; const AuthApp = lazy(() => import('./auth')); -const PrivateApp = lazy(() => import('./admin')); +const AppModule = lazy(() => import('./admin/index')); export default function App() { return ( @@ -24,7 +24,7 @@ export default function App() { > } /> - } /> + } /> } /> } /> } /> diff --git a/src/base/infrastructure/constants/environment/index.ts b/src/base/infrastructure/constants/environment/index.ts index 64f6e2d..50d770c 100644 --- a/src/base/infrastructure/constants/environment/index.ts +++ b/src/base/infrastructure/constants/environment/index.ts @@ -10,3 +10,4 @@ export const DOWLOAD_POS_LINUX_DEB_URL = import.meta.env.VITE_DOWLOAD_POS_LINUX_ export const DOWLOAD_POS_LINUX_SNAP_URL = import.meta.env.VITE_DOWLOAD_POS_LINUX_SNAP_URL; export const BASE_API_URL_LOCAL = import.meta.env.VITE_BASE_API_URL_LOCAL; +export const ACCESS_SETTING = import.meta.env.VITE_BASE_ACCESS_SETTING; -- 2.40.1 From e737a89a2430bc84b16f9325773a350490108b90 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Fri, 4 Jul 2025 14:12:13 +0700 Subject: [PATCH 09/13] feat(SPG-1173): setup setting scheduling on realtime report --- .../admin/layout/components/default-value.tsx | 155 ++++++++++++++++++ src/apps/admin/layout/index.tsx | 2 +- src/apps/admin/pages/setting.tsx | 7 +- 3 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 src/apps/admin/layout/components/default-value.tsx diff --git a/src/apps/admin/layout/components/default-value.tsx b/src/apps/admin/layout/components/default-value.tsx new file mode 100644 index 0000000..310bc42 --- /dev/null +++ b/src/apps/admin/layout/components/default-value.tsx @@ -0,0 +1,155 @@ +import dayjs from 'dayjs'; +import { Button, Card, Col, Flex, InputNumber, Modal, Row, Form } from 'antd'; +import { Fragment, useEffect, useState } from 'react'; +import axios from 'axios'; +import { notificationError } from '@pos/base'; + +export default function DefaultValue() { + const [loading, setLoading] = useState(false); + const [loadingSave, setLoadingSave] = useState(false); + const [defaultPercentage, setDefaultPercentage] = useState(100); + const [currentPercentage, setCurrentPercentage] = useState(100); + + const [form] = Form.useForm(); + const [openModal, setOpenModal] = useState(false); + + const onCloseModal = async () => { + await form.resetFields(); + setOpenModal(false); + }; + + const onOpenModal = async () => { + await form.setFieldsValue({ default_value: defaultPercentage }); + setOpenModal(true); + }; + + const handleSaveData = async () => { + try { + const payload = await form.validateFields(); + setLoadingSave(true); + await axios + .post('v1/data-scheduling-default', payload) + .then(async (resp) => { + const value = resp.data?.data?.default_value; + await form.setFieldsValue({ default_value: value }); + setDefaultPercentage(value); + setLoadingSave(false); + onCloseModal(); + }) + .catch((err) => { + const message = err.message; + if (message) notificationError(message); + setLoadingSave(false); + }); + } catch (error) { + console.error(error); + } + }; + + const handleGetData = async () => { + setLoading(true); + await Promise.all([ + axios + .get('v1/data-scheduling-default') + .then((resp) => { + const value = resp.data?.data?.default_value; + form.setFieldsValue({ default_value: value }); + setDefaultPercentage(value); + }) + .catch((err) => { + const message = err.message; + if (message) notificationError(message); + }), + axios + .get('v1/data-scheduling-active', { params: { date: dayjs().format('YYYY-MM-DD') } }) + .then((resp) => { + const value = resp.data?.data?.value; + form.setFieldsValue({ value: value }); + setCurrentPercentage(value); + }) + .catch((err) => { + const message = err.message; + if (message) notificationError(message); + }), + ]); + setLoading(false); + }; + + useEffect(() => { + handleGetData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + DEFAULT PERCENTAGE} + > +
+ + + + + +
{`%`}
+
+
+
+ {`*Value akan diterapkan otomatis jika tidak ada pengaturan khusus pada tanggal tersebut.`} +
+ +
+ +
+ + +
DEFAULT PERCENTAGE
+ +
{`${defaultPercentage >= 0 ? `${defaultPercentage} %` : '-'}`}
+ +
+
+ {`Value otomatis jika tak ada setelan khusus.`} +
+
+
+ + + + +
CURRENT PERCENTAGE
+
{`${currentPercentage >= 0 ? `${currentPercentage} %` : '-'}`}
+
+ {`Value yang di terapkan hari ini ${dayjs().format('DD-MM-YYYY')}.`} +
+
+
+ + + + ); +} diff --git a/src/apps/admin/layout/index.tsx b/src/apps/admin/layout/index.tsx index 34af951..04cd658 100644 --- a/src/apps/admin/layout/index.tsx +++ b/src/apps/admin/layout/index.tsx @@ -89,7 +89,7 @@ export default function AdminLayout(props: AdminLayoutProps) { }, { key: '2', - label: 'Settings', + label: 'Setting', icon: , onClick: () => gotoSetting(), }, diff --git a/src/apps/admin/pages/setting.tsx b/src/apps/admin/pages/setting.tsx index bb5ebc0..030ecbc 100644 --- a/src/apps/admin/pages/setting.tsx +++ b/src/apps/admin/pages/setting.tsx @@ -2,6 +2,7 @@ import { ACCESS_SETTING, UserDataState } from '@pos/base'; import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; +import DefaultValue from '../layout/components/default-value'; export default function SettingModule() { const user = useRecoilValue(UserDataState); @@ -22,5 +23,9 @@ export default function SettingModule() { } }, []); - return
Setting
; + return ( +
+ +
+ ); } -- 2.40.1 From 1b9c6560070f5da898f527fcdf285ebf94c87249 Mon Sep 17 00:00:00 2001 From: Firman Ramdhani <33869609+firmanramdhani@users.noreply.github.com> Date: Mon, 7 Jul 2025 11:33:01 +0700 Subject: [PATCH 10/13] feat: setup crud scheduling data --- package.json | 2 +- .../components/default-value.tsx | 4 +- .../pages/components/scheduling-data.tsx | 207 ++++++++++++++++++ src/apps/admin/pages/setting.tsx | 11 +- 4 files changed, 218 insertions(+), 6 deletions(-) rename src/apps/admin/{layout => pages}/components/default-value.tsx (98%) create mode 100644 src/apps/admin/pages/components/scheduling-data.tsx diff --git a/package.json b/package.json index 6922e35..f2b9457 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,10 @@ "preview": "vite preview" }, "dependencies": { - "antd": "^5.21.2", "ag-grid-community": "^31.3.2", "ag-grid-enterprise": "^31.3.2", "ag-grid-react": "^31.3.2", + "antd": "^5.21.2", "axios": "^1.7.7", "crypto-js": "^4.2.0", "dayjs": "^1.11.13", diff --git a/src/apps/admin/layout/components/default-value.tsx b/src/apps/admin/pages/components/default-value.tsx similarity index 98% rename from src/apps/admin/layout/components/default-value.tsx rename to src/apps/admin/pages/components/default-value.tsx index 310bc42..7e07d20 100644 --- a/src/apps/admin/layout/components/default-value.tsx +++ b/src/apps/admin/pages/components/default-value.tsx @@ -118,7 +118,7 @@ export default function DefaultValue() { -
+
DEFAULT PERCENTAGE
@@ -136,7 +136,7 @@ export default function DefaultValue() {
- +
CURRENT PERCENTAGE
diff --git a/src/apps/admin/pages/components/scheduling-data.tsx b/src/apps/admin/pages/components/scheduling-data.tsx new file mode 100644 index 0000000..c8fb989 --- /dev/null +++ b/src/apps/admin/pages/components/scheduling-data.tsx @@ -0,0 +1,207 @@ +import dayjs from 'dayjs'; +import axios from 'axios'; +import { App, Button, Card, Col, Flex, List, notification, Pagination, Row, Tag, Tooltip } from 'antd'; +import { useEffect, useState } from 'react'; +import { makeColorStatus, STATUS_DATA } from '@pos/base'; + +import { DeleteOutlined, EditOutlined, LockOutlined, UnlockOutlined } from '@ant-design/icons'; + +export default function SchedulingData() { + const { modal } = App.useApp(); + + const [loadingTable, setLoadingTable] = useState(false); + const [schedulingData, setSchedulingData] = useState([]); + const [meta, setMeta] = useState(); + + const handleGetData = async (page: number) => { + setLoadingTable(true); + await axios + .get('v1/data-scheduling', { params: { page: page, limit: 10 } }) + .then((resp: any) => { + const data = resp?.data?.data ?? []; + const meta = resp?.data?.meta; + setMeta(meta); + setSchedulingData(data); + setLoadingTable(false); + }) + .catch(() => { + setLoadingTable(false); + }); + }; + + const handleActivate = async (id: string) => { + await axios + .patch(`v1/data-scheduling/${id}/active`) + .then(() => { + handleGetData(meta?.currentPage); + }) + .catch((err: any) => { + notification.error({ + message: 'Gagal mengaktifkan data.', + description: + err?.message ?? err?.response?.data?.message ?? 'Terjadi kesalahan saat mengaktifkan konfigurasi', + }); + }); + }; + + const handleDeactivate = async (id: string) => { + await axios + .patch(`v1/data-scheduling/${id}/inactive`) + .then(() => { + handleGetData(meta?.currentPage); + }) + .catch((err: any) => { + notification.error({ + message: 'Gagal menonaktifkan data.', + description: + err?.message ?? err?.response?.data?.message ?? 'Terjadi kesalahan saat menonaktifkan konfigurasi', + }); + }); + }; + + const handleDelete = async (id: string) => { + await axios + .delete(`v1/data-scheduling/${id}`) + .then(() => { + handleGetData(meta?.currentPage); + }) + .catch((err: any) => { + notification.error({ + message: 'Gagal menghapus data.', + description: err?.message ?? err?.response?.data?.message ?? 'Terjadi kesalahan saat menghapus konfigurasi', + }); + }); + }; + + function makeColorText(value: number) { + if (value <= 30) { + return 'text-red-500'; + } else if (value > 30 && value <= 80) { + return 'text-yellow-500'; + } else if (value > 80 && value <= 100) { + return 'text-green-500'; + } + } + + useEffect(() => { + handleGetData(1); + }, []); + + return ( +
+ +
+ ( + + + + +
+ +
+
{item.name}
+
{`${dayjs(item?.schedule_date_from).format('DD MMM YYYY')} - ${dayjs(item?.schedule_date_to).format('DD MMM YYYY')}`}
+
+
+ + + +
{`${item.indexing_key} %`}
+ {item.status} +
+ + + + + + +
{item.name}
@@ -109,16 +100,16 @@ export default function SchedulingData() {
- +
{`${item.indexing_key} %`}
{item.status}
- + -
- ( - - - - -
- -
-
{item.name}
-
{`${dayjs(item?.schedule_date_from).format('DD MMM YYYY')} - ${dayjs(item?.schedule_date_to).format('DD MMM YYYY')}`}
-
-
- - - -
{`${item.indexing_key} %`}
- {item.status} -
- - - - - + + + + + + + + + + + + {({ getFieldsValue }) => { + const values = getFieldsValue(); + const endDate = values?.schedule_date_to; - {item.status === STATUS_DATA.ACTIVE && ( - - + + {({ getFieldsValue }) => { + const values = getFieldsValue(); + const startDate = values?.schedule_date_from; - {item.status === STATUS_DATA.INACTIVE && ( - - + + {schedulingData?.length > 0 && ( + + + )} - /> -
- - - +
+ ( + + + + +
+ +
+
+ {capitalizeEachWord(item.status)} +
+
{item.name}
+
{`${dayjs(item?.schedule_date_from).format('DD MMM YYYY')} - ${dayjs(item?.schedule_date_to).format('DD MMM YYYY')}`}
+
+
+ + + +
{`${item.indexing_key} %`}
+
+ + + + + - +
DEFAULT PERCENTAGE
@@ -139,13 +153,18 @@ export default function DefaultValue() {
- +
CURRENT PERCENTAGE
-
{`${currentPercentage >= 0 ? `${currentPercentage} %` : '-'}`}
+ +
{`${currentPercentage >= 0 ? `${currentPercentage} %` : '-'}`}
+ +
{`Value yang di terapkan hari ini ${dayjs().format('DD-MM-YYYY')}.`}
-- 2.40.1