garage-erp/shared/stores/auth-store.ts
2026-03-26 03:49:05 +03:00

91 lines
2.3 KiB
TypeScript

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 }