Display device data in ui

feature/app-setup
vinay kumar 2025-07-01 19:38:11 +05:30
parent a1accb4ca5
commit faadc33a7e
8 changed files with 63 additions and 25 deletions

View File

@ -20,7 +20,9 @@ export default function HomeScreen() {
const { t } = useTranslation(); const { t } = useTranslation();
const navigation = useNavigation(); const navigation = useNavigation();
const [isSupportModalVisible, setIsSupportModalVisible] = useState(false); const [isSupportModalVisible, setIsSupportModalVisible] = useState(false);
const { SoC, SoH } = useSelector((state: RootState) => state.telemetry); const { SoC, SoH, chargingState } = useSelector(
(state: RootState) => state.telemetry
);
useLayoutEffect(() => { useLayoutEffect(() => {
navigation.setOptions({ navigation.setOptions({
@ -54,11 +56,11 @@ export default function HomeScreen() {
subMessage="Service Reminder" subMessage="Service Reminder"
/> />
<View style={styles.iconContainer}> <View style={styles.iconContainer}>
<SemiCircleProgress progress={SoC} status={1} /> <SemiCircleProgress progress={SoC} status={chargingState} />
</View> </View>
<View style={styles.metrics}> <View style={styles.metrics}>
<MetricCard heading="SoH" value={`${SoH}%`} /> <MetricCard heading="SoH" value={SoH} unit="%" />
<MetricCard heading="Total Distance" value="20009 km" /> <MetricCard heading="Total Distance" value={20009} unit="km" />
</View> </View>
<PaymentDueCard <PaymentDueCard
label="Payment Due" label="Payment Due"

View File

@ -18,7 +18,7 @@ import { useDispatch } from "react-redux";
import { AppDispatch } from "../../store"; import { AppDispatch } from "../../store";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { RootState } from "../../store"; import { RootState } from "../../store";
import { AUTH_STATUSES } from "@/constants/config"; import { AUTH_STATUSES } from "@/constants/types";
// type VerifyOTPNavigationProp = StackNavigationProp< // type VerifyOTPNavigationProp = StackNavigationProp<
// RootStackParamList, // RootStackParamList,

View File

@ -6,7 +6,7 @@ import { clearVerifyOTPError, sendOTP, verifyOTP } from "../../store/authSlice";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { OtpInput } from "react-native-otp-entry"; import { OtpInput } from "react-native-otp-entry";
import { useRouter } from "expo-router"; import { useRouter } from "expo-router";
import { AUTH_STATUSES } from "@/constants/config"; import { AUTH_STATUSES } from "@/constants/types";
export default function VerifyOTP() { export default function VerifyOTP() {
const { phone, otpId, verifyOTPError, sendOTPError, status } = useSelector( const { phone, otpId, verifyOTPError, sendOTPError, status } = useSelector(
@ -14,7 +14,7 @@ export default function VerifyOTP() {
); );
const router = useRouter(); const router = useRouter();
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const { isLoggedIn } = useSelector((state: RootState) => state.auth);
const [seconds, setSeconds] = useState(30); const [seconds, setSeconds] = useState(30);
const [isTimerActive, setIsTimerActive] = useState(true); const [isTimerActive, setIsTimerActive] = useState(true);
const [resendAttempts, setResendAttempts] = useState(0); const [resendAttempts, setResendAttempts] = useState(0);
@ -49,6 +49,12 @@ export default function VerifyOTP() {
const formattedSeconds = seconds.toString().padStart(2, "0"); const formattedSeconds = seconds.toString().padStart(2, "0");
useEffect(() => {
if (status === AUTH_STATUSES.SUCCESS && isLoggedIn) {
router.replace("/"); // This assumes "/" leads to your `TabLayout`
}
}, [status, isLoggedIn]);
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.heading}>Verify Code</Text> <Text style={styles.heading}>Verify Code</Text>

View File

@ -3,15 +3,18 @@ import { View, Text, StyleSheet } from "react-native";
interface MetricCardProps { interface MetricCardProps {
heading: string; heading: string;
value: string | number; value: number | null;
unit: string;
} }
const MetricCard: React.FC<MetricCardProps> = ({ heading, value }) => { const MetricCard: React.FC<MetricCardProps> = ({ heading, value, unit }) => {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<View style={styles.textContainer}> <View style={styles.textContainer}>
<Text style={styles.heading}>{heading}</Text> <Text style={styles.heading}>{heading}</Text>
<Text style={styles.value}>{value}</Text> <Text style={styles.value}>
{value ?? "---"} {unit}
</Text>
</View> </View>
</View> </View>
); );

View File

@ -1,3 +1,5 @@
import { BMS_STATE_LABELS } from "@/constants/config";
import { BmsState } from "@/constants/types";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { View, StyleSheet, Text, Animated } from "react-native"; import { View, StyleSheet, Text, Animated } from "react-native";
import Svg, { Circle, Defs, LinearGradient, Stop } from "react-native-svg"; import Svg, { Circle, Defs, LinearGradient, Stop } from "react-native-svg";
@ -8,8 +10,8 @@ const CircleProgressBar = ({
progress, progress,
status, status,
}: { }: {
progress: number; progress: number | null;
status: number; status: number | null;
}) => { }) => {
const radius = 20; const radius = 20;
const strokeWidth = 5; const strokeWidth = 5;
@ -27,7 +29,7 @@ const CircleProgressBar = ({
setDisplayProgress(0); setDisplayProgress(0);
} else { } else {
Animated.timing(animatedValue, { Animated.timing(animatedValue, {
toValue: progress, toValue: progress ?? 0,
duration: 500, duration: 500,
useNativeDriver: false, useNativeDriver: false,
}).start(); }).start();
@ -97,7 +99,7 @@ const CircleProgressBar = ({
</Svg> </Svg>
<View style={styles.batteryPercent}> <View style={styles.batteryPercent}>
<Text style={{ fontSize: 60, fontWeight: "bold", fontFamily: "Inter" }}> <Text style={{ fontSize: 60, fontWeight: "bold", fontFamily: "Inter" }}>
{progress === undefined ? "---" : displayProgress} {progress ? displayProgress : "--"}
</Text> </Text>
<Text style={{ fontSize: 20, fontWeight: "bold" }}> <Text style={{ fontSize: 20, fontWeight: "bold" }}>
{progress === undefined ? null : "%"} {progress === undefined ? null : "%"}
@ -105,7 +107,7 @@ const CircleProgressBar = ({
</View> </View>
<View style={styles.batterySoc}> <View style={styles.batterySoc}>
<Text style={{ fontSize: 14, fontWeight: "bold", color: "#565F70" }}> <Text style={{ fontSize: 14, fontWeight: "bold", color: "#565F70" }}>
{status === 1 ? "Charging" : "Discharging"} {status ? BMS_STATE_LABELS[status as BmsState] : "Unknown"}
</Text> </Text>
</View> </View>
</View> </View>

View File

@ -10,6 +10,7 @@ import { BASE_URL, ENV } from "@env";
import InfoIcon from "../assets/icons/error.svg"; import InfoIcon from "../assets/icons/error.svg";
import WarningIcon from "../assets/icons/warning.svg"; import WarningIcon from "../assets/icons/warning.svg";
import DangerIcon from "../assets/icons/danger.svg"; import DangerIcon from "../assets/icons/danger.svg";
import type { BmsState } from "./types";
export default { export default {
ENV, ENV,
@ -66,13 +67,6 @@ export const MESSAGES = {
}, },
}; };
export const AUTH_STATUSES = {
IDLE: "Idle",
LOADING: "Loading",
SUCCESS: "Success",
FAILED: "Failed",
} as const;
export const ALERT_STYLES = { export const ALERT_STYLES = {
info: { info: {
backgroundColor: "#E5EBFD", backgroundColor: "#E5EBFD",
@ -97,4 +91,8 @@ export const SUPPORT = {
EMAIL_BODY: "Hello,\n\nI need assistance with...", EMAIL_BODY: "Hello,\n\nI need assistance with...",
}; };
export type StatusType = (typeof AUTH_STATUSES)[keyof typeof AUTH_STATUSES]; export const BMS_STATE_LABELS: Record<BmsState, string> = {
0: "Idle",
1: "Charging",
[-1]: "Discharging",
};

12
constants/types.ts Normal file
View File

@ -0,0 +1,12 @@
export const BMS_STATES = [0, 1, -1] as const;
export type BmsState = (typeof BMS_STATES)[number];
export const AUTH_STATUSES = {
IDLE: "Idle",
LOADING: "Loading",
SUCCESS: "Success",
FAILED: "Failed",
} as const;
export type StatusType = (typeof AUTH_STATUSES)[keyof typeof AUTH_STATUSES];

View File

@ -1,6 +1,7 @@
import { io, Socket } from "socket.io-client"; import { io, Socket } from "socket.io-client";
import { store } from "../store"; import { store } from "../store";
import { updateTelemetry } from "../store/telemetrySlice"; import { updateTelemetry } from "../store/telemetrySlice";
import { BmsState } from "@/constants/types";
const SERVER_URL = const SERVER_URL =
"http://dev.vec-tr.ai:8089/?dashboardId=deviceDashboardSocket&assetId=V16000868651064644504"; "http://dev.vec-tr.ai:8089/?dashboardId=deviceDashboardSocket&assetId=V16000868651064644504";
@ -42,12 +43,26 @@ export const disconnectSocket = () => {
}; };
const handleSocketData = (data: any) => { const handleSocketData = (data: any) => {
console.log("...");
try { try {
const SoH = const SoH =
data.dataSeries.assetData[0].bms[0].bmsSpecific.ivecSpecific.soh; data.dataSeries.assetData[0].bms[0].bmsSpecific.ivecSpecific.soh;
const SoC = data?.dataSeries?.assetData?.[0]?.bms?.[0]?.batterySoc; const SoC = data?.dataSeries?.assetData?.[0]?.bms?.[0]?.batterySoc;
// console.log(SoC, SoH); const currentMode =
store.dispatch(updateTelemetry({ SoH, SoC })); data?.dataSeries?.assetData?.[0]?.bms?.[0]?.bmsSpecific?.ivecSpecific
?.ivecStatus?.currentMode;
let bms_state: BmsState | null = null;
if (currentMode === 0) {
bms_state = 0;
} else if (currentMode === 1) {
bms_state = -1;
} else if (currentMode === 2) {
bms_state = 1;
}
store.dispatch(updateTelemetry({ SoH, SoC, chargingState: bms_state }));
} catch (err) { } catch (err) {
console.error("Error handling socket data:", err); console.error("Error handling socket data:", err);
} }