diff --git a/app.json b/app.json
index a8f37f9..c8a1bc7 100644
--- a/app.json
+++ b/app.json
@@ -9,6 +9,7 @@
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
+ "googleServicesFile": "./GoogleService-Info.plist",
"supportsTablet": true,
"bundleIdentifier": "com.builtbybennett.nameflame",
"infoPlist": {
@@ -16,6 +17,7 @@
}
},
"android": {
+ "googleServicesFile": "./google-services.json",
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
@@ -41,7 +43,9 @@
[
"expo-font",
{
- "fonts": ["./assets/fonts/BricolageGrotesque.ttf"]
+ "fonts": [
+ "./assets/fonts/BricolageGrotesque.ttf"
+ ]
}
]
],
@@ -56,6 +60,12 @@
"projectId": "4a498677-22c5-4a41-a8ca-3fdcc2c436b1"
}
},
- "owner": "builtbybennett"
+ "owner": "builtbybennett",
+ "runtimeVersion": {
+ "policy": "appVersion"
+ },
+ "updates": {
+ "url": "https://u.expo.dev/4a498677-22c5-4a41-a8ca-3fdcc2c436b1"
+ }
}
}
diff --git a/app/(app)/_layout.tsx b/app/(app)/_layout.tsx
index 49b76b1..da0f352 100644
--- a/app/(app)/_layout.tsx
+++ b/app/(app)/_layout.tsx
@@ -7,13 +7,13 @@ import { Colors } from '../../constants/Colors';
import { MaterialIcons } from '@expo/vector-icons';
import { useRouter, useLocalSearchParams } from 'expo-router';
-import { useToken } from '../../contexts/authCtx';
+import { useAuth } from '../../contexts/authCtx';
import useApi from '@/hooks/useApi';
import { useActiveNameContext } from '../../contexts/activeNameContext';
import { ThemedView } from '@/components/ThemedView';
export default function AppLayout() {
- const { token, isLoading } = useToken();
+ const { user, isLoading } = useAuth();
const router = useRouter();
const api = useApi();
@@ -29,7 +29,7 @@ export default function AppLayout() {
// Only require authentication within the (app) group's layout as users
// need to be able to access the (auth) group and sign in again.
- if (!token) {
+ if (!user) {
// On web, static rendering will stop here as the user is not authenticated
// in the headless Node process that the pages are rendered in.
return ;
diff --git a/app/(app)/nameContext/[id].tsx b/app/(app)/nameContext/[id].tsx
index 8d0e965..5f990d6 100644
--- a/app/(app)/nameContext/[id].tsx
+++ b/app/(app)/nameContext/[id].tsx
@@ -6,15 +6,19 @@ import { Dropdown } from 'react-native-element-dropdown';
import { Colors } from '@/constants/Colors';
import useApi from '@/hooks/useApi';
import { useActiveNameContext } from '@/contexts/activeNameContext';
+import { useConfirmationContext } from '@/contexts/confirmationCtx';
+import { useErrorContext } from '@/contexts/errorCtx';
import { MaterialIcons } from '@expo/vector-icons';
export default function NameContextDetailsView() {
const { id } = useLocalSearchParams<{ id: string }>();
const router = useRouter();
const activeNameContext = useActiveNameContext();
+ const { requireConfirmation } = useConfirmationContext();
+ const { addApiError } = useErrorContext();
const api = useApi();
const [loading, setLoading] = useState(true);
- const [error, setError] = useState('');
+ const [error, setError] = useState({});
// form values
const [nameValue, setNameValue] = useState('');
const [descriptionValue, setDescriptionValue] = useState('');
@@ -66,12 +70,14 @@ export default function NameContextDetailsView() {
})
}).catch((err) => {
- setError(err);
+ addApiError(err);
+ }).finally(() => {
setLoading(false);
});
}
function saveNameContext() {
+ setLoading(true);
api.post('/nameContext', {
name: nameValue,
description: descriptionValue,
@@ -83,24 +89,28 @@ export default function NameContextDetailsView() {
},
participants
}).then(() => {
- alert('Name context created');
router.push('/nameContext');
}).catch((err) => {
- console.log(err);
- alert('Failed to create name context');
+ if (err.response?.status === 500) {
+ addApiError(err);
+ }
+ else {
+ setError(err.response?.data?.error || {});
+ }
+ }).finally(() => {
+ setLoading(false);
});
}
function handleDelete() {
- if (confirm('Are you sure you want to delete this name context?')) {
+ setLoading(true);
api.delete(`/nameContext/${id}`).then(() => {
- alert('Name context deleted');
router.push('/nameContext');
}).catch((err) => {
- console.log(err);
- alert('Failed to delete name context');
+ addApiError(err);
+ }).finally(() => {
+ setLoading(false);
});
- }
}
if (loading) {
@@ -115,15 +125,23 @@ export default function NameContextDetailsView() {
Basic Information
{isExistingNameContxt &&
-
+ {
+ requireConfirmation({
+ primaryActionTitle: 'Delete Name Context',
+ primaryAction: handleDelete,
+ message: 'Are you sure you want to delete this name context?'
+ });
+ }} style={{ padding: 5, backgroundColor: Colors.core.purple, borderRadius: 5 }}>
}
+ {isExistingNameContxt &&
router.push(`/nameContext/${id}/match`)} style={{ padding: 5, backgroundColor: Colors.core.orange, borderRadius: 5 }}>
+ }
Name
+ {error.name?.message ? {error.name?.message} : null}
Description
+ {error.description?.message ? {error.description?.message} : null}
Noun
+ {error.noun?.message ? {error.noun?.message} : null}
Max Characters
+ {error.maxCharacters?.message ? {error.maxCharacters?.message} : null}
Gender
+ {error.gender?.message ? {error.gender.message} : null}
Starts with the letter
setStartsWithValue(String(value).toUpperCase())}
maxLength={1}
/>
+ {error.startsWithLetter?.message ? {error.startsWithLetter?.message} : null}
);
@@ -255,4 +279,8 @@ const styles = StyleSheet.create({
color: Colors.core.white,
fontSize: 16,
},
+ errorText: {
+ color: Colors.core.orange,
+ fontSize: 12,
+ },
});
\ No newline at end of file
diff --git a/app/(app)/nameContext/[id]/match.tsx b/app/(app)/nameContext/[id]/match.tsx
index 03a928a..675a93d 100644
--- a/app/(app)/nameContext/[id]/match.tsx
+++ b/app/(app)/nameContext/[id]/match.tsx
@@ -30,8 +30,6 @@ export default function NameContextDetailsMatchs() {
function fetchNewName() {
api.get('/name/random').then((resp) => {
setCurrentName(resp.data);
- }).catch((err) => {
- alert(err);
});
}
@@ -45,9 +43,6 @@ export default function NameContextDetailsMatchs() {
}).then(() => {
setSearchValue('');
fetchNewName();
- }
- ).catch((err) => {
- alert(err);
});
}
diff --git a/app/(app)/nameContext/index.tsx b/app/(app)/nameContext/index.tsx
index 4886a75..3ae24d5 100644
--- a/app/(app)/nameContext/index.tsx
+++ b/app/(app)/nameContext/index.tsx
@@ -21,11 +21,9 @@ export default function NameContextListView() {
setRefreshing(true);
api.get('/nameContexts').then((resp) => {
setNameContexts(resp.data);
- console.log(resp);
setRefreshing(false);
}).catch((err) => {
setRefreshing(false);
- alert(err);
})
};
diff --git a/app/(app)/settings/index.js b/app/(app)/settings/index.js
index eaba31d..f2c1fc8 100644
--- a/app/(app)/settings/index.js
+++ b/app/(app)/settings/index.js
@@ -1,15 +1,50 @@
-import { useState, useEffect } from "react";
-import { View, Button, Switch } from 'react-native';
+import { useState } from "react";
+import { View, Button, Switch, Pressable, ActivityIndicator } from 'react-native';
import { Colors } from '../../../constants/Colors';
import { ThemedView } from '../../../components/ThemedView';
import { ThemedText } from '../../../components/ThemedText';
-import { useToken } from '../../../contexts/authCtx';
+import { useAuth } from '../../../contexts/authCtx';
+import { useConfirmationContext } from '../../../contexts/confirmationCtx';
+import useApi from '../../../hooks/useApi';
export default function SettingsView() {
- const { signOut } = useToken();
+ const { signOutUser } = useAuth();
+ const api = useApi();
+ const [loading, setLoading] = useState(false);
const [sendNotifications, setSendNotifications] = useState(true);
+ const { requireConfirmation, resolveModal } = useConfirmationContext();
+
+ function handleAccoundDeletion() {
+ requireConfirmation({
+ message: 'Are you sure you want to delete your account? Deleting your account will remove all of your data including shared name contexts and cannot be undone.',
+ primaryActionTitle: 'Delete Account',
+ primaryAction: async () => {
+ setLoading(true);
+ try {
+ await api.delete('/user');
+ resolveModal();
+ signOutUser();
+ } catch (error) {
+ console.error(error);
+ }
+ setLoading(false);
+ }
+ });
+ }
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
return (
-
-
diff --git a/app/(app)/sign-out.tsx b/app/(app)/sign-out.tsx
index ae512e5..7329f8e 100644
--- a/app/(app)/sign-out.tsx
+++ b/app/(app)/sign-out.tsx
@@ -1,8 +1,6 @@
-import { useToken } from '../../contexts/authCtx';
-import { Redirect } from 'expo-router';
+import { useAuth } from '../../contexts/authCtx';
export default function SignOutEmptyView() {
- const { signOut } = useToken();
- signOut();
- return ;
+ const { signOutUser } = useAuth();
+ signOutUser();
}
\ No newline at end of file
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 765328b..9bc9a7e 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -1,14 +1,23 @@
import { Slot } from 'expo-router';
-import { TokenProvider } from '../contexts/authCtx';
+import { AuthProvider } from '../contexts/authCtx';
import { ActiveNameProvider } from '../contexts/activeNameContext';
+import { ErrorProvider } from '@/contexts/errorCtx';
+import { ConfirmationProvider } from '@/contexts/confirmationCtx';
+import { ErrorModal } from '@/components/ErrorModal';
+import { ConfirmationModal } from '@/components/ConfirmationModal';
export default function Root() {
- // Set up the auth context and render our layout inside of it.
return (
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/app/sign-in.tsx b/app/sign-in.tsx
index 1e366c2..c60a729 100644
--- a/app/sign-in.tsx
+++ b/app/sign-in.tsx
@@ -1,34 +1,53 @@
import { useState } from "react";
import { router } from 'expo-router';
-import { TextInput, StyleSheet, View, Text, TouchableOpacity } from 'react-native';
+import { TextInput, StyleSheet, View, Text, TouchableOpacity, ActivityIndicator } from 'react-native';
import { ThemedView } from "@/components/ThemedView";
import { ThemedText } from "@/components/ThemedText";
-import { useToken } from '../contexts/authCtx';
+import { useAuth } from '../contexts/authCtx';
import { Colors } from "@/constants/Colors";
import { MaterialIcons } from "@expo/vector-icons";
export default function SignIn() {
- const { signIn } = useToken();
+ const { signIn, user } = useAuth();
- const [username, setUsername] = useState("");
- const [password, setPassword] = useState("");
+ if (user) {
+ // Redirect to the home page if the user is already signed in.
+ router.replace('/');
+ }
+
+ const [isLoading, setIsLoading] = useState(false);
+ const [username, setUsername] = useState('');
+ const [password, setPassword] = useState('');
+ const [errorMsg, setErrorMsg] = useState('');
- function handleSignIn() {
- if (username && password) {
- signIn(username, password);
+ async function handleSignIn() {
+ setIsLoading(true);
+ setErrorMsg('');
+ try {
+ await signIn(username, password);
+ } catch (e) {
+ setErrorMsg('Invalid Credentials, please try again');
}
+ setIsLoading(false);
}
- return (
-
-
-
-
- Sign In
+ function renderContents() {
+ if (isLoading) {
+ return (
+
+
+
+
+ );
+ }
+
+ return (
+
+ { errorMsg ? {errorMsg} : null }
Sign In
@@ -40,13 +59,26 @@ export default function SignIn() {
Sign Up
+ )
+ }
+
+ return (
+
+
+
+
+ Sign In
+
+ {renderContents()}
+
);
}
const styles = StyleSheet.create({
container: {
- padding: 50,
+ padding: 20,
+ minWidth: 300,
borderRadius: 10,
backgroundColor: Colors.core.tan,
shadowColor: Colors.core.black,
diff --git a/app/sign-up.tsx b/app/sign-up.tsx
index 8cb147a..f61fa5d 100644
--- a/app/sign-up.tsx
+++ b/app/sign-up.tsx
@@ -1,54 +1,72 @@
-import { TextInput, Button, View, StyleSheet } from 'react-native';
+import { TextInput, TouchableOpacity, View, StyleSheet, ActivityIndicator } from 'react-native';
import { useState } from "react";
import { router } from 'expo-router';
import { ThemedView } from "@/components/ThemedView";
import { Colors } from "@/constants/Colors";
import { ThemedText } from "@/components/ThemedText";
import useApi from '@/hooks/useApi';
+import { useErrorContext } from '@/contexts/errorCtx';
+import { useConfirmationContext } from '@/contexts/confirmationCtx';
export default function SignUpView() {
- const [firstName, setFirstname] = useState("");
- const [lastName, setLastname] = useState("");
+ const [isLoading, setIsLoading] = useState(false);
const [userName, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [passwordConfirm, setPasswordConfirm] = useState("");
- const [registationSuccess, setRegistrationSuccess] = useState(false);
+
const api = useApi();
+ const { addApiError } = useErrorContext();
+ const { requireConfirmation } = useConfirmationContext();
async function handleSignUp() {
api.post('/auth/register', {
- firstName,
- lastName,
userName,
email,
password
}).then(() => {
- setRegistrationSuccess(true);
- }).catch((err: String) => {
- console.error(err);
+ requireConfirmation({
+ message: 'User Created successfully 🔥',
+ primaryActionTitle: 'Go to Sign In',
+ primaryAction: () => router.replace('./sign-in')
+ });
+ }).catch((err) => {
+ addApiError(err);
});
}
- if (registationSuccess) {
- return (
-
- router.replace('./sign-in')}>User Created go login 🔥
-
- )
+ function renderContent() {
+ if (isLoading) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ Sign Up
+
+ router.replace('./sign-in')}>
+ Go to Sign In
+
+
+ );
}
return (
- Sign Up Page
-
-
-
-
-
-
-
+ Sign Up
+ {renderContent()}
);
@@ -56,7 +74,8 @@ export default function SignUpView() {
const styles = StyleSheet.create({
container: {
- padding: 50,
+ padding: 20,
+ minWidth: 300,
color: Colors.core.black,
borderRadius: 10,
backgroundColor: Colors.core.tan,
@@ -71,6 +90,7 @@ const styles = StyleSheet.create({
marginBottom: 10,
backgroundColor: Colors.core.tanLighter,
borderRadius: 5,
+ fontFamily: 'Bricolage-Grotesque',
},
buttons: {
backgroundColor: Colors.core.purple,
@@ -78,9 +98,11 @@ const styles = StyleSheet.create({
borderRadius: 5,
marginTop: 10,
alignItems: 'center',
+ textAlign: 'center',
},
buttonText: {
color: Colors.core.white,
fontSize: 16,
+ fontFamily: 'Bricolage-Grotesque',
},
});
diff --git a/components/ConfirmationModal.tsx b/components/ConfirmationModal.tsx
new file mode 100644
index 0000000..ed5d302
--- /dev/null
+++ b/components/ConfirmationModal.tsx
@@ -0,0 +1,81 @@
+import { Modal, StyleSheet, View, Text, Pressable } from "react-native";
+import { useConfirmationContext } from "../contexts/confirmationCtx";
+import { BlurView } from 'expo-blur';
+import { Colors } from "../constants/Colors";
+
+export function ConfirmationModal() {
+ const { confirmationModals, requiresConfirmation, resolveModal} = useConfirmationContext();
+
+ if (!requiresConfirmation) {
+ return
+ }
+
+ const modal = confirmationModals[0];
+ return (
+
+
+
+ {modal.message}
+
+
+ {modal.secondaryActionTitle}
+
+ {
+ modal.primaryAction();
+ resolveModal();
+ }}>
+ {modal.primaryActionTitle}
+
+
+
+
+
+ );
+}
+
+const confirmationModalStyles = StyleSheet.create({
+ centeredView: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ modalView: {
+ margin: 20,
+ backgroundColor: Colors.core.white,
+ borderRadius: 20,
+ padding: 15,
+ alignItems: 'center',
+ shadowColor: '#000',
+ shadowOffset: {
+ width: 0,
+ height: 2,
+ },
+ shadowOpacity: 0.25,
+ shadowRadius: 4,
+ elevation: 5,
+ },
+ button: {
+ borderRadius: 20,
+ padding: 10,
+ elevation: 2,
+ },
+ textStyle: {
+ fontFamily: 'Bricolage-Grotesque',
+ color: 'white',
+ fontWeight: 'bold',
+ textAlign: 'center',
+ },
+ modalText: {
+ fontFamily: 'Bricolage-Grotesque',
+ marginBottom: 15,
+ textAlign: 'center',
+ },
+});
\ No newline at end of file
diff --git a/components/ErrorModal.tsx b/components/ErrorModal.tsx
new file mode 100644
index 0000000..1c79122
--- /dev/null
+++ b/components/ErrorModal.tsx
@@ -0,0 +1,73 @@
+import { Modal, StyleSheet, View, Text, Pressable } from "react-native";
+import { useErrorContext } from "../contexts/errorCtx";
+import { BlurView } from 'expo-blur';
+import { Colors } from "../constants/Colors";
+
+export function ErrorModal() {
+ const { apiErrors, clearApiErrors, hasErrors } = useErrorContext();
+
+ if (!hasErrors) {
+ return
+ }
+
+ const error = apiErrors[0];
+ return (
+
+
+
+ {error.message}
+
+ Ok
+
+
+
+
+ );
+}
+
+
+const errorModalStyles = StyleSheet.create({
+ centeredView: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ modalView: {
+ margin: 20,
+ backgroundColor: 'white',
+ borderRadius: 20,
+ padding: 35,
+ alignItems: 'center',
+ shadowColor: '#000',
+ shadowOffset: {
+ width: 0,
+ height: 2,
+ },
+ shadowOpacity: 0.25,
+ shadowRadius: 4,
+ elevation: 5,
+ },
+ button: {
+ borderRadius: 20,
+ padding: 10,
+ elevation: 2,
+ },
+ buttonClose: {
+ backgroundColor: Colors.core.orange,
+ },
+ textStyle: {
+ color: 'white',
+ fontWeight: 'bold',
+ textAlign: 'center',
+ },
+ modalText: {
+ marginBottom: 15,
+ textAlign: 'center',
+ },
+});
\ No newline at end of file
diff --git a/contexts/authCtx.tsx b/contexts/authCtx.tsx
index 530afb8..3c49c45 100644
--- a/contexts/authCtx.tsx
+++ b/contexts/authCtx.tsx
@@ -1,66 +1,53 @@
-import { useContext, createContext, type PropsWithChildren } from 'react';
-import { useStorageState } from '../hooks/useStorageState';
-import useApi from '../hooks/useApi';
-import { useRouter } from 'expo-router';
+import { useContext, createContext, useState, useEffect, ReactNode } from 'react';
+import { onAuthStateChanged, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut } from 'firebase/auth';
+import { auth } from '../firebaseConfig';
+import { User, IdTokenResult } from 'firebase/auth';
-export enum UserRoles {
- USER = 'user',
- ADMIN = 'admin'
+interface AuthContextType {
+ user: any;
+ token: string;
+ isLoading: boolean;
+ signIn: (email: string, password: string) => Promise;
+ signUp: (email: string, password: string) => Promise;
+ signOutUser: () => Promise;
}
-const AuthContext = createContext<{
- signIn: (email: string, password: string) => void;
- signOut: () => void;
- token?: string | null;
- isLoading: boolean;
-}>({
- signIn: () => null,
- signOut: () => null,
- token: null,
+const AuthContext = createContext({
+ user: null,
+ token: '',
isLoading: false,
+ signIn: async () => {},
+ signUp: async () => {},
+ signOutUser: async () => {},
});
-// This hook can be used to access the user info.
-export function useToken() {
- const value = useContext(AuthContext);
- if (process.env.NODE_ENV !== 'production') {
- if (!value) {
- throw new Error('useToken must be wrapped in a ');
- }
- }
+export const AuthProvider = ({ children }: { children: ReactNode }) => {
+ const [user, setUser] = useState(null);
+ const [token, setToken] = useState('');
+ const [isLoading, setIsLoading] = useState(false);
- return value;
-}
+ useEffect(() => {
+ const unsubscribe = onAuthStateChanged(auth, async (user) => {
+ setUser(user);
+ const userToken = await user?.getIdToken();
+ setToken(userToken || '');
+ });
+ return unsubscribe;
+ }, []);
-export function TokenProvider({ children }: PropsWithChildren) {
- const [[isLoading, token], setToken] = useStorageState('token');
- const api = useApi();
- const router = useRouter();
+ const signIn = async (email: string, password: string) => {
+ setIsLoading(true);
+ await signInWithEmailAndPassword(auth, email, password);
+ setIsLoading(false);
+ }
+ const signUp = (email: string, password: string) => createUserWithEmailAndPassword(auth, email, password);
+ const signOutUser = () => signOut(auth);
return (
- {
- api.post('/auth/login', {
- userName,
- password
- }).then((response: any) => {
- if (response.data?.token) {
- console.log('setting token');
- setToken(response.data.token);
- router.replace('./(app)/nameContext');
- }
- }).catch((err: any) => {
- console.log('failed to login', err);
- })},
- signOut: () => {
- setToken(null);
- router.replace('../sign-in');
- },
- token,
- isLoading,
- }}>
+
{children}
);
-}
+};
+
+export const useAuth = () => useContext(AuthContext);
diff --git a/contexts/confirmationCtx.tsx b/contexts/confirmationCtx.tsx
new file mode 100644
index 0000000..b7dd4e4
--- /dev/null
+++ b/contexts/confirmationCtx.tsx
@@ -0,0 +1,67 @@
+import React, { createContext, useState, useContext, useEffect } from 'react';
+
+type ModalInfo = {
+ message: string;
+ primaryActionTitle: string;
+ primaryAction: () => void;
+ secondaryActionTitle?: string;
+ secondaryAction?: () => void;
+};
+
+type ConfirmationContextType = {
+ confirmationModals: ModalInfo[];
+ requiresConfirmation: boolean;
+ requireConfirmation: (newModal: Partial) => void;
+ resolveModal: () => void;
+};
+
+const ConfirmationContext = createContext(undefined);
+
+interface ChildProviderProps {
+ children: React.ReactNode;
+}
+
+export const ConfirmationProvider: React.FC = ({ children }) => {
+ const [confirmationModals, setConfirmationModals] = useState([]);
+ const requiresConfirmation = confirmationModals.length > 0;
+
+ const resolveModal = () => {
+ setConfirmationModals((prevModals) => {
+ if (prevModals.length === 0) {
+ return prevModals;
+ }
+ return prevModals.slice(1);
+ });
+ };
+
+ const requireConfirmation = (newModal: Partial) => {
+ const defaultModal = {
+ message: 'Are you sure?',
+ primaryActionTitle: 'Ok',
+ primaryAction: () => { console.log('default primary action') },
+ secondaryActionTitle: 'Cancel',
+ secondaryAction: resolveModal,
+ };
+ setConfirmationModals((prevModals) => [...prevModals, { ...defaultModal, ...newModal }]);
+ };
+
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useConfirmationContext = (): ConfirmationContextType => {
+ const context = useContext(ConfirmationContext);
+ if (!context) {
+ throw new Error('useConfirmationContext must be used within a ConfirmationProvider');
+ }
+ return context;
+};
\ No newline at end of file
diff --git a/contexts/errorCtx.tsx b/contexts/errorCtx.tsx
new file mode 100644
index 0000000..7287e5c
--- /dev/null
+++ b/contexts/errorCtx.tsx
@@ -0,0 +1,74 @@
+import { AxiosError } from 'axios';
+import React, { createContext, useState, useContext } from 'react';
+
+type ApiError = {
+ message: string;
+ info?: any,
+ status?: number;
+ canRetry: boolean
+};
+
+type ErrorResponseData = {
+ message?: string;
+ error?: any;
+ };
+
+type ErrorContextType = {
+ apiErrors: ApiError[];
+ hasErrors: boolean;
+ addApiError: (error: AxiosError) => void;
+ clearApiErrors: () => void;
+ nextApiError: () => void;
+};
+
+const ErrorContext = createContext(undefined);
+
+interface ErrorProviderProps {
+ children: React.ReactNode;
+}
+
+export const ErrorProvider: React.FC = ({ children }) => {
+ const [apiErrors, setApiErrors] = useState([]);
+ const hasErrors = apiErrors.length > 0;
+
+ const addApiError = (error: AxiosError) => {
+ console.log(error);
+ const newApiErr = {
+ message: error.response?.data?.message || error.message || 'something went wrong',
+ status: error.response?.status,
+ info: error.response?.data?.error || {},
+ canRetry: error.response?.status !== 500
+ }
+ setApiErrors((prevErrors) => [...prevErrors, newApiErr]);
+ };
+
+ const clearApiErrors = () => {
+ setApiErrors([]);
+ };
+
+ const nextApiError = () => {
+ if (apiErrors.length) {
+ setApiErrors((prevErrors) => prevErrors.slice(1));
+ }
+ }
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useErrorContext = (): ErrorContextType => {
+ const context = useContext(ErrorContext);
+ if (!context) {
+ throw new Error('useErrorContext must be used within an ErrorProvider');
+ }
+ return context;
+};
\ No newline at end of file
diff --git a/firebaseConfig.ts b/firebaseConfig.ts
new file mode 100644
index 0000000..c7c73e3
--- /dev/null
+++ b/firebaseConfig.ts
@@ -0,0 +1,17 @@
+import { initializeApp } from 'firebase/app';
+import { getAuth } from 'firebase/auth';
+
+const firebaseConfig = {
+ apiKey: "AIzaSyAvw5oa9seT9XMoFu7Oysx_PWEVin2wgiA",
+ authDomain: "nameflame.firebaseapp.com",
+ projectId: "nameflame",
+ storageBucket: "nameflame.firebasestorage.app",
+ messagingSenderId: "1090437595615",
+ appId: "1:1090437595615:web:545e0ca29ed57291adc46a",
+ measurementId: "G-LGBKR79HPS"
+};
+
+const app = initializeApp(firebaseConfig);
+const auth = getAuth(app);
+
+export { auth };
\ No newline at end of file
diff --git a/hooks/useApi.ts b/hooks/useApi.ts
index 97c12e2..7794dcd 100644
--- a/hooks/useApi.ts
+++ b/hooks/useApi.ts
@@ -1,9 +1,9 @@
import axios from 'axios';
-import { useToken } from '@/contexts/authCtx';
+import { useAuth } from '@/contexts/authCtx';
export default function useApi() {
- const { token, signOut } = useToken();
+ const { token } = useAuth();
const api = axios.create({
baseURL: `${process.env.EXPO_PUBLIC_NAME_FLAME_ENDPOINT}/api/v1`,
timeout: 30000,
@@ -30,13 +30,6 @@ export default function useApi() {
return response;
},
(error) => {
- if (error.response?.status === 401) {
- // Handle unauthorized responses
- if (error.response.data.error?.name === 'TokenExpiredError') {
- signOut();
- alert('Your session has expired. Please log in again.');
- }
- }
// Handle response errors
return Promise.reject(error);
}
diff --git a/package-lock.json b/package-lock.json
index 7f5f9cc..dbf7021 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@expo/vector-icons": "^14.0.2",
+ "@react-native-firebase/auth": "^21.11.0",
"@react-navigation/bottom-tabs": "^7.2.0",
"@react-navigation/drawer": "^7.1.1",
"@react-navigation/native": "^7.0.14",
@@ -26,6 +27,7 @@
"expo-status-bar": "~2.0.1",
"expo-symbols": "~0.2.2",
"expo-system-ui": "~4.0.8",
+ "expo-updates": "~0.27.1",
"expo-web-browser": "~14.0.2",
"react": "18.3.1",
"react-dom": "18.3.1",
@@ -2499,14 +2501,14 @@
}
},
"node_modules/@expo/config-plugins": {
- "version": "9.0.15",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-9.0.15.tgz",
- "integrity": "sha512-elKY/zIpAJ40RH26iwfyp+hwgeyPgIXX0SrCSOcjeJLsMsCmMac9ewvb+AN8y4k+N7m5lD/dMZupsaateKTFwA==",
+ "version": "9.0.16",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-9.0.16.tgz",
+ "integrity": "sha512-AnJzmFB7ztM0JZBn+Ut6BQYC2WeGDzfIhBZVOIPMQbdBqvwJ7TmFEsGTGSxdwU/VqJaJK2sWxyt1zbWkpIYCEA==",
"license": "MIT",
"dependencies": {
- "@expo/config-types": "^52.0.4",
- "@expo/json-file": "~9.0.1",
- "@expo/plist": "^0.2.1",
+ "@expo/config-types": "^52.0.5",
+ "@expo/json-file": "~9.0.2",
+ "@expo/plist": "^0.2.2",
"@expo/sdk-runtime-versions": "^1.0.0",
"chalk": "^4.1.2",
"debug": "^4.3.5",
@@ -2533,9 +2535,9 @@
}
},
"node_modules/@expo/config-types": {
- "version": "52.0.4",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-52.0.4.tgz",
- "integrity": "sha512-oMGrb2o3niVCIfjnIHFrOoiDA9jGb0lc3G4RI1UiO//KjULBaQr3QTBoKDzZQwMqDV1AgYgSr9mgEcnX3LqhIg==",
+ "version": "52.0.5",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-52.0.5.tgz",
+ "integrity": "sha512-AMDeuDLHXXqd8W+0zSjIt7f37vUd/BP8p43k68NHpyAvQO+z8mbQZm3cNQVAMySeayK2XoPigAFB1JF2NFajaA==",
"license": "MIT"
},
"node_modules/@expo/config/node_modules/@babel/code-frame": {
@@ -3027,6 +3029,690 @@
"@babel/highlight": "^7.10.4"
}
},
+ "node_modules/@firebase/analytics": {
+ "version": "0.10.11",
+ "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.11.tgz",
+ "integrity": "sha512-zwuPiRE0+hgcS95JZbJ6DFQN4xYFO8IyGxpeePTV51YJMwCf3lkBa6FnZ/iXIqDKcBPMgMuuEZozI0BJWaLEYg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/installations": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/analytics-compat": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.17.tgz",
+ "integrity": "sha512-SJNVOeTvzdqZQvXFzj7yAirXnYcLDxh57wBFROfeowq/kRN1AqOw1tG6U4OiFOEhqi7s3xLze/LMkZatk2IEww==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/analytics": "0.10.11",
+ "@firebase/analytics-types": "0.8.3",
+ "@firebase/component": "0.6.12",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/analytics-types": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz",
+ "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/app": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.11.1.tgz",
+ "integrity": "sha512-Vz4DrNLPfDx3RwQf+4klXtu7OUYDO6xz2hlRyFawWskS7YqdtNzkDDxrqH20KDfjCF1lib46/NgchIj1+8h4wQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "idb": "7.1.1",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@firebase/app-check": {
+ "version": "0.8.11",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.11.tgz",
+ "integrity": "sha512-42zIfRI08/7bQqczAy7sY2JqZYEv3a1eNa4fLFdtJ54vNevbBIRSEA3fZgRqWFNHalh5ohsBXdrYgFqaRIuCcQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/app-check-compat": {
+ "version": "0.3.18",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.18.tgz",
+ "integrity": "sha512-qjozwnwYmAIdrsVGrJk+hnF1WBois54IhZR6gO0wtZQoTvWL/GtiA2F31TIgAhF0ayUiZhztOv1RfC7YyrZGDQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/app-check": "0.8.11",
+ "@firebase/app-check-types": "0.5.3",
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/app-check-interop-types": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz",
+ "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/app-check-types": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz",
+ "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/app-compat": {
+ "version": "0.2.50",
+ "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.50.tgz",
+ "integrity": "sha512-7yD362icKgjoNvFxwth420TNZgqCfuTJ28yQCdpyjC2fXyaZHhAbxVKnHEXGTAaUKSHWxsIy46lBKGi/x/Mflw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/app": "0.11.1",
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@firebase/app-types": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
+ "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/auth": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.9.0.tgz",
+ "integrity": "sha512-Xz2mbEYauF689qXG/4HppS2+/yGo9R7B6eNUBh3H2+XpAZTGdx8d8TFsW/BMTAK9Q95NB0pb1Bbvfx0lwofq8Q==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x",
+ "@react-native-async-storage/async-storage": "^1.18.1"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-async-storage/async-storage": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@firebase/auth-compat": {
+ "version": "0.5.18",
+ "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.18.tgz",
+ "integrity": "sha512-dFBev8AMNb2AgIt9afwf/Ku4/0Wq9R9OFSeBB/xjyJt+RfQ9PnNWqU2oFphews23byLg6jle8twRA7iOYfRGRw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/auth": "1.9.0",
+ "@firebase/auth-types": "0.13.0",
+ "@firebase/component": "0.6.12",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/auth-interop-types": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz",
+ "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/auth-types": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz",
+ "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "peerDependencies": {
+ "@firebase/app-types": "0.x",
+ "@firebase/util": "1.x"
+ }
+ },
+ "node_modules/@firebase/component": {
+ "version": "0.6.12",
+ "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.12.tgz",
+ "integrity": "sha512-YnxqjtohLbnb7raXt2YuA44cC1wA9GiehM/cmxrsoxKlFxBLy2V0OkRSj9gpngAE0UoJ421Wlav9ycO7lTPAUw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@firebase/data-connect": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.0.tgz",
+ "integrity": "sha512-inbLq0JyQD/d02Al3Lso0Hc8z1BVpB3dYSMFcQkeKhYyjn5bspLczLdasPbCOEUp8MOkLblLZhJuRs7Q/spFnw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/auth-interop-types": "0.2.4",
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/database": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.12.tgz",
+ "integrity": "sha512-psFl5t6rSFHq3i3fnU1QQlc4BB9Hnhh8TgEqvQlPPm8kDLw8gYxvjqYw3c5CZW0+zKR837nwT6im/wtJUivMKw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/app-check-interop-types": "0.3.3",
+ "@firebase/auth-interop-types": "0.2.4",
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "faye-websocket": "0.11.4",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@firebase/database-compat": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.3.tgz",
+ "integrity": "sha512-uHGQrSUeJvsDfA+IyHW5O4vdRPsCksEzv4T4Jins+bmQgYy20ZESU4x01xrQCn/nzqKHuQMEW99CoCO7D+5NiQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/database": "1.0.12",
+ "@firebase/database-types": "1.0.8",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@firebase/database-types": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.8.tgz",
+ "integrity": "sha512-6lPWIGeufhUq1heofZULyVvWFhD01TUrkkB9vyhmksjZ4XF7NaivQp9rICMk7QNhqwa+uDCaj4j+Q8qqcSVZ9g==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/app-types": "0.9.3",
+ "@firebase/util": "1.10.3"
+ }
+ },
+ "node_modules/@firebase/firestore": {
+ "version": "4.7.8",
+ "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.8.tgz",
+ "integrity": "sha512-eDvVJ/I5vSmIdGmLHJAK1OcviigIxjjia6i5/AkMFq6vZMt7CBXA0B5Xz9pGRCZ7WewFcsCbK1ZUQoYJ91+Cew==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "@firebase/webchannel-wrapper": "1.0.3",
+ "@grpc/grpc-js": "~1.9.0",
+ "@grpc/proto-loader": "^0.7.8",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/firestore-compat": {
+ "version": "0.3.43",
+ "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.43.tgz",
+ "integrity": "sha512-zxg7YS07XQnTetGs3GADM/eA6HB4vWUp+Av4iugmTbft0fQxuTSnGm7ifctaYuR7VMTPckU9CW+oFC9QUNSYvg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/firestore": "4.7.8",
+ "@firebase/firestore-types": "3.0.3",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/firestore-types": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz",
+ "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "peerDependencies": {
+ "@firebase/app-types": "0.x",
+ "@firebase/util": "1.x"
+ }
+ },
+ "node_modules/@firebase/functions": {
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.2.tgz",
+ "integrity": "sha512-iKpFDoCYk/Qm+Qwv5ynRb9/yq64QOt0A0+t9NuekyAZnSoV56kSNq/PmsVmBauar5SlmEjhHk6QKdMBP9S0gXA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/app-check-interop-types": "0.3.3",
+ "@firebase/auth-interop-types": "0.2.4",
+ "@firebase/component": "0.6.12",
+ "@firebase/messaging-interop-types": "0.2.3",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/functions-compat": {
+ "version": "0.3.19",
+ "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.19.tgz",
+ "integrity": "sha512-uw4tR8NcJCDu86UD63Za8A8SgFgmAVFb1XsGlkuBY7gpLyZWEFavWnwRkZ/8cUwpqUhp/SptXFZ1WFJSnOokLw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/functions": "0.12.2",
+ "@firebase/functions-types": "0.6.3",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/functions-types": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz",
+ "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/installations": {
+ "version": "0.6.12",
+ "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.12.tgz",
+ "integrity": "sha512-ES/WpuAV2k2YtBTvdaknEo7IY8vaGjIjS3zhnHSAIvY9KwTR8XZFXOJoZ3nSkjN1A5R4MtEh+07drnzPDg9vaw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/util": "1.10.3",
+ "idb": "7.1.1",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/installations-compat": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.12.tgz",
+ "integrity": "sha512-RhcGknkxmFu92F6Jb3rXxv6a4sytPjJGifRZj8MSURPuv2Xu+/AispCXEfY1ZraobhEHTG5HLGsP6R4l9qB5aA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/installations": "0.6.12",
+ "@firebase/installations-types": "0.5.3",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/installations-types": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz",
+ "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "peerDependencies": {
+ "@firebase/app-types": "0.x"
+ }
+ },
+ "node_modules/@firebase/logger": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz",
+ "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@firebase/messaging": {
+ "version": "0.12.16",
+ "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.16.tgz",
+ "integrity": "sha512-VJ8sCEIeP3+XkfbJA7410WhYGHdloYFZXoHe/vt+vNVDGw8JQPTQSVTRvjrUprEf5I4Tbcnpr2H34lS6zhCHSA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/installations": "0.6.12",
+ "@firebase/messaging-interop-types": "0.2.3",
+ "@firebase/util": "1.10.3",
+ "idb": "7.1.1",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/messaging-compat": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.16.tgz",
+ "integrity": "sha512-9HZZ88Ig3zQ0ok/Pwt4gQcNsOhoEy8hDHoGsV1am6ulgMuGuDVD2gl11Lere2ksL+msM12Lddi2x/7TCqmODZw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/messaging": "0.12.16",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/messaging-interop-types": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz",
+ "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/performance": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.0.tgz",
+ "integrity": "sha512-L91PwYuiJdKXKSRqsWNicvTppAJVzKjye03UlegeD6TkpKjb93T8AmJ9B0Mt0bcWHCNtnnRBCdSCvD2U9GZDjw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/installations": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0",
+ "web-vitals": "^4.2.4"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/performance-compat": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.13.tgz",
+ "integrity": "sha512-pB0SMQj2TLQ6roDcX0YQDWvUnVgsVOl0VnUvyT/VBdCUuQYDHobZsPEuQsoEqmPA44KS/Gl0oyKqf+I8UPtRgw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/performance": "0.7.0",
+ "@firebase/performance-types": "0.2.3",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/performance-types": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz",
+ "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/remote-config": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.5.0.tgz",
+ "integrity": "sha512-weiEbpBp5PBJTHUWR4GwI7ZacaAg68BKha5QnZ8Go65W4oQjEWqCW/rfskABI/OkrGijlL3CUmCB/SA6mVo0qA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/installations": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/remote-config-compat": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.12.tgz",
+ "integrity": "sha512-91jLWPtubIuPBngg9SzwvNCWzhMLcyBccmt7TNZP+y1cuYFNOWWHKUXQ3IrxCLB7WwLqQaEu7fTDAjHsTyBsSw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/remote-config": "0.5.0",
+ "@firebase/remote-config-types": "0.4.0",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/remote-config-types": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz",
+ "integrity": "sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/storage": {
+ "version": "0.13.6",
+ "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.6.tgz",
+ "integrity": "sha512-BEJLYQzVgAoglRl5VRIRZ91RRBZgS/O37/PSGQJBYNuoLmFZUrtwrlLTOAwG776NlO9VQR+K2j15/36Lr2EqHA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/storage-compat": {
+ "version": "0.3.16",
+ "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.16.tgz",
+ "integrity": "sha512-EeMuok/s0r938lEomia8XILEqSYULm7HcYZ/GTZLDWur0kMf2ktuPVZiTdRiwEV3Iki7FtQO5txrQ/0pLRVLAw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.6.12",
+ "@firebase/storage": "0.13.6",
+ "@firebase/storage-types": "0.8.3",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/storage-types": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz",
+ "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "peerDependencies": {
+ "@firebase/app-types": "0.x",
+ "@firebase/util": "1.x"
+ }
+ },
+ "node_modules/@firebase/util": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.3.tgz",
+ "integrity": "sha512-wfoF5LTy0m2ufUapV0ZnpcGQvuavTbJ5Qr1Ze9OJGL70cSMvhDyjS4w2121XdA3lGZSTOsDOyGhpoDtYwck85A==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@firebase/vertexai": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.0.4.tgz",
+ "integrity": "sha512-Nkf/r4u166b4Id6zrrW0Qtg1KyZpQvvYchtkebamnHtIfY+Qnt51I/sx4Saos/WrmO8SnrSU850LfmJ7pehYXg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/app-check-interop-types": "0.3.3",
+ "@firebase/component": "0.6.12",
+ "@firebase/logger": "0.4.4",
+ "@firebase/util": "1.10.3",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x",
+ "@firebase/app-types": "0.x"
+ }
+ },
+ "node_modules/@firebase/webchannel-wrapper": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz",
+ "integrity": "sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@grpc/grpc-js": {
+ "version": "1.9.15",
+ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz",
+ "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@grpc/proto-loader": "^0.7.8",
+ "@types/node": ">=12.12.47"
+ },
+ "engines": {
+ "node": "^8.13.0 || >=10.10.0"
+ }
+ },
+ "node_modules/@grpc/proto-loader": {
+ "version": "0.7.13",
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz",
+ "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "lodash.camelcase": "^4.3.0",
+ "long": "^5.0.0",
+ "protobufjs": "^7.2.5",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
@@ -3723,6 +4409,80 @@
"node": ">=14"
}
},
+ "node_modules/@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/codegen": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/eventemitter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/fetch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+ "license": "BSD-3-Clause",
+ "peer": true,
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.1",
+ "@protobufjs/inquire": "^1.1.0"
+ }
+ },
+ "node_modules/@protobufjs/float": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/inquire": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@protobufjs/utf8": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
@@ -3748,6 +4508,44 @@
"react": "^16.8 || ^17.0 || ^18.0"
}
},
+ "node_modules/@react-native-firebase/app": {
+ "version": "21.11.0",
+ "resolved": "https://registry.npmjs.org/@react-native-firebase/app/-/app-21.11.0.tgz",
+ "integrity": "sha512-25qALpiaVuJB+QA6XdNw/t9Cqb/wbf9cf0XeXfBbSoOYZfaa7yZynS8a2HnBFEHfpV0KfD4tS/5g1sgZSLp0zg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "firebase": "11.3.1"
+ },
+ "peerDependencies": {
+ "expo": ">=47.0.0",
+ "react": "*",
+ "react-native": "*"
+ },
+ "peerDependenciesMeta": {
+ "expo": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-native-firebase/auth": {
+ "version": "21.11.0",
+ "resolved": "https://registry.npmjs.org/@react-native-firebase/auth/-/auth-21.11.0.tgz",
+ "integrity": "sha512-xV+BhQu6QS+R+/x9zUJKzjJlJsPxdN9/PsmH49PF4AOi36UWpgFshIKW7dMD9MRfK9cUzJLacIzCazD4OPgxEg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "plist": "^3.1.0"
+ },
+ "peerDependencies": {
+ "@react-native-firebase/app": "21.11.0",
+ "expo": ">=47.0.0"
+ },
+ "peerDependenciesMeta": {
+ "expo": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@react-native/assets-registry": {
"version": "0.76.7",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.76.7.tgz",
@@ -8363,6 +9161,12 @@
"react-native": "*"
}
},
+ "node_modules/expo-eas-client": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/expo-eas-client/-/expo-eas-client-0.13.3.tgz",
+ "integrity": "sha512-t+1F1tiDocSot8iSnrn/CjTUMvVvPV2DpafSVcticpbSzMGybEN7wcamO1t18fK7WxGXpZE9gxtd80qwv/LLqQ==",
+ "license": "MIT"
+ },
"node_modules/expo-file-system": {
"version": "18.0.11",
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.0.11.tgz",
@@ -8398,6 +9202,12 @@
"expo": "*"
}
},
+ "node_modules/expo-json-utils": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-0.14.0.tgz",
+ "integrity": "sha512-xjGfK9dL0B1wLnOqNkX0jM9p48Y0I5xEPzHude28LY67UmamUyAACkqhZGaPClyPNfdzczk7Ej6WaRMT3HfXvw==",
+ "license": "MIT"
+ },
"node_modules/expo-keep-awake": {
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-14.0.3.tgz",
@@ -8433,6 +9243,19 @@
"react-native": "*"
}
},
+ "node_modules/expo-manifests": {
+ "version": "0.15.7",
+ "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-0.15.7.tgz",
+ "integrity": "sha512-IVzLcPamzUi4Br96xw6JPHaa1vjYupUnMqYyV1Mtd9VQojS5hJsf5VcVzbAMZE/cFGzWLZ1oJa6QXxYjN39Uww==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/config": "~10.0.10",
+ "expo-json-utils": "~0.14.0"
+ },
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
"node_modules/expo-modules-autolinking": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-2.0.8.tgz",
@@ -8581,6 +9404,12 @@
"react-native": "*"
}
},
+ "node_modules/expo-structured-headers": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-4.0.0.tgz",
+ "integrity": "sha512-uPiwZjWq3AdFGgY52+I2nGPrNa6izxAglymPXHUZLekZW290GqIUOk7MBNDD4sg4JwUbSi3gdxEurpEvuq+FSg==",
+ "license": "MIT"
+ },
"node_modules/expo-symbols": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-0.2.2.tgz",
@@ -8613,6 +9442,50 @@
}
}
},
+ "node_modules/expo-updates": {
+ "version": "0.27.1",
+ "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-0.27.1.tgz",
+ "integrity": "sha512-1iCU/icvanYuJonHottHcTeYGxOAXcIOfeW0FXmELGLkliHpbXtFthmeiucIcdefgebIz3GxHk9CiTS0QrT7ZA==",
+ "license": "MIT",
+ "dependencies": {
+ "@expo/code-signing-certificates": "0.0.5",
+ "@expo/config": "~10.0.10",
+ "@expo/config-plugins": "~9.0.16",
+ "@expo/spawn-async": "^1.7.2",
+ "arg": "4.1.0",
+ "chalk": "^4.1.2",
+ "expo-eas-client": "~0.13.3",
+ "expo-manifests": "~0.15.7",
+ "expo-structured-headers": "~4.0.0",
+ "expo-updates-interface": "~1.0.0",
+ "fast-glob": "^3.3.2",
+ "fbemitter": "^3.0.0",
+ "ignore": "^5.3.1",
+ "resolve-from": "^5.0.0"
+ },
+ "bin": {
+ "expo-updates": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*"
+ }
+ },
+ "node_modules/expo-updates-interface": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-1.0.0.tgz",
+ "integrity": "sha512-93oWtvULJOj+Pp+N/lpTcFfuREX1wNeHtp7Lwn8EbzYYmdn37MvZU3TPW2tYYCZuhzmKEXnUblYcruYoDu7IrQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo": "*"
+ }
+ },
+ "node_modules/expo-updates/node_modules/arg": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
+ "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==",
+ "license": "MIT"
+ },
"node_modules/expo-web-browser": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-14.0.2.tgz",
@@ -8707,6 +9580,19 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/faye-websocket": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+ "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "websocket-driver": ">=0.5.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/fb-watchman": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
@@ -8959,6 +9845,43 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/firebase": {
+ "version": "11.3.1",
+ "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.3.1.tgz",
+ "integrity": "sha512-P4YVFM0Bm2d8aO61SCEMF8E1pYgieGLrmr/LFw7vs6sAMebwuwHt+Wug+1qL2fhAHWPwpWbCLsdJH8NQ+4Sw8Q==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/analytics": "0.10.11",
+ "@firebase/analytics-compat": "0.2.17",
+ "@firebase/app": "0.11.1",
+ "@firebase/app-check": "0.8.11",
+ "@firebase/app-check-compat": "0.3.18",
+ "@firebase/app-compat": "0.2.50",
+ "@firebase/app-types": "0.9.3",
+ "@firebase/auth": "1.9.0",
+ "@firebase/auth-compat": "0.5.18",
+ "@firebase/data-connect": "0.3.0",
+ "@firebase/database": "1.0.12",
+ "@firebase/database-compat": "2.0.3",
+ "@firebase/firestore": "4.7.8",
+ "@firebase/firestore-compat": "0.3.43",
+ "@firebase/functions": "0.12.2",
+ "@firebase/functions-compat": "0.3.19",
+ "@firebase/installations": "0.6.12",
+ "@firebase/installations-compat": "0.2.12",
+ "@firebase/messaging": "0.12.16",
+ "@firebase/messaging-compat": "0.2.16",
+ "@firebase/performance": "0.7.0",
+ "@firebase/performance-compat": "0.2.13",
+ "@firebase/remote-config": "0.5.0",
+ "@firebase/remote-config-compat": "0.2.12",
+ "@firebase/storage": "0.13.6",
+ "@firebase/storage-compat": "0.3.16",
+ "@firebase/util": "1.10.3",
+ "@firebase/vertexai": "1.0.4"
+ }
+ },
"node_modules/flat-cache": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
@@ -9625,6 +10548,13 @@
"node": ">= 0.8"
}
},
+ "node_modules/http-parser-js": {
+ "version": "0.5.9",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz",
+ "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/http-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@@ -9682,6 +10612,13 @@
"node": ">=0.10.0"
}
},
+ "node_modules/idb": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
+ "license": "ISC",
+ "peer": true
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -12096,6 +13033,13 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -12198,6 +13142,13 @@
"node": ">=4"
}
},
+ "node_modules/long": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.1.tgz",
+ "integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -14011,6 +14962,31 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
+ "node_modules/protobufjs": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
+ "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "peer": true,
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/node": ">=13.7.0",
+ "long": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -17247,6 +18223,13 @@
"node": ">= 8"
}
},
+ "node_modules/web-vitals": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
+ "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
"node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -17342,6 +18325,31 @@
"node": ">=4.0"
}
},
+ "node_modules/websocket-driver": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+ "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "http-parser-js": ">=0.5.1",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/websocket-extensions": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/whatwg-encoding": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
diff --git a/package.json b/package.json
index 75d2838..3e43c98 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"web": "expo start --web",
"test": "jest --watchAll",
"lint": "expo lint",
+ "update:prod": "eas update --channel production",
"deploy:web": "npx expo export --platform web && eas deploy"
},
"jest": {
@@ -17,6 +18,7 @@
},
"dependencies": {
"@expo/vector-icons": "^14.0.2",
+ "@react-native-firebase/auth": "^21.11.0",
"@react-navigation/bottom-tabs": "^7.2.0",
"@react-navigation/drawer": "^7.1.1",
"@react-navigation/native": "^7.0.14",
@@ -34,6 +36,7 @@
"expo-status-bar": "~2.0.1",
"expo-symbols": "~0.2.2",
"expo-system-ui": "~4.0.8",
+ "expo-updates": "~0.27.1",
"expo-web-browser": "~14.0.2",
"react": "18.3.1",
"react-dom": "18.3.1",