import React, { Component } from 'react'; import PropTypes from 'prop-types'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import _ from "underscore"; // Material UI import Box from '@material-ui/core/Box'; import Button from '@material-ui/core/Button'; import Card from '@material-ui/core/Card'; import CircularProgress from '@material-ui/core/CircularProgress'; import Fab from '@material-ui/core/Fab'; import Grid from '@material-ui/core/Grid'; import Popover from '@material-ui/core/Popover'; import TextField from '@material-ui/core/TextField'; import Typography from '@material-ui/core/Typography'; import withStyles from '@material-ui/core/styles/withStyles'; // Material UI Icons import AddCircleIcon from '@material-ui/icons/AddBox'; import CheckMarkIcon from '@material-ui/icons/Check'; import ErrorIcon from '@material-ui/icons/ErrorOutline'; import SendIcon from '@material-ui/icons/Send'; // Redux import { connect } from 'react-redux'; import { getDirectMessages, createNewDirectMessage, getNewDirectMessages, reloadDirectMessageChannels, sendDirectMessage } from '../redux/actions/dataActions'; const styles = { pageContainer: { minHeight: 'calc(100vh - 50px - 60px)' }, sidePadding: { maxWidth: 350 }, dmList: { width: 300, marginLeft: 15 }, dmItemsUpper: { marginBottom: 1, // height: 'calc(100vh - 50px - 142px)', minHeight: 100, maxHeight: 'calc(100vh - 50px - 142px)', overflow: "auto" }, dmItemsLower: { }, dmItemUsernameSelected: { fontSize: 20, color: 'white' }, dmItemUsernameUnselected: { fontSize: 20, color: '#1da1f2' }, dmItemTimeSelected: { color: '#D6D6D6', fontSize: 12, float: 'right', marginRight: 5, marginTop: 5 }, dmItemTimeUnselected: { color: 'black', fontSize: 12, float: 'right', marginRight: 5, marginTop: 5 }, dmRecentMessageSelected: { wordBreak: "break-all", color: '#D6D6D6' }, dmRecentMessageUnselected: { wordBreak: "break-all", color: 'black' }, dmRecentMessageDisabled: { wordBreak: "break-all", color: 'red' }, dmListItemContainer: { height: 100 }, dmListLayoutContainer: { height: "100%" }, dmListRecentMessage: { marginLeft: 10, marginRight: 10 }, dmListTextLayout: { height: 30 }, dmCardUnselected: { fontSize: 20, backgroundColor: '#FFFFFF', width: 300 }, dmCardSelected: { fontSize: 20, backgroundColor: '#1da1f2', width: 300 }, messagesGrid: { // // margin: "auto" // height: "auto", // width: "auto" }, messagesBox: { width: 450 }, messagesContainer: { height: 'calc(100vh - 50px - 110px)', overflow: 'auto', width: 450, marginLeft: 2, marginRight: 17 }, fromMessage: { minWidth: 150, maxWidth: 350, minHeight: 40, marginRight: 2, marginTop: 2, marginBottom: 10, backgroundColor: '#008394', color: '#FFFFFF', float: 'right' }, toMessage: { minWidth: 150, maxWidth: 350, minHeight: 40, marginLeft: 15, marginTop: 2, marginBottom: 10, backgroundColor: '#008394', color: '#FFFFFF', float: 'left' }, messageContent: { // maxWidth: 330, // width: 330, wordBreak: "break-all", textAlign: 'left', marginLeft: 5, marginRight: 5 }, messageTime: { color: '#D6D6D6', textAlign: 'left', marginLeft: 5, fontSize: 12 }, writeMessage: { backgroundColor: '#FFFFFF', boxShadow: '0px 0px 5px 0px grey', width: 450 }, messageTextField: { width: 388 }, messageButton: { backgroundColor: '#1da1f2', marginTop: 8, marginLeft: 2 }, loadingUsernameChecks: { height: 55, width: 55, marginLeft: 5 }, errorIcon: { height: 55, width: 55, marginLeft: 5, color: '#ff3d00' }, checkMarkIcon: { height: 55, width: 55, marginLeft: 5, color: '#1da1f2' }, createButton: { // textAlign: "center", // display: "block", marginLeft: 96, marginRight: 96, position: "relative" } }; export class directMessages extends Component { constructor() { super(); this.state = { hasChannelSelected: false, selectedChannel: null, dmData: null, anchorEl: null, createDMUsername: '', usernameValid: false, // message: '', drafts: {}, errors: null }; } componentDidUpdate() { if (this.state.hasChannelSelected) { document.getElementById('messagesContainer').scrollTop = document.getElementById( 'messagesContainer' ).scrollHeight; } } componentDidMount() { this.props.getDirectMessages(); // this.updatePage(); } // Updates the state whenever redux is updated componentWillReceiveProps(nextProps) { if (nextProps.directMessages && !_.isEqual(nextProps.directMessages, this.state.dmData)) { this.setState({ dmData: nextProps.directMessages}, () => { if (this.state.selectedChannel) { this.state.dmData.forEach((channel) => { if (channel.dmId === this.state.selectedChannel.dmId) { this.setState({ selectedChannel: channel }); } }); } }); } } updatePage = async() => { while (true) { await this.sleep(15000); // console.log("getting new DMs"); this.props.getNewDirectMessages(); } } sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); } // Handles selecting different DM channels handleClickChannel = (event) => { this.setState({ hasChannelSelected: true }); const dmItemsUpper = document.getElementById("dmItemsUpper"); let target = event.target; let dmChannelKey; // Determine which DM channel was clicked by finding the data-key. // A while loop is necessary, because the user can click on any part of the // DM list item. dmItemsUpper is the list container of the dmItems while (target !== dmItemsUpper) { dmChannelKey = target.dataset.key; if (dmChannelKey) { break; } else { target = target.parentNode; } } // Save the entire DM channel in the state so that it is easier to load the messages this.state.dmData.forEach((channel) => { if (channel.dmId === dmChannelKey) { this.setState({ selectedChannel: channel }); } }); }; formatDateToString(dateString) { let newDate = new Date(Date.parse(dateString)); return newDate.toDateString(); } formatDateToTimeDiff(dateString) { return dayjs(dateString).fromNow(); } shortenText = (text, length) => { // Shorten the text let shortened = text.slice(0, length + 1); // Trim whitespace from the end of the text if (shortened[shortened.length - 1] === ' ') { shortened = shortened.trimRight(); } // Add ... to the end shortened = `${shortened}...`; return shortened; } handleOpenAddDMPopover = (event) => { this.setState({ anchorEl: event.currentTarget }); }; handleCloseAddDMPopover = () => { this.setState({ anchorEl: null, createDMUsername: '', usernameValid: false }); }; handleChangeAddDMUsername = (event) => { this.setState({ createDMUsername: event.target.value }); }; handleClickCreate = () => { this.props.createNewDirectMessage(this.state.createDMUsername) .then(() => { return this.props.reloadDirectMessageChannels(); }) .then(() => { this.handleCloseAddDMPopover(); return; }) .catch(() => { return; }) } handleChangeMessage = (event) => { let drafts = this.state.drafts; drafts[this.state.selectedChannel.dmId] = event.target.value; this.setState({ drafts }); } handleClickSend = () => { // console.log(this.state.drafts[this.state.selectedChannel.dmId]); let drafts = this.state.drafts; if (this.state.hasChannelSelected && drafts[this.state.selectedChannel.dmId]) { this.props.sendDirectMessage(this.state.selectedChannel.recipient, drafts[this.state.selectedChannel.dmId]); drafts[this.state.selectedChannel.dmId] = null; this.setState({ drafts }); } } render() { const { classes, user: { credentials: { dmEnabled } } } = this.props; const loadingDirectMessages = this.props.UI.loading2; const creatingDirectMessage = this.props.UI.loading3; const sendingDirectMessage = this.props.UI.loading4; let errors = this.props.UI.errors ? this.props.UI.errors : {}; dayjs.extend(relativeTime); // Used for the add button on the dmList const open = Boolean(this.state.anchorEl); const id = open ? 'simple-popover' : undefined; let dmListMarkup = this.state.dmData ? ( this.state.dmData.map((channel) => ( {channel.recipient} {channel.recentMessageTimestamp ? ( this.formatDateToTimeDiff(channel.recentMessageTimestamp) ) : null} {!channel.hasDirectMessagesEnabled ? "This user has DMs disabled" : !channel.recentMessage ? 'No messages' : channel.recentMessage.length > 65 ? this.shortenText(channel.recentMessage, 65) : channel.recentMessage } )) ) : (

