Skip to content

Commit

Permalink
Update the referral mechanism (#886)
Browse files Browse the repository at this point in the history
Closes: #876 

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.
  • Loading branch information
kkosiorowska authored Nov 26, 2024
2 parents 01338c5 + 80b0eab commit 18b5373
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 56 deletions.
1 change: 0 additions & 1 deletion dapp/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
10 changes: 0 additions & 10 deletions dapp/src/hooks/useDetectReferral.ts

This file was deleted.

2 changes: 0 additions & 2 deletions dapp/src/hooks/useInitApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -13,7 +12,6 @@ export function useInitApp() {
// useDetectThemeMode()
useSentry()
useDetectEmbed()
useDetectReferral()
useInitializeAcreSdk()
useInitDataFromSdk()
useFetchBTCPriceUSD()
Expand Down
7 changes: 6 additions & 1 deletion dapp/src/hooks/useLocalStorage.ts
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -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)
Expand Down
48 changes: 9 additions & 39 deletions dapp/src/hooks/useReferral.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,33 @@
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<number>(
"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)
}, [setReferral])

return useMemo(
() => ({
detectReferral,
resetReferral,
referral,
}),
[detectReferral, resetReferral, referral],
[resetReferral, referral],
)
}
20 changes: 20 additions & 0 deletions dapp/src/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ 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 { env } from "#/constants"
import { routerPath } from "./path"

const mainLayoutLoader: LoaderFunction = ({ request }) => {
Expand All @@ -32,6 +34,24 @@ export const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
loader: ({ request }) => {
// TODO: display the error page/modal when the referral is invalid.
const referralCodeFromUrl = referralProgram.getReferralFromURL()

const referralCode = referralProgram.isValidReferral(referralCodeFromUrl)
? referralCodeFromUrl!
: env.REFERRAL

writeReferral(referralCode.toString())

const embedApp = referralProgram.getEmbeddedApp(request.url)
if (referralProgram.isEmbedApp(embedApp)) {
writeReferral(
referralProgram.getReferralByEmbeddedApp(embedApp).toString(),
)
}
return null
},
children: [
{
index: true,
Expand Down
20 changes: 17 additions & 3 deletions dapp/src/utils/referralProgram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,23 @@ const EMBEDDED_APP_TO_REFERRAL: Record<EmbedApp, number> = {
"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 = () =>
Expand Down

0 comments on commit 18b5373

Please sign in to comment.