diff --git a/package.json b/package.json index 3c2e7af6a..b076c3ea2 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,9 @@ "html-webpack-plugin": "^5.5.3", "prettier": "^2.8.1", "typescript": "^5.0.2", + "uglifyjs-webpack-plugin": "^2.2.0", "webpack": "^5.88.1", + "webpack-bundle-analyzer": "^4.10.1", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.7.3" diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 000000000..8f2f228c1 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,27 @@ +import React from "react" +import { Web3OnboardProvider } from "@web3-onboard/react" +import { Provider } from "react-redux" +import web3Onboard from "shared/utils/web3Onboard" +import { PostHogProvider } from "posthog-js/react" +import { BrowserRouter as Router } from "react-router-dom" +import GlobalStyles from "ui/GlobalStyles" +import { POSTHOG_API_KEY, POSTHOG_API_OPTIONS } from "config/posthog" +import Dapp from "ui/DApp/Dapp" +import reduxStore from "./redux-state" + +export default function App() { + return ( + <> + + + + + + + + + + + + ) +} diff --git a/src/config/posthog.ts b/src/config/posthog.ts new file mode 100644 index 000000000..15961dd61 --- /dev/null +++ b/src/config/posthog.ts @@ -0,0 +1,18 @@ +import { PostHogConfig } from "posthog-js" + +export const { POSTHOG_API_KEY } = process.env + +export const POSTHOG_API_OPTIONS: Partial = { + persistence: "localStorage", + autocapture: false, + capture_pageview: false, + disable_session_recording: true, + sanitize_properties(properties) { + return { + ...properties, + // The extension has set an expectation that the lib is set to + // the analytics env. + $lib: process.env.ANALYTICS_ENV, + } + }, +} diff --git a/src/env.d.ts b/src/env.d.ts index 44ba2fe88..2d88c6f06 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -30,6 +30,9 @@ declare module "*.mp4" { export = value } +declare module "webpack-bundle-analyzer" +declare module "uglifyjs-webpack-plugin" + declare namespace NodeJS { interface ProcessEnv { NODE_ENV: "production" | "development" | "test" diff --git a/src/index.tsx b/src/index.tsx index da7313411..da0b8d8a3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,52 +1,16 @@ import React from "react" import ReactDOM from "react-dom/client" -import { Web3OnboardProvider } from "@web3-onboard/react" -import { Provider } from "react-redux" -import web3Onboard from "shared/utils/web3Onboard" -import { PostHogProvider } from "posthog-js/react" -import { BrowserRouter as Router } from "react-router-dom" -import DApp from "ui/DApps" -import reduxStore from "./redux-state" - -function DAppProviders() { - return ( - - - - - - - - - - ) -} +import App from "./App" const root = document.getElementById("root") if (root) { if (process.env.SKIP_REACT_STRICT_MODE === "true") { - ReactDOM.createRoot(root).render() + ReactDOM.createRoot(root).render() } else { ReactDOM.createRoot(root).render( - + ) } diff --git a/src/public/index.html b/src/public/index.html index a3e183d07..1b89a0be9 100644 --- a/src/public/index.html +++ b/src/public/index.html @@ -4,6 +4,14 @@ Subscape + + + +
- - - -
diff --git a/src/shared/constants/realms.ts b/src/shared/constants/realms.ts index f0c3ea31f..34142687a 100644 --- a/src/shared/constants/realms.ts +++ b/src/shared/constants/realms.ts @@ -7,6 +7,7 @@ import frax from "shared/assets/partners/frax.svg" import base from "shared/assets/partners/base.svg" import zksync from "shared/assets/partners/zksync.svg" import { RealmPosition } from "shared/types/realm" +import CHALLENGES_DATA from "assets/challenges-data.json" import { realm4, realm7, @@ -17,7 +18,6 @@ import { realm22, // realm15, } from "./realms-data" -import CHALLENGES_DATA from "../../assets/challenges-data.json" // TODO: read the correct challenge data for realms // The challenge data should be read from a JSON file. diff --git a/src/shared/context/index.ts b/src/shared/context/index.ts new file mode 100644 index 000000000..1e9f887e2 --- /dev/null +++ b/src/shared/context/index.ts @@ -0,0 +1,2 @@ +export * from "./island" +export * from "./reflect" diff --git a/src/shared/context/island.ts b/src/shared/context/island.ts new file mode 100644 index 000000000..db3ed5a1f --- /dev/null +++ b/src/shared/context/island.ts @@ -0,0 +1,11 @@ +/* eslint-disable import/prefer-default-export */ +import { createContext, MutableRefObject } from "react" +import { IslandContextType } from "shared/types" + +export const IslandContext = createContext>( + { + current: { + onRealmClick: () => {}, + }, + } +) diff --git a/src/shared/context/reflect.ts b/src/shared/context/reflect.ts new file mode 100644 index 000000000..2d8a9cf56 --- /dev/null +++ b/src/shared/context/reflect.ts @@ -0,0 +1,5 @@ +/* eslint-disable import/prefer-default-export */ +import { createContext } from "react" +import { ReflectInstance } from "shared/utils" + +export const ReflectContext = createContext(null) diff --git a/src/shared/hooks/assistant.ts b/src/shared/hooks/assistant.ts index 5ca3d1416..ee886e901 100644 --- a/src/shared/hooks/assistant.ts +++ b/src/shared/hooks/assistant.ts @@ -1,14 +1,8 @@ import { useEffect } from "react" import { LOCAL_STORAGE_ASSISTANT } from "shared/constants" import { selectStakingRealmId, useDappSelector } from "redux-state" -import { useLocalStorageChange } from "./helpers" - -type AssistantType = "welcome" | "challenges" | "default" | "first-realm" - -type Assistant = { - type: AssistantType - visible: boolean -} +import { Assistant, AssistantType } from "shared/types" +import { useLocalStorageChange } from "./storage" // eslint-disable-next-line import/prefer-default-export export function useAssistant(): { diff --git a/src/shared/hooks/challenge.ts b/src/shared/hooks/challenge.ts index 81e84413a..1529ad6df 100644 --- a/src/shared/hooks/challenge.ts +++ b/src/shared/hooks/challenge.ts @@ -2,7 +2,7 @@ import { useCallback } from "react" import { LOCAL_STORAGE_DISPLAYED_CHALLENGES } from "shared/constants" import { getRealmIdFromChallengeInLocalStorage } from "shared/utils" -import { useLocalStorageChange } from "./helpers" +import { useLocalStorageChange } from "./storage" export function useDisplayedChallenges(): { isChallengeDisplayed: (id: string) => string | false diff --git a/src/shared/hooks/helpers.ts b/src/shared/hooks/helpers.ts index 9b065f53c..b2fb65ea4 100644 --- a/src/shared/hooks/helpers.ts +++ b/src/shared/hooks/helpers.ts @@ -1,20 +1,8 @@ /* eslint-disable no-console */ -import { - MutableRefObject, - useEffect, - useLayoutEffect, - useMemo, - useRef, - useState, -} from "react" -import { debounce } from "lodash" +import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react" +import debounce from "lodash/debounce" import { useSpring } from "@react-spring/web" -import { getWindowDimensions } from "shared/utils" -import { MOBILE_BREAKPOINT, TABLET_BREAKPOINT } from "shared/constants" -import { usePostHog } from "posthog-js/react" -import { useLocation } from "react-router-dom" - -type VoidFn = () => unknown +import { VoidFn } from "shared/types/utils" export const useDebounce = (initial: T, wait = 300): [T, (v: T) => void] => { const [state, setState] = useState(initial) @@ -27,35 +15,6 @@ export const useDebounce = (initial: T, wait = 300): [T, (v: T) => void] => { return [state, debounceCallback] } -export function useLocalStorage( - key: string, - initialValue: string -): [string, React.Dispatch>] { - const [value, setValue] = useState( - () => localStorage.getItem(key) || initialValue - ) - - useEffect(() => { - localStorage.setItem(key, value) - }, [key, value]) - - return [value, setValue] -} - -/** - * Returns a ref that holds updated values & references - */ -export function useValueRef(value: T) { - const val = typeof value === "function" ? value() : value - const ref = useRef infer P ? P : T>(val) - - useLayoutEffect(() => { - ref.current = val - }) - - return ref -} - /** * Runs a callback on mount, as a layout effect */ @@ -84,17 +43,6 @@ export function usePrevious(value: T) { return ref.current } -/** - * Subscribes an event listener to the window resize event - */ -export function useOnResize(callback: T): void { - useBeforeFirstPaint(() => { - window.addEventListener("resize", callback) - - return () => window.removeEventListener("resize", callback) - }) -} - // Source: https://usehooks-ts.com/react-hook/use-interval export function useInterval(callback: () => void, delay: number | null) { const savedCallback = useRef(callback) @@ -179,118 +127,3 @@ export function useAssets(assets: string[]) { return assetsLoaded } - -// Source: https://sabesh.hashnode.dev/update-components-based-on-localstorage-change-in-react-hooks -export function useLocalStorageChange(key: string): { - value: T | null - updateStorage: (newValue: Partial) => void -} { - const getInitialValue = () => { - try { - return localStorage.getItem(key) - ? JSON.parse(localStorage.getItem(key)!) - : null - } catch (err) { - console.error(err) - return null - } - } - - const [value, setValue] = useState(getInitialValue()) - - useEffect(() => { - const handleStorageChange = (e: StorageEvent) => { - if (e.key !== key) return - try { - setValue(e.newValue ? JSON.parse(e.newValue) : null) - } catch (err) { - // eslint-disable-next-line no-console - console.error(err) - } - } - - window.addEventListener("storage", handleStorageChange) - return () => window.removeEventListener("storage", handleStorageChange) - }, [key]) - - const updateStorage = (newValue: Partial) => { - try { - window.localStorage.setItem(key, JSON.stringify(newValue)) - - const event = new StorageEvent("storage", { - key, - newValue: JSON.stringify(newValue), - }) - - window.dispatchEvent(event) - } catch (err) { - // eslint-disable-next-line no-console - console.error(err) - } - } - - return { value, updateStorage } -} - -export function useTabletScreen() { - const [width, setWidth] = useState(window.innerWidth) - - useOnResize(() => { - const windowSize = getWindowDimensions() - setWidth(windowSize.width) - }) - - return width < TABLET_BREAKPOINT -} - -export function useMobileScreen() { - const [width, setWidth] = useState(window.innerWidth) - - useOnResize(() => { - const windowSize = getWindowDimensions() - setWidth(windowSize.width) - }) - - return width < MOBILE_BREAKPOINT -} - -export function useUnLoad() { - const posthog = usePostHog() - - useEffect(() => { - const onUnload = () => { - posthog?.capture("$pageleave") - } - window.addEventListener("beforeunload", onUnload) - return () => { - window.removeEventListener("beforeunload", onUnload) - } - }, [posthog]) -} - -export function useTrackEvents() { - const location = useLocation() - const posthog = usePostHog() - const isMobile = useMobileScreen() - - useEffect(() => { - posthog?.capture("$pageview", { - url: location.pathname, - data: { isMobile }, - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) -} - -export function useMultiRef(): [ - MutableRefObject<(T | null)[]>, - (element: T | null, index: number) => void -] { - const multiRef = useRef<(T | null)[]>([]) - - const addMultiRef = (element: T | null, index: number) => { - multiRef.current[index] = element - } - - return [multiRef, addMultiRef] -} diff --git a/src/shared/hooks/index.ts b/src/shared/hooks/index.ts index b97c8b4fa..578524114 100644 --- a/src/shared/hooks/index.ts +++ b/src/shared/hooks/index.ts @@ -8,3 +8,7 @@ export * from "./wallets" export * from "./population" export * from "./realm" export * from "./challenge" +export * from "./posthog" +export * from "./ref" +export * from "./screen" +export * from "./storage" diff --git a/src/shared/hooks/island.ts b/src/shared/hooks/island.ts index 20c9ec48b..f3968b835 100644 --- a/src/shared/hooks/island.ts +++ b/src/shared/hooks/island.ts @@ -30,23 +30,8 @@ import { Path } from "konva/lib/shapes/Path" import { Group } from "konva/lib/Group" import { KonvaEventObject } from "konva/lib/Node" import { useArbitrumProvider } from "./wallets" -import { useInterval, useLocalStorageChange } from "./helpers" - -export const IslandContext = React.createContext< - MutableRefObject ->({ - current: { - onRealmClick: () => {}, - }, -}) - -export type IslandContextType = { - onRealmClick: (id: string) => void -} - -export function useIslandContext() { - return useContext(IslandContext) -} +import { useInterval } from "./helpers" +import { useLocalStorageChange } from "./storage" // Used to fetch all necessary data for the game to load export function useGameLoadDataFetch() { diff --git a/src/shared/hooks/posthog.ts b/src/shared/hooks/posthog.ts new file mode 100644 index 000000000..81fe25f5c --- /dev/null +++ b/src/shared/hooks/posthog.ts @@ -0,0 +1,32 @@ +import { usePostHog } from "posthog-js/react" +import { useLocation } from "react-router-dom" +import { useEffect } from "react" +import { useMobileScreen } from "./screen" + +export function useUnLoad() { + const posthog = usePostHog() + + useEffect(() => { + const onUnload = () => { + posthog?.capture("$pageleave") + } + window.addEventListener("beforeunload", onUnload) + return () => { + window.removeEventListener("beforeunload", onUnload) + } + }, [posthog]) +} + +export function useTrackEvents() { + const location = useLocation() + const posthog = usePostHog() + const isMobile = useMobileScreen() + + useEffect(() => { + posthog?.capture("$pageview", { + url: location.pathname, + data: { isMobile }, + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) +} diff --git a/src/shared/hooks/realm.ts b/src/shared/hooks/realm.ts index 4080e7c66..86eda7c5c 100644 --- a/src/shared/hooks/realm.ts +++ b/src/shared/hooks/realm.ts @@ -12,8 +12,9 @@ import { LOCAL_STORAGE_VISITED_REALM, REALM_PANEL_ANIMATION_TIME, } from "shared/constants" -import { useLocalStorageChange, useTabletScreen } from "./helpers" import { useAssistant } from "./assistant" +import { useTabletScreen } from "./screen" +import { useLocalStorageChange } from "./storage" export function useRealmPanelTransition(position: "left" | "right") { const realmPanelVisible = useDappSelector(selectRealmPanelVisible) diff --git a/src/shared/hooks/ref.ts b/src/shared/hooks/ref.ts new file mode 100644 index 000000000..0fb41edfc --- /dev/null +++ b/src/shared/hooks/ref.ts @@ -0,0 +1,28 @@ +import { MutableRefObject, useLayoutEffect, useRef } from "react" + +export function useMultiRef(): [ + MutableRefObject<(T | null)[]>, + (element: T | null, index: number) => void +] { + const multiRef = useRef<(T | null)[]>([]) + + const addMultiRef = (element: T | null, index: number) => { + multiRef.current[index] = element + } + + return [multiRef, addMultiRef] +} + +/** + * Returns a ref that holds updated values & references + */ +export function useValueRef(value: T) { + const val = typeof value === "function" ? value() : value + const ref = useRef infer P ? P : T>(val) + + useLayoutEffect(() => { + ref.current = val + }) + + return ref +} diff --git a/src/shared/hooks/reflect.ts b/src/shared/hooks/reflect.ts index aab9c7e34..c0f0724c6 100644 --- a/src/shared/hooks/reflect.ts +++ b/src/shared/hooks/reflect.ts @@ -1,4 +1,4 @@ -import { createContext, useContext, useEffect, useMemo, useState } from "react" +import { useContext, useEffect, useMemo, useState } from "react" import { selectDisplayedRealmId, selectRealmNameById, @@ -7,16 +7,12 @@ import { useDappSelector, } from "redux-state" import { usePresence, useSubscribe } from "@rocicorp/reflect/react" -import { - ReflectInstance, - ReflectMutators, - getClientState, - mutators, -} from "shared/utils" +import { ReflectMutators, getClientState, mutators } from "shared/utils" import { getRealmMapData } from "shared/constants" import { RootState } from "redux-state/reducers" import { Reflect } from "@rocicorp/reflect/client" import { nanoid } from "@reduxjs/toolkit" +import { ReflectContext } from "shared/context" import { useWalletOnboarding } from "./wallets" export const reflectSingleton = @@ -32,8 +28,6 @@ export const reflectSingleton = const DEFAULT_BG_COLOR = "#2C2C2C" const DEFAULT_TEXT_COLOR = "#FFF" -export const ReflectContext = createContext(null) - export function useInitializeReflect() { const reflect = useContext(ReflectContext) const [initialized, setInitialized] = useState(false) diff --git a/src/shared/hooks/screen.ts b/src/shared/hooks/screen.ts new file mode 100644 index 000000000..a5900175f --- /dev/null +++ b/src/shared/hooks/screen.ts @@ -0,0 +1,38 @@ +import { getWindowDimensions } from "shared/utils" +import { MOBILE_BREAKPOINT, TABLET_BREAKPOINT } from "shared/constants" +import { useState } from "react" +import { VoidFn } from "shared/types/utils" +import { useBeforeFirstPaint } from "./helpers" + +/** + * Subscribes an event listener to the window resize event + */ +export function useOnResize(callback: T): void { + useBeforeFirstPaint(() => { + window.addEventListener("resize", callback) + + return () => window.removeEventListener("resize", callback) + }) +} + +export function useTabletScreen() { + const [width, setWidth] = useState(window.innerWidth) + + useOnResize(() => { + const windowSize = getWindowDimensions() + setWidth(windowSize.width) + }) + + return width < TABLET_BREAKPOINT +} + +export function useMobileScreen() { + const [width, setWidth] = useState(window.innerWidth) + + useOnResize(() => { + const windowSize = getWindowDimensions() + setWidth(windowSize.width) + }) + + return width < MOBILE_BREAKPOINT +} diff --git a/src/shared/hooks/storage.ts b/src/shared/hooks/storage.ts new file mode 100644 index 000000000..a50e0953f --- /dev/null +++ b/src/shared/hooks/storage.ts @@ -0,0 +1,68 @@ +import { useEffect, useState } from "react" + +export function useLocalStorage( + key: string, + initialValue: string +): [string, React.Dispatch>] { + const [value, setValue] = useState( + () => localStorage.getItem(key) || initialValue + ) + + useEffect(() => { + localStorage.setItem(key, value) + }, [key, value]) + + return [value, setValue] +} + +// Source: https://sabesh.hashnode.dev/update-components-based-on-localstorage-change-in-react-hooks +export function useLocalStorageChange(key: string): { + value: T | null + updateStorage: (newValue: Partial) => void +} { + const getInitialValue = () => { + try { + return localStorage.getItem(key) + ? JSON.parse(localStorage.getItem(key)!) + : null + } catch (err) { + console.error(err) + return null + } + } + + const [value, setValue] = useState(getInitialValue()) + + useEffect(() => { + const handleStorageChange = (e: StorageEvent) => { + if (e.key !== key) return + try { + setValue(e.newValue ? JSON.parse(e.newValue) : null) + } catch (err) { + // eslint-disable-next-line no-console + console.error(err) + } + } + + window.addEventListener("storage", handleStorageChange) + return () => window.removeEventListener("storage", handleStorageChange) + }, [key]) + + const updateStorage = (newValue: Partial) => { + try { + window.localStorage.setItem(key, JSON.stringify(newValue)) + + const event = new StorageEvent("storage", { + key, + newValue: JSON.stringify(newValue), + }) + + window.dispatchEvent(event) + } catch (err) { + // eslint-disable-next-line no-console + console.error(err) + } + } + + return { value, updateStorage } +} diff --git a/src/shared/hooks/wallets.ts b/src/shared/hooks/wallets.ts index ff409fb0c..175e92cda 100644 --- a/src/shared/hooks/wallets.ts +++ b/src/shared/hooks/wallets.ts @@ -25,7 +25,8 @@ import { Network } from "@ethersproject/networks" import { Logger, defineReadOnly } from "ethers/lib/utils" import { usePostHog } from "posthog-js/react" import { useAssistant } from "./assistant" -import { useInterval, useLocalStorageChange } from "./helpers" +import { useInterval } from "./helpers" +import { useLocalStorageChange } from "./storage" class StaticJsonBatchRpcProvider extends ethers.providers.JsonRpcBatchProvider { override async detectNetwork(): Promise { diff --git a/src/shared/types/assistant.ts b/src/shared/types/assistant.ts new file mode 100644 index 000000000..a6e10b1e8 --- /dev/null +++ b/src/shared/types/assistant.ts @@ -0,0 +1,6 @@ +export type AssistantType = "welcome" | "challenges" | "default" | "first-realm" + +export type Assistant = { + type: AssistantType + visible: boolean +} diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index 624a4a23f..6e9eb3b66 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -6,3 +6,5 @@ export * from "./island" export * from "./wallet" export * from "./xp" export * from "./challenge" +export * from "./assistant" +export * from "./utils" diff --git a/src/shared/types/island.ts b/src/shared/types/island.ts index 6a9676e18..ac66d9e46 100644 --- a/src/shared/types/island.ts +++ b/src/shared/types/island.ts @@ -85,3 +85,7 @@ export type RealmMapData = { isNew?: boolean cursorText: string } + +export type IslandContextType = { + onRealmClick: (id: string) => void +} diff --git a/src/shared/types/utils.ts b/src/shared/types/utils.ts new file mode 100644 index 000000000..1e37c1a2d --- /dev/null +++ b/src/shared/types/utils.ts @@ -0,0 +1 @@ +export type VoidFn = () => unknown diff --git a/src/shared/utils/xp.ts b/src/shared/utils/xp.ts index 707e817dc..e259f99e4 100644 --- a/src/shared/utils/xp.ts +++ b/src/shared/utils/xp.ts @@ -5,10 +5,8 @@ import { XpMerkleTreeGlossary, } from "shared/types/xp" import { isSameAddress, normalizeAddress } from "shared/utils/address" -import XP_DATA from "../../assets/xp-data.json" -// eslint-disable-next-line prefer-destructuring -const XP_HOSTING_BASE_URL = process.env.XP_HOSTING_BASE_URL +const { XP_HOSTING_BASE_URL } = process.env type XpDataType = { [realmId: string]: { @@ -45,7 +43,8 @@ export async function getRealmLeaderboardData( throw new Error("Missing realm id") } - const xpData = (XP_DATA as XpDataType)[realmId] + const XP_DATA: XpDataType = (await import("assets/xp-data.json")).default + const xpData = XP_DATA[realmId] if (!xpData) { throw new Error("Missing data in xp-data.json") @@ -82,7 +81,8 @@ export async function getXpDataForRealmId( const targetAddress = BigInt(normalizedAddress) let claimsData: (null | XpMerkleTree)[] = [] - const xpData = (XP_DATA as XpDataType)[realmId] + const XP_DATA: XpDataType = (await import("assets/xp-data.json")).default + const xpData = XP_DATA[realmId] try { const { rootFolder, claimsFolder, xpGlossary } = xpData diff --git a/src/ui/Claim/ClaimCheck.tsx b/src/ui/Claim/ClaimCheck.tsx index debbe95b7..08e5890ac 100644 --- a/src/ui/Claim/ClaimCheck.tsx +++ b/src/ui/Claim/ClaimCheck.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react" import classNames from "classnames" import { Redirect } from "react-router-dom" -import { useDebounce } from "shared/hooks/helpers" +import { useDebounce } from "shared/hooks" import Button from "shared/components/Interface/Button" import Modal from "shared/components/Dialogs/Modal" import Spinner from "shared/components/Loaders/Spinner" diff --git a/src/ui/Claim/subpages/ClaimingTransactions.tsx b/src/ui/Claim/subpages/ClaimingTransactions.tsx index f1fcb0155..68f7a7065 100644 --- a/src/ui/Claim/subpages/ClaimingTransactions.tsx +++ b/src/ui/Claim/subpages/ClaimingTransactions.tsx @@ -9,7 +9,7 @@ import { } from "redux-state" import TransactionsModal from "shared/components/Transactions/TransactionsModal" import { ROUTES } from "shared/constants" -import { useTransactionSuccessCallback } from "shared/hooks/transactions" +import { useTransactionSuccessCallback } from "shared/hooks" const CLAIM_TX_ID = "claim" diff --git a/src/ui/DApp/DAppDesktop.tsx b/src/ui/DApp/DAppDesktop.tsx new file mode 100644 index 000000000..dd26cae29 --- /dev/null +++ b/src/ui/DApp/DAppDesktop.tsx @@ -0,0 +1,34 @@ +import React from "react" + +import { + reflectSingleton, + useBalanceFetch, + useCorrectChain, + useGameDataFetch, + useGameLoadDataFetch, + useInitializeReflect, + usePopulationFetch, + useReflect, + useWallet, + useWalletChange, +} from "shared/hooks" +import { ReflectContext } from "shared/context" +import IslandView from "../Island/View/IslandView" + +export default function DAppDesktop() { + useInitializeReflect() + useReflect() + useWallet() + useGameLoadDataFetch() + useBalanceFetch() + usePopulationFetch() + useGameDataFetch() + useWalletChange() + useCorrectChain() + + return ( + + + + ) +} diff --git a/src/ui/MobileScreen/index.tsx b/src/ui/DApp/DAppMobile.tsx similarity index 97% rename from src/ui/MobileScreen/index.tsx rename to src/ui/DApp/DAppMobile.tsx index 135b2d9b0..4b3871c69 100644 --- a/src/ui/MobileScreen/index.tsx +++ b/src/ui/DApp/DAppMobile.tsx @@ -4,7 +4,7 @@ import mobileCircle from "shared/assets/mobile/mobile-circle.png" import mobileScreen from "shared/assets/mobile/mobile-screen.png" import MobileNav from "ui/Nav/MobileNav" -export default function MobileScreen() { +export default function DAppMobile() { return ( <>
diff --git a/src/ui/DApp/Dapp.tsx b/src/ui/DApp/Dapp.tsx new file mode 100644 index 000000000..e5bec50fd --- /dev/null +++ b/src/ui/DApp/Dapp.tsx @@ -0,0 +1,34 @@ +import React from "react" + +import { + useConnect, + useMobileScreen, + useTrackEvents, + useUnLoad, + useWalletOnboarding, +} from "shared/hooks" +import Onboarding from "ui/Onboarding" +import PrivacyPolicy from "shared/components/Misc/PrivacyPolicy" +import DAppMobile from "./DAppMobile" +import DAppDesktop from "./DAppDesktop" + +export default function Dapp() { + const { isConnected } = useConnect() + const { walletOnboarded } = useWalletOnboarding() + const isMobileScreen = useMobileScreen() + const isOnboarding = + process.env.IS_PORTAL_CLOSED === "true" || !walletOnboarded || !isConnected + useTrackEvents() + useUnLoad() + + if (isMobileScreen) { + return + } + + return ( + <> + {isOnboarding ? : } + + + ) +} diff --git a/src/ui/DApps/DesktopDApp.tsx b/src/ui/DApps/DesktopDApp.tsx deleted file mode 100644 index 407b8eaf9..000000000 --- a/src/ui/DApps/DesktopDApp.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react" - -import { - ReflectContext, - reflectSingleton, - useBalanceFetch, - useConnect, - useCorrectChain, - useGameDataFetch, - useGameLoadDataFetch, - useInitializeReflect, - usePopulationFetch, - useReflect, - useWallet, - useWalletChange, - useWalletOnboarding, -} from "shared/hooks" -import Onboarding from "ui/Onboarding" -import PrivacyPolicy from "../../shared/components/Misc/PrivacyPolicy" -import IslandView from "./IslandView" - -function DesktopDAppContent() { - useInitializeReflect() - useReflect() - - const { isConnected } = useConnect() - const { walletOnboarded } = useWalletOnboarding() - - useWallet() - useGameLoadDataFetch() - useBalanceFetch() - usePopulationFetch() - useGameDataFetch() - useWalletChange() - useCorrectChain() - - return ( - <> - {(!walletOnboarded || !isConnected) && } - {process.env.IS_PORTAL_CLOSED !== "true" && - walletOnboarded && - isConnected && } - - - ) -} - -export default function DesktopDApp() { - return ( - - - - ) -} diff --git a/src/ui/DApps/MobileDApp.tsx b/src/ui/DApps/MobileDApp.tsx deleted file mode 100644 index 97ef45bd4..000000000 --- a/src/ui/DApps/MobileDApp.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from "react" -import MobileScreen from "ui/MobileScreen" - -export default function MobileDApp() { - return -} diff --git a/src/ui/DApps/index.tsx b/src/ui/DApps/index.tsx deleted file mode 100644 index 2419db155..000000000 --- a/src/ui/DApps/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react" -import { useMobileScreen, useTrackEvents, useUnLoad } from "shared/hooks" -import GlobalStyles from "ui/GlobalStyles" -import MobileDApp from "./MobileDApp" -import DesktopDApp from "./DesktopDApp" - -export default function DApp() { - const isMobileScreen = useMobileScreen() - useTrackEvents() - useUnLoad() - - return ( - <> - - {isMobileScreen ? : } - - ) -} diff --git a/src/ui/Island/Background/InteractiveIsland.tsx b/src/ui/Island/Background/InteractiveIsland.tsx index 148ae6439..add4e03e6 100644 --- a/src/ui/Island/Background/InteractiveIsland.tsx +++ b/src/ui/Island/Background/InteractiveIsland.tsx @@ -15,10 +15,10 @@ import { } from "redux-state/selectors/island" import { ISLAND_BOX, getRealmPosition } from "shared/constants" import { - useValueRef, useBeforeFirstPaint, useOnResize, useTabletScreen, + useValueRef, } from "shared/hooks" import { getWindowDimensions, diff --git a/src/ui/Island/Details/NetOverlay.tsx b/src/ui/Island/Details/NetOverlay.tsx index c7bb1b037..820a4892e 100644 --- a/src/ui/Island/Details/NetOverlay.tsx +++ b/src/ui/Island/Details/NetOverlay.tsx @@ -2,7 +2,7 @@ import React, { memo } from "react" import { Group } from "react-konva" import netGif from "shared/assets/island-overlay-net.gif" import { FIGMA_FACTOR } from "shared/constants" -import Gif from "../../../shared/components/Media/Gif" +import Gif from "shared/components/Media/Gif" function NetOverlay() { return ( diff --git a/src/ui/Island/Leaderboard/index.tsx b/src/ui/Island/Leaderboard/index.tsx index e4ca048f2..0406a81fe 100644 --- a/src/ui/Island/Leaderboard/index.tsx +++ b/src/ui/Island/Leaderboard/index.tsx @@ -6,8 +6,8 @@ import { selectLeaderboardById, useDappSelector, } from "redux-state" +import RealmDetailsPlaceholder from "shared/components/Media/Placeholder" import LeaderboardItem from "./LeaderboardItem" -import RealmDetailsPlaceholder from "../../../shared/components/Media/Placeholder" const leaderboardDateAvailable = "Dec 14" diff --git a/src/ui/Island/Modals/CongratulationsModal.tsx b/src/ui/Island/Modals/CongratulationsModal.tsx index 85f8c75d6..0ce647409 100644 --- a/src/ui/Island/Modals/CongratulationsModal.tsx +++ b/src/ui/Island/Modals/CongratulationsModal.tsx @@ -1,6 +1,6 @@ import React, { ReactElement, ReactNode } from "react" -import Modal from "../../../shared/components/Dialogs/Modal" -import Button from "../../../shared/components/Interface/Button" +import Modal from "shared/components/Dialogs/Modal" +import Button from "shared/components/Interface/Button" type CongratulationsModalProps = { children: string | ReactNode diff --git a/src/ui/Island/Modals/OnboardingModal.tsx b/src/ui/Island/Modals/OnboardingModal.tsx index b2780ab54..293280e37 100644 --- a/src/ui/Island/Modals/OnboardingModal.tsx +++ b/src/ui/Island/Modals/OnboardingModal.tsx @@ -1,6 +1,6 @@ import React, { ReactNode } from "react" -import Modal from "../../../shared/components/Dialogs/Modal" -import Button from "../../../shared/components/Interface/Button" +import Modal from "shared/components/Dialogs/Modal" +import Button from "shared/components/Interface/Button" type OnboardingModalProps = { children: ReactNode diff --git a/src/ui/Island/RealmPanel/RealmPanelCloseButton.tsx b/src/ui/Island/RealmPanel/RealmPanelCloseButton.tsx index 1b1c3da3a..aa3927f7f 100644 --- a/src/ui/Island/RealmPanel/RealmPanelCloseButton.tsx +++ b/src/ui/Island/RealmPanel/RealmPanelCloseButton.tsx @@ -2,8 +2,8 @@ import React from "react" import closeIcon from "shared/assets/icons/s/close-black.svg" import { animated } from "@react-spring/web" import { useRealmCloseButtonTransition } from "shared/hooks" -import Button from "../../../shared/components/Interface/Button" import Portal from "shared/components/Interface/Portal" +import Button from "shared/components/Interface/Button" export default function RealmPanelCloseButton({ onClose, diff --git a/src/ui/Island/Realms/Realm.tsx b/src/ui/Island/Realms/Realm.tsx index 924cc727c..b9c175fa2 100644 --- a/src/ui/Island/Realms/Realm.tsx +++ b/src/ui/Island/Realms/Realm.tsx @@ -1,7 +1,13 @@ /* eslint-disable react/no-array-index-key */ // Need to pass spring props to spring abstracted components /* eslint-disable react/jsx-props-no-spreading */ -import React, { useCallback, useMemo, useRef, useState } from "react" +import React, { + useCallback, + useContext, + useMemo, + useRef, + useState, +} from "react" import type Konva from "konva" import { Group } from "react-konva" import { animated, easings, useSpring } from "@react-spring/konva" @@ -13,10 +19,9 @@ import { } from "shared/constants" import { useDisplayedRealms, - useMultiRef, - useIslandContext, useIslandRealmsPaths, usePopulationBubble, + useMultiRef, } from "shared/hooks" import { BUBBLE_CONFIG } from "shared/components/Realm/Bubble" import { @@ -24,6 +29,7 @@ import { selectRealmPanelVisible, useDappSelector, } from "redux-state" +import { IslandContext } from "shared/context" import NewRealmLabel from "../Details/NewRealmLabel" import NewChallengeLabel from "../Details/NewChallengeLabel" @@ -71,7 +77,7 @@ export default function Realm({ const [isFocused, setFocus] = useState(false) const [, setIsSelected] = useState(false) - const islandContext = useIslandContext() + const islandContext = useContext(IslandContext) const groupRef = useRef(null) const textRef = useRef(null) const partnerLogoRef = useRef(null) diff --git a/src/ui/DApps/IslandView.tsx b/src/ui/Island/View/IslandView.tsx similarity index 100% rename from src/ui/DApps/IslandView.tsx rename to src/ui/Island/View/IslandView.tsx diff --git a/src/ui/Island/index.tsx b/src/ui/Island/index.tsx index c683baa65..342d5578e 100644 --- a/src/ui/Island/index.tsx +++ b/src/ui/Island/index.tsx @@ -2,7 +2,6 @@ import React, { memo, useEffect } from "react" import backgroundImg from "public/dapp_island_bg.webp" import { useValueRef, - IslandContext, useAssets, usePanelRealmClose, useOnRealmClick, @@ -15,6 +14,7 @@ import { import FullPageLoader from "shared/components/Loaders/FullPageLoader" import { usePostHog } from "posthog-js/react" import RealmPanel from "ui/Island/RealmPanel" +import { IslandContext } from "shared/context" import InteractiveIsland from "./Background/InteractiveIsland" import IslandPresence from "./Reflect/IslandPresence" diff --git a/src/ui/Onboarding/OnboardingContent.tsx b/src/ui/Onboarding/OnboardingContent.tsx new file mode 100644 index 000000000..3e4e0b72a --- /dev/null +++ b/src/ui/Onboarding/OnboardingContent.tsx @@ -0,0 +1,40 @@ +import React from "react" +import Version from "shared/components/Misc/Version" +import portalBackground from "shared/assets/portal-background.mp4" +import OnboardingModals from "./OnboardingModals" + +export default function OnboardingContent() { + return ( + <> +
+ +
+ + + ) +} diff --git a/src/ui/Footer/OnboardingFooter.tsx b/src/ui/Onboarding/OnboardingFooter.tsx similarity index 53% rename from src/ui/Footer/OnboardingFooter.tsx rename to src/ui/Onboarding/OnboardingFooter.tsx index 086260b35..89eb4661a 100644 --- a/src/ui/Footer/OnboardingFooter.tsx +++ b/src/ui/Onboarding/OnboardingFooter.tsx @@ -1,7 +1,7 @@ import React from "react" -import FooterWrapper from "./FooterWrapper" -import FooterLinks from "./FooterLinks" -import PopulationCount from "./PopulationCount" +import FooterWrapper from "../Footer/FooterWrapper" +import FooterLinks from "../Footer/FooterLinks" +import PopulationCount from "../Footer/PopulationCount" export default function OnboardingFooter() { return ( diff --git a/src/ui/Onboarding/OnboardingModals.tsx b/src/ui/Onboarding/OnboardingModals.tsx new file mode 100644 index 000000000..3b6a77a9a --- /dev/null +++ b/src/ui/Onboarding/OnboardingModals.tsx @@ -0,0 +1,56 @@ +import React from "react" +import { + useDappSelector, + selectHasLoadedBalances, + selectHasRelevantTokens, +} from "redux-state" +import { useConnect } from "shared/hooks" +import BetaEndModal from "ui/Island/Modals/BetaEndModal" +import ConnectWallet from "./modals/ConnectWallet" +import EnterPortal from "./modals/EnterPortal" +import JoinWaitlist from "./modals/JoinWaitlist" +import OnboardingModalLoader from "./modals/Loader" + +export default function OnboardingDetails() { + const { isConnected } = useConnect() + const hasBalances = useDappSelector(selectHasLoadedBalances) + const hasRelevantTokens = useDappSelector(selectHasRelevantTokens) + + if (process.env.IS_PORTAL_CLOSED === "true") { + return ( + + Thanks for participating in our Beta, we hope you had fun +
and see you in Season 1. +
+ ) + } + + if (process.env.IS_COMING_SOON === "true") { + return ( + + Portal opens +
+ soon +
+ ) + } + + if (!isConnected) { + return + } + + if (!hasBalances) { + return + } + + if (hasRelevantTokens) { + return + } + + return ( + + The Portal +
is Open +
+ ) +} diff --git a/src/ui/Onboarding/index.tsx b/src/ui/Onboarding/index.tsx index 4df3cdc02..cba533f76 100644 --- a/src/ui/Onboarding/index.tsx +++ b/src/ui/Onboarding/index.tsx @@ -1,95 +1,16 @@ -import React from "react" -import { useAssets, useConnect } from "shared/hooks" -import { - useDappSelector, - selectHasRelevantTokens, - selectHasLoadedBalances, -} from "redux-state" -import FullPageLoader from "shared/components/Loaders/FullPageLoader" +import React, { memo } from "react" import Nav from "ui/Nav" -import portalBackground from "shared/assets/portal-background.mp4" -import Version from "shared/components/Misc/Version" -import OnboardingFooter from "ui/Footer/OnboardingFooter" -import BetaEndModal from "ui/Island/Modals/BetaEndModal" -import ConnectWallet from "./ConnectWallet" -import JoinWaitlist from "./JoinWaitlist" -import EnterPortal from "./EnterPortal" -import OnboardingModalLoader from "./Loader" - -function OnboardingModal() { - const { isConnected } = useConnect() - const hasBalances = useDappSelector(selectHasLoadedBalances) - const hasRelevantTokens = useDappSelector(selectHasRelevantTokens) - - if (process.env.IS_COMING_SOON === "true") { - return ( - - Portal opens -
- soon -
- ) - } - - if (!isConnected) { - return - } - - if (!hasBalances) { - return - } - - if (hasRelevantTokens) { - return - } - - return ( - - The Portal -
is Open -
- ) -} - -export default function Onboarding() { - const assetsLoaded = useAssets([portalBackground]) +import OnboardingFooter from "ui/Onboarding/OnboardingFooter" +import OnboardingContent from "./OnboardingContent" +function Onboarding() { return ( <> - -
- {process.env.IS_PORTAL_CLOSED === "true" ? ( - - Thanks for participating in our Beta, we hope you had fun -
and see you in Season 1. -
- ) : ( - - )} - -
- -
-
+