diff --git a/apps/gacha/src/app/page.tsx b/apps/gacha/src/app/page.tsx
index eefefed..6cac5b2 100644
--- a/apps/gacha/src/app/page.tsx
+++ b/apps/gacha/src/app/page.tsx
@@ -1,9 +1,9 @@
import { ArrowDownOutlined } from '@ant-design/icons';
import { Button } from '@imphnen-frontend-service/ui/atoms';
-import { ModalsGacha } from '@imphnen-frontend-service/ui/organisms';
+import { InputForm, Modal } from '@imphnen-frontend-service/ui/molecules';
import { cn } from '@imphnen-frontend-service/utils';
import { FC, Fragment, ReactElement, useEffect, useState } from 'react';
-import { createPortal } from 'react-dom';
+import { Link } from 'react-router';
interface GachaItemProps {
src: string;
@@ -14,7 +14,6 @@ interface GachaItemProps {
export const Components: FC = (): ReactElement => {
// Pinjem
const [showModal, setShowModal] = useState(false);
- //
const scrollToRoulette = () => {
const rouletteSection = document.getElementById('roulette');
@@ -222,16 +221,58 @@ export const Components: FC = (): ReactElement => {
{/**Izin pake untuk debug modals gacha */}
-
-
Debug : Test Modals Gacha
-
-
- {showModal && createPortal(
- ,
- document.body
- )}
+
+ setShowModal(false)}
+ >
+
+
+
+ Login
+
+
+
+
+
+
+
+ Lupa Password?
+
+
+
+
+
+
+
Belum punya akun?
+
+ Daftar disini
+
+
+
+
{/**Izin pake untuk debug modals gacha */}
);
diff --git a/libs/ui/src/molecules/index.ts b/libs/ui/src/molecules/index.ts
index dbe5a6d..e13b7fd 100644
--- a/libs/ui/src/molecules/index.ts
+++ b/libs/ui/src/molecules/index.ts
@@ -1,2 +1,3 @@
export * from './input-form';
export * from './pagination';
+export * from './modal';
diff --git a/libs/ui/src/molecules/modal/index.tsx b/libs/ui/src/molecules/modal/index.tsx
new file mode 100644
index 0000000..2f0d9ba
--- /dev/null
+++ b/libs/ui/src/molecules/modal/index.tsx
@@ -0,0 +1,190 @@
+import { CloseOutlined } from '@ant-design/icons';
+import { cn } from '@imphnen-frontend-service/utils';
+import React, { useEffect, useMemo, useCallback } from 'react';
+import { createPortal } from 'react-dom';
+
+interface ModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ children: React.ReactNode;
+ className?: string;
+ overlayClassName?: string;
+ closeButtonClassName?: string;
+ disableEscapeKeyDown?: boolean;
+ 'aria-label'?: string;
+ 'aria-labelledby'?: string;
+ 'aria-describedby'?: string;
+}
+
+const Modal = ({
+ isOpen,
+ onClose,
+ children,
+ className,
+ overlayClassName,
+ closeButtonClassName,
+ disableEscapeKeyDown = false,
+ 'aria-label': ariaLabel,
+ 'aria-labelledby': ariaLabelledBy,
+ 'aria-describedby': ariaDescribedBy,
+}: ModalProps) => {
+ const handleEscapeKey = useCallback(
+ (event: KeyboardEvent) => {
+ if (event.key === 'Escape' && isOpen && !disableEscapeKeyDown) {
+ onClose();
+ }
+ },
+ [isOpen, onClose, disableEscapeKeyDown]
+ );
+
+ useEffect(() => {
+ if (isOpen) {
+ document.body.style.overflow = 'hidden';
+ window.addEventListener('keydown', handleEscapeKey);
+ } else {
+ document.body.style.overflow = '';
+ }
+
+ return () => {
+ document.body.style.overflow = '';
+ window.removeEventListener('keydown', handleEscapeKey);
+ };
+ }, [isOpen, handleEscapeKey]);
+
+ const modalNode = useMemo(() => document.createElement('div'), []);
+
+ useEffect(() => {
+ document.body.appendChild(modalNode);
+ return () => {
+ document.body.removeChild(modalNode);
+ };
+ }, [modalNode]);
+
+ if (!isOpen) return null;
+
+ return createPortal(
+
+
+
+ {children}
+
+
+
,
+ modalNode
+ );
+};
+
+interface ModalHeaderProps {
+ className?: string;
+ children: React.ReactNode;
+}
+
+const ModalHeader = ({ className, children }: ModalHeaderProps) => (
+
+ {children}
+
+);
+
+interface ModalContentProps {
+ className?: string;
+ children: React.ReactNode;
+}
+
+const ModalContent = ({ className, children }: ModalContentProps) => (
+ {children}
+);
+
+interface ModalFooterProps {
+ className?: string;
+ children: React.ReactNode;
+}
+
+const ModalFooter = ({ className, children }: ModalFooterProps) => (
+
+ {children}
+
+);
+
+interface ModalTitleProps {
+ className?: string;
+ children: React.ReactNode;
+ id?: string;
+}
+
+const ModalTitle = ({ className, children, id }: ModalTitleProps) => (
+
+ {children}
+
+);
+
+interface ModalDescriptionProps {
+ className?: string;
+ children: React.ReactNode;
+ id?: string;
+}
+
+const ModalDescription = ({
+ className,
+ children,
+ id,
+}: ModalDescriptionProps) => (
+
+ {children}
+
+);
+
+Modal.Header = ModalHeader;
+Modal.Content = ModalContent;
+Modal.Footer = ModalFooter;
+Modal.Title = ModalTitle;
+Modal.Description = ModalDescription;
+
+export { Modal };
+export type {
+ ModalProps,
+ ModalHeaderProps,
+ ModalContentProps,
+ ModalFooterProps,
+ ModalTitleProps,
+ ModalDescriptionProps,
+};
diff --git a/libs/ui/src/organisms/navbar/navbar.tsx b/libs/ui/src/organisms/navbar/navbar.tsx
index e6822e7..f431833 100644
--- a/libs/ui/src/organisms/navbar/navbar.tsx
+++ b/libs/ui/src/organisms/navbar/navbar.tsx
@@ -40,6 +40,14 @@ export const Navbar: FC = (): ReactElement => {
Merch Gacha
+
+
+