ultisuite-client/components/mobile/native-bridge-provider.tsx
R3D347HR4Y d6d18f911b
Some checks failed
E2E / Playwright e2e (push) Has been cancelled
Lots of stuff and mobile app
2026-06-17 00:13:28 +02:00

66 lines
2.0 KiB
TypeScript

"use client"
import { useEffect, useRef, type ReactNode } from "react"
import { useRouter } from "next/navigation"
import { useNativeRuntime } from "@/lib/platform"
import { listen } from "@/lib/native/bridge"
import { routeForDeepLink } from "@/lib/native/deep-links"
import {
takePendingShare,
stashShare,
shareLandingRoute,
} from "@/lib/native/share"
import { registerPushAfterLogin } from "@/lib/native/push"
import { useAuthStore } from "@/lib/api/auth-store"
/**
* Wires the native shell capabilities into the React app: deep-link routing,
* inbound share intake, and push-token registration after login. Inert on web.
*/
export function NativeBridgeProvider({ children }: { children: ReactNode }) {
const native = useNativeRuntime()
const router = useRouter()
const accessToken = useAuthStore((s) => s.accessToken)
const pushDone = useRef(false)
// Deep links -> client navigation.
useEffect(() => {
if (!native) return
let unlisten: (() => void) | null = null
void (async () => {
unlisten = await listen("ulti://deep-link", (payload) => {
const urls = Array.isArray(payload) ? payload : [payload]
for (const raw of urls) {
if (typeof raw !== "string") continue
const route = routeForDeepLink(raw)
if (route) router.push(route)
}
})
})()
return () => {
if (unlisten) unlisten()
}
}, [native, router])
// Inbound share content (cold start: drain the native queue).
useEffect(() => {
if (!native) return
void (async () => {
const payload = await takePendingShare()
if (payload) {
stashShare(payload)
router.push(shareLandingRoute())
}
})()
}, [native, router])
// Register the push device token once we have a session.
useEffect(() => {
if (!native || !accessToken || pushDone.current) return
pushDone.current = true
void registerPushAfterLogin()
}, [native, accessToken])
return <>{children}</>
}