kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/715/head
rodzic
33fc9c331c
commit
2ed2873a93
|
@ -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])
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Ładowanie…
Reference in New Issue