From 7b2b48c0e33bfc404e7ff1b27c784ef41475d8d6 Mon Sep 17 00:00:00 2001 From: Rafal Czajkowski Date: Wed, 20 Nov 2024 21:31:55 +0100 Subject: [PATCH 1/5] Update the referral mechanism Detect the referral code in the main router loader instead of the hooks. Using a router loader is simpler and we avoid race between two hooks `useDetectEmbed` and `useDetectReferral`. We noticed a bug with hooks implementation - `acre.referral` set to `0` for Ledger Live after clearing local storage. The `acre.referral` key should always be set to `2083` value for users using Acre in Ledger Live. --- dapp/src/hooks/index.ts | 1 - dapp/src/hooks/useDetectReferral.ts | 10 ------ dapp/src/hooks/useInitApp.ts | 2 -- dapp/src/hooks/useLocalStorage.ts | 7 ++++- dapp/src/hooks/useReferral.ts | 48 ++++++----------------------- dapp/src/router/index.tsx | 19 ++++++++++++ 6 files changed, 34 insertions(+), 53 deletions(-) delete mode 100644 dapp/src/hooks/useDetectReferral.ts diff --git a/dapp/src/hooks/index.ts b/dapp/src/hooks/index.ts index 9584fa5eb..28bc42703 100644 --- a/dapp/src/hooks/index.ts +++ b/dapp/src/hooks/index.ts @@ -27,7 +27,6 @@ export { default as useMobileMode } from "./useMobileMode" export { default as useBitcoinRecoveryAddress } from "./useBitcoinRecoveryAddress" export { default as useIsFetchedWalletData } from "./useIsFetchedWalletData" export { default as useLocalStorage } from "./useLocalStorage" -export { default as useDetectReferral } from "./useDetectReferral" export { default as useReferral } from "./useReferral" export { default as useMats } from "./useMats" export { default as useIsEmbed } from "./useIsEmbed" diff --git a/dapp/src/hooks/useDetectReferral.ts b/dapp/src/hooks/useDetectReferral.ts deleted file mode 100644 index e32a457b6..000000000 --- a/dapp/src/hooks/useDetectReferral.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { useEffect } from "react" -import useReferral from "./useReferral" - -export default function useDetectReferral() { - const { detectReferral } = useReferral() - - useEffect(() => { - detectReferral() - }, [detectReferral]) -} diff --git a/dapp/src/hooks/useInitApp.ts b/dapp/src/hooks/useInitApp.ts index e87e8955a..caf792595 100644 --- a/dapp/src/hooks/useInitApp.ts +++ b/dapp/src/hooks/useInitApp.ts @@ -4,7 +4,6 @@ import { useAccountsChangedOKX } from "./orangeKit/useAccountsChangedOKX" import { useInitDataFromSdk, useInitializeAcreSdk } from "./sdk" import { useSentry } from "./sentry" import useDetectEmbed from "./useDetectEmbed" -import useDetectReferral from "./useDetectReferral" import { useDisconnectWallet } from "./useDisconnectWallet" import { useFetchBTCPriceUSD } from "./useFetchBTCPriceUSD" @@ -13,7 +12,6 @@ export function useInitApp() { // useDetectThemeMode() useSentry() useDetectEmbed() - useDetectReferral() useInitializeAcreSdk() useInitDataFromSdk() useFetchBTCPriceUSD() diff --git a/dapp/src/hooks/useLocalStorage.ts b/dapp/src/hooks/useLocalStorage.ts index d3d03e990..73272cecd 100644 --- a/dapp/src/hooks/useLocalStorage.ts +++ b/dapp/src/hooks/useLocalStorage.ts @@ -1,4 +1,7 @@ -import { useLocalStorage as useRehooksLocalStorage } from "@rehooks/local-storage" +import { + useLocalStorage as useRehooksLocalStorage, + writeStorage, +} from "@rehooks/local-storage" export const parseLocalStorageValue = (value: string | null | undefined) => { if ( @@ -12,6 +15,8 @@ export const parseLocalStorageValue = (value: string | null | undefined) => { return value } +export { writeStorage } + export const getLocalStorageItem = (key: string): string | undefined => { const value = localStorage.getItem(key) return parseLocalStorageValue(value) diff --git a/dapp/src/hooks/useReferral.ts b/dapp/src/hooks/useReferral.ts index d919850e9..4e6f7566c 100644 --- a/dapp/src/hooks/useReferral.ts +++ b/dapp/src/hooks/useReferral.ts @@ -1,52 +1,23 @@ import { env } from "#/constants" -import { referralProgram } from "#/utils" - import { useCallback, useMemo } from "react" -import { MODAL_TYPES } from "#/types" -import useIsEmbed from "./useIsEmbed" -import useLocalStorage from "./useLocalStorage" -import { useModal } from "./useModal" +import useLocalStorage, { writeStorage } from "./useLocalStorage" type UseReferralReturn = { referral: number | null - detectReferral: () => void resetReferral: () => void } +const LOCAL_STORAGE_KEY = "acre.referral" + +export const writeReferral = (value: string) => { + writeStorage(LOCAL_STORAGE_KEY, value) +} + export default function useReferral(): UseReferralReturn { const [referral, setReferral] = useLocalStorage( - "acre.referral", + LOCAL_STORAGE_KEY, env.REFERRAL, ) - const { openModal } = useModal() - const { isEmbed, embeddedApp } = useIsEmbed() - - const detectReferral = useCallback(() => { - const param = referralProgram.getReferralFromURL() - - if (isEmbed && embeddedApp) { - setReferral(referralProgram.getReferralByEmbeddedApp(embeddedApp)) - return - } - - if (param === null) { - setReferral(env.REFERRAL) - return - } - - const convertedReferral = Number(param) - - if (referralProgram.isValidReferral(convertedReferral)) { - setReferral(convertedReferral) - } else { - console.error("Incorrect referral") - setReferral(null) - openModal(MODAL_TYPES.UNEXPECTED_ERROR, { - withCloseButton: false, - closeOnEsc: false, - }) - } - }, [isEmbed, embeddedApp, openModal, setReferral]) const resetReferral = useCallback(() => { setReferral(env.REFERRAL) @@ -54,10 +25,9 @@ export default function useReferral(): UseReferralReturn { return useMemo( () => ({ - detectReferral, resetReferral, referral, }), - [detectReferral, resetReferral, referral], + [resetReferral, referral], ) } diff --git a/dapp/src/router/index.tsx b/dapp/src/router/index.tsx index 9d6a42b0f..de54de5bc 100644 --- a/dapp/src/router/index.tsx +++ b/dapp/src/router/index.tsx @@ -12,6 +12,7 @@ import AccessPage from "#/pages/AccessPage" import WelcomePage from "#/pages/WelcomePage" import welcomePageLoader from "#/pages/WelcomePage/loader" import accessPageLoader from "#/pages/AccessPage/loader" +import { writeReferral } from "#/hooks/useReferral" import { routerPath } from "./path" const mainLayoutLoader: LoaderFunction = ({ request }) => { @@ -32,6 +33,24 @@ export const router = createBrowserRouter([ { path: "/", element: , + loader: ({ request }) => { + // TODO: display the error page/modal when the referral is invalid. + const referralCode = referralProgram.getReferralFromURL() + if ( + referralCode && + referralProgram.isValidReferral(Number(referralCode)) + ) { + writeReferral(referralCode) + } + + const embedApp = referralProgram.getEmbeddedApp(request.url) + if (referralProgram.isEmbedApp(embedApp)) { + writeReferral( + referralProgram.getReferralByEmbeddedApp(embedApp).toString(), + ) + } + return null + }, children: [ { index: true, From ac311737feabe9bdf4ef4b347b8bd40a28d9e8e2 Mon Sep 17 00:00:00 2001 From: Rafal Czajkowski Date: Thu, 21 Nov 2024 15:49:01 +0100 Subject: [PATCH 2/5] Set the default referral code If there is no `ref` query param in URL. In that case we should back to the default value. --- dapp/src/router/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dapp/src/router/index.tsx b/dapp/src/router/index.tsx index de54de5bc..f1a65ef10 100644 --- a/dapp/src/router/index.tsx +++ b/dapp/src/router/index.tsx @@ -13,6 +13,7 @@ import WelcomePage from "#/pages/WelcomePage" import welcomePageLoader from "#/pages/WelcomePage/loader" import accessPageLoader from "#/pages/AccessPage/loader" import { writeReferral } from "#/hooks/useReferral" +import { env } from "#/constants" import { routerPath } from "./path" const mainLayoutLoader: LoaderFunction = ({ request }) => { @@ -35,12 +36,12 @@ export const router = createBrowserRouter([ element: , loader: ({ request }) => { // TODO: display the error page/modal when the referral is invalid. - const referralCode = referralProgram.getReferralFromURL() + const referralCode = referralProgram.getReferralFromURL() ?? env.REFERRAL if ( referralCode && referralProgram.isValidReferral(Number(referralCode)) ) { - writeReferral(referralCode) + writeReferral(referralCode.toString()) } const embedApp = referralProgram.getEmbeddedApp(request.url) From aafe02f5533dee549adc45c78332480caefb5931 Mon Sep 17 00:00:00 2001 From: Rafal Czajkowski Date: Fri, 22 Nov 2024 15:37:05 +0100 Subject: [PATCH 3/5] Update main router loader Handle a case when someone passes invalid referral code via URL. We should set the default value in local storage instaed of using the previous one. --- dapp/src/router/index.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dapp/src/router/index.tsx b/dapp/src/router/index.tsx index f1a65ef10..1a5b3ced0 100644 --- a/dapp/src/router/index.tsx +++ b/dapp/src/router/index.tsx @@ -36,13 +36,15 @@ export const router = createBrowserRouter([ element: , loader: ({ request }) => { // TODO: display the error page/modal when the referral is invalid. - const referralCode = referralProgram.getReferralFromURL() ?? env.REFERRAL - if ( - referralCode && - referralProgram.isValidReferral(Number(referralCode)) - ) { - writeReferral(referralCode.toString()) - } + const referralCodeFromUrl = referralProgram.getReferralFromURL() + + const referralCode = referralProgram.isValidReferral( + Number(referralCodeFromUrl), + ) + ? referralCodeFromUrl! + : env.REFERRAL + + writeReferral(referralCode.toString()) const embedApp = referralProgram.getEmbeddedApp(request.url) if (referralProgram.isEmbedApp(embedApp)) { From f2d48ad920d4b0dc645513aba03a49481c9d0895 Mon Sep 17 00:00:00 2001 From: Rafal Czajkowski Date: Mon, 25 Nov 2024 11:00:32 +0100 Subject: [PATCH 4/5] Improve `isValidReferral` fn Accept only numbers in string w/o leading zeros. --- dapp/src/router/index.tsx | 4 +--- dapp/src/utils/referralProgram.ts | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/dapp/src/router/index.tsx b/dapp/src/router/index.tsx index 1a5b3ced0..351a8504e 100644 --- a/dapp/src/router/index.tsx +++ b/dapp/src/router/index.tsx @@ -38,9 +38,7 @@ export const router = createBrowserRouter([ // TODO: display the error page/modal when the referral is invalid. const referralCodeFromUrl = referralProgram.getReferralFromURL() - const referralCode = referralProgram.isValidReferral( - Number(referralCodeFromUrl), - ) + const referralCode = referralProgram.isValidReferral(referralCodeFromUrl) ? referralCodeFromUrl! : env.REFERRAL diff --git a/dapp/src/utils/referralProgram.ts b/dapp/src/utils/referralProgram.ts index 36f48b9a3..82a3bfbc5 100644 --- a/dapp/src/utils/referralProgram.ts +++ b/dapp/src/utils/referralProgram.ts @@ -9,9 +9,23 @@ const EMBEDDED_APP_TO_REFERRAL: Record = { "ledger-live": 2083, } -const isValidReferral = (value: number) => { - const isInteger = Number.isInteger(value) - return isInteger && value >= 0 && value <= MAX_UINT16 +const isValidReferral = (value: unknown) => { + let valueAsNumber: number | undefined + + if (typeof value === "string") { + // Only digits w/o leading zeros. + const isNumber = /^(?:[1-9][0-9]*|0)$/.test(value) + valueAsNumber = isNumber ? Number(value) : undefined + } else if (typeof value === "number") { + valueAsNumber = value + } + + return ( + !!valueAsNumber && + Number.isInteger(valueAsNumber) && + valueAsNumber >= 0 && + valueAsNumber <= MAX_UINT16 + ) } const getReferralFromURL = () => From 108533649e916859402762545b8a1278d8cb6d06 Mon Sep 17 00:00:00 2001 From: Karolina Kosiorowska Date: Tue, 26 Nov 2024 15:57:50 +0100 Subject: [PATCH 5/5] Copy change for dApp --- .../BuildTransactionModal.tsx | 4 ++-- .../TransactionModal/WalletInteractionModal.tsx | 17 ++++++++++++----- .../src/pages/DashboardPage/PositionDetails.tsx | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dapp/src/components/TransactionModal/ActiveUnstakingStep/BuildTransactionModal.tsx b/dapp/src/components/TransactionModal/ActiveUnstakingStep/BuildTransactionModal.tsx index c6b6f81af..84c3069b3 100644 --- a/dapp/src/components/TransactionModal/ActiveUnstakingStep/BuildTransactionModal.tsx +++ b/dapp/src/components/TransactionModal/ActiveUnstakingStep/BuildTransactionModal.tsx @@ -16,10 +16,10 @@ export default function BuildTransactionModal({ return ( <> - Building transaction data... + Preparing withdrawal transaction... - We are building your withdrawal data. + This may take a few minutes. diff --git a/dapp/src/components/TransactionModal/WalletInteractionModal.tsx b/dapp/src/components/TransactionModal/WalletInteractionModal.tsx index dbbf4c53b..8a3da5e94 100644 --- a/dapp/src/components/TransactionModal/WalletInteractionModal.tsx +++ b/dapp/src/components/TransactionModal/WalletInteractionModal.tsx @@ -10,8 +10,8 @@ import { ProgressProps, } from "@chakra-ui/react" import { AcreSignIcon } from "#/assets/icons" -import { useActionFlowType, useConnector } from "#/hooks" -import { ACTION_FLOW_TYPES } from "#/types" +import { useActionFlowType, useConnector, useIsEmbed } from "#/hooks" +import { ACTION_FLOW_TYPES, DappMode } from "#/types" import { Alert, AlertIcon } from "../shared/Alert" import { TextMd } from "../shared/Typography" @@ -22,11 +22,16 @@ const ICON_STYLES = { type WalletInteractionStep = "opening-wallet" | "awaiting-transaction" +const CONTENT_BY_DAPP_MODE: Record = { + standalone: "wallet", + "ledger-live": "Ledger Device", +} + const DATA: Record< WalletInteractionStep, { header: string - description: (action: string) => string + description: (action: string, mode: DappMode) => string progressProps?: ProgressProps } > = { @@ -37,7 +42,8 @@ const DATA: Record< }, "awaiting-transaction": { header: "Awaiting signature confirmation", - description: () => "Waiting for your wallet to confirm the transaction.", + description: (_, mode: DappMode) => + `Communicating with your ${CONTENT_BY_DAPP_MODE[mode]}...`, progressProps: { transform: "scaleX(-1)" }, }, } @@ -50,6 +56,7 @@ export default function WalletInteractionModal({ const actionType = useActionFlowType() const connector = useConnector() const { header, description, progressProps } = DATA[step] + const { embeddedApp } = useIsEmbed() return ( <> @@ -78,6 +85,7 @@ export default function WalletInteractionModal({ {description( actionType === ACTION_FLOW_TYPES.STAKE ? "deposit" : "withdraw", + embeddedApp ?? "standalone", )} {step === "awaiting-transaction" && ( @@ -85,7 +93,6 @@ export default function WalletInteractionModal({ This may take up to a minute. - Don't close this window. )} diff --git a/dapp/src/pages/DashboardPage/PositionDetails.tsx b/dapp/src/pages/DashboardPage/PositionDetails.tsx index 8346fcc8a..f5b2e30b4 100644 --- a/dapp/src/pages/DashboardPage/PositionDetails.tsx +++ b/dapp/src/pages/DashboardPage/PositionDetails.tsx @@ -56,7 +56,7 @@ export default function PositionDetails() { {/* TODO: Component should be moved to `CardHeader` */} - Your deposit + Your balance {/* TODO: Uncomment when position will be implemented */} {/* {positionPercentage && (