Skip to content

Commit

Permalink
Merge pull request #80 from ECN/feature-conversational-ui
Browse files Browse the repository at this point in the history
Feature conversational ui
  • Loading branch information
campb303 authored Oct 23, 2020
2 parents 4b89356 + 9a64d00 commit d4a4c5b
Show file tree
Hide file tree
Showing 30 changed files with 683 additions and 128 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"material-table": "^1.63.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-relative-time": "0.0.7",
"react-scripts": "3.4.1",
"react-table": "^7.5.1",
"react-router-dom": "^5.2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function App() {
/>
}
</Box>
</Box>
</Paper>
</ThemeProvider>
);
}
Expand Down
21 changes: 21 additions & 0 deletions src/components/Assignment/Assignment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import PropTypes from "prop-types";
import { Typography } from "@material-ui/core";
import RelativeTime from "react-relative-time";

export default function Assignment({ by, to, datetime }){
return (
<Typography>
<b>{by}</b> assigned this to <b>{to}</b> <RelativeTime value={new Date(datetime)} />.
</Typography>
);
}

Assignment.propTypes = {
/** The person who changed the assignment. */
"by": PropTypes.string.isRequired,
/** The person the item was assigned to. */
"to": PropTypes.string.isRequired,
/** The time the assignment was changed in ISO 8601 format. */
"datetime": PropTypes.string.isRequired
}
26 changes: 26 additions & 0 deletions src/components/Assignment/Assignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Renders a string representation of an assignment with a relative time.

```jsx
import Assignment from "./Assignment";

const example_assignment = {
"type": "assignment",
"datetime": "2020-06-23T13:27:00-0400",
"by": "campb303",
"to": "campb303"
};

<Assignment {...example_assignment} />

```

```jsx static
const example_assignment = {
"type": "assignment",
"datetime": "2020-06-23T13:27:00-0400",
"by": "campb303",
"to": "campb303"
};

<Assignment {...example_assignment} />
```
1 change: 1 addition & 0 deletions src/components/Assignment/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./Assignment";
44 changes: 44 additions & 0 deletions src/components/CurrentBreakPoint/CurrentBreakPoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import PropTypes from "prop-types";
import { useTheme, useMediaQuery, makeStyles } from '@material-ui/core';

export default function CurrentBreakPoint(){
const theme = useTheme();
const useStyles = makeStyles({
true: {
color: theme.palette.success.main
},
false: {
color: theme.palette.error.main
}
});
const classes = useStyles();

const mediaQueries = {
"xs": useMediaQuery(theme.breakpoints.up('xs')),
"sm": useMediaQuery(theme.breakpoints.up('sm')),
"md": useMediaQuery(theme.breakpoints.up('md')),
"lg": useMediaQuery(theme.breakpoints.up('lg')),
"xl": useMediaQuery(theme.breakpoints.up('xl')),
}

return (
<p style={{ margin: "0px" }}>
{ Object.keys(mediaQueries).map( (key) => {
return(
<span className={ mediaQueries[key] ? classes.true : classes.false }>
{`${key.toUpperCase()}: ${ mediaQueries[key] ? "true" : "false"}\n\n\n\n`}
</span>
)
})}
</p>
);
}

CurrentBreakPoint.propTypes = {

};

CurrentBreakPoint.defaultProps = {

};
30 changes: 30 additions & 0 deletions src/components/CurrentBreakPoint/CurrentBreakPoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Displays the MUI theme breakpoints and whether or not they are active. This is a utility component meant to make UI development easier, not as a UI element for production code.

It must be used under a [ThemeProvider](https://material-ui.com/styles/api/#themeprovider).

---

```jsx
import { ThemeProvider } from '@material-ui/core/styles';
import { Paper, makeStyles } from '@material-ui/core';
import webqueue2Theme from "../../theme.js";
import CurrentBreakPoint from "./CurrentBreakPoint";

const theme = webqueue2Theme(false);

const useStyles = makeStyles({
paperPadding: {
padding: theme.spacing(1)
}
});
const classes = useStyles();

<ThemeProvider theme={theme}>
<Paper classes={{ root: classes.paperPadding }}>
<CurrentBreakPoint />
</Paper>
</ThemeProvider>
```
```jsx static
<CurrentBreakPoint />
```
1 change: 1 addition & 0 deletions src/components/CurrentBreakPoint/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CurrentBreakPoint";
50 changes: 50 additions & 0 deletions src/components/DirectoryInformation/DirectoryInformation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react";
import PropTypes from "prop-types";
import { TableContainer, Table, TableRow, TableCell, Paper, makeStyles, useTheme } from "@material-ui/core";

export default function DirectoryInformation({ section }) {

const theme = useTheme();
const useStyles = makeStyles((theme) => ({
headerCell: {
borderBottom: "none",
paddingTop: theme.spacing(0.5),
paddingBottom: theme.spacing(0.5),
},
bodyCell: {
wordBreak: "break-word",
borderBottom: "none",
paddingTop: theme.spacing(0.5),
paddingBottom: theme.spacing(0.5),
},
stripedRow: {
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.action.hover,
},
},
}));
const classes = useStyles(theme);

return (
<TableContainer component={Paper}>
<Table size="small" >
{Object.keys(section).map((key) => (
key === "type" ? "" :
<TableRow classes={{ root: classes.stripedRow }}>
<TableCell classes={{ root: classes.headerCell }} variant="head">{key}</TableCell>
<TableCell classes={{ root: classes.bodyCell }}>{section[key]}</TableCell>
</TableRow>
))}
</Table>
</TableContainer>
);
};

DirectoryInformation.propTypes = {
/** The object containing directory information. */
"section": PropTypes.object
};

