fix: ensure messages are always ordered
Also: - remove messages that have a timestamp further than tomorrow. - remove dupes
This commit is contained in:
parent
0b494e4069
commit
47b57bbe2c
|
@ -3,7 +3,7 @@ import { Message } from "./Message";
|
|||
import type { ChatListProps } from "./types";
|
||||
|
||||
export default function ChatList(props: ChatListProps) {
|
||||
const renderedMessages = props.messages.map((message) => (
|
||||
const renderedMessages = props.messages.array.map((message) => (
|
||||
<div
|
||||
key={
|
||||
message.nick +
|
||||
|
@ -24,7 +24,7 @@ export default function ChatList(props: ChatListProps) {
|
|||
return (
|
||||
<div className="overflow-y-auto h-full">
|
||||
{renderedMessages}
|
||||
<AlwaysScrollToBottom messages={props.messages} />
|
||||
<AlwaysScrollToBottom messages={props.messages.array} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,18 @@ export class Message {
|
|||
this.sentTimestamp = sentTimestamp;
|
||||
}
|
||||
|
||||
static cmp(left: Message, right: Message): boolean {
|
||||
return left.timestamp.getTime() < right.timestamp.getTime();
|
||||
}
|
||||
|
||||
static isEqual(left: Message, right: Message): boolean {
|
||||
return (
|
||||
left.timestamp.valueOf() === right.timestamp.valueOf() &&
|
||||
left.chatMessage.nick === right.chatMessage.nick &&
|
||||
left.chatMessage.payloadAsUtf8 === right.chatMessage.payloadAsUtf8
|
||||
);
|
||||
}
|
||||
|
||||
static fromWakuMessage(wakuMsg: IDecodedMessage): Message | undefined {
|
||||
if (wakuMsg.payload) {
|
||||
try {
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
UsePeersParams,
|
||||
UsePeersResults,
|
||||
} from "./types";
|
||||
import { OrderedSet } from "./ordered_array";
|
||||
|
||||
export const usePersistentNick = (): [
|
||||
string,
|
||||
|
@ -40,15 +41,22 @@ export const useMessages = (params: UseMessagesParams): UseMessagesResult => {
|
|||
setLocalMessages((prev) => [...prev, ...msgs]);
|
||||
};
|
||||
|
||||
const allMessages = React.useMemo((): Message[] => {
|
||||
return [...storedMessages, ...newMessages]
|
||||
const allMessages = React.useMemo((): OrderedSet<Message> => {
|
||||
const allMessages = new OrderedSet(Message.cmp, Message.isEqual);
|
||||
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
const _msgs = [...storedMessages, ...newMessages]
|
||||
.map(Message.fromWakuMessage)
|
||||
.concat(localMessages)
|
||||
.filter((v): v is Message => !!v)
|
||||
.filter((v) => v.payloadAsUtf8 !== "")
|
||||
.sort(
|
||||
(left, right) => left.timestamp.getTime() - right.timestamp.getTime()
|
||||
);
|
||||
// Filter out messages that are "sent" tomorrow are they are likely to be flukes
|
||||
.filter((m) => m.timestamp.valueOf() < tomorrow.valueOf());
|
||||
allMessages.push(..._msgs);
|
||||
allMessages.push(...localMessages);
|
||||
|
||||
return allMessages;
|
||||
}, [storedMessages, newMessages, localMessages]);
|
||||
|
||||
return [allMessages, pushMessages];
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
export class OrderedSet<T> {
|
||||
array: Array<T>;
|
||||
|
||||
constructor(
|
||||
public orderCmp: (a: T, b: T) => boolean,
|
||||
public isEqual: (a: T, b: T) => boolean
|
||||
) {
|
||||
this.array = [];
|
||||
}
|
||||
|
||||
push(...items: T[]): void {
|
||||
for (const item of items) {
|
||||
this.insertInOrder(this.array, item);
|
||||
}
|
||||
}
|
||||
|
||||
insertInOrder(array: T[], item: T): T[] {
|
||||
let i = 0;
|
||||
while (i < array.length) {
|
||||
if (this.isEqual(item, array[i])) {
|
||||
continue;
|
||||
}
|
||||
if (this.orderCmp(item, array[i])) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
array.splice(i, 0, item);
|
||||
return array;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import type { PeerId } from "@libp2p/interface-peer-id";
|
|||
import type { LightNode, StoreQueryOptions, Waku } from "@waku/interfaces";
|
||||
import type { Decoder } from "@waku/sdk";
|
||||
import type { Message } from "./Message";
|
||||
import { OrderedSet } from "./ordered_array";
|
||||
|
||||
export type UsePeersParams = {
|
||||
node: undefined | Waku;
|
||||
|
@ -20,10 +21,10 @@ export type UseMessagesParams = {
|
|||
options: StoreQueryOptions;
|
||||
};
|
||||
|
||||
export type UseMessagesResult = [Message[], (v: Message[]) => void];
|
||||
export type UseMessagesResult = [OrderedSet<Message>, (v: Message[]) => void];
|
||||
|
||||
export interface ChatListProps {
|
||||
messages: Message[];
|
||||
messages: OrderedSet<Message>;
|
||||
}
|
||||
|
||||
export interface MessageInputProps {
|
||||
|
@ -32,7 +33,7 @@ export interface MessageInputProps {
|
|||
}
|
||||
|
||||
export interface RoomProps {
|
||||
messages: Message[];
|
||||
messages: OrderedSet<Message>;
|
||||
commandHandler: (cmd: string) => void;
|
||||
nick: string;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue