From d1fbd92b2e904b025aebabe5bead824334a51285 Mon Sep 17 00:00:00 2001 From: vinay kumar Date: Thu, 10 Jul 2025 13:57:20 +0530 Subject: [PATCH] Complete the home, profile and battery screens --- app/(tabs)/_layout.tsx | 21 ++++- app/(tabs)/index.tsx | 39 ++++++--- app/(tabs)/my-battery.tsx | 176 ++++++++++++++++++++++++++++++++++---- app/user/_layout.tsx | 2 +- package-lock.json | 39 +++++++++ package.json | 2 + 6 files changed, 247 insertions(+), 32 deletions(-) diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 730b8a0..8496bee 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -2,16 +2,18 @@ import React, { useEffect } from "react"; import { Tabs } from "expo-router"; import { useTabConfig } from "@/constants/config"; import { useSelector } from "react-redux"; -import { RootState } from "@/store"; +import { AppDispatch, RootState } from "@/store"; import { initSocket } from "@/services/socket"; import { useSnackbar } from "@/contexts/Snackbar"; import NetInfo from "@react-native-community/netinfo"; +import { getUserDetails } from "@/store/userSlice"; +import { useDispatch } from "react-redux"; export default function TabLayout() { const { isLoggedIn } = useSelector((state: RootState) => state.auth); if (!isLoggedIn) return null; const TAB_CONFIG = useTabConfig(); - + const dispatch = useDispatch(); const { showSnackbar } = useSnackbar(); useEffect(() => { const unsubscribe = NetInfo.addEventListener((state) => { @@ -29,7 +31,20 @@ export default function TabLayout() { }, []); useEffect(() => { - initSocket(); + const fetchAndInit = async () => { + try { + const result = await dispatch(getUserDetails()).unwrap(); + console.log("User details fetched", result); + initSocket(); + } catch (error) { + console.error("Failed to fetch user details", error); + showSnackbar("Failed to fetch user details", "error"); + } + }; + + if (isLoggedIn) { + fetchAndInit(); + } }, [isLoggedIn]); return ( state.telemetry); + const { data } = useSelector((state: RootState) => state.user); 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; const step = 0.001; useEffect(() => { @@ -83,8 +99,8 @@ export default function HomeScreen() { navigation.setOptions({ headerTitle: () => ( - Yatri - NBX 600 - DL253C3602 + {model} + {chasisNumber} ), headerRight: () => ( @@ -104,7 +120,7 @@ export default function HomeScreen() { }} > router.push("/user/profile")} textSize={20} boxSize={40} @@ -113,7 +129,7 @@ export default function HomeScreen() { ), }); - }, [navigation]); + }, [navigation, data, model, chasisNumber]); const openInGoogleMaps = () => { const url = `https://www.google.com/maps/search/?api=1&query=${lat},${lon}`; @@ -199,13 +215,12 @@ export default function HomeScreen() { ) )} - - + {warrantyEndDate && warrantyStartDate && ( + + )} { + const { data } = useSelector((state: RootState) => state.user); -import { Text, View } from "react-native"; + const model = data?.batteries[0]?.battery_model ?? "---"; + const batteryId = data?.batteries[0]?.battery_id ?? "---"; + const bmsId = data?.batteries[0]?.bms_id ?? "---"; + const warrantyStartDate = data?.batteries[0]?.warranty_start_date ?? "---"; + const warrantyEndDate = data?.batteries[0]?.warranty_end_date ?? "---"; + const vimId = data?.batteries[0]?.vim_id ?? "---"; + const serialNumber = data?.batteries[0]?.serial_no ?? "---"; + const chargerUid = data?.batteries[0]?.charger_uid ?? "---"; + const start = new Date(warrantyStartDate); + const end = new Date(warrantyEndDate); + const now = new Date(); -export default function MyBatteryTabScreen() { - return ( - - Coming Soon - + const totalDuration = end.getTime() - start.getTime(); + const elapsed = now.getTime() - start.getTime(); + const remaining = Math.max(end.getTime() - now.getTime(), 0); + + const progress = Math.min(elapsed / totalDuration, 1); + + const yearsLeft = Math.floor(remaining / (365.25 * 24 * 60 * 60 * 1000)); + const monthsLeft = Math.floor( + (remaining % (365.25 * 24 * 60 * 60 * 1000)) / (30.44 * 24 * 60 * 60 * 1000) ); -} + const daysLeft = Math.floor( + (remaining % (30.44 * 24 * 60 * 60 * 1000)) / (24 * 60 * 60 * 1000) + ); + + const formatDate = (date: Date): string => + date.toLocaleDateString("en-GB", { + day: "2-digit", + month: "short", + year: "numeric", + }); + + return ( + + {/* Battery Card */} + + + Battery + + In Warranty + + + + + + + + + {/* Warranty Details */} + + Battery Warranty Details + + + + + + + + + + {/* VIM Details */} + + VIM Details + + + + + + {/* Charger Details */} + + Charger Details + + + + + ); +}; + +type InfoRowProps = { + label: string; + value: string; +}; + +const InfoRow: React.FC = ({ label, value }) => ( + + {label} + {value} + +); + +export default BatteryDetails; const styles = StyleSheet.create({ container: { - flex: 1, + backgroundColor: "#F3F5F8", + padding: 16, + }, + card: { + backgroundColor: "#FCFCFC", + borderRadius: 8, + padding: 12, + marginBottom: 16, + }, + cardHeader: { + flexDirection: "row", + justifyContent: "space-between", alignItems: "center", - justifyContent: "center", }, - title: { - fontSize: 20, - fontWeight: "bold", + cardTitle: { + fontSize: 14, + fontWeight: "600", + color: "#252A34", }, - separator: { - marginVertical: 30, + badge: { + backgroundColor: "#DAF5ED", + paddingVertical: 2, + paddingHorizontal: 8, + borderRadius: 4, + }, + badgeText: { + fontSize: 12, + fontWeight: "500", + color: "#006C4D", + }, + divider: { height: 1, - width: "80%", + backgroundColor: "#e5e9f0", + marginVertical: 12, + }, + infoRow: { + flexDirection: "row", + justifyContent: "space-between", + paddingVertical: 4, + }, + label: { + fontSize: 14, + color: "#252A34", + }, + value: { + fontSize: 14, + fontWeight: "600", + color: "#252A34", + }, + progressBarBackground: { + height: 8, + backgroundColor: "#E5E9F0", + borderRadius: 10, + overflow: "hidden", + marginTop: 16, + }, + progressBarFill: { + height: 8, + backgroundColor: "#00825B", + borderRadius: 10, }, }); diff --git a/app/user/_layout.tsx b/app/user/_layout.tsx index 7b70e6f..ea84fc7 100644 --- a/app/user/_layout.tsx +++ b/app/user/_layout.tsx @@ -17,7 +17,7 @@ export default function AuthLayout() { }} /> = 16.0.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-gesture-handler": { "version": "2.26.0", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.26.0.tgz", diff --git a/package.json b/package.json index 29a92cd..84838ac 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "expo": "^53.0.13", "expo-constants": "~17.1.6", "expo-font": "~13.3.1", + "expo-image-picker": "~16.1.4", "expo-linking": "~7.1.5", "expo-router": "~5.1.1", "expo-secure-store": "^14.2.3", @@ -36,6 +37,7 @@ "react-dom": "19.0.0", "react-i18next": "^15.5.3", "react-native": "0.79.4", + "react-native-element-dropdown": "^2.12.4", "react-native-maps": "^1.24.3", "react-native-otp-entry": "^1.8.5", "react-native-paper": "^5.14.5",