Skip to content

Commit

Permalink
Merge pull request #85 from hatchways/in_translation_59
Browse files Browse the repository at this point in the history
IN translation 59
  • Loading branch information
cch5ng authored Jun 10, 2020
2 parents 50888e7 + 2318598 commit 6c30d46
Show file tree
Hide file tree
Showing 15 changed files with 173 additions and 66 deletions.
24 changes: 19 additions & 5 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 59 additions & 6 deletions client/src/components/Chat/Chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,28 @@ import MessageInput from './MessageInput';
import {useAuth} from '../../context/auth-context';
import {useSocket} from '../../context/socket-context';

const MAX_MESSAGE_LENGTHS = {
'english': 200,
'french': 200,
'spanish': 200,
'mandarin': 66,
'hindi': 66
};

const Chat = props => {
const {messages, selectedContacts} = props;
let { conversationId } = useParams();
const {user} = useAuth();
const {language} = user;
const userEmail = user.email;
const {socket, sendChatMessage, getMessage, setChatRoom} = useSocket();

const [curMessage, setCurMessage] = useState('');
const [postedMessages, setPostedMessages] = useState([]);
const [chatUserEmails, setChatUserEmails] = useState([]);
const [messageInputError, setMessageInputError] = useState('');
const [friendLanguage, setFriendLanguage] = useState('');
const [languageError, setLanguageError] = useState('');

//socket client listener for server broadcasts
if (socket && conversationId) {
Expand All @@ -28,23 +41,37 @@ const Chat = props => {
}

const messageInputOnChangeHandler = e => {
setCurMessage(e.target.value)
let {value} = e.target;
let maxLength = MAX_MESSAGE_LENGTHS[language];
if (value.length <= maxLength) {
setCurMessage(e.target.value);
} else {
setCurMessage(e.target.value.slice(0, maxLength - 1))
let error = `The max message length is ${maxLength}.`;
setMessageInputError(error);
}
};

const messageInputSubmitHandler = e => {
if (e.key === 'Enter') {
e.preventDefault();
let message = {
author_id: user.id,
author_email: user.email,
original_message: curMessage,
language: user.language,
language,
created_on: Date.now(),
translations: {}
};
e.preventDefault();
sendChatMessage({from_email: user.email, message, conversationId});
sendChatMessage({from_email: user.email,
message,
conversationId,
userEmails: chatUserEmails,
friendLanguage
});
setPostedMessages(postedMessages.concat([message]));
setCurMessage('');
setMessageInputError('');
}
}

Expand All @@ -55,18 +82,43 @@ const Chat = props => {

useEffect(() => {
setPostedMessages([]);
let jwtToken = localStorage.getItem('authToken');
if (conversationId) {
fetch(`http://localhost:3001/conversations/${conversationId}`)
fetch(`http://localhost:3001/conversations/${conversationId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `${jwtToken}`
}
})
.then(resp => resp.json())
.then(json => {
if (json.messages && json.messages.length) {
setPostedMessages(json.messages);
}
if (json.user_emails && json.user_emails.length) {
setChatUserEmails(json.user_emails);
//make api call to get friend language by email
let friendEmail = json.user_emails[0] === userEmail ? json.user_emails[1]: json.user_emails[0];
fetch(`http://localhost:3001/user/${friendEmail}/language`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `${jwtToken}`
}
})
.then(resp => resp.json())
.then(json => {
if (json.language) {
setFriendLanguage(json.language);
} else {
setLanguageError(`Could not get the friend's language. Chat translations may not work.`)
}
})
.catch(err => console.error('Could not get language.', err))
}
})
.catch(err => console.error('Could not find old messages', err))
.catch(err => console.error('Could not find existing conversation.', err))
}
}, [conversationId]);

