diff --git a/package-lock.json b/package-lock.json index 2380ce68..c53670e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18398,6 +18398,14 @@ "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz", "integrity": "sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ==" }, + "ts-react-json-table": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ts-react-json-table/-/ts-react-json-table-0.1.2.tgz", + "integrity": "sha512-R04BcrlQ8W0526Riq6HvdNRBgZgAMgQFUcpGXymM4PgC+YWW64gfnTKitS8fimOv+rEbxM0mwvaeohwoSfccHg==", + "requires": { + "react": "^16.8.6" + } + }, "tslib": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", diff --git a/package.json b/package.json index a795ff29..5febd5d4 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/src/api/delivery-needed/index.js b/src/api/delivery-needed/index.js index e5c296a0..0895b287 100644 --- a/src/api/delivery-needed/index.js +++ b/src/api/delivery-needed/index.js @@ -17,6 +17,8 @@ const { const makeFeature = async (r) => { let metaJSON = {}; let slackPermalink = {}; + let timestamp; + const location = await fetchCoordFromCrossStreets( ` ${r.fields[crossStreetFirst]}, @@ -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, @@ -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 || "", }, }, diff --git a/src/lib/strings/locales/en/webapp.json b/src/lib/strings/locales/en/webapp.json index 0d3d3100..c030896b 100644 --- a/src/lib/strings/locales/en/webapp.json +++ b/src/lib/strings/locales/en/webapp.json @@ -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" diff --git a/src/webapp/DEVELOPING.md b/src/webapp/DEVELOPING.md index bc33f667..d50d3e07 100644 --- a/src/webapp/DEVELOPING.md +++ b/src/webapp/DEVELOPING.md @@ -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! \ No newline at end of file +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. diff --git a/src/webapp/components/DeliveryTable.js b/src/webapp/components/DeliveryTable.js new file mode 100644 index 00000000..026c78a7 --- /dev/null +++ b/src/webapp/components/DeliveryTable.js @@ -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 ( + + + + + {str("webapp:zoneFinder.label.code")} + + {str("webapp:zoneFinder.label.crossStreetFirst")} + + + {str("webapp:zoneFinder.label.crossStreetSecond")} + + + {str("webapp:zoneFinder.label.firstName")} + + + {str("webapp:zoneFinder.label.slackLink")} + + + {str("webapp:zoneFinder.label.timestamp")} + + + + + {formattedRows.map((row) => ( + + + {row.Code} + + {row["Cross Street #1"]} + {row["Cross Street #2"]} + {row["First Name"]} + + + Slack + + + {row.timestamp} + + ))} + +
+
+ ); +}; + +export default DeliveryTable; diff --git a/src/webapp/pages/DeliveryNeeded.js b/src/webapp/pages/DeliveryNeeded.js index 7921f3df..70e97ca2 100644 --- a/src/webapp/pages/DeliveryNeeded.js +++ b/src/webapp/pages/DeliveryNeeded.js @@ -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), @@ -39,6 +41,7 @@ export default function DeliveryNeeded() { if (error) { return {`${error}`}; } + return ( @@ -55,49 +58,60 @@ export default function DeliveryNeeded() { geoJsonData={data} /> - - - {str("webapp:deliveryNeeded.mapDesc", { - defaultValue: - 'Above is a map of all open requests marked "Delivery Needed"', - })} - - - - {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.`, - })} - - - {str("webapp:deliveryNeeded.description.clickDot", { - defaultValue: `Click on each cluster (large circle with a number) to zoom into - individual request.`, - })} - - - {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.`, - })} - - - {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.`, - })} - - - {str("webapp:deliveryNeeded.description.questions", { - defaultValue: `Questions or concerns? Please let us know in`, - })} - - {str("webapp:slack.techChannel")} - - - - + + + + + {str("webapp:deliveryNeeded.mapDesc", { + defaultValue: + 'Above is a map of all open requests marked "Delivery Needed"', + })} + + + + {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.`, + })} + + + {str("webapp:deliveryNeeded.description.clickDot", { + defaultValue: `Click on each cluster (large circle with a number) to zoom into + individual request.`, + })} + + + {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.`, + })} + + + {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.`, + })} + + + {str("webapp:deliveryNeeded.description.questions", { + defaultValue: `Questions or concerns? Please let us know in`, + })} + + {str("webapp:slack.techChannel")} + + + + + + + + f.properties.meta)} + /> + + + ); }