initialize
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { create } from "zustand"
|
||||
|
||||
type AppStore = {
|
||||
lastLoginEmail: string
|
||||
sidebarOpen: boolean
|
||||
setLastLoginEmail: (email: string) => void
|
||||
setSidebarOpen: (open: boolean) => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
lastLoginEmail: "",
|
||||
sidebarOpen: true,
|
||||
}
|
||||
|
||||
const useAppStore = create<AppStore>()((set) => ({
|
||||
...initialState,
|
||||
setLastLoginEmail: (email) => set({ lastLoginEmail: email }),
|
||||
setSidebarOpen: (open) => set({ sidebarOpen: open }),
|
||||
reset: () => set(initialState),
|
||||
}))
|
||||
|
||||
export { useAppStore }
|
||||
@@ -0,0 +1,90 @@
|
||||
import { create } from "zustand"
|
||||
import type { AuthUser } from "@repo/api"
|
||||
import { createApi } from "@repo/api"
|
||||
import {
|
||||
setAuthCookies,
|
||||
clearAuthCookies,
|
||||
getAuthCookies,
|
||||
} from "@/modules/auth/auth.actions"
|
||||
|
||||
type AuthState = {
|
||||
token: string | undefined
|
||||
user: AuthUser | undefined
|
||||
isAuthenticated: boolean
|
||||
}
|
||||
|
||||
type AuthActions = {
|
||||
login: (token: string, user: AuthUser, expiresIn?: number) => Promise<void>
|
||||
logout: () => Promise<void>
|
||||
hydrate: () => Promise<void>
|
||||
}
|
||||
|
||||
type AuthStore = AuthState & AuthActions
|
||||
|
||||
/**
|
||||
* Synchronously read auth credentials from cookies on the client.
|
||||
* Returns undefined on the server (document is not available).
|
||||
*/
|
||||
function readCookieValue(name: string): string | undefined {
|
||||
if (typeof document === "undefined") return undefined
|
||||
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`))
|
||||
return match ? decodeURIComponent(match[1]) : undefined
|
||||
}
|
||||
|
||||
function readInitialToken(): string | undefined {
|
||||
return readCookieValue("auth_token")
|
||||
}
|
||||
|
||||
function readInitialUser(): AuthUser | undefined {
|
||||
const raw = readCookieValue("auth_user")
|
||||
if (!raw) return undefined
|
||||
try {
|
||||
return JSON.parse(raw) as AuthUser
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
const useAuthStore = create<AuthStore>()((set, get) => {
|
||||
const initialToken = readInitialToken()
|
||||
const initialUser = readInitialUser()
|
||||
return {
|
||||
token: initialToken,
|
||||
user: initialUser,
|
||||
isAuthenticated: !!(initialToken && initialUser),
|
||||
|
||||
login: async (token, user, expiresIn?) => {
|
||||
await setAuthCookies(token, user, expiresIn)
|
||||
set({ token, user, isAuthenticated: true })
|
||||
},
|
||||
|
||||
logout: async () => {
|
||||
const { token } = get()
|
||||
if (token) {
|
||||
try {
|
||||
const authedApi = createApi({
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
await authedApi.auth.logout()
|
||||
} catch {
|
||||
// proceed with local cleanup even if the API call fails
|
||||
}
|
||||
}
|
||||
await clearAuthCookies()
|
||||
set({ token: undefined, user: undefined, isAuthenticated: false })
|
||||
},
|
||||
|
||||
hydrate: async () => {
|
||||
const { token, user } = await getAuthCookies()
|
||||
if (token && user) {
|
||||
set({ token, user, isAuthenticated: true })
|
||||
} else {
|
||||
await clearAuthCookies()
|
||||
set({ token: undefined, user: undefined, isAuthenticated: false })
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export { useAuthStore }
|
||||
export type { AuthUser }
|
||||
Reference in New Issue
Block a user