mirror of
https://github.com/azaion/ui.git
synced 2026-06-22 09:51:10 +00:00
8a461a2051
Single source of truth for every /api/<service>/... URL the UI talks to: src/api/endpoints.ts (25 typed builders) re-exported via the F4 barrel. Migrates 13 production callsites in admin / annotations / flights / settings / dataset / auth / api-client / FlightContext / DetectionClasses to endpoints.* . Adds the STC-ARCH-02 static gate (--mode=api-literals in scripts/check-arch-imports.mjs, wired into scripts/run-tests.sh) that fails any new hardcoded /api/<service>/ literal in src/ outside endpoints.ts and *.test.tsx? files. Tests: +36 contract assertions in src/api/endpoints.test.ts (every builder, character-identical), +6 STC-ARCH-02 architecture cases in tests/architecture_imports.test.ts (single / double / template literal fail paths, *.test.* exemption, line-comment skip, migrated codebase pass). Fast profile 167 -> 209 PASS / 13 SKIP / 0 FAIL, +42 new, 0 regressions. Static profile 31 / 31 PASS. Closes architecture baseline finding F7. Cycle 1 of Phase B closed. Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.6 KiB
TypeScript
55 lines
1.6 KiB
TypeScript
import { createContext, useContext, useState, useCallback, useEffect, type ReactNode } from 'react'
|
|
import { api, endpoints, setToken } from '../api'
|
|
import type { AuthUser } from '../types'
|
|
|
|
interface AuthState {
|
|
user: AuthUser | null
|
|
loading: boolean
|
|
login: (email: string, password: string) => Promise<void>
|
|
logout: () => Promise<void>
|
|
hasPermission: (perm: string) => boolean
|
|
}
|
|
|
|
const AuthContext = createContext<AuthState>(null!)
|
|
|
|
export function useAuth() {
|
|
return useContext(AuthContext)
|
|
}
|
|
|
|
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
const [user, setUser] = useState<AuthUser | null>(null)
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
useEffect(() => {
|
|
api.get<{ user: AuthUser; token: string }>(endpoints.admin.authRefresh())
|
|
.then(data => {
|
|
setToken(data.token)
|
|
setUser(data.user)
|
|
})
|
|
.catch(() => {})
|
|
.finally(() => setLoading(false))
|
|
}, [])
|
|
|
|
const login = useCallback(async (email: string, password: string) => {
|
|
const data = await api.post<{ token: string; user: AuthUser }>(endpoints.admin.authLogin(), { email, password })
|
|
setToken(data.token)
|
|
setUser(data.user)
|
|
}, [])
|
|
|
|
const logout = useCallback(async () => {
|
|
try { await api.post(endpoints.admin.authLogout()) } catch {}
|
|
setToken(null)
|
|
setUser(null)
|
|
}, [])
|
|
|
|
const hasPermission = useCallback((perm: string) => {
|
|
return user?.permissions.includes(perm) ?? false
|
|
}, [user])
|
|
|
|
return (
|
|
<AuthContext.Provider value={{ user, loading, login, logout, hasPermission }}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
)
|
|
}
|