Browse Source

feat: 充电记录合并成一个列表

kuns 2 months ago
parent
commit
9a8729b566

+ 5 - 5
component/accountPages/walletPageComponent.tsx

@@ -33,9 +33,9 @@ const AmountInputModal = ({ visible, onClose, onConfirm }) => {
     const amounts = [
         // { amount: 1, percentage: 0 },
         { amount: 200, percentage: 0 },
-        { amount: 500, percentage: 5 },
-        { amount: 1000, percentage: 10 },
-        { amount: 2000, percentage: 15 }
+        { amount: 500, percentage: 25 },
+        { amount: 1000, percentage: 100 },
+        { amount: 2000, percentage: 200 }
     ];
 
     const getFontSize = () => {
@@ -88,12 +88,12 @@ const AmountInputModal = ({ visible, onClose, onConfirm }) => {
                             >
                                 <Text style={{ color: 'white', fontSize: getFontSize() }}>
                                     ${amount.amount}
-                                    {amount.percentage > 0 ? ` (+${amount.percentage}%) ` : ''}
+                                    {amount.percentage > 0 ? ` (送$${amount.percentage}) ` : ''}
                                 </Text>
                             </Pressable>
                         ))}
                     </View>
-                    <Text>*括號為回贈比例</Text>
+                    <Text>*括號為贈款金額</Text>
                     <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
                         <Text style={{ color: 'red' }}>取消</Text>
                     </Pressable>

+ 8 - 7
component/global/bookingTabViewComponent.tsx

@@ -1,7 +1,7 @@
 import React, { useState, useCallback, useEffect } from 'react';
 import { ActivityIndicator, View, RefreshControl } from 'react-native';
 import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import TabViewComponent, { TabItem } from './tabView';
+import TabViewComponent, { TabItem } from './chargingRecord';
 import { chargeStationService } from '../../service/chargeStationService';
 
 const queryClient = new QueryClient();
@@ -42,7 +42,7 @@ const fetchReservationsAndStations = async () => {
     }
 };
 
