import { Animated, Easing, Pressable, ScrollView, StyleSheet, TouchableOpacity, } from "react-native"; import { useTranslation } from "react-i18next"; import SemiCircleProgress from "../../components/home/SemiCircleProgress"; import { Text, View } from "react-native"; import { useNavigation } from "expo-router"; import { useEffect, useLayoutEffect, useState } from "react"; import { StatusBar } from "expo-status-bar"; import CustomerCareIcon from "../../assets/icons/customer-care.svg"; import ServiceReminderCard from "@/components/home/ServiceReminderCard"; import MetricCard from "@/components/home/MetricCard"; import PaymentDueCard from "@/components/home/PaymentDueCard"; import MapView, { Marker, PROVIDER_GOOGLE } from "react-native-maps"; import BatteryWarrantyCard from "@/components/home/BatteryWarrantyCars"; import CustomerSupportModal from "@/components/home/CustomerSupportModal"; import { useSelector } from "react-redux"; import { AppDispatch, RootState } from "@/store"; import LocationOff from "@/assets/icons/location_off.svg"; import { Linking } from "react-native"; import { useRouter } from "expo-router"; import ProfileImage from "@/components/home/Profile"; import { calculateBearing, calculateDistance } from "@/utils/Map"; import { useDispatch } from "react-redux"; import RefreshIcon from "@/assets/icons/refresh.svg"; import { payments } from "@/constants/config"; import { clearUser, getPaymentSummary, getUserDetails, } from "@/store/userSlice"; import { setDueAmount } from "@/store/paymentSlice"; import { Image } from "expo-image"; import EMINotification from "@/components/Payments/EmiNotification"; export default function HomeScreen() { const { t } = useTranslation(); const navigation = useNavigation(); const [isSupportModalVisible, setIsSupportModalVisible] = useState(false); const { SoC, SoH, chargingState, lat, lon, loading, totalDistance } = useSelector((state: RootState) => state.telemetry); const [refreshing, setRefreshing] = useState(false); const spinValue = useState(new Animated.Value(0))[0]; const { data, paymentSummary, loading: userLoading, } = useSelector((state: RootState) => state.user); const isRefreshing = refreshing || userLoading; const [prevPosition, setPrevPosition] = useState<{ lat: number; lon: number; } | null>(null); const [bearing, setBearing] = useState(0); const dispatch = useDispatch(); const vehicle = Array.isArray(data?.vehicles) && data.vehicles.length > 0 ? data.vehicles[0] : null; const battery = Array.isArray(data?.batteries) && data.batteries.length > 0 ? data.batteries[0] : null; const model = vehicle?.model ?? "---"; const chasisNumber = vehicle?.chasis_number ?? "---"; const warrantyStartDate = data?.batteries[0]?.warranty_start_date || null; const warrantyEndDate = data?.batteries[0]?.warranty_end_date || null; useEffect(() => { if (lat && lon) { if (prevPosition) { // Calculate bearing between prev and current position const newBearing = calculateBearing( prevPosition.lat, prevPosition.lon, lat, lon ); setBearing(newBearing); } setPrevPosition({ lat, lon }); // Update previous position } }, [lat, lon]); useEffect(() => { if (lat && lon) { if (prevPosition) { const distance = calculateDistance( prevPosition.lat, prevPosition.lon, lat, lon ); if (distance > 5) { // Only update bearing if moved >5 meters const newBearing = calculateBearing( prevPosition.lat, prevPosition.lon, lat, lon ); setBearing(newBearing); } } setPrevPosition({ lat, lon }); } }, [lat, lon]); const router = useRouter(); useLayoutEffect(() => { navigation.setOptions({ headerStyle: { backgroundColor: "#F3F5F8", }, headerTitle: () => ( {model} {chasisNumber} ), headerRight: () => ( { setIsSupportModalVisible(true); console.log("hkdlfjaldf"); }} > { router.push("/user/profile"); }} /> ), }); }, [navigation, data, model, chasisNumber, isRefreshing]); const openInGoogleMaps = () => { const url = `https://www.google.com/maps/search/?api=1&query=${lat},${lon}`; Linking.openURL(url).catch((err) => console.error("Failed to open Google Maps:", err) ); }; const startSpin = () => { spinValue.setValue(0); Animated.loop( Animated.timing(spinValue, { toValue: 1, duration: 1000, easing: Easing.linear, useNativeDriver: true, }) ).start(); }; const stopSpin = () => { spinValue.stopAnimation(); spinValue.setValue(0); }; const spin = spinValue.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"], }); const handleManualRefresh = async () => { try { setRefreshing(true); startSpin(); await dispatch(clearUser()); await dispatch(getUserDetails()).unwrap(); await dispatch(getPaymentSummary()).unwrap(); console.log("Manual refresh complete"); } catch (error) { console.error("Manual refresh failed", error); } finally { stopSpin(); setRefreshing(false); } }; const { daysLeftToPayEmi, daysLeftToPayEmiText, regularServiceDueInDaysText, due_amount, } = paymentSummary || {}; useEffect(() => { if (paymentSummary?.due_amount != null) { dispatch(setDueAmount(paymentSummary.due_amount)); } }, [paymentSummary, dispatch]); return ( {daysLeftToPayEmi != undefined && Boolean(daysLeftToPayEmi && daysLeftToPayEmi > 0) && ( = payments.EMI_WARNING_DAYS_THRESHOLD ? "warning" : "danger" } message={`${daysLeftToPayEmi} ${t("home.days-left-to-pay-emi")}`} subMessage={t("home.pay-now")} redirectPath="/(tabs)/payments" /> )} {regularServiceDueInDaysText && Boolean( regularServiceDueInDaysText && regularServiceDueInDaysText.trim() !== "" ) && ( )} {due_amount && due_amount > 0 ? ( { router.push("/payments/selectAmount"); }} /> ) : due_amount == 0 ? ( router.push("/(tabs)/payments")} /> ) : null} {loading ? ( {t("home.fetching-location")} ) : lat != null && lon != null && !(lat == 0 && lon == 0) ? ( <> {t("home.view-vehicle-location")} ) : ( {t("home.error-location")} )} {warrantyEndDate && warrantyStartDate && ( router.push("/(tabs)/my-battery")}> )} setIsSupportModalVisible(false)} /> ); } const mapStyle = [ { elementType: "geometry", stylers: [{ color: "#242f3e" }] }, { elementType: "labels.text.fill", stylers: [{ color: "#746855" }] }, { elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] }, { featureType: "administrative.locality", elementType: "labels.text.fill", stylers: [{ color: "#d59563" }], }, { featureType: "poi", elementType: "labels.text.fill", stylers: [{ color: "#d59563" }], }, { featureType: "poi.park", elementType: "geometry", stylers: [{ color: "#263c3f" }], }, { featureType: "poi.park", elementType: "labels.text.fill", stylers: [{ color: "#6b9a76" }], }, { featureType: "road", elementType: "geometry", stylers: [{ color: "#38414e" }], }, { featureType: "road", elementType: "geometry.stroke", stylers: [{ color: "#212a37" }], }, { featureType: "road", elementType: "labels.text.fill", stylers: [{ color: "#9ca5b3" }], }, { featureType: "road.highway", elementType: "geometry", stylers: [{ color: "#746855" }], }, { featureType: "road.highway", elementType: "geometry.stroke", stylers: [{ color: "#1f2835" }], }, { featureType: "road.highway", elementType: "labels.text.fill", stylers: [{ color: "#f3d19c" }], }, { featureType: "transit", elementType: "geometry", stylers: [{ color: "#2f3948" }], }, { featureType: "transit.station", elementType: "labels.text.fill", stylers: [{ color: "#d59563" }], }, { featureType: "water", elementType: "geometry", stylers: [{ color: "#17263c" }], }, { featureType: "water", elementType: "labels.text.fill", stylers: [{ color: "#515c6d" }], }, { featureType: "water", elementType: "labels.text.stroke", stylers: [{ color: "#17263c" }], }, ]; const styles = StyleSheet.create({ logo: { width: "100%", height: "100%", resizeMode: "contain", }, logoContainer: { padding: 8, borderRadius: 44 / 2, // make it perfectly round borderWidth: 2, borderColor: "#E5E9F0", width: 44, height: 44, alignItems: "center", justifyContent: "center", overflow: "hidden", // ensures image doesn't overflow }, errorText: { color: "#565F70", fontWeight: "400", fontSize: 16, textAlign: "center", }, errorContainer: { height: 255, justifyContent: "center", alignItems: "center", backgroundColor: "#FCFCFC", gap: 8, }, viewLocationText: { color: "#388E3C", fontWeight: "600", fontSize: 16, textAlign: "center", marginTop: 8, }, map: { padding: 12, borderRadius: 10, overflow: "hidden", backgroundColor: "#fff", }, mapContainer: { height: 255, }, mapStyle: { width: "100%", height: "100%", borderRadius: 10, }, metrics: { flexDirection: "row", justifyContent: "space-between", backgroundColor: "#F3F5F8", }, container: { padding: 16, gap: 16, paddingBottom: 110, }, iconContainer: { backgroundColor: "#FCFCFC", }, supportButton: { backgroundColor: "#F3F5F8", }, headerTitleContainer: { flexDirection: "row", backgroundColor: "#F3F5F8", gap: 8, }, title: { fontSize: 14, color: "#6B7280", fontWeight: "500", }, subtitle: { fontSize: 18, color: "#111827", fontWeight: "700", }, rightContainer: { flexDirection: "row", alignItems: "center", paddingRight: 16, gap: 4, backgroundColor: "#F3F5F8", }, badge: { backgroundColor: "#FEE2E2", borderRadius: 20, width: 30, height: 30, justifyContent: "center", alignItems: "center", }, badgeText: { color: "#DC2626", fontWeight: "700", }, });