diff --git a/app.json b/app.json
index 7ebbb86..398afa2 100644
--- a/app.json
+++ b/app.json
@@ -13,13 +13,25 @@
"backgroundColor": "#ffffff"
},
"ios": {
- "supportsTablet": true
+ "supportsTablet": true,
+ "usesAppleSignIn": true,
+ "config": {
+ "usesNonExemptEncryption": false
+ },
+ "infoPList": {
+ "NSLocationWhenInUseUsageDescription": "This app uses your location in order to allow you to share your location in chat.",
+ "NSCameraUsageDescription": "This app uses your camera to take photos & send them in the chat."
+ }
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
- }
+ },
+ "permissions": [
+ "android.permission.ACCESS_COARSE_LOCATION",
+ "android.permission.ACCESS_FINE_LOCATION"
+ ]
},
"web": {
"bundler": "metro",
@@ -27,10 +39,32 @@
"favicon": "./assets/images/favicon.png"
},
"plugins": [
- "expo-router"
+ "expo-router",
+ "expo-apple-authentication",
+ [
+ "expo-secure-store",
+ {
+ "faceIDPermission": "Allow $(PRODUCT_NAME) to access your Face ID biometric data."
+ }
+ ],
+ [
+ "expo-location",
+ {
+ "locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location."
+ }
+ ]
],
"experiments": {
"typedRoutes": true
- }
+ },
+ "extra": {
+ "router": {
+ "origin": false
+ },
+ "eas": {
+ "projectId": "c7056557-31c8-4f5c-a3e5-802df6a3bf7d"
+ }
+ },
+ "owner": "gibbyb"
}
}
diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
index 22a49b6..6a1f594 100644
--- a/app/(tabs)/_layout.tsx
+++ b/app/(tabs)/_layout.tsx
@@ -1,37 +1,60 @@
-import { Tabs } from 'expo-router';
-import React from 'react';
+import { Tabs } from "expo-router";
+import { TabBarIcon } from "@/components/navigation/TabBarIcon";
+import { Colors } from "@/constants/Colors";
+import { useColorScheme } from "@/hooks/useColorScheme";
-import { TabBarIcon } from '@/components/navigation/TabBarIcon';
-import { Colors } from '@/constants/Colors';
-import { useColorScheme } from '@/hooks/useColorScheme';
-
-export default function TabLayout() {
- const colorScheme = useColorScheme();
+const TabLayout = () => {
+ const scheme = useColorScheme() ?? 'dark';
return (
+ tabBarActiveTintColor: Colors[scheme].tint,
+ //headerShown: false
+ headerStyle: {
+ backgroundColor: Colors[scheme].background,
+ },
+ headerShadowVisible: false,
+ headerTintColor: Colors[scheme].tint,
+ tabBarStyle: {
+ backgroundColor: Colors[scheme].background,
+ borderTopColor: Colors[scheme].tint,
+ borderTopWidth: 1,
+ },
+ }}
+ >
+
(
-
+
),
}}
/>
- (
-
+
),
}}
/>
+
+ (
+
+ ),
+ }}
+ />
+
);
-}
+};
+export default TabLayout;
diff --git a/app/(tabs)/explore.tsx b/app/(tabs)/explore.tsx
deleted file mode 100644
index e480218..0000000
--- a/app/(tabs)/explore.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import Ionicons from '@expo/vector-icons/Ionicons';
-import { StyleSheet, Image, Platform } from 'react-native';
-
-import { Collapsible } from '@/components/Collapsible';
-import { ExternalLink } from '@/components/ExternalLink';
-import ParallaxScrollView from '@/components/ParallaxScrollView';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-
-export default function TabTwoScreen() {
- return (
- }>
-
- Explore
-
- This app includes example code to help you get started.
-
-
- This app has two screens:{' '}
- app/(tabs)/index.tsx and{' '}
- app/(tabs)/explore.tsx
-
-
- The layout file in app/(tabs)/_layout.tsx{' '}
- sets up the tab navigator.
-
-
- Learn more
-
-
-
-
- You can open this project on Android, iOS, and the web. To open the web version, press{' '}
- w in the terminal running this project.
-
-
-
-
- For static images, you can use the @2x and{' '}
- @3x suffixes to provide files for
- different screen densities
-
-
-
- Learn more
-
-
-
-
- Open app/_layout.tsx to see how to load{' '}
-
- custom fonts such as this one.
-
-
-
- Learn more
-
-
-
-
- This template has light and dark mode support. The{' '}
- useColorScheme() hook lets you inspect
- what the user's current color scheme is, and so you can adjust UI colors accordingly.
-
-
- Learn more
-
-
-
-
- This template includes an example of an animated component. The{' '}
- components/HelloWave.tsx component uses
- the powerful react-native-reanimated library
- to create a waving hand animation.
-
- {Platform.select({
- ios: (
-
- The components/ParallaxScrollView.tsx{' '}
- component provides a parallax effect for the header image.
-
- ),
- })}
-
-
- );
-}
-
-const styles = StyleSheet.create({
- headerImage: {
- color: '#808080',
- bottom: -90,
- left: -35,
- position: 'absolute',
- },
- titleContainer: {
- flexDirection: 'row',
- gap: 8,
- },
-});
diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx
index 324aeb7..e69de29 100644
--- a/app/(tabs)/index.tsx
+++ b/app/(tabs)/index.tsx
@@ -1,70 +0,0 @@
-import { Image, StyleSheet, Platform } from 'react-native';
-
-import { HelloWave } from '@/components/HelloWave';
-import ParallaxScrollView from '@/components/ParallaxScrollView';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-
-export default function HomeScreen() {
- return (
-
- }>
-
- Welcome!
-
-
-
- Step 1: Try it
-
- Edit app/(tabs)/index.tsx to see changes.
- Press{' '}
-
- {Platform.select({ ios: 'cmd + d', android: 'cmd + m' })}
- {' '}
- to open developer tools.
-
-
-
- Step 2: Explore
-
- Tap the Explore tab to learn more about what's included in this starter app.
-
-
-
- Step 3: Get a fresh start
-
- When you're ready, run{' '}
- npm run reset-project to get a fresh{' '}
- app directory. This will move the current{' '}
- app to{' '}
- app-example.
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- titleContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: 8,
- },
- stepContainer: {
- gap: 8,
- marginBottom: 8,
- },
- reactLogo: {
- height: 178,
- width: 290,
- bottom: 0,
- left: 0,
- position: 'absolute',
- },
-});
diff --git a/app/(tabs)/messages.tsx b/app/(tabs)/messages.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/app/(tabs)/settings.tsx b/app/(tabs)/settings.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/app/+html.tsx b/app/+html.tsx
deleted file mode 100644
index 8b92456..0000000
--- a/app/+html.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { ScrollViewStyleReset } from 'expo-router/html';
-import { type PropsWithChildren } from 'react';
-
-/**
- * This file is web-only and used to configure the root HTML for every web page during static rendering.
- * The contents of this function only run in Node.js environments and do not have access to the DOM or browser APIs.
- */
-export default function Root({ children }: PropsWithChildren) {
- return (
-
-
-
-
-
-
- {/*
- Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
- However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
- */}
-
-
- {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
-
- {/* Add any additional elements that you want globally available on web... */}
-
- {children}
-
- );
-}
-
-const responsiveBackground = `
-body {
- background-color: #fff;
-}
-@media (prefers-color-scheme: dark) {
- body {
- background-color: #000;
- }
-}`;
diff --git a/app/+not-found.tsx b/app/+not-found.tsx
index 963b04f..6013e5c 100644
--- a/app/+not-found.tsx
+++ b/app/+not-found.tsx
@@ -1,32 +1,31 @@
-import { Link, Stack } from 'expo-router';
import { StyleSheet } from 'react-native';
+import { ThemedView } from '@/components/theme/Theme';
+import { Link, Stack } from 'expo-router';
+import TextButton from '@/components/theme/buttons/TextButton';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-
-export default function NotFoundScreen() {
+const NotFoundScreen = () => {
return (
<>
-
+
- This screen doesn't exist.
-
- Go to home screen!
+
+
>
);
-}
+};
+export default NotFoundScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
- alignItems: 'center',
justifyContent: 'center',
- padding: 20,
- },
- link: {
- marginTop: 15,
- paddingVertical: 15,
+ alignItems: 'center',
},
});
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 2e37cdd..975a63c 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -1,37 +1,21 @@
-import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
-import { useFonts } from 'expo-font';
-import { Stack } from 'expo-router';
-import * as SplashScreen from 'expo-splash-screen';
-import { useEffect } from 'react';
-import 'react-native-reanimated';
-
-import { useColorScheme } from '@/hooks/useColorScheme';
-
-// Prevent the splash screen from auto-hiding before asset loading is complete.
-SplashScreen.preventAutoHideAsync();
+import { Stack } from "expo-router";
+import React, { useState } from "react";
+import SignInScreen from "@/components/auth/SignInScreen";
+import {
+ PushNotificationManager
+} from "@/components/services/notifications/PushNotificationManager";
export default function RootLayout() {
- const colorScheme = useColorScheme();
- const [loaded] = useFonts({
- SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
- });
-
- useEffect(() => {
- if (loaded) {
- SplashScreen.hideAsync();
- }
- }, [loaded]);
-
- if (!loaded) {
- return null;
- }
+ const [isSignedIn, setIsSignedIn] = useState(false);
+ if (!isSignedIn)
+ return ( setIsSignedIn(true)} />);
return (
-
+
-
+
);
}
diff --git a/assets/images/adaptive-icon.png b/assets/images/adaptive-icon.png
index 03d6f6b..fa3c871 100644
Binary files a/assets/images/adaptive-icon.png and b/assets/images/adaptive-icon.png differ
diff --git a/assets/images/default-profile.png b/assets/images/default-profile.png
new file mode 100644
index 0000000..0f5b1ff
Binary files /dev/null and b/assets/images/default-profile.png differ
diff --git a/assets/images/favicon.png b/assets/images/favicon.png
index e75f697..11877b6 100644
Binary files a/assets/images/favicon.png and b/assets/images/favicon.png differ
diff --git a/assets/images/icon.png b/assets/images/icon.png
index a0b1526..fa3c871 100644
Binary files a/assets/images/icon.png and b/assets/images/icon.png differ
diff --git a/assets/images/partial-react-logo.png b/assets/images/partial-react-logo.png
deleted file mode 100644
index 66fd957..0000000
Binary files a/assets/images/partial-react-logo.png and /dev/null differ
diff --git a/assets/images/react-logo.png b/assets/images/react-logo.png
deleted file mode 100644
index 9d72a9f..0000000
Binary files a/assets/images/react-logo.png and /dev/null differ
diff --git a/assets/images/react-logo@2x.png b/assets/images/react-logo@2x.png
deleted file mode 100644
index 2229b13..0000000
Binary files a/assets/images/react-logo@2x.png and /dev/null differ
diff --git a/assets/images/react-logo@3x.png b/assets/images/react-logo@3x.png
deleted file mode 100644
index a99b203..0000000
Binary files a/assets/images/react-logo@3x.png and /dev/null differ
diff --git a/assets/images/splash.png b/assets/images/splash.png
index 0e89705..3f3dd3a 100644
Binary files a/assets/images/splash.png and b/assets/images/splash.png differ
diff --git a/components/HelloWave.tsx b/components/HelloWave.tsx
deleted file mode 100644
index f4b6ea5..0000000
--- a/components/HelloWave.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { StyleSheet } from 'react-native';
-import Animated, {
- useSharedValue,
- useAnimatedStyle,
- withTiming,
- withRepeat,
- withSequence,
-} from 'react-native-reanimated';
-
-import { ThemedText } from '@/components/ThemedText';
-
-export function HelloWave() {
- const rotationAnimation = useSharedValue(0);
-
- rotationAnimation.value = withRepeat(
- withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })),
- 4 // Run the animation 4 times
- );
-
- const animatedStyle = useAnimatedStyle(() => ({
- transform: [{ rotate: `${rotationAnimation.value}deg` }],
- }));
-
- return (
-
- 👋
-
- );
-}
-
-const styles = StyleSheet.create({
- text: {
- fontSize: 28,
- lineHeight: 32,
- marginTop: -6,
- },
-});
diff --git a/components/ThemedView.tsx b/components/ThemedView.tsx
deleted file mode 100644
index 4d2cb09..0000000
--- a/components/ThemedView.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { View, type ViewProps } from 'react-native';
-
-import { useThemeColor } from '@/hooks/useThemeColor';
-
-export type ThemedViewProps = ViewProps & {
- lightColor?: string;
- darkColor?: string;
-};
-
-export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
- const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
-
- return ;
-}
diff --git a/components/auth/SignInScreen.tsx b/components/auth/SignInScreen.tsx
new file mode 100644
index 0000000..51c745a
--- /dev/null
+++ b/components/auth/SignInScreen.tsx
@@ -0,0 +1,153 @@
+import React from "react";
+import * as AppleAuthentication from "expo-apple-authentication";
+import { StyleSheet, Alert } from "react-native";
+import { ThemedView } from "@/components/theme/Theme";
+import { useColorScheme } from "@/hooks/useColorScheme";
+import * as Notifications from "expo-notifications";
+import Constants from "expo-constants";
+import { saveUser, saveInitialData } from "@/components/services/SecureStore";
+import type { InitialData, User } from "@/constants/Types";
+
+const SignInScreen({onSignIn}: {onSignIn: () => void}) => {
+ const scheme = useColorScheme() ?? 'dark';
+
+ const handleAppleSignIn = async () => {
+ try {
+ const credential = await AppleAuthentication.signInAsync({
+ requestedScopes: [
+ AppleAuthentication.AppleAuthenticationScope.EMAIL,
+ AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
+ ],
+ });
+ const projectId = Constants.expoConfig?.extra?.eas?.projectId;
+ if (!projectId) throw new Error('Project ID not found in eas.json');
+
+ const pushToken = await Notifications.getExpoPushTokenAsync({
+ projectId: projectId,
+ });
+ console.log(
+ credential.user, credential.email, credential.fullName?.givenName,
+ credential.fullName?.familyName, pushToken
+ );
+
+ const initialData = await
+ fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users/getUserByAppleId` +
+ `?appleId=${credential.user}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
+ },
+ });
+ console.log(initialData);
+ if (initialData.status === 404 || !initialData.ok) {
+ if (!credential.user || !credential.email ||
+ !credential.fullName?.givenName || !credential.fullName?.familyName ||
+ !pushToken || credential.email.length === 0) {
+ Alert.alert(
+ 'Sign in error',
+ 'Unable to create an account. ' +
+ 'Remove App from Sign in with Apple & try again.',
+ );
+ throw new Error(
+ 'Incomplete user data. This shouldn\'t happen & means that user has ' +
+ 'previously signed in with Apple, but their user data did not ' +
+ 'save in the database.'
+ );
+ }
+
+ const userResponse = await
+ fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users/createUser`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
+ },
+ body: JSON.stringify({
+ appleId: credential.user,
+ email: credential.email,
+ fullName:
+ `${credential.fullName?.givenName} ${credential.fullName?.familyName}`,
+ pushToken: pushToken,
+ }),
+ });
+ if (!userResponse.ok) {
+ const errorBody = await userResponse.text();
+ console.error(
+ 'API error: No user returned: ',
+ userResponse.status, errorBody
+ );
+ throw new Error(`Failed to create user: ${userResponse.status} ${errorBody}`);
+ }
+ const user: User = await userResponse.json() as User;
+ await saveUser(user);
+ } else if (initialData.ok) {
+ const allData: InitialData = await initialData.json() as InitialData;
+ console.log('Existing user found! Saving data...');
+
+ if (allData.user.pushToken !== pushToken.data) {
+ const updatePushTokenResponse =
+ await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users/updatePushToken`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
+ },
+ body: JSON.stringify({
+ userId: allData.user.id,
+ pushToken: pushToken.data,
+ }),
+ });
+ if (!updatePushTokenResponse.ok) {
+ throw new Error(
+ `Failed to update push token: ${updatePushTokenResponse.status}`
+ );
+ }
+ } else {
+ console.log('Push token is up to date.');
+ }
+ allData.user.pushToken = pushToken.data;
+ await saveInitialData(allData);
+ }
+ onSignIn();
+ } catch (error) {
+ console.error('Error signing in:', error);
+ if (error.code === 'ERR_REQUEST_CANCELLED') {
+ Alert.alert('Sign in error', 'Sign in was cancelled.');
+ } else {
+ Alert.alert(
+ 'Sign in error',
+ 'An error occurred while signing in. Please try again or contact support.'
+ );
+ }
+ }
+ };
+
+ return (
+
+
+
+ );
+};
+export default SignInScreen;
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ button: {
+ width: 200,
+ height: 45,
+ },
+});
diff --git a/components/Collapsible.tsx b/components/default/Collapsible.tsx
similarity index 100%
rename from components/Collapsible.tsx
rename to components/default/Collapsible.tsx
diff --git a/components/ExternalLink.tsx b/components/default/ExternalLink.tsx
similarity index 100%
rename from components/ExternalLink.tsx
rename to components/default/ExternalLink.tsx
diff --git a/components/ParallaxScrollView.tsx b/components/default/ParallaxScrollView.tsx
similarity index 100%
rename from components/ParallaxScrollView.tsx
rename to components/default/ParallaxScrollView.tsx
diff --git a/components/__tests__/ThemedText-test.tsx b/components/default/__tests__/ThemedText-test.tsx
similarity index 82%
rename from components/__tests__/ThemedText-test.tsx
rename to components/default/__tests__/ThemedText-test.tsx
index 1ac3225..0d62fec 100644
--- a/components/__tests__/ThemedText-test.tsx
+++ b/components/default/__tests__/ThemedText-test.tsx
@@ -1,7 +1,6 @@
import * as React from 'react';
import renderer from 'react-test-renderer';
-
-import { ThemedText } from '../ThemedText';
+import { ThemedText } from '@/components/Theme';
it(`renders correctly`, () => {
const tree = renderer.create(Snapshot test!).toJSON();
diff --git a/components/__tests__/__snapshots__/ThemedText-test.tsx.snap b/components/default/__tests__/__snapshots__/ThemedText-test.tsx.snap
similarity index 100%
rename from components/__tests__/__snapshots__/ThemedText-test.tsx.snap
rename to components/default/__tests__/__snapshots__/ThemedText-test.tsx.snap
diff --git a/components/navigation/TabBarIcon.tsx b/components/navigation/TabBarIcon.tsx
index b7302c3..8db42f0 100644
--- a/components/navigation/TabBarIcon.tsx
+++ b/components/navigation/TabBarIcon.tsx
@@ -1,5 +1,4 @@
// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
-
import Ionicons from '@expo/vector-icons/Ionicons';
import { type IconProps } from '@expo/vector-icons/build/createIconSet';
import { type ComponentProps } from 'react';
diff --git a/components/services/SecureStore.tsx b/components/services/SecureStore.tsx
new file mode 100644
index 0000000..580169e
--- /dev/null
+++ b/components/services/SecureStore.tsx
@@ -0,0 +1,95 @@
+import * as SecureStore from "expo-secure-store";
+import type {
+ Countdown,
+ InitialData,
+ Relationship,
+ RelationshipData,
+ User,
+} from "@/constants/Types";
+
+export const saveUser = async (user: User) => {
+ try {
+ await SecureStore.setItemAsync('user', JSON.stringify(user));
+ } catch (error) {
+ console.error('Error saving user to SecureStore:', error);
+ }
+};
+export const getUser = async () => {
+ try {
+ const user = await SecureStore.getItemAsync('user');
+ return user ? JSON.parse(user) as User : null;
+ } catch (error) {
+ console.error('Error getting user from SecureStore:', error);
+ return null;
+ }
+};
+export const savePartner = async (partner: User) => {
+ try {
+ await SecureStore.setItemAsync('partner', JSON.stringify(partner));
+ } catch (error) {
+ console.error('Error saving partner to SecureStore:', error);
+ }
+};
+export const getPartner = async () => {
+ try {
+ const partner = await SecureStore.getItemAsync('partner');
+ return partner ? JSON.parse(partner) as User : null;
+ } catch (error) {
+ console.error('Error getting partner from SecureStore:', error);
+ return null;
+ }
+};
+export const saveRelationship = async (relationship: Relationship) => {
+ try {
+ await SecureStore.setItemAsync('relationship', JSON.stringify(relationship));
+ } catch (error) {
+ console.error('Error saving relationship to SecureStore:', error);
+ }
+};
+export const getRelationship = async () => {
+ try {
+ const relationship = await SecureStore.getItemAsync('relationship');
+ return relationship ? JSON.parse(relationship) as Relationship : null;
+ } catch (error) {
+ console.error('Error getting relationship from SecureStore:', error);
+ return null;
+ }
+};
+export const saveCountdown = async (countdown: Countdown) => {
+ try {
+ await SecureStore.setItemAsync('countdown', JSON.stringify(countdown));
+ } catch (error) {
+ console.error('Error saving countdown to SecureStore:', error);
+ }
+};
+export const getCountdown = async () => {
+ try {
+ const countdown = await SecureStore.getItemAsync('countdown');
+ return countdown ? JSON.parse(countdown) as Countdown : null;
+ } catch (error) {
+ console.error('Error getting countdown from SecureStore:', error);
+ return null;
+ }
+};
+export const saveRelationshipData = async (relationshipData: RelationshipData) => {
+ try {
+ await SecureStore.setItemAsync('partner', JSON.stringify(relationshipData.Partner));
+ await SecureStore.setItemAsync('relationship', JSON.stringify(relationshipData.relationship));
+ } catch (error) {
+ console.error('Error saving partner & relationship to SecureStore:', error);
+ }
+};
+export const saveInitialData = async (initialData: InitialData) => {
+ try {
+ await SecureStore.setItemAsync('user', JSON.stringify(initialData.user));
+ await SecureStore.setItemAsync(
+ 'relationship', JSON.stringify(initialData.relationshipData.relationship)
+ );
+ await SecureStore.setItemAsync(
+ 'partner', JSON.stringify(initialData.relationshipData.Partner)
+ );
+ await SecureStore.setItemAsync('countdown', JSON.stringify(initialData.countdown));
+ } catch (error) {
+ console.error('Error saving initial data to SecureStore:', error);
+ }
+};
diff --git a/components/services/notifications/PushNotificationManager.tsx b/components/services/notifications/PushNotificationManager.tsx
new file mode 100644
index 0000000..82f42de
--- /dev/null
+++ b/components/services/notifications/PushNotificationManager.tsx
@@ -0,0 +1,107 @@
+import React, { useState, useEffect, useRef } from 'react';
+import { Platform } from 'react-native';
+import * as Device from 'expo-device';
+import * as Notifications from 'expo-notifications';
+import Constants from 'expo-constants';
+import type { NotificationMessage } from '@/constants/Types';
+
+Notifications.setNotificationHandler({
+ handleNotification: async () => ({
+ shouldShowAlert: true,
+ shouldPlaySound: true,
+ shouldSetBadge: true,
+ }),
+});
+
+export const sendPushNotification = async(expoPushToken: string, notification: NotificationMessage) => {
+ const message = {
+ to: expoPushToken,
+ sound: notification.sound ?? 'default',
+ title: notification.title,
+ body: notification.body,
+ data: notification.data ?? {},
+ };
+ await fetch('https://exp.host/--/api/v2/push/send', {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Accept-encoding': 'gzip, deflate',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(message),
+ });
+};
+
+const handleRegistrationError = (errorMessage: string) => {
+ alert(errorMessage);
+ throw new Error(errorMessage);
+};
+
+const registerforPushNotificationsAsync = async () => {
+ let token;
+
+ if (Platform.OS === 'android') {
+ await Notifications.setNotificationChannelAsync('default', {
+ name: 'default',
+ importance: Notifications.AndroidImportance.MAX,
+ vibrationPattern: [0, 250, 250, 250],
+ lightColor: '#FF231F7C',
+ });
+ }
+
+ if (Device.isDevice) {
+ const { status: existingStatus } = await Notifications.getPermissionsAsync();
+ let finalStatus = existingStatus;
+ if (existingStatus !== 'granted') {
+ const { status } = await Notifications.requestPermissionsAsync();
+ finalStatus = status;
+ }
+ if (finalStatus !== 'granted') {
+ alert('Failed to get push token for push notification!');
+ return;
+ }
+ const projectId = Constants.expoConfig?.extra?.eas?.projectId;
+ if (!projectId) {
+ alert('Project ID not found in eas.json');
+ return;
+ }
+ token = (await Notifications.getExpoPushTokenAsync({ projectId })).data;
+ } else {
+ alert('Must use physical device for Push Notifications');
+ }
+ return token;
+};
+
+export const PushNotificationManager = ({children}: {children: React.ReactNode}) => {
+ const [expoPushToken, setExpoPushToken] = useState('');
+ const [notification, setNotification] =
+ useState(undefined);
+ const notificationListener = useRef();
+ const responseListener = useRef();
+
+ useEffect(() => {
+ registerforPushNotificationsAsync()
+ .then(token => setExpoPushToken(token ?? ''))
+ .catch((error: any) => {
+ setExpoPushToken('');
+ console.error(error);
+ });
+
+ notificationListener.current = Notifications.addNotificationReceivedListener(
+ notification => {
+ setNotification(notification);
+ });
+ responseListener.current = Notifications.addNotificationResponseReceivedListener(
+ response => {
+ console.log(response);
+ // Handle notification response here
+ });
+ return () => {
+ notificationListener.current &&
+ Notifications.removeNotificationSubscription(notificationListener.current);
+ responseListener.current &&
+ Notifications.removeNotificationSubscription(responseListener.current);
+ };
+ }, []);
+ return ( <> {children} > );
+};
diff --git a/components/ThemedText.tsx b/components/theme/Theme.tsx
similarity index 75%
rename from components/ThemedText.tsx
rename to components/theme/Theme.tsx
index c0e1a78..5ff4824 100644
--- a/components/ThemedText.tsx
+++ b/components/theme/Theme.tsx
@@ -1,13 +1,22 @@
+import { View, type ViewProps } from 'react-native';
import { Text, type TextProps, StyleSheet } from 'react-native';
-
import { useThemeColor } from '@/hooks/useThemeColor';
+export type ThemedViewProps = ViewProps & {
+ lightColor?: string;
+ darkColor?: string;
+};
export type ThemedTextProps = TextProps & {
lightColor?: string;
darkColor?: string;
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
};
+export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
+ const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
+ return ;
+}
+
export function ThemedText({
style,
lightColor,
diff --git a/components/theme/buttons/DefaultButton.tsx b/components/theme/buttons/DefaultButton.tsx
new file mode 100644
index 0000000..3ac69e2
--- /dev/null
+++ b/components/theme/buttons/DefaultButton.tsx
@@ -0,0 +1,55 @@
+import { StyleSheet, Pressable } from "react-native";
+import { ThemedView } from "@/components/theme/Theme";
+import { Colors } from '@/constants/Colors';
+import { useColorScheme } from '@/hooks/useColorScheme';
+
+const DEFAULT_WIDTH = 320;
+const DEFAULT_HEIGHT = 68;
+
+type Props = {
+ width?: number;
+ height?: number;
+ onPress?: () => void;
+};
+
+const Button = ({ width, height, children, onPress }: Props & React.ComponentProps) => {
+ const scheme = useColorScheme() ?? 'dark';
+ return (
+
+
+ {children}
+
+
+ );
+};
+export default Button;
+
+const styles = StyleSheet.create({
+ buttonContainer: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 3,
+ },
+ button: {
+ borderRadius: 10,
+ width: '100%',
+ height: '100%',
+ alignItems: 'center',
+ justifyContent: 'center',
+ flexDirection: 'row',
+ },
+});
diff --git a/components/theme/buttons/TextButton.tsx b/components/theme/buttons/TextButton.tsx
new file mode 100644
index 0000000..3144657
--- /dev/null
+++ b/components/theme/buttons/TextButton.tsx
@@ -0,0 +1,37 @@
+import Button from '@/components/theme/buttons/DefaultButton';
+import { ThemedText } from "@/components/theme/Theme";
+import { Colors } from '@/constants/Colors';
+import { useColorScheme } from '@/hooks/useColorScheme';
+
+const DEFAULT_FONT_SIZE = 16;
+
+type Props = {
+ width?: number;
+ height?: number;
+ text: string;
+ fontSize?: number;
+ onPress?: () => void;
+};
+
+const TextButton = ({ width, height, text, fontSize, onPress }: Props ) => {
+ const scheme = useColorScheme() ?? 'dark';
+ return (
+
+ );
+};
+export default TextButton;
diff --git a/constants/Types.ts b/constants/Types.ts
new file mode 100644
index 0000000..25db7ca
--- /dev/null
+++ b/constants/Types.ts
@@ -0,0 +1,131 @@
+/* Types */
+
+// User Table in DB
+export type User = {
+ id: number;
+ appleId: string | null;
+ email: string;
+ fullName: string;
+ pfpUrl: string | null;
+ pushToken: string;
+ createdAt: Date;
+ metadata?: Record;
+};
+// Relationship Table in DB
+export type Relationship = {
+ id: number;
+ title: string;
+ requestorId: number;
+ isAccepted: boolean;
+ relationshipStartDate: Date;
+};
+export type UserRelationship = {
+ id: number;
+ userId: number;
+ relationshipId: number;
+};
+// Mutated Data from Relationship
+// & UserRelationship Tables in DB
+export type RelationshipData = {
+ relationship: Relationship;
+ Partner: User;
+};
+// Countdown Table in DB
+export type Countdown = {
+ id: number;
+ relationshipId: number;
+ title: string;
+ date: Date;
+ createdAt: Date;
+};
+// Mutated Data for Login
+// API Response
+export type InitialData = {
+ user: User;
+ relationshipData: RelationshipData;
+ countdown: Countdown;
+};
+// Message Table in DB
+export type Message = {
+ id: number;
+ senderId: number;
+ receiverId: number;
+ text: string;
+ createdAt: Date;
+ isRead: boolean;
+ hasLocation: boolean;
+ hasMedia: boolean;
+ hasQuickReply: boolean;
+};
+// MessageMedia Table in DB
+export type MessageMedia = {
+ id: number;
+ messageId: number;
+ mediaType:
+ 'image' | 'video' | 'audio' | 'file';
+ url: string;
+ size?: number;
+ metadata?: string;
+ order: number;
+};
+// MessageLocation Table in DB
+export type MessageLocation = {
+ id: number;
+ messageId: number;
+ latitude: number;
+ longitude: number;
+};
+// Quick Reply Table in DB
+export type QuickReply = {
+ id: number;
+ messageId: number;
+ type: 'radio' | 'checkbox';
+ keepIt: boolean;
+};
+// Quick Reply Option Table in DB
+export type QuickReplyOption = {
+ id: number;
+ quickReplyId: number;
+ title: string;
+ value: string;
+};
+
+export type GCUser = {
+ _id: number;
+ name: string;
+ avatar?: string;
+};
+export type GCQuickReplies = {
+ type: 'radio' | 'checkbox';
+ values: GCQuickReplyOptions[];
+ keepIt?: boolean;
+};
+export type GCQuickReplyOptions = {
+ title: string;
+ value: string;
+};
+export type GCLocation = {
+ latitude: number;
+ longitude: number;
+};
+export type GCMessage = {
+ _id: number;
+ text: string;
+ createdAt: Date;
+ user: GCUser;
+ image?: string;
+ video?: string;
+ audio?: string;
+ location?: GCLocation;
+ system?: boolean;
+ sent?: boolean;
+ received?: boolean;
+ pending?: boolean;
+ quickReplies?: GCQuickReplies;
+};
+export type NotificationMessage = {
+ sound?: string;
+ title: string;
+ body: string;
+ data?: any;
+};
diff --git a/hooks/useColorScheme.web.ts b/hooks/useColorScheme.web.ts
index 6dcd80d..6128e06 100644
--- a/hooks/useColorScheme.web.ts
+++ b/hooks/useColorScheme.web.ts
@@ -4,5 +4,5 @@
// to render different styles on the client and server, these aren't directly supported in React Native
// but can be achieved using a styling library like Nativewind.
export function useColorScheme() {
- return 'light';
+ return 'dark';
}
diff --git a/hooks/useThemeColor.ts b/hooks/useThemeColor.ts
index ae43b47..bfe6866 100644
--- a/hooks/useThemeColor.ts
+++ b/hooks/useThemeColor.ts
@@ -11,7 +11,7 @@ export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
) {
- const theme = useColorScheme() ?? 'light';
+ const theme = useColorScheme() ?? 'dark';
const colorFromProps = props[theme];
if (colorFromProps) {
diff --git a/package.json b/package.json
index 93b82ec..e1fb37d 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,6 @@
"version": "1.0.0",
"scripts": {
"start": "expo start",
- "reset-project": "node ./scripts/reset-project.js",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
@@ -18,10 +17,15 @@
"@expo/vector-icons": "^14.0.2",
"@react-navigation/native": "^6.0.2",
"expo": "~51.0.28",
+ "expo-apple-authentication": "~6.4.2",
"expo-constants": "~16.0.2",
+ "expo-device": "~6.0.2",
"expo-font": "~12.0.9",
"expo-linking": "~6.3.1",
+ "expo-location": "~17.0.1",
+ "expo-notifications": "~0.28.18",
"expo-router": "~3.5.23",
+ "expo-secure-store": "~13.0.2",
"expo-splash-screen": "~0.27.5",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.7",
@@ -30,6 +34,8 @@
"react-dom": "18.2.0",
"react-native": "0.74.5",
"react-native-gesture-handler": "~2.16.1",
+ "react-native-get-random-values": "~1.11.0",
+ "react-native-gifted-chat": "^2.6.4",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 53e84af..47058d1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,18 +17,33 @@ importers:
expo:
specifier: ~51.0.28
version: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
+ expo-apple-authentication:
+ specifier: ~6.4.2
+ version: 6.4.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
expo-constants:
specifier: ~16.0.2
version: 16.0.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
+ expo-device:
+ specifier: ~6.0.2
+ version: 6.0.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
expo-font:
specifier: ~12.0.9
version: 12.0.10(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
expo-linking:
specifier: ~6.3.1
version: 6.3.1(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
+ expo-location:
+ specifier: ~17.0.1
+ version: 17.0.1(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
+ expo-notifications:
+ specifier: ~0.28.18
+ version: 0.28.18(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
expo-router:
specifier: ~3.5.23
version: 3.5.23(k73ovpznblgccxklktj7qyihii)
+ expo-secure-store:
+ specifier: ~13.0.2
+ version: 13.0.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
expo-splash-screen:
specifier: ~0.27.5
version: 0.27.6(expo-modules-autolinking@1.11.3)(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
@@ -53,6 +68,12 @@ importers:
react-native-gesture-handler:
specifier: ~2.16.1
version: 2.16.2(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0)
+ react-native-get-random-values:
+ specifier: ~1.11.0
+ version: 1.11.0(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))
+ react-native-gifted-chat:
+ specifier: ^2.6.4
+ version: 2.6.4(react-native-get-random-values@1.11.0(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)))(react-native-reanimated@3.10.1(@babel/core@7.25.8)(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0)
react-native-reanimated:
specifier: ~3.10.1
version: 3.10.1(@babel/core@7.25.8)(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0)
@@ -924,6 +945,11 @@ packages:
peerDependencies:
expo-modules-autolinking: '>=0.8.1'
+ '@expo/react-native-action-sheet@4.1.0':
+ resolution: {integrity: sha512-RILoWhREgjMdr1NUSmZa/cHg8onV2YPDAMOy0iIP1c3H7nT9QQZf5dQNHK8ehcLM82sarVxriBJyYSSHAx7j6w==}
+ peerDependencies:
+ react: '>=18.0.0'
+
'@expo/rudder-sdk-node@1.1.1':
resolution: {integrity: sha512-uy/hS/awclDJ1S88w9UGpc6Nm9XnNUjzOAAib1A3PVAnGQIwebg8DpFqOthFBTlZxeuV/BKbZ5jmTbtNZkp1WQ==}
engines: {node: '>=12'}
@@ -956,6 +982,9 @@ packages:
'@hapi/topo@5.1.0':
resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+ '@ide/backoff@1.0.0':
+ resolution: {integrity: sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==}
+
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@@ -1344,6 +1373,9 @@ packages:
'@types/hammerjs@2.0.46':
resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==}
+ '@types/hoist-non-react-statics@3.3.5':
+ resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==}
+
'@types/istanbul-lib-coverage@2.0.6':
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
@@ -1365,6 +1397,12 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ '@types/lodash.isequal@4.5.8':
+ resolution: {integrity: sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==}
+
+ '@types/lodash@4.17.10':
+ resolution: {integrity: sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==}
+
'@types/node-forge@1.3.11':
resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
@@ -1552,6 +1590,9 @@ packages:
asap@2.0.6:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
+ assert@2.1.0:
+ resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
+
ast-types@0.15.2:
resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==}
engines: {node: '>=4'}
@@ -1631,6 +1672,9 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
+ badgin@1.2.3:
+ resolution: {integrity: sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==}
+
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -2241,6 +2285,16 @@ packages:
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ expo-apple-authentication@6.4.2:
+ resolution: {integrity: sha512-X4u1n3Ql1hOpztXHbKNq4I1l4+Ff82gC6RmEeW43Eht7VE6E8PrQBpYKw+JJv8osrCJt7R5O1PZwed6WLN5oig==}
+ peerDependencies:
+ expo: '*'
+
+ expo-application@5.9.1:
+ resolution: {integrity: sha512-uAfLBNZNahnDZLRU41ZFmNSKtetHUT9Ua557/q189ua0AWV7pQjoVAx49E4953feuvqc9swtU3ScZ/hN1XO/FQ==}
+ peerDependencies:
+ expo: '*'
+
expo-asset@10.0.10:
resolution: {integrity: sha512-0qoTIihB79k+wGus9wy0JMKq7DdenziVx3iUkGvMAy2azscSgWH6bd2gJ9CGnhC6JRd3qTMFBL0ou/fx7WZl7A==}
peerDependencies:
@@ -2251,6 +2305,11 @@ packages:
peerDependencies:
expo: '*'
+ expo-device@6.0.2:
+ resolution: {integrity: sha512-sCt91CuTmAuMXX4SlFOn4lIos2UIr8vb0jDstDDZXys6kErcj0uynC7bQAMreU5uRUTKMAl4MAMpKt9ufCXPBw==}
+ peerDependencies:
+ expo: '*'
+
expo-file-system@17.0.1:
resolution: {integrity: sha512-dYpnZJqTGj6HCYJyXAgpFkQWsiCH3HY1ek2cFZVHFoEc5tLz9gmdEgTF6nFHurvmvfmXqxi7a5CXyVm0aFYJBw==}
peerDependencies:
@@ -2269,6 +2328,11 @@ packages:
expo-linking@6.3.1:
resolution: {integrity: sha512-xuZCntSBGWCD/95iZ+mTUGTwHdy8Sx+immCqbUBxdvZ2TN61P02kKg7SaLS8A4a/hLrSCwrg5tMMwu5wfKr35g==}
+ expo-location@17.0.1:
+ resolution: {integrity: sha512-m+OzotzlAXO3ZZ1uqW5GC25nXW868zN+ROyBA1V4VF6jGay1ZEs4URPglCVUDzZby2F5wt24cMzqDKw2IX6nRw==}
+ peerDependencies:
+ expo: '*'
+
expo-modules-autolinking@1.11.3:
resolution: {integrity: sha512-oYh8EZEvYF5TYppxEKUTTJmbr8j7eRRnrIxzZtMvxLTXoujThVPMFS/cbnSnf2bFm1lq50TdDNABhmEi7z0ngQ==}
hasBin: true
@@ -2276,6 +2340,11 @@ packages:
expo-modules-core@1.12.26:
resolution: {integrity: sha512-y8yDWjOi+rQRdO+HY+LnUlz8qzHerUaw/LUjKPU/mX8PRXP4UUPEEp5fjAwBU44xjNmYSHWZDwet4IBBE+yQUA==}
+ expo-notifications@0.28.18:
+ resolution: {integrity: sha512-oRvr8rYhbbKNhVgcO+fj5g5g6vS0umGcElpeMSWa0KudUfOOgV6nNLvv5M89393z2Ahd7wPK4bnK8lygc0nCPQ==}
+ peerDependencies:
+ expo: '*'
+
expo-router@3.5.23:
resolution: {integrity: sha512-Re2kYcxov67hWrcjuu0+3ovsLxYn79PuX6hgtYN20MgigY5ttX79KOIBEVGTO3F3y9dxSrGHyy5Z14BcO+usGQ==}
peerDependencies:
@@ -2296,6 +2365,11 @@ packages:
react-native-reanimated:
optional: true
+ expo-secure-store@13.0.2:
+ resolution: {integrity: sha512-3QYgoneo8p8yeeBPBiAfokNNc2xq6+n8+Ob4fAlErEcf4H7Y72LH+K/dx0nQyWau2ZKZUXBxyyfuHFyVKrEVLg==}
+ peerDependencies:
+ expo: '*'
+
expo-splash-screen@0.27.5:
resolution: {integrity: sha512-9rdZuLkFCfgJBxrheUsOEOIW6Rp+9NVlpSE0hgXQwbTCLTncf00IHSE8/L2NbFyeDLNjof1yZBppaV7tXHRUzA==}
peerDependencies:
@@ -2326,6 +2400,9 @@ packages:
exponential-backoff@3.1.1:
resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
+ fast-base64-decode@1.0.0:
+ resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==}
+
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -2779,6 +2856,10 @@ packages:
resolution: {integrity: sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ==}
engines: {node: '>=0.10.0'}
+ is-nan@1.3.2:
+ resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
+ engines: {node: '>= 0.4'}
+
is-negative-zero@2.0.3:
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
engines: {node: '>= 0.4'}
@@ -3204,6 +3285,9 @@ packages:
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+ lodash.isequal@4.5.0:
+ resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+
lodash.throttle@4.1.1:
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
@@ -3520,6 +3604,10 @@ packages:
resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
engines: {node: '>= 0.4'}
+ object-is@1.1.6:
+ resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
+ engines: {node: '>= 0.4'}
+
object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
@@ -3822,17 +3910,52 @@ packages:
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ react-native-communications@2.2.1:
+ resolution: {integrity: sha512-5+C0X9mopI0+qxyQHzOPEi5v5rxNBQjxydPPiKMQSlX1RBIcJ8uTcqUPssQ9Mo8p6c1IKIWJUSqCj4jAmD0qVQ==}
+
react-native-gesture-handler@2.16.2:
resolution: {integrity: sha512-vGFlrDKlmyI+BT+FemqVxmvO7nqxU33cgXVsn6IKAFishvlG3oV2Ds67D5nPkHMea8T+s1IcuMm0bF8ntZtAyg==}
peerDependencies:
react: '*'
react-native: '*'
+ react-native-get-random-values@1.11.0:
+ resolution: {integrity: sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==}
+ peerDependencies:
+ react-native: '>=0.56'
+
+ react-native-gifted-chat@2.6.4:
+ resolution: {integrity: sha512-Ut31I1w6g4hG/iMyC1mVNVPZCNAUfijbJaEbRmKQnTPG+nAvYFje57OHr5coe9w+IBWsJKKoNvaI4h8w9Il5aQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: '*'
+ react-native: '*'
+ react-native-get-random-values: '*'
+ react-native-reanimated: '*'
+ react-native-safe-area-context: '*'
+
react-native-helmet-async@2.0.4:
resolution: {integrity: sha512-m3CkXWss6B1dd6mCMleLpzDCJJGGaHOLQsUzZv8kAASJmMfmVT4d2fx375iXKTRWT25ThBfae3dECuX5cq/8hg==}
peerDependencies:
react: ^16.6.0 || ^17.0.0 || ^18.0.0
+ react-native-iphone-x-helper@1.3.1:
+ resolution: {integrity: sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==}
+ peerDependencies:
+ react-native: '>=0.42.0'
+
+ react-native-lightbox-v2@0.9.2:
+ resolution: {integrity: sha512-+8LwINeSWvPP69YAyWhiJQyaw4Gtu8X4EMvT3PEN615NrOeDaz8jOcIw73pzYJst3z4Z0vxvFB73iH16wCPXtw==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-native: '>=0.61.0'
+
+ react-native-parsed-text@0.0.22:
+ resolution: {integrity: sha512-hfD83RDXZf9Fvth3DowR7j65fMnlqM9PpxZBGWkzVcUTFtqe6/yPcIoIAgrJbKn6YmtzkivmhWE2MCE4JKBXrQ==}
+ peerDependencies:
+ react: '*'
+ react-native: '*'
+
react-native-reanimated@3.10.1:
resolution: {integrity: sha512-sfxg6vYphrDc/g4jf/7iJ7NRi+26z2+BszPmvmk0Vnrz6FL7HYljJqTf531F1x6tFmsf+FEAmuCtTUIXFLVo9w==}
peerDependencies:
@@ -4488,6 +4611,10 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ ua-parser-js@0.7.39:
+ resolution: {integrity: sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==}
+ hasBin: true
+
ua-parser-js@1.0.39:
resolution: {integrity: sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==}
hasBin: true
@@ -4584,6 +4711,10 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
+ uuid@10.0.0:
+ resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+ hasBin: true
+
uuid@7.0.3:
resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==}
hasBin: true
@@ -6074,6 +6205,12 @@ snapshots:
- encoding
- supports-color
+ '@expo/react-native-action-sheet@4.1.0(react@18.2.0)':
+ dependencies:
+ '@types/hoist-non-react-statics': 3.3.5
+ hoist-non-react-statics: 3.3.2
+ react: 18.2.0
+
'@expo/rudder-sdk-node@1.1.1':
dependencies:
'@expo/bunyan': 4.0.1
@@ -6123,6 +6260,8 @@ snapshots:
dependencies:
'@hapi/hoek': 9.3.0
+ '@ide/backoff@1.0.0': {}
+
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
@@ -6863,6 +7002,11 @@ snapshots:
'@types/hammerjs@2.0.46': {}
+ '@types/hoist-non-react-statics@3.3.5':
+ dependencies:
+ '@types/react': 18.2.79
+ hoist-non-react-statics: 3.3.2
+
'@types/istanbul-lib-coverage@2.0.6': {}
'@types/istanbul-lib-report@3.0.3':
@@ -6891,6 +7035,12 @@ snapshots:
'@types/json-schema@7.0.15': {}
+ '@types/lodash.isequal@4.5.8':
+ dependencies:
+ '@types/lodash': 4.17.10
+
+ '@types/lodash@4.17.10': {}
+
'@types/node-forge@1.3.11':
dependencies:
'@types/node': 22.7.5
@@ -7073,6 +7223,14 @@ snapshots:
asap@2.0.6: {}
+ assert@2.1.0:
+ dependencies:
+ call-bind: 1.0.7
+ is-nan: 1.3.2
+ object-is: 1.1.6
+ object.assign: 4.1.5
+ util: 0.12.5
+
ast-types@0.15.2:
dependencies:
tslib: 2.7.0
@@ -7207,6 +7365,8 @@ snapshots:
babel-plugin-jest-hoist: 29.6.3
babel-preset-current-node-syntax: 1.1.0(@babel/core@7.25.8)
+ badgin@1.2.3: {}
+
balanced-match@1.0.2: {}
base64-js@1.5.1: {}
@@ -7834,6 +7994,14 @@ snapshots:
jest-message-util: 29.7.0
jest-util: 29.7.0
+ expo-apple-authentication@6.4.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
+ dependencies:
+ expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
+
+ expo-application@5.9.1(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
+ dependencies:
+ expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
+
expo-asset@10.0.10(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
dependencies:
expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
@@ -7851,6 +8019,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ expo-device@6.0.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
+ dependencies:
+ expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
+ ua-parser-js: 0.7.39
+
expo-file-system@17.0.1(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
dependencies:
expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
@@ -7872,6 +8045,10 @@ snapshots:
- expo
- supports-color
+ expo-location@17.0.1(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
+ dependencies:
+ expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
+
expo-modules-autolinking@1.11.3:
dependencies:
chalk: 4.1.2
@@ -7886,6 +8063,21 @@ snapshots:
dependencies:
invariant: 2.2.4
+ expo-notifications@0.28.18(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
+ dependencies:
+ '@expo/image-utils': 0.5.1
+ '@ide/backoff': 1.0.0
+ abort-controller: 3.0.0
+ assert: 2.1.0
+ badgin: 1.2.3
+ expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
+ expo-application: 5.9.1(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
+ expo-constants: 16.0.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8)))
+ fs-extra: 9.1.0
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+
expo-router@3.5.23(k73ovpznblgccxklktj7qyihii):
dependencies:
'@expo/metro-runtime': 3.2.3(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))
@@ -7913,6 +8105,10 @@ snapshots:
- supports-color
- typescript
+ expo-secure-store@13.0.2(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
+ dependencies:
+ expo: 51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))
+
expo-splash-screen@0.27.5(expo-modules-autolinking@1.11.3)(expo@51.0.38(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))):
dependencies:
'@expo/prebuild-config': 7.0.6(expo-modules-autolinking@1.11.3)
@@ -7972,6 +8168,8 @@ snapshots:
exponential-backoff@3.1.1: {}
+ fast-base64-decode@1.0.0: {}
+
fast-deep-equal@3.1.3: {}
fast-glob@3.3.2:
@@ -8438,6 +8636,11 @@ snapshots:
dependencies:
is-glob: 2.0.1
+ is-nan@1.3.2:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+
is-negative-zero@2.0.3: {}
is-number-object@1.0.7:
@@ -9100,6 +9303,8 @@ snapshots:
lodash.debounce@4.0.8: {}
+ lodash.isequal@4.5.0: {}
+
lodash.throttle@4.1.1: {}
lodash@4.17.21: {}
@@ -9489,6 +9694,11 @@ snapshots:
object-inspect@1.13.2: {}
+ object-is@1.1.6:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+
object-keys@1.1.1: {}
object.assign@4.1.5:
@@ -9787,6 +9997,8 @@ snapshots:
react-is@18.3.1: {}
+ react-native-communications@2.2.1: {}
+
react-native-gesture-handler@2.16.2(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0):
dependencies:
'@egjs/hammerjs': 2.0.17
@@ -9797,6 +10009,29 @@ snapshots:
react: 18.2.0
react-native: 0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)
+ react-native-get-random-values@1.11.0(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)):
+ dependencies:
+ fast-base64-decode: 1.0.0
+ react-native: 0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)
+
+ react-native-gifted-chat@2.6.4(react-native-get-random-values@1.11.0(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)))(react-native-reanimated@3.10.1(@babel/core@7.25.8)(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0):
+ dependencies:
+ '@expo/react-native-action-sheet': 4.1.0(react@18.2.0)
+ '@types/lodash.isequal': 4.5.8
+ dayjs: 1.11.13
+ lodash.isequal: 4.5.0
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-native: 0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)
+ react-native-communications: 2.2.1
+ react-native-get-random-values: 1.11.0(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))
+ react-native-iphone-x-helper: 1.3.1(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))
+ react-native-lightbox-v2: 0.9.2(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0)
+ react-native-parsed-text: 0.0.22(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0)
+ react-native-reanimated: 3.10.1(@babel/core@7.25.8)(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0)
+ react-native-safe-area-context: 4.10.5(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0)
+ uuid: 10.0.0
+
react-native-helmet-async@2.0.4(react@18.2.0):
dependencies:
invariant: 2.2.4
@@ -9804,6 +10039,21 @@ snapshots:
react-fast-compare: 3.2.2
shallowequal: 1.1.0
+ react-native-iphone-x-helper@1.3.1(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)):
+ dependencies:
+ react-native: 0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)
+
+ react-native-lightbox-v2@0.9.2(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0):
+ dependencies:
+ react: 18.2.0
+ react-native: 0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)
+
+ react-native-parsed-text@0.0.22(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0):
+ dependencies:
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-native: 0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0)
+
react-native-reanimated@3.10.1(@babel/core@7.25.8)(react-native@0.74.5(@babel/core@7.25.8)(@babel/preset-env@7.25.8(@babel/core@7.25.8))(@types/react@18.2.79)(react@18.2.0))(react@18.2.0):
dependencies:
'@babel/core': 7.25.8
@@ -10557,6 +10807,8 @@ snapshots:
typescript@5.3.3: {}
+ ua-parser-js@0.7.39: {}
+
ua-parser-js@1.0.39: {}
unbox-primitive@1.0.2:
@@ -10638,6 +10890,8 @@ snapshots:
utils-merge@1.0.1: {}
+ uuid@10.0.0: {}
+
uuid@7.0.3: {}
uuid@8.3.2: {}
diff --git a/scripts/reset-project.js b/scripts/reset-project.js
deleted file mode 100755
index 4512e16..0000000
--- a/scripts/reset-project.js
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * This script is used to reset the project to a blank state.
- * It moves the /app directory to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file.
- * You can remove the `reset-project` script from package.json and safely delete this file after running it.
- */
-
-const fs = require('fs');
-const path = require('path');
-
-const root = process.cwd();
-const oldDirPath = path.join(root, 'app');
-const newDirPath = path.join(root, 'app-example');
-const newAppDirPath = path.join(root, 'app');
-
-const indexContent = `import { Text, View } from "react-native";
-
-export default function Index() {
- return (
-
- Edit app/index.tsx to edit this screen.
-
- );
-}
-`;
-
-const layoutContent = `import { Stack } from "expo-router";
-
-export default function RootLayout() {
- return (
-
-
-
- );
-}
-`;
-
-fs.rename(oldDirPath, newDirPath, (error) => {
- if (error) {
- return console.error(`Error renaming directory: ${error}`);
- }
- console.log('/app moved to /app-example.');
-
- fs.mkdir(newAppDirPath, { recursive: true }, (error) => {
- if (error) {
- return console.error(`Error creating new app directory: ${error}`);
- }
- console.log('New /app directory created.');
-
- const indexPath = path.join(newAppDirPath, 'index.tsx');
- fs.writeFile(indexPath, indexContent, (error) => {
- if (error) {
- return console.error(`Error creating index.tsx: ${error}`);
- }
- console.log('app/index.tsx created.');
-
- const layoutPath = path.join(newAppDirPath, '_layout.tsx');
- fs.writeFile(layoutPath, layoutContent, (error) => {
- if (error) {
- return console.error(`Error creating _layout.tsx: ${error}`);
- }
- console.log('app/_layout.tsx created.');
- });
- });
- });
-});