Auth logic rework

This commit is contained in:
Milan Paunovic
2024-08-21 20:25:15 +02:00
parent 7500b7bdcb
commit 6b42476ef0
6 changed files with 254 additions and 200 deletions

View File

@ -1,44 +1,45 @@
import React, { useEffect, useState } from "react"; import React, {useEffect, useState} from "react";
import { Text, Button, TextInput } from "react-native"; import {Button, Text, TextInput} from "react-native";
import { View, TextField, Picker, Checkbox } from "react-native-ui-lib"; import {Checkbox, Picker, TextField, View} from "react-native-ui-lib";
import useAuth from "@/hooks/firebase/useAuth"; import useAuth from "@/hooks/firebase/useAuth";
import useChildren from "@/hooks/firebase/useChildren"; import useChildren from "@/hooks/firebase/useChildren";
import useCaregivers from "@/hooks/firebase/useCaregivers"; import useCaregivers from "@/hooks/firebase/useCaregivers";
import {useCreateSubUser} from "@/hooks/firebase/useCreateSubUser"; import {useCreateSubUser} from "@/hooks/firebase/useCreateSubUser";
import {email} from "@sideway/address";
import {UserProfile} from "@/hooks/firebase/types/profileTypes"; import {UserProfile} from "@/hooks/firebase/types/profileTypes";
import {uuidv4} from "@firebase/util"; import {uuidv4} from "@firebase/util";
import {useGetChildrenByParentId} from "@/hooks/firebase/useGetChildrenByParentId";
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
const Screen: React.FC = () => { const Screen: React.FC = () => {
const { const {user, profileType, profileData} = useAuthContext()
user,
profileType,
email,
setEmail,
password,
setPassword,
handleLogin,
handleSignOut,
handleProfileTypeSelection,
handleRegister,
} = useAuth(); const {
email,
setEmail,
password,
setPassword,
handleLogin,
handleSignOut,
handleProfileTypeSelection,
handleRegister,
} = useAuth();
const { const {
children, children,
child, child,
setChild, setChild,
fetchChildren, handleNewChild,
handleNewChild, } = useChildren(user);
} = useChildren(user);
const { const {data: childrenByParentId} = useGetChildrenByParentId()
caregivers,
caregiver, const {
setCaregiver, caregivers,
fetchCaregivers, caregiver,
handleNewCaregiver, setCaregiver,
} = useCaregivers(); fetchCaregivers,
handleNewCaregiver,
} = useCaregivers();
const {mutateAsync: createSubUser} = useCreateSubUser() const {mutateAsync: createSubUser} = useCreateSubUser()
@ -52,174 +53,172 @@ const Screen: React.FC = () => {
// contact: "+381628334", // contact: "+381628334",
// ...child // ...child
// }) // })
await fetchChildren();
await fetchCaregivers(); await fetchCaregivers();
}
useEffect(() => {
if (user) {
fetchChildren();
fetchCaregivers();
} }
}, [user]);
useEffect(() => {
if (user) {
fetchCaregivers();
}
}, [user]);
const [isParent, setIsParent] = useState<boolean>(false); const [isParent, setIsParent] = useState<boolean>(false);
const [isChild, setIsChild] = useState<boolean>(false); const [isChild, setIsChild] = useState<boolean>(false);
const [isCaregiver, setIsCaregiver] = useState<boolean>(false); const [isCaregiver, setIsCaregiver] = useState<boolean>(false);
useEffect(() => { useEffect(() => {
if (isParent) handleProfileTypeSelection("parent"); if (isParent) handleProfileTypeSelection("parent");
if (isChild) handleProfileTypeSelection("child"); if (isChild) handleProfileTypeSelection("child");
if (isCaregiver) handleProfileTypeSelection("caregiver"); if (isCaregiver) handleProfileTypeSelection("caregiver");
}, [isParent, isChild, isCaregiver]); }, [isParent, isChild, isCaregiver]);
const renderLogin = () => ( const renderLogin = () => (
<View marginH-20> <View marginH-20>
<TextInput placeholder="Email" value={email} onChangeText={setEmail} /> <TextInput placeholder="Email" value={email} onChangeText={setEmail}/>
<TextInput <TextInput
placeholder="Password" placeholder="Password"
value={password} value={password}
onChangeText={setPassword} onChangeText={setPassword}
secureTextEntry secureTextEntry
/> />
<Button title="Login" onPress={handleLogin} /> <Button title="Login" onPress={handleLogin}/>
<Button title="Register" onPress={handleRegister} /> <Button title="Register" onPress={handleRegister}/>
<Text>Choose Profile Type:</Text> <Text>Choose Profile Type:</Text>
<Checkbox <Checkbox
label="Parent" label="Parent"
value={isParent} value={isParent}
onValueChange={(value) => { onValueChange={(value) => {
setIsParent(value); setIsParent(value);
if (value) { if (value) {
setIsChild(false); setIsChild(false);
setIsCaregiver(false); setIsCaregiver(false);
} }
}} }}
/> />
<Checkbox <Checkbox
label="Child" label="Child"
value={isChild} value={isChild}
onValueChange={(value) => { onValueChange={(value) => {
setIsChild(value); setIsChild(value);
if (value) { if (value) {
setIsParent(false); setIsParent(false);
setIsCaregiver(false); setIsCaregiver(false);
} }
}} }}
/> />
<Checkbox <Checkbox
label="Caregiver" label="Caregiver"
value={isCaregiver} value={isCaregiver}
onValueChange={(value) => { onValueChange={(value) => {
setIsCaregiver(value); setIsCaregiver(value);
if (value) { if (value) {
setIsParent(false); setIsParent(false);
setIsChild(false); setIsChild(false);
} }
}} }}
/> />
</View>
);
return (
<View>
{user ? (
<View paddingH-20>
{profileType === "parent" && <Text>Parent</Text>}
{profileType === "child" && <Text>Child</Text>}
{profileType === "caregiver" && <Text>Caregiver</Text>}
<Button title="Sign Out" onPress={handleSignOut} />
<TextField
placeholder={"Child Name"}
floatingPlaceholder
value={child.name}
onChangeText={(value) =>
setChild((prevChild) => ({
...prevChild,
name: value,
}))
}
enableErrors
validate={["required", (value: string) => value.length > 6]}
validationMessage={[
"Field is required",
"Name is too short",
]}
showCharCounter
maxLength={30}
/>
<Button
title="Add Child"
onPress={() => {
createNewSubUser(child);
}}
/>
<TextField
placeholder={"Caregiver Name"}
floatingPlaceholder
value={caregiver.name}
onChangeText={(value) =>
setCaregiver((prevCaregiver) => ({
...prevCaregiver,
name: value,
}))
}
enableErrors
validate={["required", (value: string) => value.length > 6]}
validationMessage={["Field is required"]}
showCharCounter
maxLength={30}
/>
<TextField
placeholder={"Caregiver Contact"}
floatingPlaceholder
value={caregiver.contact}
onChangeText={(value) =>
setCaregiver((prevCaregiver) => ({
...prevCaregiver,
contact: value,
}))
}
enableErrors
validate={[
"number",
"required",
(value: string) => value.length > 9,
]}
validationMessage={["Field is required"]}
showCharCounter
maxLength={30}
/>
<Button
title="Add Caregiver"
onPress={() => {
createNewSubUser(caregiver);
}}
/>
<View margin-20>
<Text>Children:</Text>
{children.map((child) => (
<View key={child.name} row>
<Text>Name: {child.name} </Text>
<Picker label="Pick Caregiver">
{caregivers.map((item) => (
<Picker.Item
key={item.name}
label={item.name}
value={item.name}
/>
))}
</Picker>
</View>
))}
</View>
</View> </View>
) : ( );
renderLogin()
)} return (
</View> <View>
); {user ? (
<View paddingH-20>
{profileType === ProfileType.parent && <Text>Parent</Text>}
{profileType === ProfileType.child && <Text>Child</Text>}
{profileType === ProfileType.caregiver && <Text>Caregiver</Text>}
<Button title="Sign Out" onPress={handleSignOut}/>
<TextField
placeholder={"Child Name"}
floatingPlaceholder
value={child.name}
onChangeText={(value) =>
setChild((prevChild) => ({
...prevChild,
name: value,
}))
}
enableErrors
validate={["required", (value: string) => value.length > 6]}
validationMessage={[
"Field is required",
"Name is too short",
]}
showCharCounter
maxLength={30}
/>
<Button
title="Add Child"
onPress={() => {
createNewSubUser(child);
}}
/>
<TextField
placeholder={"Caregiver Name"}
floatingPlaceholder
value={caregiver.name}
onChangeText={(value) =>
setCaregiver((prevCaregiver) => ({
...prevCaregiver,
name: value,
}))
}
enableErrors
validate={["required", (value: string) => value.length > 6]}
validationMessage={["Field is required"]}
showCharCounter
maxLength={30}
/>
<TextField
placeholder={"Caregiver Contact"}
floatingPlaceholder
value={caregiver.contact}
onChangeText={(value) =>
setCaregiver((prevCaregiver) => ({
...prevCaregiver,
contact: value,
}))
}
enableErrors
validate={[
"number",
"required",
(value: string) => value.length > 9,
]}
validationMessage={["Field is required"]}
showCharCounter
maxLength={30}
/>
<Button
title="Add Caregiver"
onPress={() => {
createNewSubUser(caregiver);
}}
/>
<View margin-20>
<Text>Children:</Text>
{children.map((child) => (
<View key={child.name} row>
<Text>Name: {child.name} </Text>
<Picker label="Pick Caregiver">
{caregivers.map((item) => (
<Picker.Item
key={item.name}
label={item.name}
value={item.name}
/>
))}
</Picker>
</View>
))}
</View>
</View>
) : (
renderLogin()
)}
</View>
);
}; };
export default Screen; export default Screen;

