Files
HarborForge.Frontend/src/hooks/useAuth.ts
zhi 54d4c4379a feat: remove nginx, add projects/milestones/notifications pages
- Dockerfile: replace nginx with serve for static files
- Fix auth endpoint: /auth/login → /auth/token
- Add ProjectsPage, ProjectDetailPage
- Add MilestonesPage, MilestoneDetailPage with progress bar
- Add NotificationsPage with unread count
- Sidebar: add milestones/notifications nav, live unread badge
- API: configurable VITE_API_BASE for host nginx proxy
- Types: add Milestone, MilestoneProgress, Notification, ProjectMember
2026-03-06 13:05:19 +00:00

54 lines
1.4 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react'
import api from '@/services/api'
import type { User } from '@/types'
interface AuthState {
user: User | null
token: string | null
loading: boolean
}
export function useAuth() {
const [state, setState] = useState<AuthState>({
user: null,
token: localStorage.getItem('token'),
loading: true,
})
const fetchUser = useCallback(async () => {
const token = localStorage.getItem('token')
if (!token) {
setState({ user: null, token: null, loading: false })
return
}
try {
const { data } = await api.get<User>('/auth/me')
setState({ user: data, token, loading: false })
} catch {
localStorage.removeItem('token')
setState({ user: null, token: null, loading: false })
}
}, [])
useEffect(() => { fetchUser() }, [fetchUser])
const login = async (username: string, password: string) => {
const form = new URLSearchParams()
form.append('username', username)
form.append('password', password)
const { data } = await api.post('/auth/token', form, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
})
localStorage.setItem('token', data.access_token)
setState((s) => ({ ...s, token: data.access_token }))
await fetchUser()
}
const logout = () => {
localStorage.removeItem('token')
setState({ user: null, token: null, loading: false })
}
return { ...state, login, logout }
}