From 877e7d94ec8604fac0be9f59583a575e11939c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Aaron?= Date: Thu, 26 Sep 2024 22:53:23 +0200 Subject: [PATCH] fix: handle linking --- hooks/useHandleLinking.ts | 103 +++++++++++++++++++++++--------------- pages/Wildcard.tsx | 11 ++-- 2 files changed, 71 insertions(+), 43 deletions(-) diff --git a/hooks/useHandleLinking.ts b/hooks/useHandleLinking.ts index c250e08..b3aec67 100644 --- a/hooks/useHandleLinking.ts +++ b/hooks/useHandleLinking.ts @@ -1,58 +1,81 @@ -import { StackActions } from "@react-navigation/native"; import * as Linking from "expo-linking"; import { getInitialURL } from "expo-linking"; -import { router, useNavigationContainerRef } from "expo-router"; -import { useEffect } from "react"; +import { router, useRootNavigationState } from "expo-router"; +import { useEffect, useCallback, useRef } from "react"; // TESTING: ["lightning:", "bitcoin:", "alby:", "exp:"] const SUPPORTED_SCHEMES = ["lightning", "bitcoin", "alby", "exp"]; export function useHandleLinking() { - const rootNavigation = useNavigationContainerRef(); + const navigationState = useRootNavigationState(); + const pendingLinkRef = useRef(null); - useEffect(() => { - getInitialURL().then((url) => handleLink(url ?? "")); - const subscription = Linking.addEventListener( - "url", - (event: { url: string }) => handleLink(event.url), - ); - return () => subscription.remove(); - }, []); + const handleLink = useCallback( + (url: string) => { + if (!url) return; - function handleLink(url: string) { - if (!url) return; + const { hostname, path, queryParams, scheme } = Linking.parse(url); - const { hostname, path, queryParams, scheme } = Linking.parse(url); + if (!scheme) return; - if (!scheme) return; + if (SUPPORTED_SCHEMES.indexOf(scheme) > -1) { + let fullUrl = scheme === "exp" ? path : `${scheme}:${hostname}`; - if (SUPPORTED_SCHEMES.indexOf(scheme) > -1) { - let fullUrl = scheme === "exp" ? path : `${scheme}:${hostname}`; + // Add query parameters to the URL if they exist + if (queryParams && Object.keys(queryParams).length > 0) { + const queryString = new URLSearchParams( + queryParams as Record, + ).toString(); + fullUrl += `?${queryString}`; + } - // Add query parameters to the URL if they exist - if (queryParams && Object.keys(queryParams).length > 0) { - const queryString = new URLSearchParams( - queryParams as Record, - ).toString(); - fullUrl += `?${queryString}`; + if (router.canDismiss()) { + router.dismissAll(); + } + router.push({ + pathname: "/send", + params: { + url: fullUrl, + }, + }); + return; } - // Remove all items from the navigation stack - rootNavigation.dispatch(StackActions.popToTop()); - - router.push({ - pathname: "/send", - params: { - url: fullUrl, - }, + // Redirect the user to the home screen + // if no match was found + router.replace({ + pathname: "/", }); - return; - } + }, + [navigationState?.key], + ); + + useEffect(() => { + const processInitialURL = async () => { + const url = await getInitialURL(); + if (url) pendingLinkRef.current = url; + }; - // Redirect the user to the home screen - // if no match was found - router.replace({ - pathname: "/", - }); - } + processInitialURL(); + + const subscription = Linking.addEventListener( + "url", + (event: { url: string }) => { + if (navigationState?.key) { + handleLink(event.url); + } else { + pendingLinkRef.current = event.url; + } + }, + ); + + return () => subscription.remove(); + }, [handleLink]); + + useEffect(() => { + if (navigationState?.key && pendingLinkRef.current) { + handleLink(pendingLinkRef.current); + pendingLinkRef.current = null; + } + }, [navigationState?.key, handleLink]); } diff --git a/pages/Wildcard.tsx b/pages/Wildcard.tsx index ecc7d1b..6dc23d7 100644 --- a/pages/Wildcard.tsx +++ b/pages/Wildcard.tsx @@ -1,12 +1,17 @@ -import { Stack, usePathname } from "expo-router"; +import { router, Stack, useFocusEffect, usePathname } from "expo-router"; import { View } from "react-native"; import Loading from "~/components/Loading"; import { Text } from "~/components/ui/text"; -import { useHandleLinking } from "~/hooks/useHandleLinking"; export function Wildcard() { const pathname = usePathname(); - useHandleLinking(); + + // Should a user ever land on this page, redirect them to home + useFocusEffect(() => { + router.replace({ + pathname: "/" + }); + }); return (