Skip to content
Open
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
10 changes: 8 additions & 2 deletions src/frontend/src/pages/CalendarPage/AvailabilityScheduleView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from '@mui/material';
import { Availability, Event, EventWithMembers, getDayOfWeek, getNextSevenDays, User } from 'shared';
import React, { useState } from 'react';
import { enumToArray, getBackgroundColor, NUMBER_OF_TIME_SLOTS, REVIEW_TIMES } from '../../utils/design-review.utils';
import {
enumToArray,
getBackgroundColor,
NUMBER_OF_TIME_SLOTS,
REVIEW_TIMES,
reviewTimesInCurrentTimeZone
} from '../../utils/design-review.utils';
import { datePipe } from '../../utils/pipes';
import EventTimeSlot from './Components/EventTimeSlot';

Expand Down Expand Up @@ -166,7 +172,7 @@ const AvailabilityScheduleView: React.FC<AvailabilityScheduleViewProps> = ({
<TableRow>
<TableCell sx={{ ...stickyLeft, zIndex: 1 }}>
<Typography flexGrow={1} variant="h6" align="center" sx={{ fontSize: { xs: 12, md: 16 } }}>
{time}
{reviewTimesInCurrentTimeZone(time)}
</Typography>
</TableCell>
{potentialDays.map((day, dayIndex) => {
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/src/pages/CalendarPage/CalendarWeekView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useCurrentUser } from '../../hooks/users.hooks';
import { getMutedColor } from '../../utils/calendar.utils';
import { getTeamTypeIcon } from './CalendarDayCard';
import { TaskClickContent } from './TaskClickPopup';
import { formatHourInCurrentTimeZone } from '../../utils/design-review.utils';

// ─── Layout constants ────────────────────────────────────────────────────────

Expand Down Expand Up @@ -870,7 +871,7 @@ const CalendarWeekView: React.FC<CalendarWeekViewProps> = ({
>
{hour > 0 && (
<Typography sx={{ fontSize: 12, color: 'rgba(255,255,255,0.55)', whiteSpace: 'nowrap' }}>
{formatHour(hour)}
{formatHourInCurrentTimeZone(formatHour(hour))}
</Typography>
)}
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import SingleAvailabilityModal from '../../SettingsPage/UserScheduleSettings/Ava
import AvailabilityEditModal from '../../SettingsPage/UserScheduleSettings/Availability/AvailabilityEditModal';
import AvailabilityScheduleView from '../AvailabilityScheduleView';
import ScheduleEventModal from './ScheduleEventModal';
import { formatHourInCurrentTimeZone, offsetDate } from '../../../utils/design-review.utils';

const isUserOnEvent = (user: User, event: EventWithMembers): boolean => {
const isDirectMember =
Expand Down Expand Up @@ -302,14 +303,24 @@ export const EventAvailabilityPage: React.FC = () => {
{/* Date/Time display */}
{(() => {
const displaySlot = currentHoveredSlot || selectedSlot;
const specificTime = () => {
const specificDate = new Date(displaySlot!.day);
specificDate.setHours(displaySlot!.startHour);
return specificDate;
};
if (displaySlot) {
return (
<Box sx={{ mb: 3 }}>
<Typography variant="h6">
{displaySlot.day.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' })}
{offsetDate(specificTime()).toLocaleDateString('en-US', {
weekday: 'long',
month: 'short',
day: 'numeric'
})}
</Typography>
<Typography variant="body1" color="text.secondary">
{formatHour(displaySlot.startHour)} - {formatHour(displaySlot.endHour)}
{formatHourInCurrentTimeZone(formatHour(displaySlot.startHour))} -{' '}
{formatHourInCurrentTimeZone(formatHour(displaySlot.endHour))}
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
{currentAvailableUsers.length}/{relevantUsers.length} available
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useToast } from '../../../hooks/toasts.hooks';
import { formatEventTime } from 'shared';
Comment thread
glickgNU marked this conversation as resolved.
import { datePipe } from '../../../utils/pipes';
import { routes } from '../../../utils/routes';
import { offsetDate } from '../../../utils/design-review.utils';

interface ScheduleEventModalProps {
open: boolean;
Expand Down Expand Up @@ -40,10 +41,10 @@ const ScheduleEventModal: React.FC<ScheduleEventModalProps> = ({
const { mutateAsync: scheduleEvent, isLoading } = useScheduleEvent(eventId);

// Compute the full start and end times
const startTime = new Date(selectedDay);
const startTime = new Date(offsetDate(selectedDay));
startTime.setHours(startHour, 0, 0, 0);

const endTime = new Date(selectedDay);
const endTime = new Date(offsetDate(selectedDay));
endTime.setHours(endHour, 0, 0, 0);

const handleConfirm = async () => {
Expand All @@ -59,6 +60,12 @@ const ScheduleEventModal: React.FC<ScheduleEventModalProps> = ({
}
};

const dateToShow = () => {
const newDate = new Date(selectedDay);
newDate.setHours(startHour);
return newDate;
};

return (
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
<DialogTitle>
Expand All @@ -70,9 +77,9 @@ const ScheduleEventModal: React.FC<ScheduleEventModalProps> = ({
<Box
sx={{ mt: 2, p: 2, bgcolor: 'background.paper', borderRadius: 1, border: '1px solid', borderColor: 'divider' }}
>
<Typography variant="h6">{datePipe(selectedDay)}</Typography>
<Typography variant="h6">{datePipe(offsetDate(dateToShow()))}</Typography>
<Typography variant="body1" color="text.secondary">
{formatEventTime(startTime)} - {formatEventTime(endTime)}
{formatEventTime(startTime)} -{formatEventTime(endTime)}
</Typography>
</Box>

Expand Down
4 changes: 3 additions & 1 deletion src/frontend/src/pages/CalendarPage/EventClickPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { useToast } from '../../hooks/toasts.hooks';
import NERDeleteModal from '../../components/NERDeleteModal';
import NotificationsIcon from '@mui/icons-material/Notifications';
import { getPendingReason } from '../../utils/calendar.utils';
import { formatHourInCurrentTimeZone } from '../../utils/design-review.utils';

export const getStatusIcon = (status: string, isLarge?: boolean) => {
const statusIcons: Map<string, JSX.Element> = new Map([
Expand Down Expand Up @@ -278,7 +279,8 @@ export const EventClickContent: React.FC<EventClickContentProps> = ({
)}
{dayOfWeek && !event.allDay && (
<Typography variant="body2">
{formatEventTime(event.startTime)} – {formatEventTime(event.endTime)}
{formatHourInCurrentTimeZone(formatEventTime(event.startTime))} –{' '}
{formatHourInCurrentTimeZone(formatEventTime(event.endTime))}
</Typography>
)}
{dayOfWeek && event.allDay && <Typography variant="body2">All day</Typography>}
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/src/pages/CalendarPage/UpcomingMeetingsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Calendar, EventInstance, EventType, formatEventTime } from 'shared';
import { datePipe } from '../../utils/pipes';

import { getMutedColor, getPendingReason } from '../../utils/calendar.utils';
import { formatHourInCurrentTimeZone } from '../../utils/design-review.utils';

interface UpcomingMeetingProp {
calendars: Calendar[];
Expand Down Expand Up @@ -72,7 +73,7 @@ const UpcomingMeetingsCard: React.FC<UpcomingMeetingProp> = ({ event, calendars

{/* Event Time */}
<Box marginLeft="auto" whiteSpace="nowrap">
{formatEventTime(new Date(event.startTime))}
{formatHourInCurrentTimeZone(formatEventTime(new Date(event.startTime)))}
</Box>
</Box>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import {
useMediaQuery
} from '@mui/material';
import { useEffect, useState } from 'react';
import { HeatmapColors, enumToArray, REVIEW_TIMES } from '../../../../utils/design-review.utils';
import {
HeatmapColors,
enumToArray,
REVIEW_TIMES,
reviewTimesInCurrentTimeZone
} from '../../../../utils/design-review.utils';
import { addDaysToDate, Availability, getDayOfWeek, getMostRecentAvailabilities } from 'shared';
import { datePipe } from '../../../../utils/pipes';
import NERArrows from '../../../../components/NERArrows';
Expand Down Expand Up @@ -191,10 +196,10 @@ const EditAvailability: React.FC<EditAvailabilityProps> = ({
</TableHead>
<TableBody>
{enumToArray(REVIEW_TIMES).map((time, timeIndex) => (
<TableRow key={time}>
<TableRow key={reviewTimesInCurrentTimeZone(time)}>
<TableCell sx={{ ...stickyLeft, zIndex: 1, scrollSnapAlign: 'start' }}>
<Typography variant="body1" align="center" sx={{ fontSize: 15 }}>
{time}
{reviewTimesInCurrentTimeZone(time)}
</Typography>
</TableCell>
{currentlyDisplayedAvailabilities.map((availability, dayIndex) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { Availability, getDayOfWeek, getMostRecentAvailabilities } from 'shared'
import { datePipe } from '../../../../utils/pipes';
import { useState, useEffect } from 'react';
import NERArrows from '../../../../components/NERArrows';
import { enumToArray, REVIEW_TIMES, getBackgroundColor } from '../../../../utils/design-review.utils';
import {
enumToArray,
REVIEW_TIMES,
getBackgroundColor,
reviewTimesInCurrentTimeZone
} from '../../../../utils/design-review.utils';
import EventTimeSlot from '../../../CalendarPage/Components/EventTimeSlot';

interface SingleAvailabilityViewProps {
Expand Down Expand Up @@ -89,10 +94,10 @@ const SingleAvailabilityView: React.FC<SingleAvailabilityViewProps> = ({ totalAv
</TableHead>
<TableBody>
{enumToArray(REVIEW_TIMES).map((time, timeIndex) => (
<TableRow key={time}>
<TableRow key={reviewTimesInCurrentTimeZone(time)}>
<TableCell sx={{ ...stickyLeft, zIndex: 1 }}>
<Typography variant="body1" align="center" sx={{ fontSize: 15 }}>
{time}
{reviewTimesInCurrentTimeZone(time)}
</Typography>
</TableCell>
{selectedTimes.map((availability, dayIndex) => {
Expand Down
67 changes: 67 additions & 0 deletions src/frontend/src/utils/design-review.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,73 @@ export const HeatmapColors = ['#D9D9D9', '#C1E0C1', '#9BE89B', '#7AE47A', '#45EF

export const NUMBER_OF_TIME_SLOTS = enumToArray(REVIEW_TIMES).length * enumToArray(DAY_NAMES).length;

const ESTOffset = () => {
const parts = new Intl.DateTimeFormat('en', {
timeZone: 'America/New_York',
timeZoneName: 'shortOffset'
}).formatToParts(new Date());

const GMTTime = parts.find((t) => t.type === 'timeZoneName');
const offsetEST = Number(GMTTime!.value.replace('GMT', ''));

return offsetEST;
};

export const userOffsetTime = () => {
const UTCOffset = -new Date().getTimezoneOffset() / 60;
const EST = ESTOffset();
const userOffset = UTCOffset - EST;
return userOffset;
};

export const offsetDate = (date: Date) => {
const hoursOffset = userOffsetTime();
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours() + hoursOffset);
};

// converts a REVIEW_TIME (That is in string form) to the user's current time
export const reviewTimesInCurrentTimeZone = (time: string) => {
return offsetReviewTime(time, userOffsetTime());
};

const isTwoDigitHour = (time: string) => !isNaN(Number(time.charAt(1)));

const offsetReviewTime = (time: string, offset: number) => {
// get initialTime
const startTime = Number(time.charAt(0) + (isTwoDigitHour(time) ? time.charAt(1) : ''));

let newStartTime = (startTime + offset + 12) % 12;
if (newStartTime === 0) newStartTime = 12;
let newEndTime = (startTime + 1 + offset + 12) % 12;
if (newEndTime === 0) newEndTime = 12;

return newStartTime + '-' + newEndTime + ' ' + AMorPM(time, offset);
};

const AMorPM = (time: string, offset: number) => {
const startTime = Number(time.charAt(0) + (isTwoDigitHour(time) ? time.charAt(1) : ''));
const AMorPM = time.charAt(time.length - 2) + time.charAt(time.length - 1);
const startTime24Hour = startTime + (AMorPM === 'PM' && startTime !== 12 ? 12 : 0);

const newTime = startTime24Hour + offset;
const newHour = (newTime + 24) % 24;

return newHour >= 12 ? 'PM' : 'AM';
};
Comment on lines +100 to +109

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of the am/pm's are messed up on the calendar between time zones, I think since the offset could make the number negative, that might be causing a problem

London:
Image

SF:
Image


export const formatHourInCurrentTimeZone = (time: string) => {
return offsetFormatHour(time, userOffsetTime());
};

const offsetFormatHour = (time: string, offset: number) => {
const hourTime = Number(time.charAt(0) + (isTwoDigitHour(time) ? time.charAt(1) : ''));

let newHourTime = (((hourTime + offset) % 12) + 12) % 12;
if (newHourTime === 0) newHourTime = 12;

return newHourTime + ':00 ' + AMorPM(time, offset);
};

export const getBackgroundColor = (frequency: number = 0, totalUsers: number): string => {
if (frequency === 0) return HeatmapColors[0];
if (frequency >= totalUsers) return HeatmapColors[5];
Expand Down
Loading