chore: germantax customer project
This commit is contained in:
87
apps/app/src/auth/session-provider.tsx
Normal file
87
apps/app/src/auth/session-provider.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
type ReactNode,
|
||||
} from 'react'
|
||||
import { useNavigate, useRouterState } from '@tanstack/react-router'
|
||||
import { Center, Loader } from '@pikku/mantine/core'
|
||||
import { usePikkuQuery } from '@germantax/functions-sdk/pikku/api.gen'
|
||||
|
||||
export interface Session {
|
||||
userId: string
|
||||
email: string
|
||||
displayName: string
|
||||
}
|
||||
|
||||
interface SessionContextValue {
|
||||
session: Session
|
||||
refetch: () => void
|
||||
}
|
||||
|
||||
const SessionContext = createContext<SessionContextValue | null>(null)
|
||||
|
||||
const PUBLIC_ROUTES = new Set<string>(['/login', '/logout'])
|
||||
|
||||
const isPublicRoute = (pathname: string) => PUBLIC_ROUTES.has(pathname)
|
||||
|
||||
export function SessionProvider({ children }: { children: ReactNode }) {
|
||||
const navigate = useNavigate()
|
||||
const pathname = useRouterState({ select: (s) => s.location.pathname })
|
||||
const onPublicRoute = isPublicRoute(pathname)
|
||||
|
||||
const me = usePikkuQuery('getMe', undefined as never, {
|
||||
enabled: !onPublicRoute,
|
||||
retry: false,
|
||||
staleTime: 60_000,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (onPublicRoute) return
|
||||
if (me.error) {
|
||||
navigate({
|
||||
to: '/login',
|
||||
search: { redirect: pathname } as never,
|
||||
replace: true,
|
||||
})
|
||||
}
|
||||
}, [me.error, onPublicRoute, navigate, pathname])
|
||||
|
||||
if (onPublicRoute) {
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
if (me.isLoading || me.error || !me.data) {
|
||||
return (
|
||||
<Center mih="100vh">
|
||||
<Loader size="sm" />
|
||||
</Center>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<SessionContext.Provider
|
||||
value={{ session: me.data, refetch: () => me.refetch() }}
|
||||
>
|
||||
{children}
|
||||
</SessionContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useSession(): Session {
|
||||
const ctx = useContext(SessionContext)
|
||||
if (!ctx) {
|
||||
throw new Error('useSession must be used inside <SessionProvider>')
|
||||
}
|
||||
return ctx.session
|
||||
}
|
||||
|
||||
export function useOptionalSession(): Session | null {
|
||||
const ctx = useContext(SessionContext)
|
||||
return ctx?.session ?? null
|
||||
}
|
||||
|
||||
export function useSessionRefetch(): () => void {
|
||||
const ctx = useContext(SessionContext)
|
||||
return ctx?.refetch ?? (() => {})
|
||||
}
|
||||
Reference in New Issue
Block a user