Browse Source

登录

main
Mac 2 months ago
parent
commit
1bf5d0ecf7
  1. 51
      App.tsx
  2. 81
      app/constants/countries.ts
  3. 81
      app/i18n/index.ts
  4. 5
      app/navigation/types.ts
  5. 155
      app/screens/CountrySelect.tsx
  6. 346
      app/screens/LoginScreen.tsx
  7. 302
      app/screens/MainApp.tsx
  8. 14
      package.json
  9. 297
      yarn.lock

51
App.tsx

@ -1,20 +1,41 @@
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { CountrySelect } from './app/screens/CountrySelect';
import { MainApp } from './app/screens/MainApp';
import { LoginScreen } from './app/screens/LoginScreen';
import './app/i18n';
export type RootStackParamList = {
CountrySelect: undefined;
MainApp: undefined;
Login: undefined;
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<StatusBar style="auto" />
</View>
<NavigationContainer>
<Stack.Navigator
initialRouteName="CountrySelect"
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="CountrySelect" component={CountrySelect} />
<Stack.Screen
name="Login"
component={LoginScreen}
options={{
presentation: 'modal',
animation: 'slide_from_bottom',
gestureEnabled: true,
gestureDirection: 'vertical'
}}
/>
<Stack.Screen name="MainApp" component={MainApp} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

81
app/constants/countries.ts

@ -0,0 +1,81 @@
export interface Country {
code: string;
name: string;
flag: string;
userCount: number;
}
export const countries: Country[] = [
{
code: 'CD',
name: 'Democratic Republic of the Congo',
flag: '🇨🇩',
userCount: 1000000
},
{
code: 'TG',
name: 'Togo',
flag: '🇹🇬',
userCount: 900000
},
{
code: 'ML',
name: 'Mali',
flag: '🇲🇱',
userCount: 800000
},
{
code: 'BF',
name: 'Burkina Faso',
flag: '🇧🇫',
userCount: 700000
},
{
code: 'GN',
name: 'Guinea',
flag: '🇬🇳',
userCount: 600000
},
{
code: 'GA',
name: 'Gabon',
flag: '🇬🇦',
userCount: 500000
},
{
code: 'SN',
name: 'Senegal',
flag: '🇸🇳',
userCount: 400000
},
{
code: 'CG',
name: 'Republic of Congo',
flag: '🇨🇬',
userCount: 300000
},
{
code: 'BJ',
name: 'Benin',
flag: '🇧🇯',
userCount: 200000
},
{
code: 'CM',
name: 'Cameroon',
flag: '🇨🇲',
userCount: 150000
},
{
code: 'CI',
name: 'Ivory Coast',
flag: '🇨🇮',
userCount: 100000
},
{
code: 'FR',
name: 'France',
flag: '🇫🇷',
userCount: 50000
}
].sort((a, b) => b.userCount - a.userCount);

81
app/i18n/index.ts

@ -0,0 +1,81 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import * as Localization from 'expo-localization';
const resources = {
en: {
translation: {
selectCountry: 'Select your country',
subtitle: 'You can change the country & language in your profile settings anytime.',
welcomeTitle: 'Welcome!',
welcomeMessage: 'Thank you for choosing your country. You can now log in and use the app.',
loginNow: 'Log in now',
mainAppTitle: 'Welcome to MainApp',
mainAppText: 'This is the main application screen.',
resetCountry: 'Reset Country Selection',
loginTitle: 'Login For brainnel',
loginSubtitle: 'Login to start your business',
continueWithGoogle: 'Continue with Google',
continueWithFacebook: 'Continue with Facebook',
continueWithApple: 'Continue with Apple',
orContinueWith: 'Or continue with',
instagram: 'Instagram',
email: 'Email',
phone: 'Phone',
forgotPassword: 'Forget your password?',
termsText: 'By continuing, you agree to our',
termsOfUse: 'Terms of Use',
and: 'and',
privacyPolicy: 'Privacy Policy',
wholesalePrice: 'Wholesale price',
fastShipping: 'Fast shipping',
},
},
fr: {
translation: {
selectCountry: 'Sélectionnez votre pays',
subtitle: 'Vous pouvez modifier le pays et la langue dans les paramètres de votre profil à tout moment.',
welcomeTitle: 'Bienvenue!',
welcomeMessage: 'Merci d\'avoir choisi votre pays. Vous pouvez maintenant vous connecter et utiliser l\'application.',
loginNow: 'Se connecter maintenant',
mainAppTitle: 'Bienvenue sur MainApp',
mainAppText: 'Ceci est l\'écran principal de l\'application.',
resetCountry: 'Réinitialiser la sélection du pays',
loginTitle: 'Connexion à brainnel',
loginSubtitle: 'Connectez-vous pour démarrer votre entreprise',
continueWithGoogle: 'Continuer avec Google',
continueWithFacebook: 'Continuer avec Facebook',
continueWithApple: 'Continuer avec Apple',
orContinueWith: 'Ou continuer avec',
instagram: 'Instagram',
email: 'Email',
phone: 'Téléphone',
forgotPassword: 'Mot de passe oublié?',
termsText: 'En continuant, vous acceptez nos',
termsOfUse: 'Conditions d\'utilisation',
and: 'et',
privacyPolicy: 'Politique de confidentialité',
wholesalePrice: 'Prix de gros',
fastShipping: 'Livraison rapide',
},
},
};
const getDefaultLanguage = () => {
const locale = Localization.locale;
const languageCode = locale.split('-')[0]; // 获取语言代码部分
return languageCode === 'fr' ? 'fr' : 'en';
};
i18n
.use(initReactI18next)
.init({
resources,
lng: getDefaultLanguage(),
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
});
export default i18n;

5
app/navigation/types.ts

@ -0,0 +1,5 @@
export type RootStackParamList = {
CountrySelect: undefined;
Login: undefined;
MainApp: undefined;
};

155
app/screens/CountrySelect.tsx

@ -0,0 +1,155 @@
import React, { useState, useEffect } from 'react';
import {
View,
Text,
FlatList,
TouchableOpacity,
StyleSheet,
SafeAreaView,
StatusBar,
} from 'react-native';
import { useTranslation } from 'react-i18next';
import { Country, countries } from '../constants/countries';
import Constants from 'expo-constants';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RootStackParamList } from '../../App';
const SELECTED_COUNTRY_KEY = '@selected_country';
type CountrySelectScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'CountrySelect'
>;
export const CountrySelect = () => {
const { t } = useTranslation();
const [selectedCountry, setSelectedCountry] = useState<string>('');
const navigation = useNavigation<CountrySelectScreenNavigationProp>();
useEffect(() => {
checkSelectedCountry();
}, []);
const checkSelectedCountry = async () => {
try {
const savedCountry = await AsyncStorage.getItem(SELECTED_COUNTRY_KEY);
if (savedCountry) {
// 如果已经选择过国家,直接导航到主页面
navigation.replace('MainApp');
}
} catch (error) {
console.error('Error checking selected country:', error);
}
};
const handleCountrySelect = async (countryCode: string) => {
try {
setSelectedCountry(countryCode);
await AsyncStorage.setItem(SELECTED_COUNTRY_KEY, countryCode);
// 选择完成后导航到主页面
navigation.replace('MainApp');
} catch (error) {
console.error('Error saving selected country:', error);
}
};
const renderCountryItem = ({ item }: { item: Country }) => (
<TouchableOpacity
style={[
styles.countryItem,
selectedCountry === item.code && styles.selectedItem
]}
onPress={() => handleCountrySelect(item.code)}
>
<Text style={styles.flag}>{item.flag}</Text>
<Text style={[
styles.countryName,
selectedCountry === item.code && styles.selectedText
]}>{item.name}</Text>
{selectedCountry === item.code && (
<Text style={styles.checkmark}></Text>
)}
</TouchableOpacity>
);
return (
<View style={styles.container}>
<StatusBar
backgroundColor="#fff"
barStyle="dark-content"
/>
<SafeAreaView style={styles.safeArea}>
<View style={styles.header}>
<Text style={styles.title}>{t('selectCountry')}</Text>
<Text style={styles.subtitle}>{t('subtitle')}</Text>
</View>
<FlatList
data={countries}
renderItem={renderCountryItem}
keyExtractor={(item) => item.code}
style={styles.list}
showsVerticalScrollIndicator={false}
/>
</SafeAreaView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingTop: Constants.statusBarHeight,
},
safeArea: {
flex: 1,
},
header: {
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 8,
color: '#000',
},
subtitle: {
fontSize: 14,
color: '#666',
marginBottom: 20,
lineHeight: 20,
},
list: {
flex: 1,
},
countryItem: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0',
},
selectedItem: {
backgroundColor: '#f8f8f8',
},
flag: {
fontSize: 24,
marginRight: 16,
},
countryName: {
flex: 1,
fontSize: 16,
color: '#333',
},
selectedText: {
color: '#007AFF',
fontWeight: '500',
},
checkmark: {
fontSize: 20,
color: '#007AFF',
},
});

