diff --git a/packages/web/components/nav-containers/HighlightsContainer.tsx b/packages/web/components/nav-containers/HighlightsContainer.tsx
index a6a03716c..bc35a9d9f 100644
--- a/packages/web/components/nav-containers/HighlightsContainer.tsx
+++ b/packages/web/components/nav-containers/HighlightsContainer.tsx
@@ -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 && (
diff --git a/packages/web/components/nav-containers/HomeContainer.tsx b/packages/web/components/nav-containers/HomeContainer.tsx
index 017d616e1..b6f80a65f 100644
--- a/packages/web/components/nav-containers/HomeContainer.tsx
+++ b/packages/web/components/nav-containers/HomeContainer.tsx
@@ -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
}
-const NavigationContext = createContext(
- undefined
-)
+const NavigationContext =
+ createContext(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(() => {
diff --git a/packages/web/components/templates/ErrorLayout.tsx b/packages/web/components/templates/ErrorLayout.tsx
index be97b9c20..9848e6f61 100644
--- a/packages/web/components/templates/ErrorLayout.tsx
+++ b/packages/web/components/templates/ErrorLayout.tsx
@@ -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 (
@@ -32,11 +33,11 @@ export function ErrorLayout(props: ErrorLayoutProps): JSX.Element {
-
+
- );
+ )
}
diff --git a/packages/web/components/templates/NavigationLayout.tsx b/packages/web/components/templates/NavigationLayout.tsx
index 15f1b921f..cf053db7a 100644
--- a/packages/web/components/templates/NavigationLayout.tsx
+++ b/packages/web/components/templates/NavigationLayout.tsx
@@ -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)
diff --git a/packages/web/components/templates/PrimaryDropdown.tsx b/packages/web/components/templates/PrimaryDropdown.tsx
index 659df484f..9c8ab53ea 100644
--- a/packages/web/components/templates/PrimaryDropdown.tsx
+++ b/packages/web/components/templates/PrimaryDropdown.tsx
@@ -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 {
+ props.children ??
}
css={{ width: '240px', ml: '15px', bg: '$thNavMenuFooter' }}
>
@@ -150,16 +151,16 @@ export function PrimaryDropdown(props: PrimaryDropdownProps): JSX.Element {
}}
>
- {viewerData?.me && (
+ {viewerData && (
<>
- {viewerData.me.name}
+ {viewerData.name}
- {`@${viewerData.me.profile.username}`}
+ {`@${viewerData.profile.username}`}
>
)}
diff --git a/packages/web/components/templates/PrimaryLayout.tsx b/packages/web/components/templates/PrimaryLayout.tsx
index 6e5156f8a..3789b64d4 100644
--- a/packages/web/components/templates/PrimaryLayout.tsx
+++ b/packages/web/components/templates/PrimaryLayout.tsx
@@ -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)
diff --git a/packages/web/components/templates/library/LibraryContainer.tsx b/packages/web/components/templates/library/LibraryContainer.tsx
index 64d1f8ce4..589dce6a3 100644
--- a/packages/web/components/templates/library/LibraryContainer.tsx
+++ b/packages/web/components/templates/library/LibraryContainer.tsx
@@ -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([])
@@ -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({
key: 'libraryLayout',
initialValue: 'LIST_LAYOUT',
@@ -928,7 +934,7 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
{
return lastPage.pageInfo.hasNextPage
diff --git a/packages/web/lib/networking/viewer/useGetViewer.tsx b/packages/web/lib/networking/viewer/useGetViewer.tsx
new file mode 100644
index 000000000..fe9798933
--- /dev/null
+++ b/packages/web/lib/networking/viewer/useGetViewer.tsx
@@ -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}
+`
diff --git a/packages/web/pages/[username]/[slug]/index.tsx b/packages/web/pages/[username]/[slug]/index.tsx
index 90107e997..7fcd54189 100644
--- a/packages/web/pages/[username]/[slug]/index.tsx
+++ b/packages/web/pages/[username]/[slug]/index.tsx
@@ -42,6 +42,7 @@ import {
useMergeHighlight,
useUpdateHighlight,
} from '../../../lib/networking/highlights/useItemHighlights'
+import { useGetViewer } from '../../../lib/networking/viewer/useGetViewer'
const PdfArticleContainerNoSSR = dynamic(
() => 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}
- {libraryItem && viewerData?.me && libraryItem.contentReader == 'PDF' && (
+ {libraryItem && viewerData && libraryItem.contentReader == 'PDF' && (
)}
- {libraryItem && viewerData?.me && libraryItem.contentReader == 'WEB' && (
+ {libraryItem && viewerData && libraryItem.contentReader == 'WEB' && (
- {libraryItem && viewerData?.me ? (
+ {libraryItem && viewerData ? (
)}
- {libraryItem && viewerData?.me && libraryItem.contentReader == 'EPUB' && (
+ {libraryItem && viewerData && libraryItem.contentReader == 'EPUB' && (
- {libraryItem && viewerData?.me ? (
+ {libraryItem && viewerData ? (
) : (