Files
donetick/src/hooks/useOnboardingGate.js

52 lines
1.5 KiB
JavaScript

import { useEffect } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
import { hasSeenOnboarding, isNativeApp } from '../utils/Onboarding'
import { setPendingInvite } from '../utils/PendingInvite'
// Routes a first-run user may legitimately be on without having gone through
// onboarding: the flow itself, deep-link auth callbacks, and the legal pages
// linked from it.
const ALLOWED_PATHS = [
'/onboarding',
'/get-started',
'/login/settings',
'/privacy',
'/terms',
// An invite link is a legitimate first launch: the join view explains itself
// and routes to sign-in, so onboarding must not swallow the code.
'/circle/join',
]
const isAllowed = pathname =>
ALLOWED_PATHS.includes(pathname) || pathname.startsWith('/auth/')
/**
* Sends first-launch native users to the onboarding flow. Runs on every
* navigation because an expired session hard-redirects to /login through
* `window.location`, which remounts the app.
*/
const useOnboardingGate = () => {
const navigate = useNavigate()
const { pathname, search } = useLocation()
const isRedirecting =
isNativeApp() &&
!hasSeenOnboarding() &&
!localStorage.getItem('token') &&
!isAllowed(pathname)
useEffect(() => {
if (!isRedirecting) return
if (pathname === '/circle/join') {
setPendingInvite(new URLSearchParams(search).get('code'))
}
navigate('/onboarding', { replace: true })
}, [isRedirecting, pathname, search, navigate])
return isRedirecting
}
export default useOnboardingGate