From 82e8809be5cdf02da1c95903e7e9c5fd5b181025 Mon Sep 17 00:00:00 2001 From: Rafal Czajkowski Date: Fri, 8 Nov 2024 16:54:22 +0100 Subject: [PATCH] Display welcome modal in correct order Use react router loaders to display modals in correct order. We want to display welcome modal after access code modal in standalone app and before wallet connection in embedded apps. --- dapp/src/DApp.tsx | 14 ++++-- dapp/src/components/Layout.tsx | 11 +---- dapp/src/hooks/useAccessCode.ts | 9 +++- dapp/src/hooks/useInitApp.ts | 2 - dapp/src/pages/AccessPage/index.tsx | 15 +++++++ dapp/src/pages/AccessPage/loader.ts | 40 ++++++++++++++++++ dapp/src/pages/DashboardPage/loader.ts | 17 ++++++++ dapp/src/pages/WelcomePage/index.tsx | 23 ++++++++++ dapp/src/pages/WelcomePage/loader.ts | 10 +++++ dapp/src/router/index.tsx | 47 ++++++++++++++++----- dapp/src/router/path.ts | 2 +- dapp/src/router/utils.ts | 9 ++++ dapp/src/utils/index.ts | 1 + dapp/src/utils/shouldDisplayWelcomeModal.ts | 7 +++ 14 files changed, 178 insertions(+), 29 deletions(-) create mode 100644 dapp/src/pages/AccessPage/index.tsx create mode 100644 dapp/src/pages/AccessPage/loader.ts create mode 100644 dapp/src/pages/DashboardPage/loader.ts create mode 100644 dapp/src/pages/WelcomePage/index.tsx create mode 100644 dapp/src/pages/WelcomePage/loader.ts create mode 100644 dapp/src/router/utils.ts create mode 100644 dapp/src/utils/shouldDisplayWelcomeModal.ts diff --git a/dapp/src/DApp.tsx b/dapp/src/DApp.tsx index aa67ce180..31255b53d 100644 --- a/dapp/src/DApp.tsx +++ b/dapp/src/DApp.tsx @@ -20,13 +20,21 @@ import queryClient from "./queryClient" import { delay, logPromiseFailure } from "./utils" import { AcreLogo } from "./assets/icons" +function SplashPage() { + return ( +
+ +
+ ) +} + function DApp() { useInitApp() return ( <> - + } /> ) @@ -48,9 +56,7 @@ function DAppProviders() { if (!config) return ( -
- -
+
) diff --git a/dapp/src/components/Layout.tsx b/dapp/src/components/Layout.tsx index 88e533cbe..64d4a99be 100644 --- a/dapp/src/components/Layout.tsx +++ b/dapp/src/components/Layout.tsx @@ -1,8 +1,7 @@ -import React, { useEffect } from "react" +import React from "react" import { Outlet } from "react-router-dom" import { Flex, VStack } from "@chakra-ui/react" -import { useIsEmbed, useMobileMode, useModal } from "#/hooks" -import { MODAL_TYPES } from "#/types" +import { useIsEmbed, useMobileMode } from "#/hooks" import DocsDrawer from "./DocsDrawer" import Header from "./Header" import ModalRoot from "./ModalRoot" @@ -19,12 +18,6 @@ const PAGE_MAX_WIDTH = { function Layout() { const isMobileMode = useMobileMode() const { embeddedApp } = useIsEmbed() - const { openModal } = useModal() - - // TODO: Temporary solution to test Welcome modal. - useEffect(() => { - openModal(MODAL_TYPES.WELCOME, { navigateToOnClose: "/" }) - }, [openModal]) if (isMobileMode) return diff --git a/dapp/src/hooks/useAccessCode.ts b/dapp/src/hooks/useAccessCode.ts index 691f16cb7..428ae9fa6 100644 --- a/dapp/src/hooks/useAccessCode.ts +++ b/dapp/src/hooks/useAccessCode.ts @@ -1,9 +1,14 @@ import { useCallback } from "react" -import useLocalStorage from "./useLocalStorage" +import useLocalStorage, { getLocalStorageItem } from "./useLocalStorage" +const LOCAL_STORAGE_KEY = "acre.accessCode" + +export function getAccessCodeFromLocalStorage() { + return getLocalStorageItem(LOCAL_STORAGE_KEY) +} export default function useAccessCode() { const [encodedCode, setAccessCode] = useLocalStorage( - "acre.accessCode", + LOCAL_STORAGE_KEY, undefined, ) diff --git a/dapp/src/hooks/useInitApp.ts b/dapp/src/hooks/useInitApp.ts index 3f462d8db..e87e8955a 100644 --- a/dapp/src/hooks/useInitApp.ts +++ b/dapp/src/hooks/useInitApp.ts @@ -7,7 +7,6 @@ import useDetectEmbed from "./useDetectEmbed" import useDetectReferral from "./useDetectReferral" import { useDisconnectWallet } from "./useDisconnectWallet" import { useFetchBTCPriceUSD } from "./useFetchBTCPriceUSD" -import useGatingDApp from "./useGatingDApp" export function useInitApp() { // TODO: Let's uncomment when dark mode is ready @@ -15,7 +14,6 @@ export function useInitApp() { useSentry() useDetectEmbed() useDetectReferral() - useGatingDApp() useInitializeAcreSdk() useInitDataFromSdk() useFetchBTCPriceUSD() diff --git a/dapp/src/pages/AccessPage/index.tsx b/dapp/src/pages/AccessPage/index.tsx new file mode 100644 index 000000000..41acf7020 --- /dev/null +++ b/dapp/src/pages/AccessPage/index.tsx @@ -0,0 +1,15 @@ +import React from "react" +import { useAppNavigate } from "#/hooks" +import GateModal from "#/components/GateModal" + +export default function AccessPage() { + const navigate = useAppNavigate() + + return ( + { + navigate("/dashboard") + }} + /> + ) +} diff --git a/dapp/src/pages/AccessPage/loader.ts b/dapp/src/pages/AccessPage/loader.ts new file mode 100644 index 000000000..956c07065 --- /dev/null +++ b/dapp/src/pages/AccessPage/loader.ts @@ -0,0 +1,40 @@ +import { getAccessCodeFromLocalStorage } from "#/hooks/useAccessCode" +import redirectWithSearchParams from "#/router/utils" +import { acreApi, shouldDisplayWelcomeModal } from "#/utils" +import { LoaderFunction } from "react-router-dom" + +export const redirectToAccessPageLoader = async ( + url: string, + redirectToOnSuccess: null | string = null, + redirectToOnFail: null | string = null, +) => { + try { + const isValid = await acreApi.verifyAccessCode( + getAccessCodeFromLocalStorage() ?? "", + ) + + if (isValid) { + const shouldRedirectToWelcomeModal = shouldDisplayWelcomeModal() + + return shouldRedirectToWelcomeModal + ? redirectWithSearchParams(url, "/welcome") + : !redirectToOnSuccess || + redirectWithSearchParams(url, redirectToOnSuccess) + } + + return redirectToOnFail + ? redirectWithSearchParams(url, redirectToOnFail) + : null + } catch (error) { + console.error("Failed to verify access code") + + return redirectToOnFail + ? redirectWithSearchParams(url, redirectToOnFail) + : null + } +} + +const accessPageLoader: LoaderFunction = async ({ request }) => + redirectToAccessPageLoader(request.url, "/dashboard") + +export default accessPageLoader diff --git a/dapp/src/pages/DashboardPage/loader.ts b/dapp/src/pages/DashboardPage/loader.ts new file mode 100644 index 000000000..f04804b98 --- /dev/null +++ b/dapp/src/pages/DashboardPage/loader.ts @@ -0,0 +1,17 @@ +import { referralProgram, shouldDisplayWelcomeModal } from "#/utils" +import { LoaderFunction } from "react-router-dom" +import redirectWithSearchParams from "#/router/utils" +import { redirectToAccessPageLoader } from "../AccessPage/loader" + +const dashboardPageLoader: LoaderFunction = async (args) => { + const { request } = args + + if (referralProgram.isEmbedApp(referralProgram.getEmbeddedApp(request.url))) + return shouldDisplayWelcomeModal() + ? redirectWithSearchParams(request.url, "/welcome") + : null + + return redirectToAccessPageLoader(request.url, null, "/access") +} + +export default dashboardPageLoader diff --git a/dapp/src/pages/WelcomePage/index.tsx b/dapp/src/pages/WelcomePage/index.tsx new file mode 100644 index 000000000..f1ef5dd23 --- /dev/null +++ b/dapp/src/pages/WelcomePage/index.tsx @@ -0,0 +1,23 @@ +import React from "react" +import WelcomeModal from "#/components/WelcomeModal" +import { useAppNavigate, useLocalStorage } from "#/hooks" +import { LOCAL_STORAGE_KEY } from "#/utils/shouldDisplayWelcomeModal" + +function WelcomePage() { + const navigate = useAppNavigate() + const [_, setShouldDisplayWelcomeModal] = useLocalStorage( + LOCAL_STORAGE_KEY, + true, + ) + + return ( + { + setShouldDisplayWelcomeModal(false) + navigate("/dashboard") + }} + /> + ) +} + +export default WelcomePage diff --git a/dapp/src/pages/WelcomePage/loader.ts b/dapp/src/pages/WelcomePage/loader.ts new file mode 100644 index 000000000..180104869 --- /dev/null +++ b/dapp/src/pages/WelcomePage/loader.ts @@ -0,0 +1,10 @@ +import redirectWithSearchParams from "#/router/utils" +import { shouldDisplayWelcomeModal } from "#/utils" +import { LoaderFunction } from "react-router-dom" + +const welcomePageLoader: LoaderFunction = ({ request }) => + shouldDisplayWelcomeModal() + ? null + : redirectWithSearchParams(request.url, "/dashboard") + +export default welcomePageLoader diff --git a/dapp/src/router/index.tsx b/dapp/src/router/index.tsx index 5943ddd6f..869551f0c 100644 --- a/dapp/src/router/index.tsx +++ b/dapp/src/router/index.tsx @@ -1,28 +1,53 @@ import React from "react" import Layout from "#/components/Layout" import DashboardPage from "#/pages/DashboardPage" -import { createBrowserRouter, redirectDocument } from "react-router-dom" -import { referralProgram } from "#/utils" +import { createBrowserRouter, LoaderFunction } from "react-router-dom" +import { shouldDisplayWelcomeModal, referralProgram } from "#/utils" +import dashboardPageLoader from "#/pages/DashboardPage/loader" +import AccessPage from "#/pages/AccessPage" +import WelcomePage from "#/pages/WelcomePage" +import welcomePageLoader from "#/pages/WelcomePage/loader" +import accessPageLoader from "#/pages/AccessPage/loader" +import redirectWithSearchParams from "./utils" import { routerPath } from "./path" +const mainLayoutLoader: LoaderFunction = ({ request }) => { + const embedApp = referralProgram.getEmbeddedApp(request.url) + + if (referralProgram.isEmbedApp(embedApp)) { + const shouldRedirectToWelcomeModal = !shouldDisplayWelcomeModal() + + return shouldRedirectToWelcomeModal + ? redirectWithSearchParams(request.url, "/welcome") + : redirectWithSearchParams(request.url, "/dashboard") + } + + return redirectWithSearchParams(request.url, "/access") +} + export const router = createBrowserRouter([ { path: "/", element: , - loader: ({ request }) => { - const embedApp = referralProgram.getEmbeddedApp(request.url) - - if (!!embedApp && !referralProgram.isEmbedApp(embedApp)) { - return redirectDocument("/") - } - - return null - }, children: [ { index: true, + loader: mainLayoutLoader, + }, + { path: routerPath.home, element: , + loader: dashboardPageLoader, + }, + { + path: "/access", + element: , + loader: accessPageLoader, + }, + { + path: "/welcome", + element: , + loader: welcomePageLoader, }, ], }, diff --git a/dapp/src/router/path.ts b/dapp/src/router/path.ts index ce48928bf..ea138162a 100644 --- a/dapp/src/router/path.ts +++ b/dapp/src/router/path.ts @@ -5,7 +5,7 @@ export const SEARCH_PARAMS_NAMES = { } export const routerPath = { - home: "/", + home: "/dashboard", } as const export type Pathname = (typeof routerPath)[keyof typeof routerPath] diff --git a/dapp/src/router/utils.ts b/dapp/src/router/utils.ts new file mode 100644 index 000000000..76fad6c5f --- /dev/null +++ b/dapp/src/router/utils.ts @@ -0,0 +1,9 @@ +import { redirect } from "react-router-dom" + +const redirectWithSearchParams = (url: string, to: string) => { + const requestUrl = new URL(url) + + return redirect(`${to}${requestUrl.search}`) +} + +export default redirectWithSearchParams diff --git a/dapp/src/utils/index.ts b/dapp/src/utils/index.ts index 2deea8e9e..c79d332b7 100644 --- a/dapp/src/utils/index.ts +++ b/dapp/src/utils/index.ts @@ -17,3 +17,4 @@ export { default as referralProgram } from "./referralProgram" export { default as acreApi } from "./acreApi" export { default as router } from "./router" export { default as delay } from "./delay" +export { default as shouldDisplayWelcomeModal } from "./shouldDisplayWelcomeModal" diff --git a/dapp/src/utils/shouldDisplayWelcomeModal.ts b/dapp/src/utils/shouldDisplayWelcomeModal.ts new file mode 100644 index 000000000..19cc1da8d --- /dev/null +++ b/dapp/src/utils/shouldDisplayWelcomeModal.ts @@ -0,0 +1,7 @@ +import { getLocalStorageItem } from "#/hooks/useLocalStorage" + +export const LOCAL_STORAGE_KEY = "acre.shouldDisplayWelcomeModal" + +export default function shouldDisplayWelcomeModal() { + return getLocalStorageItem(LOCAL_STORAGE_KEY) !== "false" +}