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/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 (
-
+
)}
-
-
-
-
-
-
- {headerGroups.map((headerGroup) => (
-
- {headerGroup.headers.map((column) => (
-
-
- {column.render("Header")}
- {column.canSort &&
- (column.isSorted ? (
- column.isSortedDesc ? (
-
+ 0}
+ type="text"
+ rows={8}
+ 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/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;
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 && (
{
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, {
- 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);
@@ -44,7 +46,6 @@ export const UserGroupReport = () => {
...oldUsersArray,
{ ...i, stats: res },
]);
- setLoading(true);
})
.catch((error) => {
if (error.response.status === 500) {
@@ -53,9 +54,6 @@ export const UserGroupReport = () => {
setFormError(error.response.data.detail[0]["msg"]);
}
})
- .finally(() => {
- setLoading(false);
- })
);
},
[userGroupFormData]
@@ -78,14 +76,18 @@ export const UserGroupReport = () => {
formError={formError}
setFormError={setFormError}
/>
- {(isLoading || loading) && (
- Loading...
+ {isLoading && (
+
+
+ Loading...
+
)}
{data && (
0}
+ loading={userIds.length !== users.length}
/>
)}