Skip to content

Commit

Permalink
IEEE-259 Add title and project description to admin page
Browse files Browse the repository at this point in the history
  • Loading branch information
Karandeep Lubana committed Jan 28, 2024
1 parent aa3b498 commit 69e0f65
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { maxTeamSize, minTeamSize } from "constants.js";
import AlertBox from "components/general/AlertBox/AlertBox";
import { Link } from "@material-ui/core";
import DateRestrictionAlert from "components/general/DateRestrictionAlert/DateRestrictionAlert";
import ProjectDescriptionAlert from "components/teamDetail/ProjectDescription/ProjectDescriptionAlert";

const CartErrorBox = () => {
const cartQuantity = useSelector(cartTotalSelector);
Expand All @@ -22,6 +23,7 @@ const CartErrorBox = () => {
<Grid xs={12} sm={12} md={2} item />
<Grid xs={12} sm={12} md={8} item>
<DateRestrictionAlert />
<ProjectDescriptionAlert />
{orderSubmissionError && cartQuantity > 0 && (
<AlertBox
error={orderSubmissionError}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
import CircularProgress from "@material-ui/core/CircularProgress";
import { teamSizeSelector } from "slices/event/teamSlice";
import { isTestUserSelector } from "slices/users/userSlice";
import { projectDescriptionSelector } from "slices/event/teamDetailSlice";
import { displaySnackbar } from "slices/ui/uiSlice";
import {
hardwareSignOutEndDate,
hardwareSignOutStartDate,
Expand All @@ -25,18 +27,35 @@ const CartSummary = () => {
const cartQuantity = useSelector(cartTotalSelector);
const cartOrderLoading = useSelector(isLoadingSelector);
const teamSize = useSelector(teamSizeSelector);
const projectDescription = useSelector(projectDescriptionSelector);
const teamSizeValid = teamSize >= minTeamSize && teamSize <= maxTeamSize;
const dispatch = useDispatch();
const onSubmit = () => {
if (cartQuantity > 0) {
dispatch(submitOrder());
if (
projectDescription &&
projectDescription.length < MIN_DESCRIPTION_LENGTH
) {
dispatch(
displaySnackbar({
message: "Please provide a more detailed project description.",
options: {
variant: "error",
},
})
);
} else {
dispatch(submitOrder());
}
}
};
const currentDateTime = new Date();
const isOutsideSignOutPeriod =
currentDateTime < hardwareSignOutStartDate ||
currentDateTime > hardwareSignOutEndDate;

const MIN_DESCRIPTION_LENGTH = 50;

return (
<TitledPaper title="Cart Summary">
<Container className={styles.qty}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.formTextField {
margin: 20px 5px 0 0;
margin: 10px 5px 0 0;
}

.actionBtn {
Expand All @@ -10,3 +10,11 @@
width: 120px;
margin-right: 10px;
}

.projectDescriptionDetail {
padding: 10px;
}

.title {
margin-top: 30px;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import styles from "./ProjectDescription.module.scss";
import { Formik, Form, Field, FormikValues } from "formik";
import * as Yup from "yup";
import { TextField, Button, Box, Grid } from "@material-ui/core";
import { useDispatch } from "react-redux";
import { updateProjectDescription } from "slices/event/teamDetailSlice";
import { TextField, Button, Box, Grid, Typography } from "@material-ui/core";
import { useDispatch, useSelector } from "react-redux";
import {
updateProjectDescription,
fetchInitialProjectDescription,
projectDescriptionSelector,
isTeamInfoLoadingSelector,
isProjectDescriptionLoadingSelector,
} from "slices/event/teamDetailSlice";
import CircularProgress from "@material-ui/core/CircularProgress";

interface ProjectDescriptionProps {
teamCode: string;
}

const ProjectDescription = ({ teamCode }: ProjectDescriptionProps) => {
const dispatch = useDispatch();
const initialProjectDescription = "Write your project description here";
const isTeamInfoLoading: boolean = useSelector(isTeamInfoLoadingSelector);
const isProjectDescriptionLoading: boolean = useSelector(
isProjectDescriptionLoadingSelector
);
const initialProjectDescription =
useSelector(projectDescriptionSelector) ||
"Write your project description here";
const [isEditing, setIsEditing] = useState(false);
const projectDescriptionSchema = Yup.object().shape({
projectDescription: Yup.string()
Expand All @@ -30,64 +43,82 @@ const ProjectDescription = ({ teamCode }: ProjectDescriptionProps) => {
setSubmitting(false);
};

useEffect(() => {
if (teamCode != "None") {
dispatch(fetchInitialProjectDescription(teamCode));
}
}, [dispatch, teamCode]);

return (
<div>
<Formik
initialValues={{ projectDescription: initialProjectDescription }}
validationSchema={projectDescriptionSchema}
onSubmit={handleSubmit}
>
{({ isSubmitting, isValid }) => (
<Form>
<Field
as={TextField}
name="projectDescription"
multiline
fullWidth
variant="outlined"
disabled={!isEditing}
rows={4}
className={styles.formTextField}
/>
<Box mt={2}>
<Grid container justifyContent="flex-end">
{isEditing ? (
<>
<Button
type="submit"
variant="contained"
disabled={!isValid || isSubmitting}
className={styles.submitBtn}
>
SUBMIT
</Button>
<Button
type="button"
variant="contained"
color="secondary"
className={styles.actionBtn}
onClick={() => setIsEditing(false)}
>
CANCEL
</Button>
</>
) : (
<Button
type="button"
variant="contained"
color="primary"
className={styles.actionBtn}
onClick={() => setIsEditing(true)}
>
EDIT
</Button>
)}
</Grid>
</Box>
</Form>
)}
</Formik>
</div>
<>
{isProjectDescriptionLoading ? (
""
) : (
<div className={styles.title}>
<Typography variant="h2" gutterBottom>
Project Description
</Typography>
<Formik
initialValues={{
projectDescription: initialProjectDescription,
}}
validationSchema={projectDescriptionSchema}
onSubmit={handleSubmit}
>
{({ isSubmitting, isValid }) => (
<Form>
<Field
as={TextField}
name="projectDescription"
multiline
fullWidth
variant="outlined"
disabled={!isEditing}
rows={4}
className={styles.formTextField}
/>
<Box mt={2}>
<Grid container justifyContent="flex-end">
{isEditing ? (
<>
<Button
type="submit"
variant="contained"
disabled={!isValid || isSubmitting}
className={styles.submitBtn}
onClick={() => setIsEditing(false)}
>
SUBMIT
</Button>
<Button
type="button"
variant="contained"
color="secondary"
className={styles.actionBtn}
onClick={() => setIsEditing(false)}
>
CANCEL
</Button>
</>
) : (
<Button
type="button"
variant="contained"
color="primary"
className={styles.actionBtn}
onClick={() => setIsEditing(true)}
>
EDIT
</Button>
)}
</Grid>
</Box>
</Form>
)}
</Formik>
</div>
)}
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import AlertBox from "components/general/AlertBox/AlertBox";
import { projectDescriptionSelector } from "slices/event/teamDetailSlice";
import { useSelector } from "react-redux";
import { minProjectDescriptionLength } from "constants.js";

const ProjectDescriptionAlert = () => {
const projectDescription = useSelector(projectDescriptionSelector);

if (projectDescription && projectDescription.length < minProjectDescriptionLength) {
return (
<AlertBox
data-testid="project-description-alert"
title="Project Description Required"
error="Please provide a more detailed project description."
type="error"
/>
);
}

return null;
};

export default ProjectDescriptionAlert;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
fetchInitialProjectDescription,
projectDescriptionSelector,
isTeamInfoLoadingSelector,
teamInfoErrorSelector,
} from "slices/event/teamDetailSlice";
import styles from "./ProjectDescription.module.scss";
import { LinearProgress, Paper, Typography } from "@material-ui/core";
interface ProjectDescriptionProps {
teamCode: string;
}

const ProjectDescriptionDetail = ({ teamCode }: ProjectDescriptionProps) => {
const dispatch = useDispatch();

const projectDescription = useSelector(projectDescriptionSelector);
const isTeamInfoLoading = useSelector(isTeamInfoLoadingSelector);

useEffect(() => {
dispatch(fetchInitialProjectDescription(teamCode));
}, [dispatch, teamCode]);

return (
<div>
{isTeamInfoLoading ? (
<LinearProgress data-testid="team-info-linear-progress" />
) : (
<>
<Typography variant="h2" gutterBottom>
Project Description
</Typography>
<Paper className={styles.projectDescriptionDetail}>
<Typography variant="body1">{projectDescription}</Typography>
</Paper>
</>
)}
</div>
);
};

export default ProjectDescriptionDetail;
3 changes: 2 additions & 1 deletion hackathon_site/dashboard/frontend/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export const adminGroup = "Hardware Site Admins";
export const minTeamSize = 2;
export const maxTeamSize = 4;
export const hardwareSignOutStartDate = new Date(2020, 9, 1, 23, 59);
export const hardwareSignOutEndDate = new Date(2023, 9, 30, 11, 59);
export const hardwareSignOutEndDate = new Date(2025, 9, 30, 11, 59);
export const hssTestUserGroup = "HSS Test Users";
export const minProjectDescriptionLength = 20;
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import TeamCheckedOutOrderTable from "components/teamDetail/TeamCheckedOutOrderT
import { getHardwareWithFilters, setFilters } from "slices/hardware/hardwareSlice";
import { getCategories } from "slices/hardware/categorySlice";
import ProductOverview from "components/inventory/ProductOverview/ProductOverview";
import ProjectDescriptionDetail from "components/teamDetail/ProjectDescription/ProjectDescriptionDetail";

export interface PageParams {
code: string;
Expand Down Expand Up @@ -91,6 +92,7 @@ const TeamDetail = ({ match }: RouteComponentProps<PageParams>) => {
<AlertBox error={orderError} />
) : (
<>
<ProjectDescriptionDetail teamCode={teamCode} />
<SimplePendingOrderFulfillmentTable />
<Divider className={styles.dividerMargin} />
<TeamCheckedOutOrderTable />
Expand Down
Loading

0 comments on commit 69e0f65

Please sign in to comment.