authContext.jsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // ---------------------------------------------------------------------------
  2. // Folder: components/auth
  3. // File: authContext.js
  4. // Relative Path: components/auth/authContext.js
  5. // ---------------------------------------------------------------------------
  6. "use client";
  7. import React from "react";
  8. /**
  9. * Auth Context (RHL-020)
  10. *
  11. * Purpose:
  12. * - Provide a tiny, app-wide session state for the UI:
  13. * - status: "unknown" | "loading" | "authenticated" | "unauthenticated" | "error"
  14. * - user: { userId, role, branchId } | null
  15. * - error: string | null
  16. *
  17. * Why this file exists:
  18. * - Keep auth state accessible without prop-drilling.
  19. * - Keep the context/hook independent from Next.js routing.
  20. * - Avoid importing next/navigation in components that only need auth state
  21. * (helps SSR/unit tests and keeps dependencies clean).
  22. */
  23. /**
  24. * @typedef {"unknown"|"loading"|"authenticated"|"unauthenticated"|"error"} AuthStatus
  25. */
  26. /**
  27. * @typedef {Object} AuthUser
  28. * @property {string} userId
  29. * @property {string} role
  30. * @property {string|null} branchId
  31. */
  32. /**
  33. * @typedef {Object} AuthState
  34. * @property {AuthStatus} status
  35. * @property {AuthUser|null} user
  36. * @property {string|null} error
  37. */
  38. /** @type {AuthState} */
  39. export const DEFAULT_AUTH_STATE = Object.freeze({
  40. status: "unknown",
  41. user: null,
  42. error: null,
  43. });
  44. /**
  45. * The actual React context.
  46. * We provide a safe default so components can render even without a provider
  47. * (useful for SSR tests that render AppShell in isolation).
  48. */
  49. const AuthContext = React.createContext(DEFAULT_AUTH_STATE);
  50. /**
  51. * Consume the auth context.
  52. *
  53. * @returns {AuthState}
  54. */
  55. export function useAuth() {
  56. return React.useContext(AuthContext);
  57. }
  58. /**
  59. * Provider wrapper.
  60. *
  61. * We keep it very small and predictable:
  62. * - merge provided value with DEFAULT_AUTH_STATE to guarantee all fields exist
  63. * - avoid surprises when callers pass partial objects
  64. *
  65. * @param {{ value: Partial<AuthState>, children: React.ReactNode }} props
  66. */
  67. export function AuthProvider({ value, children }) {
  68. const merged = React.useMemo(() => {
  69. return { ...DEFAULT_AUTH_STATE, ...(value || {}) };
  70. }, [value]);
  71. return <AuthContext.Provider value={merged}>{children}</AuthContext.Provider>;
  72. }