Files
omnivore/packages/web/lib/networking/queries/useGetArticleQuery.tsx
Jackson Harper e4be448792 Update imports
2024-02-16 11:56:26 +08:00

190 lines
4.5 KiB
TypeScript

import { gql } from 'graphql-request'
import { Cache } from 'swr'
import { gqlFetcher, makeGqlFetcher } from '../networkHelpers'
import {
articleFragment,
ContentReader,
State,
} from '../fragments/articleFragment'
import { Highlight, highlightFragment } from '../fragments/highlightFragment'
import { ScopedMutator } from 'swr/dist/types'
import { Label, labelFragment } from '../fragments/labelFragment'
import {
LibraryItems,
Recommendation,
recommendationFragment,
} from './useGetLibraryItemsQuery'
import useSWR from 'swr'
type ArticleQueryInput = {
username?: string
slug?: string
includeFriendsHighlights?: boolean
}
type ArticleQueryOutput = {
articleData?: ArticleData
isLoading: boolean
articleFetchError: string[] | null
mutate: () => void
}
type ArticleData = {
article: NestedArticleData
}
type NestedArticleData = {
article: ArticleAttributes
errorCodes?: string[]
}
export type ArticleAttributes = {
id: string
title: string
url: string
originalArticleUrl: string
author?: string
image?: string
savedAt: string
isArchived: boolean
createdAt: string
publishedAt?: string
description?: string
wordsCount?: number
contentReader: ContentReader
readingProgressPercent: number
readingProgressTopPercent?: number
readingProgressAnchorIndex: number
slug: string
folder: string
savedByViewer?: boolean
content: string
highlights: Highlight[]
linkId: string
labels?: Label[]
state?: State
recommendations?: Recommendation[]
}
const query = gql`
query GetArticle(
$username: String!
$slug: String!
$includeFriendsHighlights: Boolean
) {
article(username: $username, slug: $slug) {
... on ArticleSuccess {
article {
...ArticleFields
content
highlights(input: { includeFriends: $includeFriendsHighlights }) {
...HighlightFields
}
labels {
...LabelFields
}
recommendations {
...RecommendationFields
}
}
}
... on ArticleError {
errorCodes
}
}
}
${articleFragment}
${highlightFragment}
${labelFragment}
${recommendationFragment}
`
export function useGetArticleQuery({
username,
slug,
includeFriendsHighlights,
}: ArticleQueryInput): ArticleQueryOutput {
const variables = {
username,
slug,
includeFriendsHighlights,
}
const { data, error, mutate } = useSWR(
slug ? [query, username, slug, includeFriendsHighlights] : null,
makeGqlFetcher(variables)
)
let resultData: ArticleData | undefined = data as ArticleData
let resultError = error
// 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 && resultData && resultData.article.errorCodes) {
resultError = resultData.article.errorCodes
resultData = undefined
}
return {
mutate: mutate,
articleData: resultData,
isLoading: !error && !data,
articleFetchError: resultError ? Array(resultError) : null,
}
}
export async function articleQuery(
input: ArticleQueryInput
): Promise<ArticleAttributes | undefined> {
const result = (await gqlFetcher(query, input)) as ArticleData
if (result.article) {
return result.article.article
}
return undefined
}
export const cacheArticle = (
mutate: ScopedMutator,
username: string,
article: ArticleAttributes,
includeFriendsHighlights = false
) => {
mutate([query, username, article.slug, includeFriendsHighlights], {
article: { article: { ...article, cached: true } },
})
}
export const removeItemFromCache = (
cache: Cache<unknown>,
mutate: ScopedMutator,
itemId: string
) => {
try {
const mappedCache = cache as Map<string, unknown>
mappedCache.forEach((value: any, key) => {
if (value && typeof value == 'object' && 'search' in value) {
const search = value.search as LibraryItems
const idx = search.edges.findIndex((edge) => edge.node.id == itemId)
if (idx > -1) {
value.search.edges.splice(idx, 1)
mutate(key, value, false)
}
}
})
mappedCache.forEach((value: any, key) => {
if (Array.isArray(value)) {
const idx = value.findIndex((item) => 'search' in item)
if (idx > -1) {
mutate(key, value, false)
}
}
})
} catch (error) {
console.log('error removing item from cache', error)
}
}