feat: add dependency injection using tanstack context (#680)
* feat: add dep injection using tanstack context * fixed small typo
This commit is contained in:
@@ -5,3 +5,4 @@ stats.html
|
|||||||
.vite
|
.vite
|
||||||
dev-dist
|
dev-dist
|
||||||
__screenshots__*
|
__screenshots__*
|
||||||
|
*.diff
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "src/core/connection"]
|
||||||
|
path = src/core/connection
|
||||||
|
url = https://github.com/meshtastic/js.git
|
||||||
@@ -82,6 +82,7 @@ export const NodeDetailsDialog = ({
|
|||||||
function handleDirectMessage() {
|
function handleDirectMessage() {
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
navigate({ to: `/messages/direct/${node.num}` });
|
navigate({ to: `/messages/direct/${node.num}` });
|
||||||
|
setDialogOpen("nodeDetails", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRequestPosition() {
|
function handleRequestPosition() {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ interface MessageItemProps {
|
|||||||
export const MessageItem = ({ message }: MessageItemProps) => {
|
export const MessageItem = ({ message }: MessageItemProps) => {
|
||||||
const { getNode } = useDevice();
|
const { getNode } = useDevice();
|
||||||
const { getMyNodeNum } = useMessageStore();
|
const { getMyNodeNum } = useMessageStore();
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation("messages");
|
||||||
|
|
||||||
const MESSAGE_STATUS_MAP = useMemo(
|
const MESSAGE_STATUS_MAP = useMemo(
|
||||||
(): Record<MessageState, MessageStatusInfo> => ({
|
(): Record<MessageState, MessageStatusInfo> => ({
|
||||||
@@ -78,7 +78,7 @@ export const MessageItem = ({ message }: MessageItemProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const UNKNOWN_STATUS = useMemo((): MessageStatusInfo => ({
|
const UNKNOWN_STATUS = useMemo((): MessageStatusInfo => ({
|
||||||
displayText: t("delveryStatus.unknown.displayText"),
|
displayText: t("deliveryStatus.unknown.displayText"),
|
||||||
icon: AlertCircle,
|
icon: AlertCircle,
|
||||||
ariaLabel: t("deliveryStatus.unknown.label"),
|
ariaLabel: t("deliveryStatus.unknown.label"),
|
||||||
iconClassName: "text-red-500 dark:text-red-400",
|
iconClassName: "text-red-500 dark:text-red-400",
|
||||||
@@ -99,7 +99,7 @@ export const MessageItem = ({ message }: MessageItemProps) => {
|
|||||||
const { displayName, shortName, isFavorite } = useMemo(() => {
|
const { displayName, shortName, isFavorite } = useMemo(() => {
|
||||||
const userIdHex = message.from.toString(16).toUpperCase().padStart(2, "0");
|
const userIdHex = message.from.toString(16).toUpperCase().padStart(2, "0");
|
||||||
const last4 = userIdHex.slice(-4);
|
const last4 = userIdHex.slice(-4);
|
||||||
const fallbackName = t("message_item_fallbackName_withLastFour", { last4 });
|
const fallbackName = t("fallbackName", { last4 });
|
||||||
const longName = messageUser?.user?.longName;
|
const longName = messageUser?.user?.longName;
|
||||||
const derivedShortName = messageUser?.user?.shortName || fallbackName;
|
const derivedShortName = messageUser?.user?.shortName || fallbackName;
|
||||||
const derivedDisplayName = longName || derivedShortName;
|
const derivedDisplayName = longName || derivedShortName;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const Generator = (
|
|||||||
key: "bit8",
|
key: "bit8",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: t("security.empty"),
|
text: t("security.0bit"),
|
||||||
value: "0",
|
value: "0",
|
||||||
key: "bit0",
|
key: "bit0",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -114,6 +114,8 @@ export interface Device {
|
|||||||
hasNodeError: (nodeNum: number) => boolean;
|
hasNodeError: (nodeNum: number) => boolean;
|
||||||
incrementUnread: (nodeNum: number) => void;
|
incrementUnread: (nodeNum: number) => void;
|
||||||
resetUnread: (nodeNum: number) => void;
|
resetUnread: (nodeNum: number) => void;
|
||||||
|
getUnreadCount: (nodeNum: number) => number;
|
||||||
|
getAllUnreadCount: () => number;
|
||||||
getNodes: (
|
getNodes: (
|
||||||
filter?: (node: Protobuf.Mesh.NodeInfo) => boolean,
|
filter?: (node: Protobuf.Mesh.NodeInfo) => boolean,
|
||||||
) => Protobuf.Mesh.NodeInfo[];
|
) => Protobuf.Mesh.NodeInfo[];
|
||||||
@@ -664,6 +666,24 @@ export const useDeviceStore = createStore<PrivateDeviceState>((set, get) => ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
getUnreadCount: (nodeNum: number): number => {
|
||||||
|
const device = get().devices.get(id);
|
||||||
|
if (!device) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return device.unreadCounts.get(nodeNum) ?? 0;
|
||||||
|
},
|
||||||
|
getAllUnreadCount: (): number => {
|
||||||
|
const device = get().devices.get(id);
|
||||||
|
if (!device) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let totalUnread = 0;
|
||||||
|
device.unreadCounts.forEach((count) => {
|
||||||
|
totalUnread += count;
|
||||||
|
});
|
||||||
|
return totalUnread;
|
||||||
|
},
|
||||||
resetUnread: (nodeNum: number) => {
|
resetUnread: (nodeNum: number) => {
|
||||||
set(
|
set(
|
||||||
produce<PrivateDeviceState>((draft) => {
|
produce<PrivateDeviceState>((draft) => {
|
||||||
|
|||||||
+28
-13
@@ -1,11 +1,15 @@
|
|||||||
|
import React from "react";
|
||||||
import "@app/index.css";
|
import "@app/index.css";
|
||||||
import { enableMapSet } from "immer";
|
import { enableMapSet } from "immer";
|
||||||
import "maplibre-gl/dist/maplibre-gl.css";
|
import "maplibre-gl/dist/maplibre-gl.css";
|
||||||
import { StrictMode, Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./i18n/config.ts";
|
import "./i18n/config.ts";
|
||||||
import { createRouter, RouterProvider } from "@tanstack/react-router";
|
import { createRouter, RouterProvider } from "@tanstack/react-router";
|
||||||
import { routeTree } from "@app/routes.tsx";
|
import { router } from "@app/routes.tsx";
|
||||||
|
import { useAppStore } from "@core/stores/appStore.ts";
|
||||||
|
import { useMessageStore } from "@core/stores/messageStore/index.ts";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
declare module "@tanstack/react-router" {
|
declare module "@tanstack/react-router" {
|
||||||
interface Register {
|
interface Register {
|
||||||
@@ -16,16 +20,27 @@ declare module "@tanstack/react-router" {
|
|||||||
const container = document.getElementById("root") as HTMLElement;
|
const container = document.getElementById("root") as HTMLElement;
|
||||||
const root = createRoot(container);
|
const root = createRoot(container);
|
||||||
|
|
||||||
enableMapSet();
|
function IndexPage() {
|
||||||
|
enableMapSet();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const messageStore = useMessageStore();
|
||||||
|
const translation = useTranslation();
|
||||||
|
|
||||||
const router = createRouter({
|
const context = React.useMemo(() => ({
|
||||||
routeTree,
|
stores: {
|
||||||
});
|
app: appStore,
|
||||||
|
message: messageStore,
|
||||||
|
},
|
||||||
|
i18n: translation,
|
||||||
|
}), [appStore, messageStore]);
|
||||||
|
|
||||||
root.render(
|
return (
|
||||||
<StrictMode>
|
<React.StrictMode>
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} context={context} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</StrictMode>,
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
root.render(<IndexPage />);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export const MessagesPage = () => {
|
|||||||
getNodes,
|
getNodes,
|
||||||
getNode,
|
getNode,
|
||||||
hasNodeError,
|
hasNodeError,
|
||||||
unreadCounts,
|
getUnreadCount,
|
||||||
resetUnread,
|
resetUnread,
|
||||||
connection,
|
connection,
|
||||||
} = useDevice();
|
} = useDevice();
|
||||||
@@ -105,7 +105,7 @@ export const MessagesPage = () => {
|
|||||||
})
|
})
|
||||||
.map((node) => ({
|
.map((node) => ({
|
||||||
...node,
|
...node,
|
||||||
unreadCount: unreadCounts.get(node.num) ?? 0,
|
unreadCount: getUnreadCount(node.num) ?? 0,
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const diff = b.unreadCount - a.unreadCount;
|
const diff = b.unreadCount - a.unreadCount;
|
||||||
@@ -211,7 +211,7 @@ export const MessagesPage = () => {
|
|||||||
{filteredChannels?.map((channel) => (
|
{filteredChannels?.map((channel) => (
|
||||||
<SidebarButton
|
<SidebarButton
|
||||||
key={channel.index}
|
key={channel.index}
|
||||||
count={unreadCounts.get(channel.index)}
|
count={getUnreadCount(channel.index)}
|
||||||
label={channel.settings?.name ||
|
label={channel.settings?.name ||
|
||||||
(channel.index === 0
|
(channel.index === 0
|
||||||
? t("page.broadcastLabel", { ns: "channels" })
|
? t("page.broadcastLabel", { ns: "channels" })
|
||||||
@@ -236,10 +236,10 @@ export const MessagesPage = () => {
|
|||||||
</Sidebar>
|
</Sidebar>
|
||||||
), [
|
), [
|
||||||
filteredChannels,
|
filteredChannels,
|
||||||
unreadCounts,
|
|
||||||
numericChatId,
|
numericChatId,
|
||||||
chatType,
|
chatType,
|
||||||
isCollapsed,
|
isCollapsed,
|
||||||
|
getUnreadCount,
|
||||||
navigateToChat,
|
navigateToChat,
|
||||||
resetUnread,
|
resetUnread,
|
||||||
t,
|
t,
|
||||||
@@ -249,7 +249,7 @@ export const MessagesPage = () => {
|
|||||||
() => (
|
() => (
|
||||||
<SidebarSection
|
<SidebarSection
|
||||||
label=""
|
label=""
|
||||||
className="px-0 flex flex-col h-full overflow-y-auto"
|
className="px-0 flex-col h-full overflow-y-auto"
|
||||||
>
|
>
|
||||||
<label className="p-2 block">
|
<label className="p-2 block">
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
+32
-7
@@ -1,17 +1,32 @@
|
|||||||
import { createRoute, redirect } from "@tanstack/react-router";
|
import {
|
||||||
|
createRootRouteWithContext,
|
||||||
|
createRoute,
|
||||||
|
createRouter,
|
||||||
|
redirect,
|
||||||
|
} from "@tanstack/react-router";
|
||||||
import { Dashboard } from "@pages/Dashboard/index.tsx";
|
import { Dashboard } from "@pages/Dashboard/index.tsx";
|
||||||
import MessagesPage from "@pages/Messages.tsx";
|
import MessagesPage from "@pages/Messages.tsx";
|
||||||
import MapPage from "@pages/Map/index.tsx";
|
import MapPage from "@pages/Map/index.tsx";
|
||||||
import ConfigPage from "@pages/Config/index.tsx";
|
import ConfigPage from "@pages/Config/index.tsx";
|
||||||
import ChannelsPage from "@pages/Channels.tsx";
|
import ChannelsPage from "@pages/Channels.tsx";
|
||||||
import NodesPage from "@pages/Nodes/index.tsx";
|
import NodesPage from "@pages/Nodes/index.tsx";
|
||||||
import { createRootRoute } from "@tanstack/react-router";
|
|
||||||
import { App } from "./App.tsx";
|
|
||||||
import { DialogManager } from "@components/Dialog/DialogManager.tsx";
|
import { DialogManager } from "@components/Dialog/DialogManager.tsx";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { useAppStore } from "@core/stores/appStore.ts";
|
||||||
|
import { useMessageStore } from "@core/stores/messageStore/index.ts";
|
||||||
|
import { App } from "./App.tsx";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const rootRoute = createRootRoute({
|
interface AppContext {
|
||||||
component: App,
|
stores: {
|
||||||
|
app: ReturnType<typeof useAppStore>;
|
||||||
|
message: ReturnType<typeof useMessageStore>;
|
||||||
|
};
|
||||||
|
i18n: ReturnType<typeof useTranslation>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rootRoute = createRootRouteWithContext<AppContext>()({
|
||||||
|
component: () => <App />,
|
||||||
});
|
});
|
||||||
|
|
||||||
const indexRoute = createRoute({
|
const indexRoute = createRoute({
|
||||||
@@ -96,7 +111,7 @@ const dialogWithParamsRoute = createRoute({
|
|||||||
component: DialogManager,
|
component: DialogManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const routeTree = rootRoute.addChildren([
|
const routeTree = rootRoute.addChildren([
|
||||||
indexRoute,
|
indexRoute,
|
||||||
messagesRoute,
|
messagesRoute,
|
||||||
messagesWithParamsRoute,
|
messagesWithParamsRoute,
|
||||||
@@ -107,4 +122,14 @@ export const routeTree = rootRoute.addChildren([
|
|||||||
dialogWithParamsRoute,
|
dialogWithParamsRoute,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export { rootRoute };
|
const router = createRouter({
|
||||||
|
routeTree,
|
||||||
|
context: {
|
||||||
|
stores: {
|
||||||
|
app: {} as ReturnType<typeof useAppStore>,
|
||||||
|
message: {} as ReturnType<typeof useMessageStore>,
|
||||||
|
},
|
||||||
|
i18n: {} as ReturnType<typeof import("react-i18next").useTranslation>,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export { router };
|
||||||
|
|||||||
Reference in New Issue
Block a user