Skip to content

Commit

Permalink
refactor: split add and delete bookmark api (quran#1797)
Browse files Browse the repository at this point in the history
* refactor: split add and delete bookmark api

* fix cache issue

* .
  • Loading branch information
muhajirdev authored Sep 15, 2022
1 parent 91c024a commit c5a8761
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 94 deletions.
31 changes: 14 additions & 17 deletions src/components/QuranReader/TranslationView/BookmarkIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import BookmarkedIcon from '@/icons/bookmark.svg';
import { selectBookmarks, toggleVerseBookmark } from '@/redux/slices/QuranReader/bookmarks';
import { selectQuranReaderStyles } from '@/redux/slices/QuranReader/styles';
import { getMushafId } from '@/utils/api';
import { addOrRemoveBookmark } from '@/utils/auth/api';
import { makeIsResourceBookmarkedUrl } from '@/utils/auth/apiPaths';
import { deleteBookmarkById } from '@/utils/auth/api';
import { makeBookmarkUrl } from '@/utils/auth/apiPaths';
import { isLoggedIn } from '@/utils/auth/login';
import { logButtonClick } from '@/utils/eventLogger';
import BookmarksMap from 'types/BookmarksMap';
Expand Down Expand Up @@ -62,31 +62,28 @@ const BookmarkIcon: React.FC<Props> = ({ verse, pageBookmarks, bookmarksRangeUrl
});

cache.delete(
makeIsResourceBookmarkedUrl(
makeBookmarkUrl(
mushafId,
Number(verse.chapterId),
BookmarkType.Ayah,
Number(verse.verseNumber),
),
);

addOrRemoveBookmark({
key: Number(verse.chapterId),
mushafId,
type: BookmarkType.Ayah,
isAdd: false,
verseNumber: verse.verseNumber,
}).catch((err) => {
if (err.status === 400) {
toast(t('common:error.bookmark-sync'), {
const bookmarkId = pageBookmarks[verse.verseKey].id;
if (bookmarkId) {
deleteBookmarkById(bookmarkId).catch((err) => {
if (err.status === 400) {
toast(t('common:error.bookmark-sync'), {
status: ToastStatus.Error,
});
return;
}
toast(t('common:error.general'), {
status: ToastStatus.Error,
});
return;
}
toast(t('common:error.general'), {
status: ToastStatus.Error,
});
});
}
} else {
dispatch(toggleVerseBookmark(verse.verseKey));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,26 +100,24 @@ const TranslationPage: React.FC<Props> = ({
);

const mushafId = getMushafId(quranReaderStyles.quranFont, quranReaderStyles.mushafLines).mushaf;
const bookmarksRangeUrl = verses
? makeBookmarksRangeUrl(
mushafId,
Number(verses[0].chapterId),
Number(verses[0].verseNumber),
initialData.pagination.perPage,
)
: '';
const { data: pageBookmarks } = useSWRImmutable(
verses && isLoggedIn() ? bookmarksRangeUrl : null,
async () => {
const response = await getPageBookmarks(
mushafId,
Number(verses[0].chapterId),
Number(verses[0].verseNumber),
initialData.pagination.perPage,
);
return response;
},
);
const bookmarksRangeUrl =
verses && verses.length && isLoggedIn()
? makeBookmarksRangeUrl(
mushafId,
Number(verses?.[0].chapterId),
Number(verses?.[0].verseNumber),
initialData.pagination.perPage,
)
: null;
const { data: pageBookmarks } = useSWRImmutable(bookmarksRangeUrl, async () => {
const response = await getPageBookmarks(
mushafId,
Number(verses[0].chapterId),
Number(verses[0].verseNumber),
initialData.pagination.perPage,
);
return response;
});

useEffect(() => {
if (verses) {
Expand Down
93 changes: 55 additions & 38 deletions src/components/Verse/BookmarkAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { ToastStatus, useToast } from 'src/components/dls/Toast/Toast';
import { selectBookmarks, toggleVerseBookmark } from 'src/redux/slices/QuranReader/bookmarks';
import { selectQuranReaderStyles } from 'src/redux/slices/QuranReader/styles';
import { getMushafId } from 'src/utils/api';
import { addOrRemoveBookmark, getIsResourceBookmarked } from 'src/utils/auth/api';
import { makeBookmarksUrl, makeIsResourceBookmarkedUrl } from 'src/utils/auth/apiPaths';
import { addBookmark, deleteBookmarkById, getBookmark } from 'src/utils/auth/api';
import { makeBookmarksUrl, makeBookmarkUrl } from 'src/utils/auth/apiPaths';
import { isLoggedIn } from 'src/utils/auth/login';
import { logButtonClick } from 'src/utils/eventLogger';
import BookmarkType from 'types/BookmarkType';
Expand All @@ -33,20 +33,20 @@ const BookmarkAction = ({ verse, isTranslationView, onActionTriggered, bookmarks
const { cache, mutate: globalMutate } = useSWRConfig();

const {
data: isVerseBookmarkedData,
data: bookmark,
isValidating: isVerseBookmarkedLoading,
mutate,
} = useSWRImmutable(
isLoggedIn()
? makeIsResourceBookmarkedUrl(
? makeBookmarkUrl(
mushafId,
Number(verse.chapterId),
BookmarkType.Ayah,
Number(verse.verseNumber),
)
: null,
async () => {
const response = await getIsResourceBookmarked(
const response = await getBookmark(
mushafId,
Number(verse.chapterId),
BookmarkType.Ayah,
Expand All @@ -57,14 +57,28 @@ const BookmarkAction = ({ verse, isTranslationView, onActionTriggered, bookmarks
);
const isVerseBookmarked = useMemo(() => {
const isUserLoggedIn = isLoggedIn();
if (isUserLoggedIn && isVerseBookmarkedData) {
return isVerseBookmarkedData;
if (isUserLoggedIn && bookmark) {
return bookmark;
}
if (!isUserLoggedIn) {
return !!bookmarkedVerses[verse.verseKey];
}
return false;
}, [bookmarkedVerses, isVerseBookmarkedData, verse.verseKey]);
}, [bookmarkedVerses, bookmark, verse.verseKey]);

const updateInBookmarkRange = (value) => {
// when it's translation view, we need to invalidate the cached bookmarks range
if (bookmarksRangeUrl) {
const bookmarkedVersesRange = cache.get(bookmarksRangeUrl);
const nextBookmarkedVersesRange = {
...bookmarkedVersesRange,
[verse.verseKey]: value,
};
globalMutate(bookmarksRangeUrl, nextBookmarkedVersesRange, {
revalidate: false,
});
}
};

const onToggleBookmarkClicked = () => {
// eslint-disable-next-line i18next/no-literal-string
Expand All @@ -77,18 +91,9 @@ const BookmarkAction = ({ verse, isTranslationView, onActionTriggered, bookmarks

if (isLoggedIn()) {
// optimistic update, we are making assumption that the bookmark update will succeed
mutate((currentIsVerseBookmarked) => !currentIsVerseBookmarked, {
revalidate: false,
});

// when it's translation view, we need to invalidate the cached bookmarks range
if (bookmarksRangeUrl) {
const bookmarkedVersesRange = cache.get(bookmarksRangeUrl);
const nextBookmarkedVersesRange = {
...bookmarkedVersesRange,
[verse.verseKey]: !isVerseBookmarked,
};
globalMutate(bookmarksRangeUrl, nextBookmarkedVersesRange, {
if (isVerseBookmarked) {
mutate(() => null, {
revalidate: false,
});
}
Expand All @@ -99,27 +104,39 @@ const BookmarkAction = ({ verse, isTranslationView, onActionTriggered, bookmarks
),
);

toast(isVerseBookmarked ? t('verse-bookmark-removed') : t('verse-bookmarked'), {
status: ToastStatus.Success,
});

addOrRemoveBookmark({
key: Number(verse.chapterId),
mushafId,
type: BookmarkType.Ayah,
isAdd: !isVerseBookmarked,
verseNumber: verse.verseNumber,
}).catch((err) => {
if (err.status === 400) {
toast(t('common:error.bookmark-sync'), {
status: ToastStatus.Error,
if (!isVerseBookmarked) {
addBookmark({
key: Number(verse.chapterId),
mushafId,
type: BookmarkType.Ayah,
verseNumber: verse.verseNumber,
})
.then((newBookmark) => {
mutate();
updateInBookmarkRange(newBookmark);
toast(t('verse-bookmarked'), {
status: ToastStatus.Success,
});
})
.catch((err) => {
if (err.status === 400) {
toast(t('common:error.bookmark-sync'), {
status: ToastStatus.Error,
});
return;
}
toast(t('error.general'), {
status: ToastStatus.Error,
});
});
} else {
deleteBookmarkById(bookmark.id).then(() => {
updateInBookmarkRange(null);
toast(t('verse-bookmark-removed'), {
status: ToastStatus.Success,
});
return;
}
toast(t('error.general'), {
status: ToastStatus.Error,
});
});
}
} else {
dispatch(toggleVerseBookmark(verse.verseKey));
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Verse/SaveToCollectionAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
makeBookmarkCollectionsUrl,
makeBookmarksUrl,
makeCollectionsUrl,
makeIsResourceBookmarkedUrl,
makeBookmarkUrl,
} from 'src/utils/auth/apiPaths';
import { isLoggedIn } from 'src/utils/auth/login';
import { logButtonClick } from 'src/utils/eventLogger';
Expand Down Expand Up @@ -82,7 +82,7 @@ const SaveToCollectionAction = ({ verse, bookmarksRangeUrl }) => {
return;
}
globalSWRMutate(
makeIsResourceBookmarkedUrl(
makeBookmarkUrl(
mushafId,
Number(verse.chapterId),
BookmarkType.Ayah,
Expand Down
20 changes: 6 additions & 14 deletions src/utils/auth/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
makeUserProfileUrl,
makeDeleteAccountUrl,
makeBookmarksRangeUrl,
makeIsResourceBookmarkedUrl,
makeBookmarkUrl,
makeReadingSessionsUrl,
makeUserPreferencesUrl,
makeVerificationCodeUrl,
Expand Down Expand Up @@ -38,6 +38,7 @@ import SyncDataType from 'types/auth/SyncDataType';
import SyncUserLocalDataResponse from 'types/auth/SyncUserLocalDataResponse';
import UserPreferencesResponse from 'types/auth/UserPreferencesResponse';
import UserProfile from 'types/auth/UserProfile';
import Bookmark from 'types/Bookmark';
import BookmarksMap from 'types/BookmarksMap';
import BookmarkType from 'types/BookmarkType';
import { Collection } from 'types/Collection';
Expand Down Expand Up @@ -97,27 +98,19 @@ export const completeAnnouncement = async (data: CompleteAnnouncementRequest): P

export const deleteAccount = async (): Promise<void> => deleteRequest(makeDeleteAccountUrl());

type AddOrRemoveBookmarkParams = {
type AddBookmarkParams = {
key: number;
mushafId: number;
type: BookmarkType;
isAdd: boolean;
verseNumber?: number;
};

export const addOrRemoveBookmark = async ({
key,
mushafId,
type,
verseNumber,
isAdd,
}: AddOrRemoveBookmarkParams) =>
export const addBookmark = async ({ key, mushafId, type, verseNumber }: AddBookmarkParams) =>
postRequest(makeBookmarksUrl(mushafId), {
key,
mushaf: mushafId,
type,
verseNumber,
isAdd,
});

export const getPageBookmarks = async (
Expand All @@ -128,13 +121,12 @@ export const getPageBookmarks = async (
): Promise<BookmarksMap> =>
privateFetcher(makeBookmarksRangeUrl(mushafId, chapterNumber, verseNumber, perPage));

export const getIsResourceBookmarked = async (
export const getBookmark = async (
mushafId: number,
key: number,
type: BookmarkType,
verseNumber?: number,
): Promise<boolean> =>
privateFetcher(makeIsResourceBookmarkedUrl(mushafId, key, type, verseNumber));
): Promise<Bookmark> => privateFetcher(makeBookmarkUrl(mushafId, key, type, verseNumber));

export const getBookmarkCollections = async (
mushafId: number,
Expand Down
4 changes: 2 additions & 2 deletions src/utils/auth/apiPaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ export const makeBookmarksRangeUrl = (
perPage: number,
): string => makeUrl('bookmarks/ayahs-range', { mushafId, chapterNumber, verseNumber, perPage });

export const makeIsResourceBookmarkedUrl = (
export const makeBookmarkUrl = (
mushafId: number,
key: number,
type: BookmarkType,
verseNumber?: number,
): string =>
makeUrl('bookmarks/is-bookmarked', { mushafId, key, type, ...(verseNumber && { verseNumber }) });
makeUrl('bookmarks/bookmark', { mushafId, key, type, ...(verseNumber && { verseNumber }) });

export const makeReadingSessionsUrl = () => makeUrl('reading-sessions');

Expand Down
4 changes: 3 additions & 1 deletion types/BookmarksMap.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
type BookmarksMap = Record<string, boolean>;
import Bookmark from './Bookmark';

type BookmarksMap = Record<string, Bookmark>;
export default BookmarksMap;

0 comments on commit c5a8761

Please sign in to comment.