1import { useAtomValue } from "@effect/atom-react";
2import { useNavigation } from "@react-navigation/native";
3import { useEffect } from "react";
4
5import { appAtomRegistry } from "../../state/atom-registry";
6import { clearConnectOnboardingRequest, connectOnboardingRequestAtom } from "./connectOnboarding";
7import { isConnectOnboardingOptedOut } from "./connectOnboardingOptOut";
8
9// Sign-in happens inside the Settings sheet; give its session-state transition
10// a beat to settle before presenting another formSheet on top.
11const PRESENT_ONBOARDING_DELAY_MS = 600;
12
13/**
14 * Consumes the onboarding request inside the navigation tree (RootStackLayout)
15 * and presents the onboarding formSheet. Lives apart from connectOnboarding.ts
16 * so non-navigation consumers (CloudAuthProvider) do not pull
17 * @react-navigation into their module graph.
18 */
19export function useConnectOnboardingNavigation(): void {
20 const navigation = useNavigation();
21 const requestedAccountId = useAtomValue(connectOnboardingRequestAtom);
22
23 useEffect(() => {
24 if (requestedAccountId === null) {
25 return;
26 }
27 let cancelled = false;
28 const timer = setTimeout(() => {
29 void (async () => {
30 // A failed preference read prefers showing the sheet.
31 const optedOut = await isConnectOnboardingOptedOut(requestedAccountId).catch(() => false);
32 // The cancelled flag covers effect re-runs, but a sign-out can clear
33 // the request atom moments before this render commits — re-check the
34 // atom so a stale request never presents the sheet.
35 if (cancelled || appAtomRegistry.get(connectOnboardingRequestAtom) !== requestedAccountId) {
36 return;
37 }
38 clearConnectOnboardingRequest();
39 if (!optedOut) {
40 navigation.navigate("ConnectOnboarding");
41 }
42 })();
43 }, PRESENT_ONBOARDING_DELAY_MS);
44 return () => {
45 cancelled = true;
46 clearTimeout(timer);
47 };
48 }, [navigation, requestedAccountId]);
49}