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:
@ -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}
|
||||
/>
|
||||
|
||||
@ -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(() => {
|
||||
|
||||
@ -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>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -230,7 +230,7 @@ export function useGetLibraryItems(
|
||||
return response.search
|
||||
},
|
||||
enabled,
|
||||
maxPages: 2,
|
||||
refetchOnMount: false,
|
||||
initialPageParam: '0',
|
||||
getNextPageParam: (lastPage: LibraryItems) => {
|
||||
return lastPage.pageInfo.hasNextPage
|
||||
|
||||
43
packages/web/lib/networking/viewer/useGetViewer.tsx
Normal file
43
packages/web/lib/networking/viewer/useGetViewer.tsx
Normal 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}
|
||||
`
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user