Front-end layout mostly completed

This commit is contained in:
Clayton Wilson 2019-11-19 01:18:20 -05:00
parent 63e917f54c
commit 0f1cfe0393

View File

@ -1,254 +1,589 @@
import React, { Component } from 'react' import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
// Material UI // Material UI
import Grid from '@material-ui/core/Grid' 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 TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import withStyles from "@material-ui/core/styles/withStyles"; import withStyles from '@material-ui/core/styles/withStyles';
import GridList from "@material-ui/core/GridList";
import GridListTile from '@material-ui/core/GridListTileBar';
import Card from "@material-ui/core/Card";
// 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 { connect } from 'react-redux';
import { Box } from '@material-ui/core'; import { getDirectMessages } from '../redux/actions/dataActions';
const styles = { const styles = {
pageContainer: { pageContainer: {
// height: "100%" minHeight: 'calc(100vh - 50px - 60px)'
minHeight: "calc(100vh - 50px - 60px)" },
}, sidePadding: {
sidePadding: { maxWidth: 350
maxWidth: 350, },
// margin: "auto" dmList: {
}, width: 300,
dmList: { marginLeft: 15
width: 300, },
marginLeft: 15, dmItem: {
// borderRight: "solid" marginBottom: 1
}, },
dmItem: { dmItemUsernameSelected: {
marginBottom: 1 fontSize: 20,
// height: 100, color: 'white'
// border: "solid grey 1px", },
// boxShadow: "2px 0px grey" dmItemUsernameUnselected: {
}, fontSize: 20,
dmItemUsernameSelected: { color: '#1da1f2'
// marginLeft: "auto" },
// float: "left" dmItemTimeSelected: {
fontSize: 20, color: '#D6D6D6',
color: "white" fontSize: 12,
}, float: 'right',
dmItemUsernameUnselected: { marginRight: 5,
fontSize: 20, marginTop: 5
color: "#1da1f2" },
}, dmItemTimeUnselected: {
dmRecentMessageSelected: { color: 'black',
color: "#D6D6D6" fontSize: 12,
}, float: 'right',
dmRecentMessageUnselected: { marginRight: 5,
color: "black" marginTop: 5
}, },
dmListItemContainer: { dmRecentMessageSelected: {
height: 100 color: '#D6D6D6'
}, },
dmCardUnselected: { dmRecentMessageUnselected: {
fontSize: 20, color: 'black'
backgroundColor: "#FFFFFF" },
}, dmListItemContainer: {
dmCardSelected: { height: 100
fontSize: 20, },
backgroundColor: "#1da1f2" dmListTextLayout: {
}, height: '100%'
messagesGrid: { },
// // margin: "auto" dmCardUnselected: {
// height: "auto", fontSize: 20,
// width: "auto" backgroundColor: '#FFFFFF'
}, },
messagesContainer: { dmCardSelected: {
height: "100%", fontSize: 20,
// width: "calc(100% - 4)", backgroundColor: '#1da1f2'
width: 450, },
marginLeft: 2, messagesGrid: {
marginRight: 17 // // margin: "auto"
}, // height: "auto",
fromMessage: { // width: "auto"
minWidth: 150, },
maxWidth: 350, messagesBox: {
minHeight: 40, width: 450
marginRight: 2, },
marginTop: 2, messagesContainer: {
marginBottom: 10, height: 'calc(100vh - 50px - 110px)',
backgroundColor: "#008394", overflow: 'auto',
color: "#FFFFFF", width: 450,
float: "right" marginLeft: 2,
}, marginRight: 17
toMessage : { },
minWidth: 150, fromMessage: {
maxWidth: 350, minWidth: 150,
minHeight: 40, maxWidth: 350,
marginLeft: 2, minHeight: 40,
marginTop: 2, marginRight: 2,
marginBottom: 10, marginTop: 2,
backgroundColor: "#008394", marginBottom: 10,
color: "#FFFFFF", backgroundColor: '#008394',
float: "left" color: '#FFFFFF',
}, float: 'right'
messageContent: { },
textAlign: "left", toMessage: {
marginLeft: 5, minWidth: 150,
marginRight: 5 maxWidth: 350,
}, minHeight: 40,
messageTime: { marginLeft: 2,
color: "#D6D6D6", marginTop: 2,
textAlign: "left", marginBottom: 10,
marginLeft: 5, backgroundColor: '#008394',
fontSize: 12 color: '#FFFFFF',
} float: 'left'
} },
messageContent: {
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
},
loadingUsernameCheck: {
height: 85,
width: 85,
marginLeft: 5
},
errorIcon: {
height: 55,
width: 55,
marginLeft: 5,
color: '#ff3d00'
},
checkMarkIcon: {
height: 55,
width: 55,
marginLeft: 5,
color: '#1da1f2'
}
};
export class directMessages extends Component { export class directMessages extends Component {
constructor() { constructor() {
super(); super();
this.state = { this.state = {
selectedMessage: "-1" hasChannelSelected: false,
}; selectedChannel: null,
} dmData: null,
anchorEl: null,
createDMUsername: '',
checkingUsername: false,
usernameValid: false
};
}
componentDidUpdate() {
if (this.state.hasChannelSelected) {
document.getElementById('messagesContainer').scrollTop = document.getElementById(
'messagesContainer'
).scrollHeight;
}
}
componentDidMount() {
// this.props.getDirectMessages();
const resp = {
data: [
{
recipient: 'batman',
messages: [],
recentMessage: null,
recentMessageTimestamp: null,
dmId: 'Lifb0XAONpNLJRhDnOHj'
},
{
recipient: 'CrazyEddy',
messages: [
{
messageId: 'yGqcBbDSM8TsoaQAfAVc',
author: 'CrazyEddy',
message: 'This is message 1',
createdAt: '2019-11-04T17:10:29.180Z'
},
{
messageId: 'c1Bd1REkMBaMaraH10WP',
author: 'keanureeves',
message: 'This is message 2',
createdAt: '2019-11-04T17:33:35.169Z'
},
{
messageId: 'CL5sThnuekks6579MKuF',
author: 'keanureeves',
message: 'Yo, this my first message',
createdAt: '2019-11-08T22:15:08.456Z'
},
{
messageId: 'BgMSSlLLLdC1DMtJl5VJ',
author: 'CrazyEddy',
message: 'That is epic',
createdAt: '2019-11-08T22:20:16.768Z'
},
{
message: 'test test test',
createdAt: '2019-11-08T22:20:58.961Z',
messageId: '9AeUuz0l4wWyQSG6RQ4A',
author: 'keanureeves'
},
{
messageId: 'zhfEpirBK7jl9FnFMtsQ',
author: 'CrazyEddy',
message: 'noice',
createdAt: '2019-11-08T22:21:29.768Z'
},
{
message: 'What time is it?',
createdAt: '2019-11-08T22:23:27.353Z',
messageId: 'XwyKwFU2L5wrTKedzlyF',
author: 'CrazyEddy'
},
{
message: "it's 5:24 right now",
createdAt: '2019-11-08T22:24:21.807Z',
messageId: 'qeasHYkAtTGvjnc3VJAi',
author: 'keanureeves'
},
{
messageId: 'I7kzyLUd9Pp5qzxTPzQv',
author: 'keanureeves',
message: 'a',
createdAt: '2019-11-08T22:31:42.852Z'
},
{
messageId: 'iySWBDFFrbY8FT6E61NL',
author: 'keanureeves',
message: 'b',
createdAt: '2019-11-08T22:31:51.558Z'
},
{
messageId: 'Yis0vXSEuMggj6z5Mq1a',
author: 'keanureeves',
message: 'c',
createdAt: '2019-11-08T22:32:01.293Z'
},
{
messageId: 'DIgjDvFczqO0OWkOrL0t',
author: 'keanureeves',
message: 'd',
createdAt: '2019-11-08T22:32:16.095Z'
},
{
message: 'e',
createdAt: '2019-11-08T22:32:22.134Z',
messageId: '6h1dnFE440MOrjySEQHU',
author: 'keanureeves'
},
{
messageId: 'lmOGGYUWZyB3xG38T7lG',
author: 'keanureeves',
message: 'f',
createdAt: '2019-11-08T22:32:28.424Z'
},
{
message: 'g',
createdAt: '2019-11-08T22:32:37.632Z',
messageId: '64swTj7yiFy7SF6BPbki',
author: 'keanureeves'
}
],
recentMessage: 'g',
recentMessageTimestamp: '2019-11-08T22:32:37.632Z',
dmId: 'avGcIs4PFCJhc4EDqAfe'
}
]
};
// const resp = {"data": null}
this.setState({ dmData: resp.data });
}
showAlert = (event) => { // Handles selecting different DM channels
// alert(event.target.dataset) handleClickChannel = (event) => {
let paper; this.setState({
if (event.target.parentNode.dataset.key === undefined) { hasChannelSelected: true
paper = event.target.parentNode.parentNode.dataset; });
} else { let dmChannelKey;
paper = event.target.parentNode.dataset;
}
this.setState({
selectedMessage: paper.key
})
}
render() { // Determine which DM channel was clicked by finding the key
const { classes } = this.props; // An if statement is needed because the user could click the card or the typography
if (event.target.parentNode.parentNode.parentNode.dataset.key === undefined) {
// They clicked text
dmChannelKey = event.target.parentNode.parentNode.parentNode.parentNode.dataset.key;
} else {
// They clicked the background/card
dmChannelKey = event.target.parentNode.parentNode.parentNode.dataset.key;
}
const selected = true; // 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
});
}
});
};
let dmListMarkup = ( formatDateToString(dateString) {
<Grid container direction="column"> let newDate = new Date(Date.parse(dateString));
<Grid item className={classes.dmItem}> return newDate.toDateString();
{this.state.selectedMessage === "0" ? }
<Card onClick={this.showAlert} key={0} data-key={0} className={classes.dmCardSelected}>
<Box className={classes.dmListItemContainer}>
<Typography className={classes.dmItemUsernameSelected}>keanureeves</Typography>
<Typography className={classes.dmRecentMessageSelected}>This is the most recent message</Typography>
</Box>
</Card>
:
<Card onClick={this.showAlert} key={0} data-key={0} className={classes.dmCardUnselected}>
<Box className={classes.dmListItemContainer}>
<Typography className={classes.dmItemUsernameUnselected}>keanureeves</Typography>
<Typography className={classes.dmRecentMessageUnselected}>This is the most recent message</Typography>
</Box>
</Card>}
</Grid>
<Grid item className={classes.dmItem}>
{this.state.selectedMessage === "1" ?
<Card onClick={this.showAlert} key={1} data-key={1} className={classes.dmCardSelected}>
<Box className={classes.dmListItemContainer}>
<Typography className={classes.dmItemUsernameSelected}>keanureeves</Typography>
<Typography className={classes.dmRecentMessageSelected}>This is the most recent message</Typography>
</Box>
</Card>
:
<Card onClick={this.showAlert} key={1} data-key={1} className={classes.dmCardUnselected}>
<Box className={classes.dmListItemContainer}>
<Typography className={classes.dmItemUsernameUnselected}>keanureeves</Typography>
<Typography className={classes.dmRecentMessageUnselected}>This is the most recent message</Typography>
</Box>
</Card>}
</Grid>
<Grid item className={classes.dmItem}>
{this.state.selectedMessage === "2" ?
<Card onClick={this.showAlert} key={2} data-key={2} className={classes.dmCardSelected}>
<Box className={classes.dmListItemContainer}>
<Typography className={classes.dmItemUsernameSelected}>keanureeves</Typography>
<Typography className={classes.dmRecentMessageSelected}>This is the most recent message</Typography>
</Box>
</Card>
:
<Card onClick={this.showAlert} key={2} data-key={2} className={classes.dmCardUnselected}>
<Box className={classes.dmListItemContainer}>
<Typography className={classes.dmItemUsernameUnselected}>keanureeves</Typography>
<Typography className={classes.dmRecentMessageUnselected}>This is the most recent message</Typography>
</Box>
</Card>}
</Grid>
</Grid>
)
let messagesMarkup = ( formatDateToTimeDiff(dateString) {
<Grid container direction="column"> return dayjs(dateString).fromNow();
<Grid item> }
<Card className={classes.toMessage}>
<Typography className={classes.messageContent}>hello</Typography>
<Typography className={classes.messageTime}>Tues 3:26pm</Typography>
</Card>
</Grid>
<Grid item>
<Card className={classes.fromMessage}>
<Typography>Hey, what's up?</Typography>
<Typography>Tues 3:26pm</Typography>
</Card>
</Grid>
<Grid item>
<Card className={classes.toMessage}>
<Typography>not much. just chillin'</Typography>
<Typography>Tues 3:27pm</Typography>
</Card>
</Grid>
<Grid item>
<Card className={classes.fromMessage}>
<Typography>yayayay yay ayay ya ys ydyyasydasy yd yas dyas ydyasy dyasydy asyd yay ydysyd yaysdy yasy dyas ydysyd yasy dasy dyaysydya sydyasyd yasyd yasyd yasydyasdy yas ys ysdyydayaysyd ysdyasyd ysdyy yasyd asydyasy dyasydy</Typography>
<Typography>Tues 9:35pm</Typography>
</Card>
</Grid>
</Grid>
)
return ( handleOpenAddDMPopover = (event) => {
<Grid container className={classes.pageContainer}> this.setState({
<Grid item className={classes.sidePadding} sm/> anchorEl: event.currentTarget
<Grid item className={classes.dmList}> });
{dmListMarkup} };
</Grid>
<Grid item className={classes.messagesGrid} sm> handleCloseAddDMPopover = () => {
<Box className={classes.messagesContainer}> this.setState({
{selected && anchorEl: null,
<Card className={classes.messagesContainer}> createDMUsername: '',
{messagesMarkup} checkingUsername: false,
</Card>} usernameValid: false
{!selected && });
<Typography>Select a DM on the left</Typography>} };
</Box> handleChangeAddDMUsername = (event) => {
</Grid> this.setState({
<Grid item className={classes.sidePadding} sm/> checkingUsername: true,
</Grid> createDMUsername: event.target.value
) });
} };
render() {
const { classes } = this.props;
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) => (
<Card
onClick={this.handleClickChannel}
key={channel.dmId}
data-key={channel.dmId}
className={
this.state.selectedChannel === channel ? classes.dmCardSelected : classes.dmCardUnselected
}
>
<Box className={classes.dmListItemContainer}>
<Grid container className={classes.dmListTextLayout}>
<Grid item sm />
<Grid item sm>
<Typography
className={
this.state.selectedChannel === channel ? (
classes.dmItemUsernameSelected
) : (
classes.dmItemUsernameUnselected
)
}
>
{channel.recipient}
</Typography>
<Typography
className={
this.state.selectedChannel === channel ? (
classes.dmRecentMessageSelected
) : (
classes.dmRecentMessageUnselected
)
}
>
{channel.recentMessage ? channel.recentMessage : 'No messages'}
</Typography>
</Grid>
<Grid item sm>
<Typography
className={
this.state.selectedChannel === channel ? (
classes.dmItemTimeSelected
) : (
classes.dmItemTimeUnselected
)
}
>
{channel.recentMessageTimestamp ? (
this.formatDateToTimeDiff(channel.recentMessageTimestamp)
) : null}
</Typography>
</Grid>
</Grid>
</Box>
</Card>
))
) : (
<p>You don't have any DMs yet</p>
);
let messagesMarkup =
this.state.selectedChannel !== null ? this.state.selectedChannel.messages.length > 0 ? (
this.state.selectedChannel.messages.map((messageObj) => (
<Grid item key={messageObj.messageId}>
<Card
className={
messageObj.author === this.state.selectedChannel.recipient ? (
classes.toMessage
) : (
classes.fromMessage
)
}
>
<Typography className={classes.messageContent}>{messageObj.message}</Typography>
<Typography className={classes.messageTime}>
{this.formatDateToString(messageObj.createdAt)}
</Typography>
</Card>
</Grid>
))
) : (
<p>No DMs here</p>
) : (
<p>Select a DM channel</p>
);
let addDMMarkup = (
<div>
<AddCircleIcon
style={{
color: '#1da1f2',
height: 82,
width: 82,
marginTop: 9,
cursor: 'pointer'
}}
aria-describedby={id}
onClick={this.handleOpenAddDMPopover}
/>
<Popover
id={id}
open={open}
anchorEl={this.state.anchorEl}
onClose={this.handleCloseAddDMPopover}
anchorOrigin={{
vertical: 'center',
horizontal: 'center'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center'
}}
>
<Box
style={{
height: 200,
width: 400
}}
>
<Grid container>
<Grid item sm />
<Grid item style={{ height: 200, width: 285 }}>
<Grid container direction="column" spacing={2}>
<Grid item>
<Typography style={{ marginTop: 49 }}>
Who would you like to start a DM with?
</Typography>
</Grid>
<Grid item>
<TextField
onChange={this.handleChangeAddDMUsername}
value={this.state.createDMUsername}
label="Username"
variant="outlined"
style={{
margin: 'auto',
textAlign: 'center'
}}
/>
{this.state.checkingUsername && (
<CircularProgress style={{ height: 55, width: 55, marginLeft: 5 }} />
) // Won't accept classes style for some reason
}
{!this.state.usernameValid &&
!this.state.checkingUsername && <ErrorIcon className={classes.errorIcon} />}
{this.state.usernameValid &&
!this.state.checkingUsername && (
<CheckMarkIcon className={classes.checkMarkIcon} />
)}
</Grid>
</Grid>
</Grid>
<Grid item sm />
</Grid>
</Box>
</Popover>
</div>
);
return (
<Grid container className={classes.pageContainer}>
<Grid item className={classes.sidePadding} sm />
<Grid item className={classes.dmList}>
<Grid container direction="column">
<Grid item className={classes.dmItem}>
{dmListMarkup}
<Card key="5555" data-key="5555" className={classes.dmCardUnselected}>
<Box className={classes.dmListItemContainer}>{addDMMarkup}</Box>
</Card>
</Grid>
</Grid>
</Grid>
<Grid item className={classes.messagesGrid} sm>
<Box>
{this.state.hasChannelSelected && (
<Card className={classes.messagesBox}>
<Box className={classes.messagesContainer} id="messagesContainer">
<Grid container direction="column">
{messagesMarkup}
</Grid>
</Box>
<Box className={classes.writeMessage}>
<TextField
className={classes.messageTextField}
variant="outlined"
multiline
rows={2}
margin="dense"
/>
<Fab className={classes.messageButton}>
<SendIcon style={{ color: '#D6D6D6' }} />
</Fab>
</Box>
</Card>
)}
{!this.state.hasChannelSelected &&
this.state.dmData && <Typography>Select a DM on the left</Typography>}
</Box>
</Grid>
<Grid item className={classes.sidePadding} sm />
</Grid>
);
}
} }
directMessages.propTypes = { directMessages.propTypes = {
classes: PropTypes.object.isRequired classes: PropTypes.object.isRequired,
} getDirectMessages: PropTypes.func.isRequired,
user: PropTypes.object.isRequired,
UI: PropTypes.object.isRequired
};
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
user: state.user, user: state.user,
UI: state.UI,
directMessages: state.directMessages
}); });
// export default directMessages const mapActionsToProps = {
export default connect(mapStateToProps)(withStyles(styles)(directMessages)); getDirectMessages
};
export default connect(mapStateToProps, mapActionsToProps)(withStyles(styles)(directMessages));