Expand Down Expand Up @@ -99,6 +151,7 @@ const Chat = props => {
messageInputOnChangeHandler={messageInputOnChangeHandler}
messageInputSubmitHandler={messageInputSubmitHandler}
curMessage={curMessage}
error={messageInputError}
/>
</div>
);
Expand Down
1 change: 0 additions & 1 deletion client/src/components/Chat/ChatHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ const ChatHeader = props => {
<div className="chatHeaderLeft">
<Avatar className={classes.orange}>{initial}</Avatar>
<Typography variant='h5' className={classes.chatHeaderName}>{email}</Typography>
<Typography variant='p2'>online status todo</Typography>
</div>
<div className="chatHeaderSpacer" />
<div className="chatHeaderRight">
Expand Down
15 changes: 10 additions & 5 deletions client/src/components/Chat/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import classNames from 'classnames';

import './style.css';
import {getPrettyTime} from '../../util/helpers';
import {useAuth} from '../../context/auth-context';

const Message = props => {
const {message, userEmail, messageTime} = props;
const {message, userEmail, messageTime, ref} = props;
const {user} = useAuth();
const {language} = user;
var msgClass = classNames({
messageBubble: true,
'messageBubbleFriend': !props.isAuthorUser,
Expand All @@ -23,21 +26,23 @@ const Message = props => {
}

if (!props.isAuthorUser) {
const translation = message.translations ? message.translations[language] : '';

return (
<div style={{display: 'flex', flexFlow: 'row nowrap', justifyContent: 'flex-start', alignItems: 'flex-start', margin: '18px 0'}}>
<div ref={ref} style={{display: 'flex', flexFlow: 'row nowrap', justifyContent: 'flex-start', alignItems: 'flex-start', margin: '18px 0'}}>
<Avatar>{getUserInitial()}</Avatar>
<div style={{display: 'flex', flexFlow: 'column nowrap', marginLeft: '8px'}}>
<Typography variant='body1' className="messageAuthorTime">{userEmail} {getPrettyTime(messageTime)}</Typography>
<div className={msgClass}>{props.message}</div>
<div className={msgClass}>{translation}</div>
</div>
</div>
)
} else {
return (
<div style={{display: 'flex', flexFlow: 'row nowrap', justifyContent: 'flex-end', alignItems: 'flex-end', margin: '18px 0'}}>
<div ref={ref} style={{display: 'flex', flexFlow: 'row nowrap', justifyContent: 'flex-end', alignItems: 'flex-end', margin: '18px 0'}}>
<div style={{display: 'flex', flexFlow: 'column nowrap', marginLeft: '8px', alignItems: 'flex-end'}}>
<Typography variant='body1' className="messageAuthorTime">{getPrettyTime(messageTime)}</Typography>
<div className={msgClass}>{props.message}</div>
<div className={msgClass}>{props.message.original_message}</div>
</div>
</div>
)
Expand Down
23 changes: 19 additions & 4 deletions client/src/components/Chat/MessageDisplay.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import React from 'react';
import React, {useEffect, useState} from 'react';
import Grid from '@material-ui/core/Grid';

import Message from './Message';
import {useAuth} from '../../context/auth-context';

const MessageDisplay = props => {
const {user} = useAuth();
const {messages} = props;
const [messagesEnd, setMessagesEnd] = useState(null);

const messages = props.messages.map((msg, idx) => (
const scrollToBottom = () => {
messagesEnd.scrollIntoView({ behavior: "smooth" });
}

useEffect(() => {
if (messagesEnd) {
scrollToBottom();
}
}, [messagesEnd, messages]);

const messageList = messages.map((msg, idx) => (
<Message
message={msg.original_message}
message={msg}
messageTime={msg.created_on}
userEmail={msg.author_email}
key={`${idx}-${msg}`}
Expand All @@ -21,7 +33,10 @@ const MessageDisplay = props => {
<div
style={{backgroundColor: '#fff', padding: '18px',
overflow: 'scroll', flexGrow: '1'}}>
{messages}
{messageList}
<div style={{ float:"left", clear: "both" }}
ref={(el) => { setMessagesEnd(el) }}>
</div>
</div>
)};

Expand Down
4 changes: 3 additions & 1 deletion client/src/components/Chat/MessageInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ const useStyles = makeStyles((theme) => ({

const MessageInput = (props) => {
const classes = useStyles();
const {messageInputOnChangeHandler, messageInputSubmitHandler, curMessage} = props;
const {messageInputOnChangeHandler, messageInputSubmitHandler, curMessage, error} = props;

return (
<form className={classes.root} style={{backgroundColor: '#fff', padding: '18px',
flexBasis: '50px', flexShrink: '0' }}>
<TextField name='msg'
error={error.length}
value={curMessage}
onChange={messageInputOnChangeHandler}
onKeyPress={messageInputSubmitHandler}
Expand All @@ -31,6 +32,7 @@ const MessageInput = (props) => {
margin="normal"
variant="filled"
className={classes.textField}
helperText={error}
/>
</form>
);
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Chat/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
/* Message style */

.messageBubble {
height: 28px;
padding: 8px 16px 0 16px;
min-height: 28px;
padding: 8px 16px 4px 16px;
}

.messageBubbleFriend {
Expand Down
3 changes: 1 addition & 2 deletions client/src/components/Invitations/InvitationDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,7 @@ export default function InvitationDialog(props) {
}
})
.catch(err => {
console.error(err)
setSubmitError(err);
console.error(err);
})
} else {
setSendRequestErrorMessage('The request could not be sent because your login seems invalid. Please log out and try again.')
Expand Down
5 changes: 2 additions & 3 deletions client/src/context/socket-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ function SocketProvider({children}) {
socket.on('connect', function() {
// Connected, let's sign-up for to receive messages for this room
socket.emit('room', conversationId);
console.log('gets here')
});
}

const sendChatMessage = ({from_email, message, conversationId}) => {
socket.send({message, conversationId});
const sendChatMessage = ({from_email, message, conversationId, userEmails, friendLanguage}) => {
socket.send({message, conversationId, userEmails, friendLanguage});
}

const socketShare = {socket, sendChatMessage, setChatRoom};
Expand Down
30 changes: 17 additions & 13 deletions server/bin/www
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ require("dotenv").config();
var app = require("../app");
var http = require("http");
const {saveMessageToConversation} = require('../util/socket_db');
const {language_codes} = require('../util/languages');
const {getTranslation} = require('../util/translate_helpers');

/**
* Get port from environment and store in Express.
Expand Down Expand Up @@ -37,22 +39,24 @@ const nsp = io.of('/chat');
nsp.on('connection', function(socket){
console.log('someone connected on /chat');

// socket.on('room', function(room) {
// socket.join(room);
// console.log('socket room', socket.rooms)
// });

socket.on('message', (data) => {
console.log('data', data)
let {conversationId, message} = data;
socket.broadcast.emit(conversationId, data);
//socket.broadcast.emit('server broadcast', data);
saveMessageToConversation({message, conversationId})
let {conversationId, message, userEmails, friendLanguage} = data;
let friendLanguageCode = language_codes[friendLanguage];

getTranslation(message.original_message, friendLanguageCode)
.then(translations => {
message.translations = {...message.translations, [friendLanguage]: translations[0]};
socket.broadcast.emit(conversationId, data);
//save translated message
saveMessageToConversation({message, conversationId});
})
.catch(err => {
//save untranslated message
saveMessageToConversation({message, conversationId});
console.error('Translation API error', err);
})
});

//socket.emit('message', 'test message server to room');//to(`${conversationId}`)
// socket.to(conversationId).emit('message', JSON.stringify(data));

socket.on("disconnect", () => {
console.log("user disconnected");
});
Expand Down
17 changes: 17 additions & 0 deletions server/routes/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,23 @@ router.get("/:fromEmail/referralId",
}
);

router.get("/:fromEmail/language",
passport.authenticate('jwt', { session: false }),
function(req, res, next) {
const {fromEmail} = req.params
User.findOne({email: fromEmail}, function(err, user) {
if (err) return console.error(err);
if (!user) {
res.status(500).json({type: 'error', message: 'A user with that email could not be found.'})
}
if (user) {
res.json({type: 'success', language: user.language})
}
});
}
);


router.post('/register/referral',
//passport.authenticate('jwt', { session: false }),
(req, res) => {
Expand Down
Loading

0 comments on commit 6c30d46

Please sign in to comment.