diff --git a/package.json b/package.json index c5d1aca9..baf990ff 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "devDependencies": { "@types/chrome": "^0.0.193", "@types/geodesy": "^2.2.3", - "@types/node": "^18.6.5", + "@types/node": "^18.7.1", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", "@types/w3c-web-serial": "^1.0.2", @@ -60,7 +60,7 @@ "tslib": "^2.4.0", "typescript": "^4.7.4", "unimported": "^1.21.0", - "vite": "^3.0.4", + "vite": "^3.0.5", "vite-plugin-cdn-import": "^0.3.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index faf48437..b45cd98a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,7 +8,7 @@ specifiers: '@meshtastic/meshtasticjs': ^0.6.88 '@types/chrome': ^0.0.193 '@types/geodesy': ^2.2.3 - '@types/node': ^18.6.5 + '@types/node': ^18.7.1 '@types/react': ^18.0.17 '@types/react-dom': ^18.0.6 '@types/w3c-web-serial': ^1.0.2 @@ -37,7 +37,7 @@ specifiers: tslib: ^2.4.0 typescript: ^4.7.4 unimported: ^1.21.0 - vite: ^3.0.4 + vite: ^3.0.5 vite-plugin-cdn-import: ^0.3.5 vite-plugin-environment: ^1.1.2 zustand: 4.0.0 @@ -65,25 +65,25 @@ dependencies: rfc4648: 1.5.2 snarkdown: 2.0.0 swr: 1.3.0_react@18.2.0 - vite-plugin-environment: 1.1.2_vite@3.0.4 + vite-plugin-environment: 1.1.2_vite@3.0.5 zustand: 4.0.0_immer@9.0.15+react@18.2.0 devDependencies: '@types/chrome': 0.0.193 '@types/geodesy': 2.2.3 - '@types/node': 18.6.5 + '@types/node': 18.7.1 '@types/react': 18.0.17 '@types/react-dom': 18.0.6 '@types/w3c-web-serial': 1.0.2 '@types/web-bluetooth': 0.0.15 - '@vitejs/plugin-react': 2.0.0_vite@3.0.4 + '@vitejs/plugin-react': 2.0.0_vite@3.0.5 gzipper: 7.1.0 rollup-plugin-visualizer: 5.7.1 tar: 6.1.11 tslib: 2.4.0 typescript: 4.7.4 unimported: 1.21.0 - vite: 3.0.4 + vite: 3.0.5 vite-plugin-cdn-import: 0.3.5 packages: @@ -106,7 +106,7 @@ packages: '@esri/arcgis-html-sanitizer': 2.10.0 '@esri/calcite-colors': 6.0.1 '@esri/calcite-components': 1.0.0-beta.82 - '@popperjs/core': 2.11.5 + '@popperjs/core': 2.11.6 focus-trap: 6.9.4 luxon: 2.4.0 sortablejs: 1.15.0 @@ -620,6 +620,10 @@ packages: resolution: {integrity: sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==} dev: false + /@popperjs/core/2.11.6: + resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} + dev: false + /@protobuf-ts/runtime/2.7.0: resolution: {integrity: sha512-CzunTplg81oMkF9MnSYiX2WOdHnAyHKnokZncgOHm5bt8iEfFNnUsMSbsWUus/ulRNIZ9VAVMjutd96vmySQaw==} dev: false @@ -822,8 +826,8 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: false - /@types/node/18.6.5: - resolution: {integrity: sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==} + /@types/node/18.7.1: + resolution: {integrity: sha512-GKX1Qnqxo4S+Z/+Z8KKPLpH282LD7jLHWJcVryOflnsnH+BtSDfieR6ObwBMwpnNws0bUK8GI7z0unQf9bARNQ==} dev: true /@types/normalize-package-data/2.4.1: @@ -1013,7 +1017,7 @@ packages: '@typescript-eslint/types': 5.33.0 eslint-visitor-keys: 3.3.0 - /@vitejs/plugin-react/2.0.0_vite@3.0.4: + /@vitejs/plugin-react/2.0.0_vite@3.0.5: resolution: {integrity: sha512-zHkRR+X4zqEPNBbKV2FvWSxK7Q6crjMBVIAYroSU8Nbb4M3E5x4qOiLoqJBHtXgr27kfednXjkwr3lr8jS6Wrw==} engines: {node: '>=14.18.0'} peerDependencies: @@ -1026,7 +1030,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.18.6_@babel+core@7.18.10 magic-string: 0.26.2 react-refresh: 0.14.0 - vite: 3.0.4 + vite: 3.0.5 transitivePeerDependencies: - supports-color dev: true @@ -1197,8 +1201,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001374 - electron-to-chromium: 1.4.212 + caniuse-lite: 1.0.30001375 + electron-to-chromium: 1.4.215 node-releases: 2.0.6 update-browserslist-db: 1.0.5_browserslist@4.21.3 dev: true @@ -1224,8 +1228,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - /caniuse-lite/1.0.30001374: - resolution: {integrity: sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw==} + /caniuse-lite/1.0.30001375: + resolution: {integrity: sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw==} dev: true /chalk/2.4.2: @@ -1256,7 +1260,7 @@ packages: /class-validator/0.13.2: resolution: {integrity: sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==} dependencies: - libphonenumber-js: 1.10.11 + libphonenumber-js: 1.10.12 validator: 13.7.0 dev: false @@ -1501,8 +1505,8 @@ packages: stream-shift: 1.0.1 dev: true - /electron-to-chromium/1.4.212: - resolution: {integrity: sha512-LjQUg1SpLj2GfyaPDVBUHdhmlDU1vDB4f0mJWSGkISoXQrn5/lH3ECPCuo2Bkvf6Y30wO+b69te+rZK/llZmjg==} + /electron-to-chromium/1.4.215: + resolution: {integrity: sha512-vqZxT8C5mlDZ//hQFhneHmOLnj1LhbzxV0+I1yqHV8SB1Oo4Y5Ne9+qQhwHl7O1s9s9cRuo2l5CoLEHdhMTwZg==} dev: true /emoji-regex/8.0.0: @@ -2778,8 +2782,8 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 - /libphonenumber-js/1.10.11: - resolution: {integrity: sha512-ehoihx4HpRXO6FH/uJ0EnaEV4dVU+FDny+jv0S6k9JPyPsAIr0eXDAFvGRMBKE1daCtyHAaFSKCiuCxrOjVAzQ==} + /libphonenumber-js/1.10.12: + resolution: {integrity: sha512-xTFBs3ipFQNmjCUkDj6ZzRJvs97IyazFHBKWtrQrLiYs0Zk0GANob1hkMRlQUQXbJrpQGwnI+/yU4oyD4ohvpw==} dev: false /lines-and-columns/1.2.4: @@ -3517,8 +3521,8 @@ packages: yargs: 17.5.1 dev: true - /rollup/2.77.2: - resolution: {integrity: sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==} + /rollup/2.77.3: + resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: @@ -4027,16 +4031,16 @@ packages: - rollup dev: true - /vite-plugin-environment/1.1.2_vite@3.0.4: + /vite-plugin-environment/1.1.2_vite@3.0.5: resolution: {integrity: sha512-WFgM/ibceOEIuficZVaLcmJvcMZiyTkGzeS8+pzfByGYRdewqil7LSLDV1DwJfFQIx/YzcW9YRSWQG7cJ2XT1w==} peerDependencies: vite: '>= 2.7' dependencies: - vite: 3.0.4 + vite: 3.0.5 dev: false - /vite/3.0.4: - resolution: {integrity: sha512-NU304nqnBeOx2MkQnskBQxVsa0pRAH5FphokTGmyy8M3oxbvw7qAXts2GORxs+h/2vKsD+osMhZ7An6yK6F1dA==} + /vite/3.0.5: + resolution: {integrity: sha512-bRvrt9Tw8EGW4jj64aYFTnVg134E8hgDxyl/eEHnxiGqYk7/pTPss6CWlurqPOUzqvEoZkZ58Ws+Iu8MB87iMA==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -4057,7 +4061,7 @@ packages: esbuild: 0.14.54 postcss: 8.4.16 resolve: 1.22.1 - rollup: 2.77.2 + rollup: 2.77.3 optionalDependencies: fsevents: 2.3.2 diff --git a/src/components/Dialog/PeersDialog.tsx b/src/components/Dialog/PeersDialog.tsx index c03949ae..632e68e3 100644 --- a/src/components/Dialog/PeersDialog.tsx +++ b/src/components/Dialog/PeersDialog.tsx @@ -25,7 +25,8 @@ export const PeersDialog = ({ isOpen, close, }: PeersDialogProps): JSX.Element => { - const { hardware, nodes, connection } = useDevice(); + const { hardware, nodes, connection, setPeerInfoOpen, setActivePeer } = + useDevice(); return ( Location + Telemetry Last Heard Actions @@ -58,7 +60,10 @@ export const PeersDialog = ({ alert(node.data.num)} + onSelect={() => { + setActivePeer(node.data.num); + setPeerInfoOpen(true); + }} > + Tmp {new Date(node.data.lastHeard * 1000).toLocaleString()} diff --git a/src/components/SlideSheets/PeerInfo.tsx b/src/components/SlideSheets/PeerInfo.tsx new file mode 100644 index 00000000..bb65cdca --- /dev/null +++ b/src/components/SlideSheets/PeerInfo.tsx @@ -0,0 +1,61 @@ +import type React from "react"; +import { useEffect, useState } from "react"; + +import { GeolocationIcon, Pane, PropertyIcon, SideSheet } from "evergreen-ui"; + +import { Node, useDevice } from "@app/core/stores/deviceStore.js"; +import { Hashicon } from "@emeraldpay/hashicon-react"; +import { Protobuf } from "@meshtastic/meshtasticjs"; + +import { SlideSheetTabbedContent } from "../layout/page/SlideSheetTabbedContent.js"; +import type { TabType } from "../layout/page/TabbedContent.js"; +import { Location } from "./tabs/nodes/Location.js"; +import { Overview } from "./tabs/nodes/Overview.js"; + +export const PeerInfo = () => { + const { peerInfoOpen, activePeer, setPeerInfoOpen, nodes } = useDevice(); + const [selectedTab, setSelectedTab] = useState(0); + const [node, setNode] = useState(); + + useEffect(() => { + setNode(nodes.find((n) => n.data.num === activePeer)); + }, [nodes, activePeer]); + + const tabs: TabType[] = [ + { + name: "Info", + icon: PropertyIcon, + element: () => , + }, + { + name: "Location", + icon: GeolocationIcon, + element: () => , + }, + ]; + + return ( + { + setPeerInfoOpen(false); + }} + containerProps={{ + display: "flex", + flex: "1", + flexDirection: "column", + }} + > + + + + } + /> + + ); +}; diff --git a/src/components/connect/BLE.tsx b/src/components/SlideSheets/tabs/connect/BLE.tsx similarity index 88% rename from src/components/connect/BLE.tsx rename to src/components/SlideSheets/tabs/connect/BLE.tsx index 85b810e6..a2ee3f30 100644 --- a/src/components/connect/BLE.tsx +++ b/src/components/SlideSheets/tabs/connect/BLE.tsx @@ -4,29 +4,23 @@ import { useCallback, useEffect, useState } from "react"; import { Button, majorScale, Pane } from "evergreen-ui"; import { FiPlusCircle } from "react-icons/fi"; +import { useAppStore } from "@app/core/stores/appStore.js"; import { useDeviceStore } from "@app/core/stores/deviceStore.js"; import { subscribeAll } from "@app/core/subscriptions.js"; import { randId } from "@app/core/utils/randId.js"; import { Constants, IBLEConnection } from "@meshtastic/meshtasticjs"; -import type { CloseProps } from "../SlideSheets/NewDevice.js"; +import type { CloseProps } from "../../NewDevice.js"; export const BLE = ({ close }: CloseProps): JSX.Element => { const [bleDevices, setBleDevices] = useState([]); const { addDevice } = useDeviceStore(); + const { setSelectedDevice } = useAppStore(); const updateBleDeviceList = useCallback(async (): Promise => { setBleDevices(await navigator.bluetooth.getDevices()); }, []); - navigator.bluetooth.addEventListener("advertisementreceived", (e) => { - console.log(e); - }); - - navigator.bluetooth.addEventListener("availabilitychanged", (e) => { - console.log(e); - }); - useEffect(() => { void updateBleDeviceList(); }, [updateBleDeviceList]); @@ -34,6 +28,7 @@ export const BLE = ({ close }: CloseProps): JSX.Element => { const onConnect = async (BLEDevice: BluetoothDevice) => { const id = randId(); const device = addDevice(id); + setSelectedDevice(id); const connection = new IBLEConnection(id); await connection.connect({ device: BLEDevice, diff --git a/src/components/connect/HTTP.tsx b/src/components/SlideSheets/tabs/connect/HTTP.tsx similarity index 90% rename from src/components/connect/HTTP.tsx rename to src/components/SlideSheets/tabs/connect/HTTP.tsx index bbf4756c..9494943d 100644 --- a/src/components/connect/HTTP.tsx +++ b/src/components/SlideSheets/tabs/connect/HTTP.tsx @@ -4,6 +4,7 @@ import { Button, majorScale, Pane, TextInputField } from "evergreen-ui"; import { useForm } from "react-hook-form"; import { FiPlusCircle } from "react-icons/fi"; +import { useAppStore } from "@app/core/stores/appStore.js"; import { useDeviceStore } from "@app/core/stores/deviceStore.js"; import { subscribeAll } from "@app/core/subscriptions.js"; import { randId } from "@app/core/utils/randId.js"; @@ -15,6 +16,7 @@ export interface HTTPProps { export const HTTP = ({ close }: HTTPProps): JSX.Element => { const { addDevice } = useDeviceStore(); + const { setSelectedDevice } = useAppStore(); const { register, handleSubmit } = useForm<{ ip: string; tls: boolean; @@ -25,9 +27,10 @@ export const HTTP = ({ close }: HTTPProps): JSX.Element => { }, }); - const onSubmit = handleSubmit(async (data) => { + const onSubmit = handleSubmit((data) => { const id = randId(); const device = addDevice(id); + setSelectedDevice(id); const connection = new IHTTPConnection(id); // TODO: Promise never resolves void connection.connect({ diff --git a/src/components/connect/Serial.tsx b/src/components/SlideSheets/tabs/connect/Serial.tsx similarity index 92% rename from src/components/connect/Serial.tsx rename to src/components/SlideSheets/tabs/connect/Serial.tsx index 1236b7e0..0ae13bcf 100644 --- a/src/components/connect/Serial.tsx +++ b/src/components/SlideSheets/tabs/connect/Serial.tsx @@ -4,12 +4,13 @@ import { useCallback, useEffect, useState } from "react"; import { Button, majorScale, Pane } from "evergreen-ui"; import { FiPlusCircle } from "react-icons/fi"; +import { useAppStore } from "@app/core/stores/appStore.js"; import { subscribeAll } from "@app/core/subscriptions.js"; import { useDeviceStore } from "@core/stores/deviceStore.js"; import { randId } from "@core/utils/randId.js"; import { ISerialConnection } from "@meshtastic/meshtasticjs"; -import type { CloseProps } from "../SlideSheets/NewDevice.js"; +import type { CloseProps } from "../../NewDevice.js"; interface USBID { id: number; @@ -19,6 +20,7 @@ interface USBID { export const Serial = ({ close }: CloseProps): JSX.Element => { const [serialPorts, setSerialPorts] = useState([]); const { addDevice } = useDeviceStore(); + const { setSelectedDevice } = useAppStore(); const updateSerialPortList = useCallback(async () => { setSerialPorts(await navigator.serial.getPorts()); @@ -37,6 +39,7 @@ export const Serial = ({ close }: CloseProps): JSX.Element => { const onConnect = async (port: SerialPort) => { const id = randId(); const device = addDevice(id); + setSelectedDevice(id); const connection = new ISerialConnection(id); await connection.connect({ port, diff --git a/src/components/SlideSheets/tabs/nodes/Location.tsx b/src/components/SlideSheets/tabs/nodes/Location.tsx new file mode 100644 index 00000000..3bd22ae9 --- /dev/null +++ b/src/components/SlideSheets/tabs/nodes/Location.tsx @@ -0,0 +1,18 @@ +import type React from "react"; + +import { Pane } from "evergreen-ui"; +import JSONPretty from "react-json-pretty"; + +import type { Node } from "@app/core/stores/deviceStore.js"; + +export interface LocationProps { + node?: Node; +} + +export const Location = ({ node }: LocationProps): JSX.Element => { + return ( + + + + ); +}; diff --git a/src/components/SlideSheets/tabs/nodes/Overview.tsx b/src/components/SlideSheets/tabs/nodes/Overview.tsx new file mode 100644 index 00000000..802c3f99 --- /dev/null +++ b/src/components/SlideSheets/tabs/nodes/Overview.tsx @@ -0,0 +1,17 @@ +import type React from "react"; + +import { Pane } from "evergreen-ui"; +import JSONPretty from "react-json-pretty"; + +import type { Node } from "@app/core/stores/deviceStore.js"; + +export interface OverviewProps { + node?: Node; +} +export const Overview = ({ node }: OverviewProps): JSX.Element => { + return ( + + + + ); +}; diff --git a/src/components/layout/AppLayout.tsx b/src/components/layout/AppLayout.tsx index 5f93647a..b5eac1ae 100644 --- a/src/components/layout/AppLayout.tsx +++ b/src/components/layout/AppLayout.tsx @@ -8,6 +8,7 @@ import { useDeviceStore } from "@core/stores/deviceStore.js"; import { NoDevice } from "../misc/NoDevice.js"; import { Progress } from "../Progress.js"; +import { PeerInfo } from "../SlideSheets/PeerInfo.js"; import { Header } from "./Header.js"; import { Sidebar } from "./Sidebar/index.js"; @@ -32,12 +33,12 @@ export const AppLayout = ({ children }: AppLayoutProps): JSX.Element => {
{devices.length ? ( - devices.map((device, index) => ( + devices.map((device) => ( @@ -45,6 +46,7 @@ export const AppLayout = ({ children }: AppLayoutProps): JSX.Element => { {device && device.ready ? ( <> + {children} diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 02c47f81..be7f00c4 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -5,6 +5,7 @@ import { Button, CrossIcon, GlobeIcon, + HelpIcon, IconButton, Link, majorScale, @@ -65,13 +66,13 @@ export const Header = (): JSX.Element => { - {getDevices().map((device, index) => ( + {getDevices().map((device) => ( { - setSelectedDevice(index); + setSelectedDevice(device.id); }} > @@ -121,6 +122,9 @@ export const Header = (): JSX.Element => { + diff --git a/src/components/layout/page/SlideSheetTabbedContent.tsx b/src/components/layout/page/SlideSheetTabbedContent.tsx index 4296e22d..7a483d93 100644 --- a/src/components/layout/page/SlideSheetTabbedContent.tsx +++ b/src/components/layout/page/SlideSheetTabbedContent.tsx @@ -23,23 +23,33 @@ export interface SlideSheetTabbedContentProps { heading: string; description: string; tabs: TabType[]; + tabIcon?: React.ReactNode; } export const SlideSheetTabbedContent = ({ heading, description, tabs, + tabIcon, }: SlideSheetTabbedContentProps): JSX.Element => { const [selectedTab, setSelectedTab] = useState(0); return ( <> - - {heading} - - {description} - + + {tabIcon} + + {heading} + + {description} + + diff --git a/src/core/stores/deviceStore.ts b/src/core/stores/deviceStore.ts index 61342c4a..7af9a7b1 100644 --- a/src/core/stores/deviceStore.ts +++ b/src/core/stores/deviceStore.ts @@ -32,6 +32,7 @@ export interface Node { } export interface Device { + id: number; ready: boolean; status: Types.DeviceStatusEnum; channels: Channel[]; @@ -79,6 +80,7 @@ export const useDeviceStore = create((set, get) => ({ set( produce((draft) => { draft.devices.set(id, { + id, ready: false, status: Types.DeviceStatusEnum.DEVICE_DISCONNECTED, channels: [], @@ -417,10 +419,14 @@ export const useDeviceStore = create((set, get) => ({ } return device; }, - removeDevice: (id) => - produce((draft) => { - draft.devices.delete(id); - }), + removeDevice: (id) => { + set( + produce((draft) => { + draft.devices.delete(id); + }) + ); + }, + getDevices: () => Array.from(get().devices.values()), })); diff --git a/src/pages/Messages/ChannelChat.tsx b/src/pages/Messages/ChannelChat.tsx index 0bb27ec1..966bb943 100644 --- a/src/pages/Messages/ChannelChat.tsx +++ b/src/pages/Messages/ChannelChat.tsx @@ -2,9 +2,11 @@ import type React from "react"; import { ChangeEvent, useState } from "react"; import { + AddLocationIcon, IconButton, majorScale, Pane, + Popover, SendMessageIcon, TextInputField, Tooltip, @@ -14,6 +16,7 @@ import type { Channel } from "@core/stores/deviceStore.js"; import { useDevice } from "@core/stores/deviceStore.js"; import { Message } from "./Message.js"; +import { NewLocationMessage } from "./NewLocationMessage.js"; export interface ChannelChatProps { channel: Channel; @@ -60,34 +63,46 @@ export const ChannelChat = ({ channel }: ChannelChatProps): JSX.Element => { /> ))} -
{ - e.preventDefault(); - sendMessage(); - }} - > - - ): void => { - setCurrentMessage(e.target.value); - }} - /> - + + { + e.preventDefault(); + sendMessage(); + }} + > + + ): void => { + setCurrentMessage(e.target.value); + }} + /> + + + + + + + }> - - - + + +
); }; diff --git a/src/pages/Messages/Message.tsx b/src/pages/Messages/Message.tsx index 02f513fc..932ef225 100644 --- a/src/pages/Messages/Message.tsx +++ b/src/pages/Messages/Message.tsx @@ -10,6 +10,7 @@ import { Text, } from "evergreen-ui"; +import { useDevice } from "@app/core/stores/deviceStore.js"; import { Hashicon } from "@emeraldpay/hashicon-react"; import type { Protobuf, Types } from "@meshtastic/meshtasticjs"; @@ -30,6 +31,13 @@ export const Message = ({ rxTime, sender, }: MessageProps): JSX.Element => { + const { setPeerInfoOpen, setActivePeer } = useDevice(); + + const openPeer = (): void => { + setActivePeer(messagePacket.packet.from); + setPeerInfoOpen(true); + }; + return lastMsgSameUser ? ( {ack ? ( @@ -53,10 +61,10 @@ export const Message = ({ ) : ( - + - + {sender?.user?.longName ?? "UNK"} diff --git a/src/pages/Messages/NewLocationMessage.tsx b/src/pages/Messages/NewLocationMessage.tsx new file mode 100644 index 00000000..fabf1c88 --- /dev/null +++ b/src/pages/Messages/NewLocationMessage.tsx @@ -0,0 +1,55 @@ +import type React from "react"; + +import { + Button, + majorScale, + Pane, + SelectField, + TextInputField, +} from "evergreen-ui"; + +import { useDevice } from "@app/core/stores/deviceStore.js"; +import { renderOptions } from "@app/core/utils/selectEnumOptions.js"; +import { Protobuf } from "@meshtastic/meshtasticjs"; + +enum LocationType { + MGRS, + LatLng, + DecimalDegrees, +} + +export const NewLocationMessage = (): JSX.Element => { + const { connection } = useDevice(); + + return ( + +
{ + e.preventDefault(); + }} + > + + + + {renderOptions(LocationType)} + + + + +
+ ); +};