2.0 Overhaul start

This commit is contained in:
Sacha Weatherstone
2022-09-22 16:35:40 +10:00
parent 4e45990ef5
commit a73eab1ea6
87 changed files with 2880 additions and 3573 deletions
@@ -0,0 +1,85 @@
import type React from "react";
import { ChangeEvent, useState } from "react";
import { Input } from "@app/components/form/Input.js";
import { IconButton } from "@app/components/IconButton.js";
import { Message } from "@components/PageComponents/Messages/Message.js";
import { useDevice } from "@core/providers/useDevice.js";
import type { Channel } from "@core/stores/deviceStore.js";
import { MapPinIcon, PaperAirplaneIcon } from "@heroicons/react/24/outline";
export interface ChannelChatProps {
channel: Channel;
}
export const ChannelChat = ({ channel }: ChannelChatProps): JSX.Element => {
const { nodes, connection, ackMessage } = useDevice();
const [currentMessage, setCurrentMessage] = useState("");
const sendMessage = (): void => {
void connection?.sendText(
currentMessage,
undefined,
true,
channel.config.index,
(id) => {
ackMessage(channel.config.index, id);
return Promise.resolve();
}
);
setCurrentMessage("");
};
return (
<div className="flex flex-col flex-grow">
<div className="flex flex-col flex-grow">
{channel.messages.map((message, index) => (
<Message
key={index}
message={message}
lastMsgSameUser={
index === 0
? false
: channel.messages[index - 1].packet.from ===
message.packet.from
}
sender={
nodes.find((node) => node.data.num === message.packet.from)?.data
}
/>
))}
</div>
<div className="flex gap-2">
<form
className="w-full"
onSubmit={(e): void => {
e.preventDefault();
sendMessage();
}}
>
<div className="flex flex-grow gap-2">
<span className="w-full">
<Input
minLength={2}
label=""
placeholder="Enter Message"
value={currentMessage}
onChange={(e: ChangeEvent<HTMLInputElement>): void => {
setCurrentMessage(e.target.value);
}}
/>
</span>
<IconButton
variant="secondary"
icon={<PaperAirplaneIcon className="h-4 text-slate-500" />}
/>
</div>
</form>
<IconButton
variant="secondary"
icon={<MapPinIcon className="h-4 text-slate-500" />}
/>
</div>
</div>
);
};
@@ -0,0 +1,89 @@
import type React from "react";
import { WaypointMessage } from "@components/PageComponents/Messages/WaypointMessage.js";
import { useDevice } from "@core/providers/useDevice.js";
import type { AllMessageTypes } from "@core/stores/deviceStore.js";
import { Hashicon } from "@emeraldpay/hashicon-react";
import {
CheckCircleIcon,
EllipsisHorizontalCircleIcon,
} from "@heroicons/react/24/outline";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export interface MessageProps {
lastMsgSameUser: boolean;
message: AllMessageTypes;
sender?: Protobuf.NodeInfo;
}
export const Message = ({
lastMsgSameUser,
message,
sender,
}: MessageProps): JSX.Element => {
const { setPeerInfoOpen, setActivePeer } = useDevice();
const openPeer = (): void => {
setActivePeer(message.packet.from);
setPeerInfoOpen(true);
};
return lastMsgSameUser ? (
<div className="flex ml-4">
{message.ack ? (
<CheckCircleIcon className="my-auto text-slate-200 h-4" />
) : (
<EllipsisHorizontalCircleIcon className="my-auto text-slate-200 h-4" />
)}
{"waypointID" in message ? (
<WaypointMessage waypointID={message.waypointID} />
) : (
<span
className={`ml-4 pl-2 border-l-2 border-l-slate-200 ${
message.ack ? "text-black" : "text-slate-500"
}`}
>
{message.text}
</span>
)}
</div>
) : (
<div className="mx-4 gap-2 mt-2">
<div className="flex gap-2">
<div className="cursor-pointer w-6" onClick={openPeer}>
<Hashicon value={(sender?.num ?? 0).toString()} size={32} />
</div>
<span
className="cursor-pointer font-medium text-slate-700"
onClick={openPeer}
>
{sender?.user?.longName ?? "UNK"}
</span>
<span className="text-sm">
{new Date(message.packet.rxTime).toLocaleTimeString(undefined, {
hour: "2-digit",
minute: "2-digit",
})}
</span>
</div>
<div className="flex">
{message.ack ? (
<CheckCircleIcon className="my-auto text-slate-200 h-4" />
) : (
<EllipsisHorizontalCircleIcon className="my-auto text-slate-200 h-4" />
)}
{"waypointID" in message ? (
<WaypointMessage waypointID={message.waypointID} />
) : (
<span
className={`ml-4 pl-2 border-l-2 border-l-slate-200 ${
message.ack ? "text-black" : "text-slate-500"
}`}
>
{message.text}
</span>
)}
</div>
</div>
);
};
@@ -0,0 +1,49 @@
import type React from "react";
import { Input } from "@app/components/form/Input.js";
import { Select } from "@app/components/form/Select.js";
import { Button } from "@components/Button.js";
import { useDevice } from "@core/providers/useDevice.js";
import { renderOptions } from "@core/utils/selectEnumOptions.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
enum LocationType {
MGRS,
LatLng,
DecimalDegrees,
}
export const NewLocationMessage = (): JSX.Element => {
const { connection } = useDevice();
return (
<div className="w-96 m-4">
<form
onSubmit={(e): void => {
e.preventDefault();
}}
>
<Input label="Name" />
<Input label="Description" />
<Select label="Type" value={LocationType.MGRS}>
{renderOptions(LocationType)}
</Select>
<Input label="Coordinates" />
<Button
onClick={() => {
void connection?.sendWaypoint(
Protobuf.Waypoint.create({
latitudeI: Math.floor(3.89103 * 1e7),
longitudeI: Math.floor(105.87005 * 1e7),
name: "TEST",
description: "This is a description",
})
);
}}
>
Send
</Button>
</form>
</div>
);
};
@@ -0,0 +1,33 @@
import type React from "react";
import { useDevice } from "@app/core/providers/useDevice.js";
import { toMGRS } from "@core/utils/toMGRS.js";
import { MapPinIcon } from "@heroicons/react/24/outline";
export interface WaypointMessageProps {
waypointID: number;
}
export const WaypointMessage = ({
waypointID,
}: WaypointMessageProps): JSX.Element => {
const { waypoints } = useDevice();
const waypoint = waypoints.find((wp) => wp.id === waypointID);
return (
<div className="ml-4 pl-2 border-l-slate-200 border-l-2">
<div className="gap-2 flex rounded-md p-2 shadow-md shadow-orange-300">
<MapPinIcon className="m-auto w-6 text-slate-600" />
<div>
<div className="flex gap-2">
<div className="font-bold">{waypoint?.name}</div>
<span className="text-sm font-mono text-slate-500">
{toMGRS(waypoint?.latitudeI, waypoint?.longitudeI)}
</span>
</div>
<span className="text-sm">{waypoint?.description}</span>
</div>
</div>
</div>
);
};