From 28255e073f46f8080627a93b632ba0153b697d05 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 7 Jun 2024 16:15:09 +0800 Subject: [PATCH] add get highlights api integration --- .../networking/fragments/highlightFragment.ts | 2 + .../networking/queries/useGetHighlights.tsx | 110 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 packages/web/lib/networking/queries/useGetHighlights.tsx diff --git a/packages/web/lib/networking/fragments/highlightFragment.ts b/packages/web/lib/networking/fragments/highlightFragment.ts index 0185bd524..6f6064b46 100644 --- a/packages/web/lib/networking/fragments/highlightFragment.ts +++ b/packages/web/lib/networking/fragments/highlightFragment.ts @@ -1,4 +1,5 @@ import { gql } from 'graphql-request' +import { LibraryItemNode } from '../queries/useGetLibraryItemsQuery' import { Label } from './labelFragment' export const highlightFragment = gql` @@ -45,6 +46,7 @@ export type Highlight = { color?: string highlightPositionPercent?: number highlightPositionAnchorIndex?: number + libraryItem?: LibraryItemNode } export type User = { diff --git a/packages/web/lib/networking/queries/useGetHighlights.tsx b/packages/web/lib/networking/queries/useGetHighlights.tsx new file mode 100644 index 000000000..635426d5e --- /dev/null +++ b/packages/web/lib/networking/queries/useGetHighlights.tsx @@ -0,0 +1,110 @@ +import { gql } from 'graphql-request' +import useSWRInfinite from 'swr/infinite' +import { Highlight, highlightFragment } from '../fragments/highlightFragment' +import { gqlFetcher } from '../networkHelpers' +import { PageInfo } from './useGetLibraryItemsQuery' + +interface HighlightsResponse { + highlightsData?: Array + highlightsError?: unknown + isLoading: boolean + isValidating: boolean + error: boolean + size: number + setSize: ( + size: number | ((_size: number) => number) + ) => Promise + mutate: () => void +} + +interface HighlightsVariables { + first?: number + after?: string + query?: string +} + +interface HighlightEdge { + node: Highlight + cursor: string +} + +interface HighlightsData { + highlights: { + edges: Array + pageInfo: PageInfo + errorCodes?: Array + } +} + +export const useGetHighlights = ( + variables: HighlightsVariables +): HighlightsResponse => { + const query = gql` + query Highlights($first: Int, $after: String, $query: String) { + highlights(first: $first, after: $after, query: $query) { + ... on HighlightsSuccess { + edges { + node { + ...HighlightFields + } + cursor + } + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + } + ... on HighlightsError { + errorCodes + } + } + } + ${highlightFragment} + ` + + const getKey = (pageIndex: number, previousPageData: any) => { + if (previousPageData && !previousPageData.highlights.edges) return null + + if (pageIndex === 0) return `${query}_${variables.first}_${variables.query}` + + return `${query}_${previousPageData.highlights.pageInfo.endCursor}_${variables.first}_${variables.query}` + } + + const fetcher = async () => gqlFetcher(query, variables, true) + + const { data, error, isValidating, mutate, size, setSize } = useSWRInfinite( + getKey, + fetcher, + { revalidateFirstPage: false } + ) + + let responseError = error + let responsePages = data as Array | undefined + + // We need to check the response errors here and return the error + // it will be nested in the data pages, if there is one error, + // we invalidate the data and return the error. We also zero out + // the response in the case of an error. + if (!error && responsePages) { + const errors = responsePages.filter( + (d) => d.highlights.errorCodes && d.highlights.errorCodes.length > 0 + ) + if (errors?.length > 0) { + responseError = errors + responsePages = undefined + } + } + + return { + isValidating, + highlightsData: responsePages || undefined, + highlightsError: responseError, + isLoading: !error && !data, + error: !!error, + size, + setSize, + mutate, + } +}