Skip to content

Staging #79

Merged
merged 30 commits into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e8bd3db
Create UserAvatar component w/ docs
Sep 21, 2020
c37ac25
Update ItemMetadataView to show subject, avatar, name, alias, email a…
Sep 21, 2020
223fcc6
Create EmailHeader component w/ docs
Sep 21, 2020
35d9c74
Update ItemMetadataView to use new EmalHeader component
Sep 21, 2020
e97b164
Update ItemMetadataView docs w/ demoItem
Sep 21, 2020
e4bfc3e
Fix EmailHeader export bug
Sep 21, 2020
2b43ead
Create ItemBodyView component w/ docs
Sep 21, 2020
731f8e3
Update ItemView to user new ItemBodyView component
Sep 21, 2020
0cd2734
Remove testing data for presentation
Sep 21, 2020
c538754
Remove unused components
Sep 22, 2020
9bd5dbc
Pre UI update
Sep 23, 2020
674cf0f
Merge remote-tracking branch 'origin/feature-conversational-ui' into …
Sep 23, 2020
94f63b7
Examples Images of ItemTable Component Overrides
Sep 23, 2020
57fb974
mui-datatables work in progress
Sep 25, 2020
8449bba
Created a new table component to test react-table viability
Oct 2, 2020
a787ed1
react-table implementation test
Oct 5, 2020
7110e63
Updated react-table filters todisplay column head as as placeholder
Oct 5, 2020
243534d
Move react-table implementation to ItemTable-ReactTable
Oct 7, 2020
ce0735c
Implement react-table w/ filters using search fields as column headers
Oct 7, 2020
b95d5ac
Create ItemTableFilter component
Oct 7, 2020
2c3f391
Replace inline ColumnFilter with ItemTableFilter
Oct 7, 2020
3180e56
Implemented useFlexLayout hook to to stop header text from overflowin…
Oct 7, 2020
aed5026
Update ItemTableFilter docs
Oct 7, 2020
2b6450a
Migrate to react-table based ItemTable
Oct 7, 2020
fc22c73
Migrate to react-table based ItemTable
Oct 7, 2020
07e35dd
Implemeted per column sorting for ItemTable-ReactTable
Oct 9, 2020
9d9c395
Resolved merge conflict
Oct 12, 2020
36896ff
Implemeted column sorting for ItemTable
Oct 14, 2020
c9cda61
Added onClick functionality, updated theme colors, removed uneeded de…
Oct 21, 2020
071fe7c
Merge branch 'staging' into enhancement-responsive-itemtable
campb303 Oct 23, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
315 changes: 285 additions & 30 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
"material-table": "^1.63.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1",
"react-table": "^7.5.1"
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1"
},
"scripts": {
"start:frontend": "react-scripts start",
Expand Down
10 changes: 5 additions & 5 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { ThemeProvider } from "@material-ui/core/styles";
import { Box, makeStyles } from "@material-ui/core";
import { Box, makeStyles, Paper } from "@material-ui/core";
import { Route } from "react-router-dom";
import clsx from "clsx";
import webqueueTheme from "./theme";
Expand All @@ -13,7 +13,7 @@ function App() {
const [darkMode, setDarkMode] = useState(false);
const [activeItem, setActiveItem] = useState({});
const [sidebarOpen, setSidebarOpen] = useState(false);
const [items, setItems] = useState([])
const [items, setItems] = useState([]);

useEffect(() => {
fetch("/api/ce")
Expand Down Expand Up @@ -55,15 +55,15 @@ function App() {
},
});
const classes = useStyles();

return (

<ThemeProvider theme={theme}>
<Box display="flex">

<Box className={classes.leftCol}>
<ItemTableAppBar title="webqueue2" setDarkMode={setDarkMode} />
<ItemTable items={items} />
<ItemTable setActiveItem={setActiveItem} setSideBarOpen={setSidebarOpen} />
</Box>

<Box className={clsx(classes.rightCol, sidebarOpen && classes.rightColShift)}>
Expand Down Expand Up @@ -94,7 +94,7 @@ function App() {
/>
}
</Box>
</Box>
</Paper>
</ThemeProvider>
);
}
Expand Down
73 changes: 73 additions & 0 deletions src/components/EmailHeader/EmailHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from "react";
import PropTypes from "prop-types";
import { Card, CardHeader, makeStyles } from "@material-ui/core";
import UserAvatar from "../UserAvatar/";
import webqueue2Theme from "../../theme";

export default function EmailHeader({name, date, email}){

const theme = webqueue2Theme(false);
const useStyles = makeStyles({
"verticalPadding": {
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
},
"removeCardHeaderPadding": {
padding: "0"
}
});
const classes = useStyles();

/**
* Returns the title for the user.
* @param {string} name Name of the user.
* @param {string} email Email address of the user.
* @example
* // Has alias and name
* return "campb303 (Justin Campbell)"
* // Has alias but no name
* return "campb303"
* // Has no alias and no name
* return ""
* @returns {string}
*/
function buildTitle(name, email){
let title = "";
const isNotEmpty = (value) => {
return value === "" || value === null ? false : true;
};
if (isNotEmpty(name)){
title += `${name}`;
};
if (isNotEmpty(email)){
title += ` <${email}>`
}
return title;
};

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>
);
};

