authContext.jsx 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. "use client";
  2. import React from "react";
  3. /**
  4. * Auth Context (RHL-020)
  5. *
  6. * Purpose:
  7. * - Provide a tiny, app-wide session state for the UI:
  8. * - status: "unknown" | "loading" | "authenticated" | "unauthenticated" | "error"
  9. * - user: { userId, role, branchId } | null
  10. * - error: string | null
  11. * - isValidating: boolean (true while a background session re-check runs)
  12. * - retry: () => void | null (re-run the session check)
  13. */
  14. /**
  15. * @typedef {"unknown"|"loading"|"authenticated"|"unauthenticated"|"error"} AuthStatus
  16. */
  17. /**
  18. * @typedef {Object} AuthUser
  19. * @property {string} userId
  20. * @property {string} role
  21. * @property {string|null} branchId
  22. */
  23. /**
  24. * @typedef {Object} AuthState
  25. * @property {AuthStatus} status
  26. * @property {AuthUser|null} user
  27. * @property {string|null} error
  28. * @property {boolean} isValidating
  29. * @property {(() => void)|null} retry
  30. */
  31. /** @type {AuthState} */
  32. export const DEFAULT_AUTH_STATE = Object.freeze({
  33. status: "unknown",
  34. user: null,
  35. error: null,
  36. isValidating: false,
  37. retry: null,
  38. });
  39. const AuthContext = React.createContext(DEFAULT_AUTH_STATE);
  40. /**
  41. * Consume the auth context.
  42. *
  43. * @returns {AuthState}
  44. */
  45. export function useAuth() {
  46. return React.useContext(AuthContext);
  47. }
  48. /**
  49. * Provider wrapper.
  50. *
  51. * @param {{ value: Partial<AuthState>, children: React.ReactNode }} props
  52. */
  53. export function AuthProvider({ value, children }) {
  54. const merged = React.useMemo(() => {
  55. return { ...DEFAULT_AUTH_STATE, ...(value || {}) };
  56. }, [value]);
  57. return <AuthContext.Provider value={merged}>{children}</AuthContext.Provider>;
  58. }