You don't have any DMs yet

) let messagesMarkup = this.state.selectedChannel !== null ? this.state.selectedChannel.messages.length > 0 ? ( this.state.selectedChannel.messages.map((messageObj) => ( {messageObj.message} {this.formatDateToString(messageObj.createdAt)} )) ) : (

No DMs here

) : (

Select a DM channel

); let addDMMarkup = (
Who would you like to start a DM with?
); return ( loadingDirectMessages ? : (dmEnabled !== undefined && dmEnabled !== null && !dmEnabled ? Oops! It looks like you have DMs disabled. You can enable them on the Edit Profile page. : {dmListMarkup} {addDMMarkup} {this.state.hasChannelSelected && ( {messagesMarkup} { sendingDirectMessage && // Won't accept classes style for some reason } )} {!this.state.hasChannelSelected && this.state.dmData && Select a DM on the left} ) ); } } directMessages.propTypes = { classes: PropTypes.object.isRequired, getDirectMessages: PropTypes.func.isRequired, createNewDirectMessage: PropTypes.func.isRequired, getNewDirectMessages: PropTypes.func.isRequired, reloadDirectMessageChannels: PropTypes.func.isRequired, sendDirectMessage: PropTypes.func.isRequired, user: PropTypes.object.isRequired, UI: PropTypes.object.isRequired }; const mapStateToProps = (state) => ({ user: state.user, UI: state.UI, directMessages: state.data.directMessages }); const mapActionsToProps = { getDirectMessages, createNewDirectMessage, getNewDirectMessages, reloadDirectMessageChannels, sendDirectMessage }; export default connect(mapStateToProps, mapActionsToProps)(withStyles(styles)(directMessages));