Files
k-photos/k-photos-frontend/components/auth-provider.tsx
Gabriel Kaszewski 957737ac9b feat: frontend MVP — auth, timeline, upload, albums, admin, image viewer
Backend:
- user roles (DB + JWT + first-user-is-admin)
- volume-aware file resolver (multi-volume asset serving)
- directory scanner uses volume URI directly
- date-summary endpoint (capture date from EXIF)
- timeline ordered by capture date
- list endpoints: volumes, plugins, pipelines, library paths
- delete endpoints: volumes, library paths
- configurable upload body limit (MAX_UPLOAD_BYTES)

Frontend:
- auth: login/register, token refresh, role-based admin gate
- timeline: date-grouped grid, infinite scroll, date scrubber
- image viewer: fullscreen zoom/pan/pinch, metadata sidebar
- upload: drag-drop, sequential upload, progress tracking
- albums: create, add/remove photos, asset picker dialog
- admin: storage (import library), jobs (pagination, error details),
  plugins (list + toggle), pipelines, sidecars, duplicates
- multi-select mode with add-to-album action
- TanStack Query for all data fetching
2026-06-01 01:35:43 +02:00

82 lines
2.1 KiB
TypeScript

"use client"
import { createContext, useState, useEffect, useCallback, type ReactNode } from "react"
import api from "@/lib/api"
import { getTokens, setTokens, clearTokens } from "@/lib/auth"
import type { AuthResponse, UserResponse } from "@/lib/types"
interface AuthContextValue {
user: UserResponse | null
isAuthenticated: boolean
isAdmin: boolean
isLoading: boolean
login: (email: string, password: string) => Promise<void>
register: (username: string, email: string, password: string) => Promise<void>
logout: () => void
}
export const AuthContext = createContext<AuthContextValue | null>(null)
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<UserResponse | null>(null)
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
const { access } = getTokens()
if (!access) {
setIsLoading(false)
return
}
api
.get<UserResponse>("/auth/me")
.then((res) => setUser(res.data))
.catch(() => clearTokens())
.finally(() => setIsLoading(false))
}, [])
const login = useCallback(async (email: string, password: string) => {
const { data } = await api.post<AuthResponse>("/auth/login", {
email,
password,
})
setTokens(data.token, data.refresh_token)
setUser(data.user)
}, [])
const register = useCallback(
async (username: string, email: string, password: string) => {
const { data } = await api.post<AuthResponse>("/auth/register", {
username,
email,
password,
})
setTokens(data.token, data.refresh_token)
setUser(data.user)
},
[],
)
const logout = useCallback(() => {
api.post("/auth/logout").catch(() => {})
clearTokens()
setUser(null)
window.location.href = "/login"
}, [])
return (
<AuthContext.Provider
value={{
user,
isAuthenticated: !!user,
isAdmin: user?.role === "admin",
isLoading,
login,
register,
logout,
}}
>
{children}
</AuthContext.Provider>
)
}