import React from 'react'; import { useAppDispatch, useAppSelector } from '@app/hooks/redux'; import { DeviceStatusDropdown } from '@components/menu/buttons/DeviceStatusDropdown'; import { MobileNavToggle } from '@components/menu/buttons/MobileNavToggle'; import { ThemeToggle } from '@components/menu/buttons/ThemeToggle'; import { Logo } from '@components/menu/Logo'; import { MobileNav } from '@components/menu/MobileNav'; import { Navigation } from '@components/menu/Navigation'; import { connection, setConnection } from '@core/connection'; import { useRoute } from '@core/router'; import { addChannel, addMessage, addNode, addPosition, addUser, setDeviceStatus, setLastMeshInterraction, setMyNodeInfo, setPreferences, setReady, } from '@core/slices/meshtasticSlice'; import { IHTTPConnection, Protobuf, SettingsManager, Types, } from '@meshtastic/meshtasticjs'; import { About } from '@pages/About'; import { Messages } from '@pages/Messages'; import { Nodes } from '@pages/Nodes/Index'; import { Settings } from '@pages/settings/Index'; import { NotFound } from './pages/NotFound'; import { Plugins } from './pages/Plugins/Index'; const App = (): JSX.Element => { const dispatch = useAppDispatch(); const route = useRoute(); const myNodeInfo = useAppSelector((state) => state.meshtastic.myNodeInfo); const darkMode = useAppSelector((state) => state.app.darkMode); const hostOverrideEnabled = useAppSelector( (state) => state.meshtastic.hostOverrideEnabled, ); const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride); const connectionURL = hostOverrideEnabled ? hostOverride : import.meta.env.NODE_ENV === 'production' ? window.location.hostname : (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ?? 'http://meshtastic.local'; React.useEffect(() => { SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE; setConnection(new IHTTPConnection()); void connection.connect({ address: connectionURL, tls: false, receiveBatchRequests: false, fetchInterval: 2000, }); }, [hostOverrideEnabled, hostOverride, connectionURL]); React.useEffect(() => { connection.onDeviceStatus.subscribe((status) => { dispatch(setDeviceStatus(status)); if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) { dispatch(setReady(true)); } if (status === Types.DeviceStatusEnum.DEVICE_DISCONNECTED) { dispatch(setReady(false)); } }); connection.onMyNodeInfo.subscribe((nodeInfo) => { dispatch(setMyNodeInfo(nodeInfo)); }); connection.onUserPacket.subscribe((user) => { dispatch(addUser(user)); }); connection.onPositionPacket.subscribe((position) => { dispatch(addPosition(position)); }); connection.onNodeInfoPacket.subscribe( (nodeInfoPacket): void | { payload: Protobuf.NodeInfo; type: string } => { dispatch(addNode(nodeInfoPacket.data)); }, ); connection.onAdminPacket.subscribe((adminPacket) => { switch (adminPacket.data.variant.oneofKind) { case 'getChannelResponse': dispatch(addChannel(adminPacket.data.variant.getChannelResponse)); break; case 'getRadioResponse': if (adminPacket.data.variant.getRadioResponse.preferences) { dispatch( setPreferences( adminPacket.data.variant.getRadioResponse.preferences, ), ); } break; } }); connection.onMeshHeartbeat.subscribe( (date): void | { payload: number; type: string } => dispatch(setLastMeshInterraction(date.getTime())), ); connection.onTextPacket.subscribe((message) => { dispatch( addMessage({ message: message, ack: message.packet.from !== myNodeInfo.myNodeNum, isSender: message.packet.from === myNodeInfo.myNodeNum, received: new Date(message.packet.rxTime), }), ); }); return (): void => { connection.onDeviceStatus.cancelAll(); connection.onMyNodeInfo.cancelAll(); connection.onNodeInfoPacket.cancelAll(); connection.onAdminPacket.cancelAll(); connection.onMeshHeartbeat.cancelAll(); connection.onTextPacket.cancelAll(); connection.onRoutingPacket.cancelAll(); }; }, [dispatch, myNodeInfo.myNodeNum]); return (
{route.name === 'messages' && } {route.name === 'nodes' && } {route.name === 'plugins' && } {route.name === 'settings' && } {route.name === 'about' && } {route.name === false && }
); }; export default App;