diff --git a/src/frontend/src/pages/HomePage/LeadHomePage.tsx b/src/frontend/src/pages/HomePage/LeadHomePage.tsx index e927f9adf9..5466cdc285 100644 --- a/src/frontend/src/pages/HomePage/LeadHomePage.tsx +++ b/src/frontend/src/pages/HomePage/LeadHomePage.tsx @@ -11,6 +11,7 @@ import PageLayout, { PAGE_GRID_HEIGHT } from '../../components/PageLayout'; import { AuthenticatedUser } from 'shared'; import ChangeRequestsToReview from './components/ChangeRequestsToReview'; import MyTeamsOverdueTasks from './components/MyTeamsOverdueTasks'; +import UpcomingDesignReviews from './components/UpcomingDesignReviews'; interface LeadHomePageProps { user: AuthenticatedUser; @@ -39,10 +40,13 @@ const LeadHomePage = ({ user }: LeadHomePageProps) => { - + + + + diff --git a/src/frontend/src/pages/HomePage/components/ChangeRequestsToReview.tsx b/src/frontend/src/pages/HomePage/components/ChangeRequestsToReview.tsx index e7161db966..148ed6c822 100644 --- a/src/frontend/src/pages/HomePage/components/ChangeRequestsToReview.tsx +++ b/src/frontend/src/pages/HomePage/components/ChangeRequestsToReview.tsx @@ -19,7 +19,7 @@ const NoChangeRequestsToReview: React.FC = () => { } heading={`You're all caught up!`} - message={'You have no unreviewed changre requests!'} + message={'You have no unreviewed change requests!'} /> ); }; diff --git a/src/frontend/src/pages/HomePage/components/DesignReviewCard.tsx b/src/frontend/src/pages/HomePage/components/DesignReviewCard.tsx new file mode 100644 index 0000000000..7ecf0dac6a --- /dev/null +++ b/src/frontend/src/pages/HomePage/components/DesignReviewCard.tsx @@ -0,0 +1,117 @@ +import { Box, Card, CardContent, Link, Stack, Typography, useTheme } from '@mui/material'; +import { DesignReview, User } from 'shared'; +import { datePipe, projectWbsPipe } from '../../../utils/pipes'; +import { routes } from '../../../utils/routes'; +import { Link as RouterLink } from 'react-router-dom'; +import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; +import { LocationOnOutlined, Computer } from '@mui/icons-material'; +import { useHistory } from 'react-router-dom'; +import { NERButton } from '../../../components/NERButton'; +import { meetingStartTimePipe } from '../../../../../backend/src/utils/design-reviews.utils'; +import { timezoneOffset } from '../../../utils/datetime.utils'; + +interface DesignReviewProps { + designReview: DesignReview; + user: User; +} + +const DesignReviewInfo = ({ icon, text, link }: { icon: React.ReactNode; text: string; link?: boolean }) => { + return ( + + {icon} + {link ? ( + + + {text} + + + ) : ( + + {text} + + )} + + ); +}; + +const DisplayStatus: React.FC = ({ designReview, user }) => { + const history = useHistory(); + const confirmedMemberIds = designReview.confirmedMembers.map((user) => user.userId); + + return ( + <> + {!confirmedMemberIds.includes(user.userId) ? ( + { + history.push(`${routes.SETTINGS_PREFERENCES}?drId=${designReview.designReviewId}`); + }} + component={RouterLink} + > + Confirm Availibility + + ) : ( + {designReview.status} + )} + + ); +}; + +const getWeekday = (date: Date): string => { + const weekdays: string[] = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + return weekdays[date.getDay()]; +}; + +const removeYear = (str: string): string => { + return str.substring(0, str.length - 5); +}; + +const UpcomingDesignReviewsCard: React.FC = ({ designReview, user }) => { + const theme = useTheme(); + const timezoneAdjustedDate = timezoneOffset(designReview.dateScheduled); + return ( + + + + + + + {designReview.wbsName} + + + + {} + + {getWeekday(timezoneAdjustedDate) + + ', ' + + removeYear(datePipe(timezoneAdjustedDate)) + + ' @ ' + + meetingStartTimePipe(designReview.meetingTimes)} + + + {designReview.isInPerson && !!designReview.location && ( + } text={designReview.location} /> + )} + {designReview.isOnline && !!designReview.zoomLink && ( + } text={designReview.zoomLink} link /> + )} + + + + + + ); +}; + +export default UpcomingDesignReviewsCard; diff --git a/src/frontend/src/pages/HomePage/components/OverdueWorkPackageView.tsx b/src/frontend/src/pages/HomePage/components/OverdueWorkPackageView.tsx index 4686213017..d0d42294b1 100644 --- a/src/frontend/src/pages/HomePage/components/OverdueWorkPackageView.tsx +++ b/src/frontend/src/pages/HomePage/components/OverdueWorkPackageView.tsx @@ -1,4 +1,4 @@ -import { Box, Card, CardContent, Stack, Typography, useTheme } from '@mui/material'; +import { Box, Card, CardContent, Typography, useTheme } from '@mui/material'; import { WorkPackage } from 'shared'; import EmptyPageBlockDisplay from './EmptyPageBlockDisplay'; import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined'; @@ -57,32 +57,36 @@ const OverdueWorkPackagesView: React.FC = ({ workP - {isEmpty ? : workPackages.map((wp) => )} - + diff --git a/src/frontend/src/pages/HomePage/components/ScrollablePageBlock.tsx b/src/frontend/src/pages/HomePage/components/ScrollablePageBlock.tsx index 25045b6d39..54b11ce434 100644 --- a/src/frontend/src/pages/HomePage/components/ScrollablePageBlock.tsx +++ b/src/frontend/src/pages/HomePage/components/ScrollablePageBlock.tsx @@ -34,23 +34,26 @@ const ScrollablePageBlock: React.FC = ({ children, tit sx={{ mt: 2, display: 'flex', - flexDirection: horizontal ? 'row' : 'column', + flexDirection: 'row', + flexWrap: 'wrap', gap: 2, height: '100%', overflowX: horizontal ? 'auto' : 'hidden', overflowY: horizontal ? 'hidden' : 'auto', '&::-webkit-scrollbar': { - height: '20px' + width: '20px' }, '&::-webkit-scrollbar-track': { backgroundColor: 'transparent' }, '&::-webkit-scrollbar-thumb': { - backgroundColor: theme.palette.error.dark, + backgroundColor: theme.palette.primary.main, borderRadius: '20px', border: '6px solid transparent', backgroundClip: 'content-box' - } + }, + scrollbarWidth: 'auto', + scrollbarColor: `${theme.palette.primary.main} transparent` }} > {children} diff --git a/src/frontend/src/pages/HomePage/components/TeamTaskCard.tsx b/src/frontend/src/pages/HomePage/components/TeamTaskCard.tsx index 76b80e93c3..dfd1485e64 100644 --- a/src/frontend/src/pages/HomePage/components/TeamTaskCard.tsx +++ b/src/frontend/src/pages/HomePage/components/TeamTaskCard.tsx @@ -28,7 +28,7 @@ const TeamTaskCard: React.FC = ({ task, taskNumber }) => { { + return ( + } + heading={'No Upcoming Design Reviews'} + message={'There are no Upcoming Design Reviews to Display'} + /> + ); +}; + +const UpcomingDesignReviews: React.FC = ({ user }) => { + const { data: designReviews, isLoading, isError, error } = useAllDesignReviews(); + + if (isLoading || !designReviews) return ; + if (isError) return ; + + const filteredDesignReviews = designReviews.filter((review) => { + const scheduledDate = review.dateScheduled; + const currentDate = new Date(); + const inTwoWeeks = new Date(); + inTwoWeeks.setDate(currentDate.getDate() + 14); + const memberUserIds = [ + ...review.requiredMembers.map((user) => user.userId), + ...review.optionalMembers.map((user) => user.userId) + ]; + // added in case the person who created the design review forgets to add their name onto the required members + memberUserIds.concat(review.userCreated.userId); + return ( + scheduledDate >= currentDate && + scheduledDate <= inTwoWeeks && + review.status !== DesignReviewStatus.DONE && + memberUserIds.includes(user.userId) + ); + }); + + const fullDisplay = ( + + {filteredDesignReviews.length === 0 ? ( + + ) : ( + filteredDesignReviews.map((d) => ) + )} + + ); + + return fullDisplay; +}; + +export default UpcomingDesignReviews; diff --git a/src/frontend/src/utils/datetime.utils.ts b/src/frontend/src/utils/datetime.utils.ts index e728bb5cbf..1b23c43118 100644 --- a/src/frontend/src/utils/datetime.utils.ts +++ b/src/frontend/src/utils/datetime.utils.ts @@ -34,3 +34,8 @@ export const formatDate = (date: Date) => { export const daysOverdue = (deadline: Date) => { return Math.round((new Date().getTime() - deadline.getTime()) / (1000 * 60 * 60 * 24)); }; + +export const timezoneOffset = (date: Date) => { + const timestamp = new Date(date).getTime() - new Date(date).getTimezoneOffset() * -60000; + return new Date(timestamp); +};