Frontend State Management
Relevant source files
The following files were used as context for generating this wiki page:The frontend of the QA Dashboard employs a global state management strategy using React's Context API. This approach centralizes application-wide state, making it accessible to any component within the component tree without "prop drilling". The state is primarily divided into two domains: authentication (AuthContext) and real-time data synchronization via WebSockets (WebSocketContext).
These contexts are provided at the root of the application, ensuring that all pages and components can access user session information and live question data. This architecture simplifies state logic and facilitates a reactive user interface that responds to both user actions and real-time server-pushed events.
Global State Providers
The core of the state management architecture is established in the RootLayout component. It wraps the entire application with AuthProvider and WebSocketProvider, making their respective states available to all child components.
Sources: web/src/app/layout.js:19-25
// web/src/app/layout.js:21-25
<AuthProvider>
<WebSocketProvider>
{children}
</WebSocketProvider>
</AuthProvider>
The following diagram illustrates this provider hierarchy.
This diagram shows how AuthProvider and WebSocketProvider wrap the main application components.
Sources: web/src/app/layout.js:21-25
Authentication State (AuthContext)
The AuthContext is responsible for managing user authentication status, user data, and the associated JWT. It also handles the persistence of this data in localStorage to maintain user sessions across browser reloads.
Sources: web/src/context/AuthContext.js
State and Functions
The AuthProvider exposes the following state variables and functions through the useAuth hook.
| Name | Type | Description |
|---|---|---|
user | Object | An object containing the current user's data (id, username, email, is_admin). Defaults to a hardcoded "Anonymous" user object if not logged in. |
token | String | The JWT for the authenticated user. Defaults to a hardcoded anonymous token. |
loading | boolean | A flag that is true while the context is initializing and loading data from localStorage, and false otherwise. |
login() | Function | A function that takes userData and token as arguments, updates the state, and saves the authentication data to localStorage. |
logout() | Function | A function that clears the user session by reverting the state and localStorage back to the default "Anonymous" user credentials. |
Sources: web/src/context/AuthContext.js:7-11, web/src/context/AuthContext.js:29-35, web/src/context/AuthContext.js:37-44
Data Persistence and Anonymous User
On initial mount, the AuthProvider attempts to load the user object and auth token from localStorage. If no data is found, it initializes the state with a default "Anonymous" user, ensuring that the application always has a valid, albeit unauthenticated, user context. This anonymous user has a specific hardcoded id.
- Anonymous User ID:
57a7ed3c-2369-4204-b678-78a4ab970460 - Anonymous Token:
57a7ed3c-2369-4204-b678-78a4ab970460-anonymous-token
This mechanism allows guest users to view content while still having a consistent user object structure throughout the app. The login and logout functions manage writing to and clearing localStorage.
Sources: web/src/context/AuthContext.js:14-27
Login and Logout Flow
The login process is initiated from the LoginPage, which calls the login function from AuthContext upon a successful API response. The logout process is typically triggered from the Header component.
The sequence diagram below shows the login flow.
This diagram shows the sequence of events during user login, from form submission to state update and redirection.
Sources: web/src/app/login/page.js:49-62, web/src/context/AuthContext.js:29-35
Real-Time Data State (WebSocketContext)
The WebSocketContext manages the WebSocket connection for real-time updates of question data. It establishes the connection, handles incoming messages, and maintains a synchronized list of questions.
Sources: web/src/context/WebSocketContext.js
State and Functions
The WebSocketProvider exposes the following through the useWebSocket hook.
| Name | Type | Description |
|---|---|---|
isConnected | boolean | A flag indicating the current status of the WebSocket connection. |
questions | Array | An array of question objects, kept in sync with the backend. |
connect() | Function | Initiates the WebSocket connection to the server endpoint (ws://<host>/questions/ws). |
disconnect() | Function | Closes the WebSocket connection. |
send() | Function | Sends a JSON message to the server through the WebSocket. |
on() | Function | A function to register event listeners for specific message types from the WebSocket. (Note: This is defined but not actively used by consuming components in the files). |
Sources: web/src/context/WebSocketContext.js:7-10, web/src/context/WebSocketContext.js:12-61
Connection Management
The context handles the entire lifecycle of the WebSocket connection. It includes an automatic reconnection mechanism that attempts to re-establish the connection 3 seconds after it closes unexpectedly.
Sources: web/src/context/WebSocketContext.js:58-60
The connection lifecycle can be visualized as a state machine.
This diagram illustrates the different states of the WebSocket connection managed by WebSocketContext.
Sources: web/src/context/WebSocketContext.js:18-21, web/src/context/WebSocketContext.js:52-54, web/src/context/WebSocketContext.js:56-60
Real-Time Data Synchronization
Upon a successful connection, the backend sends an initial questions_list message, which populates the questions state array. Subsequently, the context listens for question_created and question_updated messages to update the local state in real-time, ensuring the UI always reflects the current data without needing to poll the server.
The following sequence diagram demonstrates how a new question is created and broadcast to all connected clients.
This diagram shows the real-time data flow when a user posts a new question, which is then broadcast to all connected clients.
Sources: backend/api/questions.py:44-49, web/src/context/WebSocketContext.js:33-44
Consuming State in Components
Components throughout the application use the custom hooks useAuth() and useWebSocket() to access the global state.
ForumPage: UsesuseAuth()to get user/token details anduseWebSocket()to get thequestionslist andisConnectedstatus.LoginPage: UsesuseAuth()to call theloginfunction.Header: UsesuseAuth()to display user information and provide alogoutbutton.
This diagram shows which components consume data from AuthContext and WebSocketContext.