diff options
Diffstat (limited to 'apps/mobile/components/bookmarks')
| -rw-r--r-- | apps/mobile/components/bookmarks/BookmarkCard.tsx | 20 | ||||
| -rw-r--r-- | apps/mobile/components/bookmarks/ListPickerModal.tsx | 117 |
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; |
