use new react-query for addurl
This commit is contained in:
@ -11,20 +11,21 @@ import { setupAnalytics } from '../../lib/analytics'
|
||||
import { primaryCommands } from '../../lib/keyboardShortcuts/navigationShortcuts'
|
||||
import { logout } from '../../lib/logout'
|
||||
import { useApplyLocalTheme } from '../../lib/hooks/useApplyLocalTheme'
|
||||
import { updateTheme } from '../../lib/themeUpdater'
|
||||
import { Priority, useRegisterActions } from 'kbar'
|
||||
import { ThemeId, theme } from '../tokens/stitches.config'
|
||||
import { useRegisterActions } from 'kbar'
|
||||
import { theme } from '../tokens/stitches.config'
|
||||
import { NavigationMenu } from './navMenu/NavigationMenu'
|
||||
import { Button } from '../elements/Button'
|
||||
import { List } from '@phosphor-icons/react'
|
||||
import { LIBRARY_LEFT_MENU_WIDTH } from './navMenu/LibraryLegacyMenu'
|
||||
import { AddLinkModal } from './AddLinkModal'
|
||||
import { saveUrlMutation } from '../../lib/networking/mutations/saveUrlMutation'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import {
|
||||
showErrorToast,
|
||||
showSuccessToastWithAction,
|
||||
} from '../../lib/toastHelpers'
|
||||
import useWindowDimensions from '../../lib/hooks/useGetWindowDimensions'
|
||||
import { useAddItem } from '../../lib/networking/library_items/useLibraryItems'
|
||||
import { useHandleAddUrl } from '../../lib/hooks/useHandleAddUrl'
|
||||
|
||||
export type NavigationSection =
|
||||
| 'home'
|
||||
@ -52,6 +53,7 @@ export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
|
||||
const [showLogoutConfirmation, setShowLogoutConfirmation] = useState(false)
|
||||
const [showKeyboardCommandsModal, setShowKeyboardCommandsModal] =
|
||||
useState(false)
|
||||
const addItem = useAddItem()
|
||||
|
||||
useRegisterActions(navigationCommands(router))
|
||||
|
||||
@ -84,22 +86,7 @@ export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
|
||||
|
||||
const [showAddLinkModal, setShowAddLinkModal] = useState(false)
|
||||
|
||||
const handleLinkAdded = useCallback(
|
||||
async (link: string, timezone: string, locale: string) => {
|
||||
const result = await saveUrlMutation(link, timezone, locale)
|
||||
if (result) {
|
||||
showSuccessToastWithAction('Link saved', 'Read now', async () => {
|
||||
window.location.href = `/article?url=${encodeURIComponent(link)}`
|
||||
return Promise.resolve()
|
||||
})
|
||||
// const id = result.url?.match(/[^/]+$/)?.[0] ?? ''
|
||||
// performActionOnItem('refresh', undefined as unknown as any)
|
||||
} else {
|
||||
showErrorToast('Error saving link', { position: 'bottom-right' })
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
const handleLinkAdded = useHandleAddUrl()
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('logout', showLogout)
|
||||
|
||||
@ -58,6 +58,7 @@ import { TrashIcon } from '../../elements/icons/TrashIcon'
|
||||
import { theme } from '../../tokens/stitches.config'
|
||||
import { emptyTrashMutation } from '../../../lib/networking/mutations/emptyTrashMutation'
|
||||
import { State } from '../../../lib/networking/fragments/articleFragment'
|
||||
import { useHandleAddUrl } from '../../../lib/hooks/useHandleAddUrl'
|
||||
|
||||
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
|
||||
|
||||
@ -851,24 +852,6 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
[itemsPages, multiSelectMode, checkedItems]
|
||||
)
|
||||
|
||||
const handleLinkSubmission = async (
|
||||
link: string,
|
||||
timezone: string,
|
||||
locale: string
|
||||
) => {
|
||||
const result = await saveUrlMutation(link, timezone, locale)
|
||||
if (result) {
|
||||
showSuccessToastWithAction('Link saved', 'Read now', async () => {
|
||||
window.location.href = `/article?url=${encodeURIComponent(link)}`
|
||||
return Promise.resolve()
|
||||
})
|
||||
const id = result.url?.match(/[^/]+$/)?.[0] ?? ''
|
||||
// performActionOnItem('refresh', undefined as unknown as any)
|
||||
} else {
|
||||
showErrorToast('Error saving link', { position: 'bottom-right' })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<HomeFeedGrid
|
||||
folder={props.folder}
|
||||
@ -882,7 +865,6 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
performMultiSelectAction={performMultiSelectAction}
|
||||
searchTerm={queryInputs.searchQuery}
|
||||
gridContainerRef={gridContainerRef}
|
||||
handleLinkSubmission={handleLinkSubmission}
|
||||
applySearchQuery={(searchQuery: string) => {
|
||||
setQueryInputs({
|
||||
...queryInputs,
|
||||
@ -959,12 +941,6 @@ export type HomeFeedContentProps = {
|
||||
item: LibraryItem | undefined
|
||||
) => Promise<void>
|
||||
|
||||
handleLinkSubmission: (
|
||||
link: string,
|
||||
timezone: string,
|
||||
locale: string
|
||||
) => Promise<void>
|
||||
|
||||
showNavigationMenu: boolean
|
||||
|
||||
setIsChecked: (itemId: string, set: boolean) => void
|
||||
@ -1003,6 +979,8 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
|
||||
return true
|
||||
}, [props])
|
||||
|
||||
const addUrl = useHandleAddUrl()
|
||||
|
||||
return (
|
||||
<VStack
|
||||
css={{
|
||||
@ -1055,7 +1033,7 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
|
||||
|
||||
{props.showAddLinkModal && (
|
||||
<AddLinkModal
|
||||
handleLinkSubmission={props.handleLinkSubmission}
|
||||
handleLinkSubmission={addUrl}
|
||||
onOpenChange={() => props.setShowAddLinkModal(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
26
packages/web/lib/hooks/useHandleAddUrl.ts
Normal file
26
packages/web/lib/hooks/useHandleAddUrl.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { useCallback } from 'react'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useAddItem } from '../networking/library_items/useLibraryItems'
|
||||
import { showErrorToast, showSuccessToastWithAction } from '../toastHelpers'
|
||||
|
||||
export const useHandleAddUrl = () => {
|
||||
const addItem = useAddItem()
|
||||
return useCallback(async (url: string, timezone: string, locale: string) => {
|
||||
const itemId = uuidv4()
|
||||
const result = await addItem.mutateAsync({
|
||||
itemId,
|
||||
url,
|
||||
timezone,
|
||||
locale,
|
||||
})
|
||||
console.log('result: ', result)
|
||||
if (result) {
|
||||
showSuccessToastWithAction('Item saving', 'Read now', async () => {
|
||||
window.location.href = `/article?url=${encodeURIComponent(url)}`
|
||||
return Promise.resolve()
|
||||
})
|
||||
} else {
|
||||
showErrorToast('Error saving url', { position: 'bottom-right' })
|
||||
}
|
||||
}, [])
|
||||
}
|
||||
@ -258,3 +258,18 @@ export const GQL_BULK_ACTION = gql`
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const GQL_SAVE_URL = gql`
|
||||
mutation SaveUrl($input: SaveUrlInput!) {
|
||||
saveUrl(input: $input) {
|
||||
... on SaveSuccess {
|
||||
url
|
||||
clientRequestId
|
||||
}
|
||||
... on SaveError {
|
||||
errorCodes
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { gql, GraphQLClient } from 'graphql-request'
|
||||
import { GraphQLClient } from 'graphql-request'
|
||||
import {
|
||||
InfiniteData,
|
||||
QueryClient,
|
||||
useInfiniteQuery,
|
||||
useMutation,
|
||||
@ -8,8 +7,8 @@ import {
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
import { ContentReader, PageType, State } from '../fragments/articleFragment'
|
||||
import { Highlight, highlightFragment } from '../fragments/highlightFragment'
|
||||
import { makeGqlFetcher, requestHeaders } from '../networkHelpers'
|
||||
import { Highlight } from '../fragments/highlightFragment'
|
||||
import { requestHeaders } from '../networkHelpers'
|
||||
import { Label } from '../fragments/labelFragment'
|
||||
import {
|
||||
GQL_BULK_ACTION,
|
||||
@ -17,6 +16,7 @@ import {
|
||||
GQL_GET_LIBRARY_ITEM_CONTENT,
|
||||
GQL_MOVE_ITEM_TO_FOLDER,
|
||||
GQL_SAVE_ARTICLE_READING_PROGRESS,
|
||||
GQL_SAVE_URL,
|
||||
GQL_SEARCH_QUERY,
|
||||
GQL_SET_LABELS,
|
||||
GQL_SET_LINK_ARCHIVED,
|
||||
@ -165,12 +165,55 @@ const overwriteItemPropertiesInCache = (
|
||||
}
|
||||
}
|
||||
|
||||
export const insertItemInCache = (
|
||||
queryClient: QueryClient,
|
||||
itemId: string,
|
||||
url: string
|
||||
) => {
|
||||
const keys = queryClient
|
||||
.getQueryCache()
|
||||
.findAll({ queryKey: ['libraryItems'] })
|
||||
console.log('keys: ', keys)
|
||||
|
||||
keys.forEach((query) => {
|
||||
queryClient.setQueryData(query.queryKey, (data: any) => {
|
||||
console.log('data, data.pages', data)
|
||||
if (!data) return data
|
||||
if (data.pages.length > 0) {
|
||||
const firstPage = data.pages[0] as LibraryItems
|
||||
firstPage.edges = [
|
||||
...firstPage.edges,
|
||||
{
|
||||
cursor: firstPage.pageInfo.endCursor,
|
||||
node: {
|
||||
id: itemId,
|
||||
title: url,
|
||||
url: url,
|
||||
originalArticleUrl: url,
|
||||
readingProgressPercent: 0,
|
||||
readingProgressAnchorIndex: 0,
|
||||
slug: url,
|
||||
folder: 'inbox',
|
||||
ownedByViewer: true,
|
||||
state: State.PROCESSING,
|
||||
pageType: PageType.UNKNOWN,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
},
|
||||
]
|
||||
data.pages[0] = firstPage
|
||||
console.log('data: ', data)
|
||||
return data
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function useGetLibraryItems(
|
||||
folder: string | undefined,
|
||||
{ limit, searchQuery }: LibraryItemsQueryInput,
|
||||
enabled = true
|
||||
) {
|
||||
console.log('folder: ', folder)
|
||||
const fullQuery = folder
|
||||
? (`in:${folder} use:folders ` + (searchQuery ?? '')).trim()
|
||||
: searchQuery ?? ''
|
||||
@ -623,6 +666,56 @@ export const useSetItemLabels = () => {
|
||||
})
|
||||
}
|
||||
|
||||
export const useAddItem = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const addItem = async (variables: {
|
||||
itemId: string
|
||||
url: string
|
||||
timezone: string | undefined
|
||||
locale: string | undefined
|
||||
}) => {
|
||||
const result = (await gqlFetcher(GQL_SAVE_URL, {
|
||||
input: {
|
||||
clientRequestId: variables.itemId,
|
||||
url: variables.url,
|
||||
source: 'add-link',
|
||||
timezone: variables.timezone,
|
||||
locale: variables.locale,
|
||||
},
|
||||
})) as SaveUrlData
|
||||
if (result.saveUrl?.errorCodes?.length) {
|
||||
throw new Error(result.saveUrl.errorCodes[0])
|
||||
}
|
||||
return result.saveUrl?.clientRequestId
|
||||
}
|
||||
return useMutation({
|
||||
mutationFn: addItem,
|
||||
onMutate: async (variables: {
|
||||
itemId: string
|
||||
url: string
|
||||
timezone: string | undefined
|
||||
locale: string | undefined
|
||||
}) => {
|
||||
await queryClient.cancelQueries({ queryKey: ['libraryItems'] })
|
||||
const previousState = {
|
||||
previousItems: queryClient.getQueryData(['libraryItems']),
|
||||
}
|
||||
insertItemInCache(queryClient, variables.itemId, variables.url)
|
||||
return previousState
|
||||
},
|
||||
onError: (error, variables, context) => {
|
||||
if (context?.previousItems) {
|
||||
queryClient.setQueryData(['libraryItems'], context.previousItems)
|
||||
}
|
||||
},
|
||||
onSettled: async () => {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['libraryItems'],
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useBulkActions = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const bulkAction = async (variables: {
|
||||
@ -675,6 +768,18 @@ type BulkActionData = {
|
||||
bulkAction: BulkActionResult
|
||||
}
|
||||
|
||||
export type SaveUrlResult = {
|
||||
id?: string
|
||||
url?: string
|
||||
slug?: string
|
||||
clientRequestId?: string
|
||||
errorCodes?: string[]
|
||||
}
|
||||
|
||||
export type SaveUrlData = {
|
||||
saveUrl?: SaveUrlResult
|
||||
}
|
||||
|
||||
type UpdateLibraryItemInput = {
|
||||
pageId: string
|
||||
title?: string
|
||||
@ -811,16 +916,16 @@ export type LibraryItemNode = {
|
||||
readingProgressAnchorIndex: number
|
||||
slug: string
|
||||
folder?: string
|
||||
description: string
|
||||
ownedByViewer: boolean
|
||||
uploadFileId: string
|
||||
labels?: Label[]
|
||||
pageId: string
|
||||
shortId: string
|
||||
quote: string
|
||||
annotation: string
|
||||
state: State
|
||||
pageType: PageType
|
||||
description?: string
|
||||
ownedByViewer: boolean
|
||||
uploadFileId?: string
|
||||
labels?: Label[]
|
||||
pageId?: string
|
||||
shortId?: string
|
||||
quote?: string
|
||||
annotation?: string
|
||||
siteName?: string
|
||||
siteIcon?: string
|
||||
subscription?: string
|
||||
|
||||
Reference in New Issue
Block a user