346
app/screens/LoginScreen.tsx

@ -0,0 +1,346 @@
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
StatusBar,
Platform,
} from 'react-native';
import { useTranslation } from 'react-i18next';
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RootStackParamList } from '../navigation/types';
export const LoginScreen = () => {
const { t } = useTranslation();
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const handleClose = () => {
navigation.navigate('CountrySelect');
};
const handleGoogleLogin = () => {
// 处理Google登录
};
const handleFacebookLogin = () => {
// 处理Facebook登录
};
const handleAppleLogin = () => {
// 处理Apple登录
};
const handleInstagramLogin = () => {
// 处理Instagram登录
};
const handleEmailLogin = () => {
// 处理邮箱登录
};
const handlePhoneLogin = () => {
// 处理手机号登录
};
const handleForgotPassword = () => {
// 处理忘记密码
};
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" backgroundColor="#0066FF" />
<TouchableOpacity
style={styles.closeButton}
onPress={handleClose}
>
<Text style={styles.closeButtonText}></Text>
</TouchableOpacity>
{/* 顶部蓝色背景区域 */}
<View style={styles.blueHeader}>
<Text style={styles.logo}>brainnel</Text>
<View style={styles.features}>
<View style={styles.featureItem}>
<View style={styles.featureIconContainer}>
<Text style={styles.featureIcon}>💰</Text>
</View>
<Text style={styles.featureText}>{t('wholesalePrice')}</Text>
</View>
<View style={styles.featureItem}>
<View style={styles.featureIconContainer}>
<Text style={styles.featureIcon}>🚚</Text>
</View>
<Text style={styles.featureText}>{t('fastShipping')}</Text>
</View>
</View>
</View>
{/* 登录区域 */}
<View style={styles.loginContainer}>
<Text style={styles.title}>{t('loginTitle')}</Text>
<Text style={styles.subtitle}>{t('loginSubtitle')}</Text>
{/* 社交媒体登录按钮 */}
<TouchableOpacity
style={[styles.socialButton, styles.googleButton]}
onPress={handleGoogleLogin}
>
<Text style={styles.googleIcon}>G</Text>
<Text style={styles.socialButtonText}>{t('continueWithGoogle')}</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.socialButton, styles.facebookButton]}
onPress={handleFacebookLogin}
>
<Text style={styles.facebookIcon}>f</Text>
<Text style={[styles.socialButtonText, styles.whiteText]}>{t('continueWithFacebook')}</Text>
</TouchableOpacity>
{Platform.OS === 'ios' && (
<TouchableOpacity
style={[styles.socialButton, styles.appleButton]}
onPress={handleAppleLogin}
>
<Text style={styles.appleIcon}>🍎</Text>
<Text style={[styles.socialButtonText, styles.whiteText]}>{t('continueWithApple')}</Text>
</TouchableOpacity>
)}
{/* 分隔线 */}
<View style={styles.dividerContainer}>
<View style={styles.dividerLine} />
<Text style={styles.dividerText}>{t('orContinueWith')}</Text>
<View style={styles.dividerLine} />
</View>
{/* 其他登录选项 */}
<View style={styles.otherLoginOptions}>
<TouchableOpacity
style={styles.otherLoginButton}
onPress={handleInstagramLogin}
>
<View style={styles.otherLoginIconContainer}>
<Text style={styles.otherLoginIcon}>📷</Text>
</View>
<Text style={styles.otherLoginText}>{t('instagram')}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.otherLoginButton}
onPress={handleEmailLogin}
>
<View style={styles.otherLoginIconContainer}>
<Text style={styles.otherLoginIcon}></Text>
</View>
<Text style={styles.otherLoginText}>{t('email')}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.otherLoginButton}
onPress={handlePhoneLogin}
>
<View style={styles.otherLoginIconContainer}>
<Text style={styles.otherLoginIcon}>📱</Text>
</View>
<Text style={styles.otherLoginText}>{t('phone')}</Text>
</TouchableOpacity>
</View>
{/* 忘记密码 */}
<TouchableOpacity
style={styles.forgotPassword}
onPress={handleForgotPassword}
>
<Text style={styles.forgotPasswordText}>{t('forgotPassword')}</Text>
</TouchableOpacity>
{/* 服务条款 */}
<Text style={styles.terms}>
{t('termsText')} <Text style={styles.link}>{t('termsOfUse')}</Text>
{'\n'}{t('and')} <Text style={styles.link}>{t('privacyPolicy')}</Text>
</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
closeButton: {
position: 'absolute',
top: 0,
left: 20,
width: 32,
height: 32,
borderRadius: 16,
backgroundColor: 'rgba(255, 255, 255, 0.2)',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
},
closeButtonText: {
color: '#fff',
fontSize: 16,
fontWeight: '500',
},
blueHeader: {
backgroundColor: '#0066FF',
paddingHorizontal: 20,
paddingBottom: 20,
borderBottomLeftRadius: 24,
borderBottomRightRadius: 24,
paddingTop: 60,
},
logo: {
fontSize: 28,
fontWeight: 'bold',
color: '#fff',
marginBottom: 15,
},
features: {
flexDirection: 'column',
gap: 12,
},
featureItem: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
featureIconContainer: {
backgroundColor: 'rgba(255, 255, 255, 0.2)',
borderRadius: 8,
width: 24,
height: 24,
justifyContent: 'center',
alignItems: 'center',
},
featureIcon: {
fontSize: 12,
},
featureText: {
fontSize: 14,
color: '#fff',
},
loginContainer: {
flex: 1,
paddingHorizontal: 20,
paddingTop: 30,
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#000',
marginBottom: 8,
},
subtitle: {
fontSize: 14,
color: '#666',
marginBottom: 30,
},
socialButton: {
flexDirection: 'row',
height: 48,
borderRadius: 24,
alignItems: 'center',
marginBottom: 12,
paddingHorizontal: 16,
},
googleButton: {
backgroundColor: '#4285F4',
},
facebookButton: {
backgroundColor: '#3b5998',
},
appleButton: {
backgroundColor: '#000',
},
googleIcon: {
color: '#fff',
fontSize: 20,
fontWeight: 'bold',
marginRight: 12,
},
facebookIcon: {
color: '#fff',
fontSize: 24,
fontWeight: 'bold',
marginRight: 12,
},
appleIcon: {
fontSize: 20,
marginRight: 12,
},
socialButtonText: {
flex: 1,
textAlign: 'center',
fontSize: 16,
fontWeight: '500',
color: '#fff',
marginRight: 24,
},
whiteText: {
color: '#fff',
},
dividerContainer: {
flexDirection: 'row',
alignItems: 'center',
marginVertical: 24,
},
dividerLine: {
flex: 1,
height: 1,
backgroundColor: '#E5E5E5',
},
dividerText: {
marginHorizontal: 16,
color: '#666',
fontSize: 14,
},
otherLoginOptions: {
flexDirection: 'row',
justifyContent: 'space-around',
marginBottom: 30,
},
otherLoginButton: {
alignItems: 'center',
},
otherLoginIconContainer: {
width: 48,
height: 48,
backgroundColor: '#F5F5F5',
borderRadius: 24,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 8,
},
otherLoginIcon: {
fontSize: 24,
},
otherLoginText: {
fontSize: 12,
color: '#333',
},
forgotPassword: {
alignItems: 'center',
marginBottom: 20,
},
forgotPasswordText: {
color: '#0066FF',
fontSize: 14,
},
terms: {
fontSize: 12,
color: '#666',
textAlign: 'center',
lineHeight: 18,
},
link: {
color: '#0066FF',
},
});