DirectoryInformation.defaultProps = {
"section": {}
};
28 changes: 28 additions & 0 deletions src/components/DirectoryInformation/DirectoryInformation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Displays the directory information as a table.


```jsx
import DirectoryInformation from "./DirectoryInformation";

const example_directory_data = {
"type": "directory_information",
"Name": "Heyi Feng",
"Login": "feng293",
"Computer": "civil4147pc2.ecn",
"Location": "HAMP 4147",
"Email": "feng293@purdue.edu",
"Phone": "5039154835",
"Office": "",
"UNIX Dir": "None",
"Zero Dir": "U=\\\\myhome.itap.purdue.edu\\myhome\\%username%",
"User ECNDB": "http://eng.purdue.edu/jump/2e29495",
"Host ECNDB": "http://eng.purdue.edu/jump/2eccc3f",
"Subject": "Upgrade system and Abaqus"
};

<DirectoryInformation section={example_directory_data} />
```

```jsx static
<DirectoryInformation section={example_directory_data} />
```
1 change: 1 addition & 0 deletions src/components/DirectoryInformation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./DirectoryInformation";
114 changes: 83 additions & 31 deletions src/components/EmailHeader/EmailHeader.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import React from "react";
import PropTypes from "prop-types";
import { Card, CardHeader, makeStyles } from "@material-ui/core";
import { Paper, Grid, makeStyles, useTheme, Typography } from "@material-ui/core";
import RelativeTime from "react-relative-time";
import UserAvatar from "../UserAvatar/";
import webqueue2Theme from "../../theme";

export default function EmailHeader({name, date, email}){
export default function EmailHeader({ datetime, from_name, from_email, to, cc }){

const theme = webqueue2Theme(false);
const theme = useTheme();
const useStyles = makeStyles({
"verticalPadding": {
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
"paperWrapper": {
padding: `${theme.spacing(1)}px ${theme.spacing(2)}px`,
margin: `${theme.spacing(1)}px 0`,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0
},
"removeCardHeaderPadding": {
padding: "0"
"removeNegativeMargin": {
margin: 0
},
"secondaryInformation": {
backgroundColor: theme.palette.type === "light" ? theme.palette.grey[100] : theme.palette.grey[700],
margin: `${theme.spacing(1)}px ${-theme.spacing(2)}px ${-theme.spacing(1)}px ${-theme.spacing(2)}px`,
padding: `${theme.spacing(1)}px ${theme.spacing(2)}px`
}
});
const classes = useStyles();
Expand All @@ -31,43 +38,88 @@ export default function EmailHeader({name, date, email}){
* return ""
* @returns {string}
*/
function buildTitle(name, email){
let title = "";
function buildEmailNameString(name, email){
let emailNameString = "";
const isNotEmpty = (value) => {
return value === "" || value === null ? false : true;
};
if (isNotEmpty(name)){
title += `${name}`;
emailNameString += `${name}`;
};
if (isNotEmpty(email)){
title += ` <${email}>`
emailNameString += ` <${email}>`
}
return title;
return emailNameString;
};

/**
* Returns a string of emails with names.
* @param {array} Array of objects containing names and emails.
* @returns {string} String of email with names.
*/
function buildRecipientString(recipients){
if (recipients.length === 0){
return "Tits";
}

let recipientString = "";
recipients.map( (recipient, index) => {
recipientString += buildEmailNameString(recipient.name, recipient.email);
index < recipients.length - 1 ? recipientString += ", " : recipientString += "";
return true;
})
return recipientString;
};

return(
<Card elevation={0} classes={{root: classes.verticalPadding}}>
<CardHeader
avatar={<UserAvatar userName={name} />}
title={buildTitle(name, email)}
subheader={Date(date)}
classes={{root: classes.removeCardHeaderPadding}}
/>
</Card>
<Paper variant="outlined" classes={{ root: classes.paperWrapper }}>
<Paper elevation={0} square>
<Grid container alignItems="center" spacing={2}>
<Grid item xs={2} sm={1} md={2} lg={1}>
<UserAvatar
name={ from_name === "Name Unavailable" ? "" : from_name }
classes={{ root: classes.itemSpacing }}
/>
</Grid>
<Grid item xs={7}>
<Typography variant="body2">{buildEmailNameString(from_name, from_email)}</Typography>
</Grid>
<Grid item xs={3}>
<Typography variant="body2" color="textSecondary" align="right"><RelativeTime value={datetime} /></Typography>
</Grid>
</Grid>
</Paper>
{ (to.length === 0 && cc.length === 0) ? null :
<Paper elevation={0} square classes={{ root: classes.secondaryInformation }}>
<Typography variant="body2">
{to.length === 0 ? null : <><b>To: </b>{buildRecipientString(to)}</>}
</Typography>
<Typography variant="body2">
{cc.length === 0 ? null : <><b>Cc: </b>{buildRecipientString(cc)}</> }
</Typography>
</Paper>
}
</Paper>
);
};

EmailHeader.propTypes = {
/** Name of the user. */
"name": PropTypes.string,
/** Date of the message. */
"date": PropTypes.string,
/** Email address of the user. */
"email": PropTypes.string
/** Name of message sender. */
"from_name": PropTypes.string,
/** Date the message was sent in ISO 8601 format. */
"datetime": PropTypes.string,
/** Email address of message sender. */
"from_email": PropTypes.string,
/** Array of people the message was sent to */
"to": PropTypes.array,
/** Array of people the message was cc'd to */
"cc": PropTypes.array
};

EmailHeader.defaultProps = {
"name": "",
"date": "",
"email": ""
"from_name": "Name Unavailable",
"datetime": new Date(1970, 1, 1, 0, 0, 0, 0),
"from_email": "Email Unavailable",
"to": [],
"cc": []
};
Loading

0 comments on commit d4a4c5b

Please sign in to comment.