Browse Source

perf: 新增用户条款页面

kuns 2 months ago
parent
commit
4ca70ceb05

+ 14 - 0
app/(auth)/(tabs)/(account)/accountUserTermsPage.tsx

@@ -0,0 +1,14 @@
+import { View, Text, ScrollView, Pressable, Button, Alert } from 'react-native';
+import React, { useContext } from 'react';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { router } from 'expo-router';
+import UserTermsPageComponent from '../../../../component/accountPages/userTermsPageComponent';
+const UserTermsPage = () => {
+    return (
+        <View className="flex-1">
+          <UserTermsPageComponent></UserTermsPageComponent>
+        </View>
+        );
+};
+
+export default UserTermsPage;

+ 14 - 0
app/(public)/userTermsPage.tsx

@@ -0,0 +1,14 @@
+import { View, Text, ScrollView, Pressable, Button, Alert } from 'react-native';
+import React, { useContext } from 'react';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { router } from 'expo-router';
+import UserTermsPageComponent from '../../component/accountPages/userTermsPageComponent';
+const UserTermsPage = () => {
+    return (
+        <View className="flex-1">
+          <UserTermsPageComponent></UserTermsPageComponent>
+        </View>
+        );
+};
+
+export default UserTermsPage;

+ 1 - 0
app/_layout.tsx

