Skip to content

Commit

Permalink
88 table view (#104)
Browse files Browse the repository at this point in the history
* Create DeliveryTable component; Add to DeliveryNeeded

Includes changes to the grid system so that the table and explainer text can show in the same view.

* Swap out table dep for already-installed Material

Replaces the ts-react-json-table dependency with material-ui, which is already installed and available.

* Provide timestamp data in API response

* Sort by and show epoch timestamp, descending

* Format timestamp for readability

* Add i18 for table column names

Co-authored-by: Sher Minn Chong <me@piratefsh.net>
  • Loading branch information
allthesignals and piratefsh authored Aug 1, 2020
1 parent 884b5f2 commit 05759ac
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 46 deletions.
8 changes: 8 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 @@ -79,6 +79,7 @@
"react-i18next": "11.3.5",
"react-mapbox-gl": "^4.8.6",
"react-scripts": "^3.4.1",
"ts-react-json-table": "^0.1.2",
"twilio": "3.42.1"
},
"devDependencies": {
Expand Down
5 changes: 4 additions & 1 deletion src/api/delivery-needed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const {
const makeFeature = async (r) => {
let metaJSON = {};
let slackPermalink = {};
let timestamp;

const location = await fetchCoordFromCrossStreets(
`
${r.fields[crossStreetFirst]},
Expand All @@ -42,7 +44,7 @@ const makeFeature = async (r) => {

try {
const channel = metaJSON.slack_channel;
const timestamp = metaJSON.slack_ts;
timestamp = metaJSON.slack_ts;
slackPermalink = await slackapi.chat.getPermalink({
channel,
message_ts: timestamp,
Expand All @@ -69,6 +71,7 @@ const makeFeature = async (r) => {
[forDrivingClusters]: Boolean(r.fields[forDrivingClusters]),
[householdSize]: r.fields[householdSize],
slackPermalink: slackPermalink.ok ? slackPermalink.permalink : "",
timestamp,
slackTs: metaJSON.slack_ts || "",
},
},
Expand Down
6 changes: 5 additions & 1 deletion src/lib/strings/locales/en/webapp.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
"crossStreetSecond": "Cross Street #2",
"neighborhoodLabel": "Neighborhood",
"neighborhoodError": "If both this and zone are unavailable, double check the map: https://bit.ly/2UrZPkA",
"zone": "{{neighborhood}} Volunteer Zone"
"zone": "{{neighborhood}} Volunteer Zone",
"firstName": "First Name",
"slackLink": "Slack Link",
"timestamp": "Timestamp",
"code": "Code"
},
"geoError": {
"message": "Error loading. Please try again. If it fails again, let us know in"
Expand Down
10 changes: 9 additions & 1 deletion src/webapp/DEVELOPING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@ Running the React app locally is easy since we use Create React App

`npm run local:react`

You can see the app at `localhost:3000`. Some pages will likely require the API. See `/src/api/DEVELOPING.md` for how to spin that up locally!
You can see the app at `localhost:3000`. Some pages will likely require the API. See `/src/api/DEVELOPING.md` for how to spin that up locally!

## Dependencies

It's easy to run the app, but some features require additional configuration.

## Environment

Starting the app requires a few environment variables. Folks can reach out for access to those variables in #wg_tech.
85 changes: 85 additions & 0 deletions src/webapp/components/DeliveryTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from "react";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import { makeStyles } from "@material-ui/core/styles";
import { useTranslation } from "react-i18next";

const useStyles = makeStyles({
container: {
maxHeight: 440,
},
});

const DeliveryTable = ({ rows }) => {
const { t: str } = useTranslation();
const classes = useStyles();

// sort happens in-place
rows.sort((rowA, rowB) => rowB.timestamp - rowA.timestamp);

// format data for presentation
const formattedRows = rows.map((row) => {
const timestamp = new Date(row.timestamp * 1000);

return {
...row,
timestamp: `${timestamp.toLocaleDateString()}: ${timestamp.toLocaleTimeString()}`,
};
});

return (
<TableContainer className={classes.container} component={Paper}>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>{str("webapp:zoneFinder.label.code")}</TableCell>
<TableCell align="right">
{str("webapp:zoneFinder.label.crossStreetFirst")}
</TableCell>
<TableCell align="right">
{str("webapp:zoneFinder.label.crossStreetSecond")}
</TableCell>
<TableCell align="right">
{str("webapp:zoneFinder.label.firstName")}
</TableCell>
<TableCell align="right">
{str("webapp:zoneFinder.label.slackLink")}
</TableCell>
<TableCell align="right">
{str("webapp:zoneFinder.label.timestamp")}
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{formattedRows.map((row) => (
<TableRow key={row.Code}>
<TableCell component="th" scope="row">
{row.Code}
</TableCell>
<TableCell align="right">{row["Cross Street #1"]}</TableCell>
<TableCell align="right">{row["Cross Street #2"]}</TableCell>
<TableCell align="right">{row["First Name"]}</TableCell>
<TableCell align="right">
<a
href={row.slackPermalink}
target="_blank"
rel="noopener noreferrer"
>
Slack
</a>
</TableCell>
<TableCell align="right">{row.timestamp}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
};

export default DeliveryTable;
100 changes: 57 additions & 43 deletions src/webapp/pages/DeliveryNeeded.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import ListItem from "@material-ui/core/ListItem";
import { useTranslation } from "react-i18next";
import sharedStylesFn from "webapp/style/sharedStyles";
import ClusterMap from "webapp/components/ClusterMap";
import Grid from "@material-ui/core/Grid";
import DeliveryTable from "../components/DeliveryTable";

const useStyles = makeStyles((theme) => ({
...sharedStylesFn(theme),
Expand Down Expand Up @@ -39,6 +41,7 @@ export default function DeliveryNeeded() {
if (error) {
return <Box>{`${error}`}</Box>;
}

return (
<Box className={classes.root}>
<Box className={classes.heading}>
Expand All @@ -55,49 +58,60 @@ export default function DeliveryNeeded() {
geoJsonData={data}
/>
</Box>
<Box className={classes.description}>
<Typography variant="body1">
{str("webapp:deliveryNeeded.mapDesc", {
defaultValue:
'Above is a map of all open requests marked "Delivery Needed"',
})}
</Typography>
<List>
<ListItem>
{str("webapp:deliveryNeeded.description.dot", {
defaultValue: `Each dot represents a location with one or more requests. This
location is only representative of the cross street data. We do not
store full addresses.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.clickDot", {
defaultValue: `Click on each cluster (large circle with a number) to zoom into
individual request.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.popUp", {
defaultValue: `Click on a dot to pop up details. There is a link to the Slack post
for more details, where you can also claim the delivery.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.multipleRequests", {
defaultValue: `Some dots may represent multiple requests at the same cross-streets.
Clicking on them will display all of the requests.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.questions", {
defaultValue: `Questions or concerns? Please let us know in`,
})}
<a href={str("webapp:slack.techChannelUrl")}>
{str("webapp:slack.techChannel")}
</a>
</ListItem>
</List>
</Box>
<Grid container spacing={3}>
<Grid item xs={6}>
<Box className={classes.description}>
<Typography variant="body1">
{str("webapp:deliveryNeeded.mapDesc", {
defaultValue:
'Above is a map of all open requests marked "Delivery Needed"',
})}
</Typography>
<List>
<ListItem>
{str("webapp:deliveryNeeded.description.dot", {
defaultValue: `Each dot represents a location with one or more requests. This
location is only representative of the cross street data. We do not
store full addresses.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.clickDot", {
defaultValue: `Click on each cluster (large circle with a number) to zoom into
individual request.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.popUp", {
defaultValue: `Click on a dot to pop up details. There is a link to the Slack post
for more details, where you can also claim the delivery.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.multipleRequests", {
defaultValue: `Some dots may represent multiple requests at the same cross-streets.
Clicking on them will display all of the requests.`,
})}
</ListItem>
<ListItem>
{str("webapp:deliveryNeeded.description.questions", {
defaultValue: `Questions or concerns? Please let us know in`,
})}
<a href={str("webapp:slack.techChannelUrl")}>
{str("webapp:slack.techChannel")}
</a>
</ListItem>
</List>
</Box>
</Grid>
<Grid item xs={6}>
<Box>
<DeliveryTable
rows={data.requests.features.map((f) => f.properties.meta)}
/>
</Box>
</Grid>
</Grid>
</Box>
);
}

0 comments on commit 05759ac

Please sign in to comment.