Skip to content

Commit

Permalink
fix: Portal frontend 25 (#52)
Browse files Browse the repository at this point in the history
* use query manager

* refactor
  • Loading branch information
SKairinos committed Aug 9, 2024
1 parent f90ad0f commit b2b6d53
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 59 deletions.
14 changes: 14 additions & 0 deletions src/components/SyncError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { SyncProblem as SyncProblemIcon } from "@mui/icons-material"
import { Stack, Typography } from "@mui/material"
import { type FC } from "react"

export interface SyncErrorProps {}

const SyncError: FC<SyncErrorProps> = () => (
<Stack alignItems="center" alignContent="center">
<SyncProblemIcon color="error" />
<Typography color="error.main">Failed to sync data</Typography>
</Stack>
)

export default SyncError
8 changes: 2 additions & 6 deletions src/components/TablePagination.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { SyncProblem as SyncProblemIcon } from "@mui/icons-material"
import {
CircularProgress,
TablePagination as MuiTablePagination,
type TablePaginationProps as MuiTablePaginationProps,
Stack,
type StackProps,
type TablePaginationBaseProps,
Typography,
} from "@mui/material"
import type { TypedUseLazyQuery } from "@reduxjs/toolkit/query/react"
import {
Expand All @@ -18,6 +16,7 @@ import {

import { type Pagination, usePagination } from "../hooks/api"
import type { ListArg, ListResult } from "../utils/api"
import SyncError from "./SyncError"

export type TablePaginationProps<
QueryArg extends ListArg,
Expand Down Expand Up @@ -95,10 +94,7 @@ const TablePagination = <
{isLoading ? (
<CircularProgress />
) : error || !data ? (
<>
<SyncProblemIcon color="error" />
<Typography color="error.main">Failed to load data</Typography>
</>
<SyncError />
) : (
children(data, { limit, page, offset, count, maxLimit: max_limit })
)}
Expand Down
19 changes: 3 additions & 16 deletions src/components/form/ApiAutocompleteField.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import { SyncProblem as SyncProblemIcon } from "@mui/icons-material"
import {
Button,
CircularProgress,
Stack,
Typography,
type ChipTypeMap,
} from "@mui/material"
import { Button, CircularProgress, type ChipTypeMap } from "@mui/material"
import type { TypedUseLazyQuery } from "@reduxjs/toolkit/query/react"
import {
Children,
Expand All @@ -21,6 +14,7 @@ import {
} from "../../components/form"
import { usePagination } from "../../hooks/api"
import type { ListArg, ListResult, TagId } from "../../utils/api"
import SyncError from "../SyncError"

export interface ApiAutocompleteFieldProps<
SearchKey extends keyof Omit<QueryArg, "limit" | "offset">,
Expand Down Expand Up @@ -135,14 +129,7 @@ const ApiAutocompleteField = <
const listItems = Children.toArray(children)
if (isLoading) listItems.push(<CircularProgress key="is-loading" />)
else {
if (isError) {
listItems.push(
<Stack direction="row" key="is-error">
<SyncProblemIcon color="error" />
<Typography color="error.main">Failed to load data</Typography>
</Stack>,
)
}
if (isError) listItems.push(<SyncError key="is-error" />)
if (hasMore) {
listItems.push(
<Button key="load-more" onClick={loadNextPage}>
Expand Down
3 changes: 3 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Image, { type ImageProps } from "./Image"
import ItemizedList, { type ItemizedListProps } from "./ItemizedList"
import OrderedGrid, { type OrderedGridProps } from "./OrderedGrid"
import ScrollRoutes, { type ScrollRoutesProps } from "./ScrollRoutes"
import SyncError, { type SyncErrorProps } from "./SyncError"
import TablePagination, { type TablePaginationProps } from "./TablePagination"
import YouTubeVideo, { type YouTubeVideoProps } from "./YouTubeVideo"

Expand All @@ -22,6 +23,7 @@ export {
ItemizedList,
OrderedGrid,
ScrollRoutes,
SyncError,
TablePagination,
YouTubeVideo,
type AppProps,
Expand All @@ -33,6 +35,7 @@ export {
type ItemizedListProps,
type OrderedGridProps,
type ScrollRoutesProps,
type SyncErrorProps,
type TablePaginationProps,
type YouTubeVideoProps,
}
37 changes: 0 additions & 37 deletions src/hooks/api.ts

This file was deleted.

83 changes: 83 additions & 0 deletions src/hooks/api.tsx
Original file line number Diff line number Diff line change
@@ -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<Pagination>({
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<QueryArg, ResultType>(
useQuery: TypedUseQuery<ResultType, QueryArg, any>,
arg: QueryArg,
children: (data: ResultType) => ReactNode,
options?: UseQueryManagerOptions,
): ReactNode {
const { data, isLoading, isSuccess, error } = useQuery(arg)

const {
loading: loadingNode = <CircularProgress />,
error: errorNode = <SyncError />,
} = 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
}
4 changes: 4 additions & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {
usePagination,
useQueryManager,
type Pagination,
type SetPagination,
type UsePaginationOptions,
type UseQueryManagerOptions,
} from "./api"
import {
useSession,
Expand All @@ -23,13 +25,15 @@ export {
useNavigate,
usePagination,
useParams,
useQueryManager,
useSearchParams,
useSession,
useSessionMetadata,
type Pagination,
type SessionMetadata,
type SetPagination,
type UsePaginationOptions,
type UseQueryManagerOptions,
type UseSessionChildren,
type UseSessionChildrenFunction,
type UseSessionOptions,
Expand Down
1 change: 1 addition & 0 deletions src/utils/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query/react"

import type { Optional, Required } from "./general"

// -----------------------------------------------------------------------------
Expand Down

0 comments on commit b2b6d53

Please sign in to comment.