فهرست منبع

-remove nmotification stuff

Ian Fung 1 سال پیش
والد
کامیت
bbff2f0229
4فایلهای تغییر یافته به همراه143 افزوده شده و 492 حذف شده
  1. 3 5
      app/_layout.tsx
  2. 0 345
      app/hello.html
  3. 76 76
      app/hooks/usePushNotifications.ts
  4. 64 66
      package.json

+ 3 - 5
app/_layout.tsx

@@ -1,20 +1,18 @@
 import { Stack } from 'expo-router/stack';
 import AuthProvider, { useAuth } from '../context/AuthProvider';
 import { EXPO_PUBLIC_NODE_ENV } from '@env';
-import * as SecureStore from 'expo-secure-store';
 import { GestureHandlerRootView } from 'react-native-gesture-handler';
 import { useEffect, useState } from 'react';
-import { ActivityIndicator, View } from 'react-native';
 import { checkVersion } from '../component/checkVersion';
 import { authenticationService } from '../service/authService';
-import { usePushNotifications } from './hooks/usePushNotifications';
+// import { usePushNotifications } from './hooks/usePushNotifications';
 
 export default function RootLayout() {
     const [isLoading, setIsLoading] = useState(true);
     const { user } = useAuth();
-    const { expoPushToken, notification } = usePushNotifications();
+    // const { expoPushToken, notification } = usePushNotifications();
 
-    const data = JSON.stringify(notification, undefined, 2);
+    // const data = JSON.stringify(notification, undefined, 2);
 
     useEffect(() => {
         const fetchVersion = async () => {

+ 0 - 345
app/hello.html

@@ -1,345 +0,0 @@
-import { CameraView, useCameraPermissions } from 'expo-camera';
-import { useEffect, useRef, useState } from 'react';
-import {
-ActivityIndicator,
-Alert,
-Dimensions,
-Pressable,
-ScrollView,
-StyleSheet,
-Text,
-Vibration,
-View
-} from 'react-native';
-import ChooseCarForChargingRow from '../../../../component/global/chooseCarForChargingRow';
-import { CrossLogoWhiteSvg, QuestionSvg } from '../../../../component/global/SVG';
-import { router } from 'expo-router';
-import { chargeStationService } from '../../../../service/chargeStationService';
-import { authenticationService } from '../../../../service/authService';
-import { walletService } from '../../../../service/walletService';
-import useUserInfoStore from '../../../../providers/userinfo_store';
-const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
-
-const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
-const isLargeScreen = screenHeight >= 800;
-const defaultImageUrl = require('../../../../assets/car1.png');
-
-return (
-<View style={{ ...(isLargeScreen ? { marginTop: '10%' , marginBottom: '12%' , paddingBottom: 12 } : { flex: 1,
-    alignItems: 'center' , justifyContent: 'center' }) }}>
-    <View className="justify-center items-center flex-1 ">
-        <View style={{ ...(isLargeScreen ? {} : { backgroundColor: 'rgba(0,0,0,0.7)' }) }}>
-            {loading ? (
-            <View className="w-full">
-                <ActivityIndicator color="#34657b" />
-            </View>
-            ) : (
-            <View className="w-screen  bg-[#000000B3]">
-                <View className="flex-row items-center justify-between mx-[5%] ">
-                    <Pressable className="pt-4 " onPress={()=> {
-                        if (router.canGoBack()) {
-                        router.back();
-                        } else {
-                        router.replace('mainPage');
-                        }
-                        }}
-                        >
-                        <CrossLogoWhiteSvg />
-                    </Pressable>
-
-                    <Text className="text-base text-white pt-2">選擇充電車輛</Text>
-                    <Text className="text-xl text-white pt-2"></Text>
-                </View>
-
-                <ScrollView horizontal={true} showsHorizontalScrollIndicator={false} contentContainerStyle={{
-                    alignItems: 'center' , flexDirection: 'row' , marginVertical: 12 }} className="space-x-2 mx-[5%]">
-                    {carData.map((car, index) => (
-                    <ChooseCarForChargingRow key={`${car.name}+${index}`} image={car.image} onPress={()=> {
-                        setSelectedCar(car.id);
-                        console.log(car.id);
-                        }}
-                        isSelected={selectedCar === car.id}
-                        // imageUrl={image}
-                        VehicleName={car.name}
-                        isDefault={car.isDefault}
-                        />
-                        ))}
-                </ScrollView>
-            </View>
-            )}
-        </View>
-    </View>
-</View>
-);
-};
-
-//reminder: scan qr code page, ic call should be false
-const ScanQrPage = () => {
-const { userID, setUserID } = useUserInfoStore();
-// State declarations
-const [permission, requestPermission] = useCameraPermissions();
-const [scanned, setScanned] = useState(false);
-const viewRef = useRef(null);
-const [scannedResult, setScannedResult] = useState('');
-const [selectedCar, setSelectedCar] = useState('');
-
-const now = new Date();
-const [loading, setLoading] = useState(true);
-const [loading2, setLoading2] = useState(false);
-const [loading3, setLoading3] = useState(false);
-const [carData, setCarData] = useState([]);
-
-// Effect for requesting camera permissions
-useEffect(() => {
-(async () => {
-const { status } = await requestPermission();
-if (status !== 'granted') {
-alert(
-'我們需要相機權限來掃描機器上的二維碼,以便識別並啟動充電機器。我們不會儲存或共享任何掃描到的資訊。 請前往設定開啟相機權限'
-);
-}
-})();
-}, []);
-
-// Effect for fetching user's cars
-useEffect(() => {
-const fetchAllCars = async () => {
-try {
-const response = await chargeStationService.getUserCars();
-if (response) {
-// console.log(response.data);
-const carTypes = response.data.map((item: any) => ({
-id: item.id,
-name: item.car_type.name,
-image: item.car_type.type_image_url
-}));
-console.log('carTypes', carTypes);
-// console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', carTypes);
-let updatedCarTypes = [...carTypes];
-for (let i = 0; i
-< carTypes.length; i++) { const car=updatedCarTypes[i]; const imageUrl=await
-    chargeStationService.getProcessedImageUrl(car.image); updatedCarTypes[i]={ ...car, image: imageUrl }; }
-    setCarData(updatedCarTypes); console.log('updatedCarTypes', updatedCarTypes); return true; } } catch (error) {
-    console.log(error); } finally { setLoading(false); } }; fetchAllCars(); }, []); if (!permission) { return <View />;
-}
-
-if (!permission.granted) {
-return (
-<View className="flex-1 justify-center items-center">
-    <Text style={{ textAlign: 'center' }}>
-        我們需要相機權限來掃描機器上的二維碼,以便識別並啟動充電機器。我們不會儲存或共享任何掃描到的資訊。
-        請前往設定開啟相機權限
-    </Text>
-</View>
-);
-}
-
-// Function to handle barcode scanning
-const handleBarCodeScanned = async ({ bounds, data, type }: { bounds: any; data: any; type: any }) => {
-const { origin, size } = bounds;
-// Calculate the size of the square transparent area
-const transparentAreaSize = Math.min(screenWidth * 0.6, screenHeight * 0.3);
-const transparentAreaX = (screenWidth - transparentAreaSize) / 2;
-const transparentAreaY = (screenHeight - transparentAreaSize) / 2;
-
-// Check if the barcode is within the transparent area
-if (
-origin.x >= transparentAreaX &&
-origin.y >= transparentAreaY &&
-origin.x + size.width <= transparentAreaX + transparentAreaSize && origin.y + size.height <=transparentAreaY +
-    transparentAreaSize ) { setScanned(true); setScannedResult(data); Vibration.vibrate(100); console.log(` type:
-    ${type} data: ${data} typeofData ${typeof data}`); try { const response=await
-    chargeStationService.getTodayReservation(); if (response) { const now=new Date(); const
-    onlyThisConnector=response.filter( (reservation: any)=> reservation.connector.ConnectorID === data
-    );
-
-    onlyThisConnector.sort((a: any, b: any) => {
-    const timeA = new Date(a.book_time).getTime();
-    const timeB = new Date(b.book_time).getTime();
-    return timeA - timeB;
-    });
-
-    let previousReservation = null;
-    let upcomingReservation = null;
-
-    for (let i = 0; i < onlyThisConnector.length; i++) { const reservationTime=new
-        Date(onlyThisConnector[i].book_time).getTime(); if (reservationTime <=now.getTime()) {
-        previousReservation=onlyThisConnector[i]; } else { upcomingReservation=onlyThisConnector[i]; break; } } const
-        relevantReservations=[previousReservation || null, upcomingReservation || null]; console.log('Relevant
-        reservations:', relevantReservations); const getNearestSlot=(date: Date)=> {
-        const minutes = date.getMinutes();
-        const nearestSlot = new Date(date);
-        nearestSlot.setMinutes(minutes < 30 ? 0 : 30); nearestSlot.setSeconds(0); nearestSlot.setMilliseconds(0); return
-            nearestSlot; }; const currentSlot=getNearestSlot(now); const nextSlot=new Date(currentSlot.getTime() + 30 *
-            60 * 1000); const AreOrdersAdjacentToNow=relevantReservations.map((reservation, index)=> {
-            if (!reservation) return false;
-
-            const reservationTime = new Date(reservation.book_time);
-            return index === 0
-            ? reservationTime.getTime() === currentSlot.getTime()
-            : reservationTime.getTime() === nextSlot.getTime();
-            });
-
-            console.log('AreOrdersAdjacentToNow:', AreOrdersAdjacentToNow);
-
-            if (!AreOrdersAdjacentToNow[0] && !AreOrdersAdjacentToNow[1]) {
-            console.log('Charging machine is available. Starting charging process...');
-            startCharging(data);
-            } else if (AreOrdersAdjacentToNow[0]) {
-            const previousReservation = relevantReservations[0];
-            if (previousReservation && previousReservation.user.id === userID) {
-            const reservationTime = new Date(previousReservation.book_time);
-            const timeDifference = now.getTime() - reservationTime.getTime();
-            const minutesDifference = timeDifference / (1000 * 60);
-
-            if (minutesDifference <= 15) { console.log('User arrived within 15 minutes of their reservation.');
-                startCharging(data); } else { console.log('User arrived more than 15 minutes late for their
-                reservation.'); if (!AreOrdersAdjacentToNow[1]) { console.log('Next slot is available. Allowing charging
-                despite late arrival.'); startCharging(data); } else { Alert.alert( '預約已過期'
-                , '您的預約時間已經過期,且下一個時段已被預約。請重新預約。' ); console.log('Next slot is not available. Charging not allowed.'); }
-                } } else { Alert.alert('無法使用', '此充電槍已經被預約,請選擇其他位置' ); } } else if (AreOrdersAdjacentToNow[1]) { const
-                upcomingReservation=relevantReservations[1]; if (upcomingReservation &&
-                upcomingReservation.user.id===userID) { const minutesUntilReservation=(new
-                Date(upcomingReservation.book_time).getTime() - now.getTime()) / (1000 * 60); if
-                (minutesUntilReservation <=5) { console.log('User arrived slightly early for their upcoming
-                reservation.'); startCharging(data); } else { Alert.alert( '預約時間未到' , `您的預約時間還有
-                ${Math.round(minutesUntilReservation)} 分鐘開始。請稍後再試。` ); } } else {
-                Alert.alert('已被預約', '此充電槍已被其他用戶預約。請選擇其他位置。' ); } } else { Alert.alert('無法使用', '此充電槍目前無法使用。請選擇其他位置或稍後再試。'
-                ); } } else { console.log('No response from getTodayReservation'); Alert.alert('系統錯誤', '無法獲取預約信息。請稍後再試。'
-                ); } } catch (error) { console.error("Error fetching today's reservations:", error);
-                Alert.alert('系統錯誤', '發生未知錯誤。請稍後再試。' ); } setTimeout(()=> {
-                setScanned(false);
-                }, 2000);
-                }
-                };
-
-                //prepare data for submission
-                const dataForSubmission = {
-                stationID: '2405311022116801000',
-                connector: scannedResult,
-                user: userID,
-                book_time: now,
-                end_time: now,
-                total_power: 0,
-                total_fee: 0,
-                promotion_code: '',
-                car: selectedCar,
-                type: 'walking',
-                is_ic_call: false
-                };
-
-                const startCharging = async (scanResult: string) => {
-                try {
-                if (selectedCar === '') {
-                Alert.alert('請選擇車輛');
-                return;
-                }
-
-                const response = await walletService.submitPayment(
-                dataForSubmission.stationID,
-                scanResult,
-                dataForSubmission.user,
-                dataForSubmission.book_time,
-                dataForSubmission.end_time,
-                dataForSubmission.total_power,
-                dataForSubmission.total_fee,
-                dataForSubmission.promotion_code,
-                dataForSubmission.car,
-                dataForSubmission.type,
-                dataForSubmission.is_ic_call
-                );
-
-                if (response) {
-                console.log('Charging started from startCharging', response);
-                router.push('(auth)/(tabs)/(charging)/chargingPage');
-                } else {
-                console.log('Failed to start chargi12312312ng:', response);
-                Alert.alert('掃描失敗 請稍後再試。', response);
-                }
-                } catch (error) {
-                console.log('Failed to start charging:', error);
-                }
-                };
-
-                return (
-                <View style={styles.container} ref={viewRef}>
-                    {loading ? (
-                    <View className="flex-1 items-center justify-center">
-                        <ActivityIndicator />
-                    </View>
-                    ) : (
-                    <CameraView style={styles.camera} facing="back" barcodeScannerSettings={{ barcodeTypes: ['qr'] }}
-                        onBarcodeScanned={scanned ? undefined : handleBarCodeScanned}
-                        responsiveOrientationWhenOrientationLocked={true}>
-                        <View style={styles.overlay}>
-                            <View style={styles.topOverlay}>
-                                <ChooseCar carData={carData} loading={loading} selectedCar={selectedCar}
-                                    setSelectedCar={setSelectedCar} />
-                            </View>
-                            <View style={styles.centerRow}>
-                                <View style={styles.leftOverlay}></View>
-                                <View style={styles.transparentArea}></View>
-                                <View style={styles.rightOverlay} />
-                            </View>
-                            <View className="items-center justify-between" style={styles.bottomOverlay}>
-                                <View>
-                                    <Text className="text-white text-lg font-bold mt-2 text-center">
-                                        請選擇充電車輛{'\n'}及掃瞄充電座上的二維碼
-                                    </Text>
-                                </View>
-                                <View className="flex-row space-x-2 items-center ">
-                                    <QuestionSvg />
-
-                                    <Pressable onPress={()=> router.push('assistancePage')}>
-                                        <Text className="text-white text-base">需要協助?</Text>
-                                    </Pressable>
-                                </View>
-                                <View />
-                            </View>
-                        </View>
-                    </CameraView>
-                    )}
-                </View>
-                );
-                };
-
-                const styles = StyleSheet.create({
-                container: {
-                flex: 1
-                },
-                camera: {
-                flex: 1
-                },
-                overlay: {
-                flex: 1
-                },
-                topOverlay: {
-                flex: 35,
-                alignItems: 'center',
-                backgroundColor: 'rgba(0,0,0,0.5)'
-                },
-                centerRow: {
-                flex: 30,
-                flexDirection: 'row'
-                },
-                leftOverlay: {
-                flex: 20,
-                backgroundColor: 'rgba(0,0,0,0.5)'
-                },
-                transparentArea: {
-                flex: 60,
-                aspectRatio: 1,
-                position: 'relative'
-                },
-
-                rightOverlay: {
-                flex: 20,
-                backgroundColor: 'rgba(0,0,0,0.5)'
-                },
-                bottomOverlay: {
-                flex: 35,
-                backgroundColor: 'rgba(0,0,0,0.5)'
-                }
-                });
-
-                export default ScanQrPage;

+ 76 - 76
app/hooks/usePushNotifications.ts

@@ -1,88 +1,88 @@
-import { useEffect, useState, useRef } from 'react';
-import * as Notifications from 'expo-notifications';
-import * as Device from 'expo-device';
-import Constants from 'expo-constants';
-import { Platform } from 'react-native';
+// import { useEffect, useState, useRef } from 'react';
+// import * as Notifications from 'expo-notifications';
+// import * as Device from 'expo-device';
+// import Constants from 'expo-constants';
+// import { Platform } from 'react-native';
 
-export interface PushNotificationState {
-    notification?: Notifications.Notification;
-    expoPushToken?: Notifications.ExpoPushToken;
-}
+// export interface PushNotificationState {
+//     notification?: Notifications.Notification;
+//     expoPushToken?: Notifications.ExpoPushToken;
+// }
 
-export const usePushNotifications = (): PushNotificationState => {
-    const [expoPushToken, setExpoPushToken] = useState<Notifications.ExpoPushToken | undefined>();
-    const [notification, setNotification] = useState<Notifications.Notification | undefined>();
+// export const usePushNotifications = (): PushNotificationState => {
+//     const [expoPushToken, setExpoPushToken] = useState<Notifications.ExpoPushToken | undefined>();
+//     const [notification, setNotification] = useState<Notifications.Notification | undefined>();
 
-    const notificationListener = useRef<Notifications.Subscription>();
-    const responseListener = useRef<Notifications.Subscription>();
+//     const notificationListener = useRef<Notifications.Subscription>();
+//     const responseListener = useRef<Notifications.Subscription>();
 
-    useEffect(() => {
-        Notifications.setNotificationHandler({
-            handleNotification: async () => ({
-                shouldPlaySound: true,
-                shouldShowAlert: true,
-                shouldSetBadge: true,
-                icon: './assets/images/cc.png',
-                vibrate: true,
-                shouldShowWhenInForeground: true
-            })
-        });
+//     useEffect(() => {
+//         Notifications.setNotificationHandler({
+//             handleNotification: async () => ({
+//                 shouldPlaySound: true,
+//                 shouldShowAlert: true,
+//                 shouldSetBadge: true,
+//                 icon: './assets/images/cc.png',
+//                 vibrate: true,
+//                 shouldShowWhenInForeground: true
+//             })
+//         });
 
-        registerForPushNotificationAsync().then((token) => {
-            setExpoPushToken(token);
-        });
+//         registerForPushNotificationAsync().then((token) => {
+//             setExpoPushToken(token);
+//         });
 
-        notificationListener.current = Notifications.addNotificationReceivedListener((notification) => {
-            setNotification(notification);
-        });
+//         notificationListener.current = Notifications.addNotificationReceivedListener((notification) => {
+//             setNotification(notification);
+//         });
 
-        responseListener.current = Notifications.addNotificationResponseReceivedListener((response) => {
-            console.log(response);
-        });
+//         responseListener.current = Notifications.addNotificationResponseReceivedListener((response) => {
+//             console.log(response);
+//         });
 
-        return () => {
-            Notifications.removeNotificationSubscription(notificationListener.current!);
-            Notifications.removeNotificationSubscription(responseListener.current!);
-        };
-    }, []);
+//         return () => {
+//             Notifications.removeNotificationSubscription(notificationListener.current!);
+//             Notifications.removeNotificationSubscription(responseListener.current!);
+//         };
+//     }, []);
 
-    return {
-        expoPushToken,
-        notification
-    };
-};
+//     return {
+//         expoPushToken,
+//         notification
+//     };
+// };
 
-async function registerForPushNotificationAsync() {
-    let token;
+// async function registerForPushNotificationAsync() {
+//     let token;
 
-    // Check if the device is a physical device, because this only works for physical devices not simulators
-    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;
-        }
-        //if we have permission, then get the token
-        token = await Notifications.getExpoPushTokenAsync({
-            projectId: Constants.expoConfig?.extra?.eas?.projectId
-        });
+//     // Check if the device is a physical device, because this only works for physical devices not simulators
+//     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;
+//         }
+//         //if we have permission, then get the token
+//         token = await Notifications.getExpoPushTokenAsync({
+//             projectId: Constants.expoConfig?.extra?.eas?.projectId
+//         });
 
-        if (Platform.OS === 'android') {
-            Notifications.setNotificationChannelAsync('default', {
-                name: 'default',
-                importance: Notifications.AndroidImportance.MAX,
-                vibrationPattern: [0, 250, 250, 250],
-                lightColor: '#FF231F7C'
-            });
-        }
-        console.log('token', token);
-        return token;
-    } else {
-        console.log('Must use physical device for Push Notifications');
-    }
-}
+//         if (Platform.OS === 'android') {
+//             Notifications.setNotificationChannelAsync('default', {
+//                 name: 'default',
+//                 importance: Notifications.AndroidImportance.MAX,
+//                 vibrationPattern: [0, 250, 250, 250],
+//                 lightColor: '#FF231F7C'
+//             });
+//         }
+//         console.log('token', token);
+//         return token;
+//     } else {
+//         console.log('Must use physical device for Push Notifications');
+//     }
+// }

+ 64 - 66
package.json

@@ -1,68 +1,66 @@
 {
-  "name": "template",
-  "version": "1.0.0",
-  "main": "expo-router/entry",
-  "scripts": {
-    "start": "expo start -c",
-    "android": "expo run:android",
-    "ios": "expo run:ios",
-    "web": "expo start --web"
-  },
-  "dependencies": {
-    "@gorhom/bottom-sheet": "^4.6.3",
-    "@react-native-async-storage/async-storage": "^1.23.1",
-    "@shopify/flash-list": "1.6.4",
-    "@tanstack/react-query": "^5.51.23",
-    "@types/lodash": "^4.17.7",
-    "@types/react-native-datepicker": "^1.7.6",
-    "axios": "^1.6.7",
-    "crypto-js": "^4.2.0",
-    "date-fns": "^3.6.0",
-    "date-fns-tz": "^3.1.3",
-    "dotenv": "^16.4.5",
-    "expo": "~51.0.7",
-    "expo-camera": "~15.0.13",
-    "expo-checkbox": "~3.0.0",
-    "expo-constants": "~16.0.2",
-    "expo-env": "^1.1.1",
-    "expo-file-system": "~17.0.1",
-    "expo-image-picker": "~15.0.7",
-    "expo-linking": "~6.3.1",
-    "expo-location": "~17.0.1",
-    "expo-router": "~3.5.14",
-    "expo-secure-store": "~13.0.1",
-    "expo-status-bar": "~1.12.1",
-    "lodash": "^4.17.21",
-    "nativewind": "^2.0.11",
-    "react": "18.2.0",
-    "react-native": "0.74.1",
-    "react-native-element-dropdown": "^2.12.1",
-    "react-native-gesture-handler": "~2.16.1",
-    "react-native-keyboard-aware-scroll-view": "^0.9.5",
-    "react-native-maps": "1.14.0",
-    "react-native-modal": "^13.0.1",
-    "react-native-modern-datepicker": "^1.0.0-beta.91",
-    "react-native-pager-view": "6.3.0",
-    "react-native-reanimated": "~3.10.1",
-    "react-native-responsive-screen": "^1.4.2",
-    "react-native-safe-area-context": "^4.10.1",
-    "react-native-screens": "3.31.1",
-    "react-native-svg": "^15.3.0",
-    "react-native-tab-view": "^3.5.2",
-    "react-native-webview": "^13.11.1",
-    "react-query": "^3.39.3",
-    "zustand": "^4.5.2",
-    "expo-notifications": "~0.28.19",
-    "expo-device": "~6.0.2"
-  },
-  "devDependencies": {
-    "@babel/core": "^7.20.0",
-    "@types/crypto-js": "^4.2.2",
-    "@types/react": "~18.2.79",
-    "@types/react-native-modern-datepicker": "^1.0.5",
-    "react-native-dotenv": "^3.4.11",
-    "tailwindcss": "^3.3.2",
-    "typescript": "~5.3.3"
-  },
-  "private": true
+    "name": "template",
+    "version": "1.0.0",
+    "main": "expo-router/entry",
+    "scripts": {
+        "start": "expo start -c",
+        "android": "expo run:android",
+        "ios": "expo run:ios",
+        "web": "expo start --web"
+    },
+    "dependencies": {
+        "@gorhom/bottom-sheet": "^4.6.3",
+        "@react-native-async-storage/async-storage": "^1.23.1",
+        "@shopify/flash-list": "1.6.4",
+        "@tanstack/react-query": "^5.51.23",
+        "@types/lodash": "^4.17.7",
+        "@types/react-native-datepicker": "^1.7.6",
+        "axios": "^1.6.7",
+        "crypto-js": "^4.2.0",
+        "date-fns": "^3.6.0",
+        "date-fns-tz": "^3.1.3",
+        "dotenv": "^16.4.5",
+        "expo": "~51.0.7",
+        "expo-camera": "~15.0.13",
+        "expo-checkbox": "~3.0.0",
+        "expo-constants": "~16.0.2",
+        "expo-env": "^1.1.1",
+        "expo-file-system": "~17.0.1",
+        "expo-image-picker": "~15.0.7",
+        "expo-linking": "~6.3.1",
+        "expo-location": "~17.0.1",
+        "expo-router": "~3.5.14",
+        "expo-secure-store": "~13.0.1",
+        "expo-status-bar": "~1.12.1",
+        "lodash": "^4.17.21",
+        "nativewind": "^2.0.11",
+        "react": "18.2.0",
+        "react-native": "0.74.1",
+        "react-native-element-dropdown": "^2.12.1",
+        "react-native-gesture-handler": "~2.16.1",
+        "react-native-keyboard-aware-scroll-view": "^0.9.5",
+        "react-native-maps": "1.14.0",
+        "react-native-modal": "^13.0.1",
+        "react-native-modern-datepicker": "^1.0.0-beta.91",
+        "react-native-pager-view": "6.3.0",
+        "react-native-reanimated": "~3.10.1",
+        "react-native-responsive-screen": "^1.4.2",
+        "react-native-safe-area-context": "^4.10.1",
+        "react-native-screens": "3.31.1",
+        "react-native-svg": "^15.3.0",
+        "react-native-tab-view": "^3.5.2",
+        "react-native-webview": "^13.11.1",
+        "react-query": "^3.39.3",
+        "zustand": "^4.5.2"
+    },
+    "devDependencies": {
+        "@babel/core": "^7.20.0",
+        "@types/crypto-js": "^4.2.2",
+        "@types/react": "~18.2.79",
+        "@types/react-native-modern-datepicker": "^1.0.5",
+        "react-native-dotenv": "^3.4.11",
+        "tailwindcss": "^3.3.2",
+        "typescript": "~5.3.3"
+    },
+    "private": true
 }