302
app/screens/MainApp.tsx

@ -0,0 +1,302 @@
import React, { useEffect, useState, useCallback } from 'react';
import {
View,
Text,
StyleSheet,
SafeAreaView,
StatusBar,
TouchableOpacity,
Modal,
Animated,
Dimensions,
BackHandler,
} from 'react-native';
import Constants from 'expo-constants';
import { useTranslation } from 'react-i18next';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RootStackParamList } from '../../App';
type MainAppScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'MainApp'
>;
const MODAL_HEIGHT = 280; // 估计的模态框高度
export const MainApp = () => {
const { t } = useTranslation();
const navigation = useNavigation<MainAppScreenNavigationProp>();
const [modalVisible, setModalVisible] = useState(true);
const [slideAnim] = useState(new Animated.Value(MODAL_HEIGHT));
const [fadeAnim] = useState(new Animated.Value(0));
useEffect(() => {
if (modalVisible) {
slideAnim.setValue(MODAL_HEIGHT);
fadeAnim.setValue(0);
Animated.parallel([
Animated.spring(slideAnim, {
toValue: 0,
useNativeDriver: true,
tension: 65,
friction: 8,
velocity: 0.3,
}),
Animated.timing(fadeAnim, {
toValue: 1,
duration: 200,
useNativeDriver: true,
})
]).start();
}
}, [modalVisible]);
const handleCloseModal = useCallback(() => {
Animated.parallel([
Animated.timing(slideAnim, {
toValue: MODAL_HEIGHT,
duration: 200,
useNativeDriver: true,
}),
Animated.timing(fadeAnim, {
toValue: 0,
duration: 200,
useNativeDriver: true,
})
]).start(() => {
setModalVisible(false);
});
}, [slideAnim, fadeAnim]);
const handleLoginPress = () => {
handleCloseModal();
// 延迟导航,等待弹窗关闭动画完成
setTimeout(() => {
navigation.replace('Login');
}, 200);
};
useEffect(() => {
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
() => {
if (modalVisible) {
handleCloseModal();
return true;
}
return false;
}
);
return () => backHandler.remove();
}, [modalVisible, handleCloseModal]);
const handleLogout = async () => {
try {
await AsyncStorage.removeItem('@selected_country');
navigation.replace('CountrySelect');
} catch (error) {
console.error('Error logging out:', error);
}
};
return (
<View style={styles.container}>
<StatusBar
backgroundColor="#fff"
barStyle="dark-content"
/>
<SafeAreaView style={styles.safeArea}>
<View style={styles.header}>
<Text style={styles.title}>{t('mainAppTitle')}</Text>
</View>
<View style={styles.content}>
<Text style={styles.text}>{t('mainAppText')}</Text>
<TouchableOpacity
style={styles.button}
onPress={handleLogout}
>
<Text style={styles.buttonText}>{t('resetCountry')}</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
<Modal
visible={modalVisible}
transparent={true}
animationType="none"
statusBarTranslucent={true}
onRequestClose={handleCloseModal}
>
<Animated.View
style={[
styles.modalContainer,
{
opacity: fadeAnim,
}
]}
>
<Animated.View
style={[
styles.modalOverlay,
{
opacity: fadeAnim,
}
]}
>
<TouchableOpacity
style={styles.modalOverlayTouch}
activeOpacity={1}
onPress={handleCloseModal}
/>
</Animated.View>
<Animated.View
style={[
styles.modalContent,
{
transform: [{ translateY: slideAnim }],
},
]}
>
<TouchableOpacity
style={styles.closeButton}
onPress={handleCloseModal}
>
<Text style={styles.closeButtonText}></Text>
</TouchableOpacity>
<View style={styles.modalHeader}>
<View style={styles.modalIndicator} />
</View>
<Text style={styles.modalTitle}>{t('welcomeTitle')}</Text>
<Text style={styles.modalText}>
{t('welcomeMessage')}
</Text>
<TouchableOpacity
style={styles.modalButton}
onPress={handleLoginPress}
>
<Text style={styles.modalButtonText}>{t('loginNow')}</Text>
</TouchableOpacity>
</Animated.View>
</Animated.View>
</Modal>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingTop: Constants.statusBarHeight,
},
safeArea: {
flex: 1,
},
header: {
padding: 20,
backgroundColor: '#fff',
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#000',
},
content: {
flex: 1,
padding: 20,
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontSize: 16,
color: '#333',
marginBottom: 30,
},
button: {
backgroundColor: '#007AFF',
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 8,
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '500',
},
modalContainer: {
flex: 1,
justifyContent: 'flex-end',
},
modalOverlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.4)',
},
modalOverlayTouch: {
flex: 1,
},
modalContent: {
backgroundColor: '#fff',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
padding: 20,
paddingBottom: 40,
},
modalHeader: {
alignItems: 'center',
marginBottom: 20,
},
modalIndicator: {
width: 40,
height: 4,
backgroundColor: '#DDD',
borderRadius: 2,
marginVertical: 8,
},
modalTitle: {
fontSize: 22,
fontWeight: 'bold',
marginBottom: 16,
color: '#000',
},
modalText: {
fontSize: 16,
color: '#666',
marginBottom: 24,
lineHeight: 22,
},
modalButton: {
backgroundColor: '#007AFF',
paddingVertical: 14,
borderRadius: 10,
alignItems: 'center',
},
modalButtonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
closeButton: {
position: 'absolute',
top: 20,
right: 20,
width: 24,
height: 24,
alignItems: 'center',
justifyContent: 'center',
zIndex: 1,
},
closeButtonText: {
fontSize: 20,
color: '#999',
fontWeight: '400',
},
});

