| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- //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;
- id?: string;
- }
- 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();
- }, []);
- 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>
- <Text
- style={{
- fontWeight: '400',
- fontSize: 14,
- color: '#888888'
- }}
- >
- {item.chargeStationName}
- </Text>
- <View className="flex flex-row space-x-2">
- <Text
- style={{
- fontWeight: '400',
- fontSize: 14,
- color: '#02677D'
- }}
- onPress={() => {
- router.push({ pathname: 'chargingDetailsPage', params: { id: item.id, chargeStationName: item.chargeStationName }})
- }}
- >
- 訂單詳情 >
- </Text>
- </View>
- </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
- }
- });
|