From fe923bbc88e6b94cac3e8666018b57d0013545f9 Mon Sep 17 00:00:00 2001 From: Alec Li Date: Fri, 4 Aug 2023 20:41:22 -0700 Subject: [PATCH] Modify all datetime displays to use consistent formatting --- .../frontend/src/components/CourseMenu.tsx | 2 +- csm_web/frontend/src/components/Home.tsx | 3 +- .../frontend/src/components/course/Course.tsx | 4 +- .../components/course/CreateSectionModal.tsx | 66 +++--- .../src/components/course/SectionCard.tsx | 9 +- .../ResourceRowRender.tsx | 4 +- .../src/components/section/Section.tsx | 14 +- .../components/section/SpacetimeEditModal.tsx | 17 +- .../frontend/src/components/section/utils.tsx | 19 +- csm_web/frontend/src/utils/datetime.tsx | 93 ++++++++- .../frontend/src/utils/queries/spacetime.tsx | 15 +- csm_web/frontend/src/utils/types.tsx | 5 +- csm_web/scheduler/models.py | 188 +++++++++++++----- csm_web/scheduler/serializers.py | 23 +-- csm_web/scheduler/views/section.py | 60 +++--- csm_web/scheduler/views/spacetime.py | 74 ++++--- csm_web/scheduler/views/utils.py | 21 +- cypress/e2e/course/coordinator-course.cy.ts | 10 +- 18 files changed, 421 insertions(+), 206 deletions(-) diff --git a/csm_web/frontend/src/components/CourseMenu.tsx b/csm_web/frontend/src/components/CourseMenu.tsx index 213203e8..4d7d6bf8 100644 --- a/csm_web/frontend/src/components/CourseMenu.tsx +++ b/csm_web/frontend/src/components/CourseMenu.tsx @@ -35,7 +35,7 @@ const CourseMenu = () => { if (userInfoLoaded) { let priorityEnrollment = undefined; if (jsonUserInfo.priorityEnrollment) { - priorityEnrollment = DateTime.fromISO(jsonUserInfo.priorityEnrollment); + priorityEnrollment = DateTime.fromISO(jsonUserInfo.priorityEnrollment, { zone: DEFAULT_TIMEZONE }); } const convertedUserInfo: UserInfo = { ...jsonUserInfo, diff --git a/csm_web/frontend/src/components/Home.tsx b/csm_web/frontend/src/components/Home.tsx index b24b6724..13f0e7da 100644 --- a/csm_web/frontend/src/components/Home.tsx +++ b/csm_web/frontend/src/components/Home.tsx @@ -6,6 +6,7 @@ import { useCourses } from "../utils/queries/courses"; import { ROLES } from "./section/Section"; import { Profile, Course } from "../utils/types"; import LoadingSpinner from "./LoadingSpinner"; +import { formatSpacetimeInterval } from "../utils/datetime"; const Home = () => { const { data: profiles, isSuccess: profilesLoaded, isError: profilesLoadError } = useProfiles(); @@ -91,7 +92,7 @@ const CourseCard = ({ profiles }: CourseCardProps): React.ReactElement => { {profile.sectionSpacetimes.map(spacetime => (
- {spacetime.time} + {formatSpacetimeInterval(spacetime)}
))} diff --git a/csm_web/frontend/src/components/course/Course.tsx b/csm_web/frontend/src/components/course/Course.tsx index 8dbe9314..d64ab9f9 100644 --- a/csm_web/frontend/src/components/course/Course.tsx +++ b/csm_web/frontend/src/components/course/Course.tsx @@ -1,3 +1,4 @@ +import { DateTime } from "luxon"; import React, { useState } from "react"; import { useParams } from "react-router-dom"; import { useCourseSections } from "../../utils/queries/courses"; @@ -8,10 +9,9 @@ import { DataExportModal } from "./DataExportModal"; import { SectionCard } from "./SectionCard"; import { WhitelistModal } from "./WhitelistModal"; import { SettingsModal } from "./SettingsModal"; +import { DEFAULT_LONG_LOCALE_OPTIONS } from "../../utils/datetime"; import PencilIcon from "../../../static/frontend/img/pencil.svg"; -import { DateTime } from "luxon"; -import { DEFAULT_LONG_LOCALE_OPTIONS } from "../../utils/datetime"; const DAY_OF_WEEK_ABREVIATIONS: { [day: string]: string } = Object.freeze({ Monday: "M", diff --git a/csm_web/frontend/src/components/course/CreateSectionModal.tsx b/csm_web/frontend/src/components/course/CreateSectionModal.tsx index 46a529ab..27d89ed8 100644 --- a/csm_web/frontend/src/components/course/CreateSectionModal.tsx +++ b/csm_web/frontend/src/components/course/CreateSectionModal.tsx @@ -1,13 +1,13 @@ import React, { useState } from "react"; +import { dayOfWeekToEnglishString, DAYS_OF_WEEK } from "../../utils/datetime"; import { useUserEmails } from "../../utils/queries/base"; import { useSectionCreateMutation } from "../../utils/queries/sections"; import { Spacetime } from "../../utils/types"; import Modal from "../Modal"; -import { DAYS_OF_WEEK } from "../section/utils"; import TimeInput from "../TimeInput"; const makeSpacetime = (): Spacetime => { - return { dayOfWeek: "", startTime: "", location: "" } as Spacetime; + return { id: -1, duration: 0, dayOfWeek: 1, startTime: "", location: "" }; }; interface CreateSectionModalProps { @@ -57,17 +57,18 @@ export const CreateSectionModal = ({ courseId, closeModal, reloadSections }: Cre /** * Handle the change of a form field. */ - const handleChange = ({ target: { name, value } }: React.ChangeEvent): void => { - if (name.startsWith("location") || name.startsWith("startTime") || name.startsWith("dayOfWeek")) { - // Funny JavaScript scoping workaround (let [name, index] = name.split("|") doesn't work) - let index; - [name, index] = name.split("|"); - index = Number(index); - setSpacetimes([ - ...spacetimes.slice(0, index), - { ...spacetimes[index], [name]: value }, - ...spacetimes.slice(index + 1) - ]); + const handleChange = (index: number, name: string, value: string): void => { + if (name === "location" || name === "startTime" || name === "dayOfWeek" || name === "duration") { + setSpacetimes(oldSpacetimes => { + const newSpacetimes = [...oldSpacetimes]; + if (name === "dayOfWeek" || name === "duration") { + // day of week is int + newSpacetimes[index][name] = parseInt(value); + } else { + newSpacetimes[index][name] = value; + } + return newSpacetimes; + }); } else { switch (name) { case "mentorEmail": @@ -115,7 +116,7 @@ export const CreateSectionModal = ({ courseId, closeModal, reloadSections }: Cre - {spacetimes.map(({ dayOfWeek, startTime, location }, index) => ( + {spacetimes.map(({ dayOfWeek, startTime, location, duration }, index) => (

Weekly occurence {index + 1}

-
{formatDate(DateTime.fromISO(resource.date))}
+
{formatDate(DateTime.fromISO(resource.date, { zone: DEFAULT_TIMEZONE }))}
diff --git a/csm_web/frontend/src/components/section/Section.tsx b/csm_web/frontend/src/components/section/Section.tsx index 3e6ced65..1936fc5b 100644 --- a/csm_web/frontend/src/components/section/Section.tsx +++ b/csm_web/frontend/src/components/section/Section.tsx @@ -5,6 +5,7 @@ import MentorSection from "./MentorSection"; import { Override, Spacetime } from "../../utils/types"; import { useSection } from "../../utils/queries/sections"; import LoadingSpinner from "../LoadingSpinner"; +import { formatSpacetimeInterval } from "../../utils/datetime"; export const ROLES = Object.freeze({ COORDINATOR: "COORDINATOR", STUDENT: "STUDENT", MENTOR: "MENTOR" }); @@ -89,24 +90,19 @@ interface SectionSpacetimeProps { override?: Override; } -export function SectionSpacetime({ - manySpacetimes, - index, - spacetime: { location, time }, - override, - children -}: SectionSpacetimeProps) { +export function SectionSpacetime({ manySpacetimes, index, spacetime, override, children }: SectionSpacetimeProps) { + const location = spacetime.location; return ( {children} -
{time}
+
{formatSpacetimeInterval(spacetime)}
{override && (
Adjusted for {override.date}
-
{override.spacetime.time}
+
{formatSpacetimeInterval(override.spacetime)}
)} diff --git a/csm_web/frontend/src/components/section/SpacetimeEditModal.tsx b/csm_web/frontend/src/components/section/SpacetimeEditModal.tsx index bbebee6f..0b1010de 100644 --- a/csm_web/frontend/src/components/section/SpacetimeEditModal.tsx +++ b/csm_web/frontend/src/components/section/SpacetimeEditModal.tsx @@ -1,11 +1,11 @@ import { DateTime } from "luxon"; import React, { useState } from "react"; +import { DAYS_OF_WEEK } from "../../utils/datetime"; import { useSpacetimeModifyMutation, useSpacetimeOverrideMutation } from "../../utils/queries/spacetime"; import { Spacetime } from "../../utils/types"; import LoadingSpinner from "../LoadingSpinner"; import Modal from "../Modal"; import TimeInput from "../TimeInput"; -import { DAYS_OF_WEEK } from "./utils"; interface SpacetimeEditModalProps { sectionId: number; @@ -20,10 +20,9 @@ const SpaceTimeEditModal = ({ defaultSpacetime: { id: spacetimeId, startTime: timeString, location: prevLocation, dayOfWeek }, editingOverride }: SpacetimeEditModalProps): React.ReactElement => { - const sliceIndex = timeString.split(":").length < 3 ? timeString.indexOf(":") : timeString.lastIndexOf(":"); const [location, setLocation] = useState(prevLocation); const [day, setDay] = useState(dayOfWeek); - const [time, setTime] = useState(timeString.slice(0, sliceIndex)); + const [time, setTime] = useState(timeString); const [isPermanent, setIsPermanent] = useState(false); const [date, setDate] = useState(""); const [mode, setMode] = useState(prevLocation && prevLocation.startsWith("http") ? "virtual" : "inperson"); @@ -38,13 +37,13 @@ const SpaceTimeEditModal = ({ setShowSaveSpinner(true); isPermanent ? spacetimeModifyMutation.mutate({ - day_of_week: day, + dayOfWeek, location: location, - start_time: `${time}:00` + startTime: time }) : spacetimeOverrideMutation.mutate({ location: location, - start_time: `${time}:00`, + startTime: time, date: date }); closeModal(); @@ -100,15 +99,15 @@ const SpaceTimeEditModal = ({