diff --git a/src/components/UI/Sidebar/sidebarButton.tsx b/src/components/UI/Sidebar/sidebarButton.tsx
index b6444bb8..bbd99725 100644
--- a/src/components/UI/Sidebar/sidebarButton.tsx
+++ b/src/components/UI/Sidebar/sidebarButton.tsx
@@ -3,6 +3,7 @@ import type { LucideIcon } from "lucide-react";
export interface SidebarButtonProps {
label: string;
+ count?: number;
active?: boolean;
Icon?: LucideIcon;
element?;
@@ -13,6 +14,7 @@ export const SidebarButton = ({
label,
active,
Icon,
+ count,
element,
onClick,
}: SidebarButtonProps) => (
@@ -25,5 +27,6 @@ export const SidebarButton = ({
{Icon && }
{element && element}
{label}
+ {count > 0 &&
{count}
}
);
diff --git a/src/core/stores/appStore.ts b/src/core/stores/appStore.ts
index 4b286e6f..42143426 100644
--- a/src/core/stores/appStore.ts
+++ b/src/core/stores/appStore.ts
@@ -9,6 +9,7 @@ export interface RasterSource {
tileSize: number;
}
+
interface ErrorState {
field: string;
message: string;
@@ -19,7 +20,12 @@ interface ErrorState {
message: string;
}
-interface AppState {
+export interface App {
+ unreadCounts: Map;
+ setUnread: (id: number, count: number) => void;
+}
+
+export interface AppState {
selectedDevice: number;
devices: {
id: number;
@@ -34,6 +40,7 @@ interface AppState {
activeChat: number;
chatType: "broadcast" | "direct";
errors: ErrorState[];
+ unreadCounts: Map;
setRasterSources: (sources: RasterSource[]) => void;
addRasterSource: (source: RasterSource) => void;
@@ -56,6 +63,9 @@ interface AppState {
removeError: (field: string) => void;
clearErrors: () => void;
setNewErrors: (newErrors: ErrorState[]) => void;
+
+ // unread counts
+ setUnread: (id: number, count: number) => void;
}
export const useAppStore = create()((set, get) => ({
@@ -70,6 +80,7 @@ export const useAppStore = create()((set, get) => ({
activeChat: Types.ChannelNumber.Primary,
chatType: "broadcast",
errors: [],
+ unreadCounts: new Map([[0, 100],[2718471552, 1]]),
setRasterSources: (sources: RasterSource[]) => {
set(
@@ -178,4 +189,11 @@ export const useAppStore = create()((set, get) => ({
}),
);
},
+ setUnread: (id: number, count: number) => {
+ set(
+ produce((draft) => {
+ draft.unreadCounts.set(id, count);
+ })
+ );
+ }
}));
diff --git a/src/core/stores/deviceStore.ts b/src/core/stores/deviceStore.ts
index 0822473f..e2bde391 100644
--- a/src/core/stores/deviceStore.ts
+++ b/src/core/stores/deviceStore.ts
@@ -64,6 +64,7 @@ export interface Device {
pkiBackup: boolean;
nodeDetails: boolean;
};
+ unreadCounts: Map;
setStatus: (status: Types.DeviceStatusEnum) => void;
setConfig: (config: Protobuf.Config.Config) => void;
@@ -98,6 +99,7 @@ export interface Device {
setDialogOpen: (dialog: DialogVariant, open: boolean) => void;
processPacket: (data: ProcessPacketParams) => void;
setMessageDraft: (message: string) => void;
+ setUnread: (id: number, count: number) => void;
}
export interface DeviceState {
@@ -149,6 +151,7 @@ export const useDeviceStore = createStore((set, get) => ({
},
pendingSettingsChanges: false,
messageDraft: "",
+ unreadCounts: new Map([[0, 100],[2718471552, 1]]),
setStatus: (status: Types.DeviceStatusEnum) => {
set(
@@ -631,6 +634,17 @@ export const useDeviceStore = createStore((set, get) => ({
}),
);
},
+ setUnread: (id: number, count: number) => {
+ set(
+ produce((draft) => {
+ console.log(id, count);
+ const device = draft.devices.get(id);
+ if (device) {
+ device.unreadCounts.set(id, count);
+ }
+ })
+ );
+ }
});
}),
);
diff --git a/src/core/subscriptions.ts b/src/core/subscriptions.ts
index 8f1c1a09..7a1a5b95 100644
--- a/src/core/subscriptions.ts
+++ b/src/core/subscriptions.ts
@@ -1,6 +1,7 @@
import type { Device } from "@core/stores/deviceStore.ts";
import { Protobuf, type Types } from "@meshtastic/core";
+
export const subscribeAll = (
device: Device,
connection: Types.ConnectionType,
@@ -84,6 +85,7 @@ export const subscribeAll = (
...messagePacket,
state: messagePacket.from !== myNodeNum ? "ack" : "waiting",
});
+ device.unreadCounts.set(messagePacket.from, 1);
});
connection.events.onTraceRoutePacket.subscribe((traceRoutePacket) => {
diff --git a/src/index.css b/src/index.css
index 7c1ffc76..429dffe1 100644
--- a/src/index.css
+++ b/src/index.css
@@ -110,3 +110,11 @@ img {
.animate-spin-slow {
animation: spin-slower 2s linear infinite;
}
+
+.notification-count {
+ color: white;
+ border-radius: 20%;
+ padding-left: 2%;
+ padding-right: 2%;
+ background-color: rgb(195,0,0);
+}
\ No newline at end of file
diff --git a/src/pages/Messages.tsx b/src/pages/Messages.tsx
index b520f906..c5ca6170 100644
--- a/src/pages/Messages.tsx
+++ b/src/pages/Messages.tsx
@@ -14,7 +14,7 @@ import { HashIcon, LockIcon, LockOpenIcon } from "lucide-react";
import { useState } from "react";
export const MessagesPage = () => {
- const { channels, nodes, hardware, messages } = useDevice();
+ const { channels, nodes, hardware, messages, unreadCounts } = useDevice();
const { activeChat, chatType, setActiveChat, setChatType } = useAppStore();
const [searchTerm, setSearchTerm] = useState("");
const filteredNodes = Array.from(nodes.values()).filter((node) => {
@@ -38,6 +38,7 @@ export const MessagesPage = () => {
{filteredChannels.map((channel) => (
{
onClick={() => {
setChatType("broadcast");
setActiveChat(channel.index);
+ unreadCounts.set(channel.index, 0);
}}
element={}
/>
@@ -66,12 +68,14 @@ export const MessagesPage = () => {
{filteredNodes.map((node) => (
{
setChatType("direct");
setActiveChat(node.num);
+ unreadCounts.set(node.num, 1)
}}
element={