diff --git a/app/src/state/modals.tsx b/app/src/state/modals.tsx new file mode 100644 index 0000000..12e1d19 --- /dev/null +++ b/app/src/state/modals.tsx @@ -0,0 +1,112 @@ +import type { JSX, PropsWithChildren } from "react"; +import { createContext, useCallback, useContext, useMemo, useRef, useState } from "react"; +import { useWallet, type WalletName } from "@/state/wallet"; + +export type CheckoutStep = "review" | "pending" | "success"; + +interface ModalContextValue { + isWalletSheetOpen: boolean; + isCheckoutSheetOpen: boolean; + checkoutListingId: number | null; + checkoutStep: CheckoutStep; + requestBuy: (listingId: number) => void; + openWalletConnect: () => void; + connectWallet: (wallet: WalletName) => void; + closeWalletSheet: () => void; + closeCheckoutSheet: () => void; + confirmOrder: () => void; +} + +const ModalContext = createContext(null); + +export function ModalProvider({ children }: PropsWithChildren): JSX.Element { + const { connected, connect } = useWallet(); + const [isWalletSheetOpen, setWalletSheetOpen] = useState(false); + const [isCheckoutSheetOpen, setCheckoutSheetOpen] = useState(false); + const [checkoutListingId, setCheckoutListingId] = useState(null); + const [checkoutStep, setCheckoutStep] = useState("review"); + const pendingListingId = useRef(null); + + const requestBuy = useCallback( + (listingId: number) => { + if (connected) { + setCheckoutListingId(listingId); + setCheckoutStep("review"); + setCheckoutSheetOpen(true); + } else { + pendingListingId.current = listingId; + setWalletSheetOpen(true); + } + }, + [connected], + ); + + const openWalletConnect = useCallback(() => { + pendingListingId.current = null; + setWalletSheetOpen(true); + }, []); + + const connectWallet = useCallback( + (wallet: WalletName) => { + connect(wallet); + setWalletSheetOpen(false); + const listingId = pendingListingId.current; + pendingListingId.current = null; + if (listingId !== null) { + setCheckoutListingId(listingId); + setCheckoutStep("review"); + setCheckoutSheetOpen(true); + } + }, + [connect], + ); + + const closeWalletSheet = useCallback(() => { + setWalletSheetOpen(false); + pendingListingId.current = null; + }, []); + + const closeCheckoutSheet = useCallback(() => { + setCheckoutSheetOpen(false); + }, []); + + const confirmOrder = useCallback(() => { + setCheckoutStep("pending"); + setTimeout(() => setCheckoutStep("success"), 2200); + }, []); + + const value = useMemo( + () => ({ + isWalletSheetOpen, + isCheckoutSheetOpen, + checkoutListingId, + checkoutStep, + requestBuy, + openWalletConnect, + connectWallet, + closeWalletSheet, + closeCheckoutSheet, + confirmOrder, + }), + [ + isWalletSheetOpen, + isCheckoutSheetOpen, + checkoutListingId, + checkoutStep, + requestBuy, + openWalletConnect, + connectWallet, + closeWalletSheet, + closeCheckoutSheet, + confirmOrder, + ], + ); + + return {children}; +} + +export function useModals(): ModalContextValue { + const ctx = useContext(ModalContext); + if (!ctx) throw new Error("useModals must be used within a ModalProvider"); + return ctx; +}