From 791a42bcd49478024b6f1a237a2d2a9f6211749e Mon Sep 17 00:00:00 2001 From: Razboy20 Date: Sun, 17 Mar 2024 00:32:50 -0500 Subject: [PATCH] feat: calendar matchings (#173) * feat: calendar matchings * fix: build * refactor: resolve pr comments * fix: destrucure editorRef --------- Co-authored-by: doprz <52579214+doprz@users.noreply.github.com> --- src/pages/calendar/CalendarMain.tsx | 2 +- src/pages/calendar/index.html | 4 +- .../calendar/CalendarGridCell.stories.tsx | 4 + .../calendar/CalendarSchedules.stories.tsx | 6 - src/views/components/PopupMain.tsx | 13 +- .../calendar/Calendar/Calendar.module.scss | 8 - .../components/calendar/Calendar/Calendar.tsx | 59 ++------ .../CalendarCourseCell/CalendarCourseCell.tsx | 6 +- .../CalendarGrid/CalendarGrid.module.scss | 139 ------------------ .../calendar/CalendarGrid/CalendarGrid.tsx | 89 +++++------ .../CalendarGridCell.module.scss | 18 --- .../CalendarGridCell/CalendarGridCell.tsx | 17 ++- .../CalendarHeader/CalenderHeader.tsx | 68 ++++----- .../CalendarSchedules/CalendarSchedules.tsx | 68 ++------- .../components/calendar/ImportantLinks.tsx | 2 +- src/views/components/common/Dialog/Dialog.tsx | 2 +- .../common/ExtensionRoot/ExtensionRoot.tsx | 5 +- src/views/components/common/LogoIcon.tsx | 28 +++- .../ScheduleListItem/ScheduleListItem.tsx | 76 ++++++++-- .../ScheduleTotalHoursAndCourses.tsx | 10 +- .../components/common/Text/Text.module.scss | 8 + src/views/components/common/Text/Text.tsx | 17 ++- .../HeadingAndActions.tsx | 4 +- 23 files changed, 243 insertions(+), 410 deletions(-) delete mode 100644 src/views/components/calendar/Calendar/Calendar.module.scss delete mode 100644 src/views/components/calendar/CalendarGrid/CalendarGrid.module.scss delete mode 100644 src/views/components/calendar/CalendarGridCell/CalendarGridCell.module.scss diff --git a/src/pages/calendar/CalendarMain.tsx b/src/pages/calendar/CalendarMain.tsx index 4ac4d847..98d80f03 100644 --- a/src/pages/calendar/CalendarMain.tsx +++ b/src/pages/calendar/CalendarMain.tsx @@ -8,7 +8,7 @@ import React from 'react'; */ export default function CalendarMain() { return ( - + ); diff --git a/src/pages/calendar/index.html b/src/pages/calendar/index.html index c2a46388..9298b6c1 100644 --- a/src/pages/calendar/index.html +++ b/src/pages/calendar/index.html @@ -7,9 +7,9 @@ Calendar - + -
+
diff --git a/src/stories/components/calendar/CalendarGridCell.stories.tsx b/src/stories/components/calendar/CalendarGridCell.stories.tsx index 66ae4824..c9bde547 100644 --- a/src/stories/components/calendar/CalendarGridCell.stories.tsx +++ b/src/stories/components/calendar/CalendarGridCell.stories.tsx @@ -10,6 +10,10 @@ const meta = { layout: 'centered', tags: ['autodocs'], }, + args: { + row: 0, + col: 0, + }, } satisfies Meta; export default meta; diff --git a/src/stories/components/calendar/CalendarSchedules.stories.tsx b/src/stories/components/calendar/CalendarSchedules.stories.tsx index d9668bc0..6fe8d624 100644 --- a/src/stories/components/calendar/CalendarSchedules.stories.tsx +++ b/src/stories/components/calendar/CalendarSchedules.stories.tsx @@ -1,6 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react'; import { CalendarSchedules } from '@views/components/calendar/CalendarSchedules/CalendarSchedules'; -import React from 'react'; const meta = { title: 'Components/Calendar/CalendarSchedules', @@ -9,11 +8,6 @@ const meta = { layout: 'centered', tags: ['autodocs'], }, - render: args => ( -
- -
- ), } satisfies Meta; export default meta; diff --git a/src/views/components/PopupMain.tsx b/src/views/components/PopupMain.tsx index 8b8fb650..91e7d831 100644 --- a/src/views/components/PopupMain.tsx +++ b/src/views/components/PopupMain.tsx @@ -16,7 +16,7 @@ import RefreshIcon from '~icons/material-symbols/refresh'; import SettingsIcon from '~icons/material-symbols/settings'; import CourseStatus from './common/CourseStatus/CourseStatus'; -import { LogoIcon } from './common/LogoIcon'; +import { SmallLogo } from './common/LogoIcon'; import PopupCourseBlock from './common/PopupCourseBlock/PopupCourseBlock'; import ScheduleDropdown from './common/ScheduleDropdown/ScheduleDropdown'; import ScheduleListItem from './common/ScheduleListItem/ScheduleListItem'; @@ -44,16 +44,7 @@ export default function PopupMain(): JSX.Element {
-
- -
- - UT Registration -
-
- Plus -
-
+
- -
- - - LAST UPDATED: {getUpdatedAtDateTimeString(activeSchedule.updatedAt)} - -
-
-
-
- - - -
-
-
+
+
+
+ + + + + {/*
); } diff --git a/src/views/components/calendar/CalendarSchedules/CalendarSchedules.tsx b/src/views/components/calendar/CalendarSchedules/CalendarSchedules.tsx index da930b6b..2d651e04 100644 --- a/src/views/components/calendar/CalendarSchedules/CalendarSchedules.tsx +++ b/src/views/components/calendar/CalendarSchedules/CalendarSchedules.tsx @@ -1,68 +1,35 @@ -import { background } from '@shared/messages'; +import createSchedule from '@pages/background/lib/createSchedule'; import { UserScheduleStore } from '@shared/storage/UserScheduleStore'; -import type { UserSchedule } from '@shared/types/UserSchedule'; +import { Button } from '@views/components/common/Button/Button'; import List from '@views/components/common/List/List'; import ScheduleListItem from '@views/components/common/ScheduleListItem/ScheduleListItem'; import Text from '@views/components/common/Text/Text'; import useSchedules, { getActiveSchedule, switchSchedule } from '@views/hooks/useSchedules'; -import React, { useEffect, useState } from 'react'; +import React from 'react'; import AddSchedule from '~icons/material-symbols/add'; -/** - * Props for the CalendarSchedules component. - */ -export type Props = { - style?: React.CSSProperties; - dummySchedules?: UserSchedule[]; - dummyActiveIndex?: number; -}; - /** * Renders a component that displays a list of schedules. * * @param props - The component props. * @returns The rendered component. */ -export function CalendarSchedules({ style, dummySchedules, dummyActiveIndex }: Props) { - const [activeScheduleIndex, setActiveScheduleIndex] = useState(0); - const [newSchedule, setNewSchedule] = useState(''); - const [activeSchedule, schedules] = useSchedules(); - - useEffect(() => { - const index = schedules.findIndex(schedule => schedule.id === activeSchedule.id); - if (index !== -1) { - setActiveScheduleIndex(index); - } - }, [activeSchedule, schedules]); - - const handleKeyDown = event => { - if (event.code === 'Enter') { - background.createSchedule({ scheduleName: newSchedule }).then(() => { - setNewSchedule(''); - }); - } - }; - - const handleScheduleInputChange = (e: React.ChangeEvent) => { - setNewSchedule(e.target.value); - }; - - const fixBuildError = { - dummySchedules, - dummyActiveIndex, - }; - console.log(fixBuildError); +export function CalendarSchedules() { + const [, schedules] = useSchedules(); return ( -
+
MY SCHEDULES -
- - - -
+
)} -
); diff --git a/src/views/components/calendar/ImportantLinks.tsx b/src/views/components/calendar/ImportantLinks.tsx index 2a8125eb..5e205b6b 100644 --- a/src/views/components/calendar/ImportantLinks.tsx +++ b/src/views/components/calendar/ImportantLinks.tsx @@ -52,7 +52,7 @@ export default function ImportantLinks({ className }: Props): JSX.Element { diff --git a/src/views/components/common/Dialog/Dialog.tsx b/src/views/components/common/Dialog/Dialog.tsx index 01ed8adb..c3ffee9d 100644 --- a/src/views/components/common/Dialog/Dialog.tsx +++ b/src/views/components/common/Dialog/Dialog.tsx @@ -46,7 +46,7 @@ export default function Dialog(props: PropsWithChildren): JSX.Eleme
diff --git a/src/views/components/common/ExtensionRoot/ExtensionRoot.tsx b/src/views/components/common/ExtensionRoot/ExtensionRoot.tsx index bc434e1e..71fa719c 100644 --- a/src/views/components/common/ExtensionRoot/ExtensionRoot.tsx +++ b/src/views/components/common/ExtensionRoot/ExtensionRoot.tsx @@ -3,18 +3,21 @@ import 'uno.css'; import type TabInfoMessages from '@shared/messages/TabInfoMessages'; import { MessageListener } from 'chrome-extension-toolkit'; +import clsx from 'clsx'; import React, { useEffect } from 'react'; import styles from './ExtensionRoot.module.scss'; interface Props { testId?: string; + className?: string; } /** * A wrapper component for the extension elements that adds some basic styling to them */ export default function ExtensionRoot(props: React.PropsWithChildren): JSX.Element { + // TODO: move out of ExtensionRoot useEffect(() => { const tabInfoListener = new MessageListener({ getTabInfo: ({ sendResponse }) => { @@ -31,7 +34,7 @@ export default function ExtensionRoot(props: React.PropsWithChildren): JS }, []); return ( -
+
{props.children}
); diff --git a/src/views/components/common/LogoIcon.tsx b/src/views/components/common/LogoIcon.tsx index 94b793e5..01012bac 100644 --- a/src/views/components/common/LogoIcon.tsx +++ b/src/views/components/common/LogoIcon.tsx @@ -1,9 +1,9 @@ import type { SVGProps } from 'react'; import React from 'react'; -export function LogoIcon(props: SVGProps) { +export function LogoIcon(props: SVGProps): JSX.Element { return ( - + @@ -11,3 +11,27 @@ export function LogoIcon(props: SVGProps) { ); } + +export function SmallLogo(): JSX.Element { + return ( +
+ +
+

UT Registration

+

Plus

+
+
+ ); +} + +export function LargeLogo(): JSX.Element { + return ( +
+ +
+

UT Registration

+

Plus

+
+
+ ); +} diff --git a/src/views/components/common/ScheduleListItem/ScheduleListItem.tsx b/src/views/components/common/ScheduleListItem/ScheduleListItem.tsx index 3a0ec65e..2e17828e 100644 --- a/src/views/components/common/ScheduleListItem/ScheduleListItem.tsx +++ b/src/views/components/common/ScheduleListItem/ScheduleListItem.tsx @@ -1,9 +1,12 @@ +import deleteSchedule from '@pages/background/lib/deleteSchedule'; +import renameSchedule from '@pages/background/lib/renameSchedule'; import type { UserSchedule } from '@shared/types/UserSchedule'; import Text from '@views/components/common/Text/Text'; import useSchedules from '@views/hooks/useSchedules'; import clsx from 'clsx'; -import React, { useMemo } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; +import XIcon from '~icons/material-symbols/close'; import DragIndicatorIcon from '~icons/material-symbols/drag-indicator'; /** @@ -19,31 +22,80 @@ export type Props = { /** * This is a reusable dropdown component that can be used to toggle the visiblity of information */ -export default function ScheduleListItem({ style, schedule, dragHandleProps, onClick }: Props): JSX.Element { +export default function ScheduleListItem({ schedule, dragHandleProps, onClick }: Props): JSX.Element { const [activeSchedule] = useSchedules(); + const [isEditing, setIsEditing] = useState(false); + const [editorValue, setEditorValue] = useState(schedule.name); + + const editorRef = React.useRef(null); + const { current: editor } = editorRef; + useEffect(() => { + setEditorValue(schedule.name); + + if (isEditing && editor) { + editor.focus(); + editor.setSelectionRange(0, editor.value.length); + } + }, [isEditing, schedule.name, editor]); const isActive = useMemo(() => activeSchedule.id === schedule.id, [activeSchedule, schedule]); + const handleBlur = () => { + if (editorValue.trim() !== '') { + schedule.name = editorValue.trim(); + renameSchedule(schedule.id, schedule.name); + } + + setIsEditing(false); + }; + return ( -
-
  • -
    +
    +
  • +
    + +
    +
    !isEditing && onClick(...e)} > - -
    -
    - {schedule.name} + {isEditing && ( + setEditorValue(e.target.value)} + onKeyDown={e => { + if (e.key === 'Enter') handleBlur(); + if (e.key === 'Escape') { + setIsEditing(false); + } + }} + onBlur={handleBlur} + ref={editorRef} + /> + )} + {!isEditing && ( + setIsEditing(true)}> + {schedule.name} + + )} +
    +
    + deleteSchedule(schedule.id)} + />
  • diff --git a/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx b/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx index d537b610..948084a3 100644 --- a/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx +++ b/src/views/components/common/ScheduleTotalHoursAndCourses/ScheduleTotalHoursAndCourses.tsx @@ -21,14 +21,14 @@ export default function ScheduleTotalHoursAndCourses({ totalCourses, }: ScheduleTotalHoursAndCoursesProps): JSX.Element { return ( -
    - +
    + {`${scheduleName}: `} - {totalHours} {totalHours === 1 ? 'HOUR' : 'HOURS'} - - {totalCourses} {totalCourses === 1 ? 'COURSE' : 'COURSES'} + {totalHours} {totalHours === 1 ? 'Hour' : 'Hours'} + + {totalCourses} {totalCourses === 1 ? 'Course' : 'Courses'}
    diff --git a/src/views/components/common/Text/Text.module.scss b/src/views/components/common/Text/Text.module.scss index 7fd48d68..c4fa009b 100644 --- a/src/views/components/common/Text/Text.module.scss +++ b/src/views/components/common/Text/Text.module.scss @@ -9,11 +9,13 @@ .mini { font-size: 0.79rem; font-weight: 500; + letter-spacing: 0; } .small { font-size: 0.88875rem; font-weight: 500; + letter-spacing: 0; } .p { @@ -25,11 +27,13 @@ .h4 { font-size: 1.125rem; font-weight: 500; + letter-spacing: 0; } .h3-course { font-size: 0.6875rem; font-weight: 400; + letter-spacing: 0; line-height: 100%; /* 0.6875rem */ } @@ -37,6 +41,7 @@ font-size: 1.26563rem; font-weight: 600; text-transform: uppercase; + letter-spacing: 0; } .h2-course { @@ -49,16 +54,19 @@ .h2 { font-size: 1.42375rem; font-weight: 500; + letter-spacing: 0; } .h1-course { font-size: 1rem; font-weight: 600; text-transform: capitalize; + letter-spacing: 0; } .h1 { font-size: 1.60188rem; font-weight: 700; text-transform: uppercase; + letter-spacing: 0; } diff --git a/src/views/components/common/Text/Text.tsx b/src/views/components/common/Text/Text.tsx index 6fdb45d3..fb16679b 100644 --- a/src/views/components/common/Text/Text.tsx +++ b/src/views/components/common/Text/Text.tsx @@ -1,6 +1,6 @@ import type { PropsOf, ReactTag } from '@headlessui/react/dist/types'; import clsx from 'clsx'; -import type { ElementType, ReactNode } from 'react'; +import type { ElementType, ReactNode, Ref } from 'react'; import React from 'react'; import styles from './Text.module.scss'; @@ -13,6 +13,7 @@ type CleanProps = { as?: TTag; children?: ReactNode; + ref?: React.ForwardedRef>; }; type AsProps = CleanProps & OurProps & TOverrides; @@ -36,14 +37,14 @@ export type TextProps = PropsOf['classN /** * A reusable Text component with props that build on top of the design system for the extension */ -export default function Text({ - as, - className, - variant, - ...rest -}: TextProps): JSX.Element { +function Text( + { as, className, variant, ...rest }: TextProps, + ref: Ref +): JSX.Element { const Comp = as || 'span'; const mergedClassName = clsx(styles.text, styles[variant || 'p'], className); - return ; + return ; } + +export default React.forwardRef(Text) as typeof Text; diff --git a/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx b/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx index fcaf0ba0..07ec926d 100644 --- a/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx +++ b/src/views/components/injected/CourseCatalogInjectedPopup/HeadingAndActions.tsx @@ -103,10 +103,10 @@ export default function HeadingAndActions({ course, activeSchedule, onClose }: H
    - + {courseName} - + ({department} {courseNumber})