docs: add jsdoc

This commit is contained in:
2025-08-03 11:42:24 +08:00
parent 83be7c004a
commit 10c4c6d059
6 changed files with 99 additions and 8 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
printWidth: 80 printWidth: 100
tabWidth: 2 tabWidth: 2
useTabs: false useTabs: false
semi: false semi: false
+28 -1
View File
@@ -1,13 +1,40 @@
import { Navigate, Outlet, useLocation } from "react-router" import { Navigate, Outlet, useLocation } from "react-router"
import { useAppSelector } from "@/store" import { useAppSelector } from "@/store"
export const ProtectedRoute = () => { /**
* Renders child routes if the user is unauthenticated, otherwise redirects authenticated users to
* the root path.
*
* This component's logic allows unauthenticated users to access nested routes rendered
* via `Outlet`. Conversely, if a user is authenticated, they are redirected to the application's
* root path (`""`). This behaviour is inverse to the typical implementation of a 'protected route',
* which usually grants access to authenticated users and redirects unauthenticated users to a
* login page.
*/
export default function ProtectedRoute() {
/**
* Retrieves the authentication status from the Redux store.
*/
const isAuthenticated = useAppSelector((state) => state.auth.isAuthenticated) const isAuthenticated = useAppSelector((state) => state.auth.isAuthenticated)
/**
* Retrieves the current location object from React Router.
*/
const location = useLocation() const location = useLocation()
if (isAuthenticated) { if (isAuthenticated) {
/**
* Redirects authenticated users to the application's root path (`""`).
*
* The redirection includes the current location's state, allowing the
* target route to know where the user was redirected from. The
* `replace` prop ensures the current history entry is replaced.
*/
return <Navigate to="" state={{ from: location }} replace /> return <Navigate to="" state={{ from: location }} replace />
} }
/**
* Renders the child routes if the user is unauthenticated.
*/
return <Outlet /> return <Outlet />
} }
+2 -2
View File
@@ -2,9 +2,9 @@ import { StrictMode } from "react"
import { createRoot } from "react-dom/client" import { createRoot } from "react-dom/client"
import { Provider } from "react-redux" import { Provider } from "react-redux"
import { BrowserRouter, Route, Routes } from "react-router" import { BrowserRouter, Route, Routes } from "react-router"
import { store } from "@/store" import store from "@/store"
import "./index.css" import "./index.css"
import { ProtectedRoute } from "@/components/protected-route" import ProtectedRoute from "@/components/protected-route"
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>
+14 -1
View File
@@ -3,8 +3,21 @@ import duration from "dayjs/plugin/duration"
dayjs.extend(duration) dayjs.extend(duration)
/**
* Dayjs with `Duration` plugin.
*/
export default dayjs export default dayjs
const formatDatetime = (datetime: string) => dayjs(datetime).format("YYYY-MM-DD HH:mm:ss") /**
* Formats a given datetime string into a standardised "YYYY-MM-DD HH:mm:ss" format.
*
* This function utilises the [dayjs](https://day.js.org/) library for parsing and formatting.
*
* @param {string} datetime the datetime string to format
* @returns {string} the formatted datetime string in `YYYY-MM-DD HH:mm:ss` format
*/
function formatDatetime (datetime: string): string {
return dayjs(datetime).format("YYYY-MM-DD HH:mm:ss")
}
export { formatDatetime } export { formatDatetime }
+43
View File
@@ -1,20 +1,63 @@
import { createSlice } from "@reduxjs/toolkit" import { createSlice } from "@reduxjs/toolkit"
/**
* Defines the structure of the authentication state within the Redux store.
*/
interface AuthState { interface AuthState {
/**
* Indicates whether a user is currently authenticated.
* @type {boolean}
*/
isAuthenticated: boolean isAuthenticated: boolean
} }
/**
* The initial state for the authentication slice.
*
* By default, the user is considered unauthenticated.
*
* @constant
* @type {AuthState}
*/
const initialState: AuthState = { const initialState: AuthState = {
isAuthenticated: false isAuthenticated: false
} }
/**
* A Redux Toolkit slice for managing authentication-related state.
*
* This slice includes the reducer, actions, and initial state for the authentication feature.
* Currently, it only defines the initial state and no specific reducers, meaning it only
* holds the `isAuthenticated` flag.
*/
const authSlice = createSlice({ const authSlice = createSlice({
/**
* The name of the slice, used to generate action types.
* @type {string}
*/
name: "auth", name: "auth",
/**
* The initial state for this slice.
* @type {AuthState}
*/
initialState, initialState,
/**
* An object of reducer functions. Currently empty, meaning no actions are explicitly defined for
* state modification within this slice.
* @type {object}
*/
reducers: { reducers: {
} }
}) })
// export const { } = authSlice.actions // export const { } = authSlice.actions
/**
* The reducer function for the authentication slice.
*
* This is the default export and should be combined with other reducers in the Redux store.
*
* @default
*/
export default authSlice.reducer export default authSlice.reducer
+9 -1
View File
@@ -2,12 +2,20 @@ import { configureStore } from "@reduxjs/toolkit"
import { useDispatch, useSelector } from "react-redux" import { useDispatch, useSelector } from "react-redux"
import authReducer from "./auth-slice.ts" import authReducer from "./auth-slice.ts"
export const store = configureStore({ /**
* The Redux store instance for the application.
*
* This store is configured using [`configureStore`](https://redux-toolkit.js.org/api/configureStore)
* from <code>@reduxjs/toolkit</code>. It combines various slice reducers into
* a single root redux.
*/
const store = configureStore({
reducer: { reducer: {
auth: authReducer, auth: authReducer,
}, },
}) })
export default store
export type RootState = ReturnType<typeof store.getState> export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch export type AppDispatch = typeof store.dispatch
export type AppStore = typeof store export type AppStore = typeof store