aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-08-26 13:13:24 +0300
committerMohamedBassem <me@mbassem.com>2024-08-26 13:13:24 +0300
commit8410a6d3c125cf27daa4e3abeb4c4a4d228e2cfd (patch)
tree76c4b52283d6c096fc17fe3f554651dca5e19988
parentd8cf7c17a2b0a437cf4a2f983f5ab48fba775a64 (diff)
downloadkarakeep-8410a6d3c125cf27daa4e3abeb4c4a4d228e2cfd.tar.zst
ui(mobile): Change the add/edit note editor dialogs to be bottom sheets
-rw-r--r--apps/mobile/app/dashboard/(tabs)/index.tsx18
-rw-r--r--apps/mobile/app/dashboard/_layout.tsx7
-rw-r--r--apps/mobile/app/dashboard/add-note.tsx114
-rw-r--r--apps/mobile/components/bookmarks/BookmarkCard.tsx11
-rw-r--r--apps/mobile/components/bookmarks/NewBookmarkModal.tsx129
5 files changed, 154 insertions, 125 deletions
diff --git a/apps/mobile/app/dashboard/(tabs)/index.tsx b/apps/mobile/app/dashboard/(tabs)/index.tsx
index 5dccc845..994ebb45 100644
--- a/apps/mobile/app/dashboard/(tabs)/index.tsx
+++ b/apps/mobile/app/dashboard/(tabs)/index.tsx
@@ -1,17 +1,24 @@
+import { useRef } from "react";
import { Platform, View } from "react-native";
import * as Haptics from "expo-haptics";
import * as ImagePicker from "expo-image-picker";
import { useRouter } from "expo-router";
+import NoteEditorModal from "@/components/bookmarks/NewBookmarkModal";
import UpdatingBookmarkList from "@/components/bookmarks/UpdatingBookmarkList";
import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import PageTitle from "@/components/ui/PageTitle";
import { useToast } from "@/components/ui/Toast";
import useAppSettings from "@/lib/settings";
import { useUploadAsset } from "@/lib/upload";
+import { BottomSheetModal } from "@gorhom/bottom-sheet";
import { MenuView } from "@react-native-menu/menu";
import { SquarePen } from "lucide-react-native";
-function HeaderRight() {
+function HeaderRight({
+ openNewBookmarkModal,
+}: {
+ openNewBookmarkModal: () => void;
+}) {
const { toast } = useToast();
const router = useRouter();
const { settings } = useAppSettings();
@@ -25,7 +32,7 @@ function HeaderRight() {
onPressAction={async ({ nativeEvent }) => {
Haptics.selectionAsync();
if (nativeEvent.event === "note") {
- router.navigate("dashboard/add-note");
+ openNewBookmarkModal();
} else if (nativeEvent.event === "link") {
router.navigate("dashboard/add-link");
} else if (nativeEvent.event === "library") {
@@ -79,14 +86,19 @@ function HeaderRight() {
}
export default function Home() {
+ const newBookmarkModal = useRef<BottomSheetModal>(null);
+
return (
<CustomSafeAreaView>
+ <NoteEditorModal ref={newBookmarkModal} snapPoints={["90%", "60%"]} />
<UpdatingBookmarkList
query={{ archived: false }}
header={
<View className="flex flex-row justify-between">
<PageTitle title="Home" />
- <HeaderRight />
+ <HeaderRight
+ openNewBookmarkModal={() => newBookmarkModal.current?.present()}
+ />
</View>
}
/>
diff --git a/apps/mobile/app/dashboard/_layout.tsx b/apps/mobile/app/dashboard/_layout.tsx
index 7548a6db..e8733fe0 100644
--- a/apps/mobile/app/dashboard/_layout.tsx
+++ b/apps/mobile/app/dashboard/_layout.tsx
@@ -61,13 +61,6 @@ export default function Dashboard() {
presentation: "modal",
}}
/>
- <Stack.Screen
- name="add-note"
- options={{
- title: "New Note",
- presentation: "modal",
- }}
- />
</StyledStack>
);
}
diff --git a/apps/mobile/app/dashboard/add-note.tsx b/apps/mobile/app/dashboard/add-note.tsx
deleted file mode 100644
index 8aa31936..00000000
--- a/apps/mobile/app/dashboard/add-note.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import { useEffect, useState } from "react";
-import { Text, View } from "react-native";
-import { Stack, useLocalSearchParams, useRouter } from "expo-router";
-import { Button } from "@/components/ui/Button";
-import { Input } from "@/components/ui/Input";
-import { api } from "@/lib/trpc";
-
-import {
- useCreateBookmark,
- useUpdateBookmarkText,
-} from "@hoarder/shared-react/hooks/bookmarks";
-import { BookmarkTypes } from "@hoarder/shared/types/bookmarks";
-
-export default function AddNote() {
- const { bookmarkId } = useLocalSearchParams();
- if (bookmarkId && typeof bookmarkId !== "string") {
- throw new Error("Unexpected param type");
- }
-
- const isEditing = !!bookmarkId;
-
- const [text, setText] = useState("");
- const [error, setError] = useState<string | undefined>();
- const router = useRouter();
-
- const { data: bookmark } = api.bookmarks.getBookmark.useQuery(
- { bookmarkId: bookmarkId! },
- {
- enabled: !!bookmarkId,
- },
- );
-
- useEffect(() => {
- if (bookmark) {
- if (bookmark.content.type !== BookmarkTypes.TEXT) {
- throw new Error("Wrong content type rendered");
- }
- setText(bookmark.content.text);
- }
- }, [bookmark]);
-
- const onSuccess = () => {
- if (router.canGoBack()) {
- router.replace("./");
- } else {
- router.replace("dashboard");
- }
- };
-
- const { mutate: createBookmark } = useCreateBookmark({
- onSuccess,
- onError: (e) => {
- let message;
- if (e.data?.zodError) {
- const zodError = e.data.zodError;
- message = JSON.stringify(zodError);
- } else {
- message = `Something went wrong: ${e.message}`;
- }
- setError(message);
- },
- });
-
- const { mutate: updateBookmark } = useUpdateBookmarkText({
- onSuccess,
- onError: (e) => {
- let message;
- if (e.data?.zodError) {
- const zodError = e.data.zodError;
- message = JSON.stringify(zodError);
- } else {
- message = `Something went wrong: ${e.message}`;
- }
- setError(message);
- },
- });
-
- const mutate = (text: string) => {
- if (isEditing) {
- updateBookmark({
- bookmarkId,
- text,
- });
- } else {
- createBookmark({ type: BookmarkTypes.TEXT, text });
- }
- };
-
- return (
- <View className="flex gap-2 p-4">
- <Stack.Screen
- options={{
- title: isEditing ? "Edit Note" : "Add Note",
- }}
- />
- {error && (
- <Text className="w-full text-center text-red-500">{error}</Text>
- )}
- <Input
- value={text}
- onChangeText={setText}
- multiline
- numberOfLines={8}
- placeholder="What's on your mind?"
- autoFocus
- textAlignVertical="top"
- />
- <Button
- onPress={() => mutate(text)}
- label={isEditing ? "Save" : "Add Note"}
- />
- </View>
- );
-}
diff --git a/apps/mobile/components/bookmarks/BookmarkCard.tsx b/apps/mobile/components/bookmarks/BookmarkCard.tsx
index ed6a3b2c..8c582d59 100644
--- a/apps/mobile/components/bookmarks/BookmarkCard.tsx
+++ b/apps/mobile/components/bookmarks/BookmarkCard.tsx
@@ -35,6 +35,7 @@ import { useToast } from "../ui/Toast";
import BookmarkAssetImage from "./BookmarkAssetImage";
import BookmarkTextMarkdown from "./BookmarkTextMarkdown";
import ListPickerModal from "./ListPickerModal";
+import NoteEditorModal from "./NewBookmarkModal";
function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
const { toast } = useToast();
@@ -74,6 +75,7 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
});
const manageListsSheetRef = useRef<BottomSheetModal>(null);
+ const editBookmarkModal = useRef<BottomSheetModal>(null);
return (
<View className="flex flex-row gap-4">
@@ -99,6 +101,13 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
snapPoints={["50%", "90%"]}
bookmarkId={bookmark.id}
/>
+ {bookmark.content.type === BookmarkTypes.TEXT && (
+ <NoteEditorModal
+ ref={editBookmarkModal}
+ bookmark={bookmark}
+ snapPoints={["90%", "60%"]}
+ />
+ )}
<MenuView
onPressAction={({ nativeEvent }) => {
@@ -115,7 +124,7 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
} else if (nativeEvent.event === "manage_list") {
manageListsSheetRef?.current?.present();
} else if (nativeEvent.event === "edit") {
- router.push(`/dashboard/add-note?bookmarkId=${bookmark.id}`);
+ editBookmarkModal.current?.present();
}
}}
actions={[
diff --git a/apps/mobile/components/bookmarks/NewBookmarkModal.tsx b/apps/mobile/components/bookmarks/NewBookmarkModal.tsx
new file mode 100644
index 00000000..8ac8bb39
--- /dev/null
+++ b/apps/mobile/components/bookmarks/NewBookmarkModal.tsx
@@ -0,0 +1,129 @@
+import React, { useEffect, useState } from "react";
+import { Text, View } from "react-native";
+import {
+ BottomSheetBackdrop,
+ BottomSheetModal,
+ BottomSheetModalProps,
+ BottomSheetTextInput,
+ BottomSheetView,
+ useBottomSheetModal,
+} from "@gorhom/bottom-sheet";
+
+import {
+ useCreateBookmark,
+ useUpdateBookmarkText,
+} from "@hoarder/shared-react/hooks/bookmarks";
+import { BookmarkTypes, ZBookmark } from "@hoarder/shared/types/bookmarks";
+
+import { Button } from "../ui/Button";
+import PageTitle from "../ui/PageTitle";
+
+const NoteEditorModal = React.forwardRef<
+ BottomSheetModal,
+ Omit<
+ BottomSheetModalProps,
+ "children" | "backdropComponent" | "onDismiss"
+ > & {
+ bookmark?: ZBookmark;
+ }
+>(({ bookmark, ...props }, ref) => {
+ const { dismiss } = useBottomSheetModal();
+ const isEditing = !!bookmark;
+
+ const [text, setText] = useState("");
+ const [error, setError] = useState<string | undefined>();
+
+ const resetText = () => {
+ if (bookmark) {
+ if (bookmark.content.type !== BookmarkTypes.TEXT) {
+ throw new Error("Wrong content type rendered");
+ }
+ setText(bookmark.content.text);
+ }
+ };
+
+ useEffect(resetText, []);
+
+ const onSuccess = () => {
+ resetText();
+ dismiss();
+ };
+
+ const { mutate: createBookmark } = useCreateBookmark({
+ onSuccess,
+ onError: (e) => {
+ let message;
+ if (e.data?.zodError) {
+ const zodError = e.data.zodError;
+ message = JSON.stringify(zodError);
+ } else {
+ message = `Something went wrong: ${e.message}`;
+ }
+ setError(message);
+ },
+ });
+
+ const { mutate: updateBookmark } = useUpdateBookmarkText({
+ onSuccess,
+ onError: (e) => {
+ let message;
+ if (e.data?.zodError) {
+ const zodError = e.data.zodError;
+ message = JSON.stringify(zodError);
+ } else {
+ message = `Something went wrong: ${e.message}`;
+ }
+ setError(message);
+ },
+ });
+
+ const mutate = (text: string) => {
+ if (isEditing) {
+ updateBookmark({
+ bookmarkId: bookmark.id,
+ text,
+ });
+ } else {
+ createBookmark({ type: BookmarkTypes.TEXT, text });
+ }
+ };
+
+ return (
+ <View>
+ <BottomSheetModal
+ ref={ref}
+ backdropComponent={(props) => (
+ <BottomSheetBackdrop
+ appearsOnIndex={0}
+ disappearsOnIndex={-1}
+ {...props}
+ />
+ )}
+ {...props}
+ >
+ <PageTitle title={isEditing ? "Edit Note" : "New Note"} />
+ <BottomSheetView className="p-4">
+ {error && (
+ <Text className="w-full text-center text-red-500">{error}</Text>
+ )}
+ <BottomSheetTextInput
+ value={text}
+ onChangeText={setText}
+ multiline
+ numberOfLines={8}
+ placeholder="What's on your mind?"
+ autoFocus
+ textAlignVertical="top"
+ />
+ <Button
+ onPress={() => mutate(text)}
+ label={isEditing ? "Save" : "Add Note"}
+ />
+ </BottomSheetView>
+ </BottomSheetModal>
+ </View>
+ );
+});
+NoteEditorModal.displayName = "NewBookmarkModal";
+
+export default NoteEditorModal;