+
+
+ {messages.map((message, index) => {
+ return (
+
0 && messages[index - 1].from === message.from
+ }
+ />
+ );
+ })}
-
diff --git a/src/components/PageComponents/Messages/Message.tsx b/src/components/PageComponents/Messages/Message.tsx
index 66268219..a6eb8f9a 100644
--- a/src/components/PageComponents/Messages/Message.tsx
+++ b/src/components/PageComponents/Messages/Message.tsx
@@ -1,10 +1,21 @@
-import type { MessageWithState } from "@app/core/stores/deviceStore.ts";
+import {
+ Tooltip,
+ TooltipArrow,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "@app/components/UI/Tooltip";
+import { useAppStore } from "@app/core/stores/appStore";
+import {
+ type MessageWithState,
+ useDeviceStore,
+} from "@app/core/stores/deviceStore.ts";
import { cn } from "@app/core/utils/cn";
import { Avatar } from "@components/UI/Avatar";
import type { Protobuf } from "@meshtastic/js";
-import * as Tooltip from "@radix-ui/react-tooltip";
import { AlertCircle, CheckCircle2, CircleEllipsis } from "lucide-react";
import type { LucideIcon } from "lucide-react";
+import { useMemo } from "react";
const MESSAGE_STATES = {
ACK: "ack",
@@ -17,7 +28,7 @@ type MessageState = MessageWithState["state"];
interface MessageProps {
lastMsgSameUser: boolean;
message: MessageWithState;
- sender?: Protobuf.Mesh.NodeInfo;
+ sender: Protobuf.Mesh.NodeInfo;
}
interface StatusTooltipProps {
@@ -45,22 +56,20 @@ const STATUS_ICON_MAP: Record
= {
const getStatusText = (state: MessageState): string => STATUS_TEXT_MAP[state];
const StatusTooltip = ({ state, children }: StatusTooltipProps) => (
-
-
- {children}
-
-
- {getStatusText(state)}
-
-
-
-
-
+
+
+ {children}
+
+ {getStatusText(state)}
+
+
+
+
);
const StatusIcon = ({ state, className, ...otherProps }: StatusIconProps) => {
@@ -88,7 +97,7 @@ const getMessageTextStyles = (state: MessageState) => {
const isWaiting = state === MESSAGE_STATES.WAITING;
return cn(
- "pl-2 break-words overflow-hidden",
+ "break-words overflow-hidden",
isAcknowledged
? "text-black dark:text-white"
: "text-black dark:text-gray-400",
@@ -96,8 +105,11 @@ const getMessageTextStyles = (state: MessageState) => {
);
};
-const TimeDisplay = ({ date }: { date: Date }) => (
-
+const TimeDisplay = ({
+ date,
+ className,
+}: { date: Date; className?: string }) => (
+
{date.toLocaleDateString()}
@@ -111,44 +123,46 @@ const TimeDisplay = ({ date }: { date: Date }) => (
);
export const Message = ({ lastMsgSameUser, message, sender }: MessageProps) => {
+ const { getDevices } = useDeviceStore();
+
+ const isDeviceUser = useMemo(
+ () =>
+ getDevices()
+ .map((device) => device.nodes.get(device.hardware.myNodeNum)?.num)
+ .includes(message.from),
+ [getDevices, message.from],
+ );
+ const messageUser = sender?.user;
+
const messageTextClass = getMessageTextStyles(message.state);
- const isFailed = message.state === MESSAGE_STATES.ACK;
-
- const baseMessageWrapper = cn(
- "flex items-center gap-2 w-full max-w-full pl-11",
- !lastMsgSameUser && "flex-wrap flex-grow",
- );
-
- const containerClass = cn(
- "w-full px-4 relative",
- lastMsgSameUser ? "mt-1" : "mt-2",
- !lastMsgSameUser && "pt-2",
- );
return (
-
- {!lastMsgSameUser && (
-
-
-
-
- {sender?.user?.longName ?? "UNK"}
-
+
+
+
+ {!lastMsgSameUser ? (
+
+
+
+
+ {messageUser?.longName}
+
+
+
+ ) : null}
+
+
+
- )}
-
);
diff --git a/src/components/PageComponents/Messages/MessageInput.tsx b/src/components/PageComponents/Messages/MessageInput.tsx
index d1cbc5ee..e8b85357 100644
--- a/src/components/PageComponents/Messages/MessageInput.tsx
+++ b/src/components/PageComponents/Messages/MessageInput.tsx
@@ -32,7 +32,7 @@ export const MessageInput = ({
} = useDevice();
const myNodeNum = hardware.myNodeNum;
const [localDraft, setLocalDraft] = useState(messageDraft);
- const [messageBytes, setMessageBytes] = useState(maxBytes);
+ const [messageBytes, setMessageBytes] = useState(0);
const debouncedSetMessageDraft = useMemo(
() => debounce(setMessageDraft, 300),
@@ -69,11 +69,12 @@ export const MessageInput = ({
const handleInputChange = (e: React.ChangeEvent
) => {
const newValue = e.target.value;
- const messageLength = newValue.length;
- if (messageLength <= maxBytes) {
+ const byteLength = new Blob([newValue]).size;
+
+ if (byteLength <= maxBytes) {
setLocalDraft(newValue);
debouncedSetMessageDraft(newValue);
- setMessageBytes(maxBytes - messageLength);
+ setMessageBytes(byteLength);
}
};
@@ -89,6 +90,7 @@ export const MessageInput = ({
sendText(message);
setLocalDraft("");
setMessageDraft("");
+ setMessageBytes(0);
});
}}
>
@@ -103,9 +105,10 @@ export const MessageInput = ({
onChange={handleInputChange}
/>
-
+
{messageBytes}/{maxBytes}
+
diff --git a/src/components/UI/Tooltip.tsx b/src/components/UI/Tooltip.tsx
index bde4b344..2353418a 100644
--- a/src/components/UI/Tooltip.tsx
+++ b/src/components/UI/Tooltip.tsx
@@ -9,6 +9,7 @@ const Tooltip = ({ ...props }) =>
;
Tooltip.displayName = TooltipPrimitive.Tooltip.displayName;
const TooltipTrigger = TooltipPrimitive.Trigger;
+const TooltipArrow = TooltipPrimitive.Arrow;
const TooltipContent = React.forwardRef<
React.ElementRef
,
@@ -26,4 +27,10 @@ const TooltipContent = React.forwardRef<
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
-export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
+export {
+ Tooltip,
+ TooltipTrigger,
+ TooltipContent,
+ TooltipProvider,
+ TooltipArrow,
+};