Skip to content

Commit

Permalink
fix: List now keeps track of state when existing items are switched, …
Browse files Browse the repository at this point in the history
…while adding new items to the end
  • Loading branch information
knownotunknown committed Feb 28, 2024
1 parent 0003585 commit 8d528b1
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 99 deletions.
91 changes: 16 additions & 75 deletions src/stories/components/calendar/CalendarGrid.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
<<<<<<< Updated upstream
import { Meta, StoryObj } from '@storybook/react';
=======
import { Course, Status } from '@shared/types/Course';
import { getCourseColors } from '@shared/util/colors';
import type { Meta, StoryObj } from '@storybook/react';
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
import type { Serialized } from 'chrome-extension-toolkit';
import { CourseMeeting, DAY_MAP } from 'src/shared/types/CourseMeeting';
import { CourseSchedule } from 'src/shared/types/CourseSchedule';
import Instructor from 'src/shared/types/Instructor';
import { UserSchedule } from 'src/shared/types/UserSchedule';
>>>>>>> Stashed changes
import CalendarGrid from 'src/views/components/calendar/CalendarGrid/CalendarGrid';
import { Status } from '@shared/types/Course';
import { getCourseColors } from '@shared/util/colors';
import type { Meta, StoryObj } from '@storybook/react';
import CalendarGrid from '@views/components/calendar/CalendarGrid/CalendarGrid';
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';

import { ExampleCourse } from '../PopupCourseBlock.stories';