EmailHeader.propTypes = {
/** Name of the user. */
"name": PropTypes.string,
/** Date of the message. */
"date": PropTypes.string,
/** Email address of the user. */
"email": PropTypes.string
};

EmailHeader.defaultProps = {
"name": "",
"date": "",
"email": ""
};
9 changes: 9 additions & 0 deletions src/components/EmailHeader/EmailHeader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Description of EmailHeader.

```jsx
import EmailHeader from "./EmailHeader";
<EmailHeader />
```
```jsx static
<EmailHeader />
```
1 change: 1 addition & 0 deletions src/components/EmailHeader/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./EmailHeader";
105 changes: 105 additions & 0 deletions src/components/ItemBodyView/ItemBodyView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
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 { objectIsEmpty } from "../../utilities";

export default function ItemBodyView({ item }) {

const theme = webqueue2Theme(false);
const useStyles = makeStyles((theme) => ({
missingOppositeContent: {
'&:before': {
content: '""',
flex: 0,
padding: '0',
},
},
}));
const classes = useStyles(theme);

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(
<>
<EmailHeader name={section.userName} date={section.datetime} email={section.userEmail} />
{section.content.map((line, index) => <Typography variant="body1">{line}</Typography>)}
</>
);
case "edit":
return(
<>
<Typography variant="subtitle2">
{`${section.by} assigned thisat ${Date(section.datetime)}`}
</Typography>
{section.content.map((line) => <Typography variant="body1">{line}</Typography>)}
</>
);
case "status":
return(
<>
<Typography variant="subtitle2">
{`${section.by} update the status to at ${Date(section.datetime)}`}
</Typography>
{section.content.map((line) => <Typography variant="body1">{line}</Typography>)}
</>
);
case "assign":
return (
<Typography variant="subtitle2">
{`${section.by} assigned this to ${section.to} at ${Date(section.datetime)}`}
</Typography>
);
case "replyToUser":
return(
<>
<Typography variant="subtitle2">
{`${section.by} replied ${Date(section.datetime)}`}
</Typography>
{section.content.map((line) => <Typography variant="body1">{line}</Typography>)}
</>
);
case "replyFromUser":
return(
<>
<EmailHeader name={section.userName} date={section.datetime} email={section.userEmail} />
{section.content.map((line, index) => <Typography variant="body1">{line}</Typography>)}
</>
);
default:
return "No Match Found";
};
};

return (
<Timeline align="left">
{objectIsEmpty(item) ? "" : item.content.map((section, index) => {
return (
<TimelineItem classes={{missingOppositeContent: classes.missingOppositeContent}}>
<TimelineSeparator>
<TimelineDot />
<TimelineConnector />
</TimelineSeparator>
<TimelineContent>
{generateTimelineItem(section)}
</TimelineContent>
</TimelineItem>
);
})}
</Timeline>
);
};

ItemBodyView.propTypes = {
/** The item to diplay. */
"item": PropTypes.object.isRequired
};
23 changes: 23 additions & 0 deletions src/components/ItemBodyView/ItemBodyView.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
The ItemBodyView displays the seven actions possible in an item:

- **Directory information**: present when a user submits a ticket from the Contact Us page
- **Initial Message**: the first message a user sends.
- **Edit:** an internal note to and from ECN staff.
- **Status:** an internal summary of the current/next task for the item.
- **Assignment:** the career account alias for the ECN employee the item is assigned to.
- **Reply To User:** a message sent from an ECN employee to a user.
- **Reply To ECN:** a message sent from the user to ECN that has been merged into an existing 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 <campb303@purdue.edu>"}, {"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 <campb303@purdue.edu>\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"};

<div style={{backgroundColor: "white", padding: "1em"}}>
<ItemBodyView item={demoItem} />
</div>
```

```jsx static
<ItemBodyView item={demoItem} />
```
3 changes: 3 additions & 0 deletions src/components/ItemBodyView/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ItemBodyView from "./ItemBodyView";

export default ItemBodyView;
57 changes: 30 additions & 27 deletions src/components/ItemMetadataView/ItemMetadataView.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types'
import { makeStyles, Grid, Paper } from '@material-ui/core';
import { Alert } from '@material-ui/lab'
import PropTypes from 'prop-types';
import { makeStyles, Typography } 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 useStyles = makeStyles({
"verticalSpacing": {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
},
"removeCardHeaderPadding": {
padding: "0"
}
});
const classes = useStyles();

const LockedAlert = () => {
return (
<Alert severity="warning">
{item.isLocked}
</Alert>
);
}
const useStyles = makeStyles({
"gridContainer": {
paddingTop: ".75em",
}
});

const classes = useStyles();
};

const metadataFields = ["userEmail", "userAlias", "subject", "dateReceived",
"assignedTo", "status", "priority", "department", "building"];

return(
<>
{item.isLocked ? LockedAlert() : ""}
<Grid container spacing={2} classes={{root: classes.gridContainer}}>
{metadataFields.map((field) => {
const title = field.toUpperCase();
const subtitle = item[field] === undefined ? "Unknown" : item[field];
return (
<Grid item xs={12} md={4} xl={6}>
<Paper>
<b>{title}</b>: {subtitle}
</Paper>
</Grid>
);
})}
</Grid>

<Typography variant="h4" classes={{root: classes.verticalSpacing}}>
{item.subject}
</Typography>

<EmailHeader name={item.userName} date={item.dateReceived} email={item.userEmail} />

<Alert severity="info" classes={{root: classes.verticalSpacing}}>
Status, assignments, priority, refile, archive and delete controls coming soon to a theater near you.
</Alert>

</>
);
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/ItemMetadataView/ItemMetadataView.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ The ItemMetadataView displays the metadata for an item as part of the [ItemView]
import Paper from "@material-ui/core";
import ItemMetadataView from "./ItemMetadataView";

<div style={{backgroundColor: "white", padding: "1em", borderRadius: "1rem"}}>
const demoItem = {"queue": "ce", "number": 100, "lastUpdated": "07-23-20 10:11 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 <campb303@purdue.edu>"}, {"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"}], "content": ["Testtest\n", "\n", "*** Status updated by: campb303 at: 6/23/2020 13:26:55 ***\n", "Dont Delete\n", "*** Edited by: campb303 at: 06/23/20 13:27:56 ***\n", "\n", "This be an edit my boy\n", "\n", "\n", "\n", "*** 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", "=== Additional information supplied by user ===\n", "\n", "Subject: Re: Beepboop\n", "From: Justin Campbell <campb303@purdue.edu>\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"], "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": "Tue, 23 Jun 2020 13:25:51 -0400"};

<div style={{backgroundColor: "white", padding: "1em"}}>
<ItemMetadataView item={demoItem} />
</div>
```
Expand Down
Loading