mirror of
https://github.com/OHTU-German-learning-website/OHTU-German-learning-website.git
synced 2026-10-12 19:13:51 +03:00
Added more documentation to the project.
This commit is contained in:
@@ -4,6 +4,13 @@ import useQuery from "@/shared/hooks/useQuery";
|
||||
|
||||
const GlossaryContext = createContext(null);
|
||||
|
||||
/**
|
||||
* GlossaryProvider - React context provider that fetches glossary entries
|
||||
* and exposes them to the component tree.
|
||||
*
|
||||
* @param {{children: import('react').ReactNode}} props Component children.
|
||||
* @returns {JSX.Element} Provider supplying `{ entries, wordMap, isLoading, error }`.
|
||||
*/
|
||||
export function GlossaryProvider({ children }) {
|
||||
const { data: entries = [], isLoading, error } = useQuery("/glossary");
|
||||
|
||||
@@ -29,6 +36,18 @@ export function GlossaryProvider({ children }) {
|
||||
</GlossaryContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* useGlossary - hook to consume glossary context.
|
||||
*
|
||||
* @returns {{
|
||||
* entries: Array<any>,
|
||||
* wordMap: Record<string, any>,
|
||||
* isLoading: boolean,
|
||||
* error: any
|
||||
* }} The glossary context value.
|
||||
* @throws {Error} If called outside a `GlossaryProvider`.
|
||||
*/
|
||||
export function useGlossary() {
|
||||
const context = useContext(GlossaryContext);
|
||||
|
||||
|
||||
@@ -28,6 +28,13 @@ const UserContext = createContext({
|
||||
});
|
||||
|
||||
// Create a provider component
|
||||
/**
|
||||
* UserProvider - React context provider that supplies authentication state
|
||||
* and helper actions to the component tree.
|
||||
*
|
||||
* @param {{children: import('react').ReactNode}} props
|
||||
* @returns {JSX.Element} The provider wrapping `children`.
|
||||
*/
|
||||
export function UserProvider({ children }) {
|
||||
const [auth, setAuth] = useState(defaultUserState);
|
||||
const makeRequest = useRequest();
|
||||
@@ -37,11 +44,25 @@ export function UserProvider({ children }) {
|
||||
userOptions[0]
|
||||
);
|
||||
// Check if user is logged in on initial load
|
||||
/**
|
||||
* resetAuthState - reset authentication state to defaults and clear
|
||||
* persisted `actAs` selection from local storage.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
const resetAuthState = () => {
|
||||
setAuth(defaultUserState);
|
||||
clearActAs();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
* checkUserSession - internal helper to call `/auth/session` and
|
||||
* update the `auth` state accordingly. Allows HTTP 401 responses to
|
||||
* be handled gracefully (treated as not logged in).
|
||||
*
|
||||
* @returns {Promise<void>} resolves when the session check finishes.
|
||||
*/
|
||||
async function checkUserSession() {
|
||||
try {
|
||||
const response = await makeRequest("/auth/session", undefined, {
|
||||
@@ -76,7 +97,13 @@ export function UserProvider({ children }) {
|
||||
checkUserSession();
|
||||
}, [pathname]);
|
||||
|
||||
// Logout function
|
||||
/**
|
||||
* logout - perform logout request and reset client state on success.
|
||||
* If the server responds with status 200 the local auth state is reset
|
||||
* and the page is reloaded to clear any cached state.
|
||||
*
|
||||
* @returns {Promise<void>} resolves when the logout completes.
|
||||
*/
|
||||
const logout = async () => {
|
||||
const response = await makeRequest("/auth/logout");
|
||||
if (response.status === 200) {
|
||||
@@ -94,15 +121,33 @@ export function UserProvider({ children }) {
|
||||
}
|
||||
|
||||
// Custom hook to use the user context
|
||||
/**
|
||||
* useUser - React hook to access the `UserContext`.
|
||||
*
|
||||
* @returns {{auth: object, logout: function, setActAs: function, actAs: object}}
|
||||
* The value provided by `UserProvider`.
|
||||
*/
|
||||
export function useUser() {
|
||||
return useContext(UserContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* useIsLoggedIn - hook that returns whether the current user is logged in.
|
||||
*
|
||||
* @returns {boolean} `true` when a session is active, otherwise `false`.
|
||||
*/
|
||||
export function useIsLoggedIn() {
|
||||
const { auth } = useUser();
|
||||
return auth?.isLoggedIn ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* useLoggedOutGuard - redirect guard for routes that should be visible
|
||||
* only to logged-out users. When called inside a component it will
|
||||
* navigate to `/` if the user is already authenticated.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
export const useLoggedOutGuard = () => {
|
||||
const { auth } = useUser();
|
||||
const router = useRouter();
|
||||
@@ -111,6 +156,14 @@ export const useLoggedOutGuard = () => {
|
||||
}, [auth, router]);
|
||||
};
|
||||
|
||||
/**
|
||||
* useIsAdmin - hook that enforces admin-only access to a route and returns
|
||||
* whether the current user has admin privileges. The hook will redirect
|
||||
* non-admin users to the root (`/`) when used inside a component.
|
||||
*
|
||||
* @returns {boolean|undefined} `true` if current user is admin, `false`
|
||||
* if not an admin, or `undefined` when there is no authenticated user yet.
|
||||
*/
|
||||
export function useIsAdmin() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
@@ -127,6 +180,17 @@ export function useIsAdmin() {
|
||||
return auth?.user?.id ? auth.user.is_admin : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* checkUseIsAdmin - utility that inspects the current `UserContext` and
|
||||
* returns a boolean indicating admin rights.
|
||||
*
|
||||
* Note: this function relies on `useUser()` so it must be called from
|
||||
* React component or hook context (i.e. during render) to access the
|
||||
* current context value.
|
||||
*
|
||||
* @returns {boolean|undefined} `true` when user is admin, `false` when
|
||||
* not an admin, or `undefined` when there is no authenticated user.
|
||||
*/
|
||||
export function checkUseIsAdmin() {
|
||||
let is_admin = true;
|
||||
const { auth, actAs } = useUser();
|
||||
|
||||
@@ -2,11 +2,32 @@ import { NextResponse } from "next/server";
|
||||
import { AUTH_COOKIE_NAME } from "@/shared/const";
|
||||
|
||||
// Paths only logged-in users can access
|
||||
/**
|
||||
* authRequired - array of path prefixes that require an authenticated
|
||||
* session (users without a valid session cookie will be redirected
|
||||
* to the login page when attempting to access these paths).
|
||||
* @type {string[]}
|
||||
*/
|
||||
const authRequired = ["/grammar/exercises", "/edit_info"];
|
||||
|
||||
// Restricted paths logged-in users cannot access
|
||||
/**
|
||||
* unauthRequired - array of path prefixes that should not be accessible
|
||||
* to already authenticated users (e.g. login/register pages).
|
||||
* @type {string[]}
|
||||
*/
|
||||
const unauthRequired = ["/auth/login", "/auth/register"];
|
||||
|
||||
/**
|
||||
* middleware - Next.js middleware that protects certain routes by
|
||||
* checking for an authentication cookie. If a user without a valid
|
||||
* session attempts to access a protected path they are redirected to
|
||||
* the login page and the original path is provided as a `redirect`
|
||||
* query parameter. Responses are marked non-cacheable.
|
||||
*
|
||||
* @param {import('next/server').NextRequest} request
|
||||
* @returns {import('next/server').NextResponse}
|
||||
*/
|
||||
export async function middleware(request) {
|
||||
const { pathname } = request.nextUrl;
|
||||
const sessionCookie = request.cookies.get(AUTH_COOKIE_NAME);
|
||||
@@ -24,6 +45,11 @@ export async function middleware(request) {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* config - Next.js middleware configuration. The `matcher` controls which
|
||||
* paths the middleware runs for; this pattern excludes API routes, Next
|
||||
* internals and common static files.
|
||||
*/
|
||||
export const config = {
|
||||
matcher: [
|
||||
"/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
|
||||
|
||||
Reference in New Issue
Block a user