Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2217 wire drc page #2222

Merged
merged 4 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const designReviewTransformer = (designReview: DesignReview) => {
return {
...designReview,
dateCreated: new Date(designReview.dateCreated),
dateDeleted: designReview.dateDeleted ? new Date(designReview.dateDeleted) : undefined
dateDeleted: designReview.dateDeleted ? new Date(designReview.dateDeleted) : undefined,
dateScheduled: designReview.dateScheduled ? new Date(designReview.dateScheduled) : undefined
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Card, CardContent, Grid, IconButton, Stack, Typography } from '@mui/material';
import { Box, Card, CardContent, Grid, IconButton, Link, Stack, Tooltip, Typography } from '@mui/material';
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
import { DesignReview } from 'shared';
import { meetingStartTimePipe } from '../../../utils/pipes';
Expand All @@ -8,15 +8,16 @@ import ElectricalServicesIcon from '@mui/icons-material/ElectricalServices';
import TerminalIcon from '@mui/icons-material/Terminal';
import { useState } from 'react';
import DRCSummaryModal from '../DesignReviewSummaryModal';
import DynamicTooltip from '../../../components/DynamicTooltip';

export const getTeamTypeIcon = (teamTypeId: string, isLarge?: boolean) => {
export const getTeamTypeIcon = (teamTypeName: string, isLarge?: boolean) => {
const teamIcons: Map<string, JSX.Element> = new Map([
['Software', <TerminalIcon fontSize={isLarge ? 'large' : 'small'} />],
['Business', <WorkOutlineIcon fontSize={isLarge ? 'large' : 'small'} />],
['Electrical', <ElectricalServicesIcon fontSize={isLarge ? 'large' : 'small'} />],
['Mechanical', <ConstructionIcon fontSize={isLarge ? 'large' : 'small'} />]
]);
return teamIcons.get(teamTypeId);
return teamIcons.get(teamTypeName);
};

interface CalendarDayCardProps {
Expand All @@ -40,33 +41,103 @@ const CalendarDayCard: React.FC<CalendarDayCardProps> = ({ cardDate, events }) =
</Grid>
);

const EventCard = (event: DesignReview) => {
const EventCard = ({ event }: { event: DesignReview }) => {
const [isSummaryModalOpen, setIsSummaryModalOpen] = useState(false);
const name = event.designReviewId;
const name = event.wbsName;
return (
<>
<DRCSummaryModal open={isSummaryModalOpen} onHide={() => setIsSummaryModalOpen(false)} designReview={event} />
<Box marginLeft={0.5} marginBottom={0.5} onClick={() => setIsSummaryModalOpen(true)} sx={{ cursor: 'pointer' }}>
<Card sx={{ backgroundColor: 'red', borderRadius: 1, minWidth: 140, maxWidth: 140, minHeight: 20, maxHeight: 20 }}>
<Stack direction="row">
{getTeamTypeIcon(event.teamType.teamTypeId)}
<Typography marginLeft={0.5} marginBottom={0.3} fontSize={14}>
{name + ' ' + meetingStartTimePipe(event.meetingTimes)}
</Typography>
{getTeamTypeIcon(event.teamType.name)}
<DynamicTooltip
title={name + (event.meetingTimes.length > 0 ? ' - ' + meetingStartTimePipe(event.meetingTimes) : '')}
>
walker-sean marked this conversation as resolved.
Show resolved Hide resolved
<Typography marginLeft={0.5} marginBottom={0.3} fontSize={14} noWrap>
{name + (event.meetingTimes.length > 0 ? ' ' + meetingStartTimePipe(event.meetingTimes) : '')}
</Typography>
</DynamicTooltip>
</Stack>
</Card>
</Box>
</>
);
};

const ExtraEventsCard = (extraEvents: number) => {
const ExtraEventNote = ({ event }: { event: DesignReview }) => {
const [isSummaryModalOpen, setIsSummaryModalOpen] = useState(false);

return (
<>
<DRCSummaryModal open={isSummaryModalOpen} onHide={() => setIsSummaryModalOpen(false)} designReview={event} />
<Link
style={{ cursor: 'pointer' }}
fontSize={15}
onClick={() => {
setIsSummaryModalOpen(true);
}}
>
{event.wbsName + (event.meetingTimes.length > 0 ? ' - ' + meetingStartTimePipe(event.meetingTimes) : '')}
</Link>
</>
);
};

const ExtraEventsCard = ({ extraEvents }: { extraEvents: DesignReview[] }) => {
const [showTooltip, setShowTooltip] = useState(false);
return (
<Box marginLeft={0.5} marginBottom={0.2}>
<Card sx={{ backgroundColor: 'grey', borderRadius: 1, minWidth: 140, maxWidth: 140, minHeight: 20, maxHeight: 20 }}>
<Typography marginLeft={0.5} marginBottom={0.3} align="center">
{'+' + extraEvents}
</Typography>
<Card
sx={{
backgroundColor: 'grey',
borderRadius: 1,
minWidth: 140,
maxWidth: 140,
minHeight: 20,
maxHeight: 20
}}
>
<Tooltip
id="tooltip"
open={showTooltip}
disableHoverListener
onClick={() => setShowTooltip(!showTooltip)}
placement="right"
sx={{ cursor: 'pointer' }}
PopperProps={{
popperOptions: {
modifiers: [
{
name: 'flip',
options: {
fallbackPlacements: ['top', 'bottom'],
padding: -1,
rootBoundary: 'document'
}
},
{
name: 'offset',
options: {
offset: [0, -1]
}
}
]
}
}}
arrow
title={
<Stack direction="column">
{extraEvents.map((event) => (
<ExtraEventNote event={event} />
))}
</Stack>
}
>
<Typography marginLeft={0.5} marginBottom={0.3} align="center">
{'+' + extraEvents.length}
</Typography>
</Tooltip>
</Card>
</Box>
);
Expand All @@ -77,11 +148,11 @@ const CalendarDayCard: React.FC<CalendarDayCardProps> = ({ cardDate, events }) =
<CardContent sx={{ padding: 0 }}>
<DayCardTitle />
{events.length < 3 ? (
events.map((event) => EventCard(event))
events.map((event) => <EventCard event={event} />)
) : (
<>
{EventCard(events[1])}
{ExtraEventsCard(events.length - 1)}
<EventCard event={events[0]} />
<ExtraEventsCard extraEvents={events.slice(1)} />
</>
)}
</CardContent>
Expand Down
59 changes: 40 additions & 19 deletions src/frontend/src/pages/CalendarPage/CalendarPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,43 @@ import { Box, Grid, Stack, Typography, useTheme } from '@mui/material';
import PageLayout from '../../components/PageLayout';
import { DesignReview } from 'shared';
import MonthSelector from './CalendarComponents/MonthSelector';
import CalendarDayCard from './CalendarComponents/CalendarDayCard';
import CalendarDayCard, { getTeamTypeIcon } from './CalendarComponents/CalendarDayCard';
import FillerCalendarDayCard from './CalendarComponents/FillerCalendarDayCard';
import {
DAY_NAMES,
EnumToArray,
calendarPaddingDays,
daysInMonth,
exampleDesignReview1,
testDesignReview1
} from '../../utils/design-review.utils';
import { DAY_NAMES, EnumToArray, calendarPaddingDays, daysInMonth, isConfirmed } from '../../utils/design-review.utils';
import ActionsMenu from '../../components/ActionsMenu';
import { useAllDesignReviews } from '../../hooks/design-reviews.hooks';
import LoadingIndicator from '../../components/LoadingIndicator';
import ErrorPage from '../ErrorPage';
import { useCurrentUser } from '../../hooks/users.hooks';
import { datePipe } from '../../utils/pipes';

const CalendarPage = () => {
const theme = useTheme();

const [displayMonthYear, setDisplayMonthYear] = useState<Date>(new Date());
const { isLoading, isError, error, data: allDesignReviews } = useAllDesignReviews();
const user = useCurrentUser();

if (isLoading || !allDesignReviews) return <LoadingIndicator />;
if (isError) return <ErrorPage message={error.message} />;

const confirmedDesignReviews = allDesignReviews.filter(isConfirmed);

const EventDict = new Map<Number, DesignReview[]>();
// TODO remove during wire up ticket
EventDict.set(new Date().getDate(), [exampleDesignReview1]);
EventDict.set(new Date().getDate() + 3, [testDesignReview1, testDesignReview1]);
EventDict.set(new Date().getDate() + 4, [testDesignReview1, testDesignReview1, testDesignReview1]);
const designReviewData: DesignReview[] = [testDesignReview1, testDesignReview1];
const eventDict = new Map<string, DesignReview[]>();
confirmedDesignReviews.forEach((designReview) => {
// Accessing the date actually converts it to local time, which causes the date to be off. This is a workaround.
const date = datePipe(
new Date(designReview.dateScheduled.getTime() - designReview.dateScheduled.getTimezoneOffset() * -60000)
walker-sean marked this conversation as resolved.
Show resolved Hide resolved
);
if (eventDict.has(date)) {
eventDict.get(date)?.push(designReview);
} else {
eventDict.set(date, [designReview]);
}
});

const unconfirmedDesignReviews = allDesignReviews.filter(
(designReview) => designReview.userCreated.userId === user.userId && !isConfirmed(designReview)
);

const startOfEachWeek = [0, 7, 14, 21, 28, 35];

Expand All @@ -40,7 +54,8 @@ const CalendarPage = () => {
const designReviewButtons = (designReviews: DesignReview[]) => {
return designReviews.map((designReview) => {
return {
title: designReview.designReviewId,
icon: getTeamTypeIcon(designReview.teamType.name),
title: designReview.wbsName,
onClick: () => {},
disabled: false
};
Expand All @@ -62,7 +77,7 @@ const CalendarPage = () => {
.concat(paddingArrayEnd.length < 7 ? paddingArrayEnd : []);

const unconfirmedDRSDropdown = (
<ActionsMenu title="My Unconfirmed DRS" buttons={designReviewButtons(designReviewData)}>
<ActionsMenu title="My Unconfirmed DRS" buttons={designReviewButtons(unconfirmedDesignReviews)}>
My Unconfirmed DRs
</ActionsMenu>
);
Expand Down Expand Up @@ -98,7 +113,13 @@ const CalendarPage = () => {
{isDayInDifferentMonth(day, week) ? (
<FillerCalendarDayCard day={day} />
) : (
<CalendarDayCard cardDate={cardDate} events={EventDict.get(cardDate.getDate()) ?? []} />
<CalendarDayCard
cardDate={cardDate}
events={
eventDict.get(datePipe(new Date(cardDate.getTime() - cardDate.getTimezoneOffset() * -60000))) ??
[]
}
/>
)}
</Box>
</Grid>
Expand Down
55 changes: 8 additions & 47 deletions src/frontend/src/utils/design-review.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,53 +80,6 @@ export const calendarPaddingDays = (month: Date): number => {
return new Date(month.getFullYear(), month.getMonth(), 0).getDay();
};

// TODO remove during wire up ticket
export const testDesignReview1: DesignReview = {
designReviewId: 'Meeting',
dateScheduled: new Date(),
meetingTimes: [16],
dateCreated: new Date(),
userCreated: batman,
status: DesignReviewStatus.UNCONFIRMED,
teamType: { teamTypeId: 'Mechanical', name: 'Mechanical', iconName: '' },
requiredMembers: [],
optionalMembers: [],
confirmedMembers: [],
deniedMembers: [],
isOnline: false,
isInPerson: false,
attendees: [],
wbsName: 'bruh',
wbsNum: { carNumber: 1, workPackageNumber: 1, projectNumber: 1 }
};

// TODO remove during wire up ticket
export const exampleDesignReview1: DesignReview = {
designReviewId: 'Wiring',
dateScheduled: new Date(),
meetingTimes: [1, 2, 5],
dateCreated: new Date(),
userCreated: superman,
status: DesignReviewStatus.DONE,
teamType: {
teamTypeId: 'Electrical',
name: 'thisteam',
iconName: ''
},
requiredMembers: [batman, superman, greenlantern, flash, aquaman],
optionalMembers: [wonderwoman, alfred],
confirmedMembers: [],
deniedMembers: [],
location: 'Room 101',
isOnline: true,
isInPerson: false,
zoomLink: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
attendees: [],
wbsName: 'Battery',
wbsNum: { carNumber: 1, projectNumber: 1, workPackageNumber: 1 },
docTemplateLink: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
};

// TODO: We will have to make a call to the backend to get this data
export const usersToAvailabilities = new Map([
[superman, [1, 2, 3, 4, 5, 6, 7]],
Expand All @@ -145,3 +98,11 @@ existingMeetingData.set(5, 'warning');
existingMeetingData.set(10, 'build');
existingMeetingData.set(20, 'computer');
existingMeetingData.set(50, 'electrical');

export const isConfirmed = (designReview: DesignReview): boolean => {
return (
designReview.status === DesignReviewStatus.CONFIRMED ||
designReview.status === DesignReviewStatus.SCHEDULED ||
designReview.status === DesignReviewStatus.DONE
);
};
8 changes: 3 additions & 5 deletions src/frontend/src/utils/pipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*/

import { WbsNumber, User, wbsPipe, WbsElement, isProject, WorkPackage, ClubAccount, ExpenseType } from 'shared';
import { NOON_IN_MINUTES } from './design-review.utils';

/**
* Pipes:
Expand Down Expand Up @@ -165,10 +164,9 @@ export const displayEnum = (enumString: string) => {
};

export const meetingStartTimePipe = (times: number[]) => {
const time = times[0] * 15 + 9 * 60;
const minutes = time % 60;
const hours = ((time - minutes) / 60) % 12 === 0 ? 12 : ((time - minutes) / 60) % 12;
return hours + (minutes !== 0 ? ':' + minutes : '') + (time >= NOON_IN_MINUTES ? 'pm' : 'am');
const time = (times[0] % 12) + 10;

return time <= 12 ? time + 'am' : time - 12 + 'pm';
};

// takes in a Date and returns it as a string in the form mm/dd/yy
Expand Down
Loading