diff --git a/.github/workflows/check_commit.yml b/.github/workflows/check_commit.yml index a15e71f0..a8ed5484 100644 --- a/.github/workflows/check_commit.yml +++ b/.github/workflows/check_commit.yml @@ -29,8 +29,8 @@ jobs: - name: Install & Build prod js files run: | - yarn - yarn build:server + npm + npm run build:server # Runs a set of commands using the runners shell - name: Commit and push to branch @@ -72,7 +72,7 @@ jobs: touch .secrets/jwt-private-key.key echo "$JWT_PRIVATE_KEY" > .secrets/jwt-private-key.key - yarn compile + npm run compile sam build sam deploy --no-confirm-changeset --parameter-overrides\ ParameterKey=Environment,ParameterValue=PROD \ diff --git a/packages/web/src/books/Cover.tsx b/packages/web/src/books/Cover.tsx index 9c3bc036..ba403c98 100644 --- a/packages/web/src/books/Cover.tsx +++ b/packages/web/src/books/Cover.tsx @@ -11,14 +11,14 @@ import { import { useCSS } from "../common/utils" import { API_URI } from "../constants" import { useLocalSettings } from "../settings/states" -import { normalizedBookDownloadsStateSignal } from "../download/states" +import { booksDownloadStateSignal } from "../download/states" import { useSignalValue } from "reactjrx" import { authStateSignal } from "../auth/authState" const useBookCoverState = ({ bookId }: { bookId: string }) => { const tags = useTagsByIds().data const normalizedBookDownloadsState = useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ) const blurredTags = useBlurredTagIds().data ?? [] const protectedTags = useProtectedTagIds().data ?? [] diff --git a/packages/web/src/books/ManageBookCollectionsDialog.tsx b/packages/web/src/books/ManageBookCollectionsDialog.tsx index 34c4ca26..ca09e0b7 100644 --- a/packages/web/src/books/ManageBookCollectionsDialog.tsx +++ b/packages/web/src/books/ManageBookCollectionsDialog.tsx @@ -1,11 +1,10 @@ import { FC, useCallback } from "react" -import { useCollectionIdsState } from "../collections/states" +import { useVisibleCollectionIds } from "../collections/states" import { useAddCollectionToBook, useRemoveCollectionFromBook } from "./helpers" import { useBookState } from "./states" import { CollectionsSelectionDialog } from "../collections/CollectionsSelectionDialog" -import { libraryStateSignal } from "../library/states" import { useLocalSettings } from "../settings/states" -import { useProtectedTagIds, useTagsByIds } from "../tags/helpers" +import { useTagsByIds } from "../tags/helpers" import { SIGNAL_RESET, signal, useSignalValue } from "reactjrx" const openManageBookCollectionsDialogStateSignal = signal({ @@ -30,13 +29,8 @@ export const useManageBookCollectionsDialog = () => { export const ManageBookCollectionsDialog: FC<{}> = () => { const id = useSignalValue(openManageBookCollectionsDialogStateSignal) - const libraryState = useSignalValue(libraryStateSignal) const open = !!id - const collections = useCollectionIdsState({ - libraryState, - localSettingsState: useLocalSettings(), - protectedTagIds: useProtectedTagIds().data - }) + const { data: collections = [] } = useVisibleCollectionIds() const book = useBookState({ bookId: id, tags: useTagsByIds().data }) const { mutate: addToBook } = useAddCollectionToBook() diff --git a/packages/web/src/books/bookList/BookListCoverContainer.tsx b/packages/web/src/books/bookList/BookListCoverContainer.tsx index d08fbde7..ca910dc9 100644 --- a/packages/web/src/books/bookList/BookListCoverContainer.tsx +++ b/packages/web/src/books/bookList/BookListCoverContainer.tsx @@ -1,25 +1,22 @@ import React, { FC, memo } from "react" -import { Chip, useTheme } from "@mui/material" +import { Box, Chip, useTheme } from "@mui/material" import { - CheckCircleRounded, + CheckOutlined, CloudDownloadRounded, ErrorRounded, LoopRounded, - NoEncryptionRounded + NoEncryptionOutlined, + ThumbDownOutlined } from "@mui/icons-material" import { Cover } from "../Cover" -import { useEnrichedBookState } from "../states" +import { useBook, useIsBookProtected } from "../states" import { ReadingStateState } from "@oboku/shared" import { ReadingProgress } from "./ReadingProgress" -import { - DownloadState, - normalizedBookDownloadsStateSignal -} from "../../download/states" +import { DownloadState, useBookDownloadState } from "../../download/states" import { useCSS } from "../../common/utils" -import { useProtectedTagIds, useTagsByIds } from "../../tags/helpers" -import { useSignalValue } from "reactjrx" +import { CoverIconBadge } from "./CoverIconBadge" -type Book = ReturnType +type Book = ReturnType["data"] export const BookListCoverContainer: FC<{ bookId: string @@ -27,87 +24,112 @@ export const BookListCoverContainer: FC<{ style?: React.CSSProperties withReadingProgressStatus?: boolean withDownloadStatus?: boolean - withMetadaStatus?: boolean - withProtectedStatus?: boolean - size?: "small" | "large" + withBadges: boolean + size?: "small" | "large" | "medium" }> = memo( ({ bookId, className, - withMetadaStatus = true, style, withDownloadStatus = true, withReadingProgressStatus = true, - size = "small", - withProtectedStatus = true + withBadges, + size = "small" }) => { - const item = useEnrichedBookState({ - bookId, - normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal - ), - protectedTagIds: useProtectedTagIds().data, - tags: useTagsByIds().data - }) + const { data: item } = useBook({ id: bookId }) + const bookDownloadState = useBookDownloadState(bookId) + const { data: isBookProtected = true } = useIsBookProtected(item) const classes = useStyles({ item }) return ( -
{item && } - {item?.downloadState !== DownloadState.Downloaded && ( -
+ {bookDownloadState?.downloadState !== DownloadState.Downloaded && ( + )} - {withProtectedStatus && item?.isProtected && ( -
- + {withBadges && ( + + + {isBookProtected && ( + + + + )} + {item?.isNotInterested && ( + + + + )} + + {withReadingProgressStatus && + item?.readingStateCurrentState === + ReadingStateState.Finished && ( + + + + )} + + )} + {withBadges && item?.metadataUpdateStatus === "fetching" && ( + } + label="metadata..." /> -
- )} - {withReadingProgressStatus && - item?.readingStateCurrentState === ReadingStateState.Finished && ( -
- -
)} -
- {withMetadaStatus && item?.metadataUpdateStatus === "fetching" && ( -
+ {withBadges && + item?.metadataUpdateStatus !== "fetching" && + !!item?.lastMetadataUpdateError && ( } - label="metadata..." + icon={} + label="metadata" /> -
- )} - {withMetadaStatus && - item?.metadataUpdateStatus !== "fetching" && - !!item?.lastMetadataUpdateError && ( -
- } - label="metadata" - /> + )} + {withDownloadStatus && + bookDownloadState?.downloadState === DownloadState.None && ( + + + + )} + {withDownloadStatus && + bookDownloadState?.downloadState === DownloadState.Downloading && ( +
+
)} - {item?.downloadState === "none" && ( -
- -
- )} - {withDownloadStatus && item?.downloadState === "downloading" && ( -
- -
- )} -
+ {withReadingProgressStatus && ( <> {item?.readingStateCurrentState === ReadingStateState.Reading && ( @@ -120,7 +142,7 @@ export const BookListCoverContainer: FC<{ )} )} -
+
) } ) @@ -135,30 +157,13 @@ const useStyles = ({ item }: { item: Book }) => { display: "flex", minHeight: 0 // @see https://stackoverflow.com/questions/42130384/why-should-i-specify-height-0-even-if-i-specified-flex-basis-0-in-css3-flexbox }, - itemCoverCenterInfo: { - display: "flex", - overflow: "hidden" - }, - itemCoverCenterInfoText: {}, - finishIconContainer: { position: "absolute", right: 5, top: 5 }, - finishIcon: { opacity: "70%", color: "black" }, - protectedIconContainer: { - position: "absolute", - left: 5, - top: 5, - backgroundColor: "black", - borderRadius: 50, - padding: 4, - opacity: "70%" - }, - protectedIcon: { opacity: "100%", color: "white" }, bodyContainer: { position: "absolute", height: "100%", width: "100%", top: 0, display: "flex", - padding: theme.spacing(1), + padding: theme.spacing(0.5), flexDirection: "column", alignItems: "center" }, @@ -173,17 +178,6 @@ const useStyles = ({ item }: { item: Book }) => { position: "absolute", left: "50%", top: "50%" - }, - downloadOverlay: { - backgroundColor: "white", - opacity: 0.5, - height: - item?.downloadState === DownloadState.Downloading - ? `${100 - (item?.downloadProgress || 0)}%` - : `100%`, - width: "100%", - position: "absolute", - top: 0 } }), [theme, item] diff --git a/packages/web/src/books/bookList/BookListGridItem.tsx b/packages/web/src/books/bookList/BookListGridItem.tsx index f3b438c9..ae185408 100644 --- a/packages/web/src/books/bookList/BookListGridItem.tsx +++ b/packages/web/src/books/bookList/BookListGridItem.tsx @@ -6,7 +6,7 @@ import { useEnrichedBookState } from "../states" import { useDefaultItemClickHandler } from "./helpers" import { BookListCoverContainer } from "./BookListCoverContainer" import { useCSS } from "../../common/utils" -import { normalizedBookDownloadsStateSignal } from "../../download/states" +import { booksDownloadStateSignal } from "../../download/states" import { useProtectedTagIds, useTagsByIds } from "../../tags/helpers" import { useSignalValue } from "reactjrx" @@ -25,7 +25,7 @@ export const BookListGridItem: FC<{ onItemClick?: (id: string) => void }> = memo(({ bookId, onItemClick }) => { const normalizedBookDownloadsState = useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ) const { data: protectedTagIds } = useProtectedTagIds() const tags = useTagsByIds().data @@ -50,7 +50,8 @@ export const BookListGridItem: FC<{ { const book = useEnrichedBookState({ bookId, - normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal - ), + normalizedBookDownloadsState: useSignalValue(booksDownloadStateSignal), protectedTagIds: useProtectedTagIds().data, tags: useTagsByIds().data }) @@ -45,6 +45,7 @@ export const BookListListItem: FC<{ const computedHeight = itemHeight || (size === "small" ? 50 : 100) const coverWidth = computedHeight * theme.custom.coverAverageRatio const classes = useStyles({ coverWidth }) + const { data: isBookProtected = true } = useIsBookProtected(book) return (
{book?.creator || "Unknown"} - {/*
- {book?.isProtected && ( - - )} -
*/} -
-
+ + {isBookProtected && } + {book?.isNotInterested && } {book?.readingStateCurrentState === ReadingStateState.Finished && (
- +
)} {book?.readingStateCurrentState === ReadingStateState.Reading && (
- +
)} -
+
{/* {(book?.downloadState === DownloadState.Downloading) && (
@@ -169,7 +163,7 @@ export const BookListListItem: FC<{
)}
-
+
{withDrawerActions && (
{ + return ( + + {children} + + ) + } +) diff --git a/packages/web/src/books/bookList/SelectableBookListItem.tsx b/packages/web/src/books/bookList/SelectableBookListItem.tsx index 3afa862e..ba6b01fe 100644 --- a/packages/web/src/books/bookList/SelectableBookListItem.tsx +++ b/packages/web/src/books/bookList/SelectableBookListItem.tsx @@ -4,7 +4,7 @@ import { useEnrichedBookState } from "../states" import { useCSS } from "../../common/utils" import { BookListCoverContainer } from "./BookListCoverContainer" import { Checkbox } from "../../common/Checkbox" -import { normalizedBookDownloadsStateSignal } from "../../download/states" +import { booksDownloadStateSignal } from "../../download/states" import { useProtectedTagIds, useTagsByIds } from "../../tags/helpers" import { useSignalValue } from "reactjrx" @@ -29,9 +29,7 @@ export const SelectableBookListItem: FC<{ }) => { const book = useEnrichedBookState({ bookId, - normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal - ), + normalizedBookDownloadsState: useSignalValue(booksDownloadStateSignal), protectedTagIds: useProtectedTagIds().data, tags: useTagsByIds().data }) @@ -50,10 +48,9 @@ export const SelectableBookListItem: FC<{
{ const item = getEnrichedBookState({ bookId: id, normalizedBookDownloadsState: - normalizedBookDownloadsStateSignal.getValue(), + booksDownloadStateSignal.getValue(), protectedTagIds: db ? await getProtectedTags(db) : [], tags: db ? await getTagsByIds(db) : {}, normalizedLinks, diff --git a/packages/web/src/books/details/BookDetailsScreen.tsx b/packages/web/src/books/details/BookDetailsScreen.tsx index 19011c4a..cb4cc1f6 100644 --- a/packages/web/src/books/details/BookDetailsScreen.tsx +++ b/packages/web/src/books/details/BookDetailsScreen.tsx @@ -39,7 +39,7 @@ import { DataSourceSection } from "./DataSourceSection" import { isDebugEnabled } from "../../debug/isDebugEnabled.shared" import { useRemoveDownloadFile } from "../../download/useRemoveDownloadFile" import { libraryStateSignal } from "../../library/states" -import { normalizedBookDownloadsStateSignal } from "../../download/states" +import { booksDownloadStateSignal } from "../../download/states" import { useLocalSettings } from "../../settings/states" import { useProtectedTagIds, useTagsByIds } from "../../tags/helpers" import { useSignalValue } from "reactjrx" @@ -61,7 +61,7 @@ export const BookDetailsScreen = () => { const book = useEnrichedBookState({ bookId: id, normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ), protectedTagIds: useProtectedTagIds().data, tags: useTagsByIds().data diff --git a/packages/web/src/books/drawer/BookActionsDrawer.tsx b/packages/web/src/books/drawer/BookActionsDrawer.tsx index 9005a590..d89717d4 100644 --- a/packages/web/src/books/drawer/BookActionsDrawer.tsx +++ b/packages/web/src/books/drawer/BookActionsDrawer.tsx @@ -34,7 +34,7 @@ import { useModalNavigationControl } from "../../navigation/useModalNavigationCo import { useTranslation } from "react-i18next" import { useManageBookTagsDialog } from "../ManageBookTagsDialog" import { markAsInterested } from "../triggers" -import { normalizedBookDownloadsStateSignal } from "../../download/states" +import { booksDownloadStateSignal } from "../../download/states" import { useProtectedTagIds, useTagsByIds } from "../../tags/helpers" import { signal, useSignalValue } from "reactjrx" import { useRemoveHandler } from "./useRemoveHandler" @@ -50,7 +50,7 @@ export const BookActionsDrawer = memo(() => { const { openedWith: bookId, actions } = useSignalValue(bookActionDrawerSignal) const navigate = useNavigate() const normalizedBookDownloadsState = useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ) const book = useEnrichedBookState({ bookId: bookId || "-1", diff --git a/packages/web/src/books/helpers.ts b/packages/web/src/books/helpers.ts index 57bab046..b0f9f781 100644 --- a/packages/web/src/books/helpers.ts +++ b/packages/web/src/books/helpers.ts @@ -9,7 +9,7 @@ import { Report } from "../debug/report.shared" import { useCallback, useMemo } from "react" import { useDownloadBook } from "../download/useDownloadBook" import { PromiseReturnType } from "../types" -import { BookQueryResult, useBooks } from "./states" +import { BookQueryResult, useBooksDic } from "./states" import { AtomicUpdateFunction } from "rxdb" import { useLock } from "../common/BlockingBackdrop" import { useNetworkState } from "react-use" @@ -301,7 +301,7 @@ export const useBookIdsSortedBy = ( ids: string[], sorting: "date" | "activity" | "alpha" | undefined ) => { - const { data: normalizedBooks = {} } = useBooks() + const { data: normalizedBooks = {} } = useBooksDic() return useMemo(() => { const books = ids diff --git a/packages/web/src/books/states.ts b/packages/web/src/books/states.ts index f0e2af27..8c6a2f24 100644 --- a/packages/web/src/books/states.ts +++ b/packages/web/src/books/states.ts @@ -8,18 +8,23 @@ import { import { getLinkState, useLinks } from "../links/states" import { getBookDownloadsState, - normalizedBookDownloadsStateSignal, + booksDownloadStateSignal, DownloadState } from "../download/states" -import { getCollectionState, useCollections } from "../collections/states" +import { + getCollectionState, + useCollectionsDictionaryWithoutPrivacy +} from "../collections/states" import { map, switchMap, tap, withLatestFrom } from "rxjs" import { plugin } from "../plugins/local" import { latestDatabase$ } from "../rxdb/useCreateDatabase" import { useLocalSettings } from "../settings/states" -import { useForeverQuery } from "reactjrx" +import { useForeverQuery, useSignalValue } from "reactjrx" import { keyBy } from "lodash" import { Database } from "../rxdb" import { useMemo } from "react" +import { BookDocType } from "@oboku/shared" +import { DeepReadonlyObject, MangoQuery } from "rxdb" export const getBooksByIds = async (database: Database) => { const result = await database.collections.book.find({}).exec() @@ -27,24 +32,31 @@ export const getBooksByIds = async (database: Database) => { return keyBy(result, "_id") } -export const useBooks = () => { +export const useBooks = ({ + queryObj +}: { queryObj?: MangoQuery } = {}) => { return useForeverQuery({ - queryKey: ["rxdb", "get", "many", "books"], + queryKey: ["rxdb", "get", "many", "books", queryObj], queryFn: () => { return latestDatabase$.pipe( - switchMap((db) => db.collections.book.find({}).$), - map((entries) => keyBy(entries, "_id")) + switchMap((db) => db.collections.book.find(queryObj).$), + map((items) => items.map((item) => item.toJSON())) ) } }) } +export const useBooksDic = () => { + const { data, ...rest } = useBooks() + + return { ...rest, data: data ? keyBy(data, "_id") : undefined } +} + export const useBook = ({ id }: { id?: string }) => { return useForeverQuery({ queryKey: ["rxdb", "book", id], enabled: !!id, queryFn: () => { - console.log("useBook.fetch", id) return latestDatabase$.pipe( switchMap( (db) => @@ -55,11 +67,6 @@ export const useBook = ({ id }: { id?: string }) => { }).$ ), map((value) => { - console.log( - "useBook.result", - value?.readingStateCurrentBookmarkLocation - ) - return value?.toJSON() ?? null }) ) @@ -69,8 +76,10 @@ export const useBook = ({ id }: { id?: string }) => { export type BookQueryResult = NonNullable["data"]> -const isBookProtected = (protectedTags: string[], book: BookQueryResult) => - intersection(protectedTags, book?.tags || []).length > 0 +const isBookProtected = ( + protectedTags: string[], + book: Pick, "tags"> +) => intersection(protectedTags, book?.tags || []).length > 0 /** * @deprecated @@ -80,7 +89,7 @@ const getBookState = ({ book, tags = {} }: { - collections: ReturnType["data"] + collections: ReturnType["data"] book?: BookQueryResult | null tags: ReturnType["data"] }) => { @@ -104,7 +113,7 @@ export const useBookState = ({ tags: ReturnType["data"] }) => { const { data: book } = useBook({ id: bookId }) - const { data: collections } = useCollections() + const { data: collections } = useCollectionsDictionaryWithoutPrivacy() return getBookState({ book, @@ -127,16 +136,16 @@ export const getEnrichedBookState = ({ }: { bookId: string normalizedBookDownloadsState: ReturnType< - typeof normalizedBookDownloadsStateSignal.getValue + typeof booksDownloadStateSignal.getValue > protectedTagIds: ReturnType["data"] tags: ReturnType["data"] normalizedLinks: ReturnType["data"] - normalizedCollections: ReturnType["data"] - normalizedBooks: ReturnType["data"] + normalizedCollections: ReturnType["data"] + normalizedBooks: ReturnType["data"] }) => { const book = getBookState({ - book: normalizedBooks[bookId]?.toJSON(), + book: normalizedBooks[bookId], tags, collections: normalizedCollections }) @@ -163,17 +172,36 @@ export const getEnrichedBookState = ({ } } +export const useIsBookProtected = ( + book?: Parameters[1] | null +) => { + const { data: protectedTagIds, ...rest } = useProtectedTagIds({ + enabled: !!book + }) + + return { + ...rest, + data: + protectedTagIds && book + ? isBookProtected(protectedTagIds, book) + : undefined + } +} + +/** + * @deprecated + */ export const useEnrichedBookState = (param: { bookId: string normalizedBookDownloadsState: ReturnType< - typeof normalizedBookDownloadsStateSignal.getValue + typeof booksDownloadStateSignal.getValue > protectedTagIds: ReturnType["data"] tags: ReturnType["data"] }) => { const { data: normalizedLinks } = useLinks() - const { data: normalizedCollections } = useCollections() - const { data: normalizedBooks } = useBooks() + const { data: normalizedCollections } = useCollectionsDictionaryWithoutPrivacy() + const { data: normalizedBooks } = useBooksDic() return getEnrichedBookState({ ...param, @@ -190,7 +218,7 @@ export const useDownloadedBookWithUnsafeProtectedIdsState = ({ normalizedBookDownloadsState }: { normalizedBookDownloadsState: ReturnType< - typeof normalizedBookDownloadsStateSignal.getValue + typeof booksDownloadStateSignal.getValue > }) => { const book = useBookIdsState() @@ -205,21 +233,14 @@ export const useDownloadedBookWithUnsafeProtectedIdsState = ({ * @deprecated */ export const useBooksAsArrayState = ({ - libraryState, - normalizedBookDownloadsState, - protectedTagIds = [] + normalizedBookDownloadsState }: { - libraryState: ReturnType normalizedBookDownloadsState: ReturnType< - typeof normalizedBookDownloadsStateSignal.getValue + typeof booksDownloadStateSignal.getValue > - protectedTagIds: ReturnType["data"] }) => { - const { data: books = {}, isPending } = useBooks() - const visibleBookIds = useVisibleBookIdsState({ - libraryState, - protectedTagIds - }) + const { data: books = {}, isPending } = useBooksDic() + const visibleBookIds = useVisibleBookIds() const bookResult: (BookQueryResult & { downloadState: ReturnType @@ -239,7 +260,7 @@ export const useBooksAsArrayState = ({ return [ ...acc, { - ...book.toJSON(), + ...book, downloadState } ] @@ -249,28 +270,23 @@ export const useBooksAsArrayState = ({ } export const useBookIdsState = () => { - const { data: books = {} } = useBooks() + const { data: books = {} } = useBooksDic() return Object.keys(books) } -/** - * @deprecated - */ -export const useVisibleBookIdsState = ({ - libraryState: { isLibraryUnlocked }, - protectedTagIds = [] -}: { - libraryState: ReturnType - protectedTagIds: ReturnType["data"] -}) => { - const { data: books = {} } = useBooks() +export const useVisibleBookIds = ({ + queryObj +}: { queryObj?: MangoQuery } = {}) => { + const { data: books = [] } = useBooks({ queryObj }) + const { data: protectedTagIds } = useProtectedTagIds() + const { isLibraryUnlocked } = useSignalValue(libraryStateSignal) return useMemo(() => { if (isLibraryUnlocked) { - return Object.keys(books) + return books.map((item) => item._id) } else { - return Object.values(books) + return books .filter( (book) => intersection(protectedTagIds, book?.tags || []).length === 0 ) @@ -327,11 +343,8 @@ export const useBookCollectionsState = ({ tags: ReturnType["data"] }) => { const book = useBookState({ bookId, tags }) - const { data: normalizedCollections } = useCollections() - const bookIds = useVisibleBookIdsState({ - libraryState, - protectedTagIds - }) + const { data: normalizedCollections } = useCollectionsDictionaryWithoutPrivacy() + const bookIds = useVisibleBookIds() return book?.collections?.map((id) => getCollectionState({ diff --git a/packages/web/src/collections/CollectionActionsDrawer.tsx b/packages/web/src/collections/CollectionActionsDrawer.tsx index 40c8a4dc..485e9065 100644 --- a/packages/web/src/collections/CollectionActionsDrawer.tsx +++ b/packages/web/src/collections/CollectionActionsDrawer.tsx @@ -26,7 +26,6 @@ import { useCallback } from "react" import { useRef } from "react" import { libraryStateSignal } from "../library/states" import { useLocalSettings } from "../settings/states" -import { useProtectedTagIds } from "../tags/helpers" import { signal, useSignalValue } from "reactjrx" const collectionActionDrawerState = signal<{ @@ -184,9 +183,7 @@ const EditCollectionDialog: FC<{ const libraryState = useSignalValue(libraryStateSignal) const collection = useCollectionState({ id: id || "-1", - libraryState, localSettingsState: useLocalSettings(), - protectedTagIds: useProtectedTagIds().data }) const { mutate: editCollection } = useUpdateCollection() diff --git a/packages/web/src/collections/CollectionDetailsScreen.tsx b/packages/web/src/collections/CollectionDetailsScreen.tsx index e9a8bd9a..015f779f 100644 --- a/packages/web/src/collections/CollectionDetailsScreen.tsx +++ b/packages/web/src/collections/CollectionDetailsScreen.tsx @@ -1,16 +1,12 @@ -import { useMemo } from "react" import { TopBarNavigation } from "../navigation/TopBarNavigation" import { Box, Typography, useTheme } from "@mui/material" import { useNavigate, useParams } from "react-router-dom" import EmptyLibraryAsset from "../assets/empty-library.svg" import CollectionBgSvg from "../assets/series-bg.svg" -import { useCollectionState } from "./states" +import { useCollection } from "./states" import { useCollectionActionsDrawer } from "./CollectionActionsDrawer" import { BookListWithControls } from "../books/bookList/BookListWithControls" -import { useLocalSettings } from "../settings/states" -import { useProtectedTagIds } from "../tags/helpers" -import { useSignalValue } from "reactjrx" -import { libraryStateSignal } from "../library/states" +import { useVisibleBookIds } from "../books/states" type ScreenParams = { id: string @@ -20,18 +16,19 @@ export const CollectionDetailsScreen = () => { const theme = useTheme() const navigate = useNavigate() const { id = `-1` } = useParams() - const libraryState = useSignalValue(libraryStateSignal) - const collection = useCollectionState({ - id: id || "-1", - libraryState, - localSettingsState: useLocalSettings(), - protectedTagIds: useProtectedTagIds().data + const { data: collection } = useCollection({ + id }) - const data = - useMemo( - () => collection?.books?.map((book) => book || "-1"), - [collection?.books] - ) || [] + const visibleBooks = useVisibleBookIds({ + queryObj: { + selector: { + _id: { + $in: collection?.books ?? [] + } + } + } + }) + const { open: openActionDrawer } = useCollectionActionsDrawer( id, (changes) => { @@ -96,7 +93,7 @@ export const CollectionDetailsScreen = () => {
void open: boolean collectionId: string }> = ({ onClose, open, collectionId }) => { - const libraryState = useSignalValue(libraryStateSignal) const collection = useCollectionState({ id: collectionId || "-1", - libraryState, localSettingsState: useLocalSettings(), - protectedTagIds: useProtectedTagIds().data }) const { data: books } = useBooksAsArrayState({ - libraryState, normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ), - protectedTagIds: useProtectedTagIds().data }) const { mutate: addToBook } = useAddCollectionToBook() const { mutate: removeFromBook } = useRemoveCollectionFromBook() diff --git a/packages/web/src/collections/list/CollectionListItemList.tsx b/packages/web/src/collections/list/CollectionListItemList.tsx index 00734a92..9b3e7c58 100644 --- a/packages/web/src/collections/list/CollectionListItemList.tsx +++ b/packages/web/src/collections/list/CollectionListItemList.tsx @@ -15,9 +15,6 @@ import { CollectionDocType } from "@oboku/shared" import { Cover } from "../../books/Cover" import { useCollectionActionsDrawer } from "../CollectionActionsDrawer" import { useLocalSettings } from "../../settings/states" -import { useProtectedTagIds } from "../../tags/helpers" -import { useSignalValue } from "reactjrx" -import { libraryStateSignal } from "../../library/states" const ListItem = styled(MuiListItem)(() => ({ height: `100%`, @@ -35,12 +32,9 @@ export const CollectionListItemList: FC<{ viewMode?: "container" | "text" }> = memo(({ id, onItemClick }) => { const theme = useTheme() - const libraryState = useSignalValue(libraryStateSignal) const item = useCollectionState({ id, - libraryState, localSettingsState: useLocalSettings(), - protectedTagIds: useProtectedTagIds().data }) const { open: openActionDrawer } = useCollectionActionsDrawer(id) const styles = useStyle() diff --git a/packages/web/src/collections/list/SelectableCollectionListItem.tsx b/packages/web/src/collections/list/SelectableCollectionListItem.tsx index d3169070..d7d1ac06 100644 --- a/packages/web/src/collections/list/SelectableCollectionListItem.tsx +++ b/packages/web/src/collections/list/SelectableCollectionListItem.tsx @@ -1,7 +1,7 @@ import { FC, memo } from "react" import { ListItem, ListItemText, useTheme } from "@mui/material" import { useCSS } from "../../common/utils" -import { useCollections } from "../states" +import { useCollectionsDictionaryWithoutPrivacy } from "../states" import { Checkbox } from "../../common/Checkbox" export const SelectableCollectionListItem: FC<{ @@ -9,7 +9,7 @@ export const SelectableCollectionListItem: FC<{ onItemClick?: (tag: string) => void selected: boolean }> = memo(({ id, onItemClick, selected }) => { - const { data: collections = {} } = useCollections() + const { data: collections = {} } = useCollectionsDictionaryWithoutPrivacy() const data = collections[id] const styles = useStyle() diff --git a/packages/web/src/collections/states.ts b/packages/web/src/collections/states.ts index f0c3199e..fd264bf3 100644 --- a/packages/web/src/collections/states.ts +++ b/packages/web/src/collections/states.ts @@ -1,13 +1,11 @@ import { CollectionDocType, directives } from "@oboku/shared" -import { useVisibleBookIdsState } from "../books/states" import { useLocalSettings } from "../settings/states" -import { useProtectedTagIds } from "../tags/helpers" -import { libraryStateSignal } from "../library/states" import { useForeverQuery } from "reactjrx" import { latestDatabase$ } from "../rxdb/useCreateDatabase" import { map, switchMap } from "rxjs" import { keyBy } from "lodash" import { Database } from "../rxdb" +import { useVisibleBookIds } from "../books/states" export type Collection = CollectionDocType @@ -17,83 +15,117 @@ export const getCollectionsByIds = async (database: Database) => { return keyBy(result, "_id") } -export const useCollections = () => { +export const useCollectionsWithoutPrivacy = () => { return useForeverQuery({ queryKey: ["rxdb", "get", "collections"], queryFn: () => { return latestDatabase$.pipe( switchMap((db) => db.collections.obokucollection.find({}).$), - map((entries) => keyBy(entries, "_id")) + map((items) => items.map((item) => item.toJSON())) ) } }) } -/** - * @deprecated - */ -export const useCollectionsAsArrayState = ({ - libraryState, - localSettingsState, - protectedTagIds = [] -}: { - libraryState: ReturnType - localSettingsState: ReturnType - protectedTagIds: ReturnType["data"] -}) => { - const localSettings = localSettingsState - const { data: collections = {} } = useCollections() - const bookIds = useVisibleBookIdsState({ libraryState, protectedTagIds }) - const ids = Object.keys(collections) +export const useCollectionsDictionaryWithoutPrivacy = () => { + const result = useCollectionsWithoutPrivacy() - type Collection = NonNullable> + return { + ...result, + data: result.data ? keyBy(result.data, "_id") : undefined + } +} - return ids - .filter((id) => { - const collection = collections[id] - if (localSettings.showCollectionWithProtectedContent === "unlocked") { - const hasSomeNonVisibleBook = collection?.books.some( - (bookId) => !bookIds.includes(bookId) +export const useCollection = ({ id }: { id?: string }) => { + const localSettings = useLocalSettings() + + return useForeverQuery({ + queryKey: ["rxdb", "collection", id], + enabled: !!id, + queryFn: () => { + return latestDatabase$.pipe( + switchMap( + (db) => + db.obokucollection.findOne({ + selector: { + _id: id + } + }).$ + ), + map((value) => { + if (!value) return null + + return { + ...value?.toJSON(), + displayableName: localSettings.hideDirectivesFromCollectionName + ? directives.removeDirectiveFromString(value.name) + : value.name + } + }) + ) + } + }) +} + +export const useCollectionsWithPrivacy = () => { + const { data: collections } = useCollectionsWithoutPrivacy() + const visibleBookIds = useVisibleBookIds() + const { showCollectionWithProtectedContent } = useLocalSettings() + + return { + data: collections?.filter((collection) => { + if (showCollectionWithProtectedContent === "unlocked") { + const hasSomeNonVisibleBook = collection.books.some( + (bookId) => !visibleBookIds.includes(bookId) ) + return !hasSomeNonVisibleBook } else { const hasSomeVisibleBook = collection?.books.some((bookId) => - bookIds.includes(bookId) + visibleBookIds.includes(bookId) ) return hasSomeVisibleBook || collection?.books.length === 0 } }) - .map((id) => { - const value = getCollectionState({ - id, - normalizedCollections: collections, - localSettingsState, - bookIds - }) - - return value - }) as Collection[] + } } /** * @deprecated */ -export const useCollectionIdsState = ({ - libraryState, - localSettingsState, - protectedTagIds = [] -}: { - libraryState: ReturnType - localSettingsState: ReturnType - protectedTagIds: ReturnType["data"] -}) => { - return useCollectionsAsArrayState({ - libraryState, - localSettingsState, - protectedTagIds - }).map(({ _id }) => _id) +export const useCollectionsAsArrayState = () => { + const { data: collectionsDic = {} } = useCollectionsDictionaryWithoutPrivacy() + const visibleBookIds = useVisibleBookIds() + const localSettingsState = useLocalSettings() + + type Collection = NonNullable> + + const { data: visibleCollections = [] } = useCollectionsWithPrivacy() + + return visibleCollections.map((collection) => { + const value = getCollectionState({ + id: collection._id, + normalizedCollections: collectionsDic, + localSettingsState, + bookIds: visibleBookIds + }) + + return value + }) as Collection[] +} + +export const useVisibleCollectionIds = () => { + const { data: collections, ...rest } = useCollectionsWithPrivacy() + + return { + ...rest, + data: collections ? collections.map(({ _id }) => _id) : undefined + } } +/** + * @deprecated + */ export const getCollectionState = ({ id, localSettingsState, @@ -102,8 +134,8 @@ export const getCollectionState = ({ }: { id: string localSettingsState: ReturnType - normalizedCollections: ReturnType["data"] - bookIds: ReturnType + normalizedCollections: ReturnType["data"] + bookIds: ReturnType }) => { const collection = normalizedCollections[id] const localSettings = localSettingsState @@ -111,7 +143,7 @@ export const getCollectionState = ({ if (!collection) return undefined return { - ...collection.toJSON(), + ...collection, books: collection.books.filter((id) => bookIds.includes(id)), displayableName: localSettings.hideDirectivesFromCollectionName ? directives.removeDirectiveFromString(collection.name) @@ -124,20 +156,13 @@ export const getCollectionState = ({ */ export const useCollectionState = ({ id, - libraryState, - localSettingsState, - protectedTagIds = [] + localSettingsState }: { id: string - libraryState: ReturnType localSettingsState: ReturnType - protectedTagIds: ReturnType["data"] }) => { - const { data: normalizedCollections } = useCollections() - const bookIds = useVisibleBookIdsState({ - libraryState, - protectedTagIds - }) + const { data: normalizedCollections } = useCollectionsDictionaryWithoutPrivacy() + const bookIds = useVisibleBookIds() return getCollectionState({ id, diff --git a/packages/web/src/download/states.ts b/packages/web/src/download/states.ts index 46c60735..e716d907 100644 --- a/packages/web/src/download/states.ts +++ b/packages/web/src/download/states.ts @@ -1,4 +1,4 @@ -import { signal } from "reactjrx" +import { signal, useSignalValue } from "reactjrx" export enum DownloadState { None = "none", @@ -6,7 +6,7 @@ export enum DownloadState { Downloading = "downloading" } -export const normalizedBookDownloadsStateSignal = signal< +export const booksDownloadStateSignal = signal< Record< string, | { @@ -21,8 +21,7 @@ export const normalizedBookDownloadsStateSignal = signal< default: {} }) -export const normalizedBookDownloadsStatePersist = - normalizedBookDownloadsStateSignal +export const normalizedBookDownloadsStatePersist = booksDownloadStateSignal /** * @deprecated @@ -33,10 +32,22 @@ export const getBookDownloadsState = ({ }: { bookId: string normalizedBookDownloadsState: ReturnType< - typeof normalizedBookDownloadsStateSignal.getValue + typeof booksDownloadStateSignal.getValue > }) => normalizedBookDownloadsState[bookId] || { downloadState: DownloadState.None, downloadProgress: 0 } + +export const useBookDownloadState = (bookId?: string | null) => { + const bookDownloadState = useSignalValue(booksDownloadStateSignal) + + if (!bookId) return undefined + + return { + downloadState: DownloadState.None, + downloadProgress: 0, + ...bookDownloadState[bookId] + } +} diff --git a/packages/web/src/download/useDownloadBook.ts b/packages/web/src/download/useDownloadBook.ts index 6849ef30..f72d2063 100644 --- a/packages/web/src/download/useDownloadBook.ts +++ b/packages/web/src/download/useDownloadBook.ts @@ -1,7 +1,7 @@ import localforage from "localforage" import { useCallback } from "react" import throttle from "lodash.throttle" -import { DownloadState, normalizedBookDownloadsStateSignal } from "./states" +import { DownloadState, booksDownloadStateSignal } from "./states" import { Report } from "../debug/report.shared" import { useDatabase } from "../rxdb" import { DOWNLOAD_PREFIX } from "../constants.shared" @@ -25,10 +25,10 @@ export const useDownloadBook = () => { ( bookId: string, data: ReturnType< - typeof normalizedBookDownloadsStateSignal.getValue + typeof booksDownloadStateSignal.getValue >[number] ) => { - normalizedBookDownloadsStateSignal.setValue((prev) => ({ + booksDownloadStateSignal.setValue((prev) => ({ ...prev, [bookId]: { ...prev[bookId], diff --git a/packages/web/src/download/useRemoveDownloadFile.ts b/packages/web/src/download/useRemoveDownloadFile.ts index 82f03444..ce154adf 100644 --- a/packages/web/src/download/useRemoveDownloadFile.ts +++ b/packages/web/src/download/useRemoveDownloadFile.ts @@ -1,14 +1,14 @@ import localforage from "localforage" import { DOWNLOAD_PREFIX } from "../constants.shared" import { Report } from "../debug/report.shared" -import { DownloadState, normalizedBookDownloadsStateSignal } from "./states" +import { DownloadState, booksDownloadStateSignal } from "./states" export const useRemoveDownloadFile = () => { return async (bookId: string) => { try { await localforage.removeItem(`${DOWNLOAD_PREFIX}-${bookId}`) - normalizedBookDownloadsStateSignal.setValue((prev) => ({ + booksDownloadStateSignal.setValue((prev) => ({ ...prev, [bookId]: { ...prev[bookId], diff --git a/packages/web/src/download/useSynchronizeStateWithStorage.ts b/packages/web/src/download/useSynchronizeStateWithStorage.ts index 033edb46..a3507977 100644 --- a/packages/web/src/download/useSynchronizeStateWithStorage.ts +++ b/packages/web/src/download/useSynchronizeStateWithStorage.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect } from "react" import localforage from "localforage" import { DOWNLOAD_PREFIX } from "../constants.shared" -import { DownloadState, normalizedBookDownloadsStateSignal } from "./states" +import { DownloadState, booksDownloadStateSignal } from "./states" const getKeys = async () => (await localforage.keys()) @@ -10,7 +10,7 @@ const getKeys = async () => export const useSynchronizeStateWithStorageEffect = () => { const restoreStateForFinishedDownloadIfNeeded = useCallback(async () => { - const state = normalizedBookDownloadsStateSignal.getValue() + const state = booksDownloadStateSignal.getValue() const keys = await getKeys() await Promise.all( @@ -21,7 +21,7 @@ export const useSynchronizeStateWithStorageEffect = () => { `${DOWNLOAD_PREFIX}-${bookId}` ) if (item) { - normalizedBookDownloadsStateSignal.setValue((old) => ({ + booksDownloadStateSignal.setValue((old) => ({ ...old, [bookId]: { downloadProgress: 100, @@ -37,7 +37,7 @@ export const useSynchronizeStateWithStorageEffect = () => { const removeBooksThatAreNotPresentPhysicallyAnymore = useCallback(async () => { - const state = normalizedBookDownloadsStateSignal.getValue() + const state = booksDownloadStateSignal.getValue() const keys = await getKeys() const bookInProgressOrDownloadedButNotPresentAnymore = Object.keys( state @@ -47,7 +47,7 @@ export const useSynchronizeStateWithStorageEffect = () => { ) if (bookInProgressOrDownloadedButNotPresentAnymore.length > 0) { - normalizedBookDownloadsStateSignal.setValue((old) => + booksDownloadStateSignal.setValue((old) => Object.keys(old) .filter( (id) => diff --git a/packages/web/src/home/helpers.ts b/packages/web/src/home/helpers.ts index eb339061..094d4b73 100644 --- a/packages/web/src/home/helpers.ts +++ b/packages/web/src/home/helpers.ts @@ -2,26 +2,22 @@ import { useMemo } from "react" import { useBooksAsArrayState } from "../books/states" import { ReadingStateState } from "@oboku/shared" import { useBooksSortedBy } from "../books/helpers" -import { normalizedBookDownloadsStateSignal } from "../download/states" +import { booksDownloadStateSignal } from "../download/states" import { useProtectedTagIds } from "../tags/helpers" import { useSignalValue } from "reactjrx" -import { libraryStateSignal } from "../library/states" /** * @todo cleanup */ export const useContinueReadingBooks = () => { - const libraryState = useSignalValue(libraryStateSignal) - const { data: protectedTagIds, isPending } = useProtectedTagIds() + const { data: isPending } = useProtectedTagIds() const normalizedBookDownloadsState = useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ) const { data: booksAsArray, isPending: isBooksPending } = useBooksAsArrayState({ - libraryState, normalizedBookDownloadsState, - protectedTagIds }) const booksSortedByDate = useBooksSortedBy(booksAsArray, "activity") @@ -44,13 +40,10 @@ export const useContinueReadingBooks = () => { * @todo cleanup */ export const useRecentlyAddedBooks = () => { - const libraryState = useSignalValue(libraryStateSignal) const { data: books } = useBooksAsArrayState({ - libraryState, normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ), - protectedTagIds: useProtectedTagIds().data }) return useMemo(() => { diff --git a/packages/web/src/library/LibraryCollectionScreen.tsx b/packages/web/src/library/LibraryCollectionScreen.tsx index 0e356e01..6b34f881 100644 --- a/packages/web/src/library/LibraryCollectionScreen.tsx +++ b/packages/web/src/library/LibraryCollectionScreen.tsx @@ -12,14 +12,11 @@ import { import { ROUTES } from "../constants" import { useNavigate } from "react-router-dom" import { useCreateCollection } from "../collections/helpers" -import { useCollectionIdsState } from "../collections/states" import { useCSS, useMeasureElement } from "../common/utils" import { CollectionList } from "../collections/list/CollectionList" import { useDebouncedCallback } from "use-debounce" -import { useLocalSettings } from "../settings/states" -import { useProtectedTagIds } from "../tags/helpers" import { signal, useSignalValue } from "reactjrx" -import { libraryStateSignal } from "./states" +import { useLibraryCollections } from "./useLibraryCollections" type Scroll = Parameters< NonNullable["onScroll"]> @@ -44,12 +41,7 @@ export const LibraryCollectionScreen = () => { const libraryCollectionScreenPreviousScroll = useSignalValue( libraryCollectionScreenPreviousScrollState ) - const libraryState = useSignalValue(libraryStateSignal) - const collections = useCollectionIdsState({ - libraryState, - localSettingsState: useLocalSettings(), - protectedTagIds: useProtectedTagIds().data - }) + const { data: collections = [] } = useLibraryCollections() const onScroll = useDebouncedCallback((value: Scroll) => { libraryCollectionScreenPreviousScrollState.setValue(value) diff --git a/packages/web/src/library/useBooks.ts b/packages/web/src/library/useBooks.ts index 51c20fcc..df21116f 100644 --- a/packages/web/src/library/useBooks.ts +++ b/packages/web/src/library/useBooks.ts @@ -1,11 +1,7 @@ import { useRef } from "react" import { useBooksSortedBy } from "../books/helpers" import { useBooksAsArrayState } from "../books/states" -import { - DownloadState, - normalizedBookDownloadsStateSignal -} from "../download/states" -import { useProtectedTagIds } from "../tags/helpers" +import { DownloadState, booksDownloadStateSignal } from "../download/states" import { useSignalValue } from "reactjrx" import { libraryStateSignal } from "./states" @@ -14,11 +10,7 @@ export const useBooks = () => { const library = useSignalValue(libraryStateSignal) const filteredTags = library.tags const { data: unsortedBooks } = useBooksAsArrayState({ - libraryState: library, - normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal - ), - protectedTagIds: useProtectedTagIds().data + normalizedBookDownloadsState: useSignalValue(booksDownloadStateSignal) }) const filteredBooks = unsortedBooks.filter((book) => { diff --git a/packages/web/src/library/useLibraryCollections.ts b/packages/web/src/library/useLibraryCollections.ts new file mode 100644 index 00000000..e25b3e20 --- /dev/null +++ b/packages/web/src/library/useLibraryCollections.ts @@ -0,0 +1,28 @@ +import { useCollectionsWithPrivacy } from "../collections/states" +import { useBooks } from "../books/states" +import { useMemo } from "react" + +export const useLibraryCollections = () => { + const { data: visibleCollections } = useCollectionsWithPrivacy() + const { data: books } = useBooks() + + const collectionIds = useMemo( + () => + visibleCollections + ?.filter((collection) => { + if (collection.books.length === 0 || !books?.length) return true + + const hasOneInterestedBook = collection.books.some((bookId) => { + const book = books?.find((item) => item._id === bookId) + + return !book?.isNotInterested + }) + + return hasOneInterestedBook + }) + .map((collection) => collection._id), + [visibleCollections, books] + ) + + return { data: collectionIds } +} diff --git a/packages/web/src/settings/ManageStorageScreen.tsx b/packages/web/src/settings/ManageStorageScreen.tsx index 393ccb18..26d17472 100644 --- a/packages/web/src/settings/ManageStorageScreen.tsx +++ b/packages/web/src/settings/ManageStorageScreen.tsx @@ -19,7 +19,7 @@ import { LibraryViewMode } from "../rxdb" import { BookList } from "../books/bookList/BookList" import { useDownloadedBookWithUnsafeProtectedIdsState, - useVisibleBookIdsState + useVisibleBookIds } from "../books/states" import { bookActionDrawerSignal } from "../books/drawer/BookActionsDrawer" import { useDownloadedFilesInfo } from "../download/useDownloadedFilesInfo" @@ -30,21 +30,16 @@ import { Report } from "../debug/report.shared" import { useEffect } from "react" import { useMutation, useSignalValue } from "reactjrx" import { useRemoveAllDownloadedFiles } from "../download/useRemoveAllDownloadedFiles" -import { useProtectedTagIds } from "../tags/helpers" import { libraryStateSignal } from "../library/states" -import { normalizedBookDownloadsStateSignal } from "../download/states" +import { booksDownloadStateSignal } from "../download/states" export const ManageStorageScreen = () => { const bookIds = useDownloadedBookWithUnsafeProtectedIdsState({ normalizedBookDownloadsState: useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ) }) - const libraryState = useSignalValue(libraryStateSignal) - const visibleBookIds = useVisibleBookIdsState({ - libraryState, - protectedTagIds: useProtectedTagIds().data - }) + const visibleBookIds = useVisibleBookIds() const { quotaUsed, quotaInGb, usedInMb } = useStorageUse([bookIds]) const removeDownloadFile = useRemoveDownloadFile() const deleteAllDownloadedFiles = useRemoveAllDownloadedFiles() diff --git a/packages/web/src/settings/ProfileScreen.tsx b/packages/web/src/settings/ProfileScreen.tsx index 8ed21030..9ecfe7f6 100644 --- a/packages/web/src/settings/ProfileScreen.tsx +++ b/packages/web/src/settings/ProfileScreen.tsx @@ -100,7 +100,11 @@ export const ProfileScreen = () => { ? "Change app password" : "Initialize app password" } - secondary="When set, it will be used to authorize sensitive actions" + secondary={ + accountSettings?.contentPassword + ? "Used to authorize sensitive actions" + : "When set, it will be used to authorize sensitive actions" + } /> diff --git a/packages/web/src/settings/SettingsScreen.tsx b/packages/web/src/settings/SettingsScreen.tsx index 3d0bd275..f7ab1f3c 100644 --- a/packages/web/src/settings/SettingsScreen.tsx +++ b/packages/web/src/settings/SettingsScreen.tsx @@ -29,8 +29,8 @@ const showCollectionWithProtectedContentLabels: Record< LocalSettings["showCollectionWithProtectedContent"], string > = { - unlocked: "Only when protected content are unlocked", - hasNormalContent: "If the collection has non protected content as well" + unlocked: "If protected contents are unlocked only (privacy)", + hasNormalContent: "If collection has non protected content as well" } export const SettingsScreen = memo(() => { @@ -103,7 +103,7 @@ export const SettingsScreen = memo(() => { }} > { const bookIds = useBookIdsState() - const libraryState = useSignalValue(libraryStateSignal) - const collectionsAsArray = useCollectionsAsArrayState({ - libraryState, - localSettingsState: useLocalSettings(), - protectedTagIds: useProtectedTagIds().data - }) + const collectionsAsArray = useCollectionsAsArrayState() return ( <> diff --git a/packages/web/src/settings/helpers.ts b/packages/web/src/settings/helpers.ts index 83064847..594bef9c 100644 --- a/packages/web/src/settings/helpers.ts +++ b/packages/web/src/settings/helpers.ts @@ -78,6 +78,7 @@ export const useSettings = ( * Since the query is a live stream the data are always fresh anyway. */ gcTime: Infinity, + staleTime: Infinity, ...options }) diff --git a/packages/web/src/tags/ManageTagBooksDialog.tsx b/packages/web/src/tags/ManageTagBooksDialog.tsx index d988745c..da165516 100644 --- a/packages/web/src/tags/ManageTagBooksDialog.tsx +++ b/packages/web/src/tags/ManageTagBooksDialog.tsx @@ -3,10 +3,9 @@ import { useRemoveTagFromBook, useAddTagToBook } from "../books/helpers" import { useBooksAsArrayState } from "../books/states" import { useCallback } from "react" import { BooksSelectionDialog } from "../books/BooksSelectionDialog" -import { useProtectedTagIds, useTag } from "./helpers" -import { normalizedBookDownloadsStateSignal } from "../download/states" +import { useTag } from "./helpers" +import { booksDownloadStateSignal } from "../download/states" import { signal, useSignalValue } from "reactjrx" -import { libraryStateSignal } from "../library/states" export const isManageTagBooksDialogOpenedWithState = signal( { @@ -20,15 +19,12 @@ export const ManageTagBooksDialog: FC<{}> = () => { isManageTagBooksDialogOpenedWithState ) const { data: tag } = useTag(isManageTagBooksDialogOpenedWith || "-1") - const libraryState = useSignalValue(libraryStateSignal) const normalizedBookDownloadsState = useSignalValue( - normalizedBookDownloadsStateSignal + booksDownloadStateSignal ) const { data: books } = useBooksAsArrayState({ - libraryState, normalizedBookDownloadsState, - protectedTagIds: useProtectedTagIds().data }) const { mutate: addTagToBook } = useAddTagToBook() const { mutate: removeFromBook } = useRemoveTagFromBook() diff --git a/packages/web/src/tags/helpers.ts b/packages/web/src/tags/helpers.ts index 1410c7ce..53341c61 100644 --- a/packages/web/src/tags/helpers.ts +++ b/packages/web/src/tags/helpers.ts @@ -139,9 +139,10 @@ export const useBlurredTagIds = () => queryKey: ["blurredTagIds"] }) -export const useProtectedTagIds = () => +export const useProtectedTagIds = (options: { enabled?: boolean } = {}) => useForeverQuery({ + queryKey: ["protectedTagIds"], queryFn: () => protectedTags$.pipe(map((tags) => tags.map(({ _id }) => _id))), - queryKey: ["protectedTagIds"] + ...options })