Better handling of slugs and library item lists in the cache

This commit is contained in:
Jackson Harper 2024-07-30 15:48:21 +08:00
parent 17e547b95e
commit 6c6cc8d4c4
20 changed files with 538 additions and 391 deletions

View file

@ -31,6 +31,7 @@ import { highlightColor } from '../../lib/themeUpdater'
import { HighlightViewNote } from '../patterns/HighlightNotes'
import { theme } from '../tokens/stitches.config'
import { useDeleteHighlight } from '../../lib/networking/highlights/useItemHighlights'
const PAGE_SIZE = 10
@ -131,8 +132,10 @@ function HighlightCard(props: HighlightCardProps): JSX.Element {
const [isOpen, setIsOpen] = useState(false)
const [showConfirmDeleteHighlightId, setShowConfirmDeleteHighlightId] =
useState<undefined | string>(undefined)
const [labelsTarget, setLabelsTarget] =
useState<Highlight | undefined>(undefined)
const [labelsTarget, setLabelsTarget] = useState<Highlight | undefined>(
undefined
)
const deleteHighlight = useDeleteHighlight()
const viewInReader = useCallback(
(highlightId: string) => {
@ -283,24 +286,22 @@ function HighlightCard(props: HighlightCardProps): JSX.Element {
message={'Are you sure you want to delete this highlight?'}
onAccept={() => {
;(async () => {
const highlightId = showConfirmDeleteHighlightId
const success = await deleteHighlightMutation(
props.highlight.libraryItem?.id || '',
showConfirmDeleteHighlightId
)
props.mutate()
if (success) {
showSuccessToast('Highlight deleted.', {
position: 'bottom-right',
})
const event = new CustomEvent('deleteHighlightbyId', {
detail: highlightId,
})
document.dispatchEvent(event)
} else {
showErrorToast('Error deleting highlight', {
position: 'bottom-right',
if (props.highlight.libraryItem) {
const success = await deleteHighlight.mutateAsync({
itemId: props.highlight.libraryItem?.id,
slug: props.highlight.libraryItem?.slug,
highlightId: showConfirmDeleteHighlightId,
})
if (success) {
showSuccessToast('Highlight deleted.', {
position: 'bottom-right',
})
} else {
showErrorToast('Error deleting highlight', {
position: 'bottom-right',
})
}
}
})()
setShowConfirmDeleteHighlightId(undefined)

View file

@ -950,12 +950,12 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
useLibraryItemActions()
const doArchiveItem = useCallback(
async (libraryItemId: string) => {
async (libraryItemId: string, slug: string) => {
dispatch({
type: 'REMOVE_ITEM',
payload: libraryItemId,
})
if (!(await archiveItem(libraryItemId))) {
if (!(await archiveItem(libraryItemId, slug))) {
// dispatch({
// type: 'REPLACE_ITEM',
// itemId: libraryItemId,
@ -966,7 +966,7 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
)
const doDeleteItem = useCallback(
async (libraryItemId: string) => {
async (libraryItemId: string, slug: string) => {
dispatch({
type: 'REMOVE_ITEM',
payload: libraryItemId,
@ -977,7 +977,7 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
// : libraryItemId,
// })
}
if (!(await deleteItem(libraryItemId, undo))) {
if (!(await deleteItem(libraryItemId, slug, undo))) {
// dispatch({
// type: 'REPLACE_ITEM',
// payload: libraryItemId,
@ -988,12 +988,12 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
)
const doMoveItem = useCallback(
async (libraryItemId: string) => {
async (libraryItemId: string, slug: string) => {
dispatch({
type: 'REMOVE_ITEM',
payload: libraryItemId,
})
if (!(await moveItem(libraryItemId))) {
if (!(await moveItem(libraryItemId, slug))) {
// dispatch({
// type: 'REPLACE_ITEM',
// payload: libraryItemId,
@ -1043,13 +1043,13 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
;(event.target as HTMLElement).click()
break
case 'e':
doArchiveItem(props.homeItem.id)
doArchiveItem(props.homeItem.id, props.homeItem.slug)
break
case '#':
doDeleteItem(props.homeItem.id)
doDeleteItem(props.homeItem.id, props.homeItem.slug)
break
case 'm':
doMoveItem(props.homeItem.id)
doMoveItem(props.homeItem.id, props.homeItem.slug)
break
case 'o':
window.open(props.homeItem.url, '_blank')
@ -1097,8 +1097,7 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
onClick={async (event) => {
event.preventDefault()
event.stopPropagation()
await doMoveItem(props.homeItem.id)
await doMoveItem(props.homeItem.id, props.homeItem.slug)
}}
>
<AddToLibraryActionIcon />
@ -1111,8 +1110,7 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
onClick={async (event) => {
event.preventDefault()
event.stopPropagation()
await doArchiveItem(props.homeItem.id)
await doArchiveItem(props.homeItem.id, props.homeItem.slug)
}}
>
<ArchiveActionIcon />
@ -1125,8 +1123,7 @@ const TopPicksItemView = (props: HomeItemViewProps): JSX.Element => {
onClick={async (event) => {
event.preventDefault()
event.stopPropagation()
await doDeleteItem(props.homeItem.id)
await doDeleteItem(props.homeItem.id, props.homeItem.slug)
}}
>
<RemoveActionIcon />

View file

@ -69,9 +69,13 @@ export function CardMenu(props: CardMenuProps): JSX.Element {
<DropdownOption
onSelect={async () => {
await updateItemReadStatus.mutateAsync({
id: props.item.id,
readingProgressPercent: 100,
force: true,
itemId: props.item.id,
slug: props.item.slug,
input: {
id: props.item.id,
readingProgressPercent: 100,
force: true,
},
})
}}
title="Mark read"
@ -80,9 +84,13 @@ export function CardMenu(props: CardMenuProps): JSX.Element {
<DropdownOption
onSelect={async () => {
await updateItemReadStatus.mutateAsync({
id: props.item.id,
readingProgressPercent: 0,
force: true,
itemId: props.item.id,
slug: props.item.slug,
input: {
id: props.item.id,
readingProgressPercent: 0,
force: true,
},
})
}}
title="Mark unread"

View file

@ -107,8 +107,12 @@ export const LibraryHoverActions = (props: LibraryHoverActionsProps) => {
style="hoverActionIcon"
onClick={async (event) => {
await archiveItem.mutateAsync({
linkId: props.item.id,
archived: props.item.state !== State.ARCHIVED,
itemId: props.item.id,
slug: props.item.slug,
input: {
linkId: props.item.id,
archived: props.item.state !== State.ARCHIVED,
},
})
event.preventDefault()
event.stopPropagation()
@ -132,9 +136,14 @@ export const LibraryHoverActions = (props: LibraryHoverActionsProps) => {
style="hoverActionIcon"
onClick={async (event) => {
if (props.item.state == State.DELETED) {
await restoreItem.mutateAsync(props.item.id)
} else {
await deleteItem.mutateAsync(props.item.id)
await restoreItem.mutateAsync({
itemId: props.item.id,
slug: props.item.slug,
})
await deleteItem.mutateAsync({
itemId: props.item.id,
slug: props.item.slug,
})
}
event.preventDefault()
event.stopPropagation()

View file

@ -523,9 +523,6 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
item={props.article}
scrollToHighlight={highlightHref}
highlights={props.article.highlights}
articleTitle={title}
articleAuthor={props.article.author ?? ''}
articleId={props.article.id}
isAppleAppEmbed={props.isAppleAppEmbed}
highlightBarDisabled={props.highlightBarDisabled}
showHighlightsModal={props.showHighlightsModal}

View file

@ -11,9 +11,6 @@ import {
import PSPDFKit from 'pspdfkit'
import { Instance, HighlightAnnotation, List, Annotation, Rect } from 'pspdfkit'
import type { Highlight } from '../../../lib/networking/fragments/highlightFragment'
import { createHighlightMutation } from '../../../lib/networking/mutations/createHighlightMutation'
import { deleteHighlightMutation } from '../../../lib/networking/mutations/deleteHighlightMutation'
import { mergeHighlightMutation } from '../../../lib/networking/mutations/mergeHighlightMutation'
import { useCanShareNative } from '../../../lib/hooks/useCanShareNative'
import { pspdfKitKey } from '../../../lib/appConfig'
import { NotebookModal } from './NotebookModal'
@ -310,56 +307,6 @@ export default function EpubContainer(props: EpubContainerProps): JSX.Element {
{/* EPUB CONTAINER
<div ></div> */}
</Box>
{noteTarget && (
<HighlightNoteModal
highlight={noteTarget}
libraryItemId={props.article.id}
author={props.article.author ?? ''}
title={props.article.title}
onUpdate={(highlight: Highlight) => {
const savedHighlight = highlightsRef.current.find(
(other: Highlight) => {
return other.id == highlight.id
}
)
if (savedHighlight) {
savedHighlight.annotation = highlight.annotation
}
}}
onOpenChange={() => {
setNoteTarget(undefined)
}}
/>
)}
{props.showHighlightsModal && (
<NotebookModal
key={notebookKey}
viewer={props.viewer}
item={props.article}
onClose={(updatedHighlights, deletedAnnotations) => {
console.log(
'closed PDF notebook: ',
updatedHighlights,
deletedAnnotations
)
deletedAnnotations.forEach((highlight) => {
const event = new CustomEvent('deleteHighlightbyId', {
detail: highlight.id,
})
document.dispatchEvent(event)
})
props.setShowHighlightsModal(false)
}}
viewHighlightInReader={(highlightId) => {
const event = new CustomEvent('scrollToHighlightId', {
detail: highlightId,
})
document.dispatchEvent(event)
props.setShowHighlightsModal(false)
}}
/>
)}
</Box>
)
}

View file

@ -13,10 +13,9 @@ import { showErrorToast } from '../../../lib/toastHelpers'
import { useUpdateHighlight } from '../../../lib/networking/highlights/useItemHighlights'
type HighlightNoteModalProps = {
author: string
title: string
highlight?: Highlight
libraryItemId: string
libraryItemSlug: string
onUpdate: (updatedHighlight: Highlight) => void
onOpenChange: (open: boolean) => void
createHighlightForNote?: (note?: string) => Promise<Highlight | undefined>
@ -43,6 +42,7 @@ export function HighlightNoteModal(
try {
const result = await updateHighlight.mutateAsync({
itemId: props.libraryItemId,
slug: props.libraryItemSlug,
input: {
libraryItemId: props.libraryItemId,
highlightId: props.highlight?.id,

View file

@ -39,9 +39,6 @@ type HighlightsLayerProps = {
item: ReadableItem
highlights: Highlight[]
articleId: string
articleTitle: string
articleAuthor: string
isAppleAppEmbed: boolean
highlightBarDisabled: boolean
showHighlightsModal: boolean
@ -105,7 +102,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
const result = await createHighlight(
{
selection: selection,
articleId: props.articleId,
articleId: props.item.id,
existingHighlights: highlights,
color: options?.color,
highlightStartEndOffsets: highlightLocations,
@ -141,7 +138,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
[
highlightLocations,
highlights,
props.articleId,
props.item.id,
props.articleMutations,
setSelectionData,
]
@ -189,7 +186,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
const didDeleteHighlight =
await props.articleMutations.deleteHighlightMutation(
props.articleId,
props.item.id,
highlightId
)
@ -226,7 +223,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
updateHighlightsCallback(highlight)
;(async () => {
const update = await props.articleMutations.updateHighlightMutation({
libraryItemId: props.articleId,
libraryItemId: props.item.id,
highlightId: highlight.id,
color: color,
})
@ -718,7 +715,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
const annotation = event.annotation ?? ''
const result = await props.articleMutations.updateHighlightMutation({
libraryItemId: props.articleId,
libraryItemId: props.item.id,
highlightId: focusedHighlight.id,
annotation: event.annotation ?? '',
})
@ -800,9 +797,8 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
{highlightModalAction?.highlightModalAction == 'addComment' && (
<HighlightNoteModal
highlight={highlightModalAction.highlight}
author={props.articleAuthor}
title={props.articleTitle}
libraryItemId={props.articleId}
libraryItemId={props.item.id}
libraryItemSlug={props.item.slug}
onUpdate={updateHighlightsCallback}
onOpenChange={() =>
setHighlightModalAction({ highlightModalAction: 'none' })

View file

@ -5,10 +5,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { updateHighlightMutation } from '../../../lib/networking/mutations/updateHighlightMutation'
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
import 'react-markdown-editor-lite/lib/index.css'
import { createHighlightMutation } from '../../../lib/networking/mutations/createHighlightMutation'
import { v4 as uuidv4 } from 'uuid'
import { nanoid } from 'nanoid'
import { deleteHighlightMutation } from '../../../lib/networking/mutations/deleteHighlightMutation'
import { HighlightViewItem } from './HighlightViewItem'
import { ConfirmationModal } from '../../patterns/ConfirmationModal'
import { TrashIcon } from '../../elements/icons/TrashIcon'
@ -20,6 +18,11 @@ import { formattedShortTime } from '../../../lib/dateFormatting'
import { isDarkTheme } from '../../../lib/themeUpdater'
import { sortHighlights } from '../../../lib/highlights/sortHighlights'
import { useGetLibraryItemContent } from '../../../lib/networking/library_items/useLibraryItems'
import {
useCreateHighlight,
useDeleteHighlight,
useUpdateHighlight,
} from '../../../lib/networking/highlights/useItemHighlights'
type NotebookContentProps = {
viewer: UserBasicData
@ -42,6 +45,9 @@ type NoteState = {
export function NotebookContent(props: NotebookContentProps): JSX.Element {
const isDark = isDarkTheme()
const createHighlight = useCreateHighlight()
const deleteHighlight = useDeleteHighlight()
const updateHighlight = useUpdateHighlight()
const { data: article } = useGetLibraryItemContent(
props.viewer.profile.username as string,
@ -87,12 +93,16 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
noteState.current.createStarted = new Date()
;(async () => {
try {
const success = await createHighlightMutation({
id: newNoteId,
shortId: nanoid(8),
type: 'NOTE',
articleId: props.item.id,
annotation: text,
const success = await createHighlight.mutateAsync({
itemId: props.item.id,
slug: props.item.slug,
input: {
id: newNoteId,
shortId: nanoid(8),
type: 'NOTE',
articleId: props.item.id,
annotation: text,
},
})
if (success) {
noteState.current.note = success
@ -164,7 +174,11 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
highlights
?.filter((h) => h.type === 'NOTE')
.forEach(async (h) => {
const result = await deleteHighlightMutation(props.item.id, h.id)
const result = await deleteHighlight.mutateAsync({
itemId: props.item.id,
slug: props.item.slug,
highlightId: h.id,
})
if (!result) {
showErrorToast('Error deleting note')
}
@ -284,10 +298,11 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
onAccept={() => {
;(async () => {
const highlightId = showConfirmDeleteHighlightId
const success = await deleteHighlightMutation(
props.item.id,
showConfirmDeleteHighlightId
)
const success = await deleteHighlight.mutateAsync({
itemId: props.item.id,
slug: props.item.slug,
highlightId: showConfirmDeleteHighlightId,
})
if (success) {
showSuccessToast('Highlight deleted.', {
position: 'bottom-right',

View file

@ -10,9 +10,6 @@ import { isDarkTheme } from '../../../lib/themeUpdater'
import PSPDFKit from 'pspdfkit'
import { Instance, HighlightAnnotation, List, Annotation, Rect } from 'pspdfkit'
import type { Highlight } from '../../../lib/networking/fragments/highlightFragment'
import { createHighlightMutation } from '../../../lib/networking/mutations/createHighlightMutation'
import { deleteHighlightMutation } from '../../../lib/networking/mutations/deleteHighlightMutation'
import { mergeHighlightMutation } from '../../../lib/networking/mutations/mergeHighlightMutation'
import { pspdfKitKey } from '../../../lib/appConfig'
import { HighlightNoteModal } from './HighlightNoteModal'
import { showErrorToast } from '../../../lib/toastHelpers'
@ -24,6 +21,12 @@ import { NotebookHeader } from './NotebookHeader'
import useWindowDimensions from '../../../lib/hooks/useGetWindowDimensions'
import { ResizableSidebar } from './ResizableSidebar'
import { DEFAULT_HOME_PATH } from '../../../lib/navigations'
import {
useCreateHighlight,
useDeleteHighlight,
useMergeHighlight,
useUpdateHighlight,
} from '../../../lib/networking/highlights/useItemHighlights'
export type PdfArticleContainerProps = {
viewer: UserBasicData
@ -42,6 +45,10 @@ export default function PdfArticleContainer(
number | undefined
>(undefined)
const highlightsRef = useRef<Highlight[]>([])
const createHighlight = useCreateHighlight()
const deleteHighlight = useDeleteHighlight()
const mergeHighlight = useMergeHighlight()
const updateHighlight = useUpdateHighlight()
const updateItemReadStatus = useUpdateItemReadStatus()
const annotationOmnivoreId = (annotation: Annotation): string | undefined => {
@ -117,7 +124,11 @@ export default function PdfArticleContainer(
.delete(annotation)
.then(() => {
if (annotationId) {
return deleteHighlightMutation(props.article.id, annotationId)
return deleteHighlight.mutateAsync({
itemId: props.article.id,
slug: props.article.slug,
highlightId: annotationId,
})
}
})
.then(() => {
@ -218,8 +229,6 @@ export default function PdfArticleContainer(
}),
}
console.log('instnace config: ', config)
instance = await PSPDFKit.load(config)
console.log('created PDF instance', instance)
@ -233,7 +242,11 @@ export default function PdfArticleContainer(
}
const annotationId = annotationOmnivoreId(annotation)
if (annotationId) {
await deleteHighlightMutation(props.article.id, annotationId)
await deleteHighlight.mutateAsync({
itemId: props.article.id,
slug: props.article.slug,
highlightId: annotationId,
})
}
})
@ -343,16 +356,21 @@ export default function PdfArticleContainer(
if (overlapping.size === 0) {
const positionPercent = positionPercentForAnnotation(annotation)
const result = await createHighlightMutation({
id: id,
shortId: shortId,
quote: quote,
articleId: props.article.id,
prefix: surroundingText.prefix,
suffix: surroundingText.suffix,
patch: JSON.stringify(serialized),
highlightPositionPercent: positionPercent * 100,
highlightPositionAnchorIndex: annotation.pageIndex,
const result = await createHighlight.mutateAsync({
itemId: props.article.id,
slug: props.article.slug,
input: {
id: id,
shortId: shortId,
quote: quote,
articleId: props.article.id,
prefix: surroundingText.prefix,
suffix: surroundingText.suffix,
patch: JSON.stringify(serialized),
highlightPositionPercent: positionPercent * 100,
highlightPositionAnchorIndex: annotation.pageIndex,
},
})
if (result) {
highlightsRef.current.push(result)
@ -388,20 +406,24 @@ export default function PdfArticleContainer(
(ha) => (ha.customData?.omnivoreHighlight as Highlight).id
)
const positionPercent = positionPercentForAnnotation(annotation)
const result = await mergeHighlightMutation({
quote,
id,
shortId,
patch: JSON.stringify(serialized),
prefix: surroundingText.prefix,
suffix: surroundingText.suffix,
articleId: props.article.id,
overlapHighlightIdList: mergedIds.toArray(),
highlightPositionPercent: positionPercent * 100,
highlightPositionAnchorIndex: annotation.pageIndex,
const result = await mergeHighlight.mutateAsync({
itemId: props.article.id,
slug: props.article.slug,
input: {
quote,
id,
shortId,
patch: JSON.stringify(serialized),
prefix: surroundingText.prefix,
suffix: surroundingText.suffix,
articleId: props.article.id,
overlapHighlightIdList: mergedIds.toArray(),
highlightPositionPercent: positionPercent * 100,
highlightPositionAnchorIndex: annotation.pageIndex,
},
})
if (result) {
highlightsRef.current.push(result)
if (result && result.highlight) {
highlightsRef.current.push(result.highlight)
}
}
}
@ -415,10 +437,14 @@ export default function PdfArticleContainer(
Math.max(0, ((pageIndex + 1) / instance.totalPageCount) * 100)
)
await updateItemReadStatus.mutateAsync({
id: props.article.id,
force: true,
readingProgressPercent: percent,
readingProgressAnchorIndex: pageIndex,
itemId: props.article.id,
slug: props.article.slug,
input: {
id: props.article.id,
force: true,
readingProgressPercent: percent,
readingProgressAnchorIndex: pageIndex,
},
})
}
)
@ -521,7 +547,11 @@ export default function PdfArticleContainer(
const storedId = annotationOmnivoreId(annotation)
if (storedId == annotationId) {
await instance.delete(annotation)
await deleteHighlightMutation(props.article.id, annotationId)
await deleteHighlight.mutateAsync({
itemId: props.article.id,
slug: props.article.slug,
highlightId: annotationId,
})
const highlightIdx = highlightsRef.current.findIndex((value) => {
return value.id == annotationId
@ -586,8 +616,7 @@ export default function PdfArticleContainer(
<HighlightNoteModal
highlight={noteTarget}
libraryItemId={props.article.id}
author={props.article.author ?? ''}
title={props.article.title}
libraryItemSlug={props.article.slug}
onUpdate={(highlight: Highlight) => {
const savedHighlight = highlightsRef.current.find(
(other: Highlight) => {

View file

@ -4,21 +4,24 @@ import { LabelsProvider } from './SetLabelsControl'
import { SetLabelsModal } from './SetLabelsModal'
import { useSetHighlightLabels } from '../../../lib/hooks/useSetHighlightLabels'
import { Highlight } from '../../../lib/networking/fragments/highlightFragment'
import { LibraryItemNode } from '../../../lib/networking/library_items/useLibraryItems'
type SetPageLabelsModalPresenterProps = {
articleId: string
article: LabelsProvider
libraryItem: LibraryItemNode
onOpenChange: (open: boolean) => void
}
export function SetPageLabelsModalPresenter(
props: SetPageLabelsModalPresenterProps
): JSX.Element {
const [labels, dispatchLabels] = useSetPageLabels(props.articleId)
const [labels, dispatchLabels] = useSetPageLabels(
props.libraryItem.id,
props.libraryItem.slug
)
const onOpenChange = useCallback(() => {
if (props.article) {
props.article.labels = labels.labels
if (props.libraryItem) {
props.libraryItem.labels = labels.labels
}
props.onOpenChange(true)
}, [props, labels])
@ -26,13 +29,13 @@ export function SetPageLabelsModalPresenter(
useEffect(() => {
dispatchLabels({
type: 'RESET',
labels: props.article.labels ?? [],
labels: props.libraryItem.labels ?? [],
})
}, [props.article, dispatchLabels])
}, [props.libraryItem, dispatchLabels])
return (
<SetLabelsModal
provider={props.article}
provider={props.libraryItem}
selectedLabels={labels.labels}
dispatchLabels={dispatchLabels}
onOpenChange={onOpenChange}

View file

@ -1,7 +1,10 @@
import dayjs, { Dayjs } from 'dayjs'
import { useCallback, useState } from 'react'
import { updatePageMutation } from '../../../lib/networking/mutations/updatePageMutation'
import { ArticleAttributes } from '../../../lib/networking/library_items/useLibraryItems'
import {
ArticleAttributes,
useUpdateItem,
} from '../../../lib/networking/library_items/useLibraryItems'
import { LibraryItem } from '../../../lib/networking/library_items/useLibraryItems'
import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers'
import { CloseButton } from '../../elements/CloseButton'
@ -24,6 +27,7 @@ type EditLibraryItemModalProps = {
export function EditLibraryItemModal(
props: EditLibraryItemModalProps
): JSX.Element {
const updateItem = useUpdateItem()
const onSave = useCallback(
(
title: string,
@ -34,13 +38,17 @@ export function EditLibraryItemModal(
) => {
;(async () => {
if (title !== '') {
const res = await updatePageMutation({
pageId: props.item.node.id,
title,
description,
byline: author,
savedAt: savedAt.toISOString(),
publishedAt: publishedAt ? publishedAt.toISOString() : undefined,
const res = await updateItem.mutateAsync({
itemId: props.item.node.id,
slug: props.item.node.slug,
input: {
pageId: props.item.node.id,
title,
description,
byline: author,
savedAt: savedAt.toISOString(),
publishedAt: publishedAt ? publishedAt.toISOString() : undefined,
},
})
if (res) {
@ -102,6 +110,7 @@ type EditArticleModalProps = {
}
export function EditArticleModal(props: EditArticleModalProps): JSX.Element {
const updateItem = useUpdateItem()
const onSave = useCallback(
(
title: string,
@ -112,13 +121,17 @@ export function EditArticleModal(props: EditArticleModalProps): JSX.Element {
) => {
;(async () => {
if (title !== '') {
const res = await updatePageMutation({
pageId: props.article.id,
title,
description,
byline: author,
savedAt: savedAt.toISOString(),
publishedAt: publishedAt ? publishedAt.toISOString() : undefined,
const res = await updateItem.mutateAsync({
itemId: props.article.id,
slug: props.article.slug,
input: {
pageId: props.article.id,
title,
description,
byline: author,
savedAt: savedAt.toISOString(),
publishedAt: publishedAt ? publishedAt.toISOString() : undefined,
},
})
if (res) {
props.updateArticle(

View file

@ -398,8 +398,12 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
case 'unarchive':
try {
await archiveItem.mutateAsync({
linkId: item.node.id,
archived: action == 'archive',
itemId: item.node.id,
slug: item.node.slug,
input: {
linkId: item.node.id,
archived: action == 'archive',
},
})
} catch (err) {
console.log('Error setting archive state: ', err)
@ -414,7 +418,10 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
break
case 'delete':
try {
await deleteItem.mutateAsync(item.node.id)
await deleteItem.mutateAsync({
itemId: item.node.id,
slug: item.node.slug,
})
} catch (err) {
console.log('Error deleting item: ', err)
showErrorToast(`Error deleting item`, {
@ -443,9 +450,13 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
}
try {
await updateItemReadStatus.mutateAsync({
id: item.node.id,
force: true,
...values,
itemId: item.node.id,
slug: item.node.slug,
input: {
id: item.node.id,
force: true,
...values,
},
})
} catch (err) {
console.log('Error marking item: ', err)
@ -459,6 +470,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
try {
await moveToFolder.mutateAsync({
itemId: item.node.id,
slug: item.node.slug,
folder: 'inbox',
})
} catch (err) {
@ -1250,8 +1262,7 @@ export function LibraryItemsLayout(
)}
{props.labelsTarget?.node.id && (
<SetPageLabelsModalPresenter
articleId={props.labelsTarget.node.id}
article={props.labelsTarget.node}
libraryItem={props.labelsTarget.node}
onOpenChange={() => {
if (props.labelsTarget) {
const activate = props.labelsTarget

View file

@ -4,23 +4,27 @@ import {
showSuccessToast,
showSuccessToastWithUndo,
} from '../toastHelpers'
import { updatePageMutation } from '../networking/mutations/updatePageMutation'
import { State } from '../networking/fragments/articleFragment'
import {
useArchiveItem,
useDeleteItem,
useMoveItemToFolder,
useRestoreItem,
} from '../networking/library_items/useLibraryItems'
export default function useLibraryItemActions() {
const archiveItem = useArchiveItem()
const deleteItem = useDeleteItem()
const moveItem = useMoveItemToFolder()
const restoreItem = useRestoreItem()
const doArchiveItem = useCallback(async (itemId: string) => {
const doArchiveItem = useCallback(async (itemId: string, slug: string) => {
const result = await archiveItem.mutateAsync({
linkId: itemId,
archived: true,
itemId: itemId,
slug: slug,
input: {
linkId: itemId,
archived: true,
},
})
console.log('result: ', result)
@ -33,33 +37,37 @@ export default function useLibraryItemActions() {
return !!result
}, [])
const doDeleteItem = useCallback(async (itemId: string, undo: () => void) => {
const result = await deleteItem.mutateAsync(itemId)
const doDeleteItem = useCallback(
async (itemId: string, slug: string, undo: () => void) => {
const result = await deleteItem.mutateAsync({ itemId, slug })
if (result) {
showSuccessToastWithUndo('Item removed', async () => {
const result = await updatePageMutation({
pageId: itemId,
state: State.SUCCEEDED,
if (result) {
showSuccessToastWithUndo('Item removed', async () => {
const result = await restoreItem.mutateAsync({ itemId, slug })
undo()
if (result) {
showSuccessToast('Item recovered')
} else {
showErrorToast('Error recovering, check your deleted items')
}
})
} else {
showErrorToast('Error removing item', { position: 'bottom-right' })
}
undo()
return !!result
},
[]
)
if (result) {
showSuccessToast('Item recovered')
} else {
showErrorToast('Error recovering, check your deleted items')
}
})
} else {
showErrorToast('Error removing item', { position: 'bottom-right' })
}
return !!result
}, [])
const doMoveItem = useCallback(async (itemId: string) => {
const result = await moveItem.mutateAsync({ itemId, folder: 'inbox' })
const doMoveItem = useCallback(async (itemId: string, slug: string) => {
const result = await moveItem.mutateAsync({
itemId,
slug,
folder: 'inbox',
})
if (result) {
showSuccessToast('Moved to library', { position: 'bottom-right' })
} else {

View file

@ -11,7 +11,8 @@ export type LabelsDispatcher = (action: {
}) => void
export const useSetPageLabels = (
articleId?: string
libraryItemId?: string,
libraryItemSlug?: string
): [{ labels: Label[] }, LabelsDispatcher] => {
const setItemLabels = useSetItemLabels()
const saveLabels = (labels: Label[], articleId: string) => {
@ -19,6 +20,7 @@ export const useSetPageLabels = (
if (articleId) {
const result = await setItemLabels.mutateAsync({
itemId: articleId,
slug: libraryItemSlug,
labels,
})
if (!result) {
@ -91,13 +93,13 @@ export const useSetPageLabels = (
dispatchLabels({
type: 'UPDATE_ARTICLE_ID',
labels: [],
articleId: articleId,
articleId: libraryItemId,
})
}, [articleId])
}, [libraryItemId])
const [labels, dispatchLabels] = useReducer(labelsReducer, {
labels: [],
articleId: articleId,
articleId: libraryItemId,
throttledSave: debouncedSave,
})

View file

@ -15,6 +15,7 @@ export const useCreateHighlight = () => {
const queryClient = useQueryClient()
const createHighlight = async (variables: {
itemId: string
slug: string | undefined
input: CreateHighlightInput
}) => {
const result = (await gqlFetcher(GQL_CREATE_HIGHLIGHT, {
@ -29,12 +30,17 @@ export const useCreateHighlight = () => {
mutationFn: createHighlight,
onSuccess: (newHighlight, variables) => {
if (newHighlight) {
updateItemProperty(queryClient, variables.itemId, (item) => {
return {
...item,
highlights: [...item.highlights, newHighlight],
updateItemProperty(
queryClient,
variables.itemId,
variables.slug,
(item) => {
return {
...item,
highlights: [...item.highlights, newHighlight],
}
}
})
)
}
},
})
@ -44,6 +50,7 @@ export const useDeleteHighlight = () => {
const queryClient = useQueryClient()
const deleteHighlight = async (variables: {
itemId: string
slug: string
highlightId: string
}) => {
const result = (await gqlFetcher(GQL_DELETE_HIGHLIGHT, {
@ -58,14 +65,19 @@ export const useDeleteHighlight = () => {
mutationFn: deleteHighlight,
onSuccess: (deletedHighlight, variables) => {
if (deletedHighlight) {
updateItemProperty(queryClient, variables.itemId, (item) => {
return {
...item,
highlights: item.highlights.filter(
(h) => h.id != deletedHighlight.id
),
updateItemProperty(
queryClient,
variables.itemId,
variables.slug,
(item) => {
return {
...item,
highlights: item.highlights.filter(
(h) => h.id != deletedHighlight.id
),
}
}
})
)
}
},
})
@ -75,6 +87,7 @@ export const useUpdateHighlight = () => {
const queryClient = useQueryClient()
const updateHighlight = async (variables: {
itemId: string
slug: string | undefined
input: UpdateHighlightInput
}) => {
const result = (await gqlFetcher(GQL_UPDATE_HIGHLIGHT, {
@ -89,15 +102,20 @@ export const useUpdateHighlight = () => {
mutationFn: updateHighlight,
onSuccess: (updatedHighlight, variables) => {
if (updatedHighlight) {
updateItemProperty(queryClient, variables.itemId, (item) => {
return {
...item,
highlights: [
...item.highlights.filter((h) => h.id != updatedHighlight.id),
updatedHighlight,
],
updateItemProperty(
queryClient,
variables.itemId,
variables.slug,
(item) => {
return {
...item,
highlights: [
...item.highlights.filter((h) => h.id != updatedHighlight.id),
updatedHighlight,
],
}
}
})
)
}
},
})
@ -107,6 +125,7 @@ export const useMergeHighlight = () => {
const queryClient = useQueryClient()
const mergeHighlight = async (variables: {
itemId: string
slug: string
input: MergeHighlightInput
}) => {
const result = (await gqlFetcher(GQL_MERGE_HIGHLIGHT, {
@ -137,15 +156,20 @@ export const useMergeHighlight = () => {
if (mergeHighlights && mergeHighlights.highlight) {
const newHighlight = mergeHighlights.highlight
const mergedIds = mergeHighlights.overlapHighlightIdList ?? []
updateItemProperty(queryClient, variables.itemId, (item) => {
return {
...item,
highlights: [
...item.highlights.filter((h) => mergedIds.indexOf(h.id) == -1),
newHighlight,
],
updateItemProperty(
queryClient,
variables.itemId,
variables.slug,
(item) => {
return {
...item,
highlights: [
...item.highlights.filter((h) => mergedIds.indexOf(h.id) == -1),
newHighlight,
],
}
}
})
)
}
},
})

View file

@ -43,9 +43,10 @@ function gqlFetcher(
const updateItemStateInCache = (
queryClient: QueryClient,
itemId: string,
slug: string | undefined,
newState: State
) => {
updateItemPropertyInCache(queryClient, itemId, 'state', newState)
updateItemPropertyInCache(queryClient, itemId, slug, 'state', newState)
}
function createDictionary(
@ -59,10 +60,11 @@ function createDictionary(
const updateItemPropertyInCache = (
queryClient: QueryClient,
itemId: string,
slug: string | undefined,
propertyName: string,
propertyValue: any
) => {
updateItemProperty(queryClient, itemId, (oldItem) => {
updateItemProperty(queryClient, itemId, slug, (oldItem) => {
const setter = createDictionary(propertyName, propertyValue)
return {
...oldItem,
@ -74,12 +76,15 @@ const updateItemPropertyInCache = (
export const updateItemProperty = (
queryClient: QueryClient,
itemId: string,
slug: string | undefined,
updateFunc: (input: ArticleAttributes) => ArticleAttributes
) => {
let foundItemSlug: string | undefined
const keys = queryClient
.getQueryCache()
.findAll({ queryKey: ['libraryItems'] })
console.log('updateItemProperty::KEYS: ', keys)
keys.forEach((query) => {
queryClient.setQueryData(query.queryKey, (data: any) => {
if (!data) return data
@ -101,9 +106,9 @@ export const updateItemProperty = (
}
return updatedData
})
if (foundItemSlug)
if (foundItemSlug || slug)
queryClient.setQueryData(
['libraryItem', foundItemSlug],
['libraryItem', foundItemSlug ?? slug],
(oldData: ArticleAttributes) => {
return {
...oldData,
@ -114,29 +119,66 @@ export const updateItemProperty = (
})
}
const updateItemPropertiesInCache = (
const overwriteItemPropertiesInCache = (
queryClient: QueryClient,
itemId: string,
item: ArticleAttributes
slug: string | undefined,
item: any
) => {
let foundItemSlug: string | undefined
const keys = queryClient
.getQueryCache()
.findAll({ queryKey: ['libraryItems'] })
console.log('overwriteItemPropertiesInCache::KEYS: ', keys)
// keys.forEach((query) => {
// queryClient.setQueryData(query.queryKey, (data: any) => {
// if (!data) return data
// return {
// ...data,
// pages: data.pages.map((page: any) => ({
// ...page,
// edges: page.edges.map((edge: any) =>
// edge.node.id === itemId
// ? { ...edge, node: { ...edge.node, ...item } }
// : edge
// ),
// })),
// }
// })
// })
keys.forEach((query) => {
queryClient.setQueryData(query.queryKey, (data: any) => {
console.log('query.queryKey', query.queryKey, data)
if (!data) return data
return {
const updatedData = {
...data,
pages: data.pages.map((page: any) => ({
...page,
edges: page.edges.map((edge: any) =>
edge.node.id === itemId
? { ...edge, node: { ...edge.node, ...item } }
: edge
),
edges: page.edges.map((edge: any) => {
if (edge.node.id === itemId) {
foundItemSlug = edge.node.slug
return {
...edge,
node: { ...edge.node, ...item },
}
}
return edge
}),
})),
}
return updatedData
})
console.log('updating foundItem slug: ', foundItemSlug)
if (foundItemSlug || slug)
queryClient.setQueryData(
['libraryItem', foundItemSlug ?? slug],
(oldData: ArticleAttributes) => {
return {
...oldData,
...item,
}
}
)
})
}
@ -172,9 +214,13 @@ export function useGetLibraryItems(
export const useArchiveItem = () => {
const queryClient = useQueryClient()
const archiveItem = async (input: SetLinkArchivedInput) => {
const archiveItem = async (variables: {
itemId: string
slug: string
input: SetLinkArchivedInput
}) => {
const result = (await gqlFetcher(GQL_SET_LINK_ARCHIVED, {
input,
input: variables.input,
})) as SetLinkArchivedData
if (result.errorCodes?.length) {
throw new Error(result.errorCodes[0])
@ -183,13 +229,18 @@ export const useArchiveItem = () => {
}
return useMutation({
mutationFn: archiveItem,
onMutate: async (input: SetLinkArchivedInput) => {
onMutate: async (variables: {
itemId: string
slug: string
input: SetLinkArchivedInput
}) => {
await queryClient.cancelQueries({ queryKey: ['libraryItems'] })
updateItemStateInCache(
queryClient,
input.linkId,
input.archived ? State.ARCHIVED : State.SUCCEEDED
variables.itemId,
variables.slug,
variables.input.archived ? State.ARCHIVED : State.SUCCEEDED
)
return { previousItems: queryClient.getQueryData(['libraryItems']) }
@ -209,9 +260,9 @@ export const useArchiveItem = () => {
export const useDeleteItem = () => {
const queryClient = useQueryClient()
const deleteItem = async (itemId: string) => {
const deleteItem = async (variables: { itemId: string; slug: string }) => {
const result = (await gqlFetcher(GQL_DELETE_LIBRARY_ITEM, {
input: { articleID: itemId, bookmark: false },
input: { articleID: variables.itemId, bookmark: false },
})) as SetBookmarkArticleData
if (result.setBookmarkArticle.errorCodes?.length) {
throw new Error(result.setBookmarkArticle.errorCodes[0])
@ -220,11 +271,16 @@ export const useDeleteItem = () => {
}
return useMutation({
mutationFn: deleteItem,
onMutate: async (itemId: string) => {
onMutate: async (variables: { itemId: string; slug: string }) => {
await queryClient.cancelQueries({
queryKey: ['libraryItems'],
})
updateItemStateInCache(queryClient, itemId, State.DELETED)
updateItemStateInCache(
queryClient,
variables.itemId,
variables.slug,
State.DELETED
)
return { previousItems: queryClient.getQueryData(['libraryItems']) }
},
onError: (error, itemId, context) => {
@ -242,9 +298,9 @@ export const useDeleteItem = () => {
export const useRestoreItem = () => {
const queryClient = useQueryClient()
const restoreItem = async (itemId: string) => {
const restoreItem = async (variables: { itemId: string; slug: string }) => {
const result = (await gqlFetcher(GQL_UPDATE_LIBRARY_ITEM, {
input: { pageId: itemId, state: State.SUCCEEDED },
input: { pageId: variables.itemId, state: State.SUCCEEDED },
})) as UpdateLibraryItemData
if (result.updatePage.errorCodes?.length) {
throw new Error(result.updatePage.errorCodes[0])
@ -253,9 +309,59 @@ export const useRestoreItem = () => {
}
return useMutation({
mutationFn: restoreItem,
onMutate: async (itemId: string) => {
onMutate: async (variables: { itemId: string; slug: string }) => {
await queryClient.cancelQueries({ queryKey: ['libraryItems'] })
updateItemStateInCache(queryClient, itemId, State.SUCCEEDED)
updateItemStateInCache(
queryClient,
variables.itemId,
variables.slug,
State.SUCCEEDED
)
return { previousItems: queryClient.getQueryData(['libraryItems']) }
},
onError: (error, itemId, context) => {
if (context?.previousItems) {
queryClient.setQueryData(['libraryItems'], context.previousItems)
}
},
onSettled: async () => {
await queryClient.invalidateQueries({
queryKey: ['libraryItems'],
})
},
})
}
export const useUpdateItem = () => {
const queryClient = useQueryClient()
const updateItem = async (variables: {
itemId: string
slug: string | undefined
input: UpdateLibraryItemInput
}) => {
const result = (await gqlFetcher(GQL_UPDATE_LIBRARY_ITEM, {
input: variables.input,
})) as UpdateLibraryItemData
if (result.updatePage.errorCodes?.length) {
throw new Error(result.updatePage.errorCodes[0])
}
return result.updatePage
}
return useMutation({
mutationFn: updateItem,
onMutate: async (variables: {
itemId: string
slug: string | undefined
input: UpdateLibraryItemInput
}) => {
await queryClient.cancelQueries({ queryKey: ['libraryItems'] })
console.log('will update item')
overwriteItemPropertiesInCache(
queryClient,
variables.itemId,
variables.slug,
variables.input
)
return { previousItems: queryClient.getQueryData(['libraryItems']) }
},
onError: (error, itemId, context) => {
@ -273,11 +379,13 @@ export const useRestoreItem = () => {
export const useUpdateItemReadStatus = () => {
const queryClient = useQueryClient()
const updateItemReadStatus = async (
const updateItemReadStatus = async (variables: {
itemId: string
slug: string
input: ArticleReadingProgressMutationInput
) => {
}) => {
const result = (await gqlFetcher(GQL_SAVE_ARTICLE_READING_PROGRESS, {
input,
input: variables.input,
})) as ArticleReadingProgressMutationData
if (result.saveArticleReadingProgress.errorCodes?.length) {
throw new Error(result.saveArticleReadingProgress.errorCodes[0])
@ -286,13 +394,18 @@ export const useUpdateItemReadStatus = () => {
}
return useMutation({
mutationFn: updateItemReadStatus,
onMutate: async (input: ArticleReadingProgressMutationInput) => {
onMutate: async (variables: {
itemId: string
slug: string
input: ArticleReadingProgressMutationInput
}) => {
await queryClient.cancelQueries({ queryKey: ['libraryItems'] })
updateItemPropertyInCache(
queryClient,
input.id,
variables.itemId,
variables.slug,
'readingProgressPercent',
input.readingProgressPercent
variables.input.readingProgressPercent
)
return { previousItems: queryClient.getQueryData(['libraryItems']) }
},
@ -305,7 +418,8 @@ export const useUpdateItemReadStatus = () => {
if (data) {
updateItemPropertyInCache(
queryClient,
data.id,
variables.itemId,
variables.slug,
'readingProgressPercent',
data.readingProgressPercent
)
@ -329,7 +443,12 @@ export const useGetLibraryItemContent = (username: string, slug: string) => {
}
const article = response.article.article
if (article) {
updateItemPropertiesInCache(queryClient, article.id, article)
overwriteItemPropertiesInCache(
queryClient,
article.id,
article.slug,
article
)
}
return response.article.article
},
@ -338,7 +457,11 @@ export const useGetLibraryItemContent = (username: string, slug: string) => {
export const useMoveItemToFolder = () => {
const queryClient = useQueryClient()
const moveItem = async (variables: { itemId: string; folder: string }) => {
const moveItem = async (variables: {
itemId: string
slug: string | undefined
folder: string
}) => {
const result = (await gqlFetcher(GQL_MOVE_ITEM_TO_FOLDER, {
id: variables.itemId,
folder: variables.folder,
@ -350,11 +473,16 @@ export const useMoveItemToFolder = () => {
}
return useMutation({
mutationFn: moveItem,
onMutate: async (variables: { itemId: string; folder: string }) => {
onMutate: async (variables: {
itemId: string
slug: string | undefined
folder: string
}) => {
await queryClient.cancelQueries({ queryKey: ['libraryItems'] })
updateItemPropertyInCache(
queryClient,
variables.itemId,
variables.slug,
'folder',
variables.folder
)
@ -375,7 +503,11 @@ export const useMoveItemToFolder = () => {
export const useSetItemLabels = () => {
const queryClient = useQueryClient()
const setLabels = async (variables: { itemId: string; labels: Label[] }) => {
const setLabels = async (variables: {
itemId: string
slug: string | undefined
labels: Label[]
}) => {
const labelIds = variables.labels.map((l) => l.id)
const result = (await gqlFetcher(GQL_SET_LABELS, {
input: { pageId: variables.itemId, labelIds },
@ -387,11 +519,16 @@ export const useSetItemLabels = () => {
}
return useMutation({
mutationFn: setLabels,
onMutate: async (variables: { itemId: string; labels: Label[] }) => {
onMutate: async (variables: {
itemId: string
slug: string | undefined
labels: Label[]
}) => {
await queryClient.cancelQueries({ queryKey: ['libraryItems'] })
updateItemPropertyInCache(
queryClient,
variables.itemId,
variables.slug,
'labels',
variables.labels
)
@ -406,6 +543,7 @@ export const useSetItemLabels = () => {
updateItemPropertyInCache(
queryClient,
variables.itemId,
variables.slug,
'labels',
newLabels
)
@ -418,6 +556,16 @@ export const useSetItemLabels = () => {
})
}
type UpdateLibraryItemInput = {
pageId: string
title?: string
byline?: string | undefined
description?: string
savedAt?: string
publishedAt?: string
state?: State
}
type SetLabelsData = {
setLabels: SetLabelsResult
}

View file

@ -1,45 +0,0 @@
import { gql } from 'graphql-request'
import { gqlFetcher } from '../networkHelpers'
import {
Highlight,
highlightFragment,
HighlightType,
} from './../fragments/highlightFragment'
import { CreateHighlightInput } from '../highlights/useItemHighlights'
type CreateHighlightOutput = {
createHighlight: InnerCreateHighlightOutput
}
type InnerCreateHighlightOutput = {
highlight: Highlight
}
export async function createHighlightMutation(
input: CreateHighlightInput
): Promise<Highlight | undefined> {
const mutation = gql`
mutation CreateHighlight($input: CreateHighlightInput!) {
createHighlight(input: $input) {
... on CreateHighlightSuccess {
highlight {
...HighlightFields
}
}
... on CreateHighlightError {
errorCodes
}
}
}
${highlightFragment}
`
try {
const data = await gqlFetcher(mutation, { input })
const output = data as CreateHighlightOutput | undefined
return output?.createHighlight.highlight
} catch {
return undefined
}
}

View file

@ -1,33 +0,0 @@
import { gql } from 'graphql-request'
import { gqlFetcher } from '../networkHelpers'
type ShareHighlightToFeedMutationInput = {
id: string
share: boolean
}
export async function shareHighlightToFeedMutation(
input: ShareHighlightToFeedMutationInput
): Promise<boolean> {
const mutation = gql`
mutation SetShareHighlight($input: SetShareHighlightInput!) {
setShareHighlight(input: $input) {
... on SetShareHighlightSuccess {
highlight {
id
}
}
... on SetShareHighlightError {
errorCodes
}
}
}
`
try {
await gqlFetcher(mutation, { input })
return true
} catch {
return false
}
}

View file

@ -11,10 +11,6 @@ import { PdfArticleContainerProps } from './../../../components/templates/articl
import { useCallback, useEffect, useState } from 'react'
import dynamic from 'next/dynamic'
import { Toaster } from 'react-hot-toast'
import { createHighlightMutation } from '../../../lib/networking/mutations/createHighlightMutation'
import { deleteHighlightMutation } from '../../../lib/networking/mutations/deleteHighlightMutation'
import { mergeHighlightMutation } from '../../../lib/networking/mutations/mergeHighlightMutation'
import { updateHighlightMutation } from '../../../lib/networking/mutations/updateHighlightMutation'
import Script from 'next/script'
import { ArticleActionsMenu } from '../../../components/templates/article/ArticleActionsMenu'
import { Label } from '../../../lib/networking/fragments/labelFragment'
@ -130,8 +126,12 @@ export default function Reader(): JSX.Element {
case 'unarchive':
try {
await archiveItem.mutateAsync({
linkId: libraryItem.id,
archived: action == 'archive',
itemId: libraryItem.id,
slug: libraryItem.slug,
input: {
linkId: libraryItem.id,
archived: action == 'archive',
},
})
} catch {
showErrorToast(`Error ${action}ing item`, {
@ -161,9 +161,13 @@ export default function Reader(): JSX.Element {
}
try {
await updateItemReadStatus.mutateAsync({
id: libraryItem.id,
force: true,
...values,
itemId: libraryItem.id,
slug: libraryItem.slug,
input: {
id: libraryItem.id,
force: true,
...values,
},
})
} catch {
showErrorToast(`Error marking as ${desc}`, {
@ -175,7 +179,10 @@ export default function Reader(): JSX.Element {
break
case 'delete':
try {
await deleteItem.mutateAsync(libraryItem.id)
await deleteItem.mutateAsync({
itemId: libraryItem.id,
slug: libraryItem.slug,
})
} catch {
showErrorToast(`Error deleting item`, {
position: 'bottom-right',
@ -457,7 +464,10 @@ export default function Reader(): JSX.Element {
[readerSettings, showHighlightsModal]
)
const [labels, dispatchLabels] = useSetPageLabels(libraryItem?.id)
const [labels, dispatchLabels] = useSetPageLabels(
libraryItem?.id,
libraryItem?.slug
)
new Error()
if (
@ -590,6 +600,7 @@ export default function Reader(): JSX.Element {
try {
const result = await createHighlight.mutateAsync({
itemId: libraryItem.id,
slug: libraryItem.slug,
input,
})
return result
@ -605,6 +616,7 @@ export default function Reader(): JSX.Element {
try {
await deleteHighlight.mutateAsync({
itemId: libraryItem.id,
slug: libraryItem.slug,
highlightId,
})
return true
@ -617,6 +629,7 @@ export default function Reader(): JSX.Element {
try {
const result = await mergeHighlight.mutateAsync({
itemId: libraryItem.id,
slug: libraryItem.slug,
input,
})
return result?.highlight
@ -629,6 +642,7 @@ export default function Reader(): JSX.Element {
try {
const result = await updateHighlight.mutateAsync({
itemId: libraryItem.id,
slug: libraryItem.slug,
input,
})
return result?.id
@ -641,7 +655,11 @@ export default function Reader(): JSX.Element {
input: ArticleReadingProgressMutationInput
) => {
try {
await updateItemReadStatus.mutateAsync(input)
await updateItemReadStatus.mutateAsync({
itemId: libraryItem.id,
slug: libraryItem.slug,
input,
})
} catch {
return false
}
@ -722,15 +740,14 @@ export default function Reader(): JSX.Element {
article={libraryItem}
onOpenChange={() => setShowEditModal(false)}
updateArticle={(title, author, description, savedAt, publishedAt) => {
libraryItem.title = title
libraryItem.author = author
libraryItem.description = description
libraryItem.savedAt = savedAt
libraryItem.publishedAt = publishedAt
const titleEvent = new Event('updateTitle') as UpdateTitleEvent
titleEvent.title = title
document.dispatchEvent(titleEvent)
// libraryItem.title = title
// libraryItem.author = author
// libraryItem.description = description
// libraryItem.savedAt = savedAt
// libraryItem.publishedAt = publishedAt
// const titleEvent = new Event('updateTitle') as UpdateTitleEvent
// titleEvent.title = title
// document.dispatchEvent(titleEvent)
}}
/>
)}