feat: add API client and auth store
This commit is contained in:
57
frontend/src/api.ts
Normal file
57
frontend/src/api.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
const api = axios.create({
|
||||||
|
baseURL: '/api',
|
||||||
|
withCredentials: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
api.interceptors.response.use(
|
||||||
|
(res) => res,
|
||||||
|
(err) => {
|
||||||
|
if (err.response?.status === 401 && window.location.pathname !== '/login') {
|
||||||
|
window.location.href = '/login'
|
||||||
|
}
|
||||||
|
return Promise.reject(err)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default api
|
||||||
|
|
||||||
|
// --- Auth ---
|
||||||
|
export const authApi = {
|
||||||
|
login: (username: string, password: string) =>
|
||||||
|
api.post('/auth/login', { username, password }),
|
||||||
|
logout: () => api.post('/auth/logout'),
|
||||||
|
me: () => api.get('/auth/me'),
|
||||||
|
register: (username: string, email: string, password: string) =>
|
||||||
|
api.post('/auth/register', { username, email, password }),
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Configs ---
|
||||||
|
export const configsApi = {
|
||||||
|
list: () => api.get('/configs'),
|
||||||
|
create: (data: object) => api.post('/configs', data),
|
||||||
|
get: (id: number) => api.get(`/configs/${id}`),
|
||||||
|
update: (id: number, data: object) => api.put(`/configs/${id}`, data),
|
||||||
|
delete: (id: number) => api.delete(`/configs/${id}`),
|
||||||
|
generate: (id: number, format: 'json' | 'zip' = 'json') =>
|
||||||
|
api.post(`/configs/${id}/generate?format=${format}`, null, {
|
||||||
|
responseType: format === 'zip' ? 'blob' : 'json',
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Nested resources (zones, interfaces, policies, rules, masq) ---
|
||||||
|
const nestedApi = (resource: string) => ({
|
||||||
|
list: (configId: number) => api.get(`/configs/${configId}/${resource}`),
|
||||||
|
create: (configId: number, data: object) => api.post(`/configs/${configId}/${resource}`, data),
|
||||||
|
update: (configId: number, id: number, data: object) =>
|
||||||
|
api.put(`/configs/${configId}/${resource}/${id}`, data),
|
||||||
|
delete: (configId: number, id: number) =>
|
||||||
|
api.delete(`/configs/${configId}/${resource}/${id}`),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const zonesApi = nestedApi('zones')
|
||||||
|
export const interfacesApi = nestedApi('interfaces')
|
||||||
|
export const policiesApi = nestedApi('policies')
|
||||||
|
export const rulesApi = nestedApi('rules')
|
||||||
|
export const masqApi = nestedApi('masq')
|
||||||
39
frontend/src/store/auth.ts
Normal file
39
frontend/src/store/auth.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { authApi } from '../api'
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
id: number
|
||||||
|
username: string
|
||||||
|
email: string
|
||||||
|
is_active: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple module-level state (no external lib needed)
|
||||||
|
let currentUser: User | null = null
|
||||||
|
const listeners = new Set<() => void>()
|
||||||
|
|
||||||
|
export function useAuth() {
|
||||||
|
const [user, setUser] = useState<User | null>(currentUser)
|
||||||
|
const [loading, setLoading] = useState(currentUser === null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const update = () => setUser(currentUser)
|
||||||
|
listeners.add(update)
|
||||||
|
if (currentUser === null) {
|
||||||
|
authApi.me()
|
||||||
|
.then((res) => { currentUser = res.data; listeners.forEach((l) => l()) })
|
||||||
|
.catch(() => { currentUser = null; listeners.forEach((l) => l()) })
|
||||||
|
.finally(() => setLoading(false))
|
||||||
|
}
|
||||||
|
return () => { listeners.delete(update) }
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const logout = async () => {
|
||||||
|
await authApi.logout()
|
||||||
|
currentUser = null
|
||||||
|
listeners.forEach((l) => l())
|
||||||
|
window.location.href = '/login'
|
||||||
|
}
|
||||||
|
|
||||||
|
return { user, loading, logout }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user