@@ -55,6 +55,7 @@ export default function RootLayout() {
                     <Stack.Screen name="(public)/login" options={{ headerShown: false }} />
                     <Stack.Screen name="(public)/registerChooseVehiclesOne" options={{ headerShown: false }} />
                     <Stack.Screen name="(public)/registerChooseVehiclesTwo" options={{ headerShown: false }} />
+                    <Stack.Screen name="(public)/userTermsPage" options={{ headerShown: false }} />
                     {/* Testing Purpose */}
                     {NODE_ENV == 'development' ? (
                         <Stack.Screen

+ 19 - 1
component/accountPages/accountMainPageComponent.tsx

@@ -15,7 +15,9 @@ import {
     SettingIconSvg,
     VipCodeIcoonSvg,
     WalletSvg,
-    NotificationSvg
+    NotificationSvg,
+    BookingIconSvg,
+    UserTermsSvg
 } from '../global/SVG';
 import { usePushNotifications } from '../../app/hooks/usePushNotifications';
 import useUserInfoStore from '../../providers/userinfo_store';
@@ -211,6 +213,22 @@ const AccountMainPageComponent = () => {
                         </Pressable>
                     </View> */}
                     <View className="h-0.5  bg-[#f4f4f4] dark:bg-[#5E6C70]" />
+                    <View className="py-4">
+                        <Pressable
+                            onPress={() => router.push('/accountUserTermsPage')}
+                            className="flex-row items-center"
+                            hitSlop={{
+                                top: 10,
+                                bottom: 10,
+                                left: 10,
+                                right: 10
+                            }}
+                        >
+                            <UserTermsSvg />
+                            <Text className="text-lg pl-2 text-black dark:text-white">用戶條款</Text>
+                        </Pressable>
+                    </View>
+                    <View className="h-0.5  bg-[#f4f4f4] dark:bg-[#5E6C70]" />
                     <View className="py-4">
                         <Pressable
                             onPress={logout}

+ 28 - 0
component/accountPages/userTermsPageComponent.tsx

@@ -0,0 +1,28 @@
+import { View, Text, ScrollView, Pressable, Button, Alert } from 'react-native';
+import React, { useContext } from 'react';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { router } from 'expo-router';
+import { CrossLogoSvg, RightArrowIconSvg } from '../global/SVG';
+const UserTermsPageComponent = () => {
+    return (
+            <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
+                <ScrollView className="flex-1 mx-[5%]" showsVerticalScrollIndicator={false}>
+                    <View style={{ marginTop: 25 }}>
+                        <Pressable
+                            onPress={() => {
+                                router.back();
+                            }}
+                        >
+                            <CrossLogoSvg />
+                        </Pressable>
+                        <Text style={{ fontSize: 45, marginVertical: 25 }}>用戶條款</Text>
+                    </View>
+                    <View>
+                      
+                    </View>
+                </ScrollView>
+            </SafeAreaView>
+        );
+};
+
+export default UserTermsPageComponent;

+ 7 - 0
component/global/SVG.tsx

@@ -409,3 +409,10 @@ export const NotificationSvg = ({ isDark }: { isDark: boolean }) => (
         />
     </Svg>
 );
+export const UserTermsSvg = () => (
+    <Svg viewBox="0 0 1024 1024" width="26" height="22" fill="#02677D">
+        <Path
+           d="M157.76 896h690.24v-786.24h-690.24v786.24zM925.76 32v941.76h-845.76v-941.76h845.76zM430.88 286.88v77.76h288v-77.76h-288zM286.88 286.88v77.76h77.76v-77.76h-77.76zM430.88 454.88v77.76h288v-77.76h-288zM286.88 454.88v77.76h77.76v-77.76h-77.76zM430.88 622.88v77.76h288v-77.76h-288zM286.88 622.88v77.76h77.76v-77.76h-77.76z" p-id="5801" fill="#02677D"
+        />
+    </Svg>
+)

+ 12 - 178
component/global/phone_input.tsx

@@ -1,179 +1,5 @@
-// import React, { useState } from "react";
-// import { View, Text, TextInput, StyleSheet, ViewStyle, StyleProp } from "react-native";
-// import { HandleSignUpFormDataChange } from "../../types/signup";
-// interface PhoneInputProps {
-// 	placeholder: string;
-// 	extendedStyle?: StyleProp<ViewStyle>;
-// 	handleFormDataChange?: HandleSignUpFormDataChange;
-// 	editable?: boolean;
-// }
-
-// const PhoneInput: React.FC<PhoneInputProps> = ({ placeholder, extendedStyle, handleFormDataChange, editable }) => {
-// 	const [error, setError] = useState("");
-// 	const handleTextChange = (text: string) => {
-// 		if (text.length >= 8) {
-// 			setError("");
-// 			handleFormDataChange?.("phone", text);
-// 			handleFormDataChange?.("phoneVerificationStatus", true);
-// 		} else {
-// 			setError("Please enter at least 8 digits");
-// 			handleFormDataChange?.("phone", text);
-// 			handleFormDataChange?.("phoneVerificationStatus", false);
-// 		}
-// 	};
-
-// 	return (
-// 		<View>
-// 			<View style={[styles.inputContainer, extendedStyle]}>
-// 				<Text style={styles.prefix}>+852</Text>
-// 				<View style={styles.horizontalLine} />
-// 				<TextInput
-// 					keyboardType="numeric"
-// 					onChangeText={handleTextChange}
-// 					placeholder={placeholder}
-// 					style={[styles.input]}
-// 					placeholderTextColor="#888888"
-// 					editable={editable}
-// 				/>
-// 			</View>
-// 			{error && <Text style={styles.errorMessage}>{error}</Text>}
-// 		</View>
-// 	);
-// };
-
-// const styles = StyleSheet.create({
-// 	inputContainer: {
-// 		maxWidth: "100%",
-// 		flexDirection: "row",
-// 		alignItems: "center",
-// 		justifyContent: "center",
-// 		borderWidth: 1,
-// 		borderColor: "#bbbbbb",
-// 		borderRadius: 12,
-// 		padding: 20,
-// 	},
-// 	prefix: {
-// 		marginRight: 5,
-// 		fontSize: 16,
-// 	},
-// 	horizontalLine: {
-// 		width: 24,
-// 		borderColor: "#bbbbbb",
-// 		borderWidth: 0.5,
-// 		transform: [{ rotate: "90deg" }],
-// 	},
-// 	input: {
-// 		flex: 1,
-// 		marginLeft: 5,
-// 		fontSize: 16,
-// 	},
-// 	errorMessage: {
-// 		fontSize: 14,
-// 		color: "#ff0033",
-// 		fontWeight: "400",
-// 		marginLeft: 10,
-// 		marginTop: 10,
-// 	},
-// });
-// export default PhoneInput;
-
-// import React, { useState } from "react";
-// import { View, Text, TextInput, StyleSheet, ViewStyle, StyleProp } from "react-native";
-// import { SignUpFormData } from "../../types/signUpFormData";
-
-// interface PhoneInputProps {
-// 	placeholder: string;
-// 	extendedStyle?: StyleProp<ViewStyle>;
-// 	editable?: boolean;
-// 	signUpFormData?: SignUpFormData;
-// 	setSignUpFormData?: (newFormData: Partial<SignUpFormData>) => void;
-// }
-
-// const PhoneInput: React.FC<PhoneInputProps> = ({
-// 	placeholder,
-// 	extendedStyle,
-// 	editable,
-// 	signUpFormData,
-// 	setSignUpFormData,
-// }) => {
-// 	const [error, setError] = useState("");
-
-// 	const handleTextChange = (text: string) => {
-// 		if (text.length >= 8) {
-// 			setError("");
-// 			setSignUpFormData({
-// 				...signUpFormData,
-// 				phone: text,
-// 				phoneVerificationStatus: true,
-// 			});
-// 		} else {
-// 			setError("Please enter at least 8 digits");
-// 			setSignUpFormData({
-// 				...signUpFormData,
-// 				phone: text,
-// 				phoneVerificationStatus: false,
-// 			});
-// 		}
-// 	};
-
-// 	return (
-// 		<View>
-// 			<View style={[styles.inputContainer, extendedStyle]}>
-// 				<Text style={styles.prefix}>+852</Text>
-// 				<View style={styles.horizontalLine} />
-// 				<TextInput
-// 					value={signUpFormData?.phone}
-// 					keyboardType="numeric"
-// 					onChangeText={handleTextChange}
-// 					placeholder={placeholder}
-// 					style={[styles.input]}
-// 					placeholderTextColor="#888888"
-// 					editable={editable}
-// 				/>
-// 			</View>
-// 			{error && <Text style={styles.errorMessage}>{error}</Text>}
-// 		</View>
-// 	);
-// };
-
-// const styles = StyleSheet.create({
-// 	inputContainer: {
-// 		maxWidth: "100%",
-// 		flexDirection: "row",
-// 		alignItems: "center",
-// 		justifyContent: "center",
-// 		borderWidth: 1,
-// 		borderColor: "#bbbbbb",
-// 		borderRadius: 12,
-// 		padding: 20,
-// 	},
-// 	prefix: {
-// 		marginRight: 5,
-// 		fontSize: 16,
-// 	},
-// 	horizontalLine: {
-// 		width: 24,
-// 		borderColor: "#bbbbbb",
-// 		borderWidth: 0.5,
-// 		transform: [{ rotate: "90deg" }],
-// 	},
-// 	input: {
-// 		flex: 1,
-// 		marginLeft: 5,
-// 		fontSize: 16,
-// 	},
-// 	errorMessage: {
-// 		fontSize: 14,
-// 		color: "#ff0033",
-// 		fontWeight: "400",
-// 		marginLeft: 10,
-// 		marginTop: 10,
-// 	},
-// });
-// export default PhoneInput;
-
 import React from "react";
-import { View, Text, TextInput, StyleSheet, ViewStyle, StyleProp } from "react-native";
+import { View, Text, TextInput, StyleSheet, ViewStyle, StyleProp, KeyboardTypeOptions, TextInputProps } from "react-native";
 
 interface PhoneInputProps {
 	value: string | undefined;
@@ -181,9 +7,13 @@ interface PhoneInputProps {
 	placeholder: string;
 	extendedStyle?: StyleProp<ViewStyle>;
 	editable?: boolean;
+    textContentType?: TextInputProps['textContentType']; 
+    autoComplete?: TextInputProps['autoComplete']
+    keyboardType?: KeyboardTypeOptions
+    autoCapitalize?: TextInputProps['autoCapitalize']
 }
 
-const PhoneInput: React.FC<PhoneInputProps> = ({ value, onChangeText, placeholder, extendedStyle, editable }) => {
+const PhoneInput: React.FC<PhoneInputProps> = ({ value, onChangeText, placeholder, extendedStyle, editable, keyboardType, textContentType, autoComplete, autoCapitalize }) => {
 	return (
 		<View>
 			<View style={[styles.inputContainer, extendedStyle]}>
@@ -192,11 +22,15 @@ const PhoneInput: React.FC<PhoneInputProps> = ({ value, onChangeText, placeholde
 				<TextInput
 					value={value}
 					onChangeText={onChangeText}
-					keyboardType="numeric"
+					keyboardType={keyboardType}
 					placeholder={placeholder}
 					style={[styles.input]}
 					placeholderTextColor="#888888"
-					editable={editable}
+					editable={editable}       
+                    textContentType={textContentType}
+                    autoComplete={autoComplete}
+                    autoCapitalize={autoCapitalize}
+             
 				/>
 			</View>
 		</View>

+ 44 - 13
component/registrationMultiStepForm/formComponent/formPages/loginPage.tsx

@@ -33,6 +33,7 @@ const LoginPage: React.FC<LoginPageProps> = ({ goToNextPage, goToForgetPassWordP
     const [loginPhone, setLoginPhone] = useState('');
     const [loginPassword, setLoginPassword] = useState('');
     const [saveAccount, setSaveAccount] = useState(false);
+    const [userTerms, setUserTerms] = useState(false);
     const [isLoading, setIsLoading] = useState(false);
     const { login } = useAuth();
     const [isChecked, setChecked] = useState(false);
@@ -52,6 +53,7 @@ const LoginPage: React.FC<LoginPageProps> = ({ goToNextPage, goToForgetPassWordP
                 setLoginPhone(savedPhone);
                 setLoginPassword(savedPassword);
                 setSaveAccount(true);
+                setUserTerms(true);
                 setChecked(true);
             }
         } catch (error) {
@@ -68,25 +70,32 @@ const LoginPage: React.FC<LoginPageProps> = ({ goToNextPage, goToForgetPassWordP
                 { text: '我已綁定,帶我回登入頁面', onPress: () => router.replace('/login') }
             ]);
         } else {
-            // const lowerCaseUsername = username.toLowerCase();
-            const isBinding = false;
-            const response = await login(username, password, isBinding);
+            if (userTerms) {
+                const isBinding = false;
+                const response = await login(username, password, isBinding);
 
-            if (response === 'login successful') {
-                if (saveAccount) {
-                    await AsyncStorage.setItem('savedPhone', username);
-                    await AsyncStorage.setItem('savedPassword', password);
+                if (response) {
+                    if (saveAccount) {
+                        await AsyncStorage.setItem('savedPhone', username);
+                        await AsyncStorage.setItem('savedPassword', password);
+                    } else {
+                        await AsyncStorage.removeItem('savedPhone');
+                        await AsyncStorage.removeItem('savedPassword');
+                    }
                 } else {
-                    await AsyncStorage.removeItem('savedPhone');
-                    await AsyncStorage.removeItem('savedPassword');
+                    Alert.alert('登入失敗', `原因: ${response}`);
                 }
             } else {
-                Alert.alert('登入失敗', `原因: ${response}`);
+                Alert.alert('請先同意用戶條款');
+
             }
+            
         }
         setIsLoading(false);
     };
-
+    const goToUserTermsPage = () => {
+        router.push('(public)/userTermsPage');
+    };
     const insets = useSafeAreaInsets();
     console.log(screenHeight);
     return (
@@ -165,11 +174,25 @@ const LoginPage: React.FC<LoginPageProps> = ({ goToNextPage, goToForgetPassWordP
                             color={saveAccount ? '#02677D' : '#02677D'}
                             onValueChange={(newValue) => {
                                 setSaveAccount(newValue);
-                                console.log(newValue);
                             }}
                         />
 
                         <Text style={styles.text}>記住我的電話號碼</Text>
+                        
+                    </View>
+                    <View className="flex flex-row items-center">
+                        <Checkbox
+                            style={styles.checkbox}
+                            value={userTerms}
+                            color={userTerms ? '#02677D' : '#02677D'}
+                            onValueChange={(newValue) => {
+                                setUserTerms(newValue);
+                            }}
+                        />
+
+                        <Text style={styles.text}>登入即同意
+                            <Text style={styles.userTerms} onPress={goToUserTermsPage}>用戶條款</Text>
+                        </Text>
                     </View>
 
                     <NormalButton
@@ -223,12 +246,20 @@ const styles = StyleSheet.create({
     },
     topContainerForLogo: {},
     checkbox: {
-        margin: 8
+        marginLeft: 8,
+        marginRight: 8
     },
     text: {
         color: '#02677D',
         fontSize: 16,
         paddingVertical: 5
+    },
+    userTerms: {
+        color: '#02677D',
+        fontSize: 16,
+        paddingVertical: 5,
+        textDecorationLine: 'underline'
+
     }
 });
 export default LoginPage;

+ 109 - 137
package-lock.json

@@ -42,6 +42,7 @@
         "nativewind": "^4.2.1",
         "prettier-plugin-tailwindcss": "^0.6.14",
         "react": "19.1.0",
+        "react-dom": "19.1.0",
         "react-native": "0.81.4",
         "react-native-element-dropdown": "^2.12.4",
         "react-native-gesture-handler": "~2.28.0",
@@ -50,7 +51,7 @@
         "react-native-modal": "14.0.0-rc.1",
         "react-native-modern-datepicker": "^1.0.0-beta.91",
         "react-native-pager-view": "^6.9.1",
-        "react-native-reanimated": "~4.1.0",
+        "react-native-reanimated": "~4.1.2",
         "react-native-responsive-screen": "^1.4.2",
         "react-native-safe-area-context": "5.6.0",
         "react-native-screens": "~4.16.0",
@@ -1919,9 +1920,9 @@
       }
     },
     "node_modules/@expo/mcp-tunnel": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/@expo/mcp-tunnel/-/mcp-tunnel-0.0.7.tgz",
-      "integrity": "sha512-ht8Q1nKtiHobZqkUqt/7awwjW2D59ardP6XDVmGceGjQtoZELVaJDHyMIX+aVG9SZ9aj8+uGlhQYeBi57SZPMA==",
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/@expo/mcp-tunnel/-/mcp-tunnel-0.0.8.tgz",
+      "integrity": "sha512-6261obzt6h9TQb6clET7Fw4Ig4AY2hfTNKI3gBt0gcTNxZipwMg8wER7ssDYieA9feD/FfPTuCPYFcR280aaWA==",
       "license": "MIT",
       "dependencies": {
         "ws": "^8.18.3",
@@ -1979,9 +1980,9 @@
       }
     },
     "node_modules/@expo/metro-config": {
-      "version": "54.0.4",
-      "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-54.0.4.tgz",
-      "integrity": "sha512-syzvZGFGrOSQOWjpo+lHHwMV8XOLK5Ev/E+e0Or3fJvsAi4o7h62qbbPuAicrfFUPxlAm7XBvkWmAwPr2jIAYA==",
+      "version": "54.0.5",
+      "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-54.0.5.tgz",
+      "integrity": "sha512-Y+oYtLg8b3L4dHFImfu8+yqO+KOcBpLLjxN7wGbs7miP/BjntBQ6tKbPxyKxHz5UUa1s+buBzZlZhsFo9uqKMg==",
       "license": "MIT",
       "dependencies": {
         "@babel/code-frame": "^7.20.0",
@@ -2154,9 +2155,9 @@
       "license": "MIT"
     },
     "node_modules/@expo/server": {
-      "version": "0.7.4",
-      "resolved": "https://registry.npmjs.org/@expo/server/-/server-0.7.4.tgz",
-      "integrity": "sha512-8bfRzL7h1Qgrmf3auR71sPAcAuxnmNkRJs+8enL8vZi2+hihevLhrayDu7P0A/XGEq7wySAGvBBFfIB00Et/AA==",
+      "version": "0.7.5",
+      "resolved": "https://registry.npmjs.org/@expo/server/-/server-0.7.5.tgz",
+      "integrity": "sha512-aNVcerBSJEcUspvXRWChEgFhix1gTNIcgFDevaU/A1+TkfbejNIjGX4rfLEpfyRzzdLIRuOkBNjD+uTYMzohyg==",
       "license": "MIT",
       "dependencies": {
         "abort-controller": "^3.0.0",
@@ -3056,6 +3057,36 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-tabs": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz",
+      "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.3",
+        "@radix-ui/react-context": "1.1.2",
+        "@radix-ui/react-direction": "1.1.1",
+        "@radix-ui/react-id": "1.1.1",
+        "@radix-ui/react-presence": "1.1.5",
+        "@radix-ui/react-primitive": "2.1.3",
+        "@radix-ui/react-roving-focus": "1.1.11",
+        "@radix-ui/react-use-controllable-state": "1.2.2"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-use-callback-ref": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
@@ -3533,9 +3564,9 @@
       }
     },
     "node_modules/@tanstack/query-core": {
-      "version": "5.89.0",
-      "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.89.0.tgz",
-      "integrity": "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==",
+      "version": "5.90.2",
+      "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.2.tgz",
+      "integrity": "sha512-k/TcR3YalnzibscALLwxeiLUub6jN5EDLwKDiO7q5f4ICEoptJ+n9+7vcEFy5/x/i6Q+Lb/tXrsKCggf5uQJXQ==",
       "license": "MIT",
       "funding": {
         "type": "github",
@@ -3543,12 +3574,12 @@
       }
     },
     "node_modules/@tanstack/react-query": {
-      "version": "5.89.0",
-      "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz",
-      "integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==",
+      "version": "5.90.2",
+      "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.2.tgz",
+      "integrity": "sha512-CLABiR+h5PYfOWr/z+vWFt5VsOA2ekQeRQBFSKlcoW6Ndx/f8rfyVmq4LbgOM4GG2qtxAxjLYLOpCNTYm4uKzw==",
       "license": "MIT",
       "dependencies": {
-        "@tanstack/query-core": "5.89.0"
+        "@tanstack/query-core": "5.90.2"
       },
       "funding": {
         "type": "github",
@@ -4141,9 +4172,9 @@
       }
     },
     "node_modules/babel-preset-expo": {
-      "version": "54.0.2",
-      "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-54.0.2.tgz",
-      "integrity": "sha512-wIlweUhun2+soWQf8slGrURU8ZZYrIqPGuvsvTpm03YE8aCZF9YZe1WvsMJCAlywIhQQ+970wSKzLncfPqK2hQ==",
+      "version": "54.0.3",
+      "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-54.0.3.tgz",
+      "integrity": "sha512-zC6g96Mbf1bofnCI8yI0VKAp8/ER/gpfTsWOpQvStbHU+E4jFZ294n3unW8Hf6nNP4NoeNq9Zc6Prp0vwhxbow==",
       "license": "MIT",
       "dependencies": {
         "@babel/helper-module-imports": "^7.25.9",
@@ -4521,9 +4552,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001743",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
-      "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
+      "version": "1.0.30001745",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001745.tgz",
+      "integrity": "sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ==",
       "funding": [
         {
           "type": "opencollective",
@@ -5177,9 +5208,9 @@
       }
     },
     "node_modules/detect-libc": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz",
-      "integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.1.tgz",
+      "integrity": "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==",
       "license": "Apache-2.0",
       "engines": {
         "node": ">=8"
@@ -5324,9 +5355,9 @@
       "license": "MIT"
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.5.222",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz",
-      "integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==",
+      "version": "1.5.223",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.223.tgz",
+      "integrity": "sha512-qKm55ic6nbEmagFlTFczML33rF90aU+WtrJ9MdTCThrcvDNdUHN4p6QfVN78U06ZmguqXIyMPyYhw2TrbDUwPQ==",
       "license": "ISC"
     },
     "node_modules/emoji-regex": {
@@ -5493,29 +5524,29 @@
       "license": "MIT"
     },
     "node_modules/expo": {
-      "version": "54.0.9",
-      "resolved": "https://registry.npmjs.org/expo/-/expo-54.0.9.tgz",
-      "integrity": "sha512-hCWkBkftiSSoKCV83CKm5oaA613arl9311mjXCDb7Fn/9FzQWh1koL4Q3nflnYiiCRhFQnecbDOa6YxN+GKVEQ==",
+      "version": "54.0.10",
+      "resolved": "https://registry.npmjs.org/expo/-/expo-54.0.10.tgz",
+      "integrity": "sha512-49+IginEoKC+g125ZlRvUYNl9jKjjHcDiDnQvejNWlMQ0LtcFIWiFad/PLjmi7YqF/0rj9u3FNxqM6jNP16O0w==",
       "license": "MIT",
       "dependencies": {
         "@babel/runtime": "^7.20.0",
-        "@expo/cli": "54.0.7",
+        "@expo/cli": "54.0.8",
         "@expo/config": "~12.0.9",
         "@expo/config-plugins": "~54.0.1",
         "@expo/devtools": "0.1.7",
         "@expo/fingerprint": "0.15.1",
         "@expo/metro": "~54.0.0",
-        "@expo/metro-config": "54.0.4",
+        "@expo/metro-config": "54.0.5",
         "@expo/vector-icons": "^15.0.2",
         "@ungap/structured-clone": "^1.3.0",
-        "babel-preset-expo": "~54.0.2",
+        "babel-preset-expo": "~54.0.3",
         "expo-asset": "~12.0.9",
         "expo-constants": "~18.0.9",
-        "expo-file-system": "~19.0.14",
+        "expo-file-system": "~19.0.15",
         "expo-font": "~14.0.8",
         "expo-keep-awake": "~15.0.7",
-        "expo-modules-autolinking": "3.0.12",
-        "expo-modules-core": "3.0.17",
+        "expo-modules-autolinking": "3.0.13",
+        "expo-modules-core": "3.0.18",
         "pretty-format": "^29.7.0",
         "react-refresh": "^0.14.2",
         "whatwg-url-without-unicode": "8.0.0-3"
@@ -5710,9 +5741,9 @@
       }
     },
     "node_modules/expo-file-system": {
-      "version": "19.0.14",
-      "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.14.tgz",
-      "integrity": "sha512-0CA7O5IYhab11TlxQlJAx0Xm9pdkk/zEHNiW+Hh/T4atWi9U/J38CIp7iNYSrBvy9dC3rJbze5D1ANcKKr4mSQ==",
+      "version": "19.0.15",
+      "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.15.tgz",
+      "integrity": "sha512-sRLW+3PVJDiuoCE2LuteHhC7OxPjh1cfqLylf1YG1TDEbbQXnzwjfsKeRm6dslEPZLkMWfSLYIrVbnuq5mF7kQ==",
       "license": "MIT",
       "peerDependencies": {
         "expo": "*",
@@ -5807,9 +5838,9 @@
       }
     },
     "node_modules/expo-modules-autolinking": {
-      "version": "3.0.12",
-      "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.12.tgz",
-      "integrity": "sha512-vZijQgdtmhAhL8H3C0gEjWC0gGBVPVQdVZM92Zqcu2vXjRNDSqIxYXRTS3UT0nZzFltdqmeZAGxvWspxQLYtOQ==",
+      "version": "3.0.13",
+      "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.13.tgz",
+      "integrity": "sha512-58WnM15ESTyT2v93Rba7jplXtGvh5cFbxqUCi2uTSpBf3nndDRItLzBQaoWBzAvNUhpC2j1bye7Dn/E+GJFXmw==",
       "license": "MIT",
       "dependencies": {
         "@expo/spawn-async": "^1.7.2",
@@ -5844,9 +5875,9 @@
       }
     },
     "node_modules/expo-modules-core": {
-      "version": "3.0.17",
-      "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.17.tgz",
-      "integrity": "sha512-P1jZn8yjWi4jSCH+r9A1NykLR+0JtFYprJgYwnZ1EVFRtw+DoMjir0OexM9ehCuBg8sKDCbzCUAgm/JFnpjQww==",
+      "version": "3.0.18",
+      "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.18.tgz",
+      "integrity": "sha512-9JPnjlXEFaq/uACZ7I4wb/RkgPYCEsfG75UKMvfl7P7rkymtpRGYj8/gTL2KId8Xt1fpmIPOF57U8tKamjtjXg==",
       "license": "MIT",
       "dependencies": {
         "invariant": "^2.2.4"
@@ -5877,14 +5908,14 @@
       }
     },
     "node_modules/expo-router": {
-      "version": "6.0.7",
-      "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.7.tgz",
-      "integrity": "sha512-dP/35aQadCuplEP99CZ0sLrVpnCFCQGnCBtFlI0Tph75PbepdWhI7XC0Vzt7MoNBLF9NW80q5CeZdXTvybc+4w==",
+      "version": "6.0.8",
+      "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.8.tgz",
+      "integrity": "sha512-cx6vFvBrfPNHpNbN2ij2mF5JKE4JXyq+dJVmWNqt7JplA0aohOOKXS/KQ9vQy88HpnrcJMuYqUNHp44aWyce7g==",
       "license": "MIT",
       "dependencies": {
         "@expo/metro-runtime": "^6.1.2",
         "@expo/schema-utils": "^0.1.7",
-        "@expo/server": "^0.7.4",
+        "@expo/server": "^0.7.5",
         "@radix-ui/react-slot": "1.2.0",
         "@radix-ui/react-tabs": "^1.1.12",
         "@react-navigation/bottom-tabs": "^7.4.0",
@@ -5947,36 +5978,6 @@
         }
       }
     },
-    "node_modules/expo-router/node_modules/@radix-ui/react-tabs": {
-      "version": "1.1.13",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz",
-      "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==",
-      "license": "MIT",
-      "dependencies": {
-        "@radix-ui/primitive": "1.1.3",
-        "@radix-ui/react-context": "1.1.2",
-        "@radix-ui/react-direction": "1.1.1",
-        "@radix-ui/react-id": "1.1.1",
-        "@radix-ui/react-presence": "1.1.5",
-        "@radix-ui/react-primitive": "2.1.3",
-        "@radix-ui/react-roving-focus": "1.1.11",
-        "@radix-ui/react-use-controllable-state": "1.2.2"
-      },
-      "peerDependencies": {
-        "@types/react": "*",
-        "@types/react-dom": "*",
-        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
-        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        },
-        "@types/react-dom": {
-          "optional": true
-        }
-      }
-    },
     "node_modules/expo-router/node_modules/semver": {
       "version": "7.6.3",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
@@ -6083,9 +6084,9 @@
       }
     },
     "node_modules/expo/node_modules/@expo/cli": {
-      "version": "54.0.7",
-      "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.7.tgz",
-      "integrity": "sha512-vpZDbIhN2eyb5u2o2iIL2Glu9+9eIY8U30wqeIxh0BUHLoMxFejvEBfS+90A0PtEHoQ1Zi9QxusK5UuyoEvweg==",
+      "version": "54.0.8",
+      "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.8.tgz",
+      "integrity": "sha512-bRJXvtjgxpyElmJuKLotWyIW5j9a2K3rGUjd2A8LRcFimrZp0wwuKPQjlUK0sFNbU7zHWfxubNq/B+UkUNkCxw==",
       "license": "MIT",
       "dependencies": {
         "@0no-co/graphql.web": "^1.0.8",
@@ -6098,13 +6099,13 @@
         "@expo/json-file": "^10.0.7",
         "@expo/mcp-tunnel": "~0.0.7",
         "@expo/metro": "~54.0.0",
-        "@expo/metro-config": "~54.0.4",
+        "@expo/metro-config": "~54.0.5",
         "@expo/osascript": "^2.3.7",
         "@expo/package-manager": "^1.9.8",
         "@expo/plist": "^0.4.7",
         "@expo/prebuild-config": "^54.0.3",
         "@expo/schema-utils": "^0.1.7",
-        "@expo/server": "^0.7.4",
+        "@expo/server": "^0.7.5",
         "@expo/spawn-async": "^1.7.2",
         "@expo/ws-tunnel": "^1.0.1",
         "@expo/xcpretty": "^4.3.0",
@@ -8417,9 +8418,9 @@
       }
     },
     "node_modules/minizlib": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
-      "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+      "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
       "license": "MIT",
       "dependencies": {
         "minipass": "^7.1.2"
@@ -9663,16 +9664,15 @@
       }
     },
     "node_modules/react-dom": {
-      "version": "19.1.1",
-      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
-      "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
+      "version": "19.1.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+      "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "scheduler": "^0.26.0"
       },
       "peerDependencies": {
-        "react": "^19.1.1"
+        "react": "^19.1.0"
       }
     },
     "node_modules/react-fast-compare": {
@@ -10170,9 +10170,9 @@
       }
     },
     "node_modules/react-native-reanimated": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.0.tgz",
-      "integrity": "sha512-L8FqZn8VjZyBaCUMYFyx1Y+T+ZTbblaudpxReOXJ66RnOf52g6UM4Pa/IjwLD1XAw1FUxLRQrtpdjbkEc74FiQ==",
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.2.tgz",
+      "integrity": "sha512-qzmQiFrvjm62pRBcj97QI9Xckc3EjgHQoY1F2yjktd0kpjhoyePeuTEXjYRCAVIy7IV/1cfeSup34+zFThFoHQ==",
       "license": "MIT",
       "dependencies": {
         "react-native-is-edge-to-edge": "^1.2.1",
@@ -10486,15 +10486,15 @@
       "license": "MIT"
     },
     "node_modules/regexpu-core": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.3.1.tgz",
-      "integrity": "sha512-DzcswPr252wEr7Qz8AyAVbfyBDKLoYp6eRA1We2Fa9qirRFSdtkP5sHr3yglDKy2BbA0fd2T+j/CUSKes3FeVQ==",
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz",
+      "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==",
       "license": "MIT",
       "dependencies": {
         "regenerate": "^1.4.2",
         "regenerate-unicode-properties": "^10.2.2",
         "regjsgen": "^0.8.0",
-        "regjsparser": "^0.12.0",
+        "regjsparser": "^0.13.0",
         "unicode-match-property-ecmascript": "^2.0.0",
         "unicode-match-property-value-ecmascript": "^2.2.1"
       },
@@ -10509,29 +10509,17 @@
       "license": "MIT"
     },
     "node_modules/regjsparser": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz",
-      "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
+      "version": "0.13.0",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz",
+      "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==",
       "license": "BSD-2-Clause",
       "dependencies": {
-        "jsesc": "~3.0.2"
+        "jsesc": "~3.1.0"
       },
       "bin": {
         "regjsparser": "bin/parser"
       }
     },
-    "node_modules/regjsparser/node_modules/jsesc": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
-      "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
-      "license": "MIT",
-      "bin": {
-        "jsesc": "bin/jsesc"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/repeat-string": {
       "version": "1.6.1",
       "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
@@ -11312,37 +11300,21 @@
       }
     },
     "node_modules/tar": {
-      "version": "7.4.3",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
-      "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+      "version": "7.5.1",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz",
+      "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==",
       "license": "ISC",
       "dependencies": {
         "@isaacs/fs-minipass": "^4.0.0",
         "chownr": "^3.0.0",
         "minipass": "^7.1.2",
-        "minizlib": "^3.0.1",
-        "mkdirp": "^3.0.1",
+        "minizlib": "^3.1.0",
         "yallist": "^5.0.0"
       },
       "engines": {
         "node": ">=18"
       }
     },
-    "node_modules/tar/node_modules/mkdirp": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
-      "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
-      "license": "MIT",
-      "bin": {
-        "mkdirp": "dist/cjs/src/bin.js"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
     "node_modules/tar/node_modules/yallist": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",

+ 1 - 1
package.json

@@ -53,7 +53,7 @@
     "react-native-modal": "14.0.0-rc.1",
     "react-native-modern-datepicker": "^1.0.0-beta.91",
     "react-native-pager-view": "^6.9.1",
-    "react-native-reanimated": "~4.1.0",
+    "react-native-reanimated": "~4.1.2",
     "react-native-responsive-screen": "^1.4.2",
     "react-native-safe-area-context": "5.6.0",
     "react-native-screens": "~4.16.0",