diff --git a/package-lock.json b/package-lock.json
index bd37505..2d43568 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12382,6 +12382,11 @@
"react-is": "^16.9.0"
}
},
+ "react-relative-time": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/react-relative-time/-/react-relative-time-0.0.7.tgz",
+ "integrity": "sha1-n39AdChuvmE1tTPu4a3qBV35cYM="
+ }.
"react-router": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
diff --git a/package.json b/package.json
index 8df2bc7..56190c6 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/src/App.js b/src/App.js
index 9999793..c166231 100644
--- a/src/App.js
+++ b/src/App.js
@@ -94,7 +94,7 @@ function App() {
/>
}
-
+
);
}
diff --git a/src/components/Assignment/Assignment.js b/src/components/Assignment/Assignment.js
new file mode 100644
index 0000000..d17385f
--- /dev/null
+++ b/src/components/Assignment/Assignment.js
@@ -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 (
+
+ {by} assigned this to {to} .
+
+ );
+}
+
+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
+}
\ No newline at end of file
diff --git a/src/components/Assignment/Assignment.md b/src/components/Assignment/Assignment.md
new file mode 100644
index 0000000..eaaa150
--- /dev/null
+++ b/src/components/Assignment/Assignment.md
@@ -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"
+};
+
+
+
+```
+
+```jsx static
+const example_assignment = {
+ "type": "assignment",
+ "datetime": "2020-06-23T13:27:00-0400",
+ "by": "campb303",
+ "to": "campb303"
+};
+
+
+```
\ No newline at end of file
diff --git a/src/components/Assignment/index.js b/src/components/Assignment/index.js
new file mode 100644
index 0000000..f3e1b8b
--- /dev/null
+++ b/src/components/Assignment/index.js
@@ -0,0 +1 @@
+export { default } from "./Assignment";
\ No newline at end of file
diff --git a/src/components/CurrentBreakPoint/CurrentBreakPoint.js b/src/components/CurrentBreakPoint/CurrentBreakPoint.js
new file mode 100644
index 0000000..1074891
--- /dev/null
+++ b/src/components/CurrentBreakPoint/CurrentBreakPoint.js
@@ -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 (
+
+ { Object.keys(mediaQueries).map( (key) => {
+ return(
+
+ {`${key.toUpperCase()}: ${ mediaQueries[key] ? "true" : "false"}\n\n\n\n`}
+
+ )
+ })}
+
+ );
+}
+
+CurrentBreakPoint.propTypes = {
+
+};
+
+CurrentBreakPoint.defaultProps = {
+
+};
\ No newline at end of file
diff --git a/src/components/CurrentBreakPoint/CurrentBreakPoint.md b/src/components/CurrentBreakPoint/CurrentBreakPoint.md
new file mode 100644
index 0000000..e171028
--- /dev/null
+++ b/src/components/CurrentBreakPoint/CurrentBreakPoint.md
@@ -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();
+
+
+
+
+
+
+```
+```jsx static
+
+```
\ No newline at end of file
diff --git a/src/components/CurrentBreakPoint/index.js b/src/components/CurrentBreakPoint/index.js
new file mode 100644
index 0000000..4720032
--- /dev/null
+++ b/src/components/CurrentBreakPoint/index.js
@@ -0,0 +1 @@
+export { default } from "./CurrentBreakPoint";
\ No newline at end of file
diff --git a/src/components/DirectoryInformation/DirectoryInformation.js b/src/components/DirectoryInformation/DirectoryInformation.js
new file mode 100644
index 0000000..6991e5e
--- /dev/null
+++ b/src/components/DirectoryInformation/DirectoryInformation.js
@@ -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 (
+
+
+ {Object.keys(section).map((key) => (
+ key === "type" ? "" :
+
+ {key}
+ {section[key]}
+
+ ))}
+
+
+ );
+};
+
+DirectoryInformation.propTypes = {
+ /** The object containing directory information. */
+ "section": PropTypes.object
+};
+
+DirectoryInformation.defaultProps = {
+ "section": {}
+};
\ No newline at end of file
diff --git a/src/components/DirectoryInformation/DirectoryInformation.md b/src/components/DirectoryInformation/DirectoryInformation.md
new file mode 100644
index 0000000..a71c076
--- /dev/null
+++ b/src/components/DirectoryInformation/DirectoryInformation.md
@@ -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"
+};
+
+
+```
+
+```jsx static
+
+```
\ No newline at end of file
diff --git a/src/components/DirectoryInformation/index.js b/src/components/DirectoryInformation/index.js
new file mode 100644
index 0000000..d67daa5
--- /dev/null
+++ b/src/components/DirectoryInformation/index.js
@@ -0,0 +1 @@
+export { default } from "./DirectoryInformation";
\ No newline at end of file
diff --git a/src/components/EmailHeader/EmailHeader.js b/src/components/EmailHeader/EmailHeader.js
index 3af9c0c..d3c5ccf 100644
--- a/src/components/EmailHeader/EmailHeader.js
+++ b/src/components/EmailHeader/EmailHeader.js
@@ -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();
@@ -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(
-
- }
- title={buildTitle(name, email)}
- subheader={Date(date)}
- classes={{root: classes.removeCardHeaderPadding}}
- />
-
+
+
+
+
+
+
+
+ {buildEmailNameString(from_name, from_email)}
+
+
+
+
+
+
+ { (to.length === 0 && cc.length === 0) ? null :
+
+
+ {to.length === 0 ? null : <>To: {buildRecipientString(to)}>}
+
+
+ {cc.length === 0 ? null : <>Cc: {buildRecipientString(cc)}> }
+
+
+ }
+
);
};
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": []
};
\ No newline at end of file
diff --git a/src/components/EmailHeader/EmailHeader.md b/src/components/EmailHeader/EmailHeader.md
index e163f38..522c3dd 100644
--- a/src/components/EmailHeader/EmailHeader.md
+++ b/src/components/EmailHeader/EmailHeader.md
@@ -1,9 +1,64 @@
-Description of EmailHeader.
+Displays an email header with name, email, time sent, and recipients if present.
+---
+
+Default usage, without props.
```jsx
import EmailHeader from "./EmailHeader";
```
```jsx static
+```
+
+With `datetime`, `from_name` and `from_email` props. When `first_name` is passed, the [UserAvatar](/#/Components/UserAvatar) will display the first letter of the name.
+```jsx
+import EmailHeader from "./EmailHeader";
+
+const demo_data = {
+ "datetime": "2020-05-11T13:44:12+0000",
+ "from_name": "Di Wang",
+ "from_email": "wang2039@purdue.edu",
+};
+
+
+
+```
+```jsx static
+
+```
+
+You can add to/cc data by passing `to` and `cc` props.
+```jsx
+import EmailHeader from "./EmailHeader";
+
+const demo_data = {
+ "datetime": "2020-05-11T13:44:12+0000",
+ "from_name": "Di Wang",
+ "from_email": "wang2039@purdue.edu",
+ "to": [
+ {
+ "name": "'cesite@ecn.purdue.edu'",
+ "email": "cesite@ecn.purdue.edu"
+ }
+ ],
+ "cc": [
+ {
+ "name": "Zavattieri, Pablo D",
+ "email": "zavattie@purdue.edu"
+ }
+ ]
+};
+
+
+
+```
+```jsx static
+
```
\ No newline at end of file
diff --git a/src/components/ItemBodyView/ItemBodyView.js b/src/components/ItemBodyView/ItemBodyView.js
index bed15c1..19e48fb 100644
--- a/src/components/ItemBodyView/ItemBodyView.js
+++ b/src/components/ItemBodyView/ItemBodyView.js
@@ -2,50 +2,50 @@ import React from "react";
import PropTypes from "prop-types";
import { Timeline, TimelineItem, TimelineSeparator, TimelineConnector, TimelineContent, TimelineDot } from '@material-ui/lab';
import { Typography, makeStyles } from "@material-ui/core";
-import webqueue2Theme from "../../theme";
-import EmailHeader from "../EmailHeader/";
+import DirectoryInformation from "../DirectoryInformation/";
+import Assignment from "../Assignment/";
+import TimelineActionCard from "../TimelineActionCard/";
+import MessageView from "../MessageView/";
import { objectIsEmpty } from "../../utilities";
export default function ItemBodyView({ item }) {
- const theme = webqueue2Theme(false);
- const useStyles = makeStyles((theme) => ({
- missingOppositeContent: {
+ const useStyles = makeStyles(() => ({
+ "Timeline-root": {
+ paddingLeft: "0",
+ paddingRight: "0",
+ },
+ "TimelineContent-root": {
+ paddingRight: "0",
+ },
+ "TimelineItem-missingOppositeContent": {
'&:before': {
content: '""',
flex: 0,
padding: '0',
},
- },
+ }
}));
- const classes = useStyles(theme);
+ const classes = useStyles();
const generateTimelineItem = (section) => {
- switch(section.type) {
- case "directoryInformation":
- if (section.content.length === 0){
- return "No Directory Information";
- } else {
- return "Directory Information Present"
- }
- case "initialMessage":
- return(
+ switch (section.type) {
+ case "directory_information":
+ return (
+
+ );
+ case "initial_message":
+ return (
<>
-
- {section.content.map((line, index) => {line})}
+
>
);
case "edit":
- return(
- <>
-
- {`${section.by} assigned thisat ${Date(section.datetime)}`}
-
- {section.content.map((line) => {line})}
- >
+ return (
+
);
case "status":
- return(
+ return (
<>
{`${section.by} update the status to at ${Date(section.datetime)}`}
@@ -53,27 +53,17 @@ export default function ItemBodyView({ item }) {
{section.content.map((line) => {line})}
>
);
- case "assign":
+ case "assignment":
return (
-
- {`${section.by} assigned this to ${section.to} at ${Date(section.datetime)}`}
-
+
);
- case "replyToUser":
- return(
- <>
-
- {`${section.by} replied ${Date(section.datetime)}`}
-
- {section.content.map((line) => {line})}
- >
+ case "reply_to_user":
+ return (
+
);
- case "replyFromUser":
- return(
- <>
-
- {section.content.map((line, index) => {line})}
- >
+ case "reply_from_user":
+ return (
+
);
default:
return "No Match Found";
@@ -81,20 +71,24 @@ export default function ItemBodyView({ item }) {
};
return (
-
- {objectIsEmpty(item) ? "" : item.content.map((section, index) => {
- return (
-
-
-
-
-
-
- {generateTimelineItem(section)}
-
-
- );
- })}
+
+ {objectIsEmpty(item) ? "" : item.content.map((section) => (
+
+
+
+
+
+
+ {generateTimelineItem(section)}
+
+
+ ))}
);
};
diff --git a/src/components/ItemBodyView/ItemBodyView.md b/src/components/ItemBodyView/ItemBodyView.md
index 2c224d1..6a741ea 100644
--- a/src/components/ItemBodyView/ItemBodyView.md
+++ b/src/components/ItemBodyView/ItemBodyView.md
@@ -11,8 +11,7 @@ The ItemBodyView displays the seven actions possible in an item:
```jsx
import ItemBodyView from "./ItemBodyView";
-const demoItem = {"queue": "ce", "number": 100, "lastUpdated": "08-27-20 09:49 PM", "headers": [{"type": "Merged-Time", "content": "Tue, 23 Jun 2020 13:31:53 -0400"}, {"type": "Merged-By", "content": "campb303"}, {"type": "QTime", "content": "1"}, {"type": "QTime-Updated-Time", "content": "Tue, 23 Jun 2020 13:28:50 EDT"}, {"type": "QTime-Updated-By", "content": "campb303"}, {"type": "Time", "content": "1"}, {"type": "Time-Updated-Time", "content": "Tue, 23 Jun 2020 13:28:50 EDT"}, {"type": "Time-Updated-By", "content": "campb303"}, {"type": "Replied-Time", "content": "Tue, 23 Jun 2020 13:28:48 -0400"}, {"type": "Replied-By", "content": "campb303"}, {"type": "Edited-Time", "content": "Tue, 23 Jun 2020 13:27:56 -0400"}, {"type": "Edited-By", "content": "campb303"}, {"type": "QAssigned-To", "content": "campb303"}, {"type": "QAssigned-To-Updated-Time", "content": "Tue, 23 Jun 2020 13:27:00 EDT"}, {"type": "QAssigned-To-Updated-By", "content": "campb303"}, {"type": "Assigned-To", "content": "campb303"}, {"type": "Assigned-To-Updated-Time", "content": "Tue, 23 Jun 2020 13:27:00 EDT"}, {"type": "Assigned-To-Updated-By", "content": "campb303"}, {"type": "QStatus", "content": "Dont Delete"}, {"type": "QStatus-Updated-Time", "content": "Tue, 23 Jun 2020 13:26:55 EDT"}, {"type": "QStatus-Updated-By", "content": "campb303"}, {"type": "Status", "content": "Dont Delete"}, {"type": "Status-Updated-Time", "content": "Tue, 23 Jun 2020 13:26:55 EDT"}, {"type": "Status-Updated-By", "content": "campb303"}, {"type": "Date", "content": "Tue, 23 Jun 2020 13:25:51 -0400"}, {"type": "From", "content": "Justin Campbell "}, {"type": "Message-ID", "content": "<911CE050-3240-4980-91DD-9C3EBB8DBCF8@purdue.edu>"}, {"type": "Subject", "content": "Beepboop"}, {"type": "To", "content": "cesite@ecn.purdue.edu"}, {"type": "Content-Type", "content": "text/plain; charset=\"utf-8\""}, {"type": "X-ECN-Queue-Original-Path", "content": "/home/pier/e/queue/Attachments/inbox/2020-06-23/208-original.txt"}, {"type": "X-ECN-Queue-Original-URL", "content": "https://engineering.purdue.edu/webqueue/Attachments/inbox/2020-06-23/208-original.txt"}], "content": [{"type": "directoryInformation", "content": []}, {"type": "initialMessage", "datetime": "2020-06-23T13:25:51-0400", "userName": "Justin Campbell", "userEmail": "campb303@purdue.edu", "ccRecipients": [], "content": ["Testtest\n"]}, {"type": "assign", "by": "campb303", "datetime": "2020-06-23T13:27:00-0400", "to": "campb303"}, {"type": "status", "by": "campb303", "datetime": "2020-06-23T13:26:55", "content": ["*** Status updated by: campb303 at: 6/23/2020 13:26:55 ***\n", "Dont Delete\n"]}, {"type": "edit", "by": "campb303", "datetime": "2020-06-23T13:27:56", "content": ["*** Edited by: campb303 at: 06/23/20 13:27:56 ***\n", "\n", "This be an edit my boy\n", "\n", "\n", "\n"]}, {"type": "replyToUser", "by": "campb303", "datetime": "2020-06-23T13:28:18", "content": ["*** Replied by: campb303 at: 06/23/20 13:28:18 ***\n", "\n", "This be a reply my son\n", "\n", "Justin\n", "ECN\n", "\n"]}, {"type": "replyFromUser", "datetime": "2020-06-23T13:30:45-0400", "subject": "Re: Beepboop", "userName": "Justin Campbell", "userEmail": "campb303@purdue.edu", "content": ["=== Additional information supplied by user ===\n", "\n", "Subject: Re: Beepboop\n", "From: Justin Campbell \n", "Date: Tue, 23 Jun 2020 13:30:45 -0400\n", "X-ECN-Queue-Original-Path: /home/pier/e/queue/Attachments/inbox/2020-06-23/212-original.txt\n", "X-ECN-Queue-Original-URL: https://engineering.purdue.edu/webqueue/Attachments/inbox/2020-06-23/212-original.txt\n", "\n", "Huzzah!\n", "\n", "===============================================\n", "\n"], "ccRecipients": []}], "isLocked": "ce 100 is locked by knewell using qvi", "userEmail": "campb303@purdue.edu", "userName": "Justin Campbell", "userAlias": "campb303", "assignedTo": "campb303", "subject": "Beepboop", "status": "Dont Delete", "priority": "", "department": "", "building": "", "dateReceived": "2020-06-23T13:25:51-0400"};
-
+const demoItem = {"queue": "ce", "number": 100, "lastUpdated": "09-28-20 01:26 PM", "headers": [{"type": "Merged-Time", "content": "Tue, 23 Jun 2020 13:31:53 -0400"}, {"type": "Merged-By", "content": "campb303"}, {"type": "QTime", "content": "1"}, {"type": "QTime-Updated-Time", "content": "Tue, 23 Jun 2020 13:28:50 EDT"}, {"type": "QTime-Updated-By", "content": "campb303"}, {"type": "Time", "content": "1"}, {"type": "Time-Updated-Time", "content": "Tue, 23 Jun 2020 13:28:50 EDT"}, {"type": "Time-Updated-By", "content": "campb303"}, {"type": "Replied-Time", "content": "Tue, 23 Jun 2020 13:28:48 -0400"}, {"type": "Replied-By", "content": "campb303"}, {"type": "Edited-Time", "content": "Tue, 23 Jun 2020 13:27:56 -0400"}, {"type": "Edited-By", "content": "campb303"}, {"type": "QAssigned-To", "content": "campb303"}, {"type": "QAssigned-To-Updated-Time", "content": "Tue, 23 Jun 2020 13:27:00 EDT"}, {"type": "QAssigned-To-Updated-By", "content": "campb303"}, {"type": "Assigned-To", "content": "campb303"}, {"type": "Assigned-To-Updated-Time", "content": "Tue, 23 Jun 2020 13:27:00 EDT"}, {"type": "Assigned-To-Updated-By", "content": "campb303"}, {"type": "QStatus", "content": "Dont Delete"}, {"type": "QStatus-Updated-Time", "content": "Tue, 23 Jun 2020 13:26:55 EDT"}, {"type": "QStatus-Updated-By", "content": "campb303"}, {"type": "Status", "content": "Dont Delete"}, {"type": "Status-Updated-Time", "content": "Tue, 23 Jun 2020 13:26:55 EDT"}, {"type": "Status-Updated-By", "content": "campb303"}, {"type": "Date", "content": "Tue, 23 Jun 2020 13:25:51 -0400"}, {"type": "From", "content": "Justin Campbell "}, {"type": "Message-ID", "content": "<911CE050-3240-4980-91DD-9C3EBB8DBCF8@purdue.edu>"}, {"type": "Subject", "content": "Beepboop"}, {"type": "To", "content": "cesite@ecn.purdue.edu"}, {"type": "Content-Type", "content": "text/plain; charset=\"utf-8\""}, {"type": "X-ECN-Queue-Original-Path", "content": "/home/pier/e/queue/Attachments/inbox/2020-06-23/208-original.txt"}, {"type": "X-ECN-Queue-Original-URL", "content": "https://engineering.purdue.edu/webqueue/Attachments/inbox/2020-06-23/208-original.txt"}], "content": [{"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"}, {"type": "assignment", "datetime": "2020-06-23T13:27:00-0400", "by": "campb303", "to": "campb303"}, {"type": "initial_message", "datetime": "2020-06-23T13:25:51-0400", "from_name": "Justin Campbell", "user_email": "campb303@purdue.edu", "to": [{"name": "", "email": "cesite@ecn.purdue.edu"}], "cc": [], "content": ["Testtest\n"]}, {"type": "status", "datetime": "2020-06-23T13:26:55", "by": "campb303", "content": ["Dont Delete\n"]}, {"type": "edit", "datetime": "2020-06-23T13:27:56", "by": "campb303", "content": ["This be an edit my boy\n"]}, {"type": "reply_to_user", "datetime": "2020-06-23T13:28:18", "by": "campb303", "content": ["This be a reply my son\n", "\n", "Justin\n", "ECN\n"]}, {"type": "reply_from_user", "datetime": "2020-06-23T13:30:45-0400", "from_name": "Justin Campbell", "from_email": "campb303@purdue.edu", "cc": [], "content": ["X-ECN-Queue-Original-Path: /home/pier/e/queue/Attachments/inbox/2020-06-23/212-original.txt\n", "X-ECN-Queue-Original-URL: https://engineering.purdue.edu/webqueue/Attachments/inbox/2020-06-23/212-original.txt\n", "\n", "Huzzah!\n"]}], "isLocked": "ce 100 is locked by knewell using qvi", "userEmail": "campb303@purdue.edu", "userName": "Justin Campbell", "userAlias": "campb303", "assignedTo": "campb303", "subject": "Beepboop", "status": "Dont Delete", "priority": "", "department": "", "building": "", "dateReceived": "2020-06-23T13:25:51-0400"};
diff --git a/src/components/ItemMetadataView/ItemMetadataView.js b/src/components/ItemMetadataView/ItemMetadataView.js
index e0f27bc..05f6357 100644
--- a/src/components/ItemMetadataView/ItemMetadataView.js
+++ b/src/components/ItemMetadataView/ItemMetadataView.js
@@ -1,14 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { makeStyles, Typography } from '@material-ui/core';
+import { makeStyles, Typography, useTheme } from '@material-ui/core';
import { Alert } from '@material-ui/lab';
-import webqueue2Theme from "../../theme";
-import EmailHeader from '../EmailHeader/EmailHeader';
export default function ItemMetadataView({item}){
- const theme = webqueue2Theme(false);
+ const theme = useTheme();
const useStyles = makeStyles({
"verticalSpacing": {
marginTop: theme.spacing(1),
@@ -36,8 +34,6 @@ export default function ItemMetadataView({item}){
{item.subject}
-
-
Status, assignments, priority, refile, archive and delete controls coming soon to a theater near you.
diff --git a/src/components/ItemTableAppBar/ItemTableAppBar.md b/src/components/ItemTableAppBar/ItemTableAppBar.md
index 8434018..947a46e 100644
--- a/src/components/ItemTableAppBar/ItemTableAppBar.md
+++ b/src/components/ItemTableAppBar/ItemTableAppBar.md
@@ -2,11 +2,11 @@ The ItemTableAppBar is the primary toolbar for the [ItemTable](/#/Components/Ite
```jsx
import React, { useState } from "react";
-import webqueue2Theme from "../../theme.js";
+import { useTheme } from '@material-ui/core';
const [darkMode, setDarkMode] = useState(false);
-const theme = webqueue2Theme(darkMode);
+const theme = useTheme();
```
diff --git a/src/components/ItemView/ItemView.js b/src/components/ItemView/ItemView.js
index f86bb39..3113d50 100644
--- a/src/components/ItemView/ItemView.js
+++ b/src/components/ItemView/ItemView.js
@@ -1,23 +1,26 @@
import React from 'react';
import PropTypes from "prop-types";
-import { Paper, makeStyles } from '@material-ui/core';
+import { Paper, makeStyles, useTheme } from '@material-ui/core';
import ItemMetadataView from "../ItemMetadataView/"
import ItemBodyView from "../ItemBodyView";
export default function ItemView({ activeItem }){
- const useStyles = makeStyles((theme) => ({
+ const theme = useTheme();
+ const useStyles = makeStyles({
"paperPadding": {
- padding: theme.spacing(2),
+ paddingTop: theme.spacing(1),
+ paddingLeft: theme.spacing(2),
+ paddingRight: theme.spacing(2),
+ border: "none"
}
- }));
-
+ });
const classes = useStyles();
return(
-
+
);
};
diff --git a/src/components/ItemViewAppBar/ItemViewAppBar.md b/src/components/ItemViewAppBar/ItemViewAppBar.md
index 3eba2e4..738202e 100644
--- a/src/components/ItemViewAppBar/ItemViewAppBar.md
+++ b/src/components/ItemViewAppBar/ItemViewAppBar.md
@@ -3,9 +3,9 @@ The ItemViewAppBar is the primary toolbar for the [ItemView](/#/Components/ItemV
```jsx
import React, { useState } from "react";
import ItemViewAppBar from "./ItemViewAppBar";
-import webqueue2Theme from "../../theme.js";
+import { useTheme } from '@material-ui/core';
-const theme = webqueue2Theme(false);
+const theme = useTheme();
const [sidebarOpen, setSidebarOpen] = useState(false);
diff --git a/src/components/MessageView/MessageView.js b/src/components/MessageView/MessageView.js
new file mode 100644
index 0000000..e902a79
--- /dev/null
+++ b/src/components/MessageView/MessageView.js
@@ -0,0 +1,51 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { Paper, Typography, makeStyles, useTheme } from "@material-ui/core";
+import EmailHeader from "../EmailHeader/";
+
+export default function MessageView({ datetime, from_name, from_email, to, cc, content }){
+
+ const theme = useTheme();
+ const useStyles = makeStyles({
+ "content": {
+ border: "none",
+ padding: `${theme.spacing(1)}px ${theme.spacing(2)}px ${theme.spacing(2)}px ${theme.spacing(2)}px`
+ }
+ });
+ const classes = useStyles();
+
+ return (
+
+
+
+ {content.map((line) => (
+ line === "\n" ?
: {line}
+ ))}
+
+
+ );
+};
+
+MessageView.propTypes = {
+ /** 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,
+ /** The content of the message as an array of line with non-printable characters. */
+ "content": PropTypes.array
+};
+
+MessageView.defaultProps = {
+ "from_name": "Name Unavailable",
+ "datetime": new Date(1970, 1, 1, 0, 0, 0, 0),
+ "from_email": "Email Unavailable",
+ "to": [],
+ "cc": [],
+ "content": []
+};
\ No newline at end of file
diff --git a/src/components/MessageView/MessageView.md b/src/components/MessageView/MessageView.md
new file mode 100644
index 0000000..ab2b2b4
--- /dev/null
+++ b/src/components/MessageView/MessageView.md
@@ -0,0 +1,53 @@
+The MessageView displays an [EmailHeader](/#/Components/EmailHeader) and the content of a message.
+
+---
+
+```jsx
+import MessageView from "./MessageView";
+
+
+
+
+```
+```jsx static
+
+```
+
+```jsx
+import MessageView from "./MessageView";
+
+demo_data = {
+ "datetime": "2020-04-15T15:45:45+0000",
+ "from_name": "Ricksy, Jennifer R",
+ "from_email": "jricksy@purdue.edu",
+ "to": [
+ {
+ "name": "csite@ecn.purdue.edu",
+ "email": "csite@ecn.purdue.edu"
+ }
+ ],
+ "cc": [
+
+ ],
+ "content": [
+ "I still can't get this to work. And now the \"trial\" version that I was\n",
+ "using has expired so I can't do anything with a pdf.\n",
+ "\n",
+ "Jenny\n",
+ "\n",
+ "Jenny Ricksy\n",
+ "Burke Graduate Program Administrator\n",
+ "Lyles School of Civil Engineering\n",
+ "Ph: 765-494-2436 Fax: 765-494-0395\n",
+ "HAMP 1141G\n"
+ ]
+};
+
+
+
+
+
+```
+```jsx static
+
+```
\ No newline at end of file
diff --git a/src/components/MessageView/index.js b/src/components/MessageView/index.js
new file mode 100644
index 0000000..7c7e2e9
--- /dev/null
+++ b/src/components/MessageView/index.js
@@ -0,0 +1 @@
+export { default } from "./MessageView";
\ No newline at end of file
diff --git a/src/components/TeamMemberCard/TeamMemberCard.js b/src/components/TeamMemberCard/TeamMemberCard.js
index febfa5e..7a7b4b5 100644
--- a/src/components/TeamMemberCard/TeamMemberCard.js
+++ b/src/components/TeamMemberCard/TeamMemberCard.js
@@ -1,13 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types'
import { Card, CardHeader, Avatar, IconButton, CardContent,
- CardActions, Link, makeStyles } from '@material-ui/core';
+ CardActions, Link, makeStyles, useTheme } from '@material-ui/core';
import WebsiteIcon from '@material-ui/icons/Language';
-import webqueue2Theme from "../../theme";
+
export default function TeamMemberCard({firstName, lastName, imageUrl, websiteUrl, children}){
- const theme = webqueue2Theme();
+ const theme = useTheme();
const useStyles = () => makeStyles({
"avatarImageLarge": {
diff --git a/src/components/TimelineActionCard/TimelineActionCard.js b/src/components/TimelineActionCard/TimelineActionCard.js
new file mode 100644
index 0000000..431cd3e
--- /dev/null
+++ b/src/components/TimelineActionCard/TimelineActionCard.js
@@ -0,0 +1,65 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { Typography, Paper, makeStyles, useTheme } from '@material-ui/core';
+import clsx from "clsx";
+import RelativeTime from "react-relative-time";
+
+export default function TimelineActionCard({ type, datetime, by, content }){
+
+ const theme = useTheme();
+
+ const types = {
+ "edit": {
+ "verbage": "added an edit",
+ "coloring": theme.palette.edit.main
+ },
+ "reply_to_user": {
+ "verbage": "replied",
+ "coloring": theme.palette.reply_to_user.main
+ }
+ }
+
+ const useStyles = makeStyles({
+ "Paper-root": {
+ overflow: "hidden"
+ },
+ "headerColor": {
+ backgroundColor: types[type].coloring
+ },
+ "padding": {
+ padding: theme.spacing(1)
+ }
+
+ });
+ const classes = useStyles();
+
+ return(
+
+
+ {by} {types[type].verbage}
+
+
+ {content.map((line) => (
+ line === "\n" ?
: {line}
+ ))}
+
+
+ );
+}
+
+TimelineActionCard.propTypes = {
+ "type": PropTypes.oneOf([
+ "edit",
+ "reply_to_user"
+ ]),
+ /** ISO 8601 formatted time string. */
+ "datetime": PropTypes.string.isRequired,
+ /** The name of the person who added the edit. */
+ "by": PropTypes.string.isRequired,
+ /** An array of strings containing the content of the edit. */
+ "content": PropTypes.array.isRequired
+};
+
+TimelineActionCard.defaultProps = {
+ "type": "edit",
+};
\ No newline at end of file
diff --git a/src/components/TimelineActionCard/TimelineActionCard.md b/src/components/TimelineActionCard/TimelineActionCard.md
new file mode 100644
index 0000000..7c8a8ee
--- /dev/null
+++ b/src/components/TimelineActionCard/TimelineActionCard.md
@@ -0,0 +1,60 @@
+Renders a card like view for an action with free form text content like an Edit or Reply.
+
+```jsx
+import { ThemeProvider } from "@material-ui/core/styles";
+import webqueue2Theme from "../../theme";
+import TimelineActionCard from "./TimelineActionCard";
+
+const theme = webqueue2Theme(false);
+
+
+
+
+```
+
+```jsx static
+
+
+
+```
\ No newline at end of file
diff --git a/src/components/TimelineActionCard/index.js b/src/components/TimelineActionCard/index.js
new file mode 100644
index 0000000..48454f2
--- /dev/null
+++ b/src/components/TimelineActionCard/index.js
@@ -0,0 +1 @@
+export { default } from "./TimelineActionCard";
\ No newline at end of file
diff --git a/src/components/UserAvatar/UserAvatar.js b/src/components/UserAvatar/UserAvatar.js
index 9a56370..652ce37 100644
--- a/src/components/UserAvatar/UserAvatar.js
+++ b/src/components/UserAvatar/UserAvatar.js
@@ -2,20 +2,19 @@ import React from "react";
import PropTypes from "prop-types";
import { Avatar } from "@material-ui/core";
-export default function UserAvatar({userName, userAlias}){
-
+export default function UserAvatar({ name, ...avatarProps }){
return(
-
- {userName === "" ? null : userName.charAt(0)}
+
+ {name === "" ? null : name.charAt(0)}
);
};
UserAvatar.propTypes = {
/** The name of the user. */
- "userName": PropTypes.string
+ "name": PropTypes.string
};
UserAvatar.defaultProps = {
- "userName": ""
+ "name": ""
};
\ No newline at end of file
diff --git a/src/components/UserAvatar/UserAvatar.md b/src/components/UserAvatar/UserAvatar.md
index 40c9a48..36669b6 100644
--- a/src/components/UserAvatar/UserAvatar.md
+++ b/src/components/UserAvatar/UserAvatar.md
@@ -1,23 +1,36 @@
-The UserAvatar displays a graphical representation of a person and is meant to be used in conjunction with other identifiers like names or emails.
+The UserAvatar displays a graphical representation of a person.
---
-The UserAvatar will the first letter of the `userName` prop.
+## Default Usage
+Used without any props, the UserAvatar will display a generic person icon.
```jsx
import UserAvatar from "./UserAvatar";
-
-```
+
+```
```jsx static
-
+
```
-If no value, a null value, or an empty string is passed to the UserAvatar, it will fall back to a generic icon.
+## With A Name
+If the `name` prop is passed, the UserAvatar will display the first letter of the name.
```jsx
import UserAvatar from "./UserAvatar";
-
+
+
```
+```jsx static
+
+```
+
+## Other Props
+All props other than `name` are passed to the underlying [MUI Avatar component](https://material-ui.com/api/avatar/).
+```jsx
+import UserAvatar from "./UserAvatar";
+
+```
```jsx static
-
+
```
\ No newline at end of file
diff --git a/src/theme.js b/src/theme.js
index bb9281a..685626a 100644
--- a/src/theme.js
+++ b/src/theme.js
@@ -20,9 +20,14 @@ export default function theme(darkMode = false) {
},
"type": darkMode ? "dark" : "light",
-
"edit": {
- main: "#ffe56433",
+ main: "rgba(255, 229, 100, 0.2)",
+ },
+ "reply_to_user": {
+ main: "rgba(99, 125, 255, 0.2)",
+ },
+ "reply_from_user": {
+ main: "rgba(99, 255, 151, 0.2)",
}
},
})