import { View, Text, ScrollView, FlatList, Pressable, ActivityIndicator, Image, Modal, Alert, TextInput } from 'react-native'; import NormalButton from '../global/normal_button'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router, useFocusEffect } from 'expo-router'; import { useColorScheme } from 'nativewind'; import RecentlyBookedScrollView from '../global/recentlyBookedScrollView'; import { BellIconSvg, HomeIconSvg, MyBookingIconSvg, WhatsAppSvg, WalletSvg, MyWalletSvg, QrCodeIconSvg, VipCodeIconSvg } from '../global/SVG'; import { AuthContext } from '../../context/AuthProvider'; import { useCallback, useContext, useEffect, useState } from 'react'; import { authenticationService } from '../../service/authService'; import { chargeStationService } from '../../service/chargeStationService'; import useUserInfoStore from '../../providers/userinfo_store'; import NormalInput from '../global/normal_input'; import { notificationStorage } from '../notificationStorage'; import { handleGoWhatsApp } from '../../util/index'; import { useChargingStore } from '../../providers/scan_qr_payload_store'; import { useTranslation } from '../../util/hooks/useTranslation'; interface HomePageProps {} const HomePage: React.FC = () => { const { t } = useTranslation(); // 使用翻译钩子 const { promotion_code, stationID, sum_of_coupon, scanned_qr_code, coupon_detail, total_power, processed_coupon_store, setPromotionCode, setCouponDetail, setTotalPower, setProcessedCouponStore, setSumOfCoupon, setCurrentPriceStore } = useChargingStore(); const now = new Date(); const { user } = useContext(AuthContext); const { userID, currentPrice, setUserID, setCurrentPrice, setNotifySessionID } = useUserInfoStore(); const { colorScheme, toggleColorScheme } = useColorScheme(); const [showLicencePlateMessage, setShowLicencePlateMessage] = useState(false); const [licensePlate, setLicensePlate] = useState(''); const [showConfirmationModal, setShowConfirmationModal] = useState(false); const [showOnboarding, setShowOnboarding] = useState(true); const [mainPromotion, setMainPromotion] = useState([]); const [mainPromotionImage, setMainPromotionImage] = useState(''); const [reservationAfter2025, setReservationAfter2025] = useState([]); const [isLoadingReservations, setIsLoadingReservations] = useState(true); const [unreadCount, setUnreadCount] = useState(0); useEffect(() => { const fetchIDandCheckLicensePlate = async () => { try { const response = await authenticationService.getUserInfo(); //if success, set user ID, if (response) { setNotifySessionID(response.data.notify_session_id); setUserID(response.data.id); //after setting id, also check if the user has a valid license plate, if not, show message if (!response.data.cars || !Array.isArray(response.data.cars)) { Alert.alert(t('home.vehicle_info_error_title'), t('home.vehicle_info_error_message')); setShowLicencePlateMessage(false); } if (response.data.cars.length === 1 && response.data.cars[0].license_plate === '0000') { setShowLicencePlateMessage(true); } } else { Alert.alert(t('home.fail_set_user_id')); } } catch (error) { console.log(error); } }; const fetchCurrentPrice = async () => { try { const response = await chargeStationService.getCurrentPrice(); if (response) { setCurrentPrice(response); } } catch (error) { console.log(t('home.fetch_price_error'), error); } }; const fetchMainPromotion = async () => { try { const response = await chargeStationService.getAdvertise(); if (response) { const mainPromo = response.filter((item: any) => item.is_main)[0]; setMainPromotion(mainPromo); if (mainPromo) { const mainPromoImage = await chargeStationService.getProcessedImageUrl(mainPromo.image_url); if (mainPromoImage) { setMainPromotionImage(mainPromoImage); } } } } catch (error) { console.log(t('home.fetch_promotion_error'), error); } }; fetchMainPromotion(); const fetchWithAllSettled = async () => { const results = await Promise.allSettled([ fetchIDandCheckLicensePlate(), fetchCurrentPrice(), fetchMainPromotion() ]); }; fetchWithAllSettled(); }, []); const cleanupData = () => { setPromotionCode([]); setCouponDetail([]); setProcessedCouponStore([]); setSumOfCoupon(0); setTotalPower(null); }; useFocusEffect( useCallback(() => { let isActive = true; const fetchData = async () => { setIsLoadingReservations(true); // Start loading try { const results = await Promise.allSettled([ chargeStationService.fetchReservationHistories(), chargeStationService.getAdvertise() ]); if (!isActive) return; // Handle reservation data if (results[0].status === 'fulfilled') { const year2025 = new Date('2025-02-01T00:00:00.000Z'); const reservationAfter2025 = results[0].value.filter((r: any) => { const date = new Date(r.createdAt); return date > year2025; }); setReservationAfter2025(reservationAfter2025); } else if (results[0].status === 'rejected') { Alert.alert(t('home.error_fetching_reservations'), results[0].reason); } // Get viewed notifications const viewedNotifications = await notificationStorage.getViewedNotifications(); let totalUnread = 0; // Count unread reservations if (results[0].status === 'fulfilled') { const unreadReservations = reservationAfter2025.filter((r: any) => { return !viewedNotifications.some((vn: any) => vn.id === r.id); }); totalUnread += unreadReservations.length; } // Count unread promotions if (results[1].status === 'fulfilled') { const unreadPromotions = results[1].value.filter((p: any) => { return !viewedNotifications.some((vn) => vn.id === p.id); }); totalUnread += unreadPromotions.length; } setUnreadCount(totalUnread); if (results[0].status === 'fulfilled') { const reservationHistories = results[0].value; if (reservationHistories || Array.isArray(reservationHistories)) { const unpaidPenalties = reservationHistories.filter( (reservation: any) => reservation.penalty_fee > 0 && reservation.penalty_paid_status === false ); const mostRecentUnpaidReservation = unpaidPenalties.reduce((mostRecent: any, current: any) => { return new Date(mostRecent.created_at) > new Date(current.created_at) ? mostRecent : current; }, unpaidPenalties[0]); console.log('mostRecentUnpaidReservation', mostRecentUnpaidReservation); if (unpaidPenalties.length > 0) { Alert.alert( t('home.unpaid_penalty_title'), t('home.unpaid_penalty_message'), [ { text: t('home.view_details'), onPress: () => { // Navigate to a page showing penalty details cleanupData(); router.push({ pathname: '(auth)/(tabs)/(home)/penaltyPaymentPage', params: { book_time: mostRecentUnpaidReservation.book_time, end_time: mostRecentUnpaidReservation.end_time, actual_end_time: mostRecentUnpaidReservation.actual_end_time, penalty_fee: mostRecentUnpaidReservation.penalty_fee, format_order_id: mostRecentUnpaidReservation.format_order_id, id: mostRecentUnpaidReservation.id } }); } }, { text: t('home.close'), onPress: () => { cleanupData(); } } ], { cancelable: false } ); return; } } } } catch (error) { if (!isActive) return; console.log(t('home.error_fetching_data')); } finally { if (isActive) { setIsLoadingReservations(false); } } }; fetchData(); return () => { isActive = false; }; }, []) ); const saveLicensePlate = async (licensePlate: string) => { try { const response = await chargeStationService.addCar( licensePlate, '1834d087-bfc1-4f90-8f09-805e3d9422b5', 'f599470d-53a5-4026-99c0-2dab34c77f39', true ); if (response === true) { console.log(t('home.license_plate_saved')); } else { Alert.alert(t('home.save_license_plate_failed_title'), t('home.save_license_plate_failed_message')); } } catch (error) { Alert.alert(t('home.save_license_plate_temp_failed_title'), t('home.save_license_plate_temp_failed_message')); } }; return ( {/* Add Modal component */} {mainPromotionImage && ( { setShowOnboarding(false)}} > setShowOnboarding(false)} > {t('home.tap_to_close')} )} {showLicencePlateMessage && ( setShowLicencePlateMessage(false)} > {!showConfirmationModal ? ( // License Plate Input Modal {t('home.add_license_plate_title')} {t('home.add_license_plate_message')} setLicensePlate(s)} extendedStyle={{ borderRadius: 12, marginBottom: 0 }} textContentType="none" autoComplete="off" keyboardType="default" /> {t('home.confirm')}} onPress={() => { //here when users click confirm, i want to pop another modal that say you have entered "xxxxxx", click confirm to continue if (!licensePlate.trim()) { Alert.alert(t('home.enter_license_plate')); return; } if (licensePlate.trim().length < 4 || licensePlate.trim().length > 10) { Alert.alert(t('home.invalid_license_plate_title'), t('home.invalid_license_plate_message')); return; } setShowConfirmationModal(true); }} /> ) : ( // Confirmation Modal {t('home.confirm_license_plate_title')} {t('home.confirm_license_plate_message')} {licensePlate} {t('home.cancel')}} onPress={() => setShowConfirmationModal(false)} /> {t('home.confirm')}} onPress={() => { saveLicensePlate(licensePlate); setShowConfirmationModal(false); setShowLicencePlateMessage(false); setLicensePlate(''); }} /> )} )} {t('home.greeting')} router.push({ pathname: 'notificationPage' })} disabled={isLoadingReservations} className="z-10 w-10 items-center justify-center" hitSlop={{ top: 20, bottom: 20, left: 20, right: 20 }} > {unreadCount > 0 && ( {unreadCount} )} handleGoWhatsApp()}> {user?.nickname} {/* router.push('searchPage')}> {t('home.search_placeholder')} */} router.push('scanQrPage')} // onPress={() => router.push('optionPage')} title={ {t('home.scan_and_charge')} } extendedStyle={{ alignItems: 'flex-start', padding: 24 }} /> {/* router.push('bookingMenuPage')} onPress={() => Alert.alert(t('home.coming_soon_title'), t('home.coming_soon_message'))} //onPress={() => notificationStorage.clearStorage()} title={ {t('home.my_bookings')} } extendedStyle={{ alignItems: 'flex-start', padding: 24 }} /> */} router.push('/(account)/(wallet)/walletPage')} title={ {t('home.wallet')} } extendedStyle={{ alignItems: 'flex-start', padding: 24 }} /> console.log('掃瞄及充電')} onPress={() => router.push('vipQrPage')} title={ {t('home.vip_qr_code')} } extendedStyle={{ alignItems: 'flex-start', padding: 24 }} /> ); }; export default HomePage;