diff --git a/packages/web/components/templates/homeFeed/EmptyLibrary.tsx b/packages/web/components/templates/homeFeed/EmptyLibrary.tsx index cd38758ba..7f8a37012 100644 --- a/packages/web/components/templates/homeFeed/EmptyLibrary.tsx +++ b/packages/web/components/templates/homeFeed/EmptyLibrary.tsx @@ -86,7 +86,7 @@ export const EmptyLibrary = (props: EmptyLibraryProps) => { const helpTitle = useMemo(() => { switch (type) { case 'feed': - return 'You do not have any feed items.' + return 'You do not have any feed items matching this query.' case 'newsletter': return 'You do not have any newsletter items.' } diff --git a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx index ae89e8f0f..dbfb16b20 100644 --- a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx +++ b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx @@ -2,7 +2,7 @@ import { Action, createAction, useKBar, useRegisterActions } from 'kbar' import debounce from 'lodash/debounce' import { useRouter } from 'next/router' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import toast, { Toaster } from "react-hot-toast" +import toast, { Toaster } from 'react-hot-toast' import TopBarProgress from 'react-topbar-progress-indicator' import { useFetchMore } from '../../../lib/hooks/useFetchMoreScroll' import { usePersistedState } from '../../../lib/hooks/usePersistedState' @@ -48,8 +48,9 @@ import { } from '../../../lib/toastHelpers' import { SetPageLabelsModalPresenter } from '../article/SetLabelsModalPresenter' import { NotebookPresenter } from '../article/NotebookPresenter' -import { saveUrlMutation } from "../../../lib/networking/mutations/saveUrlMutation" -import { articleQuery } from "../../../lib/networking/queries/useGetArticleQuery" +import { saveUrlMutation } from '../../../lib/networking/mutations/saveUrlMutation' +import { articleQuery } from '../../../lib/networking/queries/useGetArticleQuery' +import { searchQuery } from '../../../lib/networking/queries/search' export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT' export type LibraryMode = 'reads' | 'highlights' @@ -70,7 +71,7 @@ const debouncedFetchSearchResults = debounce((query, cb) => { // We set a relatively high delay for the refresh at the end, as it's likely there's an issue // in processing. We give it the best attempt to be able to resolve, but if it doesn't we set // the state as Failed. On refresh it will try again if the backend sends "PROCESSING" -const TIMEOUT_DELAYS = [1000, 2000, 2500, 3500, 5000, 10000, 60000]; +const TIMEOUT_DELAYS = [1000, 2000, 2500, 3500, 5000, 10000, 60000] export function HomeFeedContainer(): JSX.Element { const { viewerData } = useGetViewerQuery() @@ -179,58 +180,69 @@ export function HomeFeedContainer(): JSX.Element { return itemsPages[itemsPages.length - 1].search.pageInfo.hasNextPage }, [itemsPages]) - const libraryItems = useMemo(() => { const items = itemsPages?.flatMap((ad) => { - return ad.search.edges.map(it => ({ ...it, isLoading: it.node.state === 'PROCESSING'})); + return ad.search.edges.map((it) => ({ + ...it, + isLoading: it.node.state === 'PROCESSING', + })) }) || [] return items }, [itemsPages, performActionOnItem]) useEffect(() => { - const timeout : NodeJS.Timeout[] = [] + const timeout: NodeJS.Timeout[] = [] - const items = - (itemsPages?.flatMap((ad) => { - return ad.search.edges.map(it => ({ ...it, isLoading: it.node.state === 'PROCESSING'})); - }) || []) - .filter(it => it.isLoading); + const items = ( + itemsPages?.flatMap((ad) => { + return ad.search.edges.map((it) => ({ + ...it, + isLoading: it.node.state === 'PROCESSING', + })) + }) || [] + ).filter((it) => it.isLoading) items.map(async (item) => { - let startIdx = 0; + let startIdx = 0 const seeIfUpdated = async () => { if (startIdx > TIMEOUT_DELAYS.length) { - item.node.state = State.FAILED; + item.node.state = State.FAILED return } const username = viewerData?.me?.profile.username - const itemsToUpdate = libraryItems.filter(it => it.isLoading); + const itemsToUpdate = libraryItems.filter((it) => it.isLoading) if (itemsToUpdate.length > 0) { - const link = await articleQuery({ username, slug: item.node.slug, includeFriendsHighlights: false }) + const link = await articleQuery({ + username, + slug: item.node.slug, + includeFriendsHighlights: false, + }) - if (link && link.state != "PROCESSING") { - const updatedArticle = { ...item }; + if (link && link.state != 'PROCESSING') { + const updatedArticle = { ...item } updatedArticle.node = { ...item.node, ...link } - updatedArticle.isLoading = false; + updatedArticle.isLoading = false console.log(`Updating Metadata of ${item.node.slug}.`) - performActionOnItem('update-item', updatedArticle); - return; + performActionOnItem('update-item', updatedArticle) + return } - console.log(`Trying to get the metadata of item ${item.node.slug}... Retry ${startIdx} of 5`); + console.log( + `Trying to get the metadata of item ${item.node.slug}... Retry ${startIdx} of 5` + ) timeout.push(setTimeout(seeIfUpdated, TIMEOUT_DELAYS[startIdx++])) } } - await seeIfUpdated(); - }); + await seeIfUpdated() + }) return () => { - timeout.forEach(clearTimeout); + timeout.forEach(clearTimeout) } }, [itemsPages]) @@ -769,36 +781,39 @@ export function HomeFeedContainer(): JSX.Element { [itemsPages, multiSelectMode, checkedItems] ) - const handleLinkSubmission = - async (link: string, timezone: string, locale: string) => { - const result = await saveUrlMutation(link, timezone, locale) - if (result) { - toast( - () => ( - - Link Saved - - - - ), - { position: 'bottom-right' } - ) - const id = result.url?.match(/[^/]+$/)?.[0] ?? ""; - performActionOnItem('refresh', undefined as unknown as any) - } else { - showErrorToast('Error saving link', { position: 'bottom-right' }) - } - }; + const handleLinkSubmission = async ( + link: string, + timezone: string, + locale: string + ) => { + const result = await saveUrlMutation(link, timezone, locale) + if (result) { + toast( + () => ( + + Link Saved + + + + ), + { position: 'bottom-right' } + ) + const id = result.url?.match(/[^/]+$/)?.[0] ?? '' + performActionOnItem('refresh', undefined as unknown as any) + } else { + showErrorToast('Error saving link', { position: 'bottom-right' }) + } + } return ( Promise - handleLinkSubmission: (link: string, timezone: string, locale:string) => Promise, + handleLinkSubmission: ( + link: string, + timezone: string, + locale: string + ) => Promise setIsChecked: (itemId: string, set: boolean) => void itemIsChecked: (itemId: string) => boolean @@ -986,7 +1005,10 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element { )} {props.showAddLinkModal && ( - props.setShowAddLinkModal(false)} /> + props.setShowAddLinkModal(false)} + /> )} @@ -1044,6 +1066,7 @@ function LibraryItemsLayout(props: LibraryItemsLayoutProps): JSX.Element { > {!props.isValidating && props.items.length == 0 ? ( { props.setShowAddLinkModal(true) }} diff --git a/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx b/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx index f3177cbcf..e2c3f4094 100644 --- a/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx +++ b/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx @@ -92,7 +92,7 @@ function SavedSearches(props: LibraryFilterMenuProps): JSX.Element { term: 'in:inbox sort:read-desc is:unread', }, { - name: 'Read Later', + name: 'Non-Feed Items', term: 'in:library', }, { @@ -182,7 +182,13 @@ function Subscriptions(props: LibraryFilterMenuProps): JSX.Element { window.location.href = '/settings/subscriptions' }} > - {subscriptions.slice(0, viewAll ? undefined : 4).map((item) => { + + + {(subscriptions ?? []).slice(0, viewAll ? undefined : 4).map((item) => { return ( {props.title}