diff --git a/src/hooks/api.ts b/src/hooks/api.ts deleted file mode 100644 index 3a53daf..0000000 --- a/src/hooks/api.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { type Dispatch, type SetStateAction, useState } from "react" - -export type Pagination = { page: number; limit: number; offset: number } -export type SetPagination = Dispatch< - SetStateAction<{ page: number; limit: number }> -> -export type UsePaginationOptions = Partial<{ - page: number - limit: number -}> - -export function usePagination( - options?: UsePaginationOptions, -): [Pagination, SetPagination] { - const { page = 0, limit = 150 } = options || {} - - const [pagination, _setPagination] = useState({ - page, - limit, - offset: page * limit, - }) - - const setPagination: SetPagination = value => { - _setPagination(({ page: previousPage, limit: previousLimit }) => { - let { page, limit } = - typeof value === "function" - ? value({ page: previousPage, limit: previousLimit }) - : value - - if (limit !== previousLimit) page = 0 - - return { page, limit, offset: page * limit } - }) - } - - return [pagination, setPagination] -} diff --git a/src/hooks/api.tsx b/src/hooks/api.tsx new file mode 100644 index 0000000..558ec58 --- /dev/null +++ b/src/hooks/api.tsx @@ -0,0 +1,83 @@ +import { CircularProgress } from "@mui/material" +import type { TypedUseQuery } from "@reduxjs/toolkit/query/react" +import { + useState, + type Dispatch, + type ReactNode, + type SetStateAction, +} from "react" + +import SyncError from "../components/SyncError" + +export type Pagination = { page: number; limit: number; offset: number } +export type SetPagination = Dispatch< + SetStateAction<{ page: number; limit: number }> +> +export type UsePaginationOptions = Partial<{ + page: number + limit: number +}> + +export function usePagination( + options?: UsePaginationOptions, +): [Pagination, SetPagination] { + const { page = 0, limit = 150 } = options || {} + + const [pagination, _setPagination] = useState({ + page, + limit, + offset: page * limit, + }) + + const setPagination: SetPagination = value => { + _setPagination(({ page: previousPage, limit: previousLimit }) => { + let { page, limit } = + typeof value === "function" + ? value({ page: previousPage, limit: previousLimit }) + : value + + if (limit !== previousLimit) page = 0 + + return { page, limit, offset: page * limit } + }) + } + + return [pagination, setPagination] +} + +export type UseQueryManagerOptions = Partial<{ + loading: ReactNode + error: ReactNode +}> + +export function useQueryManager( + useQuery: TypedUseQuery, + arg: QueryArg, + children: (data: ResultType) => ReactNode, + options?: UseQueryManagerOptions, +): ReactNode { + const { data, isLoading, isSuccess, error } = useQuery(arg) + + const { + loading: loadingNode = , + error: errorNode = , + } = options || {} + + // An error occurred. + if (error) { + console.error(error) + return errorNode + } + + // Busy calling the API. + if (isLoading) return loadingNode + + // Called the API and got data. + if (data) return children(data) + + // Called the API and did not get data. + if (isSuccess) throw Error("Expected to get data from API but got nothing.") + + // Have yet to call the API. + return loadingNode +} diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 7c4d185..1d2fcd4 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,8 +1,10 @@ import { usePagination, + useQueryManager, type Pagination, type SetPagination, type UsePaginationOptions, + type UseQueryManagerOptions, } from "./api" import { useSession, @@ -23,6 +25,7 @@ export { useNavigate, usePagination, useParams, + useQueryManager, useSearchParams, useSession, useSessionMetadata, @@ -30,6 +33,7 @@ export { type SessionMetadata, type SetPagination, type UsePaginationOptions, + type UseQueryManagerOptions, type UseSessionChildren, type UseSessionChildrenFunction, type UseSessionOptions, diff --git a/src/utils/api.tsx b/src/utils/api.ts similarity index 85% rename from src/utils/api.tsx rename to src/utils/api.ts index bf3bf6b..e1536e6 100644 --- a/src/utils/api.tsx +++ b/src/utils/api.ts @@ -1,11 +1,5 @@ -import { CircularProgress } from "@mui/material" -import type { - FetchBaseQueryError, - TypedUseQuery, -} from "@reduxjs/toolkit/query/react" -import type { ReactNode } from "react" - -import { SyncError } from "../components" +import type { FetchBaseQueryError } from "@reduxjs/toolkit/query/react" + import type { Optional, Required } from "./general" // ----------------------------------------------------------------------------- @@ -247,40 +241,3 @@ export function tagData>( return [] } } - -export type UseQueryManagerOptions = Partial<{ - loading: ReactNode - error: ReactNode -}> - -export function useQueryManager( - useQuery: TypedUseQuery, - arg: QueryArg, - children: (data: ResultType) => ReactNode, - options?: UseQueryManagerOptions, -): ReactNode { - const { data, isLoading, isSuccess, error } = useQuery(arg) - - const { - loading: loadingNode = , - error: errorNode = , - } = options || {} - - // An error occurred. - if (error) { - console.error(error) - return errorNode - } - - // Busy calling the API. - if (isLoading) return loadingNode - - // Called the API and got data. - if (data) return children(data) - - // Called the API and did not get data. - if (isSuccess) throw Error("Expected to get data from API but got nothing.") - - // Have yet to call the API. - return loadingNode -}