const meta = {
title: 'Components/Calendar/CalendarGrid',
component: CalendarGrid,
Expand All @@ -30,62 +19,7 @@ const meta = {
} satisfies Meta<typeof CalendarGrid>;
export default meta;

<<<<<<< Updated upstream
const testData: CalendarGridCourse[] = [
=======
const exampleCourse: Course = new Course({
uniqueId: 50805,
number: '314',
fullName: 'C S 314 DATA STRUCTURES',
courseName: 'DATA STRUCTURES',
department: 'C S',
creditHours: 3,
status: Status.OPEN,
instructors: [
new Instructor({ fullName: 'SCOTT, MICHAEL', firstName: 'MICHAEL', lastName: 'SCOTT', middleInitial: 'D' }),
],
isReserved: true,
description: [
'Second part of a two-part sequence in programming. Introduction to specifications, simple unit testing, and debugging; building and using canonical data structures; algorithm analysis and reasoning techniques such as assertions and invariants.',
'Computer Science 314 and 314H may not both be counted.',
'BVO 311C and 312H may not both be counted.',
'Prerequisite: Computer Science 312 or 312H with a grade of at least C-.',
'May be counted toward the Quantitative Reasoning flag requirement.',
],
schedule: new CourseSchedule({
meetings: [
new CourseMeeting({
days: [DAY_MAP.T, DAY_MAP.TH],
startTime: 480,
endTime: 570,
location: { building: 'UTC', room: '123' },
}),
new CourseMeeting({
days: [DAY_MAP.TH],
startTime: 570,
endTime: 630,
location: { building: 'JES', room: '123' },
}),
],
}),
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20242/12345/',
flags: ['Writing', 'Independent Inquiry'],
instructionMode: 'In Person',
semester: {
code: '12345',
year: 2024,
season: 'Spring',
},
});

const exampleSchedule = new UserSchedule({
name: 'Example Schedule',
courses: [exampleCourse],
hours: 3,
} as Serialized<UserSchedule>);

export const exampleCalendarGridCourses: CalendarGridCourse[] = [
>>>>>>> Stashed changes
{
calendarGridPoint: {
dayIndex: 4,
Expand All @@ -98,6 +32,7 @@ export const exampleCalendarGridCourses: CalendarGridCourse[] = [
status: Status.OPEN,
colors: getCourseColors('emerald', 500),
},
course: ExampleCourse,
},
{
calendarGridPoint: {
Expand All @@ -111,6 +46,7 @@ export const exampleCalendarGridCourses: CalendarGridCourse[] = [
status: Status.OPEN,
colors: getCourseColors('emerald', 500),
},
course: ExampleCourse,
},
{
calendarGridPoint: {
Expand All @@ -124,6 +60,7 @@ export const exampleCalendarGridCourses: CalendarGridCourse[] = [
status: Status.CLOSED,
colors: getCourseColors('emerald', 500),
},
course: ExampleCourse,
},
{
calendarGridPoint: {
Expand All @@ -137,6 +74,7 @@ export const exampleCalendarGridCourses: CalendarGridCourse[] = [
status: Status.OPEN,
colors: getCourseColors('emerald', 500),
},
course: ExampleCourse,
},
{
calendarGridPoint: {
Expand All @@ -150,6 +88,7 @@ export const exampleCalendarGridCourses: CalendarGridCourse[] = [
status: Status.CLOSED,
colors: getCourseColors('emerald', 500),
},
course: ExampleCourse,
},
{
calendarGridPoint: {
Expand All @@ -163,27 +102,29 @@ export const exampleCalendarGridCourses: CalendarGridCourse[] = [
status: Status.CLOSED,
colors: getCourseColors('emerald', 500),
},
course: ExampleCourse,
},
{
calendarGridPoint: {
dayIndex: 1,
startIndex: 11,
endIndex: 13,
startIndex: 10,
endIndex: 12,
},
componentProps: {
courseDeptAndInstr: 'Course 4',
timeAndLocation: '10:00 AM - 11:00 AM, Room 102',
status: Status.CLOSED,
colors: getCourseColors('emerald', 500),
},
course: ExampleCourse,
},
]; */
];

type Story = StoryObj<typeof meta>;

/* export const Default: Story = {
export const Default: Story = {
args: {
saturdayClass: true,
courseCells: exampleCalendarGridCourses,
courseCells: testData,
},
}; */
};
1 change: 0 additions & 1 deletion src/views/components/PopupMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export default function PopupMain() {
));

const handleOpenOptions = async () => {
// Not sure if it's bad practice to export this
const url = chrome.runtime.getURL('/src/pages/options/index.html');
await openTabFromContentScript(url);
};
Expand Down
1 change: 0 additions & 1 deletion src/views/components/calendar/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { CalendarSchedules } from '@views/components/calendar/CalendarSchedules/
import ImportantLinks from '@views/components/calendar/ImportantLinks';
import React from 'react';
import type { Course } from 'src/shared/types/Course';
import { UserSchedule } from 'src/shared/types/UserSchedule';
import { ExampleCourse } from 'src/stories/components/PopupCourseBlock.stories';
import { useFlattenedCourseSchedule } from 'src/views/hooks/useFlattenedCourseSchedule';

Expand Down
4 changes: 2 additions & 2 deletions src/views/components/calendar/CalendarGrid/CalendarGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseC
<div
key={`${block}`}
style={{
gridColumn: `${block.calendarGridPoint.dayIndex + 1}`,
gridRow: `${block.calendarGridPoint.startIndex + 1} / ${block.calendarGridPoint.endIndex + 1}`,
gridColumn: `${block.calendarGridPoint.dayIndex + 2}`,
gridRow: `${block.calendarGridPoint.startIndex} / ${block.calendarGridPoint.endIndex}`,
width: `calc(100% / ${block.totalColumns})`,
marginLeft: `calc(100% * ${(block.gridColumnStart - 1) / block.totalColumns})`,
padding: '0px 10px 4px 0px',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import ScheduleTotalHoursAndCourses from '@views/components/common/ScheduleTotal
import Text from '@views/components/common/Text/Text';
import React from 'react';
import calIcon from 'src/assets/logo.png';
import { openTabFromContentScript } from 'src/views/lib/openNewTabFromContentScript';

import MenuIcon from '~icons/material-symbols/menu';
import RedoIcon from '~icons/material-symbols/redo';
import SettingsIcon from '~icons/material-symbols/settings';
import UndoIcon from '~icons/material-symbols/undo';

import handleOpenOptions from '../../PopupMain';
import UndoIcon from '~icons/material-symbols/undo';
const handleOpenOptions = async () => {
const url = chrome.runtime.getURL('/src/pages/options/index.html');
await openTabFromContentScript(url);
};

const CalendarHeader = ( { totalHours, totalCourses, scheduleName } ) => (
<div className='min-h-79px min-w-672px w-full flex px-0 py-15'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type { UserSchedule } from '@shared/types/UserSchedule';
import React, { useState, useEffect } from 'react';
import useSchedules from 'src/views/hooks/useSchedules';
import React, { useEffect,useState } from 'react';
import createSchedule from 'src/pages/background/lib/createSchedule';
import switchSchedule from 'src/pages/background/lib/switchSchedule';
import useSchedules from 'src/views/hooks/useSchedules';

import AddSchedule from '~icons/material-symbols/add';

import List from '../../common/List/List';
import ScheduleListItem from '../../common/ScheduleListItem/ScheduleListItem';
import Text from '../../common/Text/Text';
import switchSchedule from 'src/pages/background/lib/switchSchedule';

export type Props = {
style?: React.CSSProperties;
Expand Down Expand Up @@ -48,15 +50,13 @@ export function CalendarSchedules(props: Props) {
switchSchedule(schedules[index].name);
};

const scheduleComponents = schedules.map((schedule, index) => {
return (
const scheduleComponents = schedules.map((schedule, index) => (
<ScheduleListItem
active={index === activeScheduleIndex}
name={schedule.name}
onClick={() => selectItem(index)}
/>
);
});
));

return (
<div style={{ ...props.style }} className='items-center'>
Expand Down
15 changes: 10 additions & 5 deletions src/views/components/common/List/List.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
import type { ReactElement } from 'react';
import React, { useCallback, useState } from 'react';
import React, { useCallback, useEffect,useState } from 'react';

/*
* Ctrl + f dragHandleProps on PopupCourseBlock.tsx for example implementation of drag handle (two lines of code)
Expand All @@ -19,9 +19,9 @@ export interface ListProps {
gap: number; // Impacts the spacing between items in the list
}

function initial(draggableElements: any[] = []) {
function initial(draggableElements: any[] = [], count: number) {
return draggableElements.map((element, index) => ({
id: `id:${index}`,
id: `id:${index + count}`,
content: element as ReactElement,
}));
}
Expand Down Expand Up @@ -83,10 +83,15 @@ const Row: React.FC<RowProps> = React.memo(({ data: { items, gap }, index, style
* <List draggableElements={elements} />
*/
const List: React.FC<ListProps> = ({ draggableElements, itemHeight, listHeight, listWidth, gap = 12 }: ListProps) => {
const [items, setItems] = useState(() => initial(draggableElements));
const [items, setItems] = useState(() => initial(draggableElements, 0));

useEffect(() => {
setItems(initial(draggableElements));
setItems((prevItems) => {
const prevItemIds = prevItems.map(item => item.id);
const newElements = draggableElements.filter((_, index) => !prevItemIds.includes(`id:${index}`));
const newItems = initial(newElements, prevItems.length);
return [...prevItems, ...newItems];
});
}, [draggableElements]);

const onDragEnd = useCallback(
Expand Down
31 changes: 25 additions & 6 deletions src/views/hooks/useFlattenedCourseSchedule.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { CalendarCourseCellProps } from '@views/components/calendar/CalendarCourseCell/CalendarCourseCell';
import type { Course, StatusType } from 'src/shared/types/Course';
import type { CourseMeeting, TimeStringOptions } from 'src/shared/types/CourseMeeting';
import type { CourseMeeting } from 'src/shared/types/CourseMeeting';
import type { UserSchedule } from 'src/shared/types/UserSchedule';

import useSchedules from './useSchedules';
Expand Down Expand Up @@ -113,7 +113,9 @@ function extractCourseInfo(course: Course) {
return { status, courseDeptAndInstr, meetings, course };
}

// Function to handle asynchronous (online) courses
/**
* Function to process each in-person class into its distinct meeting objects for calendar grid
*/
function processAsyncCourses({ courseDeptAndInstr, status, course }: { courseDeptAndInstr: string, status: StatusType, course: Course }) {
return [{
calendarGridPoint: {
Expand All @@ -133,7 +135,9 @@ function processAsyncCourses({ courseDeptAndInstr, status, course }: { courseDep
}];
}

// Function to process in-person meeting times and locations
/**
* Function to process each in-person class into its distinct meeting objects for calendar grid
*/
function processInPersonMeetings({ days, startTime, endTime, location }: CourseMeeting, { courseDeptAndInstr, status, course }) {
const time = getTimeString({ separator: '-', capitalize: true }, startTime, endTime);
const timeAndLocation = `${time} - ${location ? location.building : 'WB'}`;
Expand All @@ -156,7 +160,10 @@ function processInPersonMeetings({ days, startTime, endTime, location }: CourseM
}));
}

// Utility function to sort courses for the calendar grid

/**
* Utility function to sort courses for the calendar grid
*/
function sortCourses(a, b) {
if (a.calendarGridPoint.dayIndex !== b.calendarGridPoint.dayIndex) {
return a.calendarGridPoint.dayIndex - b.calendarGridPoint.dayIndex;
Expand All @@ -168,7 +175,9 @@ function sortCourses(a, b) {
}


// Utility function also present in CourseMeeting object. Wasn't being found at runtime, so I copied it over.
/**
* Utility function also present in CourseMeeting object. Wasn't being found at runtime, so I copied it over.
*/
function getTimeString(options: TimeStringOptions, startTime: number, endTime: number): string {
const startHour = Math.floor(startTime / 60);
const startMinute = startTime % 60;
Expand Down Expand Up @@ -205,4 +214,14 @@ function getTimeString(options: TimeStringOptions, startTime: number, endTime: n
}

return `${startTimeString} ${options.separator} ${endTimeString}`;
}
}

/**
* Options to control the format of the time string
*/
type TimeStringOptions = {
/** the separator between the start and end times */
separator: string;
/** capitalizes the AM/PM */
capitalize?: boolean;
};

0 comments on commit 8d528b1

Please sign in to comment.