diff --git a/App.js b/App.js index 4588a1754cdf73058efd1987dee99f1e02c4e714..d5bd1028c0cb75aa55439367c387c38a5d4266ac 100644 --- a/App.js +++ b/App.js @@ -7,10 +7,13 @@ import { auth } from "./config/firebase"; import Login from "./screens/auth/Login"; import Signup from "./screens/auth/Signup"; import Chat from "./screens/tabs/Chat"; +import Home from "./screens/Home"; import ChatUid from "./screens/tabs/ChatUid"; -import Home from "./screens/tabs/Home"; +import CatownerHome from "./screens/tabs/CatownerHome"; import ChatList from "./screens/tabs/ChatList"; import Catsitter from "./screens/tabs/Catsitter"; +import CatsitterHome from "./screens/cat-sitter/CatsitterHome"; +import CatsitterSetting from "./screens/cat-sitter/CatsitterSetting"; const Stack = createStackNavigator(); @@ -25,11 +28,16 @@ function ChatStack() { return ( <Stack.Navigator defaultScreenOptions={Home}> <Stack.Screen name="Home" component={Home} /> + <Stack.Screen name="CatownerHome" component={CatownerHome} /> <Stack.Screen name="Catsitter" component={Catsitter} /> <Stack.Screen name="Chat" component={ChatList} /> <Stack.Screen name="ChatDetail" component={Chat} /> <Stack.Screen name="ChatWithUser" component={ChatUid} /> + {/* Cat sitter stack */} + <Stack.Screen name="CatsitterHome" component={CatsitterHome} /> + <Stack.Screen name="CatsitterSetting" component={CatsitterSetting} /> + </Stack.Navigator> ); } diff --git a/screens/Home.js b/screens/Home.js new file mode 100644 index 0000000000000000000000000000000000000000..f6795db8630b988c28a5400506310bc05a2e6153 --- /dev/null +++ b/screens/Home.js @@ -0,0 +1,53 @@ +import { View, Text } from 'react-native' +import React, { useState, useLayoutEffect } from "react"; +import { auth, database } from "../config/firebase"; +import { collection, query, onSnapshot, where, and, addDoc } from "firebase/firestore"; +import CatsitterHome from './cat-sitter/CatsitterHome'; +import CatOwnerHome from './tabs/CatownerHome'; +import CatsitterSetting from './cat-sitter/CatsitterSetting'; + +const Home = () => { + //Get current profile + const [userProfile, setUserProfile] = useState({}); + useLayoutEffect(() => { + const id = auth?.currentUser?.uid; + + if (!id) { + navigate("/") + return + }; + const collectionRef = collection(database, "profiles"); + const q = query(collectionRef, and(where("userId", "==", id)),); + + const unsubscribe = onSnapshot(q, (querySnapshot) => { + if (querySnapshot.docs.length > 0) { + setUserProfile(querySnapshot.docs[0].data()) + } else { + createUserProfile(auth?.currentUser?.uid) + } + }); + return unsubscribe; + }, []); + + const createUserProfile = (userId) => { + addDoc(collection(database, "profiles"), { + createdAt: new Date(), + userId: userId, + role: "cat-owner" + }); + } + + if (userProfile.role == "cat-owner") { + return <CatOwnerHome /> + } else if (userProfile.role == "cat-sitter" && userProfile.updatedAt) { + return <CatsitterHome /> + } else if (userProfile.role == "cat-sitter" && !userProfile.updatedAt) { + return <CatsitterSetting /> + } + + return <View> + <Text>Loading screen</Text> + </View> +} + +export default Home \ No newline at end of file diff --git a/screens/auth/Signup.js b/screens/auth/Signup.js index 65f83b2b34c8911ecf493cc315b01eba792ebc40..8d9a2ee7fa18ca0a481bcee4a63101bff248bca3 100644 --- a/screens/auth/Signup.js +++ b/screens/auth/Signup.js @@ -67,6 +67,7 @@ export default function Signup({ navigation }) { value={password} onChangeText={(text) => setPassword(text)} /> + {/* TODO: Add a checkbox for role */} <TouchableOpacity style={styles.button} onPress={onHandleSignup}> <Text style={{ fontWeight: "bold", color: "#fff", fontSize: 18 }}> Sign Up</Text> </TouchableOpacity> diff --git a/screens/cat-sitter/CatsitterHome.js b/screens/cat-sitter/CatsitterHome.js new file mode 100644 index 0000000000000000000000000000000000000000..d5f95f4232099a82d332033be90faff87cdf35c9 --- /dev/null +++ b/screens/cat-sitter/CatsitterHome.js @@ -0,0 +1,92 @@ +import React, { useEffect, useState, useLayoutEffect } from "react"; +import { View, TouchableOpacity, Text, Pressable, FlatList, Keyboard, Button, PRETT } from "react-native"; +import { useNavigation } from "@react-navigation/native"; +import { FontAwesome } from "@expo/vector-icons"; +import colors from "../../colors"; +import { collection, query, onSnapshot, orderBy, where } from "firebase/firestore"; +import styles from "../../assets/styles"; +import { signOut } from "firebase/auth"; +import { AntDesign } from "@expo/vector-icons"; +import { auth, database } from "../../config/firebase"; +import ChatComponent from "../../components/ChatComponent" + + +//When user has role cat sitter +//TODO: get profile of cat sitter => If not then has to create +// If not updatedAt => go profile setting +//Cat sitter has 2 screens => Profile Setting and Chat List +//Check for some needed info => If not go direct to setting screen +//Include Chatbox like in cat owner home => OK +const CatsitterHome = () => { + const navigation = useNavigation(); + const [chats, setChats] = useState([]); + const [profiles, setProfiles] = useState([]) + + const onSignOut = () => { + signOut(auth).catch((error) => console.log("Error logging out: ", error)); + }; + + useEffect(() => { + navigation.setOptions({ + headerLeft: () => <FontAwesome name="home" size={24} color={colors.gray} style={{ marginLeft: 15 }} />, + headerRight: () => ( + <TouchableOpacity + style={{ + marginRight: 10 + }} + onPress={onSignOut}> + <AntDesign name="logout" size={24} color={colors.gray} style={{ marginRight: 10 }} /> + </TouchableOpacity> + ) + }); + }, [navigation]); + + useLayoutEffect(() => { + const collectionRef = collection(database, "chats"); + const q = query(collectionRef, where("participant", "array-contains", auth.currentUser.uid), orderBy("updatedAt", "desc")); + + const unsubscribe = onSnapshot(q, (querySnapshot) => { + setChats( + querySnapshot.docs.map((doc) => ({ + _id: doc.id, + content: doc.data() + })) + ); + }); + return unsubscribe; + }, []); + + return ( + <View style={styles.container}> + <Text>My Profile</Text> + <View> + {chats.length > 0 ? ( + <FlatList + data={chats.map((chat) => { + //Find participant id + const participant_id = chat.content.participant.find(p => p !== auth?.currentUser.uid) + + //Find participant + const participant = profiles.find(p => p.data.userId == participant_id); + return ({ + id: chat._id, + name: participant ? participant.data.displayName : undefined, + avatar: participant ? participant.data.avatar : undefined, + }) + })} + keyExtractor={(item, index) => index.toString()} + renderItem={({ item }) => ( + <Pressable onPress={() => navigation.navigate("ChatDetail", { id: item.id })} style={styles.cchat}> + <ChatComponent item={item} /> + </Pressable> + )} + /> + ) : <Text style={{ textAlign: "right" }}>No Chat available</Text>} + </View> + </View> + ); +}; + +export default CatsitterHome; + + diff --git a/screens/cat-sitter/CatsitterSetting.js b/screens/cat-sitter/CatsitterSetting.js new file mode 100644 index 0000000000000000000000000000000000000000..005fe611d4b43ac55db890cdfedeaa9072e7e6dc --- /dev/null +++ b/screens/cat-sitter/CatsitterSetting.js @@ -0,0 +1,159 @@ +import React, { useEffect, useState, useLayoutEffect } from "react"; +import { View, TouchableOpacity, Text, TextInput, StyleSheet } from "react-native"; +import { useNavigation } from "@react-navigation/native"; +import { FontAwesome } from "@expo/vector-icons"; +import colors from "../../colors"; +import { signOut } from "firebase/auth"; +import { AntDesign } from "@expo/vector-icons"; +import { collection, query, onSnapshot, where, and, updateDoc, doc } from "firebase/firestore"; +import { auth, database } from "../../config/firebase"; +import { DIMENSION_WIDTH } from "../../assets/styles"; + + +//When user has role cat sitter +//TODO: get profile of cat sitter => If not then has to create +//Cat sitter has 2 screens => Profile Setting and Chat List +//Check for some needed info => If not go direct to setting screen +//Include Chatbox like in cat owner home => OK +const CatsitterSetting = () => { + const navigation = useNavigation(); + const [displayName, setDisplayName] = useState(""); + const [profileId, setProfileId] = useState(); + + const onSignOut = () => { + signOut(auth).catch((error) => console.log("Error logging out: ", error)); + }; + + useEffect(() => { + navigation.setOptions({ + headerLeft: () => <FontAwesome name="home" size={24} color={colors.gray} style={{ marginLeft: 15 }} />, + headerRight: () => ( + <TouchableOpacity + style={{ + marginRight: 10 + }} + onPress={onSignOut}> + <AntDesign name="logout" size={24} color={colors.gray} style={{ marginRight: 10 }} /> + </TouchableOpacity> + ) + }); + }, [navigation]); + + useLayoutEffect(() => { + const id = auth?.currentUser?.uid; + + if (!id) { + navigate("/") + return + }; + const collectionRef = collection(database, "profiles"); + const q = query(collectionRef, and(where("userId", "==", id)),); + + const unsubscribe = onSnapshot(q, (querySnapshot) => { + if (querySnapshot.docs.length > 0) { + setProfileId(querySnapshot.docs[0].id) + setDisplayName(querySnapshot.docs[0].data().displayName || "") + } + }); + return unsubscribe; + }, []); + + const onUpdateProfileClick = async () => { + if (!profileId) return; + alert(profileId) + const profileRef = doc(database, "profiles", profileId); + const updateProfile = await updateDoc(profileRef, { + displayName: displayName, + updatedAt: new Date() + }); + + alert(updateProfile) + } + + return ( + <View source={require("../../assets/images/10.jpg")} style={styles.containerHomePage}> + <TouchableOpacity style={{ width: "100%" }}> + <Text style={styles.heading1}>Setup your profile</Text> + </TouchableOpacity> + + <View> + <TextInput + style={styles.input} + placeholder="Display Name" + autoCapitalize="none" + textContentType="name" + value={displayName} + onChangeText={(text) => setDisplayName(text)} + /> + + <TouchableOpacity style={styles.button} onPress={onUpdateProfileClick}> + <Text style={{ fontWeight: "bold", color: "#fff", fontSize: 18 }}>Update your profile</Text> + </TouchableOpacity> + </View> + + + </View> + + + ); +}; + +export default CatsitterSetting; + + +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + backgroundColor: "#fff", + position: "relative" + }, + chatButton: { + position: "absolute", + bottom: 0, + right: 0, + backgroundColor: colors.primary, + height: 50, + width: 50, + borderRadius: 25, + alignItems: "center", + justifyContent: "center", + shadowColor: colors.primary, + shadowOffset: { + width: 0, + height: 2 + }, + shadowOpacity: 0.9, + shadowRadius: 8, + marginRight: 20, + marginBottom: 50 + }, + input: { + backgroundColor: "#F6F7FB", + height: 58, + marginBottom: 20, + fontSize: 16, + borderRadius: 10, + padding: 12 + }, + cchat: { + display: "flex", + flexDirection: "row", + width: DIMENSION_WIDTH - 40, + marginHorizontal: 20, + padding: 16, + marginVertical: 4, + backgroundColor: "#FAFAFA", + shadowColor: colors.primary, + shadowOffset: { + width: 0, + height: 2 + }, + shadowOpacity: 0.9, + shadowRadius: 8, + borderRadius: 12, + borderColor: "#EDE6DD" + }, +}); diff --git a/screens/tabs/Home.js b/screens/tabs/CatownerHome.js similarity index 97% rename from screens/tabs/Home.js rename to screens/tabs/CatownerHome.js index 4002dd4934525f554392475cd7ed6054d1263fa9..2d11848f59204df347a167ff8fcd01c1fc48d879 100644 --- a/screens/tabs/Home.js +++ b/screens/tabs/CatownerHome.js @@ -13,7 +13,9 @@ import { BLACK, WHITE } from '../../assets/styles' import { AntDesign } from "@expo/vector-icons"; import { auth, database } from "../../config/firebase"; -const Home = () => { + +//When user has role catowner +const CatownerHome = () => { const navigation = useNavigation(); const [catsitters, setCatsitters] = useState([]); const [keyword, setKeyword] = useState(""); @@ -99,6 +101,6 @@ const Home = () => { ); }; -export default Home; +export default CatownerHome;