diff --git a/calendar-integration/google-calendar-utils.js b/calendar-integration/google-calendar-utils.js index 26a0e26..982ab4e 100644 --- a/calendar-integration/google-calendar-utils.js +++ b/calendar-integration/google-calendar-utils.js @@ -1,5 +1,4 @@ export async function fetchGoogleCalendarEvents(token, email, familyId, startDate, endDate) { - console.log(token); const response = await fetch( `https://www.googleapis.com/calendar/v3/calendars/primary/events?single_events=true&time_min=${startDate}&time_max=${endDate}`, { @@ -10,7 +9,6 @@ export async function fetchGoogleCalendarEvents(token, email, familyId, startDat ); const data = await response.json(); - console.log(data); const googleEvents = []; data.items?.forEach((item) => { let isAllDay = false; @@ -41,7 +39,7 @@ export async function fetchGoogleCalendarEvents(token, email, familyId, startDat const googleEvent = { id: item.id, - title: item.summary, + title: item.summary ?? "", startDate: startDateTime, endDate: endDateTime, allDay: isAllDay, diff --git a/components/pages/calendar/ManuallyAddEventModal.tsx b/components/pages/calendar/ManuallyAddEventModal.tsx index 65cd90d..aacb252 100644 --- a/components/pages/calendar/ManuallyAddEventModal.tsx +++ b/components/pages/calendar/ManuallyAddEventModal.tsx @@ -421,7 +421,7 @@ export const ManuallyAddEventModal = () => { - diff --git a/components/pages/settings/CalendarSettingsPage.tsx b/components/pages/settings/CalendarSettingsPage.tsx index beb416c..a2e012b 100644 --- a/components/pages/settings/CalendarSettingsPage.tsx +++ b/components/pages/settings/CalendarSettingsPage.tsx @@ -90,8 +90,11 @@ const CalendarSettingsPage = (props: { const userInfo = await userInfoResponse.json(); const googleMail = userInfo.email; + let googleAccounts = profileData?.googleAccounts; + const updatedGoogleAccounts = googleAccounts ? {...googleAccounts, [googleMail]: accessToken} : {[googleMail]: accessToken}; + await updateUserData({ - newUserData: {googleToken: accessToken, googleMail: googleMail}, + newUserData: {googleAccounts: updatedGoogleAccounts}, }); await fetchAndSaveGoogleEvents({token: accessToken, email: googleMail}) @@ -171,9 +174,12 @@ const CalendarSettingsPage = (props: { } else { const outlookMail = userInfo.mail || userInfo.userPrincipalName; + let microsoftAccounts = profileData?.microsoftAccounts; + const updatedMicrosoftAccounts = microsoftAccounts ? {...microsoftAccounts, [outlookMail]: tokenData.access_token} : {[outlookMail]: tokenData.access_token}; + // Update user data with Microsoft token and email await updateUserData({ - newUserData: {microsoftToken: tokenData.access_token, outlookMail: outlookMail}, + newUserData: {microsoftAccounts: updatedMicrosoftAccounts}, }); await fetchAndSaveOutlookEvents(tokenData.access_token, outlookMail) @@ -263,21 +269,61 @@ const CalendarSettingsPage = (props: { debouncedUpdateUserData(color); }; - const clearToken = async (provider: "google" | "outlook" | "apple") => { + const clearToken = async (provider: "google" | "outlook" | "apple", email: string) => { const newUserData: Partial = {}; if (provider === "google") { - newUserData.googleToken = null; - newUserData.googleMail = null; + let googleAccounts = profileData?.googleAccounts; + if (googleAccounts) { + googleAccounts[email] = null; + newUserData.googleAccounts = googleAccounts; + } } else if (provider === "outlook") { - newUserData.microsoftToken = null; - newUserData.outlookMail = null; + let microsoftAccounts = profileData?.microsoftAccounts; + if (microsoftAccounts) { + microsoftAccounts[email] = null; + newUserData.microsoftAccounts = microsoftAccounts; + } } else if (provider === "apple") { - newUserData.appleToken = null; - newUserData.appleMail = null; + let appleAccounts = profileData?.appleAccounts; + if (appleAccounts) { + appleAccounts[email] = null; + newUserData.appleAccounts = appleAccounts; + } } await updateUserData({newUserData}); }; + let isConnectedToGoogle = false; + if (profileData?.googleAccounts) { + Object.values(profileData?.googleAccounts).forEach((item) => { + if (item !== null) { + isConnectedToGoogle = true; + return; + } + }); + } + + let isConnectedToMicrosoft = false; + const microsoftAccounts = profileData?.microsoftAccounts; + if (microsoftAccounts) { + Object.values(profileData?.microsoftAccounts).forEach((item) => { + if (item !== null) { + isConnectedToMicrosoft = true; + return; + } + }); + } + + let isConnectedToApple = false; + if (profileData?.appleAccounts) { + Object.values(profileData?.appleAccounts).forEach((item) => { + if (item !== null) { + isConnectedToApple = true; + return; + } + }); + } + return ( @@ -378,8 +424,8 @@ const CalendarSettingsPage = (props: { - - - - ); + + + + + + ); }; export default AddChore; const styles = StyleSheet.create({ - divider: { height: 1, backgroundColor: "#e4e4e4", marginVertical: 15 }, - gradient: { - height: "25%", - position: "absolute", - bottom: 0, - width: "100%", - }, - buttonContainer: { - position: "absolute", - bottom: 25, - width: "100%", - }, - button: { - backgroundColor: "rgb(253, 23, 117)", - paddingVertical: 20, - }, - topBtn: { - backgroundColor: "white", - color: "#05a8b6", - }, - rotateSwitch: { - marginLeft: 35, - marginBottom: 10, - marginTop: 25, - }, -}); + gradient: { + height: 150, + position: "absolute", + bottom: 0, + width: "100%", + justifyContent: "center", + alignItems: "center", + }, + buttonContainer: { + width: "100%", + alignItems: "center", + }, + button: { + backgroundColor: "rgb(253, 23, 117)", + paddingVertical: 15, + paddingHorizontal: 30, + borderRadius: 30, + }, +}); \ No newline at end of file diff --git a/components/pages/todos/AddChoreDialog.tsx b/components/pages/todos/AddChoreDialog.tsx index c8f061c..8a0782e 100644 --- a/components/pages/todos/AddChoreDialog.tsx +++ b/components/pages/todos/AddChoreDialog.tsx @@ -1,4 +1,4 @@ -import { View, Text, Button, Switch } from "react-native-ui-lib"; +import {View, Text, Button, Switch, PickerModes} from "react-native-ui-lib"; import React, { useRef, useState } from "react"; import PointsSlider from "@/components/shared/PointsSlider"; import { repeatOptions, useToDosContext } from "@/contexts/ToDosContext"; @@ -15,6 +15,7 @@ import { Dimensions, StyleSheet } from "react-native"; import DropModalIcon from "@/assets/svgs/DropModalIcon"; import { IToDo } from "@/hooks/firebase/types/todoData"; import AssigneesDisplay from "@/components/shared/AssigneesDisplay"; +import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers"; interface IAddChoreDialog { isVisible: boolean; @@ -29,6 +30,7 @@ const defaultTodo = { date: new Date(), rotate: false, repeatType: "Every week", + assignees: [] }; const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { @@ -36,12 +38,15 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { const [todo, setTodo] = useState( addChoreDialogProps.selectedTodo ?? defaultTodo ); + const [selectedAssignees, setSelectedAssignees] = useState(addChoreDialogProps?.selectedTodo?.assignees ?? []); const { width, height } = Dimensions.get("screen"); - const [points, setPoints] = useState(todo.points); + const {data: members} = useGetFamilyMembers(); + const handleClose = () => { setTodo(defaultTodo); + setSelectedAssignees([]); addChoreDialogProps.setIsVisible(false); }; @@ -95,12 +100,13 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { onPress={() => { try { if (addChoreDialogProps.selectedTodo) { - updateToDo({ ...todo, points: points }); + updateToDo({ ...todo, points: points, assignees: selectedAssignees }); } else { addToDo({ ...todo, done: false, points: points, + assignees: selectedAssignees }); } handleClose(); @@ -182,25 +188,46 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { Assignees - - } - /> - - )} - + + + {profileData?.userType == ProfileType.CHILD && ( + + setPageIndex(2)} + > + + View your full progress report here + + + } + /> + + )} + + + + + )} + {pageIndex == 1 && } + {pageIndex == 2 && } - - {profileData?.userType == ProfileType.PARENT && } - - )} - {pageIndex == 1 && } - {pageIndex == 2 && } - - ); + { + profileData?.userType == ProfileType.PARENT && + } + + ) + ; }; const styles = StyleSheet.create({ - linkBtn: { - backgroundColor: "transparent", - padding: 0, - }, + linkBtn: { + backgroundColor: "transparent", + padding: 0, + }, }); export default ToDosPage; diff --git a/components/shared/AssigneesDisplay.tsx b/components/shared/AssigneesDisplay.tsx index 9316394..90343ab 100644 --- a/components/shared/AssigneesDisplay.tsx +++ b/components/shared/AssigneesDisplay.tsx @@ -1,23 +1,23 @@ import React from "react"; -import {ImageBackground, StyleSheet} from "react-native"; -import {Text, TouchableOpacity, View} from "react-native-ui-lib"; +import {StyleSheet} from "react-native"; +import {Image, Text, TouchableOpacity, View} from "react-native-ui-lib"; import RemoveAssigneeBtn from "./RemoveAssigneeBtn"; import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers"; -const AssigneesDisplay = ({selectedAttendees, setSlectedAttendees}: { +const AssigneesDisplay = ({selectedAttendees, setSelectedAttendees}: { selectedAttendees: string[], - setSlectedAttendees: (value: React.SetStateAction) => void + setSelectedAttendees: (value: React.SetStateAction) => void }) => { const {data: members} = useGetFamilyMembers(true); - const selectedMembers = members?.filter((x) => selectedAttendees.includes(x?.uid!)); + const selectedMembers = members?.filter((x) => selectedAttendees?.includes(x?.uid!)); const getInitials = (firstName: string, lastName: string) => { return `${firstName.charAt(0)}${lastName.charAt(0)}`; }; const removeAttendee = (uid: string) => { - setSlectedAttendees((prev) => prev.filter((x) => x !== uid)); + setSelectedAttendees((prev) => prev.filter((x) => x !== uid)); } return ( @@ -26,7 +26,7 @@ const AssigneesDisplay = ({selectedAttendees, setSlectedAttendees}: { removeAttendee(member.uid!)}> {member?.pfp ? ( - } @@ -42,7 +42,7 @@ const AssigneesDisplay = ({selectedAttendees, setSlectedAttendees}: { ))} - {selectedAttendees.length === 0 && No attendees added} + {selectedAttendees?.length === 0 && No attendees added} ); }; diff --git a/firebase/functions/index.js b/firebase/functions/index.js index 8c59fcf..475f6d8 100644 --- a/firebase/functions/index.js +++ b/firebase/functions/index.js @@ -188,31 +188,47 @@ exports.refreshTokens = functions.pubsub.schedule('every 12 hours').onRun(async profilesSnapshot.forEach(async (profileDoc) => { const profileData = profileDoc.data(); - if (profileData.googleToken) { + if (profileData.googleAccounts) { try { - const refreshedGoogleToken = await refreshGoogleToken(profileData.googleToken); - await profileDoc.ref.update({googleToken: refreshedGoogleToken}); - console.log(`Google token updated for user ${profileDoc.id}`); + for (const googleEmail of Object.keys(profileData?.googleAccounts)) { + const googleToken = profileData?.googleAccounts?.[googleEmail]; + if (googleToken) { + const refreshedGoogleToken = await refreshGoogleToken(googleToken); + const updatedGoogleAccounts = {...profileData.googleAccounts, [googleEmail]: refreshedGoogleToken}; + await profileDoc.ref.update({googleAccounts: updatedGoogleAccounts}); + console.log(`Google token updated for user ${profileDoc.id}`); + } + } } catch (error) { console.error(`Error refreshing Google token for user ${profileDoc.id}:`, error.message); } } - if (profileData.microsoftToken) { + if (profileData.microsoftAccounts) { try { - const refreshedMicrosoftToken = await refreshMicrosoftToken(profileData.microsoftToken); - await profileDoc.ref.update({microsoftToken: refreshedMicrosoftToken}); - console.log(`Microsoft token updated for user ${profileDoc.id}`); + for (const microsoftEmail of Object.keys(profileData?.microsoftAccounts)) { + const microsoftToken = profileData?.microsoftAccounts?.[microsoftEmail]; + if (microsoftToken) { + const refreshedMicrosoftToken = await refreshMicrosoftToken(microsoftToken); + const updatedMicrosoftAccounts = {...profileData.microsoftAccounts, [microsoftEmail]: refreshedMicrosoftToken}; + await profileDoc.ref.update({microsoftAccounts: updatedMicrosoftAccounts}); + console.log(`Microsoft token updated for user ${profileDoc.id}`); + } + } } catch (error) { console.error(`Error refreshing Microsoft token for user ${profileDoc.id}:`, error.message); } } - if (profileData.appleToken) { + if (profileData.appleAccounts) { try { - const refreshedAppleToken = await refreshAppleToken(profileData.appleToken); - await profileDoc.ref.update({appleToken: refreshedAppleToken}); - console.log(`Apple token updated for user ${profileDoc.id}`); + for (const appleEmail of Object.keys(profileData?.appleAccounts)) { + const appleToken = profileData?.appleAccounts?.[appleEmail]; + const refreshedAppleToken = await refreshAppleToken(appleToken); + const updatedAppleAccounts = {...profileData.appleAccounts, [appleEmail]: refreshedAppleToken}; + await profileDoc.ref.update({appleAccunts: updatedAppleAccounts}); + console.log(`Apple token updated for user ${profileDoc.id}`); + } } catch (error) { console.error(`Error refreshing Apple token for user ${profileDoc.id}:`, error.message); } diff --git a/hooks/firebase/types/profileTypes.ts b/hooks/firebase/types/profileTypes.ts index 64bdd84..3179f65 100644 --- a/hooks/firebase/types/profileTypes.ts +++ b/hooks/firebase/types/profileTypes.ts @@ -17,16 +17,13 @@ export interface UserProfile { password: string; familyId?: string; uid?: string; - pfp?: string; - googleToken?: string | null; - microsoftToken?: string | null; - appleToken?: string | null; + pfp?: string | null; eventColor?: string | null; - googleMail?: string | null; - outlookMail?: string | null; - appleMail?: string | null; timeZone?: string | null; firstDayOfWeek?: string | null; + googleAccounts?: Object; + microsoftAccounts?: Object; + appleAccounts?: Object; } export interface ParentProfile extends UserProfile { diff --git a/hooks/firebase/types/todoData.ts b/hooks/firebase/types/todoData.ts index 515f4dd..0a1aea8 100644 --- a/hooks/firebase/types/todoData.ts +++ b/hooks/firebase/types/todoData.ts @@ -7,5 +7,6 @@ export interface IToDo { rotate: boolean; repeatType: string; creatorId?: string, - familyId?: string + familyId?: string, + assignees?: string[]; // Optional list of assignees } \ No newline at end of file diff --git a/hooks/firebase/useChangeProfilePicture.ts b/hooks/firebase/useChangeProfilePicture.ts new file mode 100644 index 0000000..4f0b97e --- /dev/null +++ b/hooks/firebase/useChangeProfilePicture.ts @@ -0,0 +1,57 @@ +import { useMutation, useQueryClient } from "react-query"; +import firestore from "@react-native-firebase/firestore"; +import storage from "@react-native-firebase/storage"; +import { useAuthContext } from "@/contexts/AuthContext"; +import * as ImagePicker from "expo-image-picker"; +import { Platform } from "react-native"; + +export const useChangeProfilePicture = () => { + const queryClient = useQueryClient(); + const { user, refreshProfileData } = useAuthContext(); + + return useMutation({ + mutationKey: ["changeProfilePicture"], + mutationFn: async (profilePicture: ImagePicker.ImagePickerAsset) => { + if (!profilePicture?.uri) { + throw new Error("No image selected"); + } + + let imageUri = profilePicture.uri; + + console.log("Selected image URI:", imageUri); + + if (Platform.OS === 'ios' && !imageUri.startsWith('file://')) { + imageUri = `file://${imageUri}`; + console.log("Updated image URI for iOS:", imageUri); + } + + const fileName = `profilePictures/${new Date().getTime()}_profile.jpg`; + console.log("Firebase Storage file path:", fileName); + + try { + const reference = storage().ref(fileName); + + console.log('Uploading image to Firebase Storage...'); + await reference.putFile(imageUri); + console.log('Image uploaded successfully!'); + + const downloadURL = await reference.getDownloadURL(); + console.log("Download URL:", downloadURL); + + await firestore() + .collection("Profiles") + .doc(user?.uid) + .update({ pfp: downloadURL }); + + } catch (e) { + console.error("Error uploading profile picture:", e.message); + throw e; + } + }, + onSuccess: () => { + // Invalidate queries to refresh profile data + queryClient.invalidateQueries("Profiles"); + refreshProfileData(); + }, + }); +}; \ No newline at end of file diff --git a/hooks/firebase/useGetFamilyMembers.ts b/hooks/firebase/useGetFamilyMembers.ts index 1657edf..e2d38c5 100644 --- a/hooks/firebase/useGetFamilyMembers.ts +++ b/hooks/firebase/useGetFamilyMembers.ts @@ -15,10 +15,24 @@ export const useGetFamilyMembers = (excludeSelf?: boolean) => { .get(); if (excludeSelf) { - return snapshot.docs.map((doc) => doc.data()).filter((doc) => doc.id !== user?.uid) as UserProfile[]; + return snapshot.docs.map((doc) => { + let documentData = doc.data(); + + return { + ...documentData, + uid: doc.id + } + }).filter((doc) => doc.id !== user?.uid) as UserProfile[]; } - return snapshot.docs.map((doc) => doc.data()) as UserProfile[]; + return snapshot.docs.map((doc) => { + let documentData = doc.data(); + + return { + ...documentData, + uid: doc.id + } + }) as UserProfile[]; } }) } \ No newline at end of file diff --git a/hooks/firebase/useGetTodos.ts b/hooks/firebase/useGetTodos.ts index d5821b9..b58834d 100644 --- a/hooks/firebase/useGetTodos.ts +++ b/hooks/firebase/useGetTodos.ts @@ -1,6 +1,8 @@ import { useQuery } from "react-query"; import firestore from "@react-native-firebase/firestore"; import { useAuthContext } from "@/contexts/AuthContext"; +import {UserProfile} from "@/hooks/firebase/types/profileTypes"; +import {IToDo} from "@/hooks/firebase/types/todoData"; export const useGetTodos = () => { const { user, profileData } = useAuthContext(); @@ -17,16 +19,11 @@ export const useGetTodos = () => { const data = doc.data(); return { + ...data, id: doc.id, - title: data.title, - done: data.done, date: data.date ? new Date(data.date.seconds * 1000) : null, - points: data.points, - rotate: data.points, - repeatType: data.repeatType, - creatorId: data.creatorId }; - }); + }) as IToDo[]; } }) }; \ No newline at end of file diff --git a/hooks/useFetchAndSaveGoogleEvents.ts b/hooks/useFetchAndSaveGoogleEvents.ts index bd3dbe2..7f823a0 100644 --- a/hooks/useFetchAndSaveGoogleEvents.ts +++ b/hooks/useFetchAndSaveGoogleEvents.ts @@ -14,12 +14,12 @@ export const useFetchAndSaveGoogleEvents = () => { const timeMin = new Date(new Date().setFullYear(new Date().getFullYear() - 1)); const timeMax = new Date(new Date().setFullYear(new Date().getFullYear() + 5)); - console.log("Token: ", token ?? profileData?.googleToken); + console.log("Token: ", token); try { const response = await fetchGoogleCalendarEvents( - token ?? profileData?.googleToken, - email ?? profileData?.googleMail, + token, + email, profileData?.familyId, timeMin.toISOString().slice(0, -5) + "Z", timeMax.toISOString().slice(0, -5) + "Z" diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f8b463d..b467d5a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1311,6 +1311,9 @@ PODS: - Firebase/Functions (10.29.0): - Firebase/CoreOnly - FirebaseFunctions (~> 10.29.0) + - Firebase/Storage (10.29.0): + - Firebase/CoreOnly + - FirebaseStorage (~> 10.29.0) - FirebaseAppCheckInterop (10.29.0) - FirebaseAuth (10.29.0): - FirebaseAppCheckInterop (~> 10.17) @@ -1382,6 +1385,13 @@ PODS: - nanopb (< 2.30911.0, >= 2.30908.0) - PromisesSwift (~> 2.1) - FirebaseSharedSwift (10.29.0) + - FirebaseStorage (10.29.0): + - FirebaseAppCheckInterop (~> 10.0) + - FirebaseAuthInterop (~> 10.25) + - FirebaseCore (~> 10.0) + - FirebaseCoreExtension (~> 10.0) + - GoogleUtilities/Environment (~> 7.12) + - GTMSessionFetcher/Core (< 4.0, >= 2.1) - fmt (9.1.0) - glog (0.3.5) - GoogleDataTransport (9.4.1): @@ -2719,6 +2729,10 @@ PODS: - Firebase/Functions (= 10.29.0) - React-Core - RNFBApp + - RNFBStorage (21.0.0): + - Firebase/Storage (= 10.29.0) + - React-Core + - RNFBApp - RNGestureHandler (2.16.2): - DoubleConversion - glog @@ -2897,6 +2911,7 @@ DEPENDENCIES: - "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)" - "RNFBFirestore (from `../node_modules/@react-native-firebase/firestore`)" - "RNFBFunctions (from `../node_modules/@react-native-firebase/functions`)" + - "RNFBStorage (from `../node_modules/@react-native-firebase/storage`)" - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - RNReanimated (from `../node_modules/react-native-reanimated`) - RNScreens (from `../node_modules/react-native-screens`) @@ -2924,6 +2939,7 @@ SPEC REPOS: - FirebaseRemoteConfigInterop - FirebaseSessions - FirebaseSharedSwift + - FirebaseStorage - GoogleDataTransport - GoogleUtilities - "gRPC-C++" @@ -3138,6 +3154,8 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-firebase/firestore" RNFBFunctions: :path: "../node_modules/@react-native-firebase/functions" + RNFBStorage: + :path: "../node_modules/@react-native-firebase/storage" RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" RNReanimated: @@ -3210,6 +3228,7 @@ SPEC CHECKSUMS: FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d FirebaseSessions: dbd14adac65ce996228652c1fc3a3f576bdf3ecc FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e + FirebaseStorage: 436c30aa46f2177ba152f268fe4452118b8a4856 fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a @@ -3283,6 +3302,7 @@ SPEC CHECKSUMS: RNFBCrashlytics: f465771d96a2eaf9f6104b30abb002cfe78fc0be RNFBFirestore: e47cdde04ea3d9e73e58e037e1aa1d0b1141c316 RNFBFunctions: 738cc9e2177d060d29b5d143ef2f9ed0eda4bb1f + RNFBStorage: 2dab66f3fcc51de3acd838c72c0ff081e61a0960 RNGestureHandler: 20a4307fd21cbff339abfcfa68192f3f0a6a518b RNReanimated: d51431fd3597a8f8320319dce8e42cee82a5445f RNScreens: 30249f9331c3b00ae7cb7922e11f58b3ed369c07 diff --git a/ios/cally/Info.plist b/ios/cally/Info.plist index f0e25c7..6bccf46 100644 --- a/ios/cally/Info.plist +++ b/ios/cally/Info.plist @@ -47,7 +47,7 @@ CFBundleVersion - 38 + 34 LSRequiresIPhoneOS NSAppTransportSecurity @@ -113,6 +113,7 @@ $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route UILaunchStoryboardName SplashScreen diff --git a/package.json b/package.json index 92e580b..bf18c9a 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@react-native-firebase/crashlytics": "^20.3.0", "@react-native-firebase/firestore": "^20.4.0", "@react-native-firebase/functions": "^20.4.0", + "@react-native-firebase/storage": "^21.0.0", "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.0.2", "date-fns": "^3.6.0", diff --git a/yarn.lock b/yarn.lock index c98bb64..c94ef55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2432,6 +2432,11 @@ resolved "https://registry.npmjs.org/@react-native-firebase/functions/-/functions-20.4.0.tgz" integrity sha512-g4kAWZboTE9cTdT7KT6k1haHDmEBA36bPCvrh2MJ2RACo2JxotB2MIOEPZ5U/cT94eIAlgI5YtxQQGQfC+VcBQ== +"@react-native-firebase/storage@^21.0.0": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@react-native-firebase/storage/-/storage-21.0.0.tgz#0905fd67c74629d947f176bfb988d7cc4d85e244" + integrity sha512-meft5Pu0nI7zxhpnP49ko9Uw8GaIy9hXGJfa/fCFrpf2vA9OXdTr3CvgloH/b9DpbkwQGcGTshRqltuttXI67w== + "@react-native/assets-registry@0.74.85": version "0.74.85" resolved "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.74.85.tgz" @@ -8987,7 +8992,7 @@ react-native-linear-gradient@^2.8.3: react-native-onboarding-swiper@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.3.0.tgz#a97f945f03a036845242b3e1f319c6fdb262bc2b" integrity sha512-2ZPMrZrJFgR5dmVWIj60x/vTBWrm0BZPuc2w7Cz2Sq/8ChypCi3oL8F7GYMrzky1fmknCS6Z0WPphfZVpnLUnQ== dependencies: tinycolor2 "^1.4.1"