aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mobile/components/bookmarks
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-07-28 20:03:15 -0700
committerMohamedBassem <me@mbassem.com>2024-07-28 20:56:27 -0700
commit93afb75619a02aa741b464634911b994620092be (patch)
tree414eb0b184027c67b01112caa56c039f2d82aebf /apps/mobile/components/bookmarks
parent92c92c161b3195bdfb571284e783f39f369a25a5 (diff)
downloadkarakeep-93afb75619a02aa741b464634911b994620092be.tar.zst
feat(mobile): Add ability to manage lists
Diffstat (limited to 'apps/mobile/components/bookmarks')
-rw-r--r--apps/mobile/components/bookmarks/BookmarkCard.tsx20
-rw-r--r--apps/mobile/components/bookmarks/ListPickerModal.tsx117
2 files changed, 137 insertions, 0 deletions
diff --git a/apps/mobile/components/bookmarks/BookmarkCard.tsx b/apps/mobile/components/bookmarks/BookmarkCard.tsx
index 8faa8618..3be1f9a0 100644
--- a/apps/mobile/components/bookmarks/BookmarkCard.tsx
+++ b/apps/mobile/components/bookmarks/BookmarkCard.tsx
@@ -1,3 +1,4 @@
+import { useRef } from "react";
import {
ActivityIndicator,
Image,
@@ -13,6 +14,7 @@ import { Link } from "expo-router";
import * as WebBrowser from "expo-web-browser";
import useAppSettings from "@/lib/settings";
import { api } from "@/lib/trpc";
+import { BottomSheetModal } from "@gorhom/bottom-sheet";
import { MenuView } from "@react-native-menu/menu";
import { Ellipsis, Star } from "lucide-react-native";
@@ -32,6 +34,7 @@ import { TailwindResolver } from "../TailwindResolver";
import { Divider } from "../ui/Divider";
import { Skeleton } from "../ui/Skeleton";
import { useToast } from "../ui/Toast";
+import ListPickerModal from "./ListPickerModal";
function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
const { toast } = useToast();
@@ -70,6 +73,8 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
onError,
});
+ const manageListsSheetRef = useRef<BottomSheetModal>(null);
+
return (
<View className="flex flex-row gap-4">
{(isArchivePending || isDeletionPending) && <ActivityIndicator />}
@@ -89,6 +94,12 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
)}
</Pressable>
+ <ListPickerModal
+ ref={manageListsSheetRef}
+ snapPoints={["50%", "90%"]}
+ bookmarkId={bookmark.id}
+ />
+
<MenuView
onPressAction={({ nativeEvent }) => {
Haptics.selectionAsync();
@@ -101,6 +112,8 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
bookmarkId: bookmark.id,
archived: !bookmark.archived,
});
+ } else if (nativeEvent.event === "manage_list") {
+ manageListsSheetRef?.current?.present();
}
}}
actions={[
@@ -121,6 +134,13 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
ios: "trash",
}),
},
+ {
+ id: "manage_list",
+ title: "Manage Lists",
+ image: Platform.select({
+ ios: "list",
+ }),
+ },
]}
shouldOpenOnLongPress={false}
>
diff --git a/apps/mobile/components/bookmarks/ListPickerModal.tsx b/apps/mobile/components/bookmarks/ListPickerModal.tsx
new file mode 100644
index 00000000..6079e53d
--- /dev/null
+++ b/apps/mobile/components/bookmarks/ListPickerModal.tsx
@@ -0,0 +1,117 @@
+import React from "react";
+import { Pressable, Text, View } from "react-native";
+import Checkbox from "expo-checkbox";
+import {
+ BottomSheetFlatList,
+ BottomSheetModal,
+ BottomSheetModalProps,
+} from "@gorhom/bottom-sheet";
+
+import {
+ useAddBookmarkToList,
+ useBookmarkLists,
+ useRemoveBookmarkFromList,
+} from "@hoarder/shared-react/hooks/lists";
+import { api } from "@hoarder/shared-react/trpc";
+
+import PageTitle from "../ui/PageTitle";
+import { useToast } from "../ui/Toast";
+
+const ListPickerModal = React.forwardRef<
+ BottomSheetModal,
+ Omit<BottomSheetModalProps, "children"> & {
+ bookmarkId: string;
+ }
+>(({ bookmarkId, ...props }, ref) => {
+ const { toast } = useToast();
+ const onError = () => {
+ toast({
+ message: "Something went wrong",
+ variant: "destructive",
+ showProgress: false,
+ });
+ };
+ const { data: existingLists } = api.lists.getListsOfBookmark.useQuery(
+ {
+ bookmarkId,
+ },
+ {
+ select: (data) => new Set(data.lists.map((l) => l.id)),
+ },
+ );
+ const { data } = useBookmarkLists();
+
+ const { mutate: addToList } = useAddBookmarkToList({
+ onSuccess: () => {
+ toast({
+ message: `The bookmark has been added to the list!`,
+ showProgress: false,
+ });
+ },
+ onError,
+ });
+
+ const { mutate: removeToList } = useRemoveBookmarkFromList({
+ onSuccess: () => {
+ toast({
+ message: `The bookmark has been removed from the list!`,
+ showProgress: false,
+ });
+ },
+ onError,
+ });
+
+ const toggleList = (listId: string) => {
+ if (!existingLists) {
+ return;
+ }
+ if (existingLists.has(listId)) {
+ removeToList({ bookmarkId, listId });
+ } else {
+ addToList({ bookmarkId, listId });
+ }
+ };
+
+ const { allPaths } = data ?? {};
+ return (
+ <View>
+ <BottomSheetModal ref={ref} {...props}>
+ <BottomSheetFlatList
+ ListHeaderComponent={<PageTitle title="Manage Lists" />}
+ className="h-full"
+ contentContainerStyle={{
+ gap: 5,
+ }}
+ renderItem={(l) => (
+ <View className="mx-2 flex flex-row items-center rounded-xl border border-input bg-white px-4 py-2 dark:bg-accent">
+ <Pressable
+ key={l.item[l.item.length - 1].id}
+ onPress={() => toggleList(l.item[l.item.length - 1].id)}
+ className="flex w-full flex-row justify-between"
+ >
+ <Text className="text-lg text-accent-foreground">
+ {l.item
+ .map((item) => `${item.icon} ${item.name}`)
+ .join(" / ")}
+ </Text>
+ <Checkbox
+ value={
+ existingLists &&
+ existingLists.has(l.item[l.item.length - 1].id)
+ }
+ onValueChange={() => {
+ toggleList(l.item[l.item.length - 1].id);
+ }}
+ />
+ </Pressable>
+ </View>
+ )}
+ data={allPaths}
+ />
+ </BottomSheetModal>
+ </View>
+ );
+});
+ListPickerModal.displayName = "ListPickerModal";
+
+export default ListPickerModal;