From 7560d46d7aa2b68f4ec9b7158d1fc73a6d438193 Mon Sep 17 00:00:00 2001 From: Jay Wu Date: Mon, 30 Dec 2024 01:53:33 -0800 Subject: [PATCH] fix: add copy, rename, and delete as unsaved actions properly (#1091) --- .../src/actions/ActionTypesStore.ts | 31 +++++++++++++++- .../antalmanac/src/actions/AppStoreActions.ts | 8 ++--- .../EditSchedule/ScheduleNameDialog.tsx | 2 +- .../src/components/dialogs/AddSchedule.tsx | 4 +-- .../src/components/dialogs/CopySchedule.tsx | 2 +- .../src/components/dialogs/RenameSchedule.tsx | 2 +- apps/antalmanac/src/stores/AppStore.ts | 35 +++++++++++++++---- apps/antalmanac/src/stores/Schedules.ts | 24 +++++++------ 8 files changed, 81 insertions(+), 27 deletions(-) diff --git a/apps/antalmanac/src/actions/ActionTypesStore.ts b/apps/antalmanac/src/actions/ActionTypesStore.ts index 0284234ef..6f24e07e7 100644 --- a/apps/antalmanac/src/actions/ActionTypesStore.ts +++ b/apps/antalmanac/src/actions/ActionTypesStore.ts @@ -57,8 +57,25 @@ export interface ClearScheduleAction { type: 'clearSchedule'; } +export interface AddScheduleAction { + type: 'addSchedule'; + newScheduleName: string; +} + +export interface RenameScheduleAction { + type: 'renameSchedule'; + scheduleIndex: number; + newScheduleName: string; +} + +export interface DeleteScheduleAction { + type: 'deleteSchedule'; + scheduleIndex: number; +} + export interface CopyScheduleAction { type: 'copySchedule'; + scheduleIndex: number; newScheduleName: string; } @@ -77,6 +94,9 @@ export type ActionType = | EditCustomEventAction | ChangeCustomEventColorAction | ClearScheduleAction + | AddScheduleAction + | RenameScheduleAction + | DeleteScheduleAction | CopyScheduleAction | ChangeCourseColorAction | UndoAction; @@ -158,8 +178,17 @@ class ActionTypesStore extends EventEmitter { case 'clearSchedule': AppStore.schedule.clearCurrentSchedule(); break; + case 'addSchedule': + AppStore.schedule.addNewSchedule(action.newScheduleName); + break; + case 'renameSchedule': + AppStore.schedule.renameSchedule(action.scheduleIndex, action.newScheduleName); + break; case 'copySchedule': - AppStore.schedule.copySchedule(action.newScheduleName); + AppStore.schedule.copySchedule(action.scheduleIndex, action.newScheduleName); + break; + case 'deleteSchedule': + AppStore.schedule.deleteSchedule(action.scheduleIndex); break; default: break; diff --git a/apps/antalmanac/src/actions/AppStoreActions.ts b/apps/antalmanac/src/actions/AppStoreActions.ts index e54a5be49..912bae61c 100644 --- a/apps/antalmanac/src/actions/AppStoreActions.ts +++ b/apps/antalmanac/src/actions/AppStoreActions.ts @@ -250,14 +250,14 @@ export const changeCourseColor = (sectionCode: string, term: string, newColor: s AppStore.changeCourseColor(sectionCode, term, newColor); }; -export const copySchedule = (newScheduleName: string, options?: CopyScheduleOptions) => { +export const copySchedule = (scheduleIndex: number, newScheduleName: string, options?: CopyScheduleOptions) => { logAnalytics({ category: analyticsEnum.addedClasses.title, action: analyticsEnum.addedClasses.actions.COPY_SCHEDULE, }); try { - AppStore.copySchedule(newScheduleName); + AppStore.copySchedule(scheduleIndex, newScheduleName); options?.onSuccess(newScheduleName); } catch (error) { options?.onError(newScheduleName); @@ -268,8 +268,8 @@ export const addSchedule = (scheduleName: string) => { AppStore.addSchedule(scheduleName); }; -export const renameSchedule = (scheduleName: string, scheduleIndex: number) => { - AppStore.renameSchedule(scheduleName, scheduleIndex); +export const renameSchedule = (scheduleIndex: number, scheduleName: string) => { + AppStore.renameSchedule(scheduleIndex, scheduleName); }; export const deleteSchedule = (scheduleIndex: number) => { diff --git a/apps/antalmanac/src/components/Calendar/Toolbar/EditSchedule/ScheduleNameDialog.tsx b/apps/antalmanac/src/components/Calendar/Toolbar/EditSchedule/ScheduleNameDialog.tsx index ee6df1779..f565dc634 100644 --- a/apps/antalmanac/src/components/Calendar/Toolbar/EditSchedule/ScheduleNameDialog.tsx +++ b/apps/antalmanac/src/components/Calendar/Toolbar/EditSchedule/ScheduleNameDialog.tsx @@ -77,7 +77,7 @@ const ScheduleNameDialog = forwardRef((props: ScheduleNameDialogProps, ref) => { onClose?.(); if (rename) { - renameSchedule(scheduleName, scheduleRenameIndex as number); // typecast works b/c this function only runs when `const rename = scheduleRenameIndex !== undefined` is true. + renameSchedule(scheduleRenameIndex as number, scheduleName); // typecast works b/c this function only runs when `const rename = scheduleRenameIndex !== undefined` is true. } else { addSchedule(scheduleName); } diff --git a/apps/antalmanac/src/components/dialogs/AddSchedule.tsx b/apps/antalmanac/src/components/dialogs/AddSchedule.tsx index ae4bc6305..44ec47ebf 100644 --- a/apps/antalmanac/src/components/dialogs/AddSchedule.tsx +++ b/apps/antalmanac/src/components/dialogs/AddSchedule.tsx @@ -13,7 +13,7 @@ function AddScheduleDialog({ onClose, onKeyDown, ...props }: DialogProps) { const isDark = useThemeStore((store) => store.isDark); const [name, setName] = useState( - AppStore.getNextScheduleName(AppStore.getDefaultScheduleName(), AppStore.getScheduleNames().length) + AppStore.getNextScheduleName(() => AppStore.getScheduleNames().length, AppStore.getDefaultScheduleName()) ); const handleCancel = () => { @@ -48,7 +48,7 @@ function AddScheduleDialog({ onClose, onKeyDown, ...props }: DialogProps) { }; const handleScheduleNamesChange = useCallback(() => { - setName(AppStore.getNextScheduleName(AppStore.getDefaultScheduleName(), AppStore.getScheduleNames().length)); + setName(AppStore.getNextScheduleName(AppStore.getScheduleNames().length, AppStore.getDefaultScheduleName())); }, []); useEffect(() => { diff --git a/apps/antalmanac/src/components/dialogs/CopySchedule.tsx b/apps/antalmanac/src/components/dialogs/CopySchedule.tsx index 5a9da35d5..ee3496822 100644 --- a/apps/antalmanac/src/components/dialogs/CopySchedule.tsx +++ b/apps/antalmanac/src/components/dialogs/CopySchedule.tsx @@ -31,7 +31,7 @@ function CopyScheduleDialog(props: CopyScheduleDialogProps) { }, [onClose]); const handleCopy = useCallback(() => { - copySchedule(name); + copySchedule(index, name); onClose?.({}, 'escapeKeyDown'); }, [onClose, name]); diff --git a/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx b/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx index aca9c387a..73e075a41 100644 --- a/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx +++ b/apps/antalmanac/src/components/dialogs/RenameSchedule.tsx @@ -45,7 +45,7 @@ function RenameScheduleDialog(props: ScheduleNameDialogProps) { }, []); const submitName = useCallback(() => { - renameSchedule(name, index); + renameSchedule(index, name); onClose?.({}, 'escapeKeyDown'); }, [onClose, name, index]); diff --git a/apps/antalmanac/src/stores/AppStore.ts b/apps/antalmanac/src/stores/AppStore.ts index b9ac5c496..be02dcb9f 100644 --- a/apps/antalmanac/src/stores/AppStore.ts +++ b/apps/antalmanac/src/stores/AppStore.ts @@ -13,8 +13,11 @@ import type { ChangeCustomEventColorAction, ClearScheduleAction, CopyScheduleAction, + RenameScheduleAction, + DeleteScheduleAction, ChangeCourseColorAction, UndoAction, + AddScheduleAction, } from '$actions/ActionTypesStore'; import { CalendarEvent, CourseEvent } from '$components/Calendar/CourseCalendarEvent'; import { SnackbarPosition } from '$components/NotificationSnackbar'; @@ -71,8 +74,8 @@ class AppStore extends EventEmitter { } } - getNextScheduleName(newScheduleName: string, scheduleIndex: number) { - return this.schedule.getNextScheduleName(newScheduleName, scheduleIndex); + getNextScheduleName(scheduleIndex: number, newScheduleName: string) { + return this.schedule.getNextScheduleName(scheduleIndex, newScheduleName); } getDefaultScheduleName() { @@ -280,13 +283,26 @@ class AppStore extends EventEmitter { // another key/value pair to keep track of the section codes for that schedule, // and redirect the user to the new schedule this.schedule.addNewSchedule(newScheduleName); + this.unsavedChanges = true; + const action: AddScheduleAction = { + type: 'addSchedule', + newScheduleName: newScheduleName, + }; + actionTypesStore.autoSaveSchedule(action); this.emit('scheduleNamesChange'); this.emit('currentScheduleIndexChange'); this.emit('scheduleNotesChange'); } - renameSchedule(scheduleName: string, scheduleIndex: number) { - this.schedule.renameSchedule(scheduleName, scheduleIndex); + renameSchedule(scheduleIndex: number, newScheduleName: string) { + this.schedule.renameSchedule(scheduleIndex, newScheduleName); + this.unsavedChanges = true; + const action: RenameScheduleAction = { + type: 'renameSchedule', + scheduleIndex: scheduleIndex, + newScheduleName: newScheduleName, + }; + actionTypesStore.autoSaveSchedule(action); this.emit('scheduleNamesChange'); } @@ -295,11 +311,12 @@ class AppStore extends EventEmitter { window.localStorage.removeItem('unsavedActions'); } - copySchedule(newScheduleName: string) { - this.schedule.copySchedule(newScheduleName); + copySchedule(scheduleIndex: number, newScheduleName: string) { + this.schedule.copySchedule(scheduleIndex, newScheduleName); this.unsavedChanges = true; const action: CopyScheduleAction = { type: 'copySchedule', + scheduleIndex: scheduleIndex, newScheduleName: newScheduleName, }; actionTypesStore.autoSaveSchedule(action); @@ -364,6 +381,12 @@ class AppStore extends EventEmitter { deleteSchedule(scheduleIndex: number) { this.schedule.deleteSchedule(scheduleIndex); + this.unsavedChanges = true; + const action: DeleteScheduleAction = { + type: 'deleteSchedule', + scheduleIndex: scheduleIndex, + }; + actionTypesStore.autoSaveSchedule(action); this.emit('scheduleNamesChange'); this.emit('currentScheduleIndexChange'); this.emit('addedCoursesChange'); diff --git a/apps/antalmanac/src/stores/Schedules.ts b/apps/antalmanac/src/stores/Schedules.ts index 8aedc7657..5ddd1a299 100644 --- a/apps/antalmanac/src/stores/Schedules.ts +++ b/apps/antalmanac/src/stores/Schedules.ts @@ -50,7 +50,7 @@ export class Schedules { this.skeletonSchedules = []; } - getNextScheduleName(newScheduleName: string, scheduleIndex: number) { + getNextScheduleName(scheduleIndex: number, newScheduleName: string) { const scheduleNames = this.getScheduleNames(); scheduleNames.splice(scheduleIndex, 1); let nextScheduleName = newScheduleName; @@ -108,7 +108,7 @@ export class Schedules { this.addUndoState(); const scheduleNoteId = Math.random(); this.schedules.push({ - scheduleName: this.getNextScheduleName(newScheduleName, this.getNumberOfSchedules()), + scheduleName: this.getNextScheduleName(this.getNumberOfSchedules(), newScheduleName), courses: [], customEvents: [], scheduleNoteId: scheduleNoteId, @@ -122,9 +122,9 @@ export class Schedules { * Rename schedule with the specified index. * @param newScheduleName The name of the new schedule. If a schedule with the same name already exists, a number will be appended to the name. */ - renameSchedule(newScheduleName: string, scheduleIndex: number) { + renameSchedule(scheduleIndex: number, newScheduleName: string) { this.addUndoState(); - this.schedules[scheduleIndex].scheduleName = this.getNextScheduleName(newScheduleName, scheduleIndex); + this.schedules[scheduleIndex].scheduleName = this.getNextScheduleName(scheduleIndex, newScheduleName); } /** @@ -146,11 +146,11 @@ export class Schedules { } /** - * Copy the current schedule to a newly created schedule with the specified name. + * Copy the schedule at the provided index to a newly created schedule with the specified name. */ - copySchedule(newScheduleName: string) { + copySchedule(scheduleIndex: number, newScheduleName: string) { this.addNewSchedule(newScheduleName); - this.currentScheduleIndex = this.previousStates[this.previousStates.length - 1].scheduleIndex; // return to previous schedule index for copying + this.currentScheduleIndex = scheduleIndex; // temporarily set current schedule to the one being copied const to = this.getNumberOfSchedules() - 1; for (const course of this.getCurrentCourses()) { @@ -158,10 +158,10 @@ export class Schedules { } for (const customEvent of this.getCurrentCustomEvents()) { - this.addCustomEvent(customEvent, [to]); + this.addCustomEvent(customEvent, [to], false); } + this.currentScheduleIndex = this.previousStates[this.previousStates.length - 1].scheduleIndex; // return to previously selected schedule index } - getCurrentCourses() { return this.schedules[this.currentScheduleIndex]?.courses || []; } @@ -339,8 +339,10 @@ export class Schedules { /** * Adds a new custom event to given indices */ - addCustomEvent(newCustomEvent: RepeatingCustomEvent, scheduleIndices: number[]) { - this.addUndoState(); + addCustomEvent(newCustomEvent: RepeatingCustomEvent, scheduleIndices: number[], addUndoState = true) { + if (addUndoState) { + this.addUndoState(); + } for (const scheduleIndex of scheduleIndices) { if (!this.doesCustomEventExistInSchedule(newCustomEvent.customEventID, scheduleIndex)) { this.schedules[scheduleIndex].customEvents.push(newCustomEvent);