Skip to content

Commit 1405540

Browse files
committed
feature(mobile): Add ability to create basic lists from the app
1 parent 410b0e7 commit 1405540

File tree

3 files changed

+111
-5
lines changed

3 files changed

+111
-5
lines changed

Diff for: apps/mobile/app.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"NSAllowsLocalNetworking": true
3131
}
3232
},
33-
"buildNumber": "7"
33+
"buildNumber": "8"
3434
},
3535
"android": {
3636
"adaptiveIcon": {
@@ -48,7 +48,7 @@
4848
}
4949
},
5050
"package": "app.hoarder.hoardermobile",
51-
"versionCode": 7
51+
"versionCode": 8
5252
},
5353
"plugins": [
5454
"expo-router",

Diff for: apps/mobile/app/dashboard/(tabs)/lists.tsx

+29-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
1-
import { useEffect, useState } from "react";
1+
import { useEffect, useRef, useState } from "react";
22
import { FlatList, Pressable, Text, View } from "react-native";
3+
import * as Haptics from "expo-haptics";
34
import { Link } from "expo-router";
5+
import NewListModal from "@/components/lists/NewListModal";
46
import { TailwindResolver } from "@/components/TailwindResolver";
57
import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
68
import PageTitle from "@/components/ui/PageTitle";
79
import { api } from "@/lib/trpc";
8-
import { ChevronRight } from "lucide-react-native";
10+
import { BottomSheetModal } from "@gorhom/bottom-sheet";
11+
import { ChevronRight, Plus } from "lucide-react-native";
912

1013
import { useBookmarkLists } from "@hoarder/shared-react/hooks/lists";
1114
import { ZBookmarkListTreeNode } from "@hoarder/shared/utils/listUtils";
1215

16+
function HeaderRight({ openNewListModal }: { openNewListModal: () => void }) {
17+
return (
18+
<Pressable
19+
className="my-auto px-4"
20+
onPress={() => {
21+
Haptics.selectionAsync();
22+
openNewListModal();
23+
}}
24+
>
25+
<Plus color="rgb(0, 122, 255)" />
26+
</Pressable>
27+
);
28+
}
29+
1330
interface ListLink {
1431
id: string;
1532
logo: string;
@@ -53,6 +70,7 @@ export default function Lists() {
5370
{},
5471
);
5572
const apiUtils = api.useUtils();
73+
const newListModal = useRef<BottomSheetModal>(null);
5674

5775
useEffect(() => {
5876
setRefreshing(isPending);
@@ -94,9 +112,17 @@ export default function Lists() {
94112

95113
return (
96114
<CustomSafeAreaView>
115+
<NewListModal ref={newListModal} snapPoints={["90%"]} />
97116
<FlatList
98117
className="h-full"
99-
ListHeaderComponent={<PageTitle title="Lists" />}
118+
ListHeaderComponent={
119+
<View className="flex flex-row justify-between">
120+
<PageTitle title="Lists" />
121+
<HeaderRight
122+
openNewListModal={() => newListModal.current?.present()}
123+
/>
124+
</View>
125+
}
100126
contentContainerStyle={{
101127
gap: 5,
102128
}}

Diff for: apps/mobile/components/lists/NewListModal.tsx

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import React, { useState } from "react";
2+
import { Text, View } from "react-native";
3+
import {
4+
BottomSheetBackdrop,
5+
BottomSheetModal,
6+
BottomSheetModalProps,
7+
BottomSheetView,
8+
useBottomSheetModal,
9+
} from "@gorhom/bottom-sheet";
10+
11+
import { useCreateBookmarkList } from "@hoarder/shared-react/hooks/lists";
12+
13+
import { Button } from "../ui/Button";
14+
import { Input } from "../ui/Input";
15+
import PageTitle from "../ui/PageTitle";
16+
import { useToast } from "../ui/Toast";
17+
18+
const NewListModal = React.forwardRef<
19+
BottomSheetModal,
20+
Omit<BottomSheetModalProps, "children" | "backdropComponent" | "onDismiss">
21+
>(({ ...props }, ref) => {
22+
const { dismiss } = useBottomSheetModal();
23+
const { toast } = useToast();
24+
const [text, setText] = useState("");
25+
26+
const { mutate, isPending } = useCreateBookmarkList({
27+
onSuccess: () => {
28+
dismiss();
29+
},
30+
onError: () => {
31+
toast({
32+
message: "Something went wrong",
33+
variant: "destructive",
34+
});
35+
},
36+
});
37+
38+
const onSubmit = () => {
39+
mutate({
40+
name: text,
41+
icon: "🚀",
42+
});
43+
};
44+
45+
return (
46+
<View>
47+
<BottomSheetModal
48+
ref={ref}
49+
onDismiss={() => setText("")}
50+
backdropComponent={(props) => (
51+
<BottomSheetBackdrop
52+
appearsOnIndex={0}
53+
disappearsOnIndex={-1}
54+
{...props}
55+
/>
56+
)}
57+
{...props}
58+
>
59+
<PageTitle title="New List" />
60+
<BottomSheetView className="gap-2 px-4">
61+
<BottomSheetView className="flex flex-row items-center gap-1">
62+
<Text className="shrink p-2">🚀</Text>
63+
<Input
64+
className="flex-1"
65+
onChangeText={setText}
66+
placeholder="List Name"
67+
autoFocus
68+
autoCapitalize={"none"}
69+
/>
70+
</BottomSheetView>
71+
<Button disabled={isPending} onPress={onSubmit} label="Save" />
72+
</BottomSheetView>
73+
</BottomSheetModal>
74+
</View>
75+
);
76+
});
77+
78+
NewListModal.displayName = "NewListModal";
79+
80+
export default NewListModal;

0 commit comments

Comments
 (0)