14
package.json

@ -10,10 +10,22 @@
"web": "expo start --web"
},
"dependencies": {
"@expo/metro-runtime": "~4.0.1",
"@react-native-async-storage/async-storage": "^2.1.2",
"@react-navigation/native": "^7.0.19",
"@react-navigation/native-stack": "^7.3.3",
"expo": "~52.0.41",
"expo-localization": "^16.0.1",
"expo-status-bar": "~2.0.1",
"i18next": "^24.2.3",
"react": "18.3.1",
"react-native": "0.76.7"
"react-dom": "18.3.1",
"react-i18next": "^15.4.1",
"react-native": "0.76.7",
"react-native-localize": "^3.4.1",
"react-native-safe-area-context": "^5.3.0",
"react-native-screens": "^4.10.0",
"react-native-web": "~0.19.13"
},
"devDependencies": {
"@babel/core": "^7.25.2",

297
yarn.lock

@ -761,7 +761,7 @@
pirates "^4.0.6"
source-map-support "^0.5.16"
"@babel/runtime@^7.20.0", "@babel/runtime@^7.25.0", "@babel/runtime@^7.8.4":
"@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0", "@babel/runtime@^7.25.0", "@babel/runtime@^7.26.10", "@babel/runtime@^7.8.4":
version "7.27.0"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762"
integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==
@ -1042,6 +1042,11 @@
postcss "~8.4.32"
resolve-from "^5.0.0"
"@expo/metro-runtime@~4.0.1":
version "4.0.1"
resolved "https://registry.npmmirror.com/@expo/metro-runtime/-/metro-runtime-4.0.1.tgz#ccc74b32bd48eb64c34a4ff29690204cc11c6e7a"
integrity sha512-CRpbLvdJ1T42S+lrYa1iZp1KfDeBp4oeZOK3hdpiS5n0vR0nhD6sC1gGF0sTboCTp64tLteikz5Y3j53dvgOIw==
"@expo/osascript@^2.1.6":
version "2.1.6"
resolved "https://registry.npmmirror.com/@expo/osascript/-/osascript-2.1.6.tgz#d20e764526310b0d393275f904e20fbff13d18f9"
@ -1316,6 +1321,13 @@
resolved "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@react-native-async-storage/async-storage@^2.1.2":
version "2.1.2"
resolved "https://registry.npmmirror.com/@react-native-async-storage/async-storage/-/async-storage-2.1.2.tgz#8aae432adfc20800308e2ef3ce380864f0f9def8"
integrity sha512-dvlNq4AlGWC+ehtH12p65+17V0Dx7IecOWl6WanF2ja38O1Dcjjvn7jVzkUHJ5oWkQBlyASurTPlTHgKXyYiow==
dependencies:
merge-options "^3.0.4"
"@react-native/assets-registry@0.76.7":
version "0.76.7"
resolved "https://registry.npmmirror.com/@react-native/assets-registry/-/assets-registry-0.76.7.tgz#b9a82d67826edebeb0537393ad984694e8b82395"
@ -1458,6 +1470,11 @@
resolved "https://registry.npmmirror.com/@react-native/normalize-colors/-/normalize-colors-0.76.7.tgz#dbf0a44e1a9a9ccae4dbb124b389eeedbd33976c"
integrity sha512-ST1xxBuYVIXPdD81dR6+tzIgso7m3pa9+6rOBXTh5Xm7KEEFik7tnQX+GydXYMp3wr1gagJjragdXkPnxK6WNg==
"@react-native/normalize-colors@^0.74.1":
version "0.74.89"
resolved "https://registry.npmmirror.com/@react-native/normalize-colors/-/normalize-colors-0.74.89.tgz#b8ac17d1bbccd3ef9a1f921665d04d42cff85976"
integrity sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==
"@react-native/virtualized-lists@0.76.7":
version "0.76.7"
resolved "https://registry.npmmirror.com/@react-native/virtualized-lists/-/virtualized-lists-0.76.7.tgz#3ef6b7030260d81060c52a0582f1e2ccc7c0eb66"
@ -1466,6 +1483,52 @@
invariant "^2.2.4"
nullthrows "^1.1.1"
"@react-navigation/core@^7.7.0":
version "7.7.0"
resolved "https://registry.npmmirror.com/@react-navigation/core/-/core-7.7.0.tgz#0de1501ca8a61c1b02046577fe13e596b28aaade"
integrity sha512-u8GaO4QuX5VyfLk7s6dw10W/zl5c0NKOPocjYfWO4Wiaq4VROY00jjVcc1oYPEhDn5XXonx7U0l7jYYUA0cHlQ==
dependencies:
"@react-navigation/routers" "^7.3.1"
escape-string-regexp "^4.0.0"
nanoid "3.3.8"
query-string "^7.1.3"
react-is "^18.2.0"
use-latest-callback "^0.2.1"
use-sync-external-store "^1.2.2"
"@react-navigation/elements@^2.3.1":
version "2.3.1"
resolved "https://registry.npmmirror.com/@react-navigation/elements/-/elements-2.3.1.tgz#2c1da08c9bbad2daeded1dfe1a5d42769494d3b5"
integrity sha512-94lFVh/yjqPjahHo8zQBggooXVHr791Frpp0v/3idsn9J8tRrzTMQVgjDNNNbSPj7PZtvh/N9EiEq5sVf/vmxA==
dependencies:
color "^4.2.3"
"@react-navigation/native-stack@^7.3.3":
version "7.3.3"
resolved "https://registry.npmmirror.com/@react-navigation/native-stack/-/native-stack-7.3.3.tgz#0b05b5aea07088ce383ae1a553eb8761fc732b49"
integrity sha512-piUO4MzYPrdiolrB/FKU25216MPQHd+90tIE2uwqioRLzEAcv78f0Pugi2Hp7RSOMmNjLIIGk6QMwZqr/ot9KQ==
dependencies:
"@react-navigation/elements" "^2.3.1"
warn-once "^0.1.1"
"@react-navigation/native@^7.0.19":
version "7.0.19"
resolved "https://registry.npmmirror.com/@react-navigation/native/-/native-7.0.19.tgz#3f9c7c809ec19f98d5c88fd895e6f0d33128a174"
integrity sha512-6UDTFVM91FIUaXF5OZ7GHb+XZK6yAktqdTOBOtn3goIyafKz0OUo+ukxe+tPGpr+E9ZQjdZDCseIH6HOI/k8rw==
dependencies:
"@react-navigation/core" "^7.7.0"
escape-string-regexp "^4.0.0"
fast-deep-equal "^3.1.3"
nanoid "3.3.8"
use-latest-callback "^0.2.1"
"@react-navigation/routers@^7.3.1":
version "7.3.1"
resolved "https://registry.npmmirror.com/@react-navigation/routers/-/routers-7.3.1.tgz#3068bb677b6cc9dbdaaea1aef23fbba2393b9bb8"
integrity sha512-d0hJi4eZJQB84JtHlA3HDR9VHoKDfyknSCdz/7a3Mdz1OJDZsvU+qjfK2c9mxNFd+ak/ekLhEkwwh8QtVF0faw==
dependencies:
nanoid "3.3.8"
"@segment/loosely-validate-event@^2.0.0":
version "2.0.0"
resolved "https://registry.npmmirror.com/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz#87dfc979e5b4e7b82c5f1d8b722dfd5d77644681"
@ -2204,11 +2267,27 @@ color-name@1.1.3:
resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
color-name@~1.1.4:
color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-string@^1.9.0:
version "1.9.1"
resolved "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^4.2.3:
version "4.2.3"
resolved "https://registry.npmmirror.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
dependencies:
color-convert "^2.0.1"
color-string "^1.9.0"
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@ -2345,6 +2424,13 @@ crypto-random-string@^2.0.0:
resolved "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
css-in-js-utils@^3.1.0:
version "3.1.0"
resolved "https://registry.npmmirror.com/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz#640ae6a33646d401fc720c54fc61c42cd76ae2bb"
integrity sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==
dependencies:
hyphenate-style-name "^1.0.3"
csstype@^3.0.2:
version "3.1.3"
resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
@ -2371,6 +2457,11 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3
dependencies:
ms "^2.1.3"
decode-uri-component@^0.2.2:
version "0.2.2"
resolved "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
deep-extend@^0.6.0:
version "0.6.0"
resolved "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
@ -2666,6 +2757,13 @@ expo-keep-awake@~14.0.3:
resolved "https://registry.npmmirror.com/expo-keep-awake/-/expo-keep-awake-14.0.3.tgz#74c91b68effdb6969bc1e8371621aad90386cfbf"
integrity sha512-6Jh94G6NvTZfuLnm2vwIpKe3GdOiVBuISl7FI8GqN0/9UOg9E0WXXp5cDcfAG8bn80RfgLJS8P7EPUGTZyOvhg==
expo-localization@^16.0.1:
version "16.0.1"
resolved "https://registry.npmmirror.com/expo-localization/-/expo-localization-16.0.1.tgz#a6016288f0e4a5acef143d2a39ac3e5b4ac8963e"
integrity sha512-kUrXiV/Pq9r7cG+TMt+Qa49IUQ9Y/czVwen4hmiboTclTopcWdIeCzYZv6JGtufoPpjEO9vVx1QJrXYl9V2u0Q==
dependencies:
rtl-detect "^1.0.2"
expo-modules-autolinking@2.0.8:
version "2.0.8"
resolved "https://registry.npmmirror.com/expo-modules-autolinking/-/expo-modules-autolinking-2.0.8.tgz#b00c10ebb589ce2220548bbaee4865db1cf1f1f7"
@ -2721,6 +2819,11 @@ exponential-backoff@^3.1.1:
resolved "https://registry.npmmirror.com/exponential-backoff/-/exponential-backoff-3.1.2.tgz#a8f26adb96bf78e8cd8ad1037928d5e5c0679d91"
integrity sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==
fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-glob@^3.2.5, fast-glob@^3.2.9, fast-glob@^3.3.2:
version "3.3.3"
resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
@ -2737,6 +2840,11 @@ fast-json-stable-stringify@^2.1.0:
resolved "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-loops@^1.1.3:
version "1.1.4"
resolved "https://registry.npmmirror.com/fast-loops/-/fast-loops-1.1.4.tgz#61bc77d518c0af5073a638c6d9d5c7683f069ce2"
integrity sha512-8dbd3XWoKCTms18ize6JmQF1SFnnfj5s0B7rRry22EofgMu7B6LKHVh+XfFqFGsqnbH54xgeO83PzpKI+ODhlg==
fastq@^1.6.0:
version "1.19.1"
resolved "https://registry.npmmirror.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5"
@ -2763,7 +2871,7 @@ fbjs-css-vars@^1.0.0:
resolved "https://registry.npmmirror.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8"
integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==
fbjs@^3.0.0:
fbjs@^3.0.0, fbjs@^3.0.4:
version "3.0.5"
resolved "https://registry.npmmirror.com/fbjs/-/fbjs-3.0.5.tgz#aa0edb7d5caa6340011790bd9249dbef8a81128d"
integrity sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==
@ -2788,6 +2896,11 @@ fill-range@^7.1.1:
dependencies:
to-regex-range "^5.0.1"
filter-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==
finalhandler@1.1.2:
version "1.1.2"
resolved "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
@ -3113,6 +3226,13 @@ hosted-git-info@^7.0.0:
dependencies:
lru-cache "^10.0.1"
html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
dependencies:
void-elements "3.1.0"
http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
@ -3129,6 +3249,18 @@ human-signals@^2.1.0:
resolved "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
hyphenate-style-name@^1.0.3:
version "1.1.0"
resolved "https://registry.npmmirror.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz#1797bf50369588b47b72ca6d5e65374607cf4436"
integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==
i18next@^24.2.3:
version "24.2.3"
resolved "https://registry.npmmirror.com/i18next/-/i18next-24.2.3.tgz#3a05f72615cbd7c00d7e348667e2aabef1df753b"
integrity sha512-lfbf80OzkocvX7nmZtu7nSTNbrTYR52sLWxPtlXX1zAhVw8WEnFk4puUkCR4B1dNQwbSpEHHHemcZu//7EcB7A==
dependencies:
"@babel/runtime" "^7.26.10"
ieee754@^1.1.13:
version "1.2.1"
resolved "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
@ -3182,6 +3314,14 @@ ini@~1.3.0:
resolved "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inline-style-prefixer@^6.0.1:
version "6.0.4"
resolved "https://registry.npmmirror.com/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz#4290ed453ab0e4441583284ad86e41ad88384f44"
integrity sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==
dependencies:
css-in-js-utils "^3.1.0"
fast-loops "^1.1.3"
internal-ip@^4.3.0:
version "4.3.0"
resolved "https://registry.npmmirror.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
@ -3212,6 +3352,11 @@ is-arrayish@^0.2.1:
resolved "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
is-arrayish@^0.3.1:
version "0.3.2"
resolved "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@ -3266,6 +3411,11 @@ is-path-inside@^3.0.2:
resolved "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-obj@^2.1.0:
version "2.1.0"
resolved "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
@ -3730,6 +3880,18 @@ memoize-one@^5.0.0:
resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
memoize-one@^6.0.0:
version "6.0.0"
resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
merge-options@^3.0.4:
version "3.0.4"
resolved "https://registry.npmmirror.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7"
integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==
dependencies:
is-plain-obj "^2.1.0"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@ -4068,6 +4230,11 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nanoid@3.3.8:
version "3.3.8"
resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
nanoid@^3.3.7:
version "3.3.11"
resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
@ -4421,6 +4588,11 @@ pngjs@^3.3.0:
resolved "https://registry.npmmirror.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@~8.4.32:
version "8.4.49"
resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19"
@ -4503,6 +4675,16 @@ qrcode-terminal@0.11.0:
resolved "https://registry.npmmirror.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz#ffc6c28a2fc0bfb47052b47e23f4f446a5fbdb9e"
integrity sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==
query-string@^7.1.3:
version "7.1.3"
resolved "https://registry.npmmirror.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==
dependencies:
decode-uri-component "^0.2.2"
filter-obj "^1.1.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@ -4538,16 +4720,69 @@ react-devtools-core@^5.3.1:
shell-quote "^1.6.1"
ws "^7"
react-dom@18.3.1:
version "18.3.1"
resolved "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.2"
react-freeze@^1.0.0:
version "1.0.4"
resolved "https://registry.npmmirror.com/react-freeze/-/react-freeze-1.0.4.tgz#cbbea2762b0368b05cbe407ddc9d518c57c6f3ad"
integrity sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==
react-i18next@^15.4.1:
version "15.4.1"
resolved "https://registry.npmmirror.com/react-i18next/-/react-i18next-15.4.1.tgz#33f3e89c2f6c68e2bfcbf9aa59986ad42fe78758"
integrity sha512-ahGab+IaSgZmNPYXdV1n+OYky95TGpFwnKRflX/16dY04DsYYKHtVLjeny7sBSCREEcoMbAgSkFiGLF5g5Oofw==
dependencies:
"@babel/runtime" "^7.25.0"
html-parse-stringify "^3.0.1"
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^18.0.0:
react-is@^18.0.0, react-is@^18.2.0:
version "18.3.1"
resolved "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
react-native-localize@^3.4.1:
version "3.4.1"
resolved "https://registry.npmmirror.com/react-native-localize/-/react-native-localize-3.4.1.tgz#df07c13231b4e8cc949e68513b124105f861229c"
integrity sha512-NJqJGBUpHtD/MpLCCkrNiqNZ+xFwbHCivxaoN1Oeb8tBAiZr/IqgP3E+MgnqmmdTMOJ33llUfiW3EM6pEIb33w==
react-native-safe-area-context@^5.3.0:
version "5.3.0"
resolved "https://registry.npmmirror.com/react-native-safe-area-context/-/react-native-safe-area-context-5.3.0.tgz#272e6786a58aafe3362fde4d3233713b66158179"
integrity sha512-glV9bwuozTjf/JDBIBm+ITnukHNaUT3nucgdeADwjtHsfEN3RL5UO6nq99vvdWv5j/O9yCZBvFncM1BBQ+UvpQ==
react-native-screens@^4.10.0:
version "4.10.0"
resolved "https://registry.npmmirror.com/react-native-screens/-/react-native-screens-4.10.0.tgz#40634aead590c6b7034ded6a9f92465d1d611906"
integrity sha512-Tw21NGuXm3PbiUGtZd0AnXirUixaAbPXDjNR0baBH7/WJDaDTTELLcQ7QRXuqAWbmr/EVCrKj1348ei1KFIr8A==
dependencies:
react-freeze "^1.0.0"
warn-once "^0.1.0"
react-native-web@~0.19.13:
version "0.19.13"
resolved "https://registry.npmmirror.com/react-native-web/-/react-native-web-0.19.13.tgz#2d84849bf0251ec0e3a8072fda7f9a7c29375331"
integrity sha512-etv3bN8rJglrRCp/uL4p7l8QvUNUC++QwDbdZ8CB7BvZiMvsxfFIRM1j04vxNldG3uo2puRd6OSWR3ibtmc29A==
dependencies:
"@babel/runtime" "^7.18.6"
"@react-native/normalize-colors" "^0.74.1"
fbjs "^3.0.4"
inline-style-prefixer "^6.0.1"
memoize-one "^6.0.0"
nullthrows "^1.1.1"
postcss-value-parser "^4.2.0"
styleq "^0.1.3"
react-native@0.76.7:
version "0.76.7"
resolved "https://registry.npmmirror.com/react-native/-/react-native-0.76.7.tgz#db7791674e52d741d2fe5a9cca59543bf1e10822"
@ -4759,6 +4994,11 @@ rimraf@~2.6.2:
dependencies:
glob "^7.1.3"
rtl-detect@^1.0.2:
version "1.1.2"
resolved "https://registry.npmmirror.com/rtl-detect/-/rtl-detect-1.1.2.tgz#ca7f0330af5c6bb626c15675c642ba85ad6273c6"
integrity sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
@ -4783,6 +5023,13 @@ scheduler@0.24.0-canary-efb381bbf-20230505:
dependencies:
loose-envify "^1.1.0"
scheduler@^0.23.2:
version "0.23.2"
resolved "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
dependencies:
loose-envify "^1.1.0"
selfsigned@^2.4.1:
version "2.4.1"
resolved "https://registry.npmmirror.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0"
@ -4924,6 +5171,13 @@ simple-plist@^1.1.0:
bplist-parser "0.3.1"
plist "^3.0.5"
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
dependencies:
is-arrayish "^0.3.1"
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.npmmirror.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
@ -4962,6 +5216,11 @@ source-map@^0.6.0, source-map@~0.6.1:
resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
split@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
@ -5015,6 +5274,11 @@ stream-buffers@2.2.x, stream-buffers@~2.2.0:
resolved "https://registry.npmmirror.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@ -5090,6 +5354,11 @@ structured-headers@^0.4.1:
resolved "https://registry.npmmirror.com/structured-headers/-/structured-headers-0.4.1.tgz#77abd9410622c6926261c09b9d16cf10592694d1"
integrity sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==
styleq@^0.1.3:
version "0.1.3"
resolved "https://registry.npmmirror.com/styleq/-/styleq-0.1.3.tgz#8efb2892debd51ce7b31dc09c227ad920decab71"
integrity sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==
sucrase@3.35.0:
version "3.35.0"
resolved "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
@ -5384,6 +5653,16 @@ update-browserslist-db@^1.1.1:
escalade "^3.2.0"
picocolors "^1.1.1"
use-latest-callback@^0.2.1:
version "0.2.3"
resolved "https://registry.npmmirror.com/use-latest-callback/-/use-latest-callback-0.2.3.tgz#2d644d3063040b9bc2d4c55bb525a13ae3de9e16"
integrity sha512-7vI3fBuyRcP91pazVboc4qu+6ZqM8izPWX9k7cRnT8hbD5svslcknsh3S9BUhaK11OmgTV4oWZZVSeQAiV53SQ==
use-sync-external-store@^1.2.2:
version "1.5.0"
resolved "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz#55122e2a3edd2a6c106174c27485e0fd59bcfca0"
integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==
utils-merge@1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
@ -5414,6 +5693,11 @@ vlq@^1.0.0:
resolved "https://registry.npmmirror.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468"
integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==
void-elements@3.1.0:
version "3.1.0"
resolved "https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
walker@^1.0.7, walker@^1.0.8:
version "1.0.8"
resolved "https://registry.npmmirror.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f"
@ -5421,6 +5705,11 @@ walker@^1.0.7, walker@^1.0.8:
dependencies:
makeerror "1.0.12"
warn-once@^0.1.0, warn-once@^0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/warn-once/-/warn-once-0.1.1.tgz#952088f4fb56896e73fd4e6a3767272a3fccce43"
integrity sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==
wcwidth@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"

Loading…
Cancel
Save