diff --git a/apps/backoffice/src/app/gacha-roll/_components/modal-add-item.tsx b/apps/backoffice/src/app/gacha-roll/_components/modal-add-item.tsx
new file mode 100644
index 0000000..b077c94
--- /dev/null
+++ b/apps/backoffice/src/app/gacha-roll/_components/modal-add-item.tsx
@@ -0,0 +1,155 @@
+import { Button } from '@imphnen-frontend-service/ui/atoms';
+import { InputField, Modal } from '@imphnen-frontend-service/ui/molecules';
+import { useState } from 'react';
+
+interface IModalAddItem {
+ isOpen: boolean;
+ onClose: () => void;
+ handleAddItem?: () => void;
+ currentStep?: number;
+ nextStep: () => void;
+ prevStep: () => void;
+ resetStep: () => void;
+}
+
+const ModalAddItem = ({
+ isOpen,
+ onClose,
+ currentStep,
+ nextStep,
+ prevStep,
+ resetStep,
+ handleAddItem,
+}: IModalAddItem) => {
+ return (
+ {
+ onClose();
+ resetStep();
+ }}
+ disableEscapeKeyDown={true}
+ >
+ {currentStep === 1 && }
+ {currentStep === 2 && (
+
+ )}
+
+ );
+};
+
+interface IStepOneProps {
+ nextStep: () => void;
+ onClose: () => void;
+}
+
+const StepOne = ({ nextStep }: IStepOneProps) => {
+ const [itemName, setItemName] = useState('');
+ const [quantity, setQuantity] = useState('');
+ const [chanceRate, setChanceRate] = useState('');
+
+ return (
+ <>
+
+
+ Tambah Item Roll Gacha
+
+
+ Lengkapi detal di bawah ini, untuk menambahkan item gacha
+
+
+
+
+ setItemName(e.target.value)}
+ size="lg"
+ className="w-full"
+ />
+ setQuantity(e.target.value)}
+ size="lg"
+ className="w-full"
+ />
+ setChanceRate(e.target.value)}
+ size="lg"
+ className="w-full"
+ />
+
+
+
+
+ >
+ );
+};
+
+interface IStepTwoProps {
+ onClose: () => void;
+ handleAddItem?: () => void;
+ resetStep: () => void;
+}
+
+const StepTwo = ({ onClose, handleAddItem, resetStep }: IStepTwoProps) => (
+ <>
+
+
+ Tambah ke Roll Gacha
+
+
+ Apakah kamu yakin ingin
+
menambahkan item ini ke roll gacha?
+
+
+
+
+
+
+ >
+);
+
+export default ModalAddItem;
diff --git a/apps/backoffice/src/app/gacha-roll/_components/modal-delete-item.tsx b/apps/backoffice/src/app/gacha-roll/_components/modal-delete-item.tsx
new file mode 100644
index 0000000..3663ee0
--- /dev/null
+++ b/apps/backoffice/src/app/gacha-roll/_components/modal-delete-item.tsx
@@ -0,0 +1,62 @@
+import { Button } from '@imphnen-frontend-service/ui/atoms';
+import { Modal } from '@imphnen-frontend-service/ui/molecules';
+
+interface IModalDeleteItem {
+ isOpen: boolean;
+ onClose: () => void;
+ handleDeleteItem?: () => void;
+}
+
+const ModalDeleteItem = ({
+ isOpen,
+ onClose,
+ handleDeleteItem,
+}: IModalDeleteItem) => {
+ return (
+
+
+
+
+
+ Delete Item
+
+
+ Apakah kamu yakin untuk menghapus item ini?
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ModalDeleteItem;
diff --git a/apps/backoffice/src/app/gacha-roll/_components/modal-update-item.tsx b/apps/backoffice/src/app/gacha-roll/_components/modal-update-item.tsx
new file mode 100644
index 0000000..f9dee1c
--- /dev/null
+++ b/apps/backoffice/src/app/gacha-roll/_components/modal-update-item.tsx
@@ -0,0 +1,152 @@
+import { Button } from '@imphnen-frontend-service/ui/atoms';
+import { InputField, Modal } from '@imphnen-frontend-service/ui/molecules';
+import { useState } from 'react';
+
+interface IModalUpdateItem {
+ isOpen: boolean;
+ onClose: () => void;
+ handleUpdateItem?: () => void;
+ currentStep?: number;
+ nextStep: () => void;
+ prevStep: () => void;
+ resetStep: () => void;
+}
+
+const ModalUpdateItem = ({
+ isOpen,
+ onClose,
+ currentStep,
+ nextStep,
+ prevStep,
+ resetStep,
+ handleUpdateItem,
+}: IModalUpdateItem) => {
+ return (
+ {
+ onClose();
+ resetStep();
+ }}
+ disableEscapeKeyDown={true}
+ >
+ {currentStep === 1 && }
+ {currentStep === 2 && (
+
+ )}
+
+ );
+};
+
+interface IStepOneProps {
+ nextStep: () => void;
+ onClose: () => void;
+}
+
+const StepOne = ({ nextStep }: IStepOneProps) => {
+ const [itemName, setItemName] = useState('Hoodie IMPHNEN Official 2025');
+ const [quantity, setQuantity] = useState('10');
+ const [chanceRate, setChanceRate] = useState('0.1');
+
+ return (
+ <>
+
+
+ Update Item Roll Gacha
+
+
+
+
+ setItemName(e.target.value)}
+ size="lg"
+ className="w-full"
+ />
+ setQuantity(e.target.value)}
+ size="lg"
+ className="w-full"
+ />
+ setChanceRate(e.target.value)}
+ size="lg"
+ className="w-full"
+ />
+
+
+
+
+ >
+ );
+};
+
+interface IStepTwoProps {
+ onClose: () => void;
+ handleUpdateItem?: () => void;
+ resetStep: () => void;
+}
+
+const StepTwo = ({ onClose, handleUpdateItem, resetStep }: IStepTwoProps) => (
+ <>
+
+
+ Update Item
+
+
+ Apakah kamu yakin dengan
+
perubahan yang dilakukan?
+
+
+
+
+
+
+ >
+);
+
+export default ModalUpdateItem;
diff --git a/apps/backoffice/src/app/gacha-roll/layout.tsx b/apps/backoffice/src/app/gacha-roll/layout.tsx
new file mode 100644
index 0000000..a770c99
--- /dev/null
+++ b/apps/backoffice/src/app/gacha-roll/layout.tsx
@@ -0,0 +1,18 @@
+import { FC, ReactElement } from 'react';
+import { Outlet } from 'react-router-dom';
+import { BackofficeSidebar } from '@imphnen-frontend-service/ui/organisms';
+
+export const AppLayout: FC = (): ReactElement => {
+ return (
+
+ );
+};
+
+export default AppLayout;
diff --git a/apps/backoffice/src/app/gacha-roll/page.tsx b/apps/backoffice/src/app/gacha-roll/page.tsx
new file mode 100644
index 0000000..0bc7499
--- /dev/null
+++ b/apps/backoffice/src/app/gacha-roll/page.tsx
@@ -0,0 +1,216 @@
+import * as React from 'react';
+
+import { FC, Fragment, ReactElement, useState } from 'react';
+import {
+ SearchOutlined,
+ EditOutlined,
+ DeleteOutlined,
+ PlusOutlined,
+} from '@ant-design/icons';
+import { Button, Input } from '@imphnen-frontend-service/ui/atoms';
+import { DataTable } from '@imphnen-frontend-service/ui/organisms';
+
+import {
+ ColumnDef,
+ getCoreRowModel,
+ getPaginationRowModel,
+ PaginationState,
+ useReactTable,
+ RowSelectionState,
+} from '@tanstack/react-table';
+import ModalAddItem from './_components/modal-add-item';
+import ModalUpdateItem from './_components/modal-update-item';
+import ModalDeleteItem from './_components/modal-delete-item';
+import { useQueryState } from '@imphnen-frontend-service/utils';
+
+interface GachaItem {
+ id: number;
+ name: string;
+ chanceRate: number;
+ quantity: number;
+}
+
+const mockData: GachaItem[] = Array.from({ length: 90 }, (_, i) => ({
+ id: i + 1,
+ name: 'Hoodie IMPHNEN Official 2025',
+ chanceRate: 0.1,
+ quantity: 10,
+}));
+
+export const Components: FC = (): ReactElement => {
+ const [showModalAddItem, setShowModalAddItem] = useState(false);
+ const [showModalUpdateItem, setShowModalUpdateItem] = useState(false);
+ const [showModalDeleteItem, setShowModalDeleteItem] = 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,
+ });
+
+ const [rowSelection, setRowSelection] = React.useState({});
+
+ const columns: ColumnDef[] = [
+ {
+ id: 'select',
+ header: ({ table }) => (
+
+ ),
+ cell: ({ row }) => (
+
+ ),
+ },
+ {
+ header: 'No',
+ accessorKey: 'id',
+ },
+ {
+ header: 'Nama Item',
+ accessorKey: 'name',
+ },
+ {
+ header: 'Chance Rate',
+ accessorKey: 'chanceRate',
+ },
+ {
+ header: 'Quantity',
+ accessorKey: 'quantity',
+ },
+ {
+ header: 'Action',
+ cell: () => (
+
+
+
+
+ ),
+ },
+ ];
+
+ const table = useReactTable({
+ data: mockData,
+ columns,
+ state: {
+ pagination,
+ rowSelection,
+ },
+ enableRowSelection: true,
+ onRowSelectionChange: setRowSelection,
+ getCoreRowModel: getCoreRowModel(),
+ getPaginationRowModel: getPaginationRowModel(),
+ onPaginationChange: setPagination,
+ pageCount: Math.ceil(mockData.length / pagination.pageSize),
+ manualPagination: false,
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setShowModalAddItem(false)}
+ handleAddItem={() => {
+ console.log('Item added');
+ }}
+ nextStep={nextStep}
+ prevStep={prevStep}
+ resetStep={resetStep}
+ />
+ setShowModalUpdateItem(false)}
+ handleUpdateItem={() => {
+ console.log('Item updated');
+ }}
+ nextStep={nextStep}
+ prevStep={prevStep}
+ resetStep={resetStep}
+ />
+ setShowModalDeleteItem(false)}
+ handleDeleteItem={() => {
+ console.log('Item deleted');
+ }}
+ />
+
+ );
+};
+
+export default Components;