pull/715/head
Travis Fischer 2025-06-17 06:23:15 +07:00
rodzic 33fc9c331c
commit 2ed2873a93
5 zmienionych plików z 104 dodań i 69 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
'use client' 'use client'
import { redirect, RedirectType } from 'next/navigation' // import { redirect, RedirectType } from 'next/navigation'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useAuthenticatedAgentic } from '@/components/agentic-provider' import { useAuthenticatedAgentic } from '@/components/agentic-provider'
@ -12,7 +12,6 @@ export default function LogoutPage() {
;(async () => { ;(async () => {
if (ctx) { if (ctx) {
ctx.logout() ctx.logout()
redirect('/', RedirectType.replace)
} }
})() })()
}, [ctx]) }, [ctx])

Wyświetl plik

@ -11,7 +11,6 @@ import {
useCallback, useCallback,
useContext, useContext,
useEffect, useEffect,
useRef,
useState useState
} from 'react' } from 'react'
import { useLocalStorage } from 'react-use' import { useLocalStorage } from 'react-use'
@ -20,6 +19,7 @@ import * as config from '@/lib/config'
type AgenticContextType = { type AgenticContextType = {
api: AgenticApiClient api: AgenticApiClient
isAuthenticated: boolean
logout: () => void logout: () => void
} }
@ -29,90 +29,117 @@ export function AgenticProvider({ children }: { children: ReactNode }) {
const [authSession, setAuthSession] = useLocalStorage<AuthSession | null>( const [authSession, setAuthSession] = useLocalStorage<AuthSession | null>(
'agentic-auth-session' 'agentic-auth-session'
) )
const logout = useCallback(() => { const logout = useCallback(() => {
setAuthSession(null) setAuthSession(null)
}, [setAuthSession]) }, [setAuthSession])
const agenticContext = useRef<AgenticContextType>({ const onUpdateAuth = useCallback(
(updatedAuthSession?: AuthSession | null) => {
// console.log('onUpdateAuth', {
// authSession: structuredClone(authSession),
// updatedAuthSession: structuredClone(updatedAuthSession),
// isCurrentlyAuthenticated: agenticContext.isAuthenticated
// })
if (
!!authSession !== !!updatedAuthSession ||
authSession?.token !== updatedAuthSession?.token ||
agenticContext.isAuthenticated !== !!updatedAuthSession
) {
setAuthSession(updatedAuthSession)
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[authSession, setAuthSession]
)
const [agenticContext, setAgenticContext] = useState<AgenticContextType>({
api: new AgenticApiClient({ api: new AgenticApiClient({
apiBaseUrl: config.apiBaseUrl, apiBaseUrl: config.apiBaseUrl,
onUpdateAuth: (updatedAuthSession) => { onUpdateAuth
// console.log('onUpdateAuth', updatedAuthSession)
if (
!!authSession !== !!updatedAuthSession &&
authSession?.token !== updatedAuthSession?.token
) {
// console.log('setAuthSession', updatedAuthSession)
setAuthSession(updatedAuthSession)
} else {
// console.log('auth session not updated')
}
}
}), }),
isAuthenticated: !!authSession,
logout logout
}) })
useEffect(() => { useEffect(() => {
// console.log('updating session from localStorage', authSession?.token) // console.log('updating session from localStorage', authSession?.token)
if (agenticContext.current) { if (authSession) {
if (authSession) { // console.log('setting auth session to truthy', {
agenticContext.current.api.authSession = authSession // authSession: structuredClone(authSession),
} else { // isAuthenticated: agenticContext.isAuthenticated,
agenticContext.current.api.authSession = undefined // setAgenticContext: !agenticContext.isAuthenticated
// })
agenticContext.api.authSession = authSession
if (!agenticContext.isAuthenticated) {
setAgenticContext({
...agenticContext,
isAuthenticated: true
})
}
} else {
// console.log('setting auth session to falsy', {
// authSession: structuredClone(authSession),
// isAuthenticated: agenticContext.isAuthenticated,
// setAgenticContext: !!agenticContext.isAuthenticated
// })
agenticContext.api.authSession = undefined
if (agenticContext.isAuthenticated) {
setAgenticContext({
...agenticContext,
isAuthenticated: false
})
} }
} }
}, [agenticContext, authSession]) }, [agenticContext, authSession])
return ( return (
<AgenticContext.Provider value={agenticContext.current}> <AgenticContext.Provider value={agenticContext}>
{children} {children}
</AgenticContext.Provider> </AgenticContext.Provider>
) )
} }
export function useAgentic(): AgenticContextType { export function useAgentic(): AgenticContextType | undefined {
const ctx = useContext(AgenticContext) const ctx = useContext(AgenticContext)
const [isMounted, setIsMounted] = useState(false)
useEffect(() => {
if (!isMounted) {
setIsMounted(true)
return
}
}, [isMounted, setIsMounted])
if (!ctx) { if (!ctx) {
throw new Error('useAgentic must be used within an AgenticProvider') throw new Error('useAgentic must be used within an AgenticProvider')
} }
return ctx return isMounted ? ctx : undefined
} }
export function useUnauthenticatedAgentic(): AgenticContextType | undefined { export function useUnauthenticatedAgentic(): AgenticContextType | undefined {
const ctx = useAgentic() const ctx = useAgentic()
const [isMounted, setIsMounted] = useState(false)
useEffect(() => { if (ctx && ctx.isAuthenticated) {
if (!isMounted) { // console.log('REQUIRES UNAUTHENTICATED: redirecting to /app')
setIsMounted(true) redirect('/app', RedirectType.replace)
return }
}
if (ctx.api.isAuthenticated) { return ctx
redirect('/app', RedirectType.replace)
}
}, [isMounted, setIsMounted, ctx])
return isMounted ? ctx : undefined
} }
export function useAuthenticatedAgentic(): AgenticContextType | undefined { export function useAuthenticatedAgentic(): AgenticContextType | undefined {
const ctx = useAgentic() const ctx = useAgentic()
const [isMounted, setIsMounted] = useState(false)
useEffect(() => { if (ctx && !ctx.isAuthenticated) {
if (!isMounted) { // console.log('REQUIRES AUTHENTICATED: redirecting to /login')
setIsMounted(true) redirect('/login', RedirectType.replace)
return }
}
if (!ctx.api.isAuthenticated) { return ctx
redirect('/login', RedirectType.replace)
}
}, [isMounted, setIsMounted, ctx])
return isMounted ? ctx : undefined
} }

Wyświetl plik

@ -11,8 +11,9 @@ import {
TooltipProvider, TooltipProvider,
TooltipTrigger TooltipTrigger
} from '@/components/ui/tooltip' } from '@/components/ui/tooltip'
import { cn } from '@/lib/utils'
export function DarkModeToggle() { export function DarkModeToggle({ className }: { className?: string }) {
const { setTheme, resolvedTheme } = useTheme() const { setTheme, resolvedTheme } = useTheme()
return ( return (
@ -22,7 +23,7 @@ export function DarkModeToggle() {
<Button <Button
variant='outline' variant='outline'
size='icon' size='icon'
className='cursor-pointer' className={cn('cursor-pointer', className)}
onClick={() => onClick={() =>
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark') setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')
} }

Wyświetl plik

@ -1,11 +1,14 @@
import cs from 'clsx' 'use client'
import { ActiveLink } from '@/components/active-link' import { ActiveLink } from '@/components/active-link'
import { useAgentic } from '@/components/agentic-provider'
import { DarkModeToggle } from '@/components/dark-mode-toggle' import { DarkModeToggle } from '@/components/dark-mode-toggle'
import styles from './styles.module.css' import styles from './styles.module.css'
export function Header() { export function Header() {
const ctx = useAgentic()
return ( return (
<header className={styles.header}> <header className={styles.header}>
<div className={styles.headerContent}> <div className={styles.headerContent}>
@ -13,18 +16,32 @@ export function Header() {
AGENTIC AGENTIC
</ActiveLink> </ActiveLink>
<div className='md:hidden'> <div className='flex justify-end items-center h-full gap-4'>
<ActiveLink href='/about' className='link'> <ActiveLink href='/about' className='link'>
About About
</ActiveLink> </ActiveLink>
</div>
<div className={cs(styles.rhs)}> {ctx?.api.isAuthenticated ? (
<div className='hidden md:block'> <>
<ActiveLink href='/about' className='link mr-2'> <ActiveLink href='/app' className='link'>
About Dashboard
</ActiveLink> </ActiveLink>
</div>
<ActiveLink href='/logout' className='link'>
Logout
</ActiveLink>
</>
) : (
<>
<ActiveLink href='/login' className='link'>
Login
</ActiveLink>
<ActiveLink href='/signup' className='link'>
Sign up
</ActiveLink>
</>
)}
<DarkModeToggle /> <DarkModeToggle />
</div> </div>

Wyświetl plik

@ -38,15 +38,6 @@
min-height: 32px; min-height: 32px;
} }
.rhs {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
height: 100%;
gap: 0.5em;
}
.logo { .logo {
font-family: 'Josefin Sans'; font-family: 'Josefin Sans';
font-weight: bold; font-weight: bold;