WIP
This commit is contained in:
+3
-2
@@ -33,7 +33,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"homepage": "https://meshtastic.org",
|
"homepage": "https://meshtastic.org",
|
||||||
"dependencies": {
|
"ddbependencies": {
|
||||||
"@bufbuild/protobuf": "^2.2.3",
|
"@bufbuild/protobuf": "^2.2.3",
|
||||||
"@meshtastic/core": "npm:@jsr/meshtastic__core@2.6.0-0",
|
"@meshtastic/core": "npm:@jsr/meshtastic__core@2.6.0-0",
|
||||||
"@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
|
"@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
|
||||||
@@ -61,6 +61,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.4",
|
"cmdk": "^1.0.4",
|
||||||
"crypto-random-string": "^5.0.0",
|
"crypto-random-string": "^5.0.0",
|
||||||
|
"idb-keyval": "^6.2.1",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"lucide-react": "^0.477.0",
|
"lucide-react": "^0.477.0",
|
||||||
@@ -100,7 +101,7 @@
|
|||||||
"tar": "^7.4.3",
|
"tar": "^7.4.3",
|
||||||
"testing-library": "^0.0.2",
|
"testing-library": "^0.0.2",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"vite": "^6.2.0",
|
"vite": "^6.2.3",
|
||||||
"vitest": "^3.0.7",
|
"vitest": "^3.0.7",
|
||||||
"vite-plugin-pwa": "^0.21.1"
|
"vite-plugin-pwa": "^0.21.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import { subscribeAll } from "@core/subscriptions.ts";
|
|||||||
import { randId } from "@core/utils/randId.ts";
|
import { randId } from "@core/utils/randId.ts";
|
||||||
import { BleConnection, ServiceUuid } from "@meshtastic/js";
|
import { BleConnection, ServiceUuid } from "@meshtastic/js";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { useMessageStore } from "@core/stores/messageStore.ts";
|
||||||
|
|
||||||
export const BLE = ({ closeDialog }: TabElementProps) => {
|
export const BLE = ({ closeDialog }: TabElementProps) => {
|
||||||
const [bleDevices, setBleDevices] = useState<BluetoothDevice[]>([]);
|
const [bleDevices, setBleDevices] = useState<BluetoothDevice[]>([]);
|
||||||
const { addDevice } = useDeviceStore();
|
const { addDevice } = useDeviceStore();
|
||||||
|
const messageStore = useMessageStore()
|
||||||
const { setSelectedDevice } = useAppStore();
|
const { setSelectedDevice } = useAppStore();
|
||||||
|
|
||||||
const updateBleDeviceList = useCallback(async (): Promise<void> => {
|
const updateBleDeviceList = useCallback(async (): Promise<void> => {
|
||||||
@@ -30,7 +32,7 @@ export const BLE = ({ closeDialog }: TabElementProps) => {
|
|||||||
device: bleDevice,
|
device: bleDevice,
|
||||||
});
|
});
|
||||||
device.addConnection(connection);
|
device.addConnection(connection);
|
||||||
subscribeAll(device, connection);
|
subscribeAll(device, connection, messageStore);
|
||||||
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { MeshDevice } from "@meshtastic/core";
|
|||||||
import { TransportHTTP } from "@meshtastic/transport-http";
|
import { TransportHTTP } from "@meshtastic/transport-http";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useForm, useController } from "react-hook-form";
|
import { useForm, useController } from "react-hook-form";
|
||||||
|
import { useMessageStore } from "@core/stores/messageStore.ts";
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
ip: string;
|
ip: string;
|
||||||
@@ -21,6 +22,7 @@ export const HTTP = ({ closeDialog }: TabElementProps) => {
|
|||||||
const isURLHTTPS = location.protocol === "https:";
|
const isURLHTTPS = location.protocol === "https:";
|
||||||
|
|
||||||
const { addDevice } = useDeviceStore();
|
const { addDevice } = useDeviceStore();
|
||||||
|
const messageStore = useMessageStore();
|
||||||
const { setSelectedDevice } = useAppStore();
|
const { setSelectedDevice } = useAppStore();
|
||||||
|
|
||||||
const { control, handleSubmit, register } = useForm<FormData>({
|
const { control, handleSubmit, register } = useForm<FormData>({
|
||||||
@@ -49,7 +51,7 @@ export const HTTP = ({ closeDialog }: TabElementProps) => {
|
|||||||
connection.configure();
|
connection.configure();
|
||||||
setSelectedDevice(id);
|
setSelectedDevice(id);
|
||||||
device.addConnection(connection);
|
device.addConnection(connection);
|
||||||
subscribeAll(device, connection);
|
subscribeAll(device, connection, messageStore);
|
||||||
closeDialog();
|
closeDialog();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ import { randId } from "@core/utils/randId.ts";
|
|||||||
import { MeshDevice } from "@meshtastic/core";
|
import { MeshDevice } from "@meshtastic/core";
|
||||||
import { TransportWebSerial } from "@meshtastic/transport-web-serial";
|
import { TransportWebSerial } from "@meshtastic/transport-web-serial";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { useMessageStore } from "@core/stores/messageStore.ts";
|
||||||
|
|
||||||
export const Serial = ({ closeDialog }: TabElementProps) => {
|
export const Serial = ({ closeDialog }: TabElementProps) => {
|
||||||
const [serialPorts, setSerialPorts] = useState<SerialPort[]>([]);
|
const [serialPorts, setSerialPorts] = useState<SerialPort[]>([]);
|
||||||
const { addDevice } = useDeviceStore();
|
const { addDevice } = useDeviceStore();
|
||||||
|
const messageStore = useMessageStore()
|
||||||
const { setSelectedDevice } = useAppStore();
|
const { setSelectedDevice } = useAppStore();
|
||||||
|
|
||||||
const updateSerialPortList = useCallback(async () => {
|
const updateSerialPortList = useCallback(async () => {
|
||||||
@@ -36,7 +38,7 @@ export const Serial = ({ closeDialog }: TabElementProps) => {
|
|||||||
const connection = new MeshDevice(transport, id);
|
const connection = new MeshDevice(transport, id);
|
||||||
connection.configure();
|
connection.configure();
|
||||||
device.addConnection(connection);
|
device.addConnection(connection);
|
||||||
subscribeAll(device, connection);
|
subscribeAll(device, connection, messageStore);
|
||||||
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -101,10 +101,10 @@ const StatusIcon = ({ state, className, ...otherProps }: StatusIconProps) => {
|
|||||||
const TimeDisplay = memo(({ date, className }: { date: Date; className?: string }) => (
|
const TimeDisplay = memo(({ date, className }: { date: Date; className?: string }) => (
|
||||||
<div className={cn("flex items-center gap-2 shrink-0", className)}>
|
<div className={cn("flex items-center gap-2 shrink-0", className)}>
|
||||||
<span className="text-xs text-slate-500 dark:text-slate-400 font-mono">
|
<span className="text-xs text-slate-500 dark:text-slate-400 font-mono">
|
||||||
{date.toLocaleDateString()}
|
{date?.toLocaleDateString()}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-slate-500 dark:text-slate-400 font-mono">
|
<span className="text-xs text-slate-500 dark:text-slate-400 font-mono">
|
||||||
{date.toLocaleTimeString(undefined, {
|
{date?.toLocaleTimeString(undefined, {
|
||||||
hour: "2-digit",
|
hour: "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
})}
|
})}
|
||||||
@@ -112,7 +112,9 @@ const TimeDisplay = memo(({ date, className }: { date: Date; className?: string
|
|||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
|
|
||||||
export const Message = memo(({ lastMsgSameUser, message, sender }: MessageProps) => {
|
export const Message = (({ lastMsgSameUser, message, sender }: MessageProps) => {
|
||||||
|
console.log('Message', message);
|
||||||
|
|
||||||
const { getDevices } = useDeviceStore();
|
const { getDevices } = useDeviceStore();
|
||||||
|
|
||||||
const isDeviceUser = useMemo(
|
const isDeviceUser = useMemo(
|
||||||
@@ -162,7 +164,7 @@ export const Message = memo(({ lastMsgSameUser, message, sender }: MessageProps)
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<TimeDisplay date={message.rxTime} />
|
<TimeDisplay date={message?.rxTime} />
|
||||||
<div className="flex place-items-center gap-2 pb-2">
|
<div className="flex place-items-center gap-2 pb-2">
|
||||||
<div className={cn(isDeviceUser && "pl-11", messageTextClass)}>
|
<div className={cn(isDeviceUser && "pl-11", messageTextClass)}>
|
||||||
{message.data}
|
{message.data}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useDevice } from "@core/stores/deviceStore.ts";
|
|||||||
import type { Types } from "@meshtastic/core";
|
import type { Types } from "@meshtastic/core";
|
||||||
import { SendIcon } from "lucide-react";
|
import { SendIcon } from "lucide-react";
|
||||||
import { startTransition, useCallback, useMemo, useState } from "react";
|
import { startTransition, useCallback, useMemo, useState } from "react";
|
||||||
|
import { useMessageStore } from "@core/stores/messageStore.ts";
|
||||||
|
|
||||||
export interface MessageInputProps {
|
export interface MessageInputProps {
|
||||||
to: Types.Destination;
|
to: Types.Destination;
|
||||||
@@ -19,13 +20,11 @@ export const MessageInput = ({
|
|||||||
}: MessageInputProps) => {
|
}: MessageInputProps) => {
|
||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
setMessageState,
|
|
||||||
messageDraft,
|
messageDraft,
|
||||||
setMessageDraft,
|
setMessageDraft,
|
||||||
isQueueingMessages,
|
|
||||||
queueStatus,
|
|
||||||
hardware,
|
hardware,
|
||||||
} = useDevice();
|
} = useDevice();
|
||||||
|
const { setMessageState } = useMessageStore()
|
||||||
const myNodeNum = hardware.myNodeNum;
|
const myNodeNum = hardware.myNodeNum;
|
||||||
const [localDraft, setLocalDraft] = useState(messageDraft);
|
const [localDraft, setLocalDraft] = useState(messageDraft);
|
||||||
const [messageBytes, setMessageBytes] = useState(0);
|
const [messageBytes, setMessageBytes] = useState(0);
|
||||||
@@ -62,7 +61,7 @@ export const MessageInput = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[channel, connection, myNodeNum, setMessageState, to, queueStatus],
|
[channel, connection, myNodeNum, setMessageState, to],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -85,12 +84,10 @@ export const MessageInput = ({
|
|||||||
if (localDraft === "") return;
|
if (localDraft === "") return;
|
||||||
const message = formData.get("messageInput") as string;
|
const message = formData.get("messageInput") as string;
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
if (!isQueueingMessages) {
|
|
||||||
sendText(message);
|
sendText(message);
|
||||||
setLocalDraft("");
|
setLocalDraft("");
|
||||||
setMessageDraft("");
|
setMessageDraft("");
|
||||||
setMessageBytes(0);
|
setMessageBytes(0);
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { StateStorage } from "zustand/middleware";
|
||||||
|
import { get, set, del } from "idb-keyval";
|
||||||
|
|
||||||
|
export const zustandIDBStorage: StateStorage = {
|
||||||
|
getItem: async (name: string): Promise<string | null> => {
|
||||||
|
return (await get(name)) || null;
|
||||||
|
},
|
||||||
|
setItem: async (name: string, value: string): Promise<void> => {
|
||||||
|
await set(name, value);
|
||||||
|
},
|
||||||
|
removeItem: async (name: string): Promise<void> => {
|
||||||
|
await del(name);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -30,10 +30,6 @@ export type DialogVariant =
|
|||||||
| "unsafeRoles"
|
| "unsafeRoles"
|
||||||
| "refreshKeys";
|
| "refreshKeys";
|
||||||
|
|
||||||
type QueueStatus = {
|
|
||||||
res: number, free: number, maxlen: number
|
|
||||||
}
|
|
||||||
|
|
||||||
type NodeError = {
|
type NodeError = {
|
||||||
node: number;
|
node: number;
|
||||||
error: string;
|
error: string;
|
||||||
@@ -66,8 +62,6 @@ export interface Device {
|
|||||||
// currentMetrics: Protobuf.DeviceMetrics;
|
// currentMetrics: Protobuf.DeviceMetrics;
|
||||||
pendingSettingsChanges: boolean;
|
pendingSettingsChanges: boolean;
|
||||||
messageDraft: string;
|
messageDraft: string;
|
||||||
queueStatus: QueueStatus,
|
|
||||||
isQueueingMessages: boolean,
|
|
||||||
dialog: {
|
dialog: {
|
||||||
import: boolean;
|
import: boolean;
|
||||||
QR: boolean;
|
QR: boolean;
|
||||||
@@ -116,7 +110,6 @@ export interface Device {
|
|||||||
getDialogOpen: (dialog: DialogVariant) => boolean;
|
getDialogOpen: (dialog: DialogVariant) => boolean;
|
||||||
processPacket: (data: ProcessPacketParams) => void;
|
processPacket: (data: ProcessPacketParams) => void;
|
||||||
setMessageDraft: (message: string) => void;
|
setMessageDraft: (message: string) => void;
|
||||||
setQueueStatus: (status: QueueStatus) => void;
|
|
||||||
setNodeError: (nodeNum: number, error: string) => void;
|
setNodeError: (nodeNum: number, error: string) => void;
|
||||||
clearNodeError: (nodeNum: number) => void;
|
clearNodeError: (nodeNum: number) => void;
|
||||||
getNodeError: (nodeNum: number) => NodeError | undefined;
|
getNodeError: (nodeNum: number) => NodeError | undefined;
|
||||||
@@ -160,10 +153,6 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
activePage: "messages",
|
activePage: "messages",
|
||||||
activeNode: 0,
|
activeNode: 0,
|
||||||
waypoints: [],
|
waypoints: [],
|
||||||
queueStatus: {
|
|
||||||
res: 0, free: 0, maxlen: 0
|
|
||||||
},
|
|
||||||
isQueueingMessages: false,
|
|
||||||
dialog: {
|
dialog: {
|
||||||
import: false,
|
import: false,
|
||||||
QR: false,
|
QR: false,
|
||||||
@@ -664,17 +653,6 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
setQueueStatus: (status: QueueStatus) => {
|
|
||||||
set(
|
|
||||||
produce<DeviceState>((draft) => {
|
|
||||||
const device = draft.devices.get(id);
|
|
||||||
if (device) {
|
|
||||||
device.queueStatus = status;
|
|
||||||
device.queueStatus.free >= 10 ? true : false
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
setNodeError: (nodeNum, error) => {
|
setNodeError: (nodeNum, error) => {
|
||||||
set(
|
set(
|
||||||
produce<DeviceState>((draft) => {
|
produce<DeviceState>((draft) => {
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { persist, createJSONStorage } from 'zustand/middleware';
|
||||||
|
import { produce } from 'immer';
|
||||||
|
import { Types } from '@meshtastic/core';
|
||||||
|
import { zustandIDBStorage } from "@core/services/messaging/db.ts";
|
||||||
|
|
||||||
|
export interface MessageWithState {
|
||||||
|
id: number;
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
channel: number;
|
||||||
|
content: string;
|
||||||
|
state: 'ack' | 'waiting' | 'failed';
|
||||||
|
type: 'direct' | 'broadcast';
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageType = 'direct' | 'broadcast';
|
||||||
|
|
||||||
|
export interface MessageStore {
|
||||||
|
messages: {
|
||||||
|
direct: Record<number, MessageWithState[]>;
|
||||||
|
broadcast: Record<number, MessageWithState[]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
activeChat: number;
|
||||||
|
chatType: MessageType;
|
||||||
|
|
||||||
|
setActiveChat: (chat: number) => void;
|
||||||
|
setChatType: (type: MessageType) => void;
|
||||||
|
addMessage: (message: MessageWithState) => void;
|
||||||
|
getMessages: (type: MessageType, key: number) => MessageWithState[];
|
||||||
|
setMessageState: (
|
||||||
|
type: MessageType,
|
||||||
|
key: number,
|
||||||
|
messageId: number,
|
||||||
|
newState: MessageWithState['state']
|
||||||
|
) => void;
|
||||||
|
clearMessages: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMessageStore = create<MessageStore>()(
|
||||||
|
persist(
|
||||||
|
(set, get) => ({
|
||||||
|
messages: {
|
||||||
|
direct: {},
|
||||||
|
broadcast: {},
|
||||||
|
},
|
||||||
|
|
||||||
|
activeChat: Types.ChannelNumber.Primary,
|
||||||
|
chatType: 'broadcast',
|
||||||
|
|
||||||
|
setActiveChat: (chat) => {
|
||||||
|
set(produce((state: MessageStore) => {
|
||||||
|
state.activeChat = chat;
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
setChatType: (type) => {
|
||||||
|
set(produce((state: MessageStore) => {
|
||||||
|
state.chatType = type;
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
addMessage: (message) => {
|
||||||
|
set(produce((state: MessageStore) => {
|
||||||
|
const group = message.type === 'direct' ? state.messages.direct : state.messages.broadcast;
|
||||||
|
const key = message.type === 'direct' ? message.from : message.channel;
|
||||||
|
if (!group[key]) {
|
||||||
|
group[key] = [];
|
||||||
|
}
|
||||||
|
group[key].push(message);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
getMessages: (type, key) => {
|
||||||
|
const group = type === 'direct' ? get().messages.direct : get().messages.broadcast;
|
||||||
|
return group[key] ?? [];
|
||||||
|
},
|
||||||
|
|
||||||
|
setMessageState: (type, key, messageId, newState) => {
|
||||||
|
set(produce((state: MessageStore) => {
|
||||||
|
const group = type === 'direct' ? state.messages.direct : state.messages.broadcast;
|
||||||
|
const messages = group[key];
|
||||||
|
if (!messages) return;
|
||||||
|
const message = messages.find((msg) => msg.id === messageId);
|
||||||
|
if (message) {
|
||||||
|
message.state = newState;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
clearMessages: () => {
|
||||||
|
set(produce((state: MessageStore) => {
|
||||||
|
state.messages.direct = {};
|
||||||
|
state.messages.broadcast = {};
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: 'mesh-messages',
|
||||||
|
storage: createJSONStorage(() => zustandIDBStorage),
|
||||||
|
// ✅ No need for partialize magic — simple object storage
|
||||||
|
partialize: (state) => ({
|
||||||
|
activeChat: state.activeChat,
|
||||||
|
chatType: state.chatType,
|
||||||
|
messages: state.messages,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import type { Device } from "@core/stores/deviceStore.ts";
|
import type { Device } from "@core/stores/deviceStore.ts";
|
||||||
import { MeshDevice, Protobuf } from "@meshtastic/core";
|
import { MeshDevice, Protobuf } from "@meshtastic/core";
|
||||||
|
import type { MessageStore } from "@core/stores/messageStore.ts";
|
||||||
|
|
||||||
export const subscribeAll = (
|
export const subscribeAll = (
|
||||||
device: Device,
|
device: Device,
|
||||||
connection: MeshDevice,
|
connection: MeshDevice,
|
||||||
|
messageStore: MessageStore
|
||||||
) => {
|
) => {
|
||||||
let myNodeNum = 0;
|
let myNodeNum = 0;
|
||||||
|
|
||||||
@@ -15,6 +17,8 @@ export const subscribeAll = (
|
|||||||
});
|
});
|
||||||
|
|
||||||
connection.events.onRoutingPacket.subscribe((routingPacket) => {
|
connection.events.onRoutingPacket.subscribe((routingPacket) => {
|
||||||
|
console.log("routingPacket", routingPacket);
|
||||||
|
|
||||||
switch (routingPacket.data.variant.case) {
|
switch (routingPacket.data.variant.case) {
|
||||||
case "errorReason": {
|
case "errorReason": {
|
||||||
if (
|
if (
|
||||||
@@ -81,8 +85,10 @@ export const subscribeAll = (
|
|||||||
|
|
||||||
|
|
||||||
connection.events.onMessagePacket.subscribe((messagePacket) => {
|
connection.events.onMessagePacket.subscribe((messagePacket) => {
|
||||||
device.addMessage({
|
console.log("messagePacket", messagePacket);
|
||||||
|
messageStore.addMessage({
|
||||||
...messagePacket,
|
...messagePacket,
|
||||||
|
|
||||||
state: messagePacket.from !== myNodeNum ? "ack" : "waiting",
|
state: messagePacket.from !== myNodeNum ? "ack" : "waiting",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -105,9 +111,9 @@ export const subscribeAll = (
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.events.onQueueStatus.subscribe((queueStatus) => {
|
// connection.events.onQueueStatus.subscribe((queueStatus) => {
|
||||||
device.setQueueStatus(queueStatus);
|
// device.setQueueStatus(queueStatus);
|
||||||
});
|
// });
|
||||||
|
|
||||||
connection.events.onRoutingPacket.subscribe((routingPacket) => {
|
connection.events.onRoutingPacket.subscribe((routingPacket) => {
|
||||||
if (routingPacket.data.variant.case === "errorReason") {
|
if (routingPacket.data.variant.case === "errorReason") {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useAppStore } from "../core/stores/appStore.ts";
|
|
||||||
import { ChannelChat } from "@components/PageComponents/Messages/ChannelChat.tsx";
|
import { ChannelChat } from "@components/PageComponents/Messages/ChannelChat.tsx";
|
||||||
import { PageLayout } from "@components/PageLayout.tsx";
|
import { PageLayout } from "@components/PageLayout.tsx";
|
||||||
import { Sidebar } from "@components/Sidebar.tsx";
|
import { Sidebar } from "@components/Sidebar.tsx";
|
||||||
@@ -14,11 +13,14 @@ import { HashIcon, LockIcon, LockOpenIcon } from "lucide-react";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx";
|
import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx";
|
||||||
import { cn } from "@core/utils/cn.ts";
|
import { cn } from "@core/utils/cn.ts";
|
||||||
|
import { useMessageStore } from "@core/stores/messageStore.ts";
|
||||||
|
|
||||||
export const MessagesPage = () => {
|
export const MessagesPage = () => {
|
||||||
const { channels, nodes, hardware, messages, hasNodeError } = useDevice();
|
const { channels, nodes, hardware, hasNodeError } = useDevice();
|
||||||
const { activeChat, chatType, setActiveChat, setChatType } = useAppStore();
|
const { getMessages, setActiveChat, chatType, activeChat, setChatType } = useMessageStore()
|
||||||
|
const { toast } = useToast();
|
||||||
const [searchTerm, setSearchTerm] = useState<string>("");
|
const [searchTerm, setSearchTerm] = useState<string>("");
|
||||||
|
|
||||||
const filteredNodes = Array.from(nodes.values()).filter((node) => {
|
const filteredNodes = Array.from(nodes.values()).filter((node) => {
|
||||||
if (node.num === hardware.myNodeNum) return false;
|
if (node.num === hardware.myNodeNum) return false;
|
||||||
const nodeName = node.user?.longName ?? `!${numberToHexUnpadded(node.num)}`;
|
const nodeName = node.user?.longName ?? `!${numberToHexUnpadded(node.num)}`;
|
||||||
@@ -29,7 +31,6 @@ export const MessagesPage = () => {
|
|||||||
(ch) => ch.role !== Protobuf.Channel.Channel_Role.DISABLED,
|
(ch) => ch.role !== Protobuf.Channel.Channel_Role.DISABLED,
|
||||||
);
|
);
|
||||||
const currentChannel = channels.get(activeChat);
|
const currentChannel = channels.get(activeChat);
|
||||||
const { toast } = useToast();
|
|
||||||
const node = nodes.get(activeChat);
|
const node = nodes.get(activeChat);
|
||||||
const nodeHex = node?.num ? numberToHexUnpadded(node.num) : "Unknown";
|
const nodeHex = node?.num ? numberToHexUnpadded(node.num) : "Unknown";
|
||||||
|
|
||||||
@@ -130,7 +131,7 @@ export const MessagesPage = () => {
|
|||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
<ChannelChat
|
<ChannelChat
|
||||||
key={currentChannel.index}
|
key={currentChannel.index}
|
||||||
messages={messages.broadcast.get(currentChannel.index)}
|
messages={getMessages('broadcast', currentChannel?.index)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,7 +142,7 @@ export const MessagesPage = () => {
|
|||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
<ChannelChat
|
<ChannelChat
|
||||||
key={node.num}
|
key={node.num}
|
||||||
messages={messages.direct.get(node.num)}
|
messages={getMessages('direct', node?.num)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user