-const processReservations = (reservations, allStations, isFuture): TabItem[] => {
+const processReservations = (reservations: any [], allStations: string [], isFuture: boolean): TabItem[] => {
     // 确保参数是数组类型
     const validReservations = Array.isArray(reservations) ? reservations : [];
     const validStations = Array.isArray(allStations) ? allStations : [];
@@ -71,7 +71,7 @@ const processReservations = (reservations, allStations, isFuture): TabItem[] =>
                 return {} as TabItem; // 返回默认对象
             }
 
-            let snapshot = {};
+            let snapshot = {} as any;
             try {
                 snapshot = reservation.snapshot ? JSON.parse(reservation.snapshot) : {};
             } catch (e) {
@@ -143,13 +143,14 @@ const BookingTabViewComponentInner: React.FC<BookingTabViewComponentProps> = ({
     const reservations = Array.isArray(data?.reservations) ? data.reservations : [];
     const stations = Array.isArray(data?.stations) ? data.stations : [];
 
-    const tabItems = processReservations(reservations, stations, true);
-    const completedReservationTabItems = processReservations(reservations, stations, false);
+    const futureReservations = processReservations(reservations, stations, true);
+    const completedReservations = processReservations(reservations, stations, false);
+    const allReservationItems = [...futureReservations, ...completedReservations];
+
     return (
         <TabViewComponent
             titles={titles}
-            tabItems={tabItems}
-            completedReservationTabItems={completedReservationTabItems}
+            tabItems={allReservationItems}
             isLoading={false}
         />
     );

+ 209 - 0
component/global/chargingRecord.tsx

@@ -0,0 +1,209 @@
+//the size of the TabView will follow its parent-container's size.
+
+import * as React from 'react';
+import * as Location from 'expo-location';
+import {
+    View,
+    Text,
+    useWindowDimensions,
+    Dimensions,
+    StyleSheet,
+    Image,
+    ImageSourcePropType,
+    ActivityIndicator,
+    Pressable
+} from 'react-native';
+import { TabView, SceneMap, TabBar } from 'react-native-tab-view';
+import { FlashList } from '@shopify/flash-list';
+import { useEffect, useState } from 'react';
+import { calculateDistance } from './distanceCalculator';
+import { router } from 'expo-router';
+
+export interface TabItem {
+    imgURL: ImageSourcePropType;
+    date: string;
+    time: string;
+    chargeStationName: string;
+    chargeStationAddress: string;
+    stationLat: string | number;
+    stationLng: string | number;
+    distance: string;
+    format_order_id: string;
+    actual_total_power?: number;
+    actual_end_time?: string;
+    actual_fee?: number;
+    current_price?: number;
+}
+
+interface TabViewComponentProps {
+    titles: string[];
+    tabItems: TabItem[];
+    isLoading?: boolean;
+}
+
+const TabViewComponent: React.FC<TabViewComponentProps> = ({
+    titles,
+    isLoading,
+    tabItems,
+}) => {
+    const layout = useWindowDimensions();
+    const [currentLocation, setCurrentLocation] = useState<Location.LocationObject | null>(null);
+
+    useEffect(() => {
+        const getCurrentLocation = async () => {
+            let { status } = await Location.requestForegroundPermissionsAsync();
+            if (status !== 'granted') {
+                console.error('Permission to access location was denied');
+                return;
+            }
+            let location = await Location.getLastKnownPositionAsync({});
+            setCurrentLocation(location);
+        };
+
+        getCurrentLocation();
+    }, []);
+
+    // 修复 FirstRoute 组件
+    const FirstRoute = ({ tabItems, isLoading, currentLocation }: { 
+            tabItems: TabItem[]; 
+            isLoading?: boolean; 
+            currentLocation: Location.LocationObject | null 
+        }) => (
+        <View style={{ flex: 1, backgroundColor: 'white' }}>
+            {isLoading ? (
+            <View className="items-center justify-center flex-1">
+                <ActivityIndicator color="#34657b" />
+            </View>
+            ) : (
+            <FlashList
+                nestedScrollEnabled={true}
+                data={tabItems.filter((item) => item?.actual_total_power && item?.actual_total_power !== 0)}
+                renderItem={({ item }) => <TabItem item={item} currentLocation={currentLocation} />}
+                keyExtractor={(item, index) => index.toString()}
+            />
+            )}
+        </View>
+    );
+
+    return (
+        <FirstRoute tabItems={tabItems} isLoading={isLoading} currentLocation={currentLocation} />
+    );
+};
+
+const TabItem = ({ item, currentLocation }: { item: TabItem; currentLocation: Location.LocationObject | null }) => {
+    const [distance, setDistance] = useState<number | null>(null);
+
+    useEffect(() => {
+        const getDistance = async () => {
+            if (currentLocation) {
+                const result = await calculateDistance(
+                    Number(item.stationLat),
+                    Number(item.stationLng),
+                    currentLocation
+                );
+                setDistance(result);
+            }
+        };
+
+        getDistance();
+    }, [currentLocation, item.stationLat, item.stationLng]);
+
+    return (
+        <Pressable
+            onPress={() => {
+                console.log(item.format_order_id);
+            }}
+        >
+            <View style={styles.container}>
+                <Image style={styles.image} source={item.imgURL} />
+                <View className="flex flex-col gap-2 mr-2">
+                    <Text
+                        style={{
+                            fontWeight: '700',
+                            color: '#02677D',
+                            fontSize: 16
+                        }}
+                    >
+                        {`${item.date}日 - ${item.time}至${item.actual_end_time}`}
+                    </Text>
+                    <View className="flex flex-row justify-between space-x-2">
+                        <Text
+                            style={{
+                                fontWeight: '400',
+                                fontSize: 14,
+                                color: '#222222'
+                            }}
+                        >
+                            已充電度數:{' '}
+                            {item.actual_total_power
+                                ? item.actual_total_power % 1 === 0
+                                    ? item.actual_total_power
+                                    : item.actual_total_power.toFixed(1)
+                                : ''}
+                        </Text>
+                        <Text
+                            style={{
+                                fontWeight: '400',
+                                fontSize: 14,
+                                color: '#222222'
+                            }}
+                        >
+                            應付金額:{' '}
+                            {item.actual_fee !== undefined && item.actual_fee !== null
+                                ? item.actual_fee <= 0
+                                    ? '$0'
+                                    : item.actual_fee % 1 === 0
+                                      ? `$${item.actual_fee}`
+                                      : `$${item.actual_fee.toFixed(1)}`
+                                : ''}
+                        </Text>
+                    </View>
+                    <View className="flex flex-row  space-x-2">
+                        <Text
+                            style={{
+                                fontWeight: '400',
+                                fontSize: 14,
+                                color: '#222222'
+                            }}
+                        >
+                            每度電金額: ${item.current_price}
+                        </Text>
+                    </View>
+                    <Text
+                        style={{
+                            fontWeight: '400',
+                            fontSize: 14,
+                            color: '#888888'
+                        }}
+                    >
+                        {item.chargeStationName}
+                    </Text>
+                </View>
+            </View>
+        </Pressable>
+    );
+};
+
+export default TabViewComponent;
+
+const styles = StyleSheet.create({
+    container: {
+        flexDirection: 'row',
+        width: '100%',
+        flex: 1,
+        alignItems: 'center'
+    },
+    image: {
+        width: 100,
+        height: 100,
+        margin: 15,
+        borderRadius: 10
+    },
+    textContainer: {
+        flex: 1,
+        flexDirection: 'column',
+        gap: 8,
+        marginTop: 20,
+        marginRight: 8 // Add right margin to prevent text from touching the edge
+    }
+});

+ 4 - 0
component/global/tabView.tsx

@@ -29,6 +29,10 @@ export interface TabItem {
     stationLng: string | number;
     distance: string;
     format_order_id: string;
+    actual_total_power?: number;
+    actual_end_time?: string;
+    actual_fee?: number;
+    current_price?: number;
 }
 
 interface TabViewComponentProps {