//the size of the TabView will follow its parent-container's size. import * as React from 'react'; import { View, Text, useWindowDimensions, StyleSheet, ImageSourcePropType, ScrollView, ActivityIndicator, Pressable, Alert } from 'react-native'; import { TabView, SceneMap, TabBar } from 'react-native-tab-view'; import { IndividualCouponComponent } from '../accountPages/walletPageComponent'; import { formatCouponDate } from '../../util/lib'; import { useCallback, useEffect, useRef, useState } from 'react'; import { walletService } from '../../service/walletService'; import { useChargingStore } from '../../providers/scan_qr_payload_store'; import { chargeStationService } from '../../service/chargeStationService'; import { router } from 'expo-router'; import axios from 'axios'; export interface TabItem { imgURL: ImageSourcePropType; date: string; time: string; chargeStationName: string; chargeStationAddress: string; distance: string; } interface TabViewComponentProps { titles: string[]; } const FirstRoute = ({ coupons, loading, handleCouponClick }: { coupons: any; loading: boolean; handleCouponClick: any; }) => { return ( {loading ? ( ) : ( {coupons.filter( (coupon: any) => coupon.permission == true && coupon.is_consumed === false && (coupon.expire_date === null || new Date(coupon.expire_date) > new Date()) ).length === 0 ? ( 暫時戶口沒有優惠券。 ) : ( coupons .filter( (coupon: any) => coupon.permission == true && coupon.is_consumed === false && (coupon.expire_date === null || new Date(coupon.expire_date) > new Date()) ) .sort( (a: any, b: any) => new Date(a.expire_date).getTime() - new Date(b.expire_date).getTime() ) .slice(0, 30) .map((coupon: any, index: any) => ( )) )} )} ); }; const SecondRoute = ({ coupons }: { coupons: any }) => ( {coupons .filter( (coupon: any) => coupon.is_consumed === true || (coupon.expire_date !== null && new Date(coupon.expire_date) < new Date()) ) .slice(0, 30) .map((coupon: any, index: any) => ( ))} ); const CouponTabViewComponent: React.FC = ({ titles }) => { const layout = useWindowDimensions(); const [loading, setLoading] = useState(false); const [coupons, setCoupons] = useState([]); const [userID, setUserID] = useState(''); const { current_price_store, setCurrentPriceStore, stationID, promotion_code, setPromotionCode, setCouponDetail, coupon_detail, total_power, setTotalPower, setProcessedCouponStore, setSumOfCoupon } = useChargingStore(); useEffect(() => { const fetchData = async () => { try { setLoading(true); const info = await walletService.getCustomerInfo(); const coupon = await walletService.getCouponForSpecificUser(info.id); setUserID(info.id); setCoupons(coupon); } catch (error) { console.log(error); } finally { setLoading(false); } }; fetchData(); }, []); //fetch current price for coupon valid calculation useEffect(() => { const fetchCurrentPrice = async () => { try { const response = await chargeStationService.getOriginalPriceInPay(stationID); setCurrentPriceStore(response); } catch (error) { // More specific error handling if (axios.isAxiosError(error)) { const errorMessage = error.response?.data?.message || 'Network error occurred'; Alert.alert('Error', `Unable to fetch price: ${errorMessage}`, [ { text: 'OK', onPress: () => { cleanupData(); router.push('/mainPage'); } } ]); } else { Alert.alert('Error', 'An unexpected error occurred while fetching the price', [ { text: 'OK', onPress: () => { cleanupData(); router.push('/mainPage'); } } ]); } } }; fetchCurrentPrice(); }, []); const handleCouponClick = async (clickedCoupon: string) => { let temp_promotion_code = [...promotion_code]; if (!current_price_store) { Alert.alert('Error', 'Unable to fetch price', [ { text: 'OK', onPress: () => { cleanupData(); router.push('/mainPage'); } } ]); return; } let orderAmount = current_price_store * total_power; //when i click on a coupon, if coupone doesnt already exist in the stack, i add it to the stack if (!promotion_code.includes(clickedCoupon)) { const found_coupon = coupons.find((coupon: any) => coupon.id === clickedCoupon); temp_promotion_code = [...promotion_code, found_coupon.id]; try { const valid = await chargeStationService.validateCoupon(temp_promotion_code, orderAmount); if (valid === true) { setCouponDetail([...coupon_detail, found_coupon]); setPromotionCode([...promotion_code, clickedCoupon]); } else { Alert.alert('不符合使用優惠券的條件', '請查看優惠卷的詳情,例如是否需要滿足最低消費金額。'); } } catch (error) { console.log(error); } } else { //coupon already exists, this de-select the coupon const index_of_clicked_coupon = promotion_code.findIndex((i) => i === clickedCoupon); const newPromotionCode = [...promotion_code]; newPromotionCode.splice(index_of_clicked_coupon, 1); setPromotionCode(newPromotionCode); const newCouponDetail = coupon_detail.filter((detail: any) => detail.id !== clickedCoupon); setCouponDetail(newCouponDetail); } }; const cleanupData = () => { setPromotionCode([]); setCouponDetail([]); setProcessedCouponStore([]); setSumOfCoupon(0); setTotalPower(null); }; const renderScene = useCallback( ({ route }: { route: any }) => { switch (route.key) { case 'firstRoute': return ; case 'secondRoute': return ; default: return null; } }, [coupons, loading, handleCouponClick] ); const [routes] = React.useState([ { key: 'firstRoute', title: titles[0] }, { key: 'secondRoute', title: titles[1] } ]); const [index, setIndex] = React.useState(0); const renderTabBar = (props: any) => ( ); return ( ( {route.title} ) }} /> ); }; export default CouponTabViewComponent; const styles = StyleSheet.create({ container: { flexDirection: 'row' }, image: { width: 100, height: 100, margin: 15, borderRadius: 10 }, textContainer: { flexDirection: 'column', gap: 8, marginTop: 20 }, floatingButton: { elevation: 5, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84 } });