aboutsummaryrefslogtreecommitdiffstats
path: root/packages/mobile/components/bookmarks
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-03-13 14:33:54 +0000
committerMohamedBassem <me@mbassem.com>2024-03-13 14:43:52 +0000
commita2ca7db052c0ce20b404f6f81b691850b3318b97 (patch)
treed060d3a541f0305c1df7e88ac321e6166d8000d9 /packages/mobile/components/bookmarks
parent408984d9325f12937ac5747505370dec26e46d3f (diff)
downloadkarakeep-a2ca7db052c0ce20b404f6f81b691850b3318b97.tar.zst
mobile: Optimistic UI updates on actions
Diffstat (limited to 'packages/mobile/components/bookmarks')
-rw-r--r--packages/mobile/components/bookmarks/BookmarkCard.tsx51
-rw-r--r--packages/mobile/components/bookmarks/BookmarkList.tsx23
2 files changed, 49 insertions, 25 deletions
diff --git a/packages/mobile/components/bookmarks/BookmarkCard.tsx b/packages/mobile/components/bookmarks/BookmarkCard.tsx
index ae0d8a33..b3ddf302 100644
--- a/packages/mobile/components/bookmarks/BookmarkCard.tsx
+++ b/packages/mobile/components/bookmarks/BookmarkCard.tsx
@@ -1,10 +1,12 @@
import { ZBookmark } from "@hoarder/trpc/types/bookmarks";
import * as WebBrowser from "expo-web-browser";
-import { Star, Archive, Trash } from "lucide-react-native";
+import { Star, Archive, Trash, ArchiveRestore } from "lucide-react-native";
import { View, Text, Image, ScrollView, Pressable } from "react-native";
import Markdown from "react-native-markdown-display";
+import { ActionButton } from "../ui/ActionButton";
import { Skeleton } from "../ui/Skeleton";
+import { useToast } from "../ui/Toast";
import { api } from "@/lib/trpc";
@@ -30,20 +32,39 @@ export function isBookmarkStillLoading(bookmark: ZBookmark) {
}
function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
+ const { toast } = useToast();
const apiUtils = api.useUtils();
- const { mutate: deleteBookmark } = api.bookmarks.deleteBookmark.useMutation({
- onSuccess: () => {
- apiUtils.bookmarks.getBookmarks.invalidate();
- },
- });
- const { mutate: updateBookmark, variables } =
- api.bookmarks.updateBookmark.useMutation({
+ const { mutate: deleteBookmark, isPending: isDeletionPending } =
+ api.bookmarks.deleteBookmark.useMutation({
onSuccess: () => {
apiUtils.bookmarks.getBookmarks.invalidate();
- apiUtils.bookmarks.getBookmark.invalidate({ bookmarkId: bookmark.id });
+ },
+ onError: () => {
+ toast({
+ message: "Something went wrong",
+ variant: "destructive",
+ showProgress: false,
+ });
},
});
+ const {
+ mutate: updateBookmark,
+ variables,
+ isPending: isUpdatePending,
+ } = api.bookmarks.updateBookmark.useMutation({
+ onSuccess: () => {
+ apiUtils.bookmarks.getBookmarks.invalidate();
+ apiUtils.bookmarks.getBookmark.invalidate({ bookmarkId: bookmark.id });
+ },
+ onError: () => {
+ toast({
+ message: "Something went wrong",
+ variant: "destructive",
+ showProgress: false,
+ });
+ },
+ });
return (
<View className="flex flex-row gap-4">
@@ -61,7 +82,8 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
<Star />
)}
</Pressable>
- <Pressable
+ <ActionButton
+ loading={isUpdatePending}
onPress={() =>
updateBookmark({
bookmarkId: bookmark.id,
@@ -69,9 +91,10 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
})
}
>
- <Archive />
- </Pressable>
- <Pressable
+ {bookmark.archived ? <ArchiveRestore /> : <Archive />}
+ </ActionButton>
+ <ActionButton
+ loading={isDeletionPending}
onPress={() =>
deleteBookmark({
bookmarkId: bookmark.id,
@@ -79,7 +102,7 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
}
>
<Trash />
- </Pressable>
+ </ActionButton>
</View>
);
}
diff --git a/packages/mobile/components/bookmarks/BookmarkList.tsx b/packages/mobile/components/bookmarks/BookmarkList.tsx
index 519ec47c..af5c9de7 100644
--- a/packages/mobile/components/bookmarks/BookmarkList.tsx
+++ b/packages/mobile/components/bookmarks/BookmarkList.tsx
@@ -1,5 +1,6 @@
import { useEffect, useState } from "react";
-import { FlatList, Text, View } from "react-native";
+import { Text, View } from "react-native";
+import Animated, { LinearTransition } from "react-native-reanimated";
import BookmarkCard from "./BookmarkCard";
@@ -37,25 +38,25 @@ export default function BookmarkList({
apiUtils.bookmarks.getBookmark.invalidate();
};
- if (!data.bookmarks.length) {
- return (
- <View className="h-full items-center justify-center">
- <Text className="text-xl">No Bookmarks</Text>
- </View>
- );
- }
-
return (
- <FlatList
+ <Animated.FlatList
+ itemLayoutAnimation={LinearTransition}
contentContainerStyle={{
gap: 15,
marginVertical: 15,
alignItems: "center",
+ height: "100%",
}}
- renderItem={(b) => <BookmarkCard key={b.item.id} bookmark={b.item} />}
+ renderItem={(b) => <BookmarkCard bookmark={b.item} />}
+ ListEmptyComponent={
+ <View className="h-full items-center justify-center">
+ <Text className="text-xl">No Bookmarks</Text>
+ </View>
+ }
data={data.bookmarks}
refreshing={refreshing}
onRefresh={onRefresh}
+ keyExtractor={(b) => b.id}
/>
);
}