feat: schedule list item action menu (#230)

* feat: action menu for schedule list item

* feat: schedule action menu functionality

* feat: dialog provider popups for delete

* feat: duplicate schedule satiesfies type

* refactor: change non-null assertion to early return for rename schedule

* refactor: move schedule list item dialog providers to util file

* style: run prettier

* chore: inline object with satisfies operator

* fix: border issues

* style: change popups to match figma

* fix: update import for schedule list item dialog providers

* style: change dropdown text style to match figma

* fix: add back dialog context

* style: rounded edges when hovering over action + soften border color

* chore: cleanup and improve styling

* fix: dialog in popupmain

---------

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
Co-authored-by: Razboy20 <razboy20@gmail.com>
This commit is contained in:
Casey Charleston
2024-10-04 23:15:51 -05:00
committed by GitHub
parent 9ec05ef764
commit 15fc3699cf
10 changed files with 325 additions and 145 deletions

View File

@@ -17,6 +17,7 @@ import RefreshIcon from '~icons/material-symbols/refresh';
import SettingsIcon from '~icons/material-symbols/settings';
import CourseStatus from './common/CourseStatus';
import DialogProvider from './common/DialogProvider/DialogProvider';
import { SmallLogo } from './common/LogoIcon';
import PopupCourseBlock from './common/PopupCourseBlock';
import ScheduleDropdown from './common/ScheduleDropdown';
@@ -50,111 +51,116 @@ export default function PopupMain(): JSX.Element {
return (
<ExtensionRoot>
<div className='h-screen max-h-full flex flex-col bg-white'>
<div className='p-5 py-3.5'>
<div className='flex items-center justify-between bg-white'>
<SmallLogo />
<div className='flex items-center gap-2.5'>
<button className='bg-ut-burntorange px-2 py-1.25 btn' onClick={handleCalendarOpenOnClick}>
<CalendarIcon className='size-6 text-white' />
</button>
<button className='bg-transparent px-2 py-1.25 btn' onClick={handleOpenOptions}>
<SettingsIcon className='size-6 color-ut-black' />
</button>
<DialogProvider>
<div className='h-screen max-h-full flex flex-col bg-white'>
<div className='p-5 py-3.5'>
<div className='flex items-center justify-between bg-white'>
<SmallLogo />
<div className='flex items-center gap-2.5'>
<button
className='bg-ut-burntorange px-2 py-1.25 btn'
onClick={handleCalendarOpenOnClick}
>
<CalendarIcon className='size-6 text-white' />
</button>
<button className='bg-transparent px-2 py-1.25 btn' onClick={handleOpenOptions}>
<SettingsIcon className='size-6 color-ut-black' />
</button>
</div>
</div>
</div>
</div>
<Divider orientation='horizontal' size='100%' />
<div className='px-5 pb-2.5 pt-3.75'>
<ScheduleDropdown>
<List
draggables={schedules}
itemKey={schedule => schedule.id}
onReordered={reordered => {
const activeSchedule = getActiveSchedule();
const activeIndex = reordered.findIndex(s => s.id === activeSchedule.id);
<Divider orientation='horizontal' size='100%' />
<div className='px-5 pb-2.5 pt-3.75'>
<ScheduleDropdown>
<List
draggables={schedules}
itemKey={schedule => schedule.id}
onReordered={reordered => {
const activeSchedule = getActiveSchedule();
const activeIndex = reordered.findIndex(s => s.id === activeSchedule.id);
// don't care about the promise
UserScheduleStore.set('schedules', reordered);
UserScheduleStore.set('activeIndex', activeIndex);
}}
gap={10}
>
{(schedule, handleProps) => (
<ScheduleListItem
schedule={schedule}
onClick={() => {
switchSchedule(schedule.id);
}}
dragHandleProps={handleProps}
/>
)}
</List>
</ScheduleDropdown>
</div>
{activeSchedule?.courses?.length === 0 && (
<div className='max-w-64 flex flex-col items-center self-center gap-1.25 px-2 py-2'>
<Text variant='small' className='text-center text-ut-gray !font-normal'>
{funny}
</Text>
<Text variant='small' className='text-center text-black'>
(No courses added)
</Text>
// don't care about the promise
UserScheduleStore.set('schedules', reordered);
UserScheduleStore.set('activeIndex', activeIndex);
}}
gap={10}
>
{(schedule, handleProps) => (
<ScheduleListItem
schedule={schedule}
onClick={() => {
switchSchedule(schedule.id);
}}
dragHandleProps={handleProps}
/>
)}
</List>
</ScheduleDropdown>
</div>
)}
<div className='flex-1 self-stretch overflow-y-auto px-5'>
{activeSchedule?.courses?.length > 0 && (
<List
draggables={activeSchedule.courses}
onReordered={reordered => {
activeSchedule.courses = reordered;
replaceSchedule(getActiveSchedule(), activeSchedule);
}}
itemKey={e => e.uniqueId}
gap={10}
>
{(course, handleProps) => (
<PopupCourseBlock
key={course.uniqueId}
course={course}
colors={course.colors}
dragHandleProps={handleProps}
/>
)}
</List>
{activeSchedule?.courses?.length === 0 && (
<div className='max-w-64 flex flex-col items-center self-center gap-1.25 px-2 py-2'>
<Text variant='small' className='text-center text-ut-gray !font-normal'>
{funny}
</Text>
<Text variant='small' className='text-center text-black'>
(No courses added)
</Text>
</div>
)}
</div>
<div className='w-full flex flex-col items-center gap-1.25 p-5 pt-3.75'>
<div className='flex gap-2.5'>
{enableCourseStatusChips && (
<>
<CourseStatus status='WAITLISTED' size='mini' />
<CourseStatus status='CLOSED' size='mini' />
<CourseStatus status='CANCELLED' size='mini' />
</>
<div className='flex-1 self-stretch overflow-y-auto px-5'>
{activeSchedule?.courses?.length > 0 && (
<List
draggables={activeSchedule.courses}
onReordered={reordered => {
activeSchedule.courses = reordered;
replaceSchedule(getActiveSchedule(), activeSchedule);
}}
itemKey={e => e.uniqueId}
gap={10}
>
{(course, handleProps) => (
<PopupCourseBlock
key={course.uniqueId}
course={course}
colors={course.colors}
dragHandleProps={handleProps}
/>
)}
</List>
)}
</div>
{enableCourseRefreshing && (
<div className='inline-flex items-center self-center gap-1'>
<Text variant='mini' className='text-ut-gray !font-normal'>
DATA LAST UPDATED: {getUpdatedAtDateTimeString(activeSchedule.updatedAt)}
</Text>
<button
className='h-4 w-4 bg-transparent p-0 btn'
onClick={() => {
setIsRefreshing(true);
}}
>
<RefreshIcon
className={clsx('h-4 w-4 text-ut-black animate-duration-800', {
'animate-spin': isRefreshing,
})}
/>
</button>
<div className='w-full flex flex-col items-center gap-1.25 p-5 pt-3.75'>
<div className='flex gap-2.5'>
{enableCourseStatusChips && (
<>
<CourseStatus status='WAITLISTED' size='mini' />
<CourseStatus status='CLOSED' size='mini' />
<CourseStatus status='CANCELLED' size='mini' />
</>
)}
</div>
)}
{enableCourseRefreshing && (
<div className='inline-flex items-center self-center gap-1'>
<Text variant='mini' className='text-ut-gray !font-normal'>
DATA LAST UPDATED: {getUpdatedAtDateTimeString(activeSchedule.updatedAt)}
</Text>
<button
className='h-4 w-4 bg-transparent p-0 btn'
onClick={() => {
setIsRefreshing(true);
}}
>
<RefreshIcon
className={clsx('h-4 w-4 text-ut-black animate-duration-800', {
'animate-spin': isRefreshing,
})}
/>
</button>
</div>
)}
</div>
</div>
</div>
</DialogProvider>
</ExtensionRoot>
);
}