Move auth and timezone hooks into dedicated hook files

This commit is contained in:
2026-04-18 20:35:28 +02:00
parent d9550ae4aa
commit fba7675eb8
8 changed files with 40 additions and 49 deletions

View File

@@ -176,6 +176,8 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
**Goal:** Move `useAuth()` into its own file `frontend/src/hooks/useAuth.ts` and `useTimezone()` into `frontend/src/hooks/useTimezone.ts`. Each provider file should only define and export the context object and the provider component. The hooks should import the context from the provider file and re-export it from the `hooks/` directory.
**Status:** Completed.
**Possible traps and issues:**
- Every file that currently imports `useAuth` from `providers/AuthProvider` must update its import path. Run a global search for `from "../providers/AuthProvider"` and `from "../../providers/AuthProvider"` to find all consumers before moving.
- The context object (`AuthContext`, `TimezoneContext`) must remain exported from the provider file so the hook can import it. Do not move the context — only the hook function.

View File

@@ -7,7 +7,7 @@
*/
import { Navigate, useLocation } from "react-router-dom";
import { useAuth } from "../providers/AuthProvider";
import { useAuth } from "../hooks/useAuth";
interface RequireAuthProps {
/** The protected page content to render when authenticated. */

View File

@@ -0,0 +1,15 @@
import { useContext } from "react";
import { AuthContext, type AuthContextValue } from "../providers/AuthProvider";
/**
* Access authentication state and actions from a mounted AuthProvider.
*
* @throws {Error} When called outside of `<AuthProvider>`.
*/
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (ctx === null) {
throw new Error("useAuth must be used within <AuthProvider>.");
}
return ctx;
}

View File

@@ -0,0 +1,15 @@
import { useContext } from "react";
import { TimezoneContext } from "../providers/TimezoneProvider";
/**
* Return the configured IANA timezone from the mounted TimezoneProvider.
*
* @throws {Error} When called outside of `<TimezoneProvider>`.
*/
export function useTimezone(): string {
const context = useContext(TimezoneContext);
if (context === undefined) {
throw new Error("useTimezone must be used within <TimezoneProvider>.");
}
return context.timezone;
}

View File

@@ -30,7 +30,7 @@ import {
NavigationRegular,
} from "@fluentui/react-icons";
import { NavLink, Outlet, useNavigate } from "react-router-dom";
import { useAuth } from "../providers/AuthProvider";
import { useAuth } from "../hooks/useAuth";
import { useServerStatus } from "../hooks/useServerStatus";
import { useBlocklistStatus } from "../hooks/useBlocklist";

View File

@@ -21,7 +21,7 @@ import {
import { useNavigate, useSearchParams } from "react-router-dom";
import type { ChangeEvent, FormEvent } from "react";
import { ApiError } from "../api/client";
import { useAuth } from "../providers/AuthProvider";
import { useAuth } from "../hooks/useAuth";
// ---------------------------------------------------------------------------
// Styles

View File

@@ -10,7 +10,6 @@
import {
createContext,
useCallback,
useContext,
useMemo,
useState,
} from "react";
@@ -25,7 +24,7 @@ interface AuthState {
expiresAt: string | null;
}
interface AuthContextValue {
export interface AuthContextValue {
/** `true` when a valid session token is held in state. */
isAuthenticated: boolean;
/**
@@ -41,7 +40,7 @@ interface AuthContextValue {
// Context
// ---------------------------------------------------------------------------
const AuthContext = createContext<AuthContextValue | null>(null);
export const AuthContext = createContext<AuthContextValue | null>(null);
const SESSION_KEY = "bangui_token";
const SESSION_EXPIRES_KEY = "bangui_expires_at";
@@ -97,22 +96,3 @@ export function AuthProvider({
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
// ---------------------------------------------------------------------------
// Hook
// ---------------------------------------------------------------------------
/**
* Access authentication state and actions.
*
* Must be called inside a component rendered within `<AuthProvider>`.
*
* @throws {Error} When called outside of `<AuthProvider>`.
*/
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (ctx === null) {
throw new Error("useAuth must be used within <AuthProvider>.");
}
return ctx;
}

View File

@@ -9,19 +9,19 @@
* always receive a safe fallback.
*/
import { createContext, useContext, useMemo } from "react";
import { createContext, useMemo } from "react";
import { useTimezoneData } from "../hooks/useTimezoneData";
// ---------------------------------------------------------------------------
// Context definition
// ---------------------------------------------------------------------------
interface TimezoneContextValue {
export interface TimezoneContextValue {
/** IANA timezone string, e.g. ``"Europe/Berlin"`` or ``"UTC"``. */
timezone: string;
}
const TimezoneContext = createContext<TimezoneContextValue>({ timezone: "UTC" });
export const TimezoneContext = createContext<TimezoneContextValue | undefined>(undefined);
// ---------------------------------------------------------------------------
// Provider
@@ -53,24 +53,3 @@ export function TimezoneProvider({
<TimezoneContext.Provider value={value}>{children}</TimezoneContext.Provider>
);
}
// ---------------------------------------------------------------------------
// Hook
// ---------------------------------------------------------------------------
/**
* Return the IANA timezone string configured during setup.
*
* Must be used inside a {@link TimezoneProvider}.
*
* @returns The configured timezone, e.g. ``"Europe/Berlin"``.
*
* @example
* ```tsx
* const { timezone } = useTimezone();
* const label = formatDate(item.created_at, timezone);
* ```
*/
export function useTimezone(): string {
return useContext(TimezoneContext).timezone;
}