Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Dejan
2024-11-18 00:17:58 +01:00
7 changed files with 204 additions and 37 deletions

View File

@ -3,6 +3,7 @@ import { ScrollView, RefreshControl } from "react-native";
import { useSetAtom } from "jotai";
import CalendarPage from "@/components/pages/calendar/CalendarPage";
import { refreshTriggerAtom } from "@/components/pages/calendar/atoms";
import { colorMap } from "@/constants/colorMap";
export default function Screen() {
const [refreshing, setRefreshing] = useState(false);
@ -29,7 +30,19 @@ export default function Screen() {
style={{ flex: 1 }}
contentContainerStyle={{ flex: 1 }}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
<RefreshControl
colors={[
colorMap.pink,
colorMap.green,
colorMap.orange,
colorMap.purple,
colorMap.teal,
]}
tintColor={colorMap.pink}
progressBackgroundColor={"white"}
refreshing={refreshing}
onRefresh={onRefresh}
/>
}
bounces={true}
showsVerticalScrollIndicator={false}

View File

@ -1,17 +1,24 @@
import {SafeAreaView} from "react-native-safe-area-context";
import {Button, Text, View} from "react-native-ui-lib";
import React from "react";
import React, { useEffect } from "react";
import {useCalSync} from "@/hooks/useCalSync";
import GoogleIcon from "@/assets/svgs/GoogleIcon";
import AppleIcon from "@/assets/svgs/AppleIcon";
import OutlookIcon from "@/assets/svgs/OutlookIcon";
import {useAuthContext} from "@/contexts/AuthContext";
import {StyleSheet} from "react-native";
import { useGetHouseholdName } from "@/hooks/firebase/useGetHouseholdName";
export default function Screen() {
const {profileData, setRedirectOverride} = useAuthContext()
const {handleStartGoogleSignIn, handleAppleSignIn, handleMicrosoftSignIn} = useCalSync()
const {data: householdName, refetch} = useGetHouseholdName(profileData?.familyId);
useEffect(() => {
refetch();
}, [profileData?.familyId])
const hasSomeCalendarsSynced =
!!profileData?.appleAccounts || !!profileData?.microsoftAccounts || !!profileData?.googleAccounts
@ -19,6 +26,9 @@ export default function Screen() {
<SafeAreaView style={{flex: 1}}>
<View style={{flex: 1, padding: 21, paddingBottom: 45, paddingTop: "20%", alignItems: "center"}}>
<View gap-13 width={"100%"} marginB-20>
{householdName && <Text style={{fontSize: 25, fontFamily: 'Manrope_600SemiBold'}}>
You Joined {householdName}
</Text>}
<Text style={{fontSize: 40, fontFamily: 'Manrope_600SemiBold'}}>
Let's get started!
</Text>

View File

@ -2,19 +2,38 @@ import React from "react";
import { View } from "react-native-ui-lib";
import HeaderTemplate from "@/components/shared/HeaderTemplate";
import { InnerCalendar } from "@/components/pages/calendar/InnerCalendar";
import { useSetAtom } from "jotai";
import { refreshEnabledAtom } from "./atoms";
export default function CalendarPage() {
const setRefreshEnabled = useSetAtom(refreshEnabledAtom);
const disableRefreshControl = () => setRefreshEnabled(false);
const enableRefreshControl = () => setRefreshEnabled(true);
return (
<View
style={{ flex: 1, height: "100%", padding: 10 }}
paddingH-22
paddingT-0
>
<HeaderTemplate
message={"Let's get your week started !"}
isWelcome
isCalendar={true}
/>
<View
onStartShouldSetResponder={() => {
enableRefreshControl();
console.log("yeah");
return true;
}}
onResponderRelease={() => {
disableRefreshControl();
console.log("sure");
console.log(refreshEnabledAtom)
}}
>
<HeaderTemplate
message={"Let's get your week started !"}
isWelcome
isCalendar={true}
/>
</View>
<InnerCalendar />
</View>
);

View File

@ -12,3 +12,4 @@ export const settingsPageIndex = atom<number>(0);
export const userSettingsView = atom<boolean>(true);
export const toDosPageIndex = atom<number>(0);
export const refreshTriggerAtom = atom<boolean>(false);
export const refreshEnabledAtom = atom<boolean>(true);

View File

@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useRef, useState} from "react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { StyleSheet, TouchableOpacity } from "react-native";
import { ScrollView } from "react-native-gesture-handler";
import * as ImagePicker from "expo-image-picker";
@ -20,11 +20,17 @@ import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
import { useChangeProfilePicture } from "@/hooks/firebase/useChangeProfilePicture";
import { colorMap } from "@/constants/colorMap";
import DeleteProfileDialogs from "../user_components/DeleteProfileDialogs";
import {AntDesign} from "@expo/vector-icons";
import {useDeleteUser} from "@/hooks/firebase/useDeleteUser";
import { AntDesign } from "@expo/vector-icons";
import { useDeleteUser } from "@/hooks/firebase/useDeleteUser";
import { useUpdateHouseholdName } from "@/hooks/firebase/useUpdateHouseholdName";
import { useGetHouseholdName } from "@/hooks/firebase/useGetHouseholdName";
const MyProfile = () => {
const { user, profileData } = useAuthContext();
const { data: hhName, refetch: refetchHHName } = useGetHouseholdName(
profileData.familyId
);
const [householdName, setHouseholdName] = useState<string>("");
const [timeZone, setTimeZone] = useState<string>(
profileData?.timeZone! ?? Localization.getCalendars()[0].timeZone
);
@ -37,10 +43,10 @@ const MyProfile = () => {
>(profileData?.pfp || null);
const [selectedColor, setSelectedColor] = useState<string>(
profileData?.eventColor ?? colorMap.pink
profileData?.eventColor ?? colorMap.pink
);
const [previousSelectedColor, setPreviousSelectedColor] = useState<string>(
profileData?.eventColor ?? colorMap.pink
profileData?.eventColor ?? colorMap.pink
);
const [showDeleteDialog, setShowDeleteDialog] = useState<boolean>(false);
@ -52,15 +58,25 @@ const MyProfile = () => {
setShowDeleteDialog(true);
};
const { mutateAsync: updateHouseholdName } = useUpdateHouseholdName();
const { mutateAsync: updateUserData } = useUpdateUserData();
const { mutateAsync: changeProfilePicture } = useChangeProfilePicture();
const { mutateAsync: deleteAsync } = useDeleteUser()
const { mutateAsync: deleteAsync } = useDeleteUser();
const isFirstRender = useRef(true);
const handleUpdateUserData = async () => {
await updateUserData({ newUserData: { firstName, lastName, timeZone } });
};
const handleUpdateHouseholdName = async () => {
if (profileData?.familyId) {
await updateHouseholdName({
familyId: profileData.familyId,
name: householdName,
});
}
};
const debouncedUserDataUpdate = debounce(handleUpdateUserData, 500);
useEffect(() => {
@ -71,6 +87,10 @@ const MyProfile = () => {
debouncedUserDataUpdate();
}, [timeZone, lastName, firstName]);
useEffect(() => {
handleUpdateHouseholdName();
}, [householdName]);
useEffect(() => {
if (profileData) {
setFirstName(profileData.firstName || "");
@ -81,6 +101,16 @@ const MyProfile = () => {
}
}, [profileData]);
useEffect(() => {
if (profileData?.familyId) {
refetchHHName();
}
}, [profileData?.familyId]);
useEffect(() => {
setHouseholdName(hhName);
}, [hhName])
const pickImage = async () => {
const permissionResult =
await ImagePicker.requestMediaLibraryPermissionsAsync();
@ -119,19 +149,19 @@ const MyProfile = () => {
};
const debouncedUpdateUserData = useCallback(
debounce(async (color: string) => {
try {
await updateUserData({
newUserData: {
eventColor: color,
},
});
} catch (error) {
console.error("Failed to update color:", error);
setSelectedColor(previousSelectedColor);
}
}, 500),
[]
debounce(async (color: string) => {
try {
await updateUserData({
newUserData: {
eventColor: color,
},
});
} catch (error) {
console.error("Failed to update color:", error);
setSelectedColor(previousSelectedColor);
}
}, 500),
[]
);
return (
@ -177,6 +207,18 @@ const MyProfile = () => {
)}
</View>
<View paddingH-15>
<Text text80 marginT-10 marginB-7 style={styles.label}>
Household
</Text>
<TextField
text70
placeholder="Household name"
style={styles.txtBox}
value={householdName}
onChangeText={async (value) => {
setHouseholdName(value);
}}
/>
<Text text80 marginT-10 marginB-7 style={styles.label}>
First name
</Text>
@ -255,39 +297,35 @@ const MyProfile = () => {
<TouchableOpacity onPress={() => handleChangeColor(colorMap.pink)}>
<View style={styles.colorBox} backgroundColor={colorMap.pink}>
{selectedColor == colorMap.pink && (
<AntDesign name="check" size={30} color="white"/>
<AntDesign name="check" size={30} color="white" />
)}
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => handleChangeColor(colorMap.orange)}
>
<TouchableOpacity onPress={() => handleChangeColor(colorMap.orange)}>
<View style={styles.colorBox} backgroundColor={colorMap.orange}>
{selectedColor == colorMap.orange && (
<AntDesign name="check" size={30} color="white"/>
<AntDesign name="check" size={30} color="white" />
)}
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => handleChangeColor(colorMap.green)}>
<View style={styles.colorBox} backgroundColor={colorMap.green}>
{selectedColor == colorMap.green && (
<AntDesign name="check" size={30} color="white"/>
<AntDesign name="check" size={30} color="white" />
)}
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => handleChangeColor(colorMap.teal)}>
<View style={styles.colorBox} backgroundColor={colorMap.teal}>
{selectedColor == colorMap.teal && (
<AntDesign name="check" size={30} color="white"/>
<AntDesign name="check" size={30} color="white" />
)}
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => handleChangeColor(colorMap.purple)}
>
<TouchableOpacity onPress={() => handleChangeColor(colorMap.purple)}>
<View style={styles.colorBox} backgroundColor={colorMap.purple}>
{selectedColor == colorMap.purple && (
<AntDesign name="check" size={30} color="white"/>
<AntDesign name="check" size={30} color="white" />
)}
</View>
</TouchableOpacity>

View File

@ -0,0 +1,36 @@
import { useQuery } from "react-query";
import firestore from "@react-native-firebase/firestore";
export const useGetHouseholdName = (familyId: string) => {
return useQuery(
["getHouseholdName", familyId], // Unique query key
async () => {
console.log(`Fetching household name for familyId: ${familyId}`);
try {
// Query the Households collection for the given familyId
const snapshot = await firestore()
.collection("Households")
.where("familyId", "==", familyId)
.get();
if (!snapshot.empty) {
// Extract the name from the first matching document
const householdData = snapshot.docs[0].data();
console.log("Household found:", householdData);
return householdData.name || null; // Return the name or null if missing
} else {
console.log("No household found for the given familyId.");
return null; // Return null if no household found
}
} catch (e) {
console.error("Error fetching household name:", e);
throw e; // Ensure error propagates to the query error handling
}
},
{
enabled: !!familyId, // Only fetch if familyId is provided
staleTime: 5 * 60 * 1000, // Cache the data for 5 minutes
}
);
};

View File

@ -0,0 +1,50 @@
import firestore from "@react-native-firebase/firestore";
import { useMutation, useQueryClient } from "react-query";
export const useUpdateHouseholdName = () => {
const queryClient = useQueryClient();
return useMutation({
mutationKey: ["updateHouseholdName"],
mutationFn: async ({
familyId,
name,
}: {
familyId: string;
name: string;
}) => {
console.log("Mutation function called with data:", { familyId, name });
try {
// Reference to the Households collection
const householdRef = firestore().collection("Households");
// Query to check if the household exists
const snapshot = await householdRef.where("familyId", "==", familyId).get();
if (!snapshot.empty) {
// If a household with the familyId exists, update the name
const docId = snapshot.docs[0].id;
console.log(`Household found with ID ${docId}, updating name...`);
await householdRef.doc(docId).update({ name });
console.log("Household name updated successfully.");
} else {
// If no household exists, create a new one with familyId and name
console.log("No household found, creating a new one...");
await householdRef.add({ familyId, name });
console.log("New household created successfully.");
}
} catch (e) {
console.error("Error updating or creating household:", e);
throw e; // Ensure error propagates to the mutation error handling
}
},
onSuccess: () => {
queryClient.invalidateQueries("households"); // Invalidate the "households" query to refresh data
},
});
};