diff --git a/apps/backoffice/src/app/accounts/_components/modal-edit-account.tsx b/apps/backoffice/src/app/accounts/_components/modal-edit-account.tsx index 0e23a97..adb382a 100644 --- a/apps/backoffice/src/app/accounts/_components/modal-edit-account.tsx +++ b/apps/backoffice/src/app/accounts/_components/modal-edit-account.tsx @@ -7,36 +7,36 @@ interface IModalEditAccount { onClose: () => void; handleEditAccount?: () => void; currentStep?: number; + nextStep: () => void; + prevStep: () => void; + resetStep: () => void; } const ModalEditAccount = ({ isOpen, onClose, + currentStep, + nextStep, + prevStep, + resetStep, handleEditAccount, - currentStep = 1, }: IModalEditAccount) => { return ( { + onClose(); + resetStep(); + }} disableEscapeKeyDown={true} > - {currentStep === 1 && ( - { - console.log('Next step'); - }} - onClose={onClose} - /> - )} + {currentStep === 1 && } {currentStep === 2 && ( { - console.log('Reset step'); - }} + resetStep={resetStep} /> )} @@ -48,7 +48,7 @@ interface IStepOneProps { onClose: () => void; } -const StepOne = ({ nextStep, onClose }: IStepOneProps) => { +const StepOne = ({ nextStep }: IStepOneProps) => { const [fullName, setFullName] = useState('Ahmad Wiyana'); const [email, setEmail] = useState('fullname23@gmail.com'); const [phoneNumber, setPhoneNumber] = useState('081904423804'); @@ -136,7 +136,10 @@ const StepTwo = ({ onClose, handleEditAccount, resetStep }: IStepTwoProps) => ( variant="bordered" size="lg" className="w-full" - onClick={resetStep} + onClick={() => { + onClose(); + resetStep(); + }} > Batal @@ -146,6 +149,8 @@ const StepTwo = ({ onClose, handleEditAccount, resetStep }: IStepTwoProps) => ( className="w-full" onClick={() => { handleEditAccount && handleEditAccount(); + onClose(); + resetStep(); }} > Update diff --git a/apps/backoffice/src/app/accounts/page.tsx b/apps/backoffice/src/app/accounts/page.tsx index 9ce96b6..e762610 100644 --- a/apps/backoffice/src/app/accounts/page.tsx +++ b/apps/backoffice/src/app/accounts/page.tsx @@ -18,6 +18,7 @@ import { RowSelectionState, } from '@tanstack/react-table'; import ModalEditAccount from './_components/modal-edit-account'; +import { useQueryState } from '../../hook/use-query-state'; interface Account { id: number; @@ -39,6 +40,17 @@ const mockData: Account[] = Array.from({ length: 90 }, (_, i) => ({ export const Components: FC = (): ReactElement => { const [showModalEditAccount, setShowModalEditAccount] = useState(false); + const { + step: currentStep, + nextStep, + prevStep, + resetStep, + } = useQueryState('step', { + defaultValue: 1, + maxValue: 2, + minValue: 1, + }); + const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize: 9, @@ -166,11 +178,15 @@ export const Components: FC = (): ReactElement => { {/* Modal Edit Account */} setShowModalEditAccount(false)} handleEditAccount={() => { console.log('Account updated'); }} + nextStep={nextStep} + prevStep={prevStep} + resetStep={resetStep} /> ); diff --git a/apps/backoffice/src/app/dashboard/_components/modal-add-item.tsx b/apps/backoffice/src/app/dashboard/_components/modal-add-item.tsx index 2b561f1..85c92b4 100644 --- a/apps/backoffice/src/app/dashboard/_components/modal-add-item.tsx +++ b/apps/backoffice/src/app/dashboard/_components/modal-add-item.tsx @@ -6,49 +6,47 @@ interface IModalAddItem { onClose: () => void; handleAddItem: () => void; currentStep?: number; + nextStep: () => void; + prevStep: () => void; + resetStep: () => void; } const ModalAddItem = ({ isOpen, onClose, + currentStep, + nextStep, + resetStep, handleAddItem, - currentStep = 1, }: IModalAddItem) => { return ( { + onClose(); + resetStep(); + }} disableEscapeKeyDown={true} > - {currentStep === 1 && ( - { - console.log('Next step'); - }} - onClose={onClose} - /> - )} + {currentStep === 1 && } {currentStep === 2 && ( { - console.log('Reset step'); - }} + resetStep={resetStep} /> )} ); }; -// TODO: Functional stepper interface IStepOneProps { nextStep: () => void; onClose: () => void; } -const StepOne = ({ nextStep, onClose }: IStepOneProps) => ( +const StepOne = ({ nextStep }: IStepOneProps) => ( <>

@@ -83,7 +81,7 @@ const StepOne = ({ nextStep, onClose }: IStepOneProps) => ( /> - @@ -92,8 +90,8 @@ const StepOne = ({ nextStep, onClose }: IStepOneProps) => ( interface IStepTwoProps { onClose: () => void; - resetStep: () => void; handleAddItem?: () => void; + resetStep: () => void; } const StepTwo = ({ onClose, handleAddItem, resetStep }: IStepTwoProps) => ( @@ -112,7 +110,10 @@ const StepTwo = ({ onClose, handleAddItem, resetStep }: IStepTwoProps) => ( variant="bordered" size="lg" className="w-full" - onClick={resetStep} + onClick={() => { + onClose(); + resetStep(); + }} > Batal @@ -122,6 +123,8 @@ const StepTwo = ({ onClose, handleAddItem, resetStep }: IStepTwoProps) => ( className="w-full" onClick={() => { handleAddItem && handleAddItem(); + onClose(); + resetStep(); }} > Tambahkan diff --git a/apps/backoffice/src/app/dashboard/_components/modal-edit-item.tsx b/apps/backoffice/src/app/dashboard/_components/modal-edit-item.tsx index 6166933..8e88a89 100644 --- a/apps/backoffice/src/app/dashboard/_components/modal-edit-item.tsx +++ b/apps/backoffice/src/app/dashboard/_components/modal-edit-item.tsx @@ -6,35 +6,35 @@ interface IModalEditItem { onClose: () => void; handleEditItem?: () => void; currentStep?: number; + nextStep: () => void; + prevStep: () => void; + resetStep: () => void; } const ModalEditItem = ({ isOpen, onClose, + currentStep, + nextStep, + resetStep, handleEditItem, - currentStep = 1, }: IModalEditItem) => { return ( { + onClose(); + resetStep(); + }} disableEscapeKeyDown={true} > - {currentStep === 1 && ( - { - console.log('Next step'); - }} - onClose={onClose} - /> - )} + {currentStep === 1 && } {currentStep === 2 && ( { - console.log('Reset step'); - }} + handleEditItem={handleEditItem} + resetStep={resetStep} /> )} @@ -46,7 +46,7 @@ interface IStepOneProps { onClose: () => void; } -const StepOne = ({ nextStep, onClose }: IStepOneProps) => ( +const StepOne = ({ nextStep }: IStepOneProps) => ( <>

@@ -110,7 +110,10 @@ const StepTwo = ({ onClose, handleEditItem, resetStep }: IStepTwoProps) => ( variant="bordered" size="lg" className="w-full" - onClick={resetStep} + onClick={() => { + onClose(); + resetStep(); + }} > Batal @@ -120,6 +123,8 @@ const StepTwo = ({ onClose, handleEditItem, resetStep }: IStepTwoProps) => ( className="w-full" onClick={() => { handleEditItem && handleEditItem(); + onClose(); + resetStep(); }} > Update diff --git a/apps/backoffice/src/app/dashboard/page.tsx b/apps/backoffice/src/app/dashboard/page.tsx index 3559af7..d337e53 100644 --- a/apps/backoffice/src/app/dashboard/page.tsx +++ b/apps/backoffice/src/app/dashboard/page.tsx @@ -10,12 +10,24 @@ import { FC, Fragment, ReactElement, useState } from 'react'; import ModalAddItem from './_components/modal-add-item'; import ModalEditItem from './_components/modal-edit-item'; import ModalDeleteItem from './_components/modal-delete-item'; +import { useQueryState } from '../../hook/use-query-state'; export const Components: FC = (): ReactElement => { const [showModalAddItem, setShowModalAddItem] = useState(false); const [showModalEditItem, setShowModalEditItem] = useState(false); const [showModalDeleteItem, setShowModalDeleteItem] = useState(false); + const { + step: currentStep, + nextStep, + prevStep, + resetStep, + } = useQueryState('step', { + defaultValue: 1, + maxValue: 2, + minValue: 1, + }); + return (
@@ -159,20 +171,28 @@ export const Components: FC = (): ReactElement => { {/* Modal Add Item */} setShowModalAddItem(false)} handleAddItem={() => { console.log('Item added'); }} + nextStep={nextStep} + prevStep={prevStep} + resetStep={resetStep} /> {/* Modal Edit Item */} setShowModalEditItem(false)} handleEditItem={() => { console.log('Item edited'); }} + nextStep={nextStep} + prevStep={prevStep} + resetStep={resetStep} /> {/* Modal Delete Item */} diff --git a/apps/backoffice/src/hook/use-query-state.tsx b/apps/backoffice/src/hook/use-query-state.tsx new file mode 100644 index 0000000..3943f95 --- /dev/null +++ b/apps/backoffice/src/hook/use-query-state.tsx @@ -0,0 +1,71 @@ +import { useCallback, useEffect, useState } from 'react'; + +interface UseQueryStateOptions { + defaultValue: number; + maxValue?: number; + minValue?: number; +} + +export const useQueryState = (key: string, options: UseQueryStateOptions) => { + const { defaultValue, maxValue = Infinity, minValue = 1 } = options; + + const getQueryParam = (param: string): string | null => { + if (typeof window === 'undefined') return null; + const searchParams = new URLSearchParams(window.location.search); + return searchParams.get(param); + }; + + const setQueryParam = (param: string, value: string) => { + const searchParams = new URLSearchParams(window.location.search); + searchParams.set(param, value); + const newUrl = `${window.location.pathname}?${searchParams.toString()}`; + window.history.replaceState(null, '', newUrl); + }; + + const initialValue = () => { + const queryValue = getQueryParam(key); + const parsedValue = queryValue ? parseInt(queryValue, 10) : defaultValue; + return Math.max(minValue, Math.min(maxValue, parsedValue)); + }; + + const [value, setValue] = useState(initialValue); + + useEffect(() => { + const handlePopState = () => { + const queryValue = getQueryParam(key); + const newValue = queryValue ? parseInt(queryValue, 10) : defaultValue; + setValue(Math.max(minValue, Math.min(maxValue, newValue))); + }; + + window.addEventListener('popstate', handlePopState); + return () => window.removeEventListener('popstate', handlePopState); + }, [key, defaultValue, minValue, maxValue]); + + const updateValue = useCallback( + (newValue: number) => { + const constrainedValue = Math.max(minValue, Math.min(maxValue, newValue)); + setValue(constrainedValue); + setQueryParam(key, constrainedValue.toString()); + }, + [key, minValue, maxValue] + ); + + const nextStep = useCallback(() => { + updateValue(value + 1); + }, [value, updateValue]); + + const prevStep = useCallback(() => { + updateValue(value - 1); + }, [value, updateValue]); + + const resetStep = useCallback(() => { + updateValue(defaultValue); + }, [defaultValue, updateValue]); + + return { + step: value, + nextStep, + prevStep, + resetStep, + }; +}; diff --git a/libs/ui/src/organisms/modal-backoffice/index.ts b/libs/ui/src/organisms/modal-backoffice/index.ts deleted file mode 100644 index 47fe845..0000000 --- a/libs/ui/src/organisms/modal-backoffice/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './modal-backoffice'; diff --git a/libs/ui/src/organisms/modal-backoffice/modal-backoffice.tsx b/libs/ui/src/organisms/modal-backoffice/modal-backoffice.tsx deleted file mode 100644 index 5c9ba0d..0000000 --- a/libs/ui/src/organisms/modal-backoffice/modal-backoffice.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { ReactElement, ReactNode } from 'react'; - -interface ModalBackofficeProps { - children: ReactNode; - className?: string; -} - -export const ModalBackoffice = ({ - children, - className, - ...rest -}: ModalBackofficeProps): ReactElement => { - return ( -
- {children} -
- ); -}; - -export default ModalBackoffice; diff --git a/libs/ui/src/organisms/modal-backoffice/modal.stories.tsx b/libs/ui/src/organisms/modal-backoffice/modal.stories.tsx deleted file mode 100644 index 2eb38e1..0000000 --- a/libs/ui/src/organisms/modal-backoffice/modal.stories.tsx +++ /dev/null @@ -1,373 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { ModalBackoffice } from './modal-backoffice'; -import { InputForm } from '../../molecules'; -import { Button } from '../../atoms'; - -const meta: Meta = { - title: 'Organisms/Modal Backoffice', - component: ModalBackoffice, - tags: ['autodocs'], - parameters: { - layout: 'centered', - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Default: Story = { - args: { - // isOpen: true, - // onClose: () => console.log('Modal closed'), - // title: 'Sample Modal', - children: ( - <> -

- Modal Title -

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas repellat - rerum doloremque dolorem fugit architecto eos blanditiis ratione - facere? Esse dolores inventore deleniti. Dicta voluptatem dolore vel - quia amet dolorem? -

-
- - ), - }, -}; - -export const TambahItemGacha: Story = { - args: { - children: ( -
-
-

- Tambah Item Gacha -

-

- Lengkapi detail di bawah ini untuk menambahkan item gacha -

-
-
- - - -
- -
- ), - }, -}; - -export const TambahItem: Story = { - args: { - children: ( -
-
-

- Tambah Item -

-

- Apakah kamu yakin ingin -
menambahkan item ini? -

-
-
- - -
-
- ), - }, -}; - -export const EditItemGacha: Story = { - args: { - children: ( -
-
-

- Edit Item Gacha -

-

- Silakan mengubah detail dari item yang diperlukan -

-
-
- - - -
- -
- ), - }, -}; - -export const UpdateItem: Story = { - args: { - children: ( -
-
-

- Update Item -

-

- Apakah kamu yakin dengan -
perubahan yang dilakukan? -

-
-
- - -
-
- ), - }, -}; - -export const DeleteItem: Story = { - args: { - children: ( -
- Delete item? -
-

- Delete Item -

-

- Apakah kamu yakin untuk menghapus item ini? -

-
-
- - -
-
- ), - }, -}; - -export const EditDataAkun: Story = { - args: { - children: ( -
-

- Edit Data Akun -

- -
- - - - -
- -
- ), - }, -}; - -export const UpdateDataAkun: Story = { - args: { - children: ( -
-
-

- Update Data -

-

- Apakah kamu yakin dengan -
perubahan yang dilakukan? -

-
-
- - -
-
- ), - }, -}; - -export const ValidasiTransaksi: Story = { - args: { - children: ( -
-

- Validasi Transaksi -

- - -
- - -
-
- ), - }, -}; - -export const ProsesDelivery: Story = { - args: { - children: ( -
-
-

- Delivery Process -

- -

- Lakukan pengiriman hadiah gacha untuk pengguna di bawah ini, jika - sudah ubah status menjadi “Delivered”. -

-
- -
- - - - -
- -
- ), - }, -};