Complete the home page with translation
parent
faadc33a7e
commit
6db5b1355b
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Tabs } from "expo-router";
|
||||
import { TAB_CONFIG } from "@/constants/config";
|
||||
import { useTabConfig } from "@/constants/config";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "@/store";
|
||||
import { initSocket } from "@/services/socket";
|
||||
|
|
@ -8,6 +8,7 @@ import { initSocket } from "@/services/socket";
|
|||
export default function TabLayout() {
|
||||
const { isLoggedIn } = useSelector((state: RootState) => state.auth);
|
||||
if (!isLoggedIn) return null;
|
||||
const TAB_CONFIG = useTabConfig();
|
||||
|
||||
useEffect(() => {
|
||||
initSocket();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
import { Pressable, StyleSheet } from "react-native";
|
||||
import {
|
||||
Pressable,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
} from "react-native";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SemiCircleProgress from "../../components/home/SemiCircleProgress";
|
||||
import { Text, View } from "@/components/Themed";
|
||||
|
|
@ -15,12 +20,14 @@ import BatteryWarrantyCard from "@/components/home/BatteryWarrantyCars";
|
|||
import CustomerSupportModal from "@/components/home/CustomerSupportModal";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "@/store";
|
||||
import LocationOff from "@/assets/icons/location_off.svg";
|
||||
import { Linking } from "react-native";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const { t } = useTranslation();
|
||||
const navigation = useNavigation();
|
||||
const [isSupportModalVisible, setIsSupportModalVisible] = useState(false);
|
||||
const { SoC, SoH, chargingState } = useSelector(
|
||||
const { SoC, SoH, chargingState, lat, lon, loading, error } = useSelector(
|
||||
(state: RootState) => state.telemetry
|
||||
);
|
||||
|
||||
|
|
@ -46,10 +53,17 @@ export default function HomeScreen() {
|
|||
});
|
||||
}, [navigation]);
|
||||
|
||||
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)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<View style={{ flex: 1, backgroundColor: "#F3F5F8" }}>
|
||||
<StatusBar style="dark" />
|
||||
<View style={styles.container}>
|
||||
<ScrollView contentContainerStyle={styles.container} style={{ flex: 1 }}>
|
||||
<ServiceReminderCard
|
||||
type="info"
|
||||
message="Service will be due in 3 days"
|
||||
|
|
@ -59,14 +73,28 @@ export default function HomeScreen() {
|
|||
<SemiCircleProgress progress={SoC} status={chargingState} />
|
||||
</View>
|
||||
<View style={styles.metrics}>
|
||||
<MetricCard heading="SoH" value={SoH} unit="%" />
|
||||
<MetricCard heading="Total Distance" value={20009} unit="km" />
|
||||
<MetricCard heading={t("home.battery-health")} value={SoH} unit="%" />
|
||||
<MetricCard
|
||||
heading={t("home.total-distance")}
|
||||
value={20009}
|
||||
unit="km"
|
||||
/>
|
||||
</View>
|
||||
<PaymentDueCard
|
||||
label="Payment Due"
|
||||
amount="$2,000"
|
||||
onPress={() => {}}
|
||||
onPress={() => {
|
||||
alert("le is number pe bhej de 8685846459");
|
||||
}}
|
||||
/>
|
||||
<View style={styles.map}>
|
||||
{loading ? (
|
||||
<View style={styles.errorContainer}>
|
||||
<LocationOff />
|
||||
<Text style={styles.errorText}>Fetching Location...</Text>
|
||||
</View>
|
||||
) : lat && lon ? (
|
||||
<>
|
||||
<View style={styles.mapContainer}>
|
||||
<MapView
|
||||
style={styles.mapStyle}
|
||||
|
|
@ -81,16 +109,35 @@ export default function HomeScreen() {
|
|||
<Marker
|
||||
draggable
|
||||
coordinate={{
|
||||
latitude: 37.78825,
|
||||
longitude: -122.4324,
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
}}
|
||||
anchor={{ x: 0.5, y: 0.5 }}
|
||||
onDragEnd={(e) => alert(JSON.stringify(e.nativeEvent.coordinate))}
|
||||
onDragEnd={(e) =>
|
||||
alert(JSON.stringify(e.nativeEvent.coordinate))
|
||||
}
|
||||
title={"Test Marker"}
|
||||
description={"This is a description of the marker"}
|
||||
image={require("../../assets/icons/marker.png")}
|
||||
/>
|
||||
</MapView>
|
||||
</View>
|
||||
<TouchableOpacity>
|
||||
<Text
|
||||
style={styles.viewLocationText}
|
||||
onPress={openInGoogleMaps}
|
||||
>
|
||||
View Vehicle Location
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
) : (
|
||||
<View style={styles.errorContainer}>
|
||||
<LocationOff />
|
||||
<Text style={styles.errorText}>Error fetching location</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<BatteryWarrantyCard
|
||||
totalWarrantyYears={8}
|
||||
|
|
@ -98,12 +145,12 @@ export default function HomeScreen() {
|
|||
new Date("2023-06-30").getTime() / 1000
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<CustomerSupportModal
|
||||
visible={isSupportModalVisible}
|
||||
onClose={() => setIsSupportModalVisible(false)}
|
||||
/>
|
||||
</>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -189,17 +236,39 @@ const mapStyle = [
|
|||
];
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
mapContainer: {
|
||||
flex: 1,
|
||||
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: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
borderRadius: 10,
|
||||
},
|
||||
metrics: {
|
||||
flexDirection: "row",
|
||||
|
|
@ -207,10 +276,9 @@ const styles = StyleSheet.create({
|
|||
backgroundColor: "#F3F5F8",
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#F3F5F8",
|
||||
padding: 16,
|
||||
gap: 16,
|
||||
paddingBottom: 110,
|
||||
},
|
||||
iconContainer: {
|
||||
backgroundColor: "#fff",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ export default function RootLayout() {
|
|||
if (!lang) {
|
||||
setShouldRedirect(true);
|
||||
}
|
||||
|
||||
setAppIsReady(true);
|
||||
};
|
||||
|
||||
|
|
@ -36,16 +35,16 @@ export default function RootLayout() {
|
|||
useEffect(() => {
|
||||
if (appIsReady) {
|
||||
SplashScreen.hideAsync();
|
||||
router.replace("/auth/login");
|
||||
router.replace("/init/language");
|
||||
}
|
||||
}, [appIsReady]);
|
||||
|
||||
useEffect(() => {
|
||||
if (appIsReady && shouldRedirect) {
|
||||
router.replace("/init/language");
|
||||
setShouldRedirect(false);
|
||||
}
|
||||
}, [appIsReady, shouldRedirect]);
|
||||
// useEffect(() => {
|
||||
// if (appIsReady && shouldRedirect) {
|
||||
// router.replace("/init/language");
|
||||
// setShouldRedirect(false);
|
||||
// }
|
||||
// }, [appIsReady, shouldRedirect]);
|
||||
|
||||
if (!appIsReady) {
|
||||
return null;
|
||||
|
|
@ -58,7 +57,12 @@ function RootLayoutNav() {
|
|||
return (
|
||||
<Provider store={store}>
|
||||
<I18nextProvider i18n={i18next}>
|
||||
<Stack>
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
animation: "fade",
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
</Stack>
|
||||
</I18nextProvider>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import { Stack } from "expo-router";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import { View, StyleSheet } from "react-native";
|
||||
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import GoBack from "@/assets/icons/chevron_left.svg";
|
||||
import { useRouter } from "expo-router";
|
||||
|
||||
export default function AuthLayout() {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<SafeAreaView style={styles.container} edges={["top"]}>
|
||||
<StatusBar style="dark" />
|
||||
<Stack
|
||||
screenOptions={{
|
||||
|
|
@ -12,10 +16,44 @@ export default function AuthLayout() {
|
|||
animation: "fade",
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<Stack.Screen
|
||||
name="login"
|
||||
options={{
|
||||
headerShown: true,
|
||||
title: "",
|
||||
headerShadowVisible: false,
|
||||
headerLeft: () => {
|
||||
return (
|
||||
<TouchableOpacity onPress={() => router.back()}>
|
||||
<GoBack />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
},
|
||||
headerStyle: {
|
||||
backgroundColor: "#F3F5F8",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// navigation.setOptions({
|
||||
// headerShown: true,
|
||||
// title: "",
|
||||
// headerLeft: () => {
|
||||
// return (
|
||||
// <TouchableOpacity onPress={() => router.back()}>
|
||||
// <GoBack />
|
||||
// </TouchableOpacity>
|
||||
// );
|
||||
// },
|
||||
// headerShadowVisible: false,
|
||||
// headerStyle: {
|
||||
// backgroundColor: "#F3F5F8",
|
||||
// },
|
||||
// });
|
||||
// }, []);
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
Keyboard,
|
||||
KeyboardAvoidingView,
|
||||
StatusBar,
|
||||
Linking,
|
||||
} from "react-native";
|
||||
import { useRouter } from "expo-router";
|
||||
import { Formik } from "formik";
|
||||
|
|
@ -19,6 +20,9 @@ import { AppDispatch } from "../../store";
|
|||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../../store";
|
||||
import { AUTH_STATUSES } from "@/constants/types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SUPPORT } from "@/constants/config";
|
||||
// import { useNavigation } from "expo-router";
|
||||
|
||||
// type VerifyOTPNavigationProp = StackNavigationProp<
|
||||
// RootStackParamList,
|
||||
|
|
@ -35,16 +39,16 @@ export default function WelcomeScreen() {
|
|||
phone: phoneNumber,
|
||||
sendOTPError,
|
||||
} = useSelector((state: RootState) => state.auth);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const router = useRouter();
|
||||
// const navigation = useNavigation();
|
||||
|
||||
const phoneValidationSchema = Yup.object().shape({
|
||||
phone: Yup.string()
|
||||
.required("Phone number is required")
|
||||
.matches(/^\d{10}$/, "Phone number must be exactly 10 digits"),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (status === AUTH_STATUSES.SUCCESS && otpId) {
|
||||
router.push({
|
||||
|
|
@ -54,12 +58,16 @@ export default function WelcomeScreen() {
|
|||
}
|
||||
}, [status, otpId, router]);
|
||||
|
||||
const makePhoneCall = () => {
|
||||
Linking.openURL(`tel:${SUPPORT.PHONE}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView style={styles.container} behavior="padding">
|
||||
<StatusBar barStyle="dark-content" backgroundColor="#F3F5F8" />
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
||||
<View style={styles.inner}>
|
||||
<Text style={styles.title}>Welcome to Driver Saathi</Text>
|
||||
<Text style={styles.title}>{t("onboarding.welcome")}</Text>
|
||||
|
||||
<Formik
|
||||
initialValues={{ phone: "" }}
|
||||
|
|
@ -75,7 +83,9 @@ export default function WelcomeScreen() {
|
|||
touched,
|
||||
}) => (
|
||||
<View style={styles.form}>
|
||||
<Text style={styles.label}>Phone Number</Text>
|
||||
<Text style={styles.label}>
|
||||
{t("onboarding.enter-mobile-number")}
|
||||
</Text>
|
||||
<TextInput
|
||||
style={{
|
||||
...styles.input,
|
||||
|
|
@ -90,7 +100,8 @@ export default function WelcomeScreen() {
|
|||
onBlur={handleBlur("phone")}
|
||||
value={values.phone}
|
||||
keyboardType="numeric"
|
||||
placeholder="Enter your registered phone number"
|
||||
placeholder={t("onboarding.enter-registered-mobile-number")}
|
||||
placeholderTextColor={"#949CAC"}
|
||||
/>
|
||||
<View style={styles.errorContainer}>
|
||||
{touched.phone && errors.phone && (
|
||||
|
|
@ -100,6 +111,14 @@ export default function WelcomeScreen() {
|
|||
<Text style={styles.error}>{sendOTPError}</Text>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.contactContainer}>
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
<Text>For any queries, </Text>
|
||||
<TouchableOpacity onPress={makePhoneCall}>
|
||||
<Text style={styles.link}>contact us.</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={handleSubmit as unknown as () => void}
|
||||
style={{
|
||||
|
|
@ -117,7 +136,9 @@ export default function WelcomeScreen() {
|
|||
status === AUTH_STATUSES.LOADING
|
||||
}
|
||||
>
|
||||
<Text style={styles.buttonText}>Send OTP</Text>
|
||||
<Text style={styles.buttonText}>
|
||||
{t("onboarding.send-otp")}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
|
|
@ -129,6 +150,19 @@ export default function WelcomeScreen() {
|
|||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
contactContainer: {
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
position: "absolute",
|
||||
bottom: 110, // slightly above the "Send OTP" button
|
||||
},
|
||||
link: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
lineHeight: 20,
|
||||
color: "#1249ED",
|
||||
},
|
||||
errorContainer: {
|
||||
flexDirection: "column",
|
||||
gap: 8,
|
||||
|
|
@ -186,10 +220,10 @@ const styles = StyleSheet.create({
|
|||
label: {
|
||||
fontSize: 14,
|
||||
marginBottom: 8,
|
||||
color: "#717B8C",
|
||||
color: "#252A34",
|
||||
fontFamily: "Inter",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "bold",
|
||||
fontWeight: "normal",
|
||||
lineHeight: 20,
|
||||
},
|
||||
input: {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { Text, View, StyleSheet, TouchableOpacity } from "react-native";
|
|||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { AppDispatch, RootState } from "../../store";
|
||||
import { clearVerifyOTPError, sendOTP, verifyOTP } from "../../store/authSlice";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { OtpInput } from "react-native-otp-entry";
|
||||
import { useRouter } from "expo-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { AUTH_STATUSES } from "@/constants/types";
|
||||
|
||||
export default function VerifyOTP() {
|
||||
|
|
@ -20,6 +20,8 @@ export default function VerifyOTP() {
|
|||
const [resendAttempts, setResendAttempts] = useState(0);
|
||||
const maxResendAttempts = 5;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(clearVerifyOTPError());
|
||||
}, []);
|
||||
|
|
@ -57,12 +59,10 @@ export default function VerifyOTP() {
|
|||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.heading}>Verify Code</Text>
|
||||
<Text style={styles.heading}>{t("onboarding.verify-otp")}</Text>
|
||||
<View style={styles.body}>
|
||||
<Text>
|
||||
<Text style={styles.order}>
|
||||
Please enter verification code that we've sent to your number
|
||||
</Text>
|
||||
<Text style={styles.order}>{t("onboarding.enter-otp")}</Text>
|
||||
<Text style={styles.phone}> +91 ********{phone?.slice(-2)}.</Text>
|
||||
</Text>
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ export default function VerifyOTP() {
|
|||
<View style={styles.otpResend}>
|
||||
{isTimerActive ? (
|
||||
<Text>
|
||||
<Text style={styles.otpText}>Resend OTP in </Text>
|
||||
<Text style={styles.otpText}>{t("onboarding.resend-otp")}</Text>{" "}
|
||||
<Text style={styles.timer}>00:{formattedSeconds}</Text>
|
||||
</Text>
|
||||
) : (
|
||||
|
|
@ -113,7 +113,7 @@ export default function VerifyOTP() {
|
|||
: "#B0B7C5",
|
||||
}}
|
||||
>
|
||||
Resend OTP
|
||||
{t("onboarding.resend-otp")}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const LanguageScreen = () => {
|
|||
const handleSelect = async () => {
|
||||
if (selectedLang) {
|
||||
await setLanguage(selectedLang);
|
||||
router.replace("/auth/login");
|
||||
router.navigate("/auth/login");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_213_3296" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
|
||||
<rect width="24" height="24" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_213_3296)">
|
||||
<path d="M10.8001 12L14.7001 15.9C14.8834 16.0833 14.9751 16.3166 14.9751 16.6C14.9751 16.8833 14.8834 17.1166 14.7001 17.3C14.5168 17.4833 14.2834 17.575 14.0001 17.575C13.7168 17.575 13.4834 17.4833 13.3001 17.3L8.7001 12.7C8.6001 12.6 8.52926 12.4916 8.4876 12.375C8.44593 12.2583 8.4251 12.1333 8.4251 12C8.4251 11.8666 8.44593 11.7416 8.4876 11.625C8.52926 11.5083 8.6001 11.4 8.7001 11.3L13.3001 6.69995C13.4834 6.51662 13.7168 6.42495 14.0001 6.42495C14.2834 6.42495 14.5168 6.51662 14.7001 6.69995C14.8834 6.88328 14.9751 7.11662 14.9751 7.39995C14.9751 7.68328 14.8834 7.91662 14.7001 8.09995L10.8001 12Z" fill="#565F70"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 939 B |
|
|
@ -0,0 +1,8 @@
|
|||
<svg width="49" height="48" viewBox="0 0 49 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_14_4139" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="49" height="48">
|
||||
<rect x="0.167969" width="48" height="48" fill="#D9D9D9"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_14_4139)">
|
||||
<path d="M24.1684 42.65C23.7017 42.65 23.235 42.5667 22.7684 42.4C22.3017 42.2333 21.885 41.9833 21.5184 41.65C19.3517 39.65 17.435 37.7 15.7684 35.8C14.1017 33.9 12.71 32.0583 11.5934 30.275C10.4767 28.4917 9.62669 26.775 9.04336 25.125C8.46003 23.475 8.16836 21.9 8.16836 20.4C8.16836 19.3333 8.25169 18.3167 8.41836 17.35C8.58503 16.3833 8.81836 15.4667 9.11836 14.6L2.91836 8.4C2.51836 8 2.31836 7.525 2.31836 6.975C2.31836 6.425 2.51836 5.95 2.91836 5.55C3.31836 5.15 3.79336 4.95 4.34336 4.95C4.89336 4.95 5.36836 5.15 5.76836 5.55L42.5684 42.35C42.9684 42.75 43.1684 43.225 43.1684 43.775C43.1684 44.325 42.9684 44.8 42.5684 45.2C42.1684 45.6 41.6934 45.8 41.1434 45.8C40.5934 45.8 40.1184 45.6 39.7184 45.2L31.5184 37C30.685 37.8667 29.8517 38.725 29.0184 39.575C28.185 40.425 27.4517 41.1167 26.8184 41.65C26.4517 41.9833 26.035 42.2333 25.5684 42.4C25.1017 42.5667 24.635 42.65 24.1684 42.65ZM24.1684 4C28.4017 4 32.1267 5.48333 35.3434 8.45C38.56 11.4167 40.1684 15.4 40.1684 20.4C40.1684 21.5667 40.0017 22.775 39.6684 24.025C39.335 25.275 38.835 26.5667 38.1684 27.9C37.8017 28.6333 37.21 29.0417 36.3934 29.125C35.5767 29.2083 34.885 28.9667 34.3184 28.4L27.7184 21.8C27.885 21.5333 28.0017 21.25 28.0684 20.95C28.135 20.65 28.1684 20.3333 28.1684 20C28.1684 19.4333 28.0684 18.9083 27.8684 18.425C27.6684 17.9417 27.385 17.5167 27.0184 17.15C26.6517 16.7833 26.2267 16.5 25.7434 16.3C25.26 16.1 24.735 16 24.1684 16C23.835 16 23.5184 16.0333 23.2184 16.1C22.9184 16.1667 22.635 16.2833 22.3684 16.45L15.9184 10C15.3184 9.4 15.06 8.69167 15.1434 7.875C15.2267 7.05833 15.6184 6.43333 16.3184 6C17.485 5.33333 18.735 4.83333 20.0684 4.5C21.4017 4.16667 22.7684 4 24.1684 4Z" fill="#949CAC"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 816 B |
|
|
@ -0,0 +1,88 @@
|
|||
import React from "react";
|
||||
import { View, Text, StyleSheet, ViewStyle } from "react-native";
|
||||
|
||||
interface BatteryStatusProps {
|
||||
status: 1 | 0 | -1 | null;
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
const BatteryStatus: React.FC<BatteryStatusProps> = ({ status, style }) => {
|
||||
const getStatusConfig = (): {
|
||||
text: string;
|
||||
backgroundColor: string;
|
||||
textColor: string;
|
||||
} => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return {
|
||||
text: "Charging",
|
||||
backgroundColor: "#006C4D",
|
||||
textColor: "#006C4D",
|
||||
};
|
||||
case -1:
|
||||
return {
|
||||
text: "Discharging",
|
||||
backgroundColor: "#E5EBFD",
|
||||
textColor: "#1249ED",
|
||||
};
|
||||
case 0:
|
||||
return {
|
||||
text: "Idle",
|
||||
backgroundColor: "#565F70",
|
||||
textColor: "#565F70",
|
||||
};
|
||||
case null:
|
||||
return {
|
||||
text: "---",
|
||||
backgroundColor: "#e2e3e5",
|
||||
textColor: "#6c757d",
|
||||
};
|
||||
default:
|
||||
return {
|
||||
text: "Unknown",
|
||||
backgroundColor: "#f8f9fa",
|
||||
textColor: "#6c757d",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const config = getStatusConfig();
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: config.backgroundColor,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
{
|
||||
color: config.textColor,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{config.text}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4,
|
||||
justifyContent: "center",
|
||||
},
|
||||
text: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
},
|
||||
});
|
||||
|
||||
export default BatteryStatus;
|
||||
|
|
@ -3,6 +3,7 @@ import { BmsState } from "@/constants/types";
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { View, StyleSheet, Text, Animated } from "react-native";
|
||||
import Svg, { Circle, Defs, LinearGradient, Stop } from "react-native-svg";
|
||||
import BatteryStatus from "./ChargingStateLabel";
|
||||
|
||||
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
||||
|
||||
|
|
@ -11,7 +12,7 @@ const CircleProgressBar = ({
|
|||
status,
|
||||
}: {
|
||||
progress: number | null;
|
||||
status: number | null;
|
||||
status: -1 | 0 | 1 | null;
|
||||
}) => {
|
||||
const radius = 20;
|
||||
const strokeWidth = 5;
|
||||
|
|
@ -99,16 +100,14 @@ const CircleProgressBar = ({
|
|||
</Svg>
|
||||
<View style={styles.batteryPercent}>
|
||||
<Text style={{ fontSize: 60, fontWeight: "bold", fontFamily: "Inter" }}>
|
||||
{progress ? displayProgress : "--"}
|
||||
{progress ? displayProgress : "---"}
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: "bold" }}>
|
||||
{progress === undefined ? null : "%"}
|
||||
{progress == null ? "" : "%"}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.batterySoc}>
|
||||
<Text style={{ fontSize: 14, fontWeight: "bold", color: "#565F70" }}>
|
||||
{status ? BMS_STATE_LABELS[status as BmsState] : "Unknown"}
|
||||
</Text>
|
||||
<BatteryStatus status={status} />
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import InfoIcon from "../assets/icons/error.svg";
|
|||
import WarningIcon from "../assets/icons/warning.svg";
|
||||
import DangerIcon from "../assets/icons/danger.svg";
|
||||
import type { BmsState } from "./types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default {
|
||||
ENV,
|
||||
|
|
@ -29,36 +30,40 @@ export const APP_CONFIG = {
|
|||
SUPPORTED_LANGUAGES: ["en", "hi"],
|
||||
};
|
||||
|
||||
export const TAB_CONFIG = [
|
||||
export const useTabConfig = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return [
|
||||
{
|
||||
name: "index",
|
||||
title: "Home",
|
||||
title: t("navigation.home"),
|
||||
Icon: HomeIcon,
|
||||
IconFilled: HomeIconFilled,
|
||||
path: "/",
|
||||
},
|
||||
{
|
||||
name: "payments",
|
||||
title: "Payments",
|
||||
title: t("navigation.payments"),
|
||||
Icon: PaymentsIcon,
|
||||
IconFilled: PaymentsIconFilled,
|
||||
path: "/payments",
|
||||
},
|
||||
{
|
||||
name: "service",
|
||||
title: "Service",
|
||||
title: t("navigation.service"),
|
||||
Icon: ServiceIcon,
|
||||
IconFilled: ServiceIconFilled,
|
||||
path: "/service",
|
||||
},
|
||||
{
|
||||
name: "my-battery",
|
||||
title: "My Battery",
|
||||
title: t("navigation.my-battery"),
|
||||
Icon: BatteryIcon,
|
||||
IconFilled: BatteryIconFilled,
|
||||
path: "/my-battery",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const MESSAGES = {
|
||||
AUTHENTICATION: {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
|
|
@ -16,30 +16,41 @@
|
|||
"@expo/vector-icons": "^14.1.0",
|
||||
"@react-native-async-storage/async-storage": "^2.2.0",
|
||||
"@react-navigation/native": "^7.1.6",
|
||||
"@react-navigation/stack": "^7.4.2",
|
||||
"@reduxjs/toolkit": "^2.8.2",
|
||||
"axios": "^1.10.0",
|
||||
"expo": "^53.0.13",
|
||||
"expo-constants": "~17.1.6",
|
||||
"expo-font": "~13.3.1",
|
||||
"expo-linking": "~7.1.5",
|
||||
"expo-router": "~5.1.1",
|
||||
"expo-secure-store": "^14.2.3",
|
||||
"expo-splash-screen": "~0.30.9",
|
||||
"expo-status-bar": "~2.2.3",
|
||||
"expo-system-ui": "~5.0.9",
|
||||
"expo-web-browser": "~14.2.0",
|
||||
"formik": "^2.4.6",
|
||||
"i18next": "^25.2.1",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-i18next": "^15.5.3",
|
||||
"react-native": "0.79.4",
|
||||
"react-native-dotenv": "^3.4.11",
|
||||
"react-native-maps": "^1.24.3",
|
||||
"react-native-otp-entry": "^1.8.5",
|
||||
"react-native-reanimated": "~3.17.4",
|
||||
"react-native-safe-area-context": "5.4.0",
|
||||
"react-native-safe-area-context": "^5.4.0",
|
||||
"react-native-screens": "~4.11.1",
|
||||
"react-native-svg": "15.11.2",
|
||||
"react-native-svg-transformer": "^1.5.1",
|
||||
"react-native-web": "~0.20.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-native-svg": "15.11.2"
|
||||
"socket.io-client": "^4.8.1",
|
||||
"yup": "^1.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@react-native-community/cli": "^18.0.0",
|
||||
"@types/react": "~19.0.10",
|
||||
"jest": "^29.2.1",
|
||||
"jest-expo": "~53.0.7",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,132 @@
|
|||
{
|
||||
"change-language": "Change language",
|
||||
"welcome": "Welcome to Driver Saathi"
|
||||
"onboarding": {
|
||||
"welcome": "Welcome to Driver Saathi",
|
||||
"enter-mobile-number": "Enter Mobile Number",
|
||||
"enter-registered-mobile-number": "Enter your registered mobile number",
|
||||
"number-not-registered": "Number not registered.",
|
||||
"enter-otp": "Please enter OTP sent to your mobile number",
|
||||
"verify-otp": "Verify OTP",
|
||||
"otp-incorrect": "OTP incorrect.",
|
||||
"resend-otp": "Resend OTP in",
|
||||
"verification-limit-exceeded": "Verification limit exceeded, try again later",
|
||||
"send-otp": "Send OTP"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"payments": "Payments",
|
||||
"service": "Service",
|
||||
"my-battery": "My Battery"
|
||||
},
|
||||
"home": {
|
||||
"vehicle-name": "Yatri - NBX 600",
|
||||
"vehicle-id": "DL253C3602",
|
||||
"battery-health": "SoH",
|
||||
"total-distance": "Total Distance",
|
||||
"payment-due": "Payment Due",
|
||||
"pay-now": "Pay Now",
|
||||
"error-location": "Error fetching location!",
|
||||
"battery-warranty-left": "Battery Warranty Left",
|
||||
"charging": "Charging",
|
||||
"discharging": "Discharging",
|
||||
"idle": "Idle",
|
||||
"payment-complete": "Payment Complete",
|
||||
"view-details": "View Details",
|
||||
"all-emi-paid": "All EMI Paid! Contact your dealer",
|
||||
"regular-service-due": "Regular service due in 3 days! Schedule now.",
|
||||
"view-vehicle-location": "View Vehicle Location",
|
||||
"battery-age": "7 years, 11 month, 29 days",
|
||||
"alerts": "Alerts",
|
||||
"emi-alert": "14 days left to pay the EMI!"
|
||||
},
|
||||
"profile": {
|
||||
"my-account": "My Account",
|
||||
"enter-name": "Enter Name",
|
||||
"name": "Amar Kesari",
|
||||
"mobile-number": "Mobile Number",
|
||||
"my-vehicle": "My Vehicle",
|
||||
"language": "Language",
|
||||
"about-app": "About App",
|
||||
"logout": "Logout",
|
||||
"edit-name": "Edit Name",
|
||||
"save": "Save",
|
||||
"name-changed": "Name changed successfully",
|
||||
"oem-model": "OEM - Model",
|
||||
"chassis-number": "Chassis Number",
|
||||
"vehicle-id": "Vehicle ID",
|
||||
"select-language": "Select Language",
|
||||
"customer-support": "Customer Support",
|
||||
"whatsapp": "Whatsapp",
|
||||
"call-us": "Call Us",
|
||||
"email": "Email"
|
||||
},
|
||||
"payment": {
|
||||
"last-emi-details": "Last EMI Details",
|
||||
"amount-due": "Amount Due",
|
||||
"amount-paid": "Amount Paid",
|
||||
"due-date": "Due Date",
|
||||
"payment-status": "Payment Status",
|
||||
"pay-emi": "Pay EMI",
|
||||
"payment-history": "Payment History",
|
||||
"no-payments": "No payments found!",
|
||||
"pending": "Pending",
|
||||
"total-amount-due": "Total Amount Due",
|
||||
"scan-to-pay": "Scan to pay your EMI with any UPI app",
|
||||
"upi-id": "UPI ID: randomupiid@vecpay",
|
||||
"share-qr": "Share QR",
|
||||
"download-qr": "Download QR",
|
||||
"my-plan": "My Plan",
|
||||
"plan-details": "Plan Details",
|
||||
"plan-type": "Plan Type",
|
||||
"total-cost": "Total Cost",
|
||||
"down-payment": "Down Payment",
|
||||
"total-emi": "Total EMI",
|
||||
"monthly-emi": "Monthly EMI",
|
||||
"installments-paid": "Installments Paid",
|
||||
"emi-paid-till-now": "EMI Paid Till Now",
|
||||
"transaction-detail": "Transaction Detail",
|
||||
"transaction-successful": "Transaction successful",
|
||||
"payment-mode": "Payment mode",
|
||||
"paid-to": "Paid to",
|
||||
"upi-transaction-id": "UPI Transaction ID",
|
||||
"all-emi-paid": "All EMI Paid",
|
||||
"contact-dealer": "For further queries, contact your dealer!",
|
||||
"view-all": "View all",
|
||||
"emi-completed": "EMI Completed",
|
||||
"plan-name": "18 Month Plan"
|
||||
},
|
||||
"service": {
|
||||
"schedule-maintenance": "Schedule Maintenance",
|
||||
"service-type": "Service Type: Regular",
|
||||
"issue": "Issue",
|
||||
"select-issue": "Select Issue",
|
||||
"select-datetime": "Select Date and Time",
|
||||
"select": "-Select-",
|
||||
"add-photos": "Add photos",
|
||||
"supported-formats": "Supported formats include JPG, JPEG and PNG.",
|
||||
"comments": "Comments",
|
||||
"submit": "Submit",
|
||||
"select-issues-tba": "Select issues ------(TBA)",
|
||||
"clear": "Clear",
|
||||
"issues-selected": "3 issue selected",
|
||||
"service-request-success": "Service request submitted successfully",
|
||||
"something-went-wrong": "Something went wrong!"
|
||||
},
|
||||
"battery": {
|
||||
"battery-and-warranty": "My Battery and Warranty",
|
||||
"battery": "Battery",
|
||||
"in-warranty": "In Warranty",
|
||||
"warranty-expired": "Warranty Expired",
|
||||
"model": "Model",
|
||||
"battery-id": "Battery ID",
|
||||
"bms-id": "BMS ID",
|
||||
"battery-warranty-details": "Battery Warranty Details",
|
||||
"start-date": "Start Date",
|
||||
"end-date": "End Date",
|
||||
"duration-left": "Duration Left",
|
||||
"vim-details": "VIM Details",
|
||||
"vim-id": "VIM ID",
|
||||
"serial-number": "Serial Number",
|
||||
"charger-details": "Charger Details",
|
||||
"uid": "UID"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,132 @@
|
|||
{
|
||||
"change-language": "भाषा बदलें",
|
||||
"welcome": "ड्राइवर साथी में आपका स्वागत है"
|
||||
"onboarding": {
|
||||
"welcome": "ड्राइवर साथी में आपका स्वागत है",
|
||||
"enter-mobile-number": "मोबाइल नंबर दर्ज करें",
|
||||
"enter-registered-mobile-number": "अपना पंजीकृत मोबाइल नंबर दर्ज करें",
|
||||
"number-not-registered": "नंबर पंजीकृत नहीं है।",
|
||||
"enter-otp": "कृपया अपने मोबाइल नंबर पर भेजा गया OTP दर्ज करें।",
|
||||
"verify-otp": "ओटीपी वेरिफाई करें",
|
||||
"otp-incorrect": "OTP गलत है।",
|
||||
"resend-otp": "OTP पुनः भेजें",
|
||||
"verification-limit-exceeded": "वेरिफिकेशन लिमिट पार हो गई है, बाद में फिर से कोशिश करो",
|
||||
"send-otp": "OTP भेजें"
|
||||
},
|
||||
"navigation": {
|
||||
"home": "होम",
|
||||
"payments": "भुगतान",
|
||||
"service": "सेवा",
|
||||
"my-battery": "मेरी बैटरी"
|
||||
},
|
||||
"home": {
|
||||
"vehicle-name": "यात्री - NBX 600",
|
||||
"vehicle-id": "DL253C3602",
|
||||
"battery-health": "बैटरी हेल्थ",
|
||||
"total-distance": "कुल दूरी",
|
||||
"payment-due": "भुगतान बकाया",
|
||||
"pay-now": "अभी भुगतान करें",
|
||||
"error-location": "स्थान प्राप्त करने में त्रुटि!",
|
||||
"battery-warranty-left": "बैटरी वारंटी शेष",
|
||||
"charging": "चार्जिंग",
|
||||
"discharging": "डिस्चार्जिंग",
|
||||
"idle": "निष्क्रिय",
|
||||
"payment-complete": "भुगतान पूर्ण",
|
||||
"view-details": "विवरण देखें",
|
||||
"all-emi-paid": "सभी EMI का भुगतान किया गया! अपने डीलर से संपर्क करें",
|
||||
"regular-service-due": "रेगुलर सर्विस 3 दिनों में होने वाली है! अभी शिड्यूल कर लो.",
|
||||
"view-vehicle-location": "वाहन का स्थान देखें",
|
||||
"battery-age": "7 वर्ष, 11 महीने, 29 दिन",
|
||||
"alerts": "अलर्ट",
|
||||
"emi-alert": "EMI का भुगतान करने के लिए 14 दिन शेष!"
|
||||
},
|
||||
"profile": {
|
||||
"my-account": "मेरा खाता",
|
||||
"enter-name": "नाम दर्ज करें",
|
||||
"name": "अमर केसरी",
|
||||
"mobile-number": "मोबाइल नंबर",
|
||||
"my-vehicle": "मेरा वाहन",
|
||||
"language": "भाषा",
|
||||
"about-app": "ऐप के बारे में",
|
||||
"logout": "लॉगआउट",
|
||||
"edit-name": "नाम बदलें",
|
||||
"save": "सहेजें",
|
||||
"name-changed": "नाम सफलतापूर्वक बदल दिया गया",
|
||||
"oem-model": "OEM - मॉडल",
|
||||
"chassis-number": "चेसिस नंबर",
|
||||
"vehicle-id": "वाहन आईडी",
|
||||
"select-language": "भाषा चुनें",
|
||||
"customer-support": "ग्राहक सहायता",
|
||||
"whatsapp": "व्हाट्सएप",
|
||||
"call-us": "हमें कॉल करें",
|
||||
"email": "ईमेल"
|
||||
},
|
||||
"payment": {
|
||||
"last-emi-details": "अंतिम EMI विवरण",
|
||||
"amount-due": "बकाया राशि",
|
||||
"amount-paid": "भुगतान की गई राशि",
|
||||
"due-date": "ड्यू डेट",
|
||||
"payment-status": "भुगतान की स्थिति",
|
||||
"pay-emi": "ईएमआई भुगतान करो",
|
||||
"payment-history": "पेमेंट हिस्ट्री",
|
||||
"no-payments": "कोई भुगतान नहीं मिला!",
|
||||
"pending": "पेंडिंग है",
|
||||
"total-amount-due": "कुल बकाया राशि",
|
||||
"scan-to-pay": "किसी भी UPI ऐप से अपने EMI का भुगतान करने के लिए स्कैन करें",
|
||||
"upi-id": "UPI ID: randomupiid@vecpay",
|
||||
"share-qr": "QR शेयर करें",
|
||||
"download-qr": "QR डाउनलोड करें",
|
||||
"my-plan": "मेरा प्लान",
|
||||
"plan-details": "योजना विवरण",
|
||||
"plan-type": "योजना प्रकार",
|
||||
"total-cost": "कुल लागत",
|
||||
"down-payment": "डाउन पेमेंट",
|
||||
"total-emi": "कुल EMI",
|
||||
"monthly-emi": "मासिक EMI",
|
||||
"installments-paid": "भुगतान की गई किश्तें",
|
||||
"emi-paid-till-now": "अभी तक भुगतान की गई EMI",
|
||||
"transaction-detail": "लेनदेन विवरण",
|
||||
"transaction-successful": "लेनदेन सफल",
|
||||
"payment-mode": "भुगतान मोड",
|
||||
"paid-to": "भुगतान किया गया",
|
||||
"upi-transaction-id": "यूपीआई ट्रांजैक्शन आईडी",
|
||||
"all-emi-paid": "सभी EMI का भुगतान किया गया",
|
||||
"contact-dealer": "अधिक जानकारी के लिए, अपने डीलर से संपर्क करें!",
|
||||
"view-all": "सभी देखें",
|
||||
"emi-completed": "EMI पूर्ण",
|
||||
"plan-name": "18 महीने की योजना"
|
||||
},
|
||||
"service": {
|
||||
"schedule-maintenance": "शेड्यूल मेंटेनेंस",
|
||||
"service-type": "सेवा प्रकार: नियमित",
|
||||
"issue": "समस्या",
|
||||
"select-issue": "समस्या का चयन करें",
|
||||
"select-datetime": "दिनांक और समय का चयन करें",
|
||||
"select": "-चुनें-",
|
||||
"add-photos": "फ़ोटो जोड़ें",
|
||||
"supported-formats": "समर्थित प्रारूपों में JPG, JPEG और PNG शामिल हैं।",
|
||||
"comments": "टिप्पणियाँ",
|
||||
"submit": "सबमिट करें",
|
||||
"select-issues-tba": "समस्याओं का चयन करें ------(TBA)",
|
||||
"clear": "साफ़ करें",
|
||||
"issues-selected": "3 समस्याएँ चुनी गई",
|
||||
"service-request-success": "सेवा अनुरोध सफलतापूर्वक सबमिट किया गया",
|
||||
"something-went-wrong": "कुछ गलत हो गया!"
|
||||
},
|
||||
"battery": {
|
||||
"battery-and-warranty": "मेरी बैटरी और वारंटी",
|
||||
"battery": "बैटरी",
|
||||
"in-warranty": "वारंटी में",
|
||||
"warranty-expired": "वारंटी समाप्त हो गई",
|
||||
"model": "मॉडल",
|
||||
"battery-id": "बैटरी आईडी",
|
||||
"bms-id": "BMS आईडी",
|
||||
"battery-warranty-details": "बैटरी वारंटी विवरण",
|
||||
"start-date": "आरंभ तिथि",
|
||||
"end-date": "समाप्ति तिथि",
|
||||
"duration-left": "अवधि शेष",
|
||||
"vim-details": "VIM विवरण",
|
||||
"vim-id": "VIM ID",
|
||||
"serial-number": "सीरियल नंबर",
|
||||
"charger-details": "चार्जर विवरण",
|
||||
"uid": "UID"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
import { io, Socket } from "socket.io-client";
|
||||
import { store } from "../store";
|
||||
import { updateTelemetry } from "../store/telemetrySlice";
|
||||
import {
|
||||
updateTelemetry,
|
||||
setTelemetryLoading,
|
||||
setTelemetryError,
|
||||
} from "../store/telemetrySlice";
|
||||
import { BmsState } from "@/constants/types";
|
||||
|
||||
const SERVER_URL =
|
||||
"http://dev.vec-tr.ai:8089/?dashboardId=deviceDashboardSocket&assetId=V16000868651064644504";
|
||||
const TOKEN =
|
||||
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiYWN0aW9uIjoiYXV0aCIsInRva2VuLXZlcnNpb24iOjAsImlhdCI6MTc1MTM0OTUwMSwiZXhwIjoxNzUxNDM1OTAxfQ.0BB0vRcFSMFDC6aILuc__pG3Ycy8EndYOAwLwCHji1M";
|
||||
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2NCIsImFjdGlvbiI6ImF1dGgiLCJ0b2tlbi12ZXJzaW9uIjowLCJpYXQiOjE3NTE0NTgxNDQsImV4cCI6MTc1MTU0NDU0NH0.ETM2hCU_5EtVcKAABd_69fyxS-FNuJ5Mv-QbY014sBY";
|
||||
|
||||
let socket: Socket | null = null;
|
||||
|
||||
export const initSocket = () => {
|
||||
store.dispatch(setTelemetryLoading());
|
||||
|
||||
socket = io(SERVER_URL, {
|
||||
transports: ["websocket"],
|
||||
extraHeaders: {
|
||||
|
|
@ -26,10 +32,12 @@ export const initSocket = () => {
|
|||
|
||||
socket.on("connect_error", (error) => {
|
||||
console.error("Socket connection error:", error);
|
||||
store.dispatch(setTelemetryError("Socket connection failed"));
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log("Socket disconnecteddddd", reason, "abc");
|
||||
console.log("Socket disconnecteddddd", reason);
|
||||
store.dispatch(setTelemetryError("Socket disconnected: " + reason));
|
||||
});
|
||||
|
||||
socket.on("dataUpdate", handleSocketData);
|
||||
|
|
@ -52,6 +60,11 @@ const handleSocketData = (data: any) => {
|
|||
data?.dataSeries?.assetData?.[0]?.bms?.[0]?.bmsSpecific?.ivecSpecific
|
||||
?.ivecStatus?.currentMode;
|
||||
|
||||
const gps = data?.dataSeries?.locationData?.gps;
|
||||
|
||||
const lat = gps?.[1];
|
||||
const lon = gps?.[2];
|
||||
console.log("GPS Data:", lat, lon);
|
||||
let bms_state: BmsState | null = null;
|
||||
|
||||
if (currentMode === 0) {
|
||||
|
|
@ -62,8 +75,19 @@ const handleSocketData = (data: any) => {
|
|||
bms_state = 1;
|
||||
}
|
||||
|
||||
store.dispatch(updateTelemetry({ SoH, SoC, chargingState: bms_state }));
|
||||
store.dispatch(
|
||||
updateTelemetry({
|
||||
SoH,
|
||||
SoC,
|
||||
chargingState: bms_state,
|
||||
lat,
|
||||
lon,
|
||||
loading: false,
|
||||
error: null,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Error handling socket data:", err);
|
||||
store.dispatch(setTelemetryError("Data parsing failed"));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,15 +3,10 @@
|
|||
// payload: T;
|
||||
// }
|
||||
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import * as SecureStore from "expo-secure-store";
|
||||
import urls, {
|
||||
STORAGE_KEYS,
|
||||
MESSAGES,
|
||||
StatusType,
|
||||
AUTH_STATUSES,
|
||||
} from "../constants/config";
|
||||
import urls, { STORAGE_KEYS, MESSAGES } from "../constants/config";
|
||||
import { AUTH_STATUSES, StatusType } from "../constants/types";
|
||||
|
||||
interface AuthState {
|
||||
phone: string | null;
|
||||
|
|
@ -87,20 +82,26 @@ export const verifyOTP = createAsyncThunk<VerifyOTPResponse, VerifyOTPParams>(
|
|||
"auth/verifyOTP",
|
||||
async (params, { rejectWithValue }) => {
|
||||
try {
|
||||
const response = await axios.post<VerifyOTPResponse>(
|
||||
`${urls.BASE_URL}/verify-otp`,
|
||||
params
|
||||
);
|
||||
if (!response.data.status) throw new Error(response.data.message);
|
||||
return {
|
||||
status: true,
|
||||
message: "Done",
|
||||
token: "token",
|
||||
refreshToken: "refreshToken",
|
||||
};
|
||||
// const response = await axios.post<VerifyOTPResponse>(
|
||||
// `${urls.BASE_URL}/verify-otp`,
|
||||
// params
|
||||
// );
|
||||
// if (!response.data.status) throw new Error(response.data.message);
|
||||
|
||||
// Store tokens
|
||||
await AsyncStorage.setItem(STORAGE_KEYS.AUTH_TOKEN, response.data.token);
|
||||
await SecureStore.setItemAsync(
|
||||
STORAGE_KEYS.REFRESH_TOKEN,
|
||||
response.data.refreshToken
|
||||
);
|
||||
// // Store tokens
|
||||
// await AsyncStorage.setItem(STORAGE_KEYS.AUTH_TOKEN, response.data.token);
|
||||
// await SecureStore.setItemAsync(
|
||||
// STORAGE_KEYS.REFRESH_TOKEN,
|
||||
// response.data.refreshToken
|
||||
// );
|
||||
|
||||
return response.data;
|
||||
// return response.data;
|
||||
} catch (error: any) {
|
||||
return rejectWithValue(MESSAGES.AUTHENTICATION.VERIFICATION_FAILED);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,14 @@
|
|||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".expo/types/**/*.ts",
|
||||
"expo-env.d.ts"
|
||||
"expo-env.d.ts",
|
||||
"declarations.d.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue