Better handling of slugs and library item lists in the cache
This commit is contained in:
@ -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}
|
||||
|
||||
@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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' })
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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}
|
||||
|
||||
Reference in New Issue
Block a user