diff --git a/hackathon_site/dashboard/frontend/src/App.tsx b/hackathon_site/dashboard/frontend/src/App.tsx index bee989b..ec4aec5 100644 --- a/hackathon_site/dashboard/frontend/src/App.tsx +++ b/hackathon_site/dashboard/frontend/src/App.tsx @@ -19,6 +19,8 @@ import Orders from "pages/Orders/Orders"; import Teams from "pages/Teams/Teams"; import Reports from "pages/Reports/Reports"; import Inventory from "pages/Inventory/Inventory"; +import Threedprinting from "pages/Threedprinting/Threedprinting"; +// import ThreeDPrinting from "pages/ThreeDPrinting/ThreeDPrinting" import Cart from "pages/Cart/Cart"; import IncidentForm from "pages/IncidentForm/IncidentForm"; import NotFound from "pages/NotFound/NotFound"; @@ -84,6 +86,11 @@ const UnconnectedApp = () => { path="/inventory" component={withUserCheck("both", Inventory)} /> + { )} + {isParticipantOrAdmin && ( + + + + )} {isParticipant && ( + ); + return ( + <> +
+ + Qty + + +
+ {isOutsideSignOutPeriod ? ( + + {addToCartButton} + + ) : ( + addToCartButton + )} +
+
+ + ); +}; + +interface EnhancedAddToCartFormProps { + quantityRemaining: number; + credits: number; + hardwareId: number; + name: string; + maxPerTeam: number | null; +} +export const EnhancedAddToCartForm = ({ + quantityRemaining, + credits, + hardwareId, + name, + maxPerTeam, +}: EnhancedAddToCartFormProps) => { + const dispatch = useDispatch(); + const currentQuantityInCart = + useSelector((state: RootState) => cartSelectors.selectById(state, hardwareId)) + ?.quantity ?? 0; + + const onSubmit = (formikValues: { quantity: string }) => { + const numQuantity: number = parseInt(formikValues.quantity); + if (currentQuantityInCart + numQuantity <= (maxPerTeam ?? quantityRemaining)) { + dispatch( + addToCart({ + hardware_id: hardwareId, + quantity: numQuantity, + credits: credits, + }) + ); + dispatch( + displaySnackbar({ + message: `Added ${numQuantity} ${name} item(s) to your cart.`, + options: { + variant: "success", + }, + }) + ); + } else { + dispatch( + displaySnackbar({ + message: `Adding this amount to your cart will exceed the quantity limit for this item.`, + options: { + variant: "warning", + }, + }) + ); + } + }; + + return ( + + {(formikProps) => ( + <> + {currentQuantityInCart > 0 && ( + + You currently have {currentQuantityInCart} of this item in + your cart. + + )} + + + )} + + ); +}; + +interface DetailInfoSectionProps { + manufacturer: string; + modelNumber: string; + datasheet: string; + notes?: string; + constraints: string[]; +} +export const DetailInfoSection = ({ + manufacturer, + modelNumber, + datasheet, + notes, + constraints, +}: DetailInfoSectionProps) => { + return ( + <> + {/*{constraints?.length > 0 && (*/} + {/* <>*/} + {/* */} + {/* Constraints*/} + {/* */} + {/* {constraints.map((constraint, i) => (*/} + {/* - {constraint}*/} + {/* ))}*/} + {/* */} + {/*)}*/} + + Manufacturer + + {manufacturer} + {modelNumber && ( + <> + + Model Number + + {modelNumber} + + )} + {datasheet && ( + <> + + Datasheet + + + + )} + {notes && ( + <> + + Notes + + {notes.split("\n").map((note, i) => ( + {note} + ))} + + )} + + ); +}; + +interface MainSectionProps { + name: string; + quantityAvailable: number; + quantityRemaining: number; + categories: string[]; + picture: string; + credits: number; +} +const MainSection = ({ + name, + quantityAvailable, + quantityRemaining, + categories, + picture, + credits, +}: MainSectionProps) => { + const userType = useSelector(userTypeSelector); + const availability = + quantityRemaining === 0 ? ( + OUT OF STOCK + ) : userType === "participant" ? ( + + {Math.max(quantityRemaining, 0)} IN STOCK + + ) : ( + + {Math.max(quantityRemaining, 0)} OF {quantityAvailable} IN STOCK + + ); + + return ( +
+
+ {name} + {availability} + {credits && ( + + Credits: {credits} + + )} + {categories.length > 0 && ( + <> + + Category + +
+ {categories.map((category, i) => ( + + ))} +
+ + )} +
+ {name} +
+ ); +}; + +export const ProductOverview = ({ + showAddToCartButton, +}: { + showAddToCartButton: boolean; +}) => { + let categoryNames: string[] = []; + let maxPerTeam: number | null = null; + let constraints: string[] = []; + + const isLoading = useSelector(is3dUpdateDetailsLoading); + + const dispatch = useDispatch(); + const closeProductOverviewPanel = () => { + dispatch(closeProductOverview()); + dispatch(remove3dProductOverviewItem()); + }; + + const isProductOverviewVisible: boolean = useSelector( + isProductOverviewVisibleSelector + ); + const hardware = useSelector(hardware3dInProductOverviewSelector); + const categories = useSelector((state: RootState) => + selectCategoriesByIds(state, hardware?.categories || []) + ); + + maxPerTeam = hardware?.max_per_team ?? null; + constraints = !!hardware?.max_per_team + ? [`Max ${hardware.max_per_team} of this item`] + : []; + + if (categories.length > 0) { + categoryNames = categories + .filter((category): category is Category => !!category) + .map((category) => category.name); + for (const category of categories) { + if (category?.max_per_team !== undefined) { + constraints.push( + `Max ${category.max_per_team} of items under category ${category.name}` + ); + maxPerTeam = + maxPerTeam === null + ? category.max_per_team + : Math.min(category.max_per_team, maxPerTeam); + } + } + } + + return ( + + {isLoading ? ( + + ) : hardware ? ( +
+
+ + +
+ + {showAddToCartButton && ( + + )} +
+ ) : ( + + Unable to display hardware. Please refresh the page and try again. + + )} +
+ ); +}; + +export default ProductOverview; diff --git a/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.tsx b/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.tsx index f67103b..b7dccf6 100644 --- a/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.tsx +++ b/hackathon_site/dashboard/frontend/src/components/orders/OrdersFilter/OrderFilter.tsx @@ -1,21 +1,22 @@ -import React from "react"; -import { Formik, Field, FieldProps, FormikValues } from "formik"; -import Typography from "@material-ui/core/Typography"; import Button from "@material-ui/core/Button"; +import Checkbox from "@material-ui/core/Checkbox"; import Chip from "@material-ui/core/Chip"; -import Paper from "@material-ui/core/Paper"; import Divider from "@material-ui/core/Divider"; -import Checkbox from "@material-ui/core/Checkbox"; +import FormControlLabel from "@material-ui/core/FormControlLabel"; +import FormGroup from "@material-ui/core/FormGroup"; +import Paper from "@material-ui/core/Paper"; import Radio from "@material-ui/core/Radio"; import RadioGroup from "@material-ui/core/RadioGroup"; -import FormGroup from "@material-ui/core/FormGroup"; -import FormControlLabel from "@material-ui/core/FormControlLabel"; -import { OrderOrdering, OrderStatus, OrderFilters } from "api/types"; +import Typography from "@material-ui/core/Typography"; +import { OrderFilters, OrderOrdering, OrderStatus } from "api/types"; import styles from "components/sharedStyles/Filter.module.scss"; +import { Field, FieldProps, Formik, FormikValues } from "formik"; import { useDispatch, useSelector } from "react-redux"; import { + adminOrderFiltersSelector, adminOrderNumStatusesSelector, clearFilters, + getOrderStatusCounts, getOrdersWithFilters, setFilters, } from "slices/order/adminOrderSlice"; @@ -165,6 +166,7 @@ const OrderFilter = ({ handleReset, handleSubmit }: FormikValues) => { export const EnhancedOrderFilter = () => { const dispatch = useDispatch(); + const savedFilters = useSelector(adminOrderFiltersSelector); // Filter Bug Fix const handleSubmit = ({ ordering, status }: OrderFilters) => { const limit = 1000; @@ -179,15 +181,19 @@ export const EnhancedOrderFilter = () => { const handleReset = () => { dispatch(clearFilters({ saveSearch: true })); + dispatch(getOrderStatusCounts()); dispatch(getOrdersWithFilters()); }; return ( { + // const initialValues = { + // search: "", + // }; + const savedFilters = useSelector(adminOrderFiltersSelector); const initialValues = { - search: "", - }; + search: savedFilters.search ?? "", + }; // Filter Bux Fix const onSubmit = ({ search }: SearchValues) => { setFilters({ search }); @@ -81,6 +85,7 @@ export const EnhancedOrderSearch = ({ return (