From 04572a8e5081b1e4871e273cde9dbaaa44c52fe0 Mon Sep 17 00:00:00 2001 From: MohamedBassem Date: Wed, 13 Mar 2024 21:43:44 +0000 Subject: structure: Create apps dir and copy tooling dir from t3-turbo repo --- apps/mobile/components/bookmarks/BookmarkCard.tsx | 243 ++++++++++++++++++++++ apps/mobile/components/bookmarks/BookmarkList.tsx | 61 ++++++ 2 files changed, 304 insertions(+) create mode 100644 apps/mobile/components/bookmarks/BookmarkCard.tsx create mode 100644 apps/mobile/components/bookmarks/BookmarkList.tsx (limited to 'apps/mobile/components/bookmarks') diff --git a/apps/mobile/components/bookmarks/BookmarkCard.tsx b/apps/mobile/components/bookmarks/BookmarkCard.tsx new file mode 100644 index 00000000..25947790 --- /dev/null +++ b/apps/mobile/components/bookmarks/BookmarkCard.tsx @@ -0,0 +1,243 @@ +import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; +import * as WebBrowser from "expo-web-browser"; +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 { Divider } from "../ui/Divider"; +import { Skeleton } from "../ui/Skeleton"; +import { useToast } from "../ui/Toast"; + +import { api } from "@/lib/trpc"; + +const MAX_LOADING_MSEC = 30 * 1000; + +export function isBookmarkStillCrawling(bookmark: ZBookmark) { + return ( + bookmark.content.type === "link" && + !bookmark.content.crawledAt && + Date.now().valueOf() - bookmark.createdAt.valueOf() < MAX_LOADING_MSEC + ); +} + +export function isBookmarkStillTagging(bookmark: ZBookmark) { + return ( + bookmark.taggingStatus === "pending" && + Date.now().valueOf() - bookmark.createdAt.valueOf() < MAX_LOADING_MSEC + ); +} + +export function isBookmarkStillLoading(bookmark: ZBookmark) { + return isBookmarkStillTagging(bookmark) || isBookmarkStillCrawling(bookmark); +} + +function ActionBar({ bookmark }: { bookmark: ZBookmark }) { + const { toast } = useToast(); + const apiUtils = api.useUtils(); + + const { mutate: deleteBookmark, isPending: isDeletionPending } = + api.bookmarks.deleteBookmark.useMutation({ + onSuccess: () => { + apiUtils.bookmarks.getBookmarks.invalidate(); + }, + 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 ( + + + updateBookmark({ + bookmarkId: bookmark.id, + favourited: !bookmark.favourited, + }) + } + > + {(variables ? variables.favourited : bookmark.favourited) ? ( + + ) : ( + + )} + + + updateBookmark({ + bookmarkId: bookmark.id, + archived: !bookmark.archived, + }) + } + > + {bookmark.archived ? ( + + ) : ( + + )} + + + deleteBookmark({ + bookmarkId: bookmark.id, + }) + } + > + + + + ); +} + +function TagList({ bookmark }: { bookmark: ZBookmark }) { + const tags = bookmark.tags; + + if (isBookmarkStillTagging(bookmark)) { + return ( + <> + + + + ); + } + + return ( + + + {tags.map((t) => ( + + {t.name} + + ))} + + + ); +} + +function LinkCard({ bookmark }: { bookmark: ZBookmark }) { + if (bookmark.content.type !== "link") { + throw new Error("Wrong content type rendered"); + } + + const url = bookmark.content.url; + const parsedUrl = new URL(url); + + const imageComp = bookmark.content.imageUrl ? ( + + ) : ( + + ); + + return ( + + {imageComp} + + WebBrowser.openBrowserAsync(url)} + > + {bookmark.content.title || parsedUrl.host} + + + + + {parsedUrl.host} + + + + + ); +} + +function TextCard({ bookmark }: { bookmark: ZBookmark }) { + if (bookmark.content.type !== "text") { + throw new Error("Wrong content type rendered"); + } + return ( + + + {bookmark.content.text} + + + + + + + + + ); +} + +export default function BookmarkCard({ + bookmark: initialData, +}: { + bookmark: ZBookmark; +}) { + const { data: bookmark } = api.bookmarks.getBookmark.useQuery( + { + bookmarkId: initialData.id, + }, + { + initialData, + refetchInterval: (query) => { + const data = query.state.data; + if (!data) { + return false; + } + // If the link is not crawled or not tagged + if (isBookmarkStillLoading(data)) { + return 1000; + } + return false; + }, + }, + ); + + let comp; + switch (bookmark.content.type) { + case "link": + comp = ; + break; + case "text": + comp = ; + break; + } + + return ( + + {comp} + + ); +} diff --git a/apps/mobile/components/bookmarks/BookmarkList.tsx b/apps/mobile/components/bookmarks/BookmarkList.tsx new file mode 100644 index 00000000..8e408709 --- /dev/null +++ b/apps/mobile/components/bookmarks/BookmarkList.tsx @@ -0,0 +1,61 @@ +import { useEffect, useState } from "react"; +import { Text, View } from "react-native"; +import Animated, { LinearTransition } from "react-native-reanimated"; + +import BookmarkCard from "./BookmarkCard"; +import FullPageSpinner from "../ui/FullPageSpinner"; + +import { api } from "@/lib/trpc"; + +export default function BookmarkList({ + favourited, + archived, + ids, +}: { + favourited?: boolean; + archived?: boolean; + ids?: string[]; +}) { + const apiUtils = api.useUtils(); + const [refreshing, setRefreshing] = useState(false); + const { data, isPending, isPlaceholderData } = + api.bookmarks.getBookmarks.useQuery({ + favourited, + archived, + ids, + }); + + useEffect(() => { + setRefreshing(isPending || isPlaceholderData); + }, [isPending, isPlaceholderData]); + + if (isPending || !data) { + return ; + } + + const onRefresh = () => { + apiUtils.bookmarks.getBookmarks.invalidate(); + apiUtils.bookmarks.getBookmark.invalidate(); + }; + + return ( + } + ListEmptyComponent={ + + No Bookmarks + + } + data={data.bookmarks} + refreshing={refreshing} + onRefresh={onRefresh} + keyExtractor={(b) => b.id} + /> + ); +} -- cgit v1.2.3-70-g09d2