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";
|
import type { ChatListProps } from "./types";
|
||||||
|
|
||||||
export default function ChatList(props: ChatListProps) {
|
export default function ChatList(props: ChatListProps) {
|
||||||
const renderedMessages = props.messages.map((message) => (
|
const renderedMessages = props.messages.array.map((message) => (
|
||||||
<div
|
<div
|
||||||
key={
|
key={
|
||||||
message.nick +
|
message.nick +
|
||||||
|
@ -24,7 +24,7 @@ export default function ChatList(props: ChatListProps) {
|
||||||
return (
|
return (
|
||||||
<div className="overflow-y-auto h-full">
|
<div className="overflow-y-auto h-full">
|
||||||
{renderedMessages}
|
{renderedMessages}
|
||||||
<AlwaysScrollToBottom messages={props.messages} />
|
<AlwaysScrollToBottom messages={props.messages.array} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,18 @@ export class Message {
|
||||||
this.sentTimestamp = sentTimestamp;
|
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 {
|
static fromWakuMessage(wakuMsg: IDecodedMessage): Message | undefined {
|
||||||
if (wakuMsg.payload) {
|
if (wakuMsg.payload) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
||||||
UsePeersParams,
|
UsePeersParams,
|
||||||
UsePeersResults,
|
UsePeersResults,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
import { OrderedSet } from "./ordered_array";
|
||||||
|
|
||||||
export const usePersistentNick = (): [
|
export const usePersistentNick = (): [
|
||||||
string,
|
string,
|
||||||
|
@ -40,15 +41,22 @@ export const useMessages = (params: UseMessagesParams): UseMessagesResult => {
|
||||||
setLocalMessages((prev) => [...prev, ...msgs]);
|
setLocalMessages((prev) => [...prev, ...msgs]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const allMessages = React.useMemo((): Message[] => {
|
const allMessages = React.useMemo((): OrderedSet<Message> => {
|
||||||
return [...storedMessages, ...newMessages]
|
const allMessages = new OrderedSet(Message.cmp, Message.isEqual);
|
||||||
|
|
||||||
|
const tomorrow = new Date();
|
||||||
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
|
||||||
|
const _msgs = [...storedMessages, ...newMessages]
|
||||||
.map(Message.fromWakuMessage)
|
.map(Message.fromWakuMessage)
|
||||||
.concat(localMessages)
|
|
||||||
.filter((v): v is Message => !!v)
|
.filter((v): v is Message => !!v)
|
||||||
.filter((v) => v.payloadAsUtf8 !== "")
|
.filter((v) => v.payloadAsUtf8 !== "")
|
||||||
.sort(
|
// Filter out messages that are "sent" tomorrow are they are likely to be flukes
|
||||||
(left, right) => left.timestamp.getTime() - right.timestamp.getTime()
|
.filter((m) => m.timestamp.valueOf() < tomorrow.valueOf());
|
||||||
);
|
allMessages.push(..._msgs);
|
||||||
|
allMessages.push(...localMessages);
|
||||||
|
|
||||||
|
return allMessages;
|
||||||
}, [storedMessages, newMessages, localMessages]);
|
}, [storedMessages, newMessages, localMessages]);
|
||||||
|
|
||||||
return [allMessages, pushMessages];
|
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 { LightNode, StoreQueryOptions, Waku } from "@waku/interfaces";
|
||||||
import type { Decoder } from "@waku/sdk";
|
import type { Decoder } from "@waku/sdk";
|
||||||
import type { Message } from "./Message";
|
import type { Message } from "./Message";
|
||||||
|
import { OrderedSet } from "./ordered_array";
|
||||||
|
|
||||||
export type UsePeersParams = {
|
export type UsePeersParams = {
|
||||||
node: undefined | Waku;
|
node: undefined | Waku;
|
||||||
|
@ -20,10 +21,10 @@ export type UseMessagesParams = {
|
||||||
options: StoreQueryOptions;
|
options: StoreQueryOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UseMessagesResult = [Message[], (v: Message[]) => void];
|
export type UseMessagesResult = [OrderedSet<Message>, (v: Message[]) => void];
|
||||||
|
|
||||||
export interface ChatListProps {
|
export interface ChatListProps {
|
||||||
messages: Message[];
|
messages: OrderedSet<Message>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageInputProps {
|
export interface MessageInputProps {
|
||||||
|
@ -32,7 +33,7 @@ export interface MessageInputProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoomProps {
|
export interface RoomProps {
|
||||||
messages: Message[];
|
messages: OrderedSet<Message>;
|
||||||
commandHandler: (cmd: string) => void;
|
commandHandler: (cmd: string) => void;
|
||||||
nick: string;
|
nick: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue