Skip to content

Commit

Permalink
Switch to using classes to define Chat objects (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
hpeebles authored Jan 13, 2021
1 parent 0c82155 commit 3ba905a
Show file tree
Hide file tree
Showing 12 changed files with 392 additions and 355 deletions.
2 changes: 1 addition & 1 deletion commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dfx canister call user_mgmt get_user_id '("Matt")'
dfx canister call chats create_direct_chat '(principal "lpfg6-5goq7-vn6yz-wegiu-r6goc-sxoor-wj3b2-dpyup-k6i5m-qhv5m-xae", "Hi Matt, how is it going")'
dfx canister call chats send_message '(45_292_552_032_833_753, "hello!!??")'
dfx identity use matt
dfx canister call chats list_chats
dfx canister call chats get_chats '(record { updated_since = null; message_count_for_top_chat = null })'
dfx canister call chats get_messages '(45_292_552_032_833_753, 1)'
dfx canister call chats mark_read '(45_292_552_032_833_753, 2)'
dfx canister call chats send_message '(45_292_552_032_833_753, "whats up?")'
Expand Down
6 changes: 4 additions & 2 deletions src/website/public/actions/chats/createGroupChat.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Dispatch } from "react";

import chatsService from "../../services/chats/service";
import { ChatId } from "../../model/chats";
import { ChatId, NewGroupChat } from "../../model/chats";
import { UnconfirmedMessage } from "../../model/messages";
import { UserId } from "../../model/users";
import { RootState } from "../../reducers";

Expand Down Expand Up @@ -52,7 +53,8 @@ export default function(subject: string, users: UserId[]) {
// Messages may have been added on the UI before the chat was confirmed on the back end. These messages will
// have been added to the 'chat.unconfirmedMessages' array. So we need to read the values out of this array,
// then apply the state change to confirm the chat, then send those messages using the new chatId.
const messagesToSend = getState().chatsState.chats.find(c => c.kind === "newGroup" && c.id === tempId)!.unconfirmedMessages;
const chat = getState().chatsState.chats.find(c => c instanceof NewGroupChat && c.id === tempId)!
const messagesToSend = chat.messages as UnconfirmedMessage[];

dispatch(outcomeEvent);

Expand Down
82 changes: 35 additions & 47 deletions src/website/public/actions/chats/sendMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Dispatch } from "react";

import chatsService from "../../services/chats/service";
import { SendDirectMessageResult } from "../../services/chats/sendDirectMessage";
import { Chat, ChatId } from "../../model/chats";
import { Chat, ChatId, DirectChat, GroupChat, NewDirectChat, NewGroupChat } from "../../model/chats";
import { Option } from "../../model/common";
import { LocalMessage } from "../../model/messages";
import { UserId } from "../../model/users";
import { RootState } from "../../reducers";

Expand All @@ -12,33 +13,26 @@ export const SEND_MESSAGE_SUCCEEDED = "SEND_MESSAGE_SUCCEEDED";
export const SEND_MESSAGE_FAILED = "SEND_MESSAGE_FAILED";

