Added creating family devices, refetch calendar on notification received

This commit is contained in:
Milan Paunovic
2024-10-13 10:21:38 +02:00
parent 9123aab566
commit 1e506dd246
6 changed files with 479 additions and 391 deletions

View File

@ -1,322 +1,388 @@
import { import {
Avatar, Avatar,
Button, Button,
Card, Card,
Colors, Colors,
Dialog, Dialog,
FloatingButton, FloatingButton,
PanningProvider, PanningProvider,
Picker, Picker,
Text, Text,
TextField, TextField,
TouchableOpacity, TouchableOpacity,
View, View,
} from "react-native-ui-lib"; } from "react-native-ui-lib";
import React, { useState } from "react"; import React, {useState} from "react";
import { ScrollView, StyleSheet } from "react-native"; import {ScrollView, StyleSheet} from "react-native";
import { PickerSingleValue } from "react-native-ui-lib/src/components/picker/types"; import {PickerSingleValue} from "react-native-ui-lib/src/components/picker/types";
import { useCreateSubUser } from "@/hooks/firebase/useCreateSubUser"; import {useCreateSubUser} from "@/hooks/firebase/useCreateSubUser";
import { ProfileType } from "@/contexts/AuthContext"; import {ProfileType} from "@/contexts/AuthContext";
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers"; import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
import UserMenu from "@/components/pages/settings/user_settings_views/UserMenu"; import UserMenu from "@/components/pages/settings/user_settings_views/UserMenu";
import {uuidv4} from "@firebase/util";
const MyGroup = () => { const MyGroup = () => {
const [showAddUserDialog, setShowAddUserDialog] = useState(false); const [showAddUserDialog, setShowAddUserDialog] = useState(false);
const [showNewUserInfoDialog, setShowNewUserInfoDialog] = useState(false); const [showNewUserInfoDialog, setShowNewUserInfoDialog] = useState(false);
const [selectedStatus, setSelectedStatus] = useState< const [selectedStatus, setSelectedStatus] = useState<
string | PickerSingleValue string | PickerSingleValue
>(ProfileType.CHILD); >(ProfileType.CHILD);
const [firstName, setFirstName] = useState(""); const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState(""); const [lastName, setLastName] = useState("");
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const { mutateAsync: createSubUser, isLoading, isError } = useCreateSubUser(); const [showQRCodeDialog, setShowQRCodeDialog] = useState("");
const { data: familyMembers } = useGetFamilyMembers(true);
const parents = const {mutateAsync: createSubUser, isLoading, isError} = useCreateSubUser();
familyMembers?.filter((x) => x.userType === ProfileType.PARENT) ?? []; const {data: familyMembers} = useGetFamilyMembers(true);
const children =
familyMembers?.filter((x) => x.userType === ProfileType.CHILD) ?? [];
const caregivers =
familyMembers?.filter((x) => x.userType === ProfileType.CAREGIVER) ?? [];
const handleCreateSubUser = async () => { const parents =
if (!firstName || !lastName || !email) { familyMembers?.filter((x) => x.userType === ProfileType.PARENT) ?? [];
console.error("All fields are required"); const children =
return; familyMembers?.filter((x) => x.userType === ProfileType.CHILD) ?? [];
} const caregivers =
familyMembers?.filter((x) => x.userType === ProfileType.CAREGIVER) ?? [];
const familyDevices =
familyMembers?.filter((x) => x.userType === ProfileType.FAMILY_DEVICE) ?? [];
if (!email.includes("@")) { const handleCreateSubUser = async () => {
console.error("Invalid email address"); if (!firstName || (selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName)) {
return; console.error("First name and last name are required");
} return;
}
await createSubUser({ if (selectedStatus !== ProfileType.FAMILY_DEVICE && !email) {
firstName, console.error("Email is required for non-family device users");
lastName, return;
email, }
password: email,
userType: selectedStatus as ProfileType,
});
if (!isError) { if (email && !email.includes("@")) {
setShowNewUserInfoDialog(false); console.error("Invalid email address");
} return;
}; }
console.log(familyMembers); const res = await createSubUser({
firstName,
lastName: selectedStatus === ProfileType.FAMILY_DEVICE ? "" : lastName,
email: email || `placeholder_${uuidv4().split("-")[0]}@family.device`,
password: uuidv4(),
userType: selectedStatus as ProfileType,
});
console.log(res)
return ( if (!isError) {
<View style={{ flex: 1 }}> setShowNewUserInfoDialog(false);
<View>
<ScrollView style={styles.card}>
{!parents.length && !children.length && !caregivers.length && (
<Text text70 marginV-10>
{isLoading ? "Loading...." : "No user devices added"}
</Text>
)}
{(!!parents.length || !!children.length) && ( if(res?.data?.userId) {
<> setTimeout(() => {
<Text text70 marginV-10> setShowQRCodeDialog(res.data.userId)
Family }, 500)
</Text> }
{[...parents, ...children]?.map((member) => ( }
<Card
enableShadow={false}
elevation={0}
key={`${member.firstName}_${member.lastName}`}
style={styles.familyCard}
row
centerV
padding-10
>
<Avatar
source={{ uri: "https://via.placeholder.com/60" }}
size={40}
backgroundColor={Colors.grey60}
/>
<View marginL-10>
<Text text70M>
{member.firstName} {member.lastName}
</Text>
<Text text90 grey40>
{member.userType === ProfileType.PARENT
? "Admin (You)"
: "Child"}
</Text>
</View>
<View flex-1 />
<UserMenu userId={member?.uid!} /> };
</Card>
))}
</>
)}
{!!caregivers.length && ( return (
<> <View style={{flex: 1}}>
<Text text70 marginB-10 marginT-15> <View>
Caregivers <ScrollView style={styles.card}>
</Text> {!parents.length && !children.length && !caregivers.length && (
{caregivers?.map((member) => ( <Text text70 marginV-10>
<Card {isLoading ? "Loading...." : "No user devices added"}
enableShadow={false} </Text>
elevation={0} )}
key={`${member.firstName}_${member.lastName}`}
style={styles.familyCard}
row
centerV
padding-10
>
<Avatar
source={{ uri: "https://via.placeholder.com/60" }}
size={40}
backgroundColor={Colors.grey60}
/>
<View marginL-10>
<Text text70M>
{member.firstName} {member.lastName}
</Text>
<Text text90 grey40>
Caregiver
</Text>
</View>
</Card>
))}
</>
)}
</ScrollView>
</View>
<FloatingButton {(!!parents.length || !!children.length) && (
fullWidth <>
hideBackgroundOverlay <Text text70 marginV-10>
visible Family
button={{ </Text>
label: "+ Add a user device", {[...parents, ...children]?.map((member, index) => (
onPress: () => setShowAddUserDialog(true), <Card
}} enableShadow={false}
/> elevation={0}
key={`${member.firstName}_${member.lastName}_${index}`}
style={styles.familyCard}
row
centerV
padding-10
>
<Avatar
source={{uri: "https://via.placeholder.com/60"}}
size={40}
backgroundColor={Colors.grey60}
/>
<View marginL-10>
<Text text70M>
{member.firstName} {member.lastName}
</Text>
<Text text90 grey40>
{member.userType === ProfileType.PARENT
? "Admin (You)"
: "Child"}
</Text>
</View>
<Dialog <View flex-1/>
visible={showAddUserDialog}
onDismiss={() => setShowAddUserDialog(false)}
panDirection={PanningProvider.Directions.DOWN}
>
<Card padding-25 gap-10>
<Text>Add a new user device</Text>
<Button backgroundColor={"#FD1775"}> <UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
<Text white>Show a QR Code</Text> </Card>
</Button> ))}
<Button </>
backgroundColor={"#05A8B6"} )}
onPress={() => {
setShowAddUserDialog(false);
setTimeout(() => {
setShowNewUserInfoDialog(true);
}, 500);
}}
>
<Text white>Enter email address</Text>
</Button>
<TouchableOpacity onPress={() => setShowAddUserDialog(false)} center> {!!caregivers.length && (
<Text>Return to user settings</Text> <>
</TouchableOpacity> <Text text70 marginB-10 marginT-15>
</Card> Caregivers
</Dialog> </Text>
{caregivers?.map((member) => (
<Card
enableShadow={false}
elevation={0}
key={`${member.firstName}_${member.lastName}`}
style={styles.familyCard}
row
centerV
padding-10
>
<Avatar
source={{uri: "https://via.placeholder.com/60"}}
size={40}
backgroundColor={Colors.grey60}
/>
<View marginL-10>
<Text text70M>
{member.firstName} {member.lastName}
</Text>
<Text text90 grey40>
Caregiver
</Text>
</View>
<Dialog <UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
panDirection={PanningProvider.Directions.DOWN} </Card>
visible={showNewUserInfoDialog} ))}
onDismiss={() => setShowNewUserInfoDialog(false)} </>
> )}
<Card padding-25 style={styles.dialogCard}>
<View row spread>
<Text text60M>New User Information</Text>
<TouchableOpacity onPress={() => setShowAddUserDialog(false)}>
<Text>X</Text>
</TouchableOpacity>
</View>
<View row centerV gap-20 marginV-20> {!!familyDevices.length && (
<Avatar <>
imageStyle={{ borderRadius: 10 }} <Text text70 marginB-10 marginT-15>
containerStyle={{ borderRadius: 10 }} Family Devices
size={60} </Text>
backgroundColor={Colors.grey60} {familyDevices?.map((member, index) => (
<Card
enableShadow={false}
elevation={0}
key={`${member.firstName}_${member.lastName}_${index}`}
style={styles.familyCard}
row
centerV
padding-10
>
<Avatar
source={{uri: "https://via.placeholder.com/60"}}
size={40}
backgroundColor={Colors.grey60}
/>
<View marginL-10>
<Text text70M>
{member.firstName}
</Text>
<Text text90 grey40>
Family Device
</Text>
</View>
<UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
</Card>
))}
</>
)}
</ScrollView>
</View>
<FloatingButton
fullWidth
hideBackgroundOverlay
visible
button={{
label: "+ Add a user device",
onPress: () => setShowAddUserDialog(true),
}}
/> />
<TouchableOpacity onPress={() => {}}>
<Text style={{ color: Colors.green10 }}>
Upload User Profile Photo
</Text>
</TouchableOpacity>
</View>
<Text style={styles.label}>Member Status</Text> <Dialog
<Picker visible={showAddUserDialog}
editable={!isLoading} onDismiss={() => setShowAddUserDialog(false)}
value={selectedStatus} panDirection={PanningProvider.Directions.DOWN}
//@ts-ignore >
onChange={(item) => setSelectedStatus(item)} <Card padding-25 gap-10>
style={styles.picker} <Text>Add a new user device</Text>
showSearch
floatingPlaceholder
>
<Picker.Item label="Child" value={ProfileType.CHILD} />
<Picker.Item label="Parent" value={ProfileType.PARENT} />
<Picker.Item label="Caregiver" value={ProfileType.CAREGIVER} />
</Picker>
<Text style={styles.label}>First Name</Text> <Button backgroundColor={"#FD1775"}>
<TextField <Text white>Show a QR Code</Text>
editable={!isLoading} </Button>
placeholder="First name" <Button
value={firstName} backgroundColor={"#05A8B6"}
onChangeText={setFirstName} onPress={() => {
style={styles.inputField} setShowAddUserDialog(false);
/> setTimeout(() => {
setShowNewUserInfoDialog(true);
}, 500);
}}
>
<Text white>Enter email address</Text>
</Button>
<Text style={styles.label}>Last Name</Text> <TouchableOpacity onPress={() => setShowAddUserDialog(false)} center>
<TextField <Text>Return to user settings</Text>
editable={!isLoading} </TouchableOpacity>
placeholder="Last name" </Card>
value={lastName} </Dialog>
onChangeText={setLastName}
style={styles.inputField}
/>
<Text style={styles.label}>Email Address</Text> <Dialog
<TextField panDirection={PanningProvider.Directions.DOWN}
editable={!isLoading} visible={showNewUserInfoDialog}
placeholder="Email address" onDismiss={() => setShowNewUserInfoDialog(false)}
value={email} >
onChangeText={setEmail} <Card padding-25 style={styles.dialogCard}>
keyboardType="email-address" <View row spread>
autoCapitalize="none" <Text text60M>New User Information</Text>
style={styles.inputField} <TouchableOpacity onPress={() => setShowAddUserDialog(false)}>
/> <Text>X</Text>
</TouchableOpacity>
</View>
<Button <View row centerV gap-20 marginV-20>
disabled={!firstName || !lastName || !email || isLoading} <Avatar
label={isLoading ? "Adding..." : "Add group member"} imageStyle={{borderRadius: 10}}
backgroundColor="#FD1775" containerStyle={{borderRadius: 10}}
style={{ marginTop: 20 }} size={60}
onPress={handleCreateSubUser} backgroundColor={Colors.grey60}
/> />
</Card> <TouchableOpacity onPress={() => {
</Dialog> }}>
</View> <Text style={{color: Colors.green10}}>
); Upload User Profile Photo
</Text>
</TouchableOpacity>
</View>
<Text style={styles.label}>Member Status</Text>
<Picker
editable={!isLoading}
value={selectedStatus}
//@ts-ignore
onChange={(item) => setSelectedStatus(item)}
style={styles.picker}
showSearch
floatingPlaceholder
>
<Picker.Item label="Child" value={ProfileType.CHILD}/>
<Picker.Item label="Parent" value={ProfileType.PARENT}/>
<Picker.Item label="Caregiver" value={ProfileType.CAREGIVER}/>
<Picker.Item label="Family Device" value={ProfileType.FAMILY_DEVICE}/>
</Picker>
<Text style={styles.label}>
{selectedStatus === ProfileType.FAMILY_DEVICE ? "Device Name" : "First Name"}
</Text>
<TextField
editable={!isLoading}
placeholder={selectedStatus === ProfileType.FAMILY_DEVICE ? "Device name" : "First name"}
value={firstName}
onChangeText={setFirstName}
style={styles.inputField}
/>
{selectedStatus !== ProfileType.FAMILY_DEVICE && (
<>
<Text style={styles.label}>Last Name</Text>
<TextField
editable={!isLoading}
placeholder="Last name"
value={lastName}
onChangeText={setLastName}
style={styles.inputField}
/>
</>
)}
{selectedStatus !== ProfileType.FAMILY_DEVICE && (
<>
<Text style={styles.label}>Email Address (Optional)</Text>
<TextField
editable={!isLoading}
placeholder="Email address"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
style={styles.inputField}
/>
</>
)}
<Button
disabled={!firstName || (selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName) || isLoading}
label={isLoading ? "Adding..." : "Add group member"}
backgroundColor="#FD1775"
style={{marginTop: 20}}
onPress={handleCreateSubUser}
/>
</Card>
</Dialog>
</View>
);
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
card: { card: {
marginVertical: 15, marginVertical: 15,
backgroundColor: "white", backgroundColor: "white",
width: "100%", width: "100%",
borderRadius: 15, borderRadius: 15,
padding: 20, padding: 20,
}, },
familyCard: { familyCard: {
marginBottom: 10, marginBottom: 10,
borderRadius: 10, borderRadius: 10,
backgroundColor: Colors.white, backgroundColor: Colors.white,
width: "100%", width: "100%",
}, },
inputField: { inputField: {
borderRadius: 50, borderRadius: 50,
paddingVertical: 12, paddingVertical: 12,
paddingHorizontal: 16, paddingHorizontal: 16,
backgroundColor: Colors.grey80, backgroundColor: Colors.grey80,
marginBottom: 16, marginBottom: 16,
borderColor: Colors.grey50, borderColor: Colors.grey50,
borderWidth: 1, borderWidth: 1,
height: 40, height: 40,
}, },
picker: { picker: {
borderRadius: 50, borderRadius: 50,
paddingVertical: 12, paddingVertical: 12,
paddingHorizontal: 16, paddingHorizontal: 16,
backgroundColor: Colors.grey80, backgroundColor: Colors.grey80,
marginBottom: 16, marginBottom: 16,
borderColor: Colors.grey50, borderColor: Colors.grey50,
borderWidth: 1, borderWidth: 1,
marginTop: -20, marginTop: -20,
height: 40, height: 40,
}, },
label: { label: {
marginBottom: 5, marginBottom: 5,
fontSize: 12, fontSize: 12,
color: Colors.grey40, color: Colors.grey40,
}, },
dialogCard: { dialogCard: {
borderRadius: 10, borderRadius: 10,
gap: 10, gap: 10,
}, },
}); });
export default MyGroup; export default MyGroup;

View File

@ -1,102 +1,102 @@
import { View, Text, TextField } from "react-native-ui-lib"; import {Text, TextField, View} from "react-native-ui-lib";
import React, { useState } from "react"; import React, {useState} from "react";
import { StyleSheet } from "react-native"; import {StyleSheet} from "react-native";
import { ScrollView } from "react-native-gesture-handler"; import {ScrollView} from "react-native-gesture-handler";
import { useAuthContext } from "@/contexts/AuthContext"; import {useAuthContext} from "@/contexts/AuthContext";
import { useSettingsContext } from "@/contexts/SettingsContext"; import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData";
import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
const MyProfile = () => { const MyProfile = () => {
const { user, profileData } = useAuthContext(); const {user, profileData} = useAuthContext();
const [lastName, setLastName] = useState<string>(profileData?.lastName || ""); const [lastName, setLastName] = useState<string>(profileData?.lastName || "");
const [firstName, setFirstName] = useState<string>( const [firstName, setFirstName] = useState<string>(
profileData?.firstName || "" profileData?.firstName || ""
); );
const { mutateAsync: updateUserData } = useUpdateUserData(); const {mutateAsync: updateUserData} = useUpdateUserData();
return ( return (
<ScrollView style={{paddingBottom: 100, flex: 1}}> <ScrollView style={{paddingBottom: 100, flex: 1}}>
<View style={styles.card}> <View style={styles.card}>
<Text text70>Your Profile</Text> <Text text70>Your Profile</Text>
<View row spread paddingH-15 centerV marginV-15> <View row spread paddingH-15 centerV marginV-15>
<View style={styles.pfp}></View> <View style={styles.pfp}></View>
<Text text80 color="#50be0c"> <Text text80 color="#50be0c">
Change Photo Change Photo
</Text> </Text>
<Text text80>Remove Photo</Text> <Text text80>Remove Photo</Text>
</View> </View>
<View paddingH-15> <View paddingH-15>
<Text text80 marginT-10 marginB-7 color="#a1a1a1"> <Text text80 marginT-10 marginB-7 color="#a1a1a1">
First name First name
</Text> </Text>
<TextField <TextField
text70 text70
placeholder="First name" placeholder="First name"
style={styles.txtBox} style={styles.txtBox}
value={firstName} value={firstName}
onChangeText={async (value) => { onChangeText={async (value) => {
setFirstName(value); setFirstName(value);
await updateUserData({ newUserData: { firstName: value } }); await updateUserData({newUserData: {firstName: value}});
}} }}
/> />
<Text text80 marginT-10 marginB-7 color="#a1a1a1"> <Text text80 marginT-10 marginB-7 color="#a1a1a1">
Last name Last name
</Text> </Text>
<TextField <TextField
text70 text70
placeholder="Last name" placeholder="Last name"
style={styles.txtBox} style={styles.txtBox}
value={lastName} value={lastName}
onChangeText={async (value) => { onChangeText={async (value) => {
setLastName(value); setLastName(value);
await updateUserData({ newUserData: { lastName: value } }); await updateUserData({newUserData: {lastName: value}});
}} }}
/> />
<Text text80 marginT-10 marginB-7 color="#a1a1a1"> <Text text80 marginT-10 marginB-7 color="#a1a1a1">
Email address Email address
</Text> </Text>
<TextField <TextField
text70 text70
placeholder="Email address" placeholder="Email address"
value={user?.email?.toString()} value={user?.email?.toString()}
style={styles.txtBox} style={styles.txtBox}
/> />
</View> </View>
</View> </View>
<View style={styles.card}> <View style={styles.card}>
<Text text70>Settings</Text> <Text text70>Settings</Text>
<Text text80 marginT-20 marginB-7 color="#a1a1a1"> <Text text80 marginT-20 marginB-7 color="#a1a1a1">
Time Zone Time Zone
</Text> </Text>
<TextField text70 placeholder="Time Zone" style={styles.txtBox} /> <TextField text70 placeholder="Time Zone" style={styles.txtBox}/>
</View> </View>
</ScrollView> </ScrollView>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
card: { card: {
marginVertical: 15, marginVertical: 15,
backgroundColor: "white", backgroundColor: "white",
width: "100%", width: "100%",
borderRadius: 15, borderRadius: 15,
padding: 20, padding: 20,
}, },
pfp: { pfp: {
aspectRatio: 1, aspectRatio: 1,
width: 60, width: 60,
backgroundColor: "green", backgroundColor: "green",
borderRadius: 20, borderRadius: 20,
}, },
txtBox: { txtBox: {
backgroundColor: "#fafafa", backgroundColor: "#fafafa",
borderRadius: 50, borderRadius: 50,
borderWidth: 2, borderWidth: 2,
borderColor: "#cecece", borderColor: "#cecece",
padding: 15, padding: 15,
height: 45, height: 45,
}, },
}); });
export default MyProfile; export default MyProfile;

View File

@ -3,15 +3,22 @@ import {Button, Card, Colors, Dialog, Hint, ListItem, Text, View} from 'react-na
import QRCode from 'react-native-qrcode-svg'; import QRCode from 'react-native-qrcode-svg';
import {PanningDirectionsEnum} from "react-native-ui-lib/src/components/panningViews/panningProvider"; import {PanningDirectionsEnum} from "react-native-ui-lib/src/components/panningViews/panningProvider";
const UserMenu = ({userId}:{userId: string}) => { const UserMenu = ({
userId,
showQRCodeDialog,
setShowQRCodeDialog
}: {
userId: string,
showQRCodeDialog: boolean,
setShowQRCodeDialog: (value: boolean) => void
}) => {
const [showHint, setShowHint] = useState(false); const [showHint, setShowHint] = useState(false);
const [showQRCodeDialog, setShowQRCodeDialog] = useState(false);
const handleShowQRCode = () => { const handleShowQRCode = () => {
setShowHint(false); setShowHint(false);
setTimeout(() => { setTimeout(() => {
setShowQRCodeDialog(true); setShowQRCodeDialog(true);
}, 500) }, 500);
}; };
return ( return (
@ -22,9 +29,7 @@ const UserMenu = ({userId}:{userId: string}) => {
color={Colors.white} color={Colors.white}
customContent={ customContent={
<View height={18}> <View height={18}>
<ListItem <ListItem onPress={handleShowQRCode}>
onPress={handleShowQRCode}
>
<Text>Show Login QR Code</Text> <Text>Show Login QR Code</Text>
</ListItem> </ListItem>
</View> </View>
@ -34,7 +39,7 @@ const UserMenu = ({userId}:{userId: string}) => {
backdropColor="transparent" backdropColor="transparent"
> >
<View> <View>
<Button link onPress={() => setShowHint(x => !x)}> <Button link onPress={() => setShowHint(!showHint)}>
<Text>...</Text> <Text>...</Text>
</Button> </Button>
</View> </View>
@ -47,7 +52,7 @@ const UserMenu = ({userId}:{userId: string}) => {
> >
<Card padding-20 center> <Card padding-20 center>
<Text marginB-10>Scan this QR Code to Login:</Text> <Text marginB-10>Scan this QR Code to Login:</Text>
<QRCode value={userId} size={150} /> <QRCode value={userId} size={150}/>
<Button <Button
marginT-20 marginT-20
label="Close" label="Close"

View File

@ -9,11 +9,14 @@ import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device'; import * as Device from 'expo-device';
import Constants from 'expo-constants'; import Constants from 'expo-constants';
import { Platform } from 'react-native'; import { Platform } from 'react-native';
import {useQueryClient} from "react-query";
export enum ProfileType { export enum ProfileType {
"PARENT" = "parent", "PARENT" = "parent",
"CHILD" = "child", "CHILD" = "child",
"CAREGIVER" = "caregiver" "CAREGIVER" = "caregiver",
FAMILY_DEVICE = "FAMILY_DEVICE"
} }
interface IAuthContext { interface IAuthContext {
@ -91,6 +94,8 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) =>
const {replace} = useRouter(); const {replace} = useRouter();
const ready = !initializing; const ready = !initializing;
const queryClient = useQueryClient();
const onAuthStateChangedHandler = async (authUser: FirebaseAuthTypes.User | null) => { const onAuthStateChangedHandler = async (authUser: FirebaseAuthTypes.User | null) => {
setUser(authUser); setUser(authUser);
@ -153,6 +158,17 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) =>
} }
}, [user, ready]); }, [user, ready]);
useEffect(() => {
const sub = Notifications.addNotificationReceivedListener(notification => {
const eventId = notification?.request?.content?.data?.eventId;
if (eventId) {
queryClient.invalidateQueries(['events']);
}
});
return () => sub.remove()
}, []);
if (!ready) { if (!ready) {
return null; return null;
} }

View File

@ -132,7 +132,7 @@ exports.createSubUser = onRequest(async (request, response) => {
const {userType, firstName, lastName, email, password, familyId} = request.body.data; const {userType, firstName, lastName, email, password, familyId} = request.body.data;
if (!email || !password || !firstName || !lastName || !userType || !familyId) { if (!email || !password || !firstName || !userType || !familyId) {
logger.warn("Missing required fields in request body", {requestBody: request.body.data}); logger.warn("Missing required fields in request body", {requestBody: request.body.data});
response.status(400).json({error: "Missing required fields"}); response.status(400).json({error: "Missing required fields"});
return; return;

View File

@ -2,6 +2,7 @@ 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"; import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
import {HttpsCallableResult} from "@firebase/functions";
export const useCreateSubUser = () => { export const useCreateSubUser = () => {
const queryClient = useQueryClient() const queryClient = useQueryClient()
@ -9,13 +10,13 @@ export const useCreateSubUser = () => {
return useMutation({ return useMutation({
mutationKey: ["createSubUser"], mutationKey: ["createSubUser"],
mutationFn: async ({email, ...userProfile}: { email: string } & UserProfile) => { mutationFn: async ({email, ...userProfile}: { email?: string } & UserProfile) => {
if (profileType === ProfileType.PARENT) { if (profileType === ProfileType.PARENT) {
return await functions().httpsCallable("createSubUser")({ return await functions().httpsCallable("createSubUser")({
...userProfile, ...userProfile,
email, email,
familyId: profileData?.familyId familyId: profileData?.familyId
}) }) as HttpsCallableResult<{ userId: string }>
} else { } else {
throw Error("Can't create sub-users as a non-parent.") throw Error("Can't create sub-users as a non-parent.")
} }