Skip to content

Commit

Permalink
Merge pull request #105 from mbret/develop
Browse files Browse the repository at this point in the history
release
  • Loading branch information
mbret authored Mar 16, 2024
2 parents 4927aa6 + d499919 commit b27ced6
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 74 deletions.
1 change: 1 addition & 0 deletions packages/shared/src/docTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ type MangoOperator =
type ConditionOperator<T> = {
$nin?: any[]
$in?: any[]
$ne?: T
}

interface MangoQuery<RxDocType> {
Expand Down
68 changes: 31 additions & 37 deletions packages/web/src/books/drawer/useRemoveHandler.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import { getBookById, useRemoveBook } from "../helpers"
import { useMutation } from "reactjrx"
import { getLatestDatabase } from "../../rxdb/useCreateDatabase"
import { combineLatest, from, map, mergeMap, of } from "rxjs"
import { from, map, mergeMap, of, tap } from "rxjs"
import { isRemovableFromDataSource } from "../../links/isRemovableFromDataSource"
import { getDataSourcePlugin } from "../../dataSources/getDataSourcePlugin"
import { getLinkById } from "../../links/helpers"
import { createDialog } from "../../common/dialogs/createDialog"
import { withUnknownErrorDialog } from "../../common/errors/withUnknownErrorDialog"
import { withOfflineErrorDialog } from "../../common/network/withOfflineErrorDialog"
import { useLock } from "../../common/BlockingBackdrop"

const deleteBookNormallyDialog: Parameters<
typeof createDialog<{ deleteFromDataSource: boolean }>
>[0] = {
preset: "CONFIRM",
title: "Delete a book",
content: `You are about to delete a book, are you sure ?`,
onConfirm: () => ({ deleteFromDataSource: false })
}

export const useRemoveHandler = (
options: { onSuccess?: () => void; onError?: () => void } = {}
) => {
const { mutateAsync: removeBook } = useRemoveBook()
const [lock] = useLock()

return useMutation({
mutationFn: ({ bookId }: { bookId: string }) => {
Expand All @@ -24,41 +35,23 @@ export const useRemoveHandler = (

const linkId = book.links[0]

if (!book?.isAttachedToDataSource || !linkId) {
return combineLatest([
of(book),
createDialog({
preset: "CONFIRM",
title: "Delete a book",
content: `You are about to delete a book, are you sure ?`,
onConfirm: () => ({ deleteFromDataSource: false })
}).$
])
}
const link$ = !linkId ? of(null) : getLinkById(database, linkId)

return getLinkById(database, linkId).pipe(
return link$.pipe(
mergeMap((firstLink) => {
if (!firstLink) {
return of({ deleteFromDataSource: false })
return createDialog(deleteBookNormallyDialog).$
}

const plugin = getDataSourcePlugin(firstLink?.type)

if (
book?.isAttachedToDataSource &&
!isRemovableFromDataSource({ link: firstLink })
) {
return createDialog({
preset: "CONFIRM",
title: "Delete a book",
content: `This book has been synchronized with one of your ${plugin?.name} data source. Oboku does not support deletion from ${plugin?.name} directly so consider deleting it there manually if you don't want the book to be synced again`,
onConfirm: () => ({ deleteFromDataSource: false })
}).$
if (!isRemovableFromDataSource({ link: firstLink })) {
return createDialog(deleteBookNormallyDialog).$
} else {
return createDialog({
preset: "CONFIRM",
title: "Delete a book",
content: `This book has been synchronized with one of your ${plugin?.name} data source. You can delete it from both oboku and ${plugin?.name} which will prevent the book to be synced again`,
content: `Do you wish to delete the original file present on the source ${plugin?.name} as well?`,
actions: [
{
type: "confirm",
Expand All @@ -74,20 +67,21 @@ export const useRemoveHandler = (
}).$
}
}),
map(
({ deleteFromDataSource }) =>
[book, { deleteFromDataSource }] as const
map((data) => [data, lock()] as const),
mergeMap(([{ deleteFromDataSource }, unlock]) =>
from(
removeBook({
id: book._id,
deleteFromDataSource: deleteFromDataSource
})
).pipe(
tap(() => {
unlock()
})
)
)
)
}),
mergeMap(([book, { deleteFromDataSource }]) =>
from(
removeBook({
id: book._id,
deleteFromDataSource: deleteFromDataSource
})
)
)
})
)
}),
withOfflineErrorDialog(),
Expand Down
4 changes: 2 additions & 2 deletions packages/web/src/books/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,10 @@ export const useBookIdsSortedBy = (
}

export const useBooksSortedBy = (
books: BookQueryResult[],
books: BookQueryResult[] | undefined,
sorting: "date" | "activity" | "alpha" | undefined
) => {
return useMemo(() => sortBooksBy(books, sorting), [books, sorting])
return useMemo(() => sortBooksBy(books ?? [], sorting), [books, sorting])
}

const sortBooksBy = (
Expand Down
19 changes: 3 additions & 16 deletions packages/web/src/books/states.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Database } from "../rxdb"
import { useMemo } from "react"
import { BookDocType } from "@oboku/shared"
import { DeepReadonlyObject, MangoQuery } from "rxdb"
import { useVisibleBooks } from "./useVisibleBooks"

export const getBooksByIds = async (database: Database) => {
const result = await database.collections.book.find({}).exec()
Expand Down Expand Up @@ -252,7 +253,7 @@ export const useBooksAsArrayState = ({
>
}) => {
const { data: books = {}, isPending } = useBooksDic()
const visibleBookIds = useVisibleBookIds()
const visibleBookIds = useVisibleBookIds() ?? []

const bookResult: (BookQueryResult & {
downloadState: ReturnType<typeof getBookDownloadsState>
Expand Down Expand Up @@ -290,21 +291,7 @@ export const useBookIdsState = () => {
export const useVisibleBookIds = ({
queryObj
}: { queryObj?: MangoQuery<BookDocType> } = {}) => {
const { data: books = [] } = useBooks({ queryObj })
const { data: protectedTagIds } = useProtectedTagIds()
const { isLibraryUnlocked } = useSignalValue(libraryStateSignal)

return useMemo(() => {
if (isLibraryUnlocked) {
return books.map((item) => item._id)
} else {
return books
.filter(
(book) => intersection(protectedTagIds, book?.tags || []).length === 0
)
.map((book) => book?._id || "-1")
}
}, [books, protectedTagIds, isLibraryUnlocked])
return useVisibleBooks({ queryObj }).data?.map((book) => book._id)
}

/**
Expand Down
28 changes: 28 additions & 0 deletions packages/web/src/books/useVisibleBooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { BookDocType, SafeMangoQuery } from "@oboku/shared"
import { useBooks } from "./states"
import { useProtectedTagIds } from "../tags/helpers"
import { useSignalValue } from "reactjrx"
import { libraryStateSignal } from "../library/states"
import { useMemo } from "react"
import { intersection } from "lodash"

export const useVisibleBooks = ({
queryObj
}: { queryObj?: SafeMangoQuery<BookDocType> } = {}) => {
const { data: books, isLoading: isBooksLoading } = useBooks({ queryObj })
const { data: protectedTagIds, isLoading: isTagsLoading } =
useProtectedTagIds()
const { isLibraryUnlocked } = useSignalValue(libraryStateSignal)

const data = useMemo(() => {
if (isLibraryUnlocked) {
return books
} else {
return books?.filter(
(book) => intersection(protectedTagIds, book?.tags || []).length === 0
)
}
}, [books, protectedTagIds, isLibraryUnlocked])

return { data, isLoading: isBooksLoading || isTagsLoading }
}
38 changes: 20 additions & 18 deletions packages/web/src/home/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import { useMemo } from "react"
import { useBooksAsArrayState } from "../books/states"
import { ReadingStateState } from "@oboku/shared"
import { useBooksSortedBy } from "../books/helpers"
import { booksDownloadStateSignal } from "../download/states"
import { useProtectedTagIds } from "../tags/helpers"
import { useSignalValue } from "reactjrx"
import { useVisibleBooks } from "../books/useVisibleBooks"

/**
* @todo cleanup
*/
export const useContinueReadingBooks = () => {
const { isPending } = useProtectedTagIds()
const normalizedBookDownloadsState = useSignalValue(booksDownloadStateSignal)

const { data: booksAsArray, isPending: isBooksPending } =
useBooksAsArrayState({
normalizedBookDownloadsState
})
const { data: booksAsArray, isLoading: isBooksPending } = useVisibleBooks({
queryObj: {
selector: {
isNotInterested: {
$ne: true
}
}
}
})
const booksSortedByDate = useBooksSortedBy(booksAsArray, "activity")

return {
Expand All @@ -34,20 +33,23 @@ export const useContinueReadingBooks = () => {
}
}

/**
* @todo cleanup
*/
export const useRecentlyAddedBooks = () => {
const { data: books } = useBooksAsArrayState({
normalizedBookDownloadsState: useSignalValue(booksDownloadStateSignal)
const { data: booksAsArray } = useVisibleBooks({
queryObj: {
selector: {
isNotInterested: {
$ne: true
}
}
}
})

return useMemo(() => {
// descend
const booksSortedByDate = [...books].sort((a, b) =>
const booksSortedByDate = [...(booksAsArray ?? [])].sort((a, b) =>
a.createdAt < b.createdAt ? 1 : -1
)

return booksSortedByDate.slice(0, 15).map((book) => book._id)
}, [books])
}, [booksAsArray])
}
3 changes: 2 additions & 1 deletion packages/web/src/plugins/dropbox/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DropboxAuth } from "dropbox"
import { CLIENT_ID } from "../constants"
import { ObokuPluginError } from "../../plugin-front"
import { ROUTES } from "../../../constants"

const defaultWindowOptions = {
toolbar: "no",
Expand Down Expand Up @@ -45,7 +46,7 @@ export const authUser = ({
// to handle it without for even long sync. Otherwise we should ask user credentials again
if (isAccessTokenStillSufficient()) return resolve(dropboxAuth)

const redirectUri = `${window.location.origin}/auth_callback`
const redirectUri = `${window.location.origin}/${ROUTES.AUTH_CALLBACK}`
const usePKCE = true
const authType = "code"
const tokenAccessType = "online"
Expand Down

0 comments on commit b27ced6

Please sign in to comment.