View File

@ -5,7 +5,7 @@ import {useRouter} from "expo-router";
import firestore from "@react-native-firebase/firestore"; import firestore from "@react-native-firebase/firestore";
import {UserProfile} from "@/hooks/firebase/types/profileTypes"; import {UserProfile} from "@/hooks/firebase/types/profileTypes";
type ProfileType = "parent" | "child" | "caregiver" | null; export enum ProfileType { "parent", "child", "caregiver" }
interface IAuthContext { interface IAuthContext {
user: FirebaseAuthTypes.User | null, user: FirebaseAuthTypes.User | null,
@ -28,6 +28,8 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) =>
const onAuthStateChanged = async (user: FirebaseAuthTypes.User | null) => { const onAuthStateChanged = async (user: FirebaseAuthTypes.User | null) => {
setUser(user); setUser(user);
console.log(user)
if (user) { if (user) {
try { try {
const documentSnapshot = await firestore() const documentSnapshot = await firestore()
@ -41,7 +43,7 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) =>
} catch (error) { } catch (error) {
console.error("Error fetching user profile type:", error); console.error("Error fetching user profile type:", error);
setProfileType(null); setProfileType(undefined);
} }
} }

View File

@ -3,6 +3,7 @@ import {useMutation} from "react-query";
import auth from "@react-native-firebase/auth"; import auth from "@react-native-firebase/auth";
import firestore from "@react-native-firebase/firestore"; import firestore from "@react-native-firebase/firestore";
import {User,} from "./types/profileTypes"; import {User,} from "./types/profileTypes";
import {useSignUp} from "@/hooks/firebase/useSignUp";
type ProfileType = "parent" | "child" | "caregiver" | null; type ProfileType = "parent" | "child" | "caregiver" | null;
@ -17,6 +18,8 @@ const useAuth = () => {
auth().signInWithEmailAndPassword(email, password) auth().signInWithEmailAndPassword(email, password)
); );
const signOutMutation = useMutation(() => auth().signOut()); const signOutMutation = useMutation(() => auth().signOut());
const {mutateAsync: signUp } = useSignUp()
/*const setProfileDataMutation = useMutation((profileData) => { /*const setProfileDataMutation = useMutation((profileData) => {
const currentUser = auth().currentUser; const currentUser = auth().currentUser;
if (currentUser) { if (currentUser) {
@ -35,11 +38,12 @@ const useAuth = () => {
const handleRegister = async () => { const handleRegister = async () => {
try { try {
await createUserMutation.mutateAsync(); await signUp({email, password})
// await createUserMutation.mutateAsync();
console.log("User registered!"); console.log("User registered!");
await signInMutation.mutateAsync(); // await signInMutation.mutateAsync();
console.log("User signed in!"); // console.log("User signed in!");
/*let profileData: ParentProfile | ChildProfile | CaregiverProfile; /*let profileData: ParentProfile | ChildProfile | CaregiverProfile;
switch (profileType) { switch (profileType) {

View File

@ -1,12 +1,23 @@
import {useMutation} from "react-query"; import {useMutation, useQueryClient} from "react-query";
import {UserProfile} from "@/hooks/firebase/types/profileTypes"; import {UserProfile} from "@/hooks/firebase/types/profileTypes";
import functions from '@react-native-firebase/functions'; import functions from '@react-native-firebase/functions';
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
export const useCreateSubUser = () => { export const useCreateSubUser = () => {
const queryClient = useQueryClient()
const { profileType } = useAuthContext()
return useMutation({ return useMutation({
mutationKey: ["createSubUser"], mutationKey: ["createSubUser"],
mutationFn: async ({email, password, ...userProfile}: { email: string, password: string } & UserProfile) => { mutationFn: async ({email, password, ...userProfile}: { email: string, password: string } & UserProfile) => {
return await functions().httpsCallable("createSubUser")({email, password, ...userProfile}) if(profileType === ProfileType.parent) {
return await functions().httpsCallable("createSubUser")({email, password, ...userProfile})
} else {
throw Error("Can't create sub-users as a non-parent.")
}
},
onSuccess: () => {
queryClient.invalidateQueries({queryKey: ["getChildrenByParentId"]})
} }
}); });
} }

View File

@ -0,0 +1,34 @@
import {useQuery} from "react-query";
import {ChildProfile} from "@/hooks/firebase/types/profileTypes";
import firestore from "@react-native-firebase/firestore";
import {useAuthContext} from "@/contexts/AuthContext";
export const useGetChildrenByParentId = () => {
const {user} = useAuthContext()
return useQuery({
queryKey: ["getChildrenByParentId", user?.uid],
queryFn: async (): Promise<ChildProfile[]> => {
try {
const snapshot = await firestore()
.collection("Profiles")
.where("userType", "==", "child")
.where("parentId", "==", user?.uid!)
.get();
return snapshot.docs.map((doc) => {
const data = doc.data();
return {
...data,
birthday: data.birthday.toDate(),
} as ChildProfile;
});
} catch (error) {
console.error("Error retrieving child users:", error);
return [];
}
},
enabled: !!user?.uid
}
)
}

View File

@ -1,11 +1,15 @@
import {useMutation} from "react-query"; import {useMutation} from "react-query";
import auth from "@react-native-firebase/auth"; import auth from "@react-native-firebase/auth";
import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData";
export const useSignUp = () => { export const useSignUp = () => {
const { mutateAsync: updateUserData } = useUpdateUserData()
return useMutation({ return useMutation({
mutationKey: ["signUp"], mutationKey: ["signUp"],
mutationFn: async ({email, password}: { email: string, password: string }) => { mutationFn: async ({email, password}: { email: string, password: string }) => {
await auth().createUserWithEmailAndPassword(email, password) await auth().createUserWithEmailAndPassword(email, password)
await updateUserData({userType: "parent", email, password})
} }
}); });
} }