Setup socket.io
parent
189f8bd673
commit
a1accb4ca5
|
|
@ -12,6 +12,9 @@
|
|||
</intent>
|
||||
</queries>
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="AIzaSyBfz20PwTeQkeMonsgXETOViBAy9LOBlXY"/>
|
||||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { Tabs } from "expo-router";
|
||||
import { TAB_CONFIG } from "@/constants/config";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "@/store";
|
||||
import { initSocket } from "@/services/socket";
|
||||
|
||||
export default function TabLayout() {
|
||||
const { isLoggedIn } = useSelector((state: RootState) => state.auth);
|
||||
if (!isLoggedIn) return null;
|
||||
|
||||
useEffect(() => {
|
||||
initSocket();
|
||||
}, [isLoggedIn]);
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
|
|
|
|||
|
|
@ -10,14 +10,17 @@ 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 LocationMap from "@/components/home/LocationMap";
|
||||
import MapView, { Marker } from "react-native-maps";
|
||||
import BatteryWarrantyCard from "@/components/home/BatteryWarrantyCars";
|
||||
import CustomerSupportModal from "@/components/home/CustomerSupportModal";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "@/store";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const { t } = useTranslation();
|
||||
const navigation = useNavigation();
|
||||
const [isSupportModalVisible, setIsSupportModalVisible] = useState(false);
|
||||
const { SoC, SoH } = useSelector((state: RootState) => state.telemetry);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
|
|
@ -51,10 +54,10 @@ export default function HomeScreen() {
|
|||
subMessage="Service Reminder"
|
||||
/>
|
||||
<View style={styles.iconContainer}>
|
||||
<SemiCircleProgress progress={90} status={1} />
|
||||
<SemiCircleProgress progress={SoC} status={1} />
|
||||
</View>
|
||||
<View style={styles.metrics}>
|
||||
<MetricCard heading="SoH" value="90%" />
|
||||
<MetricCard heading="SoH" value={`${SoH}%`} />
|
||||
<MetricCard heading="Total Distance" value="20009 km" />
|
||||
</View>
|
||||
<PaymentDueCard
|
||||
|
|
@ -62,7 +65,31 @@ export default function HomeScreen() {
|
|||
amount="$2,000"
|
||||
onPress={() => {}}
|
||||
/>
|
||||
{/* <LocationMap latitude={12.9716} longitude={77.5946} /> */}
|
||||
<View style={styles.mapContainer}>
|
||||
<MapView
|
||||
style={styles.mapStyle}
|
||||
initialRegion={{
|
||||
latitude: 28.54,
|
||||
longitude: 77.32,
|
||||
latitudeDelta: 0.0922,
|
||||
longitudeDelta: 0.0421,
|
||||
}}
|
||||
// customMapStyle={mapStyle}
|
||||
>
|
||||
<Marker
|
||||
draggable
|
||||
coordinate={{
|
||||
latitude: 37.78825,
|
||||
longitude: -122.4324,
|
||||
}}
|
||||
anchor={{ x: 0.5, y: 0.5 }}
|
||||
onDragEnd={(e) => alert(JSON.stringify(e.nativeEvent.coordinate))}
|
||||
title={"Test Marker"}
|
||||
description={"This is a description of the marker"}
|
||||
/>
|
||||
</MapView>
|
||||
</View>
|
||||
|
||||
<BatteryWarrantyCard
|
||||
totalWarrantyYears={8}
|
||||
batteryPurchaseEpoch={Math.floor(
|
||||
|
|
@ -78,7 +105,100 @@ export default function HomeScreen() {
|
|||
);
|
||||
}
|
||||
|
||||
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({
|
||||
mapContainer: {
|
||||
flex: 1,
|
||||
borderRadius: 10,
|
||||
overflow: "hidden",
|
||||
},
|
||||
mapStyle: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
metrics: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import i18next, { getLanguage } from "../services/i18n/index";
|
||||
import FontAwesome from "@expo/vector-icons/FontAwesome";
|
||||
import { useFonts } from "expo-font";
|
||||
import { Stack, useRouter } from "expo-router";
|
||||
import * as SplashScreen from "expo-splash-screen";
|
||||
import { useEffect, useState } from "react";
|
||||
|
|
@ -18,11 +16,6 @@ export const unstable_settings = {
|
|||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
export default function RootLayout() {
|
||||
const [loaded, error] = useFonts({
|
||||
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
|
||||
...FontAwesome.font,
|
||||
});
|
||||
|
||||
const [appIsReady, setAppIsReady] = useState(false);
|
||||
const [shouldRedirect, setShouldRedirect] = useState(false);
|
||||
const router = useRouter();
|
||||
|
|
@ -31,7 +24,6 @@ export default function RootLayout() {
|
|||
const initLang = async () => {
|
||||
const lang = await getLanguage();
|
||||
if (!lang) {
|
||||
console.log("Redirecting to language init...");
|
||||
setShouldRedirect(true);
|
||||
}
|
||||
|
||||
|
|
@ -42,15 +34,11 @@ export default function RootLayout() {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) throw error;
|
||||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
if (loaded && appIsReady) {
|
||||
if (appIsReady) {
|
||||
SplashScreen.hideAsync();
|
||||
router.replace("/auth/login");
|
||||
}
|
||||
}, [loaded, appIsReady]);
|
||||
}, [appIsReady]);
|
||||
|
||||
useEffect(() => {
|
||||
if (appIsReady && shouldRedirect) {
|
||||
|
|
@ -59,8 +47,7 @@ export default function RootLayout() {
|
|||
}
|
||||
}, [appIsReady, shouldRedirect]);
|
||||
|
||||
if (!loaded || !appIsReady) {
|
||||
console.log("!loaded || !appIsReady", loaded, appIsReady);
|
||||
if (!appIsReady) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +60,6 @@ function RootLayoutNav() {
|
|||
<I18nextProvider i18n={i18next}>
|
||||
<Stack>
|
||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||
<Stack.Screen name="modal" options={{ presentation: "modal" }} />
|
||||
</Stack>
|
||||
</I18nextProvider>
|
||||
</Provider>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
import { io, Socket } from "socket.io-client";
|
||||
import { store } from "../store";
|
||||
import { updateTelemetry } from "../store/telemetrySlice";
|
||||
|
||||
const SERVER_URL =
|
||||
"http://dev.vec-tr.ai:8089/?dashboardId=deviceDashboardSocket&assetId=V16000868651064644504";
|
||||
const TOKEN =
|
||||
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiYWN0aW9uIjoiYXV0aCIsInRva2VuLXZlcnNpb24iOjAsImlhdCI6MTc1MTM0OTUwMSwiZXhwIjoxNzUxNDM1OTAxfQ.0BB0vRcFSMFDC6aILuc__pG3Ycy8EndYOAwLwCHji1M";
|
||||
|
||||
let socket: Socket | null = null;
|
||||
|
||||
export const initSocket = () => {
|
||||
socket = io(SERVER_URL, {
|
||||
transports: ["websocket"],
|
||||
extraHeaders: {
|
||||
Authorization: `Bearer ${TOKEN}`,
|
||||
controllingServer: "http://dev.vec-tr.ai:8082",
|
||||
},
|
||||
reconnection: true,
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log("Socket connected:", socket?.id);
|
||||
});
|
||||
|
||||
socket.on("connect_error", (error) => {
|
||||
console.error("Socket connection error:", error);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log("Socket disconnecteddddd", reason, "abc");
|
||||
});
|
||||
|
||||
socket.on("dataUpdate", handleSocketData);
|
||||
};
|
||||
|
||||
export const disconnectSocket = () => {
|
||||
if (socket) {
|
||||
socket.disconnect();
|
||||
console.log("Socket disconnected");
|
||||
}
|
||||
};
|
||||
|
||||
const handleSocketData = (data: any) => {
|
||||
try {
|
||||
const SoH =
|
||||
data.dataSeries.assetData[0].bms[0].bmsSpecific.ivecSpecific.soh;
|
||||
const SoC = data?.dataSeries?.assetData?.[0]?.bms?.[0]?.batterySoc;
|
||||
// console.log(SoC, SoH);
|
||||
store.dispatch(updateTelemetry({ SoH, SoC }));
|
||||
} catch (err) {
|
||||
console.error("Error handling socket data:", err);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
import { combineReducers } from "@reduxjs/toolkit";
|
||||
import authreducer from "./authSlice";
|
||||
import telemetryReducer from "./telemetrySlice";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authreducer,
|
||||
telemetry: telemetryReducer,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
interface TelemetryState {
|
||||
SoH: number;
|
||||
SoC: number;
|
||||
}
|
||||
|
||||
const initialState: TelemetryState = {
|
||||
SoH: 0,
|
||||
SoC: 0,
|
||||
};
|
||||
|
||||
export const telemetrySlice = createSlice({
|
||||
name: "telemetry",
|
||||
initialState,
|
||||
reducers: {
|
||||
updateTelemetry: (state, action: PayloadAction<TelemetryState>) => {
|
||||
return { ...state, ...action.payload };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { updateTelemetry } = telemetrySlice.actions;
|
||||
export default telemetrySlice.reducer;
|
||||
Loading…
Reference in New Issue