Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicate calendar #1048

Merged
merged 12 commits into from
Nov 26, 2024
Merged
4 changes: 2 additions & 2 deletions apps/antalmanac/src/actions/ActionTypesStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export interface ClearScheduleAction {

export interface CopyScheduleAction {
type: 'copySchedule';
to: number;
newScheduleName: string;
}

export interface ChangeCourseColorAction {
Expand Down Expand Up @@ -159,7 +159,7 @@ class ActionTypesStore extends EventEmitter {
AppStore.schedule.clearCurrentSchedule();
break;
case 'copySchedule':
AppStore.schedule.copySchedule(action.to);
AppStore.schedule.copySchedule(action.newScheduleName);
break;
default:
break;
Expand Down
12 changes: 6 additions & 6 deletions apps/antalmanac/src/actions/AppStoreActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { removeLocalStorageUserId, setLocalStorageUserId } from '$lib/localStora
import AppStore from '$stores/AppStore';

export interface CopyScheduleOptions {
onSuccess: (index: number) => unknown;
onError: (index: number) => unknown;
onSuccess: (scheduleName: string) => unknown;
onError: (scheduleName: string) => unknown;
}

export const addCourse = (
Expand Down Expand Up @@ -250,17 +250,17 @@ export const changeCourseColor = (sectionCode: string, term: string, newColor: s
AppStore.changeCourseColor(sectionCode, term, newColor);
};

export const copySchedule = (to: number, options?: CopyScheduleOptions) => {
export const copySchedule = (newScheduleName: string, options?: CopyScheduleOptions) => {
logAnalytics({
category: analyticsEnum.addedClasses.title,
action: analyticsEnum.addedClasses.actions.COPY_SCHEDULE,
});

try {
AppStore.copySchedule(to);
options?.onSuccess(to);
AppStore.copySchedule(newScheduleName);
options?.onSuccess(newScheduleName);
} catch (error) {
options?.onError(to);
options?.onError(newScheduleName);
}
};

Expand Down
20 changes: 16 additions & 4 deletions apps/antalmanac/src/components/dialogs/AddSchedule.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField } from '@mui/material';
import type { DialogProps } from '@mui/material';
import { useState } from 'react';
import { useState, useEffect, useCallback } from 'react';

import { addSchedule } from '$actions/AppStoreActions';
import AppStore from '$stores/AppStore';
Expand All @@ -12,7 +12,9 @@ import { useThemeStore } from '$stores/SettingsStore';
function AddScheduleDialog({ onClose, onKeyDown, ...props }: DialogProps) {
const isDark = useThemeStore((store) => store.isDark);

const [name, setName] = useState(AppStore.getDefaultScheduleName());
const [name, setName] = useState(
AppStore.getNextScheduleName(AppStore.getDefaultScheduleName(), AppStore.getScheduleNames().length)
);

const handleCancel = () => {
onClose?.({}, 'escapeKeyDown');
Expand All @@ -24,7 +26,6 @@ function AddScheduleDialog({ onClose, onKeyDown, ...props }: DialogProps) {

const submitName = () => {
addSchedule(name);
setName(AppStore.schedule.getDefaultScheduleName());
onClose?.({}, 'escapeKeyDown');
};

Expand All @@ -46,6 +47,17 @@ function AddScheduleDialog({ onClose, onKeyDown, ...props }: DialogProps) {
}
};

const handleScheduleNamesChange = useCallback(() => {
setName(AppStore.getNextScheduleName(AppStore.getDefaultScheduleName(), AppStore.getScheduleNames().length));
}, []);

useEffect(() => {
AppStore.on('scheduleNamesChange', handleScheduleNamesChange);
return () => {
AppStore.off('scheduleNamesChange', handleScheduleNamesChange);
};
}, [handleScheduleNamesChange]);

return (
<Dialog onKeyDown={handleKeyDown} {...props}>
<DialogTitle>Add Schedule</DialogTitle>
Expand All @@ -60,7 +72,7 @@ function AddScheduleDialog({ onClose, onKeyDown, ...props }: DialogProps) {
<Button onClick={handleCancel} color={isDark ? 'secondary' : 'primary'}>
Cancel
</Button>
<Button onClick={submitName} variant="contained" color="primary" disabled={name.trim() === ''}>
<Button onClick={submitName} variant="contained" color="primary" disabled={name?.trim() === ''}>
Add Schedule
</Button>
</DialogActions>
Expand Down
45 changes: 12 additions & 33 deletions apps/antalmanac/src/components/dialogs/CopySchedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import {
DialogActions,
DialogContent,
DialogTitle,
MenuItem,
Select,
TextField,
type DialogProps,
} from '@mui/material';
import { SelectChangeEvent } from '@mui/material';
import { useState, useEffect, useCallback } from 'react';

import { copySchedule } from '$actions/AppStoreActions';
Expand All @@ -22,65 +20,46 @@ interface CopyScheduleDialogProps extends DialogProps {
function CopyScheduleDialog(props: CopyScheduleDialogProps) {
const { index } = props;
const { onClose } = props; // destructured separately for memoization.
const [scheduleNames, setScheduleNames] = useState(AppStore.getScheduleNames());
const [selectedSchedule, setSelectedSchedule] = useState<number>(0);
const [name, setName] = useState<string>(`Copy of ${AppStore.getScheduleNames()[index]}`);

const handleScheduleChange = useCallback((event: SelectChangeEvent<number>) => {
setSelectedSchedule(event.target.value as number);
const handleNameChange = useCallback((event: React.ChangeEvent<HTMLTextAreaElement>) => {
setName(event.target.value);
}, []);

const handleCancel = useCallback(() => {
onClose?.({}, 'escapeKeyDown');
}, [onClose]);

const handleCopy = useCallback(() => {
if (selectedSchedule !== scheduleNames.length) {
copySchedule(selectedSchedule);
} else {
scheduleNames.forEach((_, scheduleIndex) => {
if (scheduleIndex !== index) {
copySchedule(scheduleIndex);
}
});
}
copySchedule(name);
onClose?.({}, 'escapeKeyDown');
}, [index, onClose, selectedSchedule, scheduleNames]);
}, [onClose, name]);

const handleScheduleNamesChange = useCallback(() => {
setScheduleNames([...AppStore.getScheduleNames()]);
}, []);
setName(`Copy of ${AppStore.getScheduleNames()[index]}`);
}, [index]);

useEffect(() => {
AppStore.on('scheduleNamesChange', handleScheduleNamesChange);

return () => {
AppStore.off('scheduleNamesChange', handleScheduleNamesChange);
};
}, [handleScheduleNamesChange]);

return (
<Dialog onClose={onClose} {...props}>
<DialogTitle>Copy To Schedule</DialogTitle>

<DialogTitle>Copy Schedule</DialogTitle>
<DialogContent>
<Box padding={1}>
<Select fullWidth value={selectedSchedule} onChange={handleScheduleChange}>
{scheduleNames.map((name, idx) => (
<MenuItem key={idx} value={idx} disabled={index === idx}>
{name}
</MenuItem>
))}
<MenuItem value={scheduleNames.length}>Copy to All Schedules</MenuItem>
</Select>
<TextField fullWidth label="Name" onChange={handleNameChange} value={name} />
</Box>
</DialogContent>

<DialogActions>
<Button onClick={handleCancel} color="inherit">
Cancel
</Button>
<Button onClick={handleCopy} variant="contained" color="primary">
Copy Schedule
<Button onClick={handleCopy} variant="contained" color="primary" disabled={name?.trim() === ''}>
Make a Copy
</Button>
</DialogActions>
</Dialog>
Expand Down
21 changes: 15 additions & 6 deletions apps/antalmanac/src/components/dialogs/DeleteSchedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DialogTitle,
type DialogProps,
} from '@mui/material';
import { useCallback, useMemo } from 'react';
import { useCallback, useEffect, useState } from 'react';

import { deleteSchedule } from '$actions/AppStoreActions';
import AppStore from '$stores/AppStore';
Expand Down Expand Up @@ -35,10 +35,7 @@ function DeleteScheduleDialog(props: ScheduleNameDialogProps) {
* This is destructured separately for memoization.
*/
const { onClose } = props;

const scheduleName = useMemo(() => {
return AppStore.schedule.getScheduleName(index);
}, [index]);
const [name, setName] = useState<string>(AppStore.getScheduleNames()[index]);

const handleCancel = useCallback(() => {
onClose?.({}, 'escapeKeyDown');
Expand All @@ -49,12 +46,24 @@ function DeleteScheduleDialog(props: ScheduleNameDialogProps) {
onClose?.({}, 'escapeKeyDown');
}, [index, onClose]);

const handleScheduleNamesChange = useCallback(() => {
setName(AppStore.getScheduleNames()[index]);
}, [index]);

useEffect(() => {
AppStore.on('scheduleNamesChange', handleScheduleNamesChange);

return () => {
AppStore.off('scheduleNamesChange', handleScheduleNamesChange);
};
}, [handleScheduleNamesChange]);

return (
<Dialog {...dialogProps}>
<DialogTitle>Delete Schedule</DialogTitle>

<DialogContent>
<DialogContentText>Are you sure you want to delete &#34;{scheduleName}&#34;?</DialogContentText>
<DialogContentText>Are you sure you want to delete &#34;{name}&#34;?</DialogContentText>
</DialogContent>

<DialogActions>
Expand Down
20 changes: 6 additions & 14 deletions apps/antalmanac/src/components/dialogs/RenameSchedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
TextField,
type DialogProps,
} from '@mui/material';
import { useCallback, useState, useEffect, useMemo } from 'react';
import { useCallback, useState, useEffect } from 'react';

import { renameSchedule } from '$actions/AppStoreActions';
import AppStore from '$stores/AppStore';
Expand All @@ -34,19 +34,11 @@ function RenameScheduleDialog(props: ScheduleNameDialogProps) {
* This is destructured separately for memoization.
*/
const { onClose } = props;

const [scheduleNames, setScheduleNames] = useState(AppStore.getScheduleNames());

const [name, setName] = useState(scheduleNames[index]);

const disabled = useMemo(() => {
return name?.trim() === '';
}, [name]);
const [name, setName] = useState(AppStore.getScheduleNames()[index]);

const handleCancel = useCallback(() => {
onClose?.({}, 'escapeKeyDown');
setName(scheduleNames[index]);
}, [onClose, scheduleNames, index]);
}, [onClose, index]);

const handleNameChange = useCallback((event: React.ChangeEvent<HTMLTextAreaElement>) => {
setName(event.target.value);
Expand Down Expand Up @@ -75,8 +67,8 @@ function RenameScheduleDialog(props: ScheduleNameDialogProps) {
);

const handleScheduleNamesChange = useCallback(() => {
setScheduleNames(AppStore.getScheduleNames());
}, []);
setName(AppStore.getScheduleNames()[index]);
}, [index]);

useEffect(() => {
AppStore.on('scheduleNamesChange', handleScheduleNamesChange);
Expand All @@ -100,7 +92,7 @@ function RenameScheduleDialog(props: ScheduleNameDialogProps) {
<Button onClick={handleCancel} color={'inherit'}>
Cancel
</Button>
<Button onClick={submitName} variant="contained" color="primary" disabled={disabled}>
<Button onClick={submitName} variant="contained" color="primary" disabled={name?.trim() === ''}>
Rename Schedule
</Button>
</DialogActions>
Expand Down
13 changes: 10 additions & 3 deletions apps/antalmanac/src/stores/AppStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class AppStore extends EventEmitter {
}
}

getNextScheduleName(newScheduleName: string, scheduleIndex: number) {
return this.schedule.getNextScheduleName(newScheduleName, scheduleIndex);
}

getDefaultScheduleName() {
return this.schedule.getDefaultScheduleName();
}
Expand Down Expand Up @@ -291,14 +295,17 @@ class AppStore extends EventEmitter {
window.localStorage.removeItem('unsavedActions');
}

copySchedule(to: number) {
this.schedule.copySchedule(to);
copySchedule(newScheduleName: string) {
this.schedule.copySchedule(newScheduleName);
this.unsavedChanges = true;
const action: CopyScheduleAction = {
type: 'copySchedule',
to: to,
newScheduleName: newScheduleName,
};
actionTypesStore.autoSaveSchedule(action);
this.emit('scheduleNamesChange');
this.emit('currentScheduleIndexChange');
this.emit('scheduleNotesChange');
this.emit('addedCoursesChange');
this.emit('customEventsChange');
}
Expand Down
Loading
Loading