Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"@material-ui/core": "^4.12.0",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.60",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
import React from "react";
import {Avatar, ListItem, ListItemIcon, ListItemText} from "@material-ui/core";
import {AvatarGroup} from "@material-ui/lab";
import {Conversation} from "../../../types/conversation";

const buildAvatarText = (fullName: string) => {
const [firstName, lastName] = fullName.split(' ');

return `${firstName.charAt(0)} ${lastName.charAt(0)}`;
};

type Props = {
conversation: Conversation;
selectConversation: Function;
};

export const ConversationListItem: React.FC<Props> = ({conversation, selectConversation}) => {
const handleClick = () => selectConversation(conversation.id);
const {id, participants, lastMessage} = conversation;
const participantsNames = participants.map(p => p.name).join(' ');
const handleClick = () => selectConversation(id);

return (
<ListItem button key={conversation.id} onClick={handleClick}>
<ListItem button key={id} onClick={handleClick}>
<ListItemIcon>
<Avatar alt={conversation.secondUser.name} src="https://material-ui.com/static/images/avatar/1.jpg">
If no avatar provided
</Avatar>
<AvatarGroup max={3}>
{participants.map(participant => {
return (
<Avatar key={participant.id} alt={participant.name} src={participant.avatarUrl}>
{buildAvatarText(participant.name)}
</Avatar>
);
})}
</AvatarGroup>
</ListItemIcon>
<ListItemText primary={conversation.secondUser.name} secondary={conversation.lastMessage.content}/>
<ListItemText primary={participantsNames} secondary={lastMessage.content}/>
</ListItem>
);
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React from "react";
import {ListItemText, makeStyles} from "@material-ui/core";
import {Message as MessageType} from "../../../types/message";
import React, {useMemo} from "react";
import {ListItemText, makeStyles, Typography} from "@material-ui/core";
import {Message} from "../../../types/message";
import {User} from "../../../../models/user";

type Props = {
message: MessageType;
message: Message;
user: User;
isOwn?: boolean;
inMultiUserConversation?: boolean;
}

const useStyles = makeStyles(() => ({
Expand All @@ -13,11 +16,25 @@ const useStyles = makeStyles(() => ({
}
}));

export const MessageListItem: React.FC<Props> = ({message, isOwn = false}) => {
export const MessageListItem: React.FC<Props> = ({message, user, isOwn = false, inMultiUserConversation = false}) => {
const classes = useStyles();
const appliedClasses = isOwn ? classes.root : '';
const date = new Date(message.timestamp);
const secondaryText = useMemo(() => [date.getHours(), date.getMinutes(), date.getSeconds()].join(':'), [message.timestamp]);

return (
<ListItemText className={appliedClasses} primary={message.content} secondary="09:31"/>
<ListItemText
className={appliedClasses}
primary={
<React.Fragment>
{!isOwn && inMultiUserConversation && (
<Typography color="secondary">
{user.username}
</Typography>
)}
{message.content}
</React.Fragment>
}
secondary={secondaryText}/>
);
};
16 changes: 13 additions & 3 deletions src/chat/components/MessagesList/MessagesList.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from "react";
import React, {useMemo} from "react";
import {List, ListItem, makeStyles} from "@material-ui/core";
import {MessageListItem} from './MessageListItem/MessageListItem';
import {Conversation} from "../../types/conversation";
import {User} from "../../../models/user";


type Props = {
Expand All @@ -20,13 +21,22 @@ const useStyles = makeStyles(() => ({

export const MessagesList: React.FC<Props> = ({selectedConversation}) => {
const classes = useStyles();
const {messages = [], userId} = selectedConversation;
const {messages = [], userId, user, participants} = selectedConversation;
const allParticipantsMap: { [userId: string]: User } = useMemo(
() => [user, ...participants].reduce((acc, p) => ({...acc, [p.id]: p}), {}),
[selectedConversation]
);

return (
<List className={classes.root}>
{messages.map(message => (
<ListItem key={message.id}>
<MessageListItem message={message} isOwn={message.userId === userId}/>
<MessageListItem
message={message}
user={allParticipantsMap[message.userId]}
isOwn={message.userId === userId}
inMultiUserConversation={participants.length > 1}
/>
</ListItem>
))}
</List>
Expand Down
2 changes: 1 addition & 1 deletion src/chat/store/actions/chat-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
SendMessageAction
} from "../types/store";
import {MessageType} from "../../types/message";
import {Conversation} from "../../types/conversation";
import {Dispatch} from "redux";
import {conversations} from "../../../testData";

Expand All @@ -33,6 +32,7 @@ export const addTextMessage = (content: string, conversationId: string, userId:
conversationId,
userId,
messageType: MessageType.TEXT,
timestamp: Date.now(),
id: `${Date.now()}`
}
});
Expand Down
6 changes: 5 additions & 1 deletion src/chat/store/reducers/chatReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ export const chatReducer = (state = initialState, action: ChatAction): ChatState
return {
...state,
filteredConversations: state.conversations.filter(
conversation => conversation.secondUser.name.toLowerCase().includes(action.payload.toLowerCase())
conversation => {
const participantsNames = conversation.participants.map(p => p.name.toLowerCase()).join(' ');

return participantsNames.includes(action.payload.toLowerCase())
}
)
};
default:
Expand Down
3 changes: 1 addition & 2 deletions src/chat/types/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ export interface Conversation {
id: string;
userId: string;
user: User;
secondUserId: string;
secondUser: User;
participants: User[];
lastMessage: Message;
messages: Message[];
}
1 change: 1 addition & 0 deletions src/chat/types/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export interface Message {
conversationId: string;
messageType: MessageType;
content: string;
timestamp: number;
}
89 changes: 49 additions & 40 deletions src/testData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,70 @@ export const users: User[] = [
];

export const messages: Message[] = [
{id: '1', conversationId: '1', content: 'Hello John', messageType: MessageType.TEXT, userId: '1'},
{id: '2', conversationId: '1', content: 'Hi', messageType: MessageType.TEXT, userId: '2'},
{id: '3', conversationId: '1', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{id: '4', conversationId: '1', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '2'},
{id: '5', conversationId: '1', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{id: '6', conversationId: '1', content: 'Where are you?', messageType: MessageType.TEXT, userId: '2'},
{id: '7', conversationId: '1', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '1', conversationId: '1', content: 'Hello John', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '2', conversationId: '1', content: 'Hi', messageType: MessageType.TEXT, userId: '2'},
{timestamp: Date.now(), id: '3', conversationId: '1', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '4', conversationId: '1', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '2'},
{timestamp: Date.now(), id: '5', conversationId: '1', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '6', conversationId: '1', content: 'Where are you?', messageType: MessageType.TEXT, userId: '2'},
{timestamp: Date.now(), id: '7', conversationId: '1', content: 'At home', messageType: MessageType.TEXT, userId: '1'},


{id: '8', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{id: '9', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{id: '10', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{id: '11', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{id: '12', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{id: '13', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{id: '14', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{id: '34', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{id: '15', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{id: '16', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{id: '17', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{id: '18', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{id: '19', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{id: '20', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{id: '35', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{id: '21', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{id: '22', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{id: '23', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{id: '24', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{id: '25', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{id: '26', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{id: '27', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{id: '28', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{id: '29', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{id: '30', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{id: '31', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{id: '32', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{id: '33', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '8', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '9', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '10', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '11', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '12', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '13', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '14', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '34', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '15', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '16', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '17', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '18', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '19', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '20', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '35', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '21', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '22', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '23', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '24', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '25', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '26', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '27', conversationId: '2', content: 'Hello Sam', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '28', conversationId: '2', content: 'Hi', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '29', conversationId: '2', content: 'Whats up?', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '30', conversationId: '2', content: 'Everything fine, what about you', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '31', conversationId: '2', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '32', conversationId: '2', content: 'Where are you?', messageType: MessageType.TEXT, userId: '3'},
{timestamp: Date.now(), id: '33', conversationId: '2', content: 'At home', messageType: MessageType.TEXT, userId: '1'},

{timestamp: Date.now(), id: '41', conversationId: '3', content: 'OK', messageType: MessageType.TEXT, userId: '1'},
{timestamp: Date.now(), id: '42', conversationId: '3', content: 'Where are you?', messageType: MessageType.TEXT, userId: '2'},
{timestamp: Date.now(), id: '43', conversationId: '3', content: 'At home', messageType: MessageType.TEXT, userId: '3'},
].reverse();

export const conversations: Conversation[] = [
{
id: '1',
userId: '1',
secondUserId: '2',
lastMessage: messages.filter(({conversationId}) => conversationId === '2').pop() as Message,
lastMessage: messages.filter(({conversationId}) => conversationId === '1').pop() as Message,
user: users[0],
secondUser: users[1],
participants: [users[1]],
messages: messages.filter(({conversationId}) => conversationId === '1')
},{
id: '2',
userId: '1',
secondUserId: '3',
lastMessage: messages.filter(({conversationId}) => conversationId === '2').pop() as Message,
user: users[0],
secondUser: users[2],
participants: [users[2]],
messages: messages.filter(({conversationId}) => conversationId === '2')
},{
id: '3',
userId: '1',
lastMessage: messages.filter(({conversationId}) => conversationId === '3').pop() as Message,
user: users[0],
participants: [...users],
messages: messages.filter(({conversationId}) => conversationId === '3')
},
];
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,16 @@
dependencies:
"@babel/runtime" "^7.4.4"

"@material-ui/lab@^4.0.0-alpha.60":
version "4.0.0-alpha.60"
resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.60.tgz#5ad203aed5a8569b0f1753945a21a05efa2234d2"
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/utils" "^4.11.2"
clsx "^1.0.4"
prop-types "^15.7.2"
react-is "^16.8.0 || ^17.0.0"

"@material-ui/styles@^4.11.4":
version "4.11.4"
resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.11.4.tgz#eb9dfccfcc2d208243d986457dff025497afa00d"
Expand Down