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

Wyświetl plik

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

Wyświetl plik

@ -11,8 +11,9 @@ import {
TooltipProvider,
TooltipTrigger
} from '@/components/ui/tooltip'
import { cn } from '@/lib/utils'
export function DarkModeToggle() {
export function DarkModeToggle({ className }: { className?: string }) {
const { setTheme, resolvedTheme } = useTheme()
return (
@ -22,7 +23,7 @@ export function DarkModeToggle() {
<Button
variant='outline'
size='icon'
className='cursor-pointer'
className={cn('cursor-pointer', className)}
onClick={() =>
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 { useAgentic } from '@/components/agentic-provider'
import { DarkModeToggle } from '@/components/dark-mode-toggle'
import styles from './styles.module.css'
export function Header() {
const ctx = useAgentic()
return (
<header className={styles.header}>
<div className={styles.headerContent}>
@ -13,18 +16,32 @@ export function Header() {
AGENTIC
</ActiveLink>
<div className='md:hidden'>
<div className='flex justify-end items-center h-full gap-4'>
<ActiveLink href='/about' className='link'>
About
</ActiveLink>
</div>
<div className={cs(styles.rhs)}>
<div className='hidden md:block'>
<ActiveLink href='/about' className='link mr-2'>
About
</ActiveLink>
</div>
{ctx?.api.isAuthenticated ? (
<>
<ActiveLink href='/app' className='link'>
Dashboard
</ActiveLink>
<ActiveLink href='/logout' className='link'>
Logout
</ActiveLink>
</>
) : (
<>
<ActiveLink href='/login' className='link'>
Login
</ActiveLink>
<ActiveLink href='/signup' className='link'>
Sign up
</ActiveLink>
</>
)}
<DarkModeToggle />
</div>

Wyświetl plik

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