diff --git a/hackathon_site/dashboard/frontend/src/components/orders/OrdersCount/OrdersCount.tsx b/hackathon_site/dashboard/frontend/src/components/orders/OrdersCount/OrdersCount.tsx index 8e9ef5ffd..d84bca565 100644 --- a/hackathon_site/dashboard/frontend/src/components/orders/OrdersCount/OrdersCount.tsx +++ b/hackathon_site/dashboard/frontend/src/components/orders/OrdersCount/OrdersCount.tsx @@ -4,7 +4,7 @@ import RefreshIcon from "@material-ui/icons/Refresh"; import { useDispatch, useSelector } from "react-redux"; import styles from "pages/Orders/Orders.module.scss"; import { - adminOrderTotalSelector, + adminOrderTotalWithFiltersSelector, getOrdersWithFilters, } from "slices/order/adminOrderSlice"; @@ -13,7 +13,7 @@ const OrdersCount = () => { const refreshOrders = () => { dispatch(getOrdersWithFilters()); }; - const orderQuantity = useSelector(adminOrderTotalSelector); + const orderQuantity = useSelector(adminOrderTotalWithFiltersSelector); return (
{orderQuantity} results diff --git a/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.module.scss b/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.module.scss index c6c02965f..7ce80a85c 100644 --- a/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.module.scss +++ b/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.module.scss @@ -6,8 +6,9 @@ } .title { + margin-top: 20px; text-justify: left; - margin-bottom: 10px; + margin-bottom: 5px; font-family: "Roboto"; font-style: normal; font-weight: 500; @@ -22,3 +23,14 @@ .section { margin-bottom: 1rem; } + +.overviewTitle { + padding-bottom: 10px; +} + +.itemContent { + padding-left: 7px; + padding-bottom: 10px; + padding-top: 10px; + color: black; +} diff --git a/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.tsx b/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.tsx index 113d307a8..3191a6785 100644 --- a/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.tsx +++ b/hackathon_site/dashboard/frontend/src/pages/AdminDashboard/AdminDashboard.tsx @@ -1,39 +1,145 @@ -import React from "react"; +import React, { useEffect } from "react"; import Typography from "@material-ui/core/Typography"; import Header from "components/general/Header/Header"; -import { hackathonName } from "constants.js"; import OrderCard from "components/orders/OrderCard/OrderCard"; -import { useDispatch, useSelector } from "react-redux"; import styles from "./AdminDashboard.module.scss"; +import { hackathonName } from "constants.js"; +import { OrderFilters } from "api/types"; +import Box from "@material-ui/core/Box"; import Grid from "@material-ui/core/Grid"; import Button from "@material-ui/core/Button"; +import Paper from "@material-ui/core/Paper"; +import { styled } from "@material-ui/core/styles"; +import MemoryIcon from "@material-ui/icons/Memory"; +import PeopleIcon from "@material-ui/icons/People"; +import AccountBoxIcon from "@material-ui/icons/AccountBox"; +import LocalMallIcon from "@material-ui/icons/LocalMall"; +import BrokenImageIcon from "@material-ui/icons/BrokenImage"; +import { useDispatch, useSelector } from "react-redux"; +import { useHistory } from "react-router-dom"; +import { + teamCountSelector, + getTeamsWithSearchThunk, + totalParticipantCountSelector, +} from "slices/event/teamAdminSlice"; +import { clearFilters } from "slices/hardware/hardwareSlice"; import { adminOrderSelectors, getOrdersWithFilters, setFilters, + adminOrderTotalSelector, + adminCheckedOutOrderTotalSelector, } from "slices/order/adminOrderSlice"; -import { OrderFilters } from "api/types"; -import { useHistory } from "react-router-dom"; + +const Item = styled(Paper)(({ theme }) => ({ + backgroundColor: "#fff", + ...theme.typography.body2, + padding: theme.spacing(1), + textAlign: "center", + color: theme.palette.text.secondary, +})); const AdminDashboard = () => { const dispatch = useDispatch(); const history = useHistory(); const allOrders = useSelector(adminOrderSelectors.selectAll); - const pendingFilter: OrderFilters = { - status: ["Submitted", "Ready for Pickup"], - }; - dispatch(setFilters(pendingFilter)); - dispatch(getOrdersWithFilters()); + const orderQuantity = useSelector(adminOrderTotalSelector); + const count = useSelector(teamCountSelector); + const participants = useSelector(totalParticipantCountSelector); + const checkedOut = useSelector(adminCheckedOutOrderTotalSelector); const numOrdersOnPage = 6; const ordersLength = allOrders.length <= numOrdersOnPage ? allOrders.length : numOrdersOnPage; + // TODO: Create selector for Broken/Lost Item + + useEffect(() => { + const pendingFilter: OrderFilters = { + status: ["Submitted", "Ready for Pickup"], + }; + dispatch(setFilters(pendingFilter)); + dispatch(clearFilters()); + dispatch(getOrdersWithFilters()); + dispatch(getTeamsWithSearchThunk()); + }, [dispatch]); return ( <>
{hackathonName} Admin Dashboard -
- Overview +
+ + {" "} + Overview{" "} + + + + + + + {" "} + + {checkedOut} item's checked out + + + + + + + + {" "} + + {participants} participants + + + + + + + + {" "} + + {count} teams + + + + + + + + {" "} + + {orderQuantity} orders + + + + + + + + {" "} + + 7 broken/lost items + + + + + +
diff --git a/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.test.ts b/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.test.ts index 57f34e32b..e2531ae35 100644 --- a/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.test.ts +++ b/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.test.ts @@ -8,14 +8,17 @@ import { teamAdminSelectors, NUM_TEAM_LIMIT, getTeamNextPage, + teamCountSelector, + totalParticipantCountSelector, } from "slices/event/teamAdminSlice"; import { makeMockApiListResponse, makeStoreWithEntities, waitFor } from "testing/utils"; -import { mockTeam, mockTeams } from "testing/mockData"; +import { mockTeam, mockTeamMultiple, mockTeams, mockValidTeam } from "testing/mockData"; import { get, stripHostnameReturnFilters } from "api/api"; import { displaySnackbar } from "slices/ui/uiSlice"; import thunk, { ThunkDispatch } from "redux-thunk"; import { AnyAction } from "redux"; import configureStore from "redux-mock-store"; +import { teamReducerName, teamSizeSelector } from "./teamSlice"; jest.mock("api/api", () => ({ ...jest.requireActual("api/api"), @@ -57,6 +60,18 @@ describe("Selectors", () => { expect(isLoadingSelector(loadingTrueState)).toEqual(true); expect(isLoadingSelector(loadingFalseState)).toEqual(false); }); + test("totalParticipantCountSelector", () => { + const store = makeStoreWithEntities({ teams: mockTeams }); + const totalTeams = totalParticipantCountSelector(store.getState()); + const totalProfiles = mockTeams.reduce((sum, team) => { + if (team.profiles) { + return sum + team.profiles.length; + } else { + return sum; + } + }, 0); + expect(totalTeams).toEqual(totalProfiles); + }); }); describe("getTeamsWithSearch thunk", () => { @@ -92,6 +107,7 @@ describe("getTeamsWithSearch thunk", () => { limit: NUM_TEAM_LIMIT, }); expect(teamAdminSelectors.selectAll(store.getState())).toEqual(mockTeams); + expect(teamCountSelector(store.getState())).toEqual(mockTeams.length); }); }); diff --git a/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.ts b/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.ts index 05fb3a18b..eac72e19e 100644 --- a/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.ts +++ b/hackathon_site/dashboard/frontend/src/slices/event/teamAdminSlice.ts @@ -171,3 +171,14 @@ export const teamCountSelector = createSelector( [teamAdminSliceSelector], (teamAdminSlice) => teamAdminSlice.count ); + +export const totalParticipantCountSelector = createSelector( + [teamAdminSelectors.selectAll], + (teamsList) => { + let count = 0; + for (let i = 0; i < teamsList.length; i++) { + count += teamsList[i].profiles.length; + } + return count; + } +); diff --git a/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.test.ts b/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.test.ts index f446ac187..c9f78373b 100644 --- a/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.test.ts +++ b/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.test.ts @@ -8,11 +8,13 @@ import { errorSelector, getOrdersWithFilters, adminOrderSelectors, + adminOrderTotalWithFiltersSelector, adminOrderTotalSelector, + adminCheckedOutOrderTotalSelector, } from "slices/order/adminOrderSlice"; import { get } from "api/api"; import { makeMockApiListResponse, makeStoreWithEntities } from "testing/utils"; -import { mockPendingOrders } from "testing/mockData"; +import { mockCheckedOutOrders, mockOrders, mockPendingOrders } from "testing/mockData"; import { waitFor } from "@testing-library/react"; jest.mock("api/api", () => ({ @@ -52,11 +54,30 @@ describe("adminOrderSlice Selectors", () => { expect(errorSelector(errorExistsState)).toEqual("exists"); expect(errorSelector(errorNullState)).toEqual(null); }); - test("adminOrderTotalSelector", () => { + test("adminOrderTotalWithFiltersSelector", () => { const store = makeStoreWithEntities({ allOrders: mockPendingOrders }); - const total = adminOrderTotalSelector(store.getState()); + const total = adminOrderTotalWithFiltersSelector(store.getState()); expect(total).toEqual(mockPendingOrders.length); }); + // todo not working, doesnt select all orders + test("adminOrderTotalSelector", () => { + const store = makeStoreWithEntities({ allOrders: mockOrders }); + const total = adminOrderTotalSelector(store.getState()); + expect(total).toEqual(mockOrders.length); + }); + test("adminCheckedOutOrderTotalSelector", () => { + const store = makeStoreWithEntities({ allOrders: mockCheckedOutOrders }); + const total = adminCheckedOutOrderTotalSelector(store.getState()); + const totalRequestedQuantity = mockCheckedOutOrders.reduce((sum, order) => { + return ( + sum + + order.request.reduce((orderSum, item) => { + return orderSum + item.requested_quantity; + }, 0) + ); + }, 0); + expect(total).toEqual(totalRequestedQuantity); // total number of orders in mockCheckedOutOrders + }); }); describe("getOrdersWithFilters Thunk", () => { it("Updates the store on API success", async () => { diff --git a/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.ts b/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.ts index 82fab7a4c..04a254884 100644 --- a/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.ts +++ b/hackathon_site/dashboard/frontend/src/slices/order/adminOrderSlice.ts @@ -200,9 +200,24 @@ export const adminOrderNumStatusesSelector = createSelector( (adminOrderSlice) => adminOrderSlice.numStatuses ); -export const adminOrderTotalSelector = createSelector( +export const adminOrderTotalWithFiltersSelector = createSelector( [adminOrderSelectors.selectAll], (orderItems) => orderItems.reduce((accum) => accum + 1, 0) ); +//Todo this selector is being affected by filters +export const adminOrderTotalSelector = createSelector(); + +export const adminCheckedOutOrderTotalSelector = createSelector( + [adminOrderSelectors.selectAll], + (ordersList) => { + let count = 0; + for (let i = 0; i < ordersList.length; i++) { + if (ordersList[i].status === "Picked Up") { + count += ordersList[i].items.length; + } + } + return count; + } +); export const { setFilters, clearFilters } = actions;