-
-
Notifications
You must be signed in to change notification settings - Fork 528
[QF-3097] bookmark icons sync issue #2582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,10 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /* eslint-disable max-lines */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import classNames from 'classnames'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useRouter } from 'next/router'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import useTranslation from 'next-translate/useTranslation'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { shallowEqual, useSelector } from 'react-redux'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useSWRConfig } from 'swr'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import useSWRInfinite from 'swr/infinite'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import layoutStyles from '../../../pages/index.module.scss'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -12,6 +16,10 @@ import Spinner, { SpinnerSize } from '@/dls/Spinner/Spinner'; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ToastStatus, useToast } from '@/dls/Toast/Toast'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ArrowLeft from '@/icons/west.svg'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Error from '@/pages/_error'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { selectQuranReaderStyles } from '@/redux/slices/QuranReader/styles'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import BookmarkType from '@/types/BookmarkType'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getMushafId } from '@/utils/api'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { makeBookmarkCollectionsUrl, makeBookmarkUrl } from '@/utils/auth/apiPaths'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { logButtonClick } from '@/utils/eventLogger'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getLanguageAlternates } from '@/utils/locale'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -50,6 +58,10 @@ const CollectionDetailContainer = ({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const collectionId = router.query.collectionId as string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const toast = useToast(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const quranReaderStyles = useSelector(selectQuranReaderStyles, shallowEqual); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { cache } = useSWRConfig(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data, size, setSize, mutate, isValidating, error } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useSWRInfinite<GetBookmarkCollectionsIdResponse>(getSWRKey, privateFetcher); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -65,8 +77,21 @@ const CollectionDetailContainer = ({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const onUpdated = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const onUpdated = (bookmarkId: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mutate(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mushafId = getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const bookmark = bookmarks.find((b) => b.id === bookmarkId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (bookmark) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cache.delete( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| makeBookmarkUrl(mushafId, bookmark.key, BookmarkType.Ayah, bookmark.verseNumber), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cache.delete( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| makeBookmarkCollectionsUrl(mushafId, bookmark.key, BookmarkType.Ayah, bookmark.verseNumber), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+80
to
95
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial LGTM: Cache invalidation correctly implemented. The cache invalidation logic properly:
The conditional cache deletion is acceptable since the bookmark may not be in the currently loaded pages (due to pagination). Optional: Consider memoizing mushafId at component level for consistency. For consistency with the broader caching strategy and to avoid recomputing mushafId on every deletion: +const mushafId = useMemo(
+ () => getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf,
+ [quranReaderStyles.quranFont, quranReaderStyles.mushafLines]
+);
+
const onUpdated = (bookmarkId: string) => {
mutate();
- const mushafId = getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf;
const bookmark = bookmarks.find((b) => b.id === bookmarkId);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const lastPageData = data[data.length - 1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -90,7 +115,7 @@ const CollectionDetailContainer = ({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (shouldDeleteBookmark) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deleteBookmarkById(bookmarkId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .then(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUpdated(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUpdated(bookmarkId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .catch(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toast(t('common:error.general'), { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -100,7 +125,7 @@ const CollectionDetailContainer = ({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deleteCollectionBookmarkById(collectionId, bookmarkId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .then(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUpdated(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUpdated(bookmarkId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .catch(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toast(t('common:error.general'), { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,13 @@ | ||
| /* eslint-disable max-lines */ | ||
| /* eslint-disable max-lines, react-func/max-lines-per-function */ | ||
| /* eslint-disable jsx-a11y/no-static-element-interactions */ | ||
| /* eslint-disable jsx-a11y/click-events-have-key-events */ | ||
| /* eslint-disable jsx-a11y/anchor-is-valid */ | ||
|
|
||
|
Comment on lines
+1
to
+5
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider refactoring to remove eslint-disable directives. Multiple eslint-disable directives indicate code quality concerns:
Per coding guidelines, components should be small, focused, and accessible. Consider splitting this component and addressing the accessibility issues. 🤖 Prompt for AI Agents |
||
| import React, { useMemo } from 'react'; | ||
|
|
||
| import useTranslation from 'next-translate/useTranslation'; | ||
| import { shallowEqual, useSelector, useDispatch } from 'react-redux'; | ||
| import useSWR from 'swr'; | ||
| import useSWR, { useSWRConfig } from 'swr'; | ||
|
|
||
| import styles from './BookmarkedVersesList.module.scss'; | ||
| import BookmarkedVersesListSkeleton from './BookmarkedVesesListSkeleton'; | ||
|
|
@@ -16,9 +17,14 @@ import Link from '@/dls/Link/Link'; | |
| import { ToastStatus, useToast } from '@/dls/Toast/Toast'; | ||
| import { selectBookmarks, toggleVerseBookmark } from '@/redux/slices/QuranReader/bookmarks'; | ||
| import { selectQuranReaderStyles } from '@/redux/slices/QuranReader/styles'; | ||
| import BookmarkType from '@/types/BookmarkType'; | ||
| import { getMushafId } from '@/utils/api'; | ||
| import { deleteBookmarkById, privateFetcher } from '@/utils/auth/api'; | ||
| import { makeBookmarksUrl } from '@/utils/auth/apiPaths'; | ||
| import { | ||
| makeBookmarkCollectionsUrl, | ||
| makeBookmarksUrl, | ||
| makeBookmarkUrl, | ||
| } from '@/utils/auth/apiPaths'; | ||
| import { isLoggedIn } from '@/utils/auth/login'; | ||
| import { logButtonClick } from '@/utils/eventLogger'; | ||
| import { getVerseAndChapterNumbersFromKey, makeVerseKey } from '@/utils/verse'; | ||
|
|
@@ -31,17 +37,17 @@ const BookmarkedVersesList = () => { | |
|
|
||
| const quranReaderStyles = useSelector(selectQuranReaderStyles, shallowEqual); | ||
| const dispatch = useDispatch(); | ||
| const { cache } = useSWRConfig(); | ||
|
|
||
| const toast = useToast(); | ||
|
|
||
| const bookmarkedVerses = useSelector(selectBookmarks, shallowEqual); | ||
|
|
||
| const mushafId = getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf; | ||
|
|
||
|
Comment on lines
+46
to
+47
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider memoizing mushafId for performance. The mushafId is recomputed on every render. While the performance impact is minimal, wrapping it in +const mushafId = useMemo(
+ () => getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf,
+ [quranReaderStyles.quranFont, quranReaderStyles.mushafLines]
+);
-const mushafId = getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf;
🤖 Prompt for AI Agents |
||
| const { data, isValidating, mutate } = useSWR<Bookmark[]>( | ||
| isLoggedIn() // only fetch the data when user is loggedIn | ||
| ? makeBookmarksUrl( | ||
| getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf, | ||
| BOOKMARKS_API_LIMIT, | ||
| ) | ||
| ? makeBookmarksUrl(mushafId, BOOKMARKS_API_LIMIT) | ||
| : null, | ||
| privateFetcher, | ||
| ); | ||
|
|
@@ -73,6 +79,7 @@ const BookmarkedVersesList = () => { | |
|
|
||
| const onBookmarkDeleted = (verseKey: string) => { | ||
| logButtonClick('bookmarked_verses_list_delete'); | ||
|
|
||
| if (isLoggedIn()) { | ||
| const selectedBookmark = data.find((bookmark) => { | ||
| const [chapter, verseNumber] = getVerseAndChapterNumbersFromKey(verseKey); | ||
|
|
@@ -82,9 +89,29 @@ const BookmarkedVersesList = () => { | |
| ); | ||
| }); | ||
|
|
||
| if (!selectedBookmark) return; | ||
|
|
||
| deleteBookmarkById(selectedBookmark.id) | ||
| .then(() => { | ||
| mutate(); | ||
|
|
||
| cache.delete( | ||
| makeBookmarkUrl( | ||
| mushafId, | ||
| selectedBookmark.key, | ||
| BookmarkType.Ayah, | ||
| selectedBookmark.verseNumber, | ||
| ), | ||
| ); | ||
|
|
||
| cache.delete( | ||
| makeBookmarkCollectionsUrl( | ||
| mushafId, | ||
| selectedBookmark.key, | ||
| BookmarkType.Ayah, | ||
| selectedBookmark.verseNumber, | ||
| ), | ||
| ); | ||
| }) | ||
| .catch(() => { | ||
| toast(t('common:error.general'), { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider refactoring to address max-lines violation.
The
max-linesdisable suggests this component exceeds recommended size limits. Per coding guidelines, components should follow the single responsibility principle and be split when they become too complex.🤖 Prompt for AI Agents