Merge pull request #4262 from omnivore-app/fix/web-library-fetch

Use react-query for most viewer queries to get better caching, remove the maxpages on library as that broke scrolling
This commit is contained in:
Jackson Harper
2024-08-14 11:58:22 +08:00
committed by GitHub
12 changed files with 106 additions and 48 deletions

View File

@ -33,12 +33,13 @@ import { HighlightViewNote } from '../patterns/HighlightNotes'
import { theme } from '../tokens/stitches.config'
import { useDeleteHighlight } from '../../lib/networking/highlights/useItemHighlights'
import { EmptyLibrary } from '../templates/homeFeed/EmptyLibrary'
import { useGetViewer } from '../../lib/networking/viewer/useGetViewer'
const PAGE_SIZE = 10
export function HighlightsContainer(): JSX.Element {
const router = useRouter()
const viewer = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const { isLoading, setSize, size, data, mutate } = useGetHighlights({
first: PAGE_SIZE,
@ -86,11 +87,11 @@ export function HighlightsContainer(): JSX.Element {
)}
{highlights.map((highlight) => {
return (
viewer.viewerData?.me && (
viewerData && (
<HighlightCard
key={highlight.id}
highlight={highlight}
viewer={viewer.viewerData.me}
viewer={viewerData}
router={router}
mutate={mutate}
/>

View File

@ -34,11 +34,11 @@ import {
} from '../../lib/networking/queries/useGetSubscriptionsQuery'
import { Box, HStack, SpanBox, VStack } from '../elements/LayoutPrimitives'
import { Toaster } from 'react-hot-toast'
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
import useLibraryItemActions from '../../lib/hooks/useLibraryItemActions'
import { SyncLoader } from 'react-spinners'
import { useGetLibraryItems } from '../../lib/networking/library_items/useLibraryItems'
import { useRegisterActions } from 'kbar'
import { useGetViewer } from '../../lib/networking/viewer/useGetViewer'
type HomeState = {
items: HomeItem[]
@ -182,9 +182,8 @@ type NavigationContextType = {
dispatch: React.Dispatch<Action>
}
const NavigationContext = createContext<NavigationContextType | undefined>(
undefined
)
const NavigationContext =
createContext<NavigationContextType | undefined>(undefined)
export const useNavigation = (): NavigationContextType => {
const context = useContext(NavigationContext)
@ -199,7 +198,7 @@ export function HomeContainer(): JSX.Element {
const homeData = useGetHomeItems()
const router = useRouter()
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const hasTopPicks = (homeData: HomeItemResponse) => {
const topPicks = homeData.sections?.find(
@ -226,7 +225,7 @@ export function HomeContainer(): JSX.Element {
useApplyLocalTheme()
const viewerUsername = useMemo(() => {
return viewerData?.me?.profile.username
return viewerData?.profile.username
}, [viewerData])
const searchItems = useMemo(() => {

View File

@ -3,6 +3,7 @@ import { StyledText } from '../elements/StyledText'
import Link from 'next/link'
import { Button } from '../elements/Button'
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
import { useGetViewer } from '../../lib/networking/viewer/useGetViewer'
type ErrorPageStatusCode = 404 | 500
@ -12,7 +13,7 @@ type ErrorLayoutProps = {
}
export function ErrorLayout(props: ErrorLayoutProps): JSX.Element {
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
return (
<VStack alignment="center" distribution="start" css={{ height: '100%' }}>
@ -32,11 +33,11 @@ export function ErrorLayout(props: ErrorLayoutProps): JSX.Element {
</StyledText>
</HStack>
<SpanBox css={{ height: '64px' }} />
<Link passHref href={viewerData?.me ? '/home' : '/login'} legacyBehavior>
<Link passHref href={viewerData ? '/home' : '/login'} legacyBehavior>
<Button style="ctaDarkYellow">
{viewerData?.me ? 'Go Home' : 'Login'}
{viewerData ? 'Go Home' : 'Login'}
</Button>
</Link>
</VStack>
);
)
}

View File

@ -26,6 +26,7 @@ import {
import useWindowDimensions from '../../lib/hooks/useGetWindowDimensions'
import { useAddItem } from '../../lib/networking/library_items/useLibraryItems'
import { useHandleAddUrl } from '../../lib/hooks/useHandleAddUrl'
import { useGetViewer } from '../../lib/networking/viewer/useGetViewer'
export type NavigationSection =
| 'home'
@ -48,7 +49,7 @@ type NavigationLayoutProps = {
export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
useApplyLocalTheme()
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const router = useRouter()
const [showLogoutConfirmation, setShowLogoutConfirmation] = useState(false)
const [showKeyboardCommandsModal, setShowKeyboardCommandsModal] =
@ -69,8 +70,10 @@ export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
// Attempt to identify the user if they are logged in.
useEffect(() => {
setupAnalytics(viewerData?.me)
}, [viewerData?.me])
if (viewerData) {
setupAnalytics(viewerData)
}
}, [viewerData])
const showLogout = useCallback(() => {
setShowLogoutConfirmation(true)

View File

@ -17,6 +17,7 @@ import { styled, theme, ThemeId } from '../tokens/stitches.config'
import { LayoutType } from './homeFeed/HomeFeedContainer'
import { useCurrentTheme } from '../../lib/hooks/useCurrentTheme'
import { ThemeSelector } from './article/ReaderSettingsControl'
import { useGetViewer } from '../../lib/networking/viewer/useGetViewer'
type PrimaryDropdownProps = {
children?: ReactNode
@ -82,7 +83,7 @@ const TriggerButton = (props: TriggerButtonProps): JSX.Element => {
}
export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element {
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const router = useRouter()
const headerDropdownActionHandler = useCallback(
@ -129,7 +130,7 @@ export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element {
<Dropdown
side="top"
triggerElement={
props.children ?? <TriggerButton name={viewerData?.me?.name} />
props.children ?? <TriggerButton name={viewerData?.name} />
}
css={{ width: '240px', ml: '15px', bg: '$thNavMenuFooter' }}
>
@ -150,16 +151,16 @@ export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element {
}}
>
<Avatar
imageURL={viewerData?.me?.profile.pictureUrl}
imageURL={viewerData?.profile.pictureUrl}
height="40px"
fallbackText={viewerData?.me?.name.charAt(0) ?? ''}
fallbackText={viewerData?.name.charAt(0) ?? ''}
/>
<VStack
css={{ height: '40px', maxWidth: '240px' }}
alignment="start"
distribution="around"
>
{viewerData?.me && (
{viewerData && (
<>
<StyledText
css={{
@ -173,7 +174,7 @@ export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element {
whiteSpace: 'nowrap',
}}
>
{viewerData.me.name}
{viewerData.name}
</StyledText>
<StyledText
css={{
@ -186,7 +187,7 @@ export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element {
whiteSpace: 'nowrap',
}}
>
{`@${viewerData.me.profile.username}`}
{`@${viewerData.profile.username}`}
</StyledText>
</>
)}

View File

@ -15,6 +15,7 @@ import { updateTheme } from '../../lib/themeUpdater'
import { Priority, useRegisterActions } from 'kbar'
import { ThemeId } from '../tokens/stitches.config'
import { useVerifyAuth } from '../../lib/hooks/useVerifyAuth'
import { useGetViewer } from '../../lib/networking/viewer/useGetViewer'
type PrimaryLayoutProps = {
children: ReactNode
@ -28,7 +29,7 @@ type PrimaryLayoutProps = {
export function PrimaryLayout(props: PrimaryLayoutProps): JSX.Element {
useApplyLocalTheme()
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const router = useRouter()
const [showLogoutConfirmation, setShowLogoutConfirmation] = useState(false)
const [showKeyboardCommandsModal, setShowKeyboardCommandsModal] =
@ -78,8 +79,10 @@ export function PrimaryLayout(props: PrimaryLayoutProps): JSX.Element {
// Attempt to identify the user if they are logged in.
useEffect(() => {
setupAnalytics(viewerData?.me)
}, [viewerData?.me])
if (viewerData) {
setupAnalytics(viewerData)
}
}, [viewerData])
const showLogout = useCallback(() => {
setShowLogoutConfirmation(true)

View File

@ -55,6 +55,7 @@ import { emptyTrashMutation } from '../../../lib/networking/mutations/emptyTrash
import { State } from '../../../lib/networking/fragments/articleFragment'
import { useHandleAddUrl } from '../../../lib/hooks/useHandleAddUrl'
import { QueryClient, useQueryClient } from '@tanstack/react-query'
import { useGetViewer } from '../../../lib/networking/viewer/useGetViewer'
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
@ -80,7 +81,7 @@ type LibraryContainerProps = {
export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
const router = useRouter()
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const { queryValue } = useKBar((state) => ({ queryValue: state.searchQuery }))
const [searchResults, setSearchResults] = useState<SearchItem[]>([])
@ -116,6 +117,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
const {
data: itemsPages,
isLoading,
isFetching,
fetchNextPage,
hasNextPage,
error: fetchItemsError,
@ -309,7 +311,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
switch (action) {
case 'showDetail':
const username = viewerData?.me?.profile.username
const username = viewerData?.profile.username
if (username) {
setActiveCardId(item.node.id)
if (item.node.state === State.PROCESSING) {
@ -652,7 +654,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
name: link.title,
keywords: '#' + link.title + ' #' + link.siteName,
perform: () => {
const username = viewerData?.me?.profile.username
const username = viewerData?.profile.username
if (username) {
setActiveCardId(link.id)
router.push(`/${username}/${link.slug}`)
@ -666,7 +668,11 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
activeCardId ? [...ACTIVE_ACTIONS, ...UNACTIVE_ACTIONS] : UNACTIVE_ACTIONS,
[activeCardId, activeItem]
)
useFetchMore(fetchNextPage)
useFetchMore(() => {
if (!isFetching && !isLoading && hasNextPage) {
fetchNextPage()
}
})
const setIsChecked = useCallback(
(itemId: string, set: boolean) => {
@ -885,7 +891,7 @@ export type HomeFeedContentProps = {
}
function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const [layout, setLayout] = usePersistedState<LayoutType>({
key: 'libraryLayout',
initialValue: 'LIST_LAYOUT',
@ -928,7 +934,7 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
<LibraryHeader
layout={layout}
folder={props.folder}
viewer={viewerData?.me}
viewer={viewerData}
updateLayout={updateLayout}
showFilterMenu={props.showNavigationMenu}
searchTerm={props.searchTerm}
@ -954,7 +960,7 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
{showItems && (
<LibraryItemsLayout
viewer={viewerData?.me}
viewer={viewerData}
layout={layout}
isChecked={props.itemIsChecked}
{...props}

View File

@ -230,7 +230,7 @@ export function useGetLibraryItems(
return response.search
},
enabled,
maxPages: 2,
refetchOnMount: false,
initialPageParam: '0',
getNextPageParam: (lastPage: LibraryItems) => {
return lastPage.pageInfo.hasNextPage

View File

@ -0,0 +1,43 @@
import { useQuery } from '@tanstack/react-query'
import { gqlFetcher } from '../networkHelpers'
import { featureFragment } from '../fragments/featureFragment'
import { gql } from 'graphql-request'
import { UserBasicData } from '../queries/useGetViewerQuery'
export function useGetViewer() {
return useQuery({
queryKey: ['viewer'],
staleTime: Infinity,
queryFn: async () => {
const response = (await gqlFetcher(GQL_GET_VIEWER)) as ViewerData
return response.me
},
})
}
type ViewerData = {
me?: UserBasicData
}
const GQL_GET_VIEWER = gql`
query Viewer {
me {
id
name
isFullUser
profile {
id
username
pictureUrl
bio
}
email
source
intercomHash
featureList {
...FeatureFields
}
}
}
${featureFragment}
`

View File

@ -42,6 +42,7 @@ import {
useMergeHighlight,
useUpdateHighlight,
} from '../../../lib/networking/highlights/useItemHighlights'
import { useGetViewer } from '../../../lib/networking/viewer/useGetViewer'
const PdfArticleContainerNoSSR = dynamic<PdfArticleContainerProps>(
() => import('./../../../components/templates/article/PdfArticleContainer'),
@ -57,7 +58,7 @@ export default function Reader(): JSX.Element {
const router = useRouter()
const [showEditModal, setShowEditModal] = useState(false)
const [showHighlightsModal, setShowHighlightsModal] = useState(false)
const { viewerData } = useGetViewerQuery()
const { data: viewerData } = useGetViewer()
const readerSettings = useReaderSettings()
const archiveItem = useArchiveItem()
const deleteItem = useDeleteItem()
@ -275,7 +276,7 @@ export default function Reader(): JSX.Element {
}, [actionHandler, goNextOrHome, goPreviousOrHome])
useEffect(() => {
if (libraryItem && viewerData?.me) {
if (libraryItem && viewerData) {
posthog.capture('link_read', {
link: libraryItem.id,
slug: libraryItem.slug,
@ -547,15 +548,15 @@ export default function Reader(): JSX.Element {
/>
) : null}
</VStack>
{libraryItem && viewerData?.me && libraryItem.contentReader == 'PDF' && (
{libraryItem && viewerData && libraryItem.contentReader == 'PDF' && (
<PdfArticleContainerNoSSR
article={libraryItem}
showHighlightsModal={showHighlightsModal}
setShowHighlightsModal={setShowHighlightsModal}
viewer={viewerData.me}
viewer={viewerData}
/>
)}
{libraryItem && viewerData?.me && libraryItem.contentReader == 'WEB' && (
{libraryItem && viewerData && libraryItem.contentReader == 'WEB' && (
<VStack
id="article-wrapper"
alignment="center"
@ -572,9 +573,9 @@ export default function Reader(): JSX.Element {
},
}}
>
{libraryItem && viewerData?.me ? (
{libraryItem && viewerData ? (
<ArticleContainer
viewer={viewerData.me}
viewer={viewerData}
article={libraryItem}
isAppleAppEmbed={false}
highlightBarDisabled={false}
@ -677,7 +678,7 @@ export default function Reader(): JSX.Element {
</VStack>
)}
{libraryItem && viewerData?.me && libraryItem.contentReader == 'EPUB' && (
{libraryItem && viewerData && libraryItem.contentReader == 'EPUB' && (
<VStack
alignment="center"
distribution="start"
@ -690,12 +691,12 @@ export default function Reader(): JSX.Element {
paddingTop: '80px',
}}
>
{libraryItem && viewerData?.me ? (
{libraryItem && viewerData ? (
<EpubContainerNoSSR
article={libraryItem}
showHighlightsModal={showHighlightsModal}
setShowHighlightsModal={setShowHighlightsModal}
viewer={viewerData.me}
viewer={viewerData}
/>
) : (
<SkeletonArticleContainer

View File

@ -4,12 +4,13 @@ import { PageMetaData } from '../components/patterns/PageMetaData'
import { LoadingView } from '../components/patterns/LoadingView'
import { About } from '../components/templates/About'
import { DEFAULT_HOME_PATH } from '../lib/navigations'
import { useGetViewer } from '../lib/networking/viewer/useGetViewer'
export default function LandingPage(): JSX.Element {
const router = useRouter()
const { viewerData, isLoading } = useGetViewerQuery()
const { data: viewerData, isLoading } = useGetViewer()
if (!isLoading && router.isReady && viewerData?.me) {
if (!isLoading && router.isReady && viewerData) {
const navReturn = window.localStorage.getItem('nav-return')
if (navReturn) {
router.push(navReturn)

View File

@ -29,6 +29,7 @@ import {
} from '../../lib/networking/queries/useGetIntegrationsQuery'
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers'
import { useGetViewer } from '../../lib/networking/viewer/useGetViewer'
// Styles
const Header = styled(Box, {
color: '$utilityTextDefault',
@ -73,8 +74,6 @@ type integrationsCard = {
}
}
export default function Integrations(): JSX.Element {
const { viewerData } = useGetViewerQuery()
const { integrations, revalidate } = useGetIntegrationsQuery()
// const { webhooks } = useGetWebhooksQuery()