summaryrefslogtreecommitdiffstats
path: root/front/odiparpack/app/components/Email
diff options
context:
space:
mode:
authorDayana31 <[email protected]>2022-04-21 17:27:08 -0500
committerDayana31 <[email protected]>2022-04-21 17:27:08 -0500
commit67c50667678dd0ce4709b29a854f6a47093a1ac5 (patch)
treeb6f9f39092ad54bf6b815984d32b37d7c7ca67ab /front/odiparpack/app/components/Email
parent91140b24f0d49a9f89a080ee063e9eb023a4b73a (diff)
parente13e630cd6e4fc0b1ff92098a28a770794c7bb9a (diff)
downloadDP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.tar.gz
DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.tar.bz2
DP1_project-67c50667678dd0ce4709b29a854f6a47093a1ac5.zip
Merge branch 'gabshr' into dayana
Diffstat (limited to 'front/odiparpack/app/components/Email')
-rw-r--r--front/odiparpack/app/components/Email/ComposeEmail.js65
-rw-r--r--front/odiparpack/app/components/Email/ComposeEmailForm.js262
-rw-r--r--front/odiparpack/app/components/Email/EmailHeader.js49
-rw-r--r--front/odiparpack/app/components/Email/EmailList.js314
-rw-r--r--front/odiparpack/app/components/Email/EmailSidebar.js162
-rw-r--r--front/odiparpack/app/components/Email/email-jss.js238
6 files changed, 1090 insertions, 0 deletions
diff --git a/front/odiparpack/app/components/Email/ComposeEmail.js b/front/odiparpack/app/components/Email/ComposeEmail.js
new file mode 100644
index 0000000..8d06ebd
--- /dev/null
+++ b/front/odiparpack/app/components/Email/ComposeEmail.js
@@ -0,0 +1,65 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withStyles } from '@material-ui/core/styles';
+import Add from '@material-ui/icons/Add';
+import { Fab, Tooltip } from '@material-ui/core';
+import ComposeEmailForm from './ComposeEmailForm';
+import FloatingPanel from '../Panel/FloatingPanel';
+import styles from './email-jss';
+
+
+class ComposeEmail extends React.Component {
+ render() {
+ const {
+ classes,
+ open,
+ closeForm,
+ sendEmail,
+ to,
+ subject,
+ validMail,
+ inputChange,
+ compose
+ } = this.props;
+ const branch = '';
+ return (
+ <div>
+ <Tooltip title="Compose Email">
+ <Fab color="secondary" onClick={() => compose()} className={classes.addBtn}>
+ <Add />
+ </Fab>
+ </Tooltip>
+ <FloatingPanel
+ openForm={open}
+ branch={branch}
+ closeForm={closeForm}
+ title="Compose Email"
+ extraSize
+ >
+ <ComposeEmailForm
+ to={to}
+ subject={subject}
+ validMail={validMail}
+ sendEmail={sendEmail}
+ closeForm={closeForm}
+ inputChange={inputChange}
+ />
+ </FloatingPanel>
+ </div>
+ );
+ }
+}
+
+ComposeEmail.propTypes = {
+ classes: PropTypes.object.isRequired,
+ open: PropTypes.bool.isRequired,
+ to: PropTypes.string.isRequired,
+ subject: PropTypes.string.isRequired,
+ validMail: PropTypes.string.isRequired,
+ compose: PropTypes.func.isRequired,
+ closeForm: PropTypes.func.isRequired,
+ sendEmail: PropTypes.func.isRequired,
+ inputChange: PropTypes.func.isRequired,
+};
+
+export default withStyles(styles)(ComposeEmail);
diff --git a/front/odiparpack/app/components/Email/ComposeEmailForm.js b/front/odiparpack/app/components/Email/ComposeEmailForm.js
new file mode 100644
index 0000000..3620d4d
--- /dev/null
+++ b/front/odiparpack/app/components/Email/ComposeEmailForm.js
@@ -0,0 +1,262 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Editor } from 'react-draft-wysiwyg';
+import { convertFromRaw, EditorState, convertToRaw } from 'draft-js';
+import draftToHtml from 'draftjs-to-html';
+import Dropzone from 'react-dropzone';
+import { withStyles } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+import Attachment from '@material-ui/icons/Attachment';
+import FileIcon from '@material-ui/icons/Description';
+import ActionDelete from '@material-ui/icons/Delete';
+import Send from '@material-ui/icons/Send';
+import EditorStyle from 'ba-styles/TextEditor.scss';
+import css from 'ba-styles/Form.scss';
+import 'ba-styles/vendors/react-draft-wysiwyg/react-draft-wysiwyg.css';
+import { Button, Grid, Typography, Snackbar, IconButton } from '@material-ui/core';
+import isImage from '../Forms/helpers/helpers.js';
+import styles from './email-jss';
+
+
+const content = {
+ blocks: [{
+ key: '637gr',
+ text: 'Lorem ipsum dolor sit amet 😀',
+ type: 'unstyled',
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {}
+ }],
+ entityMap: {}
+};
+
+class ComposeEmailForm extends React.Component {
+ constructor(props) {
+ super(props);
+ const contentBlock = convertFromRaw(content);
+ if (contentBlock) {
+ const editorState = EditorState.createWithContent(contentBlock);
+ this.state = {
+ openSnackBar: false,
+ errorMessage: '',
+ files: [],
+ editorState,
+ emailContent: draftToHtml(convertToRaw(editorState.getCurrentContent())),
+ };
+ }
+ this.onDrop = this.onDrop.bind(this);
+ }
+
+ onDrop(filesVal) {
+ const { files } = this.state;
+ let oldFiles = files;
+ const filesLimit = 3;
+ oldFiles = oldFiles.concat(filesVal);
+ if (oldFiles.length > filesLimit) {
+ console.log('Cannot upload more than ' + filesLimit + ' items.');
+ } else {
+ this.setState({ files: oldFiles });
+ }
+ }
+
+ onEditorStateChange = editorState => {
+ this.setState({
+ editorState,
+ emailContent: draftToHtml(convertToRaw(editorState.getCurrentContent()))
+ });
+ };
+
+ onDropRejected() {
+ this.setState({
+ openSnackBar: true,
+ errorMessage: 'File too big, max size is 3MB',
+ });
+ }
+
+ handleRequestCloseSnackBar = () => {
+ this.setState({
+ openSnackBar: false,
+ });
+ };
+
+ handleRemove(file, fileIndex) {
+ const thisFiles = this.state.files;
+ // This is to prevent memory leaks.
+ window.URL.revokeObjectURL(file.preview);
+
+ thisFiles.splice(fileIndex, 1);
+ this.setState({ files: thisFiles });
+ }
+
+ handleSend = (to, subject, emailContent, files) => {
+ this.props.sendEmail(to, subject, emailContent, files);
+ this.setState({ emailContent: '', files: [] });
+ };
+
+ render() {
+ const {
+ classes,
+ closeForm,
+ to,
+ subject,
+ validMail,
+ inputChange
+ } = this.props;
+ const {
+ editorState,
+ emailContent,
+ files,
+ openSnackBar,
+ errorMessage,
+ } = this.state;
+ let dropzoneRef;
+ const deleteBtn = (file, index) => (
+ <div className="middle">
+ <IconButton onClick={() => this.handleRemove(file, index)}>
+ <ActionDelete className="removeBtn" />
+ </IconButton>
+ </div>
+ );
+ const previews = filesArray => filesArray.map((file, index) => {
+ if (isImage(file)) {
+ const base64Img = URL.createObjectURL(file);
+ return (
+ <div key={index.toString()} className={classes.item}>
+ <div className="imageContainer col fileIconImg">
+ <figure className="imgWrap"><img className="smallPreviewImg" src={base64Img} alt="preview" /></figure>
+ {deleteBtn(file, index)}
+ </div>
+ <Typography noWrap variant="caption">{file.name}</Typography>
+ </div>
+ );
+ }
+ return (
+ <div key={index.toString()} className={classes.item}>
+ <div className="imageContainer col fileIconImg">
+ <div className="fileWrap">
+ <FileIcon className="smallPreviewImg" alt="preview" />
+ {deleteBtn(file, index)}
+ </div>
+ </div>
+ <Typography noWrap variant="caption">{file.name}</Typography>
+ </div>
+ );
+ });
+ const fileSizeLimit = 3000000;
+ return (
+ <div>
+ <form>
+ <section className={css.bodyForm}>
+ <div>
+ <TextField
+ error={validMail === 'Invalid email'}
+ id="to"
+ label="To"
+ helperText={validMail}
+ className={classes.field}
+ type="email"
+ placeholder="To"
+ value={to}
+ onChange={(event) => inputChange(event, 'to')}
+ margin="normal"
+ />
+ </div>
+ <div>
+ <TextField
+ id="subject"
+ label="Subject"
+ className={classes.field}
+ placeholder="Subject"
+ value={subject}
+ onChange={(event) => inputChange(event, 'subject')}
+ margin="normal"
+ />
+ </div>
+ <Grid container alignItems="center">
+ <Dropzone
+ className={classes.hiddenDropzone}
+ acceptClassName="stripes"
+ onDrop={this.onDrop}
+ maxSize={fileSizeLimit}
+ ref={(node) => { dropzoneRef = node; }}
+ >
+ {({ getRootProps, getInputProps }) => (
+ <div {...getRootProps()}>
+ <input {...getInputProps()} />
+ </div>
+ )}
+ </Dropzone>
+ <Button
+ className={classes.buttonUpload}
+ color="secondary"
+ component="button"
+ onClick={() => {
+ dropzoneRef.open();
+ }}
+ >
+ <Attachment />
+ Attach Files
+ </Button>
+ &nbsp;
+ <Typography variant="caption">(Max 3MB)</Typography>
+ </Grid>
+ <div className={classes.preview}>
+ {previews(files)}
+ </div>
+ <div>
+ <Editor
+ editorState={editorState}
+ editorClassName={EditorStyle.TextEditor}
+ toolbarClassName={EditorStyle.ToolbarEditor}
+ onEditorStateChange={this.onEditorStateChange}
+ toolbar={{
+ options: ['inline', 'fontSize', 'fontFamily', 'colorPicker', 'image', 'emoji', 'list', 'textAlign', 'link'],
+ inline: { inDropdown: true },
+ color: true,
+ list: { inDropdown: true },
+ textAlign: { inDropdown: true },
+ link: { inDropdown: true },
+ }}
+ />
+ </div>
+ </section>
+ <div className={css.buttonArea}>
+ <Button type="button" onClick={() => closeForm()}>
+ Discard
+ </Button>
+ <Button
+ variant="contained"
+ color="secondary"
+ type="button"
+ disabled={!to || !subject}
+ onClick={() => this.handleSend(to, subject, emailContent, files)}
+ >
+ Send
+ {' '}
+ <Send className={classes.sendIcon} />
+ </Button>
+ </div>
+ </form>
+ <Snackbar
+ open={openSnackBar}
+ message={errorMessage}
+ autoHideDuration={4000}
+ onClose={this.handleRequestCloseSnackBar}
+ />
+ </div>
+ );
+ }
+}
+
+ComposeEmailForm.propTypes = {
+ classes: PropTypes.object.isRequired,
+ to: PropTypes.string.isRequired,
+ subject: PropTypes.string.isRequired,
+ validMail: PropTypes.string.isRequired,
+ sendEmail: PropTypes.func.isRequired,
+ closeForm: PropTypes.func.isRequired,
+ inputChange: PropTypes.func.isRequired,
+};
+
+export default withStyles(styles)(ComposeEmailForm);
diff --git a/front/odiparpack/app/components/Email/EmailHeader.js b/front/odiparpack/app/components/Email/EmailHeader.js
new file mode 100644
index 0000000..eceb757
--- /dev/null
+++ b/front/odiparpack/app/components/Email/EmailHeader.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withStyles } from '@material-ui/core/styles';
+import SearchIcon from '@material-ui/icons/Search';
+import MenuIcon from '@material-ui/icons/Menu';
+import { AppBar, Hidden, Toolbar, Typography, IconButton } from '@material-ui/core';
+import styles from './email-jss';
+
+
+class EmailHeader extends React.Component {
+ render() {
+ const { classes, search, handleDrawerToggle } = this.props;
+ return (
+ <AppBar position="absolute" className={classes.appBar}>
+ <Toolbar>
+ <Hidden smDown>
+ <Typography variant="h6" color="inherit" className={classes.title} noWrap>
+ Email
+ </Typography>
+ </Hidden>
+ <IconButton
+ color="inherit"
+ aria-label="open drawer"
+ onClick={() => handleDrawerToggle()}
+ className={classes.navIconHide}
+ >
+ <MenuIcon />
+ </IconButton>
+ <div className={classes.flex}>
+ <div className={classes.wrapper}>
+ <div className={classes.search}>
+ <SearchIcon />
+ </div>
+ <input className={classes.input} onChange={(event) => search(event)} placeholder="Search Email" />
+ </div>
+ </div>
+ </Toolbar>
+ </AppBar>
+ );
+ }
+}
+
+EmailHeader.propTypes = {
+ classes: PropTypes.object.isRequired,
+ search: PropTypes.func.isRequired,
+ handleDrawerToggle: PropTypes.func.isRequired,
+};
+
+export default withStyles(styles)(EmailHeader);
diff --git a/front/odiparpack/app/components/Email/EmailList.js b/front/odiparpack/app/components/Email/EmailList.js
new file mode 100644
index 0000000..1fc3507
--- /dev/null
+++ b/front/odiparpack/app/components/Email/EmailList.js
@@ -0,0 +1,314 @@
+import React, { Fragment } from 'react';
+import PropTypes from 'prop-types';
+import { withStyles } from '@material-ui/core/styles';
+import Bookmark from '@material-ui/icons/Bookmark';
+import Delete from '@material-ui/icons/Delete';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import classNames from 'classnames';
+import Flag from '@material-ui/icons/Flag';
+import People from '@material-ui/icons/People';
+import QuestionAnswer from '@material-ui/icons/QuestionAnswer';
+import ReportIcon from '@material-ui/icons/Report';
+import LabelIcon from '@material-ui/icons/Label';
+import FileIcon from '@material-ui/icons/Description';
+import Download from '@material-ui/icons/CloudDownload';
+import StarBorder from '@material-ui/icons/StarBorder';
+import Star from '@material-ui/icons/Star';
+import {
+ List,
+ Typography,
+ ExpansionPanel,
+ ExpansionPanelDetails,
+ ExpansionPanelSummary,
+ ExpansionPanelActions,
+ Tooltip,
+ IconButton,
+ Avatar,
+ Button,
+ ListSubheader,
+ Menu,
+ MenuItem,
+ Divider,
+} from '@material-ui/core';
+import isImage from '../Forms/helpers/helpers.js';
+import styles from './email-jss';
+
+
+const ITEM_HEIGHT = 80;
+class EmailList extends React.Component {
+ state = {
+ anchorElOpt: null,
+ itemToMove: null
+ };
+
+ handleClickOpt = (event, item) => {
+ this.setState({
+ anchorElOpt: event.currentTarget,
+ itemToMove: item
+ });
+ };
+
+ handleCloseOpt = () => {
+ this.setState({ anchorElOpt: null });
+ };
+
+ handleMoveTo = (item, category) => {
+ this.props.moveTo(item, category);
+ this.setState({ anchorElOpt: null });
+ }
+
+ render() {
+ const {
+ classes,
+ emailData,
+ openMail,
+ filterPage,
+ keyword,
+ remove,
+ toggleStar,
+ reply
+ } = this.props;
+ const { anchorElOpt, itemToMove } = this.state;
+ /* Basic Filter */
+ const inbox = emailData.filter(item => item.get('category') !== 'sent' && item.get('category') !== 'spam');
+ const stared = emailData.filter(item => item.get('stared'));
+ const sent = emailData.filter(item => item.get('category') === 'sent');
+ const spam = emailData.filter(item => item.get('category') === 'spam');
+ /* Category Filter */
+ const updates = emailData.filter(item => item.get('category') === 'updates');
+ const social = emailData.filter(item => item.get('category') === 'social');
+ const forums = emailData.filter(item => item.get('category') === 'forums');
+ const promos = emailData.filter(item => item.get('category') === 'promos');
+ const getCategory = cat => {
+ switch (cat) {
+ case 'updates':
+ return (
+ <span className={classNames(classes.iconOrange, classes.category)}>
+ <Flag />
+ {' '}
+Updates
+ </span>
+ );
+ case 'social':
+ return (
+ <span className={classNames(classes.iconRed, classes.category)}>
+ <People />
+ {' '}
+Social
+ </span>
+ );
+ case 'promos':
+ return (
+ <span className={classNames(classes.iconBlue, classes.category)}>
+ <LabelIcon />
+ {' '}
+Promos
+ </span>
+ );
+ case 'forums':
+ return (
+ <span className={classNames(classes.iconCyan, classes.category)}>
+ <QuestionAnswer />
+ {' '}
+Forums
+ </span>
+ );
+ default:
+ return false;
+ }
+ };
+ const attachmentPreview = filesArray => filesArray.map((file, index) => {
+ const base64File = URL.createObjectURL(file);
+ if (isImage(file)) {
+ return (
+ <div key={index.toString()} className={classes.item}>
+ <div className="imageContainer col fileIconImg">
+ <div className="downloadBtn">
+ <IconButton color="secondary" component="a" href={base64File} target="_blank">
+ <Download />
+ </IconButton>
+ </div>
+ <figure className="imgWrap"><img className="smallPreviewImg" src={base64File} alt="preview" /></figure>
+ </div>
+ <Typography noWrap>{file.name}</Typography>
+ </div>
+ );
+ }
+ return (
+ <div key={index.toString()} className={classes.item}>
+ <div className="imageContainer col fileIconImg">
+ <div className="fileWrap">
+ <div className="downloadBtn">
+ <IconButton color="secondary" href={base64File} target="_blank">
+ <Download />
+ </IconButton>
+ </div>
+ <FileIcon className="smallPreviewImg" alt="preview" />
+ </div>
+ </div>
+ <Typography noWrap>{file.name}</Typography>
+ </div>
+ );
+ });
+ const getEmail = dataArray => dataArray.map(mail => {
+ const renderHTML = { __html: mail.get('content') };
+ if (mail.get('subject').toLowerCase().indexOf(keyword) === -1) {
+ return false;
+ }
+ return (
+ <ExpansionPanel className={classes.emailList} key={mail.get('id')} onChange={() => openMail(mail)}>
+ <ExpansionPanelSummary className={classes.emailSummary} expandIcon={<ExpandMoreIcon />}>
+ <div className={classes.fromHeading}>
+ <Tooltip id="tooltip-mark" title="Stared">
+ <IconButton onClick={() => toggleStar(mail)} className={classes.starBtn}>{mail.get('stared') ? (<Star className={classes.iconOrange} />) : (<StarBorder />) }</IconButton>
+ </Tooltip>
+ {mail.get('category') !== 'spam'
+ ? (<Avatar alt="avatar" src={mail.get('avatar')} className={classes.avatar} />)
+ : (<Avatar alt="avatar" className={classes.avatar}><ReportIcon /></Avatar>)
+ }
+ <Typography className={classes.heading}>
+ {mail.get('category') === 'sent' && ('To ')}
+ {mail.get('name')}
+ <Typography variant="caption" display="block">{mail.get('date')}</Typography>
+ </Typography>
+ </div>
+ <div className={classes.column}>
+ <Typography className={classes.secondaryHeading} noWrap>{mail.get('subject')}</Typography>
+ {getCategory(mail.get('category'))}
+ </div>
+ </ExpansionPanelSummary>
+ <ExpansionPanelDetails className={classes.details}>
+ <section>
+ <div className={classes.topAction}>
+ <Typography className={classes.headMail}>
+ {mail.get('category') !== 'sent' && (
+ <Fragment>
+From
+ {mail.get('name')}
+ {' '}
+to me
+ </Fragment>
+ )}
+ </Typography>
+ <div className={classes.opt}>
+ <Tooltip id="tooltip-mark" title="Stared">
+ <IconButton onClick={() => toggleStar(mail)}>{mail.get('stared') ? (<Star className={classes.iconOrange} />) : (<StarBorder />) }</IconButton>
+ </Tooltip>
+ <Tooltip id="tooltip-mark" title="Mark message to">
+ <IconButton
+ className={classes.button}
+ aria-label="mark"
+ aria-owns={anchorElOpt ? 'long-menu' : null}
+ aria-haspopup="true"
+ onClick={(event) => this.handleClickOpt(event, mail)}
+ >
+ <Bookmark />
+ </IconButton>
+ </Tooltip>
+ <Tooltip id="tooltip-mark" title="Remove mail">
+ <IconButton className={classes.button} aria-label="Delete" onClick={() => remove(mail)}><Delete /></IconButton>
+ </Tooltip>
+ </div>
+ </div>
+ <div className={classes.emailContent}>
+ <Typography variant="h6" gutterBottom>{mail.get('subject')}</Typography>
+ <article dangerouslySetInnerHTML={renderHTML} />
+ </div>
+ <div className={classes.preview}>
+ {attachmentPreview(mail.get('attachment'))}
+ </div>
+ </section>
+ </ExpansionPanelDetails>
+ <Divider />
+ <ExpansionPanelActions>
+ <div className={classes.action}>
+ <Button size="small">Forwad</Button>
+ <Button size="small" color="secondary" onClick={() => reply(mail)}>Reply</Button>
+ </div>
+ </ExpansionPanelActions>
+ </ExpansionPanel>
+ );
+ });
+ const showEmail = category => {
+ switch (category) {
+ case 'inbox':
+ return getEmail(inbox);
+ case 'stared':
+ return getEmail(stared);
+ case 'sent':
+ return getEmail(sent);
+ case 'spam':
+ return getEmail(spam);
+ case 'updates':
+ return getEmail(updates);
+ case 'social':
+ return getEmail(social);
+ case 'promos':
+ return getEmail(promos);
+ case 'forums':
+ return getEmail(forums);
+ default:
+ return getEmail(inbox);
+ }
+ };
+ return (
+ <main className={classes.content}>
+ <div className={classes.toolbar} />
+ <Menu
+ id="long-menu"
+ anchorEl={anchorElOpt}
+ open={Boolean(anchorElOpt)}
+ onClose={this.handleCloseOpt}
+ className={classes.markMenu}
+ PaperProps={{ style: { maxHeight: ITEM_HEIGHT * 4.5, width: 200 } }}
+ >
+ <List
+ component="nav"
+ subheader={<ListSubheader component="div">Mark to... </ListSubheader>}
+ />
+ <MenuItem selected onClick={() => this.handleMoveTo(itemToMove, 'updates')}>
+ <Flag className={classes.iconOrange} />
+ {' '}
+Updates
+ </MenuItem>
+ <MenuItem onClick={() => this.handleMoveTo(itemToMove, 'social')}>
+ <People className={classes.iconRed} />
+ {' '}
+Social
+ </MenuItem>
+ <MenuItem onClick={() => this.handleMoveTo(itemToMove, 'promos')}>
+ <LabelIcon className={classes.iconBlue} />
+ {' '}
+Promos
+ </MenuItem>
+ <MenuItem onClick={() => this.handleMoveTo(itemToMove, 'forums')}>
+ <QuestionAnswer className={classes.iconCyan} />
+ {' '}
+Forums
+ </MenuItem>
+ <Divider />
+ <MenuItem onClick={() => this.handleMoveTo(itemToMove, 'spam')}>
+ <ReportIcon />
+ {' '}
+Spam
+ </MenuItem>
+ </Menu>
+ {showEmail(filterPage)}
+ </main>
+ );
+ }
+}
+
+EmailList.propTypes = {
+ classes: PropTypes.object.isRequired,
+ emailData: PropTypes.object.isRequired,
+ openMail: PropTypes.func.isRequired,
+ moveTo: PropTypes.func.isRequired,
+ remove: PropTypes.func.isRequired,
+ toggleStar: PropTypes.func.isRequired,
+ reply: PropTypes.func.isRequired,
+ filterPage: PropTypes.string.isRequired,
+ keyword: PropTypes.string.isRequired,
+};
+
+export default withStyles(styles)(EmailList);
diff --git a/front/odiparpack/app/components/Email/EmailSidebar.js b/front/odiparpack/app/components/Email/EmailSidebar.js
new file mode 100644
index 0000000..1951de2
--- /dev/null
+++ b/front/odiparpack/app/components/Email/EmailSidebar.js
@@ -0,0 +1,162 @@
+import React, { Fragment } from 'react';
+import PropTypes from 'prop-types';
+import { withStyles } from '@material-ui/core/styles';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import SendIcon from '@material-ui/icons/Send';
+import ReportIcon from '@material-ui/icons/Report';
+import StarIcon from '@material-ui/icons/Star';
+import Flag from '@material-ui/icons/Flag';
+import People from '@material-ui/icons/People';
+import QuestionAnswer from '@material-ui/icons/QuestionAnswer';
+import LabelIcon from '@material-ui/icons/Label';
+import Add from '@material-ui/icons/Add';
+import {
+ Drawer,
+ List,
+ ListItem,
+ ListItemIcon,
+ ListItemText,
+ Hidden,
+ Button,
+ Divider,
+} from '@material-ui/core';
+import styles from './email-jss';
+
+
+const MenuList = props => {
+ const {
+ classes,
+ compose,
+ goto,
+ selected,
+ } = props;
+ return (
+ <Fragment>
+ <List>
+ <ListItem>
+ <Button variant="contained" onClick={compose} fullWidth color="primary">
+ <Add />
+ {' '}
+Compose
+ </Button>
+ </ListItem>
+ <ListItem button className={selected === 'inbox' ? classes.selected : ''} onClick={() => goto('inbox')}>
+ <ListItemIcon>
+ <InboxIcon />
+ </ListItemIcon>
+ <ListItemText primary="Inbox" />
+ </ListItem>
+ <ListItem button className={selected === 'stared' ? classes.selected : ''} onClick={() => goto('stared')}>
+ <ListItemIcon>
+ <StarIcon />
+ </ListItemIcon>
+ <ListItemText primary="Stared" />
+ </ListItem>
+ <ListItem button className={selected === 'sent' ? classes.selected : ''} onClick={() => goto('sent')}>
+ <ListItemIcon>
+ <SendIcon />
+ </ListItemIcon>
+ <ListItemText primary="Sent" />
+ </ListItem>
+ <ListItem button className={selected === 'spam' ? classes.selected : ''} onClick={() => goto('spam')}>
+ <ListItemIcon>
+ <ReportIcon />
+ </ListItemIcon>
+ <ListItemText primary="Spam" />
+ </ListItem>
+ </List>
+ <Divider className={classes.divider} />
+ <List>
+ <ListItem button className={selected === 'updates' ? classes.selected : ''} onClick={() => goto('updates')}>
+ <ListItemIcon>
+ <Flag className={classes.iconOrange} />
+ </ListItemIcon>
+ <ListItemText primary="Updates" />
+ </ListItem>
+ <ListItem button className={selected === 'social' ? classes.selected : ''} onClick={() => goto('social')}>
+ <ListItemIcon>
+ <People className={classes.iconRed} />
+ </ListItemIcon>
+ <ListItemText primary="Social" />
+ </ListItem>
+ <ListItem button className={selected === 'promos' ? classes.selected : ''} onClick={() => goto('promos')}>
+ <ListItemIcon>
+ <LabelIcon className={classes.iconBlue} />
+ </ListItemIcon>
+ <ListItemText primary="Promos" />
+ </ListItem>
+ <ListItem button className={selected === 'forums' ? classes.selected : ''} onClick={() => goto('forums')}>
+ <ListItemIcon>
+ <QuestionAnswer className={classes.iconCyan} />
+ </ListItemIcon>
+ <ListItemText primary="Forums" />
+ </ListItem>
+ </List>
+ </Fragment>
+ );
+};
+
+MenuList.propTypes = {
+ classes: PropTypes.object.isRequired,
+ compose: PropTypes.func.isRequired,
+ goto: PropTypes.func.isRequired,
+ selected: PropTypes.string.isRequired,
+};
+
+const MenuEmail = withStyles(styles)(MenuList);
+
+class EmailSidebar extends React.Component {
+ render() {
+ const {
+ classes,
+ compose,
+ goto,
+ selected,
+ handleDrawerToggle,
+ mobileOpen
+ } = this.props;
+ return (
+ <Fragment>
+ <Hidden mdUp>
+ <Drawer
+ variant="temporary"
+ open={mobileOpen}
+ onClose={handleDrawerToggle}
+ classes={{
+ paper: classes.drawerPaper,
+ }}
+ ModalProps={{
+ keepMounted: true, // Better open performance on mobile.
+ }}
+ >
+ <div className={classes.toolbar} />
+ <MenuEmail compose={compose} goto={goto} selected={selected} />
+ </Drawer>
+ </Hidden>
+ <Hidden smDown>
+ <Drawer
+ variant="permanent"
+ className={classes.sidebar}
+ classes={{
+ paper: classes.drawerPaper,
+ }}
+ >
+ <div className={classes.toolbar} />
+ <MenuEmail compose={compose} goto={goto} selected={selected} />
+ </Drawer>
+ </Hidden>
+ </Fragment>
+ );
+ }
+}
+
+EmailSidebar.propTypes = {
+ classes: PropTypes.object.isRequired,
+ compose: PropTypes.func.isRequired,
+ goto: PropTypes.func.isRequired,
+ handleDrawerToggle: PropTypes.func.isRequired,
+ selected: PropTypes.string.isRequired,
+ mobileOpen: PropTypes.bool.isRequired,
+};
+
+export default withStyles(styles)(EmailSidebar);
diff --git a/front/odiparpack/app/components/Email/email-jss.js b/front/odiparpack/app/components/Email/email-jss.js
new file mode 100644
index 0000000..6775966
--- /dev/null
+++ b/front/odiparpack/app/components/Email/email-jss.js
@@ -0,0 +1,238 @@
+import { fade } from '@material-ui/core/styles/colorManipulator';
+import { red, orange, indigo as blue, cyan } from '@material-ui/core/colors';
+const drawerWidth = 240;
+const styles = theme => ({
+ iconRed: {
+ color: red[500]
+ },
+ iconOrange: {
+ color: orange[500]
+ },
+ iconBlue: {
+ color: blue[500]
+ },
+ iconCyan: {
+ color: cyan[500]
+ },
+ appBar: {
+ zIndex: 130,
+ background: theme.palette.secondary.main,
+ '& ::-webkit-input-placeholder': {
+ color: theme.palette.common.white
+ },
+ '& ::-moz-placeholder': {
+ color: theme.palette.common.white
+ },
+ '& :-ms-input-placeholder': {
+ color: theme.palette.common.white
+ },
+ '& :-moz-placeholder': {
+ color: theme.palette.common.white
+ }
+ },
+ flex: {
+ flex: 1,
+ },
+ wrapper: {
+ fontFamily: theme.typography.fontFamily,
+ position: 'relative',
+ marginLeft: theme.spacing(1),
+ borderRadius: 2,
+ background: fade(theme.palette.common.white, 0.15),
+ '&:hover': {
+ background: fade(theme.palette.common.white, 0.25),
+ },
+ '& $input': {
+ transition: theme.transitions.create('width'),
+ },
+ },
+ addBtn: {
+ position: 'fixed',
+ bottom: 30,
+ right: 30,
+ zIndex: 1000
+ },
+ sidebar: {
+ zIndex: 120
+ },
+ search: {
+ width: theme.spacing(9),
+ height: '100%',
+ position: 'absolute',
+ pointerEvents: 'none',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ input: {
+ font: 'inherit',
+ padding: `${theme.spacing(1)}px ${theme.spacing(1)}px ${theme.spacing(1)}px ${theme.spacing(9)}px`,
+ border: 0,
+ display: 'block',
+ verticalAlign: 'middle',
+ whiteSpace: 'normal',
+ background: 'none',
+ margin: 0, // Reset for Safari
+ color: 'inherit',
+ width: '100%',
+ '&:focus': {
+ outline: 0,
+ },
+ },
+ drawerPaper: {
+ [theme.breakpoints.up('md')]: {
+ position: 'relative',
+ },
+ width: drawerWidth,
+ background: theme.palette.grey[50],
+ border: 'none',
+ padding: 10
+ },
+ selected: {
+ background: theme.palette.secondary.light,
+ borderLeft: `2px solid ${theme.palette.secondary.main}`,
+ paddingLeft: 22,
+ '& h3': {
+ color: theme.palette.secondary.dark
+ }
+ },
+ content: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.default,
+ zIndex: 120,
+ marginBottom: theme.spacing(8),
+ [theme.breakpoints.up('md')]: {
+ padding: theme.spacing(3),
+ marginBottom: theme.spacing(4),
+ paddingLeft: 0,
+ },
+ position: 'relative',
+ minWidth: 0, // So the Typography noWrap works
+ },
+ toolbar: {
+ minHeight: 32
+ },
+ title: {
+ width: 205
+ },
+ divider: {
+ margin: '0 20px 0 10px'
+ },
+ /* Email List */
+ column: {
+ flexBasis: '33.33%',
+ overflow: 'hidden',
+ paddingRight: '0 !important',
+ paddingTop: 5,
+ marginLeft: 20
+ },
+ secondaryHeading: {
+ fontSize: 14,
+ color: theme.palette.text.secondary,
+ },
+ icon: {
+ verticalAlign: 'bottom',
+ height: 20,
+ width: 20,
+ },
+ details: {
+ alignItems: 'center',
+ [theme.breakpoints.down('sm')]: {
+ padding: `${theme.spacing(1)}px ${theme.spacing(1)}px ${theme.spacing(3)}px`
+ },
+ '& section': {
+ width: '100%'
+ }
+ },
+ link: {
+ color: theme.palette.secondary.main,
+ textDecoration: 'none',
+ '&:hover': {
+ textDecoration: 'underline',
+ },
+ },
+ avatar: {},
+ fromHeading: {
+ overflow: 'hidden',
+ display: 'flex',
+ alignItems: 'center',
+ '& $avatar': {
+ width: 30,
+ height: 30,
+ marginRight: 20
+ }
+ },
+ topAction: {
+ display: 'flex',
+ background: theme.palette.grey[100],
+ marginBottom: 20,
+ alignItems: 'center',
+ padding: '0 20px',
+ borderRadius: 2,
+ },
+ category: {
+ fontSize: 12,
+ textTransform: 'uppercase',
+ display: 'flex',
+ '& svg': {
+ fontSize: 16,
+ marginRight: 5
+ }
+ },
+ markMenu: {
+ '& svg': {
+ marginRight: 10
+ }
+ },
+ headMail: {
+ flex: 1
+ },
+ field: {
+ width: '100%',
+ marginBottom: 20,
+ '& svg': {
+ color: theme.palette.grey[400],
+ fontSize: 18,
+ }
+ },
+ hiddenDropzone: {
+ display: 'none'
+ },
+ sendIcon: {
+ marginLeft: 10
+ },
+ item: {},
+ preview: {
+ display: 'flex',
+ marginBottom: 20,
+ '& $item': {
+ maxWidth: 160,
+ marginBottom: 5,
+ marginRight: 5
+ }
+ },
+ emailSummary: {
+ paddingLeft: 0,
+ '& > div': {
+ [theme.breakpoints.down('sm')]: {
+ flexDirection: 'column'
+ },
+ }
+ },
+ emailContent: {
+ padding: theme.spacing(2),
+ [theme.breakpoints.down('sm')]: {
+ padding: `${theme.spacing(2)}px ${theme.spacing(2)}px`,
+ },
+ },
+ starBtn: {
+ marginRight: 10
+ },
+ navIconHide: {
+ [theme.breakpoints.up('md')]: {
+ display: 'none',
+ },
+ },
+});
+
+export default styles;