import { Separator } from "@components/UI/Seperator.tsx"; import { Heading } from "@components/UI/Typography/Heading.tsx"; import { Subtle } from "@components/UI/Typography/Subtle.tsx"; import { formatQuantity } from "@core/utils/string.ts"; import { Avatar } from "@components/UI/Avatar.tsx"; import { Mono } from "@components/generic/Mono.tsx"; import { TimeAgo } from "@components/generic/TimeAgo.tsx"; import { Protobuf } from "@meshtastic/core"; import type { Protobuf as ProtobufType } from "@meshtastic/core"; import { Dot, LockIcon, LockOpenIcon, MessageSquareIcon, MountainSnow, Star, } from "lucide-react"; import { Tooltip, TooltipContent, TooltipPortal, TooltipProvider, TooltipTrigger, } from "@radix-ui/react-tooltip"; import { useDevice } from "@core/stores/deviceStore.ts"; import { MessageType, useMessageStore, } from "@core/stores/messageStore/index.ts"; import BatteryStatus from "@components/BatteryStatus.tsx"; import { useTranslation } from "react-i18next"; export interface NodeDetailProps { node: ProtobufType.Mesh.NodeInfo; } export const NodeDetail = ({ node }: NodeDetailProps) => { const { setChatType, setActiveChat } = useMessageStore(); const { t } = useTranslation(); const { setActivePage } = useDevice(); const name = node.user?.longName ?? t("common_unknown"); const shortName = node.user?.shortName ?? t("common_unknown"); const hwModel = node.user?.hwModel ?? 0; const rawHardwareType = Protobuf.Mesh.HardwareModel[hwModel] as | keyof typeof Protobuf.Mesh.HardwareModel | undefined; const hardwareType = rawHardwareType ? rawHardwareType === "UNSET" ? t("common_unset") : rawHardwareType.replaceAll("_", " ") : `${hwModel}`; function handleDirectMessage() { setChatType(MessageType.Direct); setActiveChat(node.num); setActivePage("messages"); } return (
{ // Required to prevent DM tooltip auto-appearing on creation e.stopPropagation(); }} > {node.user?.publicKey && node.user?.publicKey.length > 0 ? ( ) : ( )} {t("node_detail_direct_message_tooltip", { shortName, })}
{name} {hardwareType !== t("common_unset") && {hardwareType} } {!!node.deviceMetrics?.batteryLevel && ( )}
{node.user?.shortName && (
{t("node_detail_short_name_display_format", { name: node.user?.shortName, })}
)} {node.user?.id &&
{node.user?.id}
}
{node.lastHeard > 0 && (
{t("node_detail_status_heard")}{" "}
)}
{node.viaMqtt && (
{t("node_detail_status_mqtt")}
)}
{Number.isNaN(node.hopsAway) ? t("node_detail_hops_unknown") : node.hopsAway}
{node.hopsAway === 1 ? t("node_detail_hops_label_one") : t("node_detail_hops_label_other")}
{node.position?.altitude && (
{formatQuantity(node.position?.altitude, { one: t("node_detail_altitude_unit_one"), other: t("node_detail_altitude_unit_other"), })}
)}
{!!node.deviceMetrics?.channelUtilization && (
{t("node_detail_channel_util_label")}
{node.deviceMetrics?.channelUtilization.toPrecision(3)}%
)} {!!node.deviceMetrics?.airUtilTx && (
{t("node_detail_airtime_util_label")}
{node.deviceMetrics?.airUtilTx.toPrecision(3)}%
)}
{node.snr !== 0 && (
{t("node_detail_snr_label")}
{node.snr} {t("common_unit_dbm")} {Math.min(Math.max((node.snr + 10) * 5, 0), 100)}% {(node.snr + 10) * 5} {t("common_rawUnit")}
)}
); };