export default function(chat: Chat, message: string) {
switch (chat.kind) {
case "direct":
return sendDirectMessage(chat.them, chat.chatId, message);

case "group":
return sendGroupMessage(chat.chatId, message);

case "newDirect":
return sendDirectMessage(chat.them, null, message);

case "newGroup":
return sendMessageToNewGroup(chat.id, message);
if (chat instanceof DirectChat) {
return sendDirectMessage(chat.them, chat.chatId, message);
} else if (chat instanceof GroupChat) {
return sendGroupMessage(chat.chatId, message);
} else if (chat instanceof NewDirectChat) {
return sendDirectMessage(chat.them, null, message);
} else if (chat instanceof NewGroupChat) {
return sendMessageToNewGroup(chat.id, message);
}
}

function sendDirectMessage(userId: UserId, chatId: Option<ChatId>, message: string) {
return async (dispatch: Dispatch<any>, getState: () => RootState) => {
const id = Symbol("id");

const requestEvent: SendMessageRequestedEvent = {
type: SEND_MESSAGE_REQUESTED,
payload: {
kind: "direct",
userId: userId,
chatId: chatId,
message: message,
unconfirmedMessageId: id
message: message
}
};

Expand All @@ -58,11 +52,13 @@ function sendDirectMessage(userId: UserId, chatId: Option<ChatId>, message: stri
kind: "direct",
userId: userId,
chatId: chatId ?? (response.result as SendDirectMessageResult).chatId,
sender: myUserId,
message: message,
unconfirmedMessageId: id,
confirmedMessageId: response.result.messageId,
confirmedMessageDate: response.result.date
message: {
kind: "local",
id: response.result.messageId,
date: response.result.date,
sender: myUserId,
text: message
}
}
} as SendMessageSucceededEvent;
} else {
Expand All @@ -77,15 +73,12 @@ function sendDirectMessage(userId: UserId, chatId: Option<ChatId>, message: stri

function sendGroupMessage(chatId: ChatId, message: string) {
return async (dispatch: Dispatch<any>, getState: () => RootState) => {
const id = Symbol("id");

const requestEvent: SendMessageRequestedEvent = {
type: SEND_MESSAGE_REQUESTED,
payload: {
kind: "group",
chatId: chatId,
message: message,
unconfirmedMessageId: id
message: message
}
};

Expand All @@ -102,11 +95,13 @@ function sendGroupMessage(chatId: ChatId, message: string) {
payload: {
kind: "group",
chatId: chatId,
sender: myUserId,
message: message,
unconfirmedMessageId: id,
confirmedMessageId: response.result.messageId,
confirmedMessageDate: response.result.date
message: {
kind: "local",
id: response.result.messageId,
date: response.result.date,
sender: myUserId,
text: message
}
}
} as SendMessageSucceededEvent;
} else {
Expand Down Expand Up @@ -153,15 +148,13 @@ export type SendDirectMessageRequest = {
kind: "direct",
userId: UserId,
chatId: Option<ChatId>,
message: string,
unconfirmedMessageId: Symbol
message: string
}

export type SendGroupMessageRequest = {
kind: "group",
chatId: ChatId,
message: string,
unconfirmedMessageId: Symbol
message: string
}

export type SendMessageToNewGroupRequest = {
Expand All @@ -172,20 +165,15 @@ export type SendMessageToNewGroupRequest = {

export type SendMessageSuccess = SendDirectMessageSuccess | SendGroupMessageSuccess;

export type SendDirectMessageSuccess = SendMessageSuccessCommon & {
export type SendDirectMessageSuccess = {
kind: "direct",
userId: UserId
}

export type SendGroupMessageSuccess = SendMessageSuccessCommon & {
kind: "group"
userId: UserId,
chatId: ChatId,
message: LocalMessage
}

type SendMessageSuccessCommon = {
export type SendGroupMessageSuccess = {
kind: "group",
chatId: ChatId,
sender: UserId,
message: string,
unconfirmedMessageId: Symbol,
confirmedMessageId: number,
confirmedMessageDate: Date
message: LocalMessage
}
2 changes: 1 addition & 1 deletion src/website/public/actions/chats/setupNewDirectChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function(username: string) {
}

function chatAlreadyExists(chats: Chat[], userId: UserId) : boolean {
const chat = chats.find(c => c.kind === "direct" && c.them === userId);
const chat = chats.find(c => "them" in c && c.them === userId);

return Boolean(chat);
}
Expand Down
19 changes: 10 additions & 9 deletions src/website/public/components/ChatList.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from "react";
import { Option } from "../model/common";
import { RootState } from "../reducers";
import { useSelector } from "react-redux";

import { GroupChat } from "../model/chats";
import { Option } from "../model/common";
import { UserId } from "../model/users";
import { RootState } from "../reducers";

import ChatListItem from "./ChatListItem";

Expand All @@ -26,18 +28,17 @@ function ChatList() {
userId = c.them;
} else {
name = c.subject;
key = c.kind === "group" ? "G-" + c.chatId.toString() : key = "NG-" + c.subject;
key = c instanceof GroupChat ? "G-" + c.chatId.toString() : key = "NG-" + c.subject;
isGroup = true;
userId = null;
}

let latestMessageText = "";
if (c.unconfirmedMessages.length) {
latestMessageText = c.unconfirmedMessages[c.unconfirmedMessages.length - 1].text;
} else if ("confirmedMessages" in c && c.confirmedMessages.length) {
const latestMessage = c.confirmedMessages[c.confirmedMessages.length - 1];
if ("text" in latestMessage) {
latestMessageText = latestMessage.text;
for (let i = c.messages.length - 1; i >= 0; i--) {
const message = c.messages[i];
if ("text" in message) {
latestMessageText = message.text;
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/website/public/components/MainHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react";
import { useSelector } from "react-redux";

import { RootState } from "../reducers";
import DefaultAvatar from "./defaultAvatar";
import GroupChatIcon from "../assets/icons/groupChatIcon.svg";
Expand Down
48 changes: 21 additions & 27 deletions src/website/public/components/MessagesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import { useSelector } from "react-redux";

import { RootState } from "../reducers";
import { DirectChat } from "../model/chats";
import { Option } from "../model/common";
import { UserId } from "../model/users";

Expand Down Expand Up @@ -31,13 +32,26 @@ function MessagesList() {
let lastSeenDate: Option<Date> = null;
let lastSeenDayString: Option<string> = null;
let prevMessageSender: Option<UserId> = null;
if ("confirmedMessages" in chat) {
for (let i = 0; i < chat.confirmedMessages.length; i++) {
const message = chat.confirmedMessages[i];
if (message.kind === "remote") {
continue;
}
for (let i = 0; i < chat.messages.length; i++) {
const message = chat.messages[i];
if (message.kind === "remote") {
continue;
} else if (message.kind === "unconfirmed") {
const now = new Date();

const mergeWithPrevious: boolean =
lastSeenDate !== null &&
(prevMessageSender === null || prevMessageSender === myUserId) &&
now.getTime() - lastSeenDate.getTime() < MERGE_MESSAGES_SENT_BY_SAME_USER_WITHIN_MILLIS;

const props = {
message: message.text,
mergeWithPrevious
};
children.push(<UnconfirmedMessage key={"u-" + i} {...props} />);
prevMessageSender = myUserId;
lastSeenDate = now;
} else {
const dayString = message.date.toDateString();
if (lastSeenDayString === null || lastSeenDayString !== dayString) {
children.push(<DayChangeMarker key={dayString} date={message.date}/>);
Expand All @@ -57,7 +71,7 @@ function MessagesList() {
mergeWithPrevious
};
children.push(<MessageSentByMe key={message.id} {...props} />);
} else if (chat.kind === "direct") {
} else if (chat instanceof DirectChat) {
const props = {
message: message.text,
date: message.date,
Expand All @@ -81,26 +95,6 @@ function MessagesList() {
}
}

for (let i = 0; i < chat.unconfirmedMessages.length; i++) {
const message = chat.unconfirmedMessages[i];

const now = new Date();

const mergeWithPrevious: boolean =
lastSeenDate !== null &&
(prevMessageSender === null || prevMessageSender === myUserId) &&
now.getTime() - lastSeenDate.getTime() < MERGE_MESSAGES_SENT_BY_SAME_USER_WITHIN_MILLIS;

const props = {
message: message.text,
mergeWithPrevious
};
children.push(<UnconfirmedMessage key={"u-" + i} {...props} />);

lastSeenDate = now;
prevMessageSender = myUserId;
}

return (
<div id="messages" className="detail">
{children}
Expand Down
Loading

0 comments on commit 3ba905a

Please sign in to comment.