From 2488804d26bd309e6782a3463d6d62e6d0613f70 Mon Sep 17 00:00:00 2001
From: Diana Rita Nanyanzi <31903212+d-rita@users.noreply.github.com>
Date: Wed, 11 May 2022 00:53:56 +0300
Subject: [PATCH 1/4] Add loading spinner and placeholder as data loads
---
package-lock.json | 15 +++
package.json | 1 +
src/assets/svgIcons/index.js | 1 +
src/assets/svgIcons/spinner.js | 22 ++++
src/components/userGroup/userGroupResults.js | 131 +++++++++++--------
src/views/MapathonReports.js | 11 +-
src/views/UserGroupReport.js | 6 +-
7 files changed, 129 insertions(+), 58 deletions(-)
create mode 100644 src/assets/svgIcons/spinner.js
diff --git a/package-lock.json b/package-lock.json
index 2965c40..749bb05 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
"react-datepicker": "^4.2.1",
"react-dom": "^17.0.2",
"react-intl": "^5.20.12",
+ "react-placeholder": "^4.1.0",
"react-query": "^3.27.0",
"react-redux": "^7.2.5",
"react-router-dom": "^5.3.0",
@@ -18483,6 +18484,14 @@
"react-dom": "^15.5.x || ^16.x || ^17.x"
}
},
+ "node_modules/react-placeholder": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/react-placeholder/-/react-placeholder-4.1.0.tgz",
+ "integrity": "sha512-z1HGD86NWJTYTQumHsmGH9jkozv4QHa9dju/vHVUd4f1svu23pf5v7QoBLBfs3kA1S9GLJaCeRMHLbO2SCdz5A==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17"
+ }
+ },
"node_modules/react-popper": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz",
@@ -38342,6 +38351,12 @@
"integrity": "sha512-oPlOTYcISLHfpMog2lUZMFSbqOs4LFcA4+vo7fpfevB5v9Z0D5VBDBkfeO5lv+hpEcGoaGk67braLT+QT+eICA==",
"requires": {}
},
+ "react-placeholder": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/react-placeholder/-/react-placeholder-4.1.0.tgz",
+ "integrity": "sha512-z1HGD86NWJTYTQumHsmGH9jkozv4QHa9dju/vHVUd4f1svu23pf5v7QoBLBfs3kA1S9GLJaCeRMHLbO2SCdz5A==",
+ "requires": {}
+ },
"react-popper": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz",
diff --git a/package.json b/package.json
index a37ce23..2c1051a 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"react-datepicker": "^4.2.1",
"react-dom": "^17.0.2",
"react-intl": "^5.20.12",
+ "react-placeholder": "^4.1.0",
"react-query": "^3.27.0",
"react-redux": "^7.2.5",
"react-router-dom": "^5.3.0",
diff --git a/src/assets/svgIcons/index.js b/src/assets/svgIcons/index.js
index 4af57cd..965f1b0 100644
--- a/src/assets/svgIcons/index.js
+++ b/src/assets/svgIcons/index.js
@@ -1,2 +1,3 @@
export { BanIcon } from "./ban";
export { SortIcon, SortDownIcon, SortUpIcon } from "./sortIcons";
+export { SpinnerIcon } from "./spinner";
diff --git a/src/assets/svgIcons/spinner.js b/src/assets/svgIcons/spinner.js
new file mode 100644
index 0000000..c09c0d6
--- /dev/null
+++ b/src/assets/svgIcons/spinner.js
@@ -0,0 +1,22 @@
+import React from "react";
+
+// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/
+// License: CC-By 4.0
+export class SpinnerIcon extends React.PureComponent {
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/src/components/userGroup/userGroupResults.js b/src/components/userGroup/userGroupResults.js
index 33d3e31..fb31bbb 100644
--- a/src/components/userGroup/userGroupResults.js
+++ b/src/components/userGroup/userGroupResults.js
@@ -2,13 +2,25 @@ import React from "react";
import { useSelector } from "react-redux";
import { useTable, useSortBy } from "react-table";
import { FormattedMessage } from "react-intl";
+import ReactPlaceholder from "react-placeholder";
import messages from "./messages";
import { Error } from "../formResponses";
import { UserGroupErrorMessage } from "./userGroupError";
-import { SortDownIcon, SortIcon, SortUpIcon } from "../../assets/svgIcons";
+import {
+ SortDownIcon,
+ SortIcon,
+ SortUpIcon,
+ SpinnerIcon,
+} from "../../assets/svgIcons";
import { DownloadCSVButton } from "../download";
+import "react-placeholder/lib/reactPlaceholder.css";
-export function UserGroupResultsTable({ columns, data, userDataCheck }) {
+export function UserGroupResultsTable({
+ columns,
+ data,
+ userDataCheck,
+ loading,
+}) {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable(
{
@@ -28,63 +40,72 @@ export function UserGroupResultsTable({ columns, data, userDataCheck }) {
)}
-
-
-
-
-
-
- {headerGroups.map((headerGroup) => (
-
- {headerGroup.headers.map((column) => (
-
-
- {column.render("Header")}
- {column.canSort &&
- (column.isSorted ? (
- column.isSortedDesc ? (
-
+ 0}
+ type="text"
+ rows={5}
+ className="mt-20 mx-4"
+ >
+
+
+
+
+
+
+ {headerGroups.map((headerGroup) => (
+
+ {headerGroup.headers.map((column) => (
+
+
+ {column.render("Header")}
+ {column.canSort &&
+ (column.isSorted ? (
+ column.isSortedDesc ? (
+
+ ) : (
+
+ )
) : (
-
- )
- ) : (
-
- ))}
-
- |
- ))}
-
- ))}
-
-
- {rows.map((row, i) => {
- prepareRow(row);
- return (
-
- {row.cells.map((cell) => {
- return (
-
- {cell.render("Cell")}
- |
- );
- })}
+
+ ))}
+
+
+ ))}
- );
- })}
-
-
+ ))}
+ |
+
+ {rows.map((row, i) => {
+ prepareRow(row);
+ return (
+
+ {row.cells.map((cell) => {
+ return (
+
+ {cell.render("Cell")}
+ |
+ );
+ })}
+
+ );
+ })}
+
+
+ {/* {loading ? (
) : (
End of Table
)} */}
+
-
+
>
);
diff --git a/src/views/MapathonReports.js b/src/views/MapathonReports.js
index 57d3fa2..1f20e10 100644
--- a/src/views/MapathonReports.js
+++ b/src/views/MapathonReports.js
@@ -15,6 +15,7 @@ import { setTriggerSubmit } from "../features/form/formSlice";
import { MiniNavBar } from "../components/nav/navbar";
import { aggregateMapathonUserData } from "../utils/mapathonDataUtils";
import { MapathonDetailedTableHeaders } from "../components/mapathon/constants";
+import { SpinnerIcon } from "../assets/svgIcons";
const MAPATHON_PAGES = [
{ pageTitle: "Mapathon Summary Report", pageURL: "/mapathon-report/summary" },
@@ -51,7 +52,10 @@ export const MapathonSummaryReport = (props) => {
{isLoading && (
- Loading...
+
+
+ Loading...
+
)}
{data && }
@@ -80,7 +84,10 @@ export const MapathonDetailedReport = () => {
loading={isLoading || triggeredLoading}
/>
{(isLoading || triggeredLoading) && (
- Loading...
+
+
+ Loading...
+
)}
{data && (
{
setFormError={setFormError}
/>
{(isLoading || loading) && (
- Loading...
+
+
+ Loading...
+
)}
{data && (
Date: Thu, 12 May 2022 00:24:11 +0300
Subject: [PATCH 2/4] Add row loading spinner + center user group table results
---
src/components/download.js | 4 +++-
src/components/userGroup/userGroupResults.js | 22 ++++++++++++++------
src/views/UserGroupReport.js | 8 ++-----
3 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/src/components/download.js b/src/components/download.js
index 1aa0b45..09044fd 100644
--- a/src/components/download.js
+++ b/src/components/download.js
@@ -105,7 +105,9 @@ export const DownloadCSVButton = ({ data, source }) => {
)}`;
return (
-
+
0}
type="text"
- rows={5}
+ rows={8}
className="mt-20 mx-4"
>
-
+
+
+
-
+
{headerGroups.map((headerGroup) => (
{headerGroup.headers.map((column) => (
{
return (
|
{cell.render("Cell")}
@@ -102,7 +104,15 @@ export function UserGroupResultsTable({
})}
|
- {/* {loading ? (
) : (End of Table
)} */}
+ {loading ? (
+
+
+
+ ) : (
+
+ End of Table
+
+ )}
diff --git a/src/views/UserGroupReport.js b/src/views/UserGroupReport.js
index 21b799a..762fb5e 100644
--- a/src/views/UserGroupReport.js
+++ b/src/views/UserGroupReport.js
@@ -19,7 +19,6 @@ export const UserGroupReport = () => {
const { userGroupFormData, setUserGroupFormData } = useContext(FormContext);
const [formError, setFormError] = useState(null);
const [userIds, setUserIds] = useState([]);
- const [loading, setLoading] = useState(false);
const [users, setUsers] = useState();
const { mutate, data, isLoading } = useMutation(getUserIds, {
@@ -45,7 +44,6 @@ export const UserGroupReport = () => {
...oldUsersArray,
{ ...i, stats: res },
]);
- setLoading(true);
})
.catch((error) => {
if (error.response.status === 500) {
@@ -54,9 +52,6 @@ export const UserGroupReport = () => {
setFormError(error.response.data.detail[0]["msg"]);
}
})
- .finally(() => {
- setLoading(false);
- })
);
},
[userGroupFormData]
@@ -79,7 +74,7 @@ export const UserGroupReport = () => {
formError={formError}
setFormError={setFormError}
/>
- {(isLoading || loading) && (
+ {isLoading && (
Loading...
@@ -90,6 +85,7 @@ export const UserGroupReport = () => {
columns={UserGroupColumnHeadings}
data={aggregateUserGroupData(users)}
userDataCheck={userIds && userIds.length > 0}
+ loading={userIds.length !== users.length}
/>
)}
From 22890ea926901e01d73fec4bd327cfd044c6c934 Mon Sep 17 00:00:00 2001
From: Diana Rita Nanyanzi <31903212+d-rita@users.noreply.github.com>
Date: Tue, 17 May 2022 09:55:36 +0300
Subject: [PATCH 3/4] Modify error capturing logic in user report
---
src/views/UserGroupReport.js | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/views/UserGroupReport.js b/src/views/UserGroupReport.js
index 762fb5e..b6f8360 100644
--- a/src/views/UserGroupReport.js
+++ b/src/views/UserGroupReport.js
@@ -21,15 +21,17 @@ export const UserGroupReport = () => {
const [userIds, setUserIds] = useState([]);
const [users, setUsers] = useState();
- const { mutate, data, isLoading } = useMutation(getUserIds, {
- onError: (error) => {
+ const { mutate, data, isLoading, error } = useMutation(getUserIds);
+
+ useEffect(() => {
+ if (error) {
if (error.response.status === 500) {
setFormError(error.response.data);
} else {
setFormError(error.response.data.detail[0]["msg"]);
}
- },
- });
+ }
+ }, [error]);
useEffect(() => {
if (data) setUserIds(data);
From f51142bb4ec0fc6dece548262ab647020a23b83d Mon Sep 17 00:00:00 2001
From: Diana Rita Nanyanzi <31903212+d-rita@users.noreply.github.com>
Date: Tue, 17 May 2022 10:32:43 +0300
Subject: [PATCH 4/4] Modify user group stats logic:
- Due to the API endpoint upgrade, user stats can be retrieved directly
- Remove redundant userGroup feature-count-and-filter util function
- Map relevant stats directly to keys in data aggregation function
---
src/utils/userGroupUtils.js | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/src/utils/userGroupUtils.js b/src/utils/userGroupUtils.js
index d7bcc2f..eb982dc 100644
--- a/src/utils/userGroupUtils.js
+++ b/src/utils/userGroupUtils.js
@@ -1,19 +1,12 @@
-export const featureActionCount = (array, feature, action) => {
- let x = array.filter(
- (i) => i["feature"] === feature && i["action"] === action
- );
- return x[0] ? x[0]["count"] : 0;
-};
-
export const aggregateUserGroupData = (obj) => {
const arr = [];
obj.forEach((i) => {
arr.push({
...i,
- createdBuildings: featureActionCount(i["stats"], "building", "create"),
- modifiedBuildings: featureActionCount(i["stats"], "building", "modify"),
- createdHighways: featureActionCount(i["stats"], "highway", "create"),
- modifiedHighways: featureActionCount(i["stats"], "highway", "modify"),
+ createdBuildings: i["stats"][0]["addedBuildings"],
+ modifiedBuildings: i["stats"][0]["modifiedBuildings"],
+ createdHighways: i["stats"][0]["addedHighway"],
+ modifiedHighways: i["stats"][0]["modifiedHighway"],
});
});
return arr;