WIP 1.3
This commit is contained in:
@@ -10,9 +10,7 @@ export const Debug = (): JSX.Element => {
|
||||
(state) => state.meshtastic.radio.hardware,
|
||||
);
|
||||
const node = useAppSelector((state) =>
|
||||
state.meshtastic.nodes.find(
|
||||
(node) => node.number === hardwareInfo.myNodeNum,
|
||||
),
|
||||
state.meshtastic.nodes.find((node) => node.num === hardwareInfo.myNodeNum),
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -33,6 +31,13 @@ export const Debug = (): JSX.Element => {
|
||||
>
|
||||
Get Preferences
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async (): Promise<void> => {
|
||||
await connection.getAllChannels();
|
||||
}}
|
||||
>
|
||||
Get All Channels
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -14,9 +14,7 @@ export const Info = (): JSX.Element => {
|
||||
(state) => state.meshtastic.radio.hardware,
|
||||
);
|
||||
const node = useAppSelector((state) =>
|
||||
state.meshtastic.nodes.find(
|
||||
(node) => node.number === hardwareInfo.myNodeNum,
|
||||
),
|
||||
state.meshtastic.nodes.find((node) => node.num === hardwareInfo.myNodeNum),
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
+10
-10
@@ -7,14 +7,14 @@ import { RiRoadMapLine } from 'react-icons/ri';
|
||||
|
||||
import { Layout } from '@components/layout';
|
||||
import { MapboxProvider } from '@components/MapBox/MapboxProvider';
|
||||
import type { Node } from '@core/slices/meshtasticSlice';
|
||||
import { useAppSelector } from '@hooks/useAppSelector';
|
||||
import { MapContainer } from '@pages/Map/MapContainer';
|
||||
import { Marker } from '@pages/Map/Marker';
|
||||
import { NodeCard } from '@pages/Nodes/NodeCard';
|
||||
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
||||
|
||||
export const Map = (): JSX.Element => {
|
||||
const [selectedNode, setSelectedNode] = useState<Node>();
|
||||
const [selectedNode, setSelectedNode] = useState<Protobuf.NodeInfo>();
|
||||
|
||||
const nodes = useAppSelector((state) => state.meshtastic.nodes);
|
||||
const myNodeNum = useAppSelector(
|
||||
@@ -25,13 +25,13 @@ export const Map = (): JSX.Element => {
|
||||
<MapboxProvider>
|
||||
{nodes.map((node) => {
|
||||
return (
|
||||
node.currentPosition && (
|
||||
node.position && (
|
||||
<Marker
|
||||
key={node.number}
|
||||
key={node.num}
|
||||
center={
|
||||
new mapboxgl.LngLat(
|
||||
node.currentPosition.longitudeI / 1e7,
|
||||
node.currentPosition.latitudeI / 1e7,
|
||||
node.position.longitudeI / 1e7,
|
||||
node.position.latitudeI / 1e7,
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -40,7 +40,7 @@ export const Map = (): JSX.Element => {
|
||||
setSelectedNode(node);
|
||||
}}
|
||||
className={`z-50 rounded-full border-2 bg-opacity-30 ${
|
||||
node.number === selectedNode?.number
|
||||
node.num === selectedNode?.num
|
||||
? 'border-green-500 bg-green-500'
|
||||
: 'border-blue-500 bg-blue-500'
|
||||
}`}
|
||||
@@ -66,10 +66,10 @@ export const Map = (): JSX.Element => {
|
||||
|
||||
{nodes.map((node) => (
|
||||
<NodeCard
|
||||
key={node.number}
|
||||
key={node.num}
|
||||
node={node}
|
||||
isMyNode={node.number === myNodeNum}
|
||||
selected={selectedNode?.number === node.number}
|
||||
isMyNode={node.num === myNodeNum}
|
||||
selected={selectedNode?.num === node.num}
|
||||
setSelected={(): void => {
|
||||
setSelectedNode(node);
|
||||
}}
|
||||
|
||||
@@ -27,7 +27,7 @@ export const ChannelChat = ({
|
||||
(state) => state.meshtastic.radio.hardware,
|
||||
).myNodeNum;
|
||||
const nodes = useAppSelector((state) => state.meshtastic.nodes).filter(
|
||||
(node) => node.number !== myNodeNum,
|
||||
(node) => node.num !== myNodeNum,
|
||||
);
|
||||
const chats = useAppSelector((state) => state.meshtastic.chats);
|
||||
const channels = useAppSelector(
|
||||
@@ -80,7 +80,7 @@ export const ChannelChat = ({
|
||||
<Tooltip
|
||||
key={nodeId}
|
||||
content={
|
||||
nodes.find((node) => node.number === nodeId)?.user
|
||||
nodes.find((node) => node.num === nodeId)?.user
|
||||
?.longName ?? 'UNK'
|
||||
}
|
||||
>
|
||||
|
||||
@@ -4,11 +4,11 @@ import { FiSettings } from 'react-icons/fi';
|
||||
|
||||
import { IconButton } from '@components/generic/button/IconButton';
|
||||
import { SidebarItem } from '@components/layout/Sidebar/SidebarItem';
|
||||
import type { Node } from '@core/slices/meshtasticSlice';
|
||||
import { Hashicon } from '@emeraldpay/hashicon-react';
|
||||
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
||||
|
||||
export interface DmChatProps {
|
||||
node: Node;
|
||||
node: Protobuf.NodeInfo;
|
||||
selectedIndex: number;
|
||||
setSelectedIndex: (index: number) => void;
|
||||
}
|
||||
@@ -20,16 +20,16 @@ export const DmChat = ({
|
||||
}: DmChatProps): JSX.Element => {
|
||||
return (
|
||||
<SidebarItem
|
||||
key={node.number}
|
||||
selected={node.number === selectedIndex}
|
||||
key={node.num}
|
||||
selected={node.num === selectedIndex}
|
||||
setSelected={(): void => {
|
||||
setSelectedIndex(node.number);
|
||||
setSelectedIndex(node.num);
|
||||
}}
|
||||
actions={<IconButton nested icon={<FiSettings />} />}
|
||||
>
|
||||
<div className="flex dark:text-white">
|
||||
<div className="m-auto">
|
||||
<Hashicon value={node.number.toString()} size={32} />
|
||||
<Hashicon value={node.num.toString()} size={32} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-auto mr-auto font-semibold dark:text-white">
|
||||
|
||||
@@ -3,15 +3,15 @@ import type React from 'react';
|
||||
import { FiClock } from 'react-icons/fi';
|
||||
|
||||
import { Tooltip } from '@components/generic/Tooltip';
|
||||
import type { Node } from '@core/slices/meshtasticSlice';
|
||||
import { Hashicon } from '@emeraldpay/hashicon-react';
|
||||
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
||||
|
||||
export interface MessageProps {
|
||||
lastMsgSameUser: boolean;
|
||||
message: string;
|
||||
ack: boolean;
|
||||
rxTime: Date;
|
||||
sender?: Node;
|
||||
sender?: Protobuf.NodeInfo;
|
||||
}
|
||||
|
||||
export const Message = ({
|
||||
@@ -59,7 +59,7 @@ export const Message = ({
|
||||
) : (
|
||||
<div className="mx-6 flex gap-2">
|
||||
<div className="my-auto w-8">
|
||||
<Hashicon value={(sender?.number ?? 0).toString()} size={32} />
|
||||
<Hashicon value={(sender?.num ?? 0).toString()} size={32} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex gap-2">
|
||||
|
||||
@@ -52,10 +52,10 @@ export const Messages = (): JSX.Element => {
|
||||
<div className="mx-2 border-b border-gray-400 dark:border-gray-600" />
|
||||
)}
|
||||
{nodes
|
||||
.filter((node) => node.number !== myNodeNum)
|
||||
.filter((node) => node.num !== myNodeNum)
|
||||
.map((node) => (
|
||||
<DmChat
|
||||
key={node.number}
|
||||
key={node.num}
|
||||
node={node}
|
||||
selectedIndex={selectedChatIndex}
|
||||
setSelectedIndex={setSelectedChatIndex}
|
||||
@@ -81,7 +81,7 @@ export const Messages = (): JSX.Element => {
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-gray-500 dark:text-gray-400">
|
||||
{nodes.find((n) => n.number === selectedChatIndex)?.user
|
||||
{nodes.find((node) => node.num === selectedChatIndex)?.user
|
||||
?.longName ?? 'Unknown'}
|
||||
</span>
|
||||
)}
|
||||
@@ -106,7 +106,7 @@ export const Messages = (): JSX.Element => {
|
||||
.packet.from === message.message.packet.from
|
||||
}
|
||||
sender={nodes.find(
|
||||
(node) => node.number === message.message.packet.from,
|
||||
(node) => node.num === message.message.packet.from,
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -21,14 +21,14 @@ import { SidebarOverlay } from '@components/generic/Sidebar/SidebarOverlay';
|
||||
import { Tooltip } from '@components/generic/Tooltip';
|
||||
import { SidebarItem } from '@components/layout/Sidebar/SidebarItem';
|
||||
import { CopyButton } from '@components/menu/buttons/CopyButton';
|
||||
import type { Node } from '@core/slices/meshtasticSlice';
|
||||
import { Hashicon } from '@emeraldpay/hashicon-react';
|
||||
import { useMapbox } from '@hooks/useMapbox';
|
||||
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
||||
|
||||
type PositionConfidence = 'high' | 'low' | 'none';
|
||||
|
||||
export interface NodeCardProps {
|
||||
node: Node;
|
||||
node: Protobuf.NodeInfo;
|
||||
isMyNode: boolean;
|
||||
selected: boolean;
|
||||
setSelected: () => void;
|
||||
@@ -47,14 +47,14 @@ export const NodeCard = ({
|
||||
|
||||
useEffect(() => {
|
||||
setPositionConfidence(
|
||||
node.currentPosition
|
||||
? new Date(node.currentPosition.posTimestamp * 1000) >
|
||||
node.position
|
||||
? new Date(node.position.posTimestamp * 1000) >
|
||||
new Date(new Date().getTime() - 1000 * 60 * 30)
|
||||
? 'high'
|
||||
: 'low'
|
||||
: 'none',
|
||||
);
|
||||
}, [node.currentPosition]);
|
||||
}, [node.position]);
|
||||
return (
|
||||
<>
|
||||
<SidebarItem
|
||||
@@ -69,11 +69,11 @@ export const NodeCard = ({
|
||||
onClick={(e): void => {
|
||||
e.stopPropagation();
|
||||
setSelected();
|
||||
if (PositionConfidence !== 'none' && node.currentPosition) {
|
||||
if (PositionConfidence !== 'none' && node.position) {
|
||||
map?.flyTo({
|
||||
center: new LngLat(
|
||||
node.currentPosition.longitudeI / 1e7,
|
||||
node.currentPosition.latitudeI / 1e7,
|
||||
node.position.longitudeI / 1e7,
|
||||
node.position.latitudeI / 1e7,
|
||||
),
|
||||
zoom: 16,
|
||||
});
|
||||
@@ -113,12 +113,12 @@ export const NodeCard = ({
|
||||
</m.div>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Hashicon value={node.number.toString()} size={32} />
|
||||
<Hashicon value={node.num.toString()} size={32} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-auto mr-auto text-xs font-semibold dark:text-gray-400">
|
||||
{node.lastHeard.getTime()
|
||||
? node.lastHeard.toLocaleTimeString(undefined, {
|
||||
{node.lastHeard
|
||||
? new Date(node.lastHeard).toLocaleTimeString(undefined, {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
@@ -136,7 +136,7 @@ export const NodeCard = ({
|
||||
<CollapsibleSection title="User" icon={<FiUser />}>
|
||||
<div className="flex p-2">
|
||||
<div className="m-auto flex flex-col gap-2">
|
||||
<Hashicon value={node.number.toString()} size={180} />
|
||||
<Hashicon value={node.num.toString()} size={180} />
|
||||
<div className="text-center text-lg font-medium dark:text-white">
|
||||
{node?.user?.longName || 'Unknown'}
|
||||
</div>
|
||||
@@ -146,18 +146,18 @@ export const NodeCard = ({
|
||||
<CollapsibleSection title="Location" icon={<FiMapPin />}>
|
||||
<>
|
||||
<div className="flex h-10 select-none justify-between rounded-md border border-gray-400 bg-transparent bg-gray-300 px-1 text-gray-500 dark:border-gray-600 dark:bg-secondaryDark dark:text-gray-400 ">
|
||||
{node.currentPosition ? (
|
||||
{node.position ? (
|
||||
<>
|
||||
<div className="my-auto px-1">
|
||||
{(node.currentPosition.latitudeI / 1e7).toPrecision(6)}
|
||||
{(node.position.latitudeI / 1e7).toPrecision(6)}
|
||||
,
|
||||
{(node.currentPosition?.longitudeI / 1e7).toPrecision(6)}
|
||||
{(node.position?.longitudeI / 1e7).toPrecision(6)}
|
||||
</div>
|
||||
<CopyButton
|
||||
data={
|
||||
node.currentPosition
|
||||
? `${node.currentPosition.latitudeI / 1e7},${
|
||||
node.currentPosition.longitudeI / 1e7
|
||||
node.position
|
||||
? `${node.position.latitudeI / 1e7},${
|
||||
node.position.longitudeI / 1e7
|
||||
}`
|
||||
: ''
|
||||
}
|
||||
|
||||
+20
-20
@@ -37,8 +37,8 @@ export const Nodes = (): JSX.Element => {
|
||||
|
||||
nodes.map((node, index) => {
|
||||
tmpNodes.push({
|
||||
id: node.number.toString(),
|
||||
data: { label: node.user?.longName ?? `Unknown ${node.number}` },
|
||||
id: node.num.toString(),
|
||||
data: { label: node.user?.longName ?? `Unknown ${node.num}` },
|
||||
position: { x: index * 160 + 500, y: 100 + 500 },
|
||||
});
|
||||
});
|
||||
@@ -50,7 +50,7 @@ export const Nodes = (): JSX.Element => {
|
||||
const tmpEdges: Edge[] = [];
|
||||
|
||||
nodes.map((node, index) => {
|
||||
if (node.number === myNodeNum) {
|
||||
if (node.num === myNodeNum) {
|
||||
tmpEdges.push({
|
||||
id: `e${1}-${myNodeNum}`,
|
||||
source: '1',
|
||||
@@ -63,15 +63,15 @@ export const Nodes = (): JSX.Element => {
|
||||
});
|
||||
}
|
||||
|
||||
node.routes.map((route) => {
|
||||
tmpEdges.push({
|
||||
id: `e${route.from}-${route.to}`,
|
||||
source: node.number.toString(),
|
||||
target: route.to.toString(),
|
||||
type: 'smoothstep',
|
||||
animated: true,
|
||||
});
|
||||
});
|
||||
// node.routes.map((route) => {
|
||||
// tmpEdges.push({
|
||||
// id: `e${route.from}-${route.to}`,
|
||||
// source: node.num.toString(),
|
||||
// target: route.to.toString(),
|
||||
// type: 'smoothstep',
|
||||
// animated: true,
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
setGraphEdges(tmpEdges);
|
||||
@@ -85,17 +85,17 @@ export const Nodes = (): JSX.Element => {
|
||||
<>
|
||||
{nodes.map((node) => (
|
||||
<SidebarItem
|
||||
key={node.number}
|
||||
selected={node.number === selected}
|
||||
key={node.num}
|
||||
selected={node.num === selected}
|
||||
setSelected={(): void => {
|
||||
setSelected(node.number);
|
||||
setSelected(node.num);
|
||||
}}
|
||||
actions={
|
||||
<IconButton
|
||||
nested
|
||||
onClick={(e): void => {
|
||||
e.stopPropagation();
|
||||
setSelected(node.number);
|
||||
setSelected(node.num);
|
||||
}}
|
||||
icon={<FiSettings />}
|
||||
/>
|
||||
@@ -103,7 +103,7 @@ export const Nodes = (): JSX.Element => {
|
||||
>
|
||||
<div className="flex dark:text-white">
|
||||
<div className="relative m-auto">
|
||||
{node.number === myNodeNum && (
|
||||
{node.num === myNodeNum && (
|
||||
<Tooltip content="Your Node">
|
||||
<m.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
@@ -113,12 +113,12 @@ export const Nodes = (): JSX.Element => {
|
||||
</m.div>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Hashicon value={node.number.toString()} size={32} />
|
||||
<Hashicon value={node.num.toString()} size={32} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-auto mr-auto text-xs font-semibold dark:text-gray-400">
|
||||
{node.lastHeard.getTime()
|
||||
? node.lastHeard.toLocaleTimeString(undefined, {
|
||||
{node.lastHeard
|
||||
? new Date(node.lastHeard).toLocaleTimeString(undefined, {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user