feat: allow bypassing the 10-schedule limit (#675)
* feat: allow bypassing the 10-schedule limit * feat: option to bypass 10 schedules- code done, not tested * feat(ui): option to bypass 10 schedules * feat(ui): button to lead to settings after reaching max limit * Delete manifest.json * Remove cross-env from build:watch script * Remove cross-env and update caniuse-lite version Removed cross-env dependency and updated caniuse-lite version. * chore: lint --------- Co-authored-by: Derek <derex1987@gmail.com>
This commit is contained in:
@@ -24,6 +24,8 @@ export interface IOptionsStore {
|
||||
|
||||
/** whether the promo should be shown */
|
||||
showUTDiningPromo: boolean;
|
||||
/** whether users are allowed to bypass the 10 schedule limit */
|
||||
allowMoreSchedules: boolean;
|
||||
}
|
||||
|
||||
export const OptionsStore = createSyncStore<IOptionsStore>({
|
||||
@@ -34,6 +36,7 @@ export const OptionsStore = createSyncStore<IOptionsStore>({
|
||||
alwaysOpenCalendarInNewTab: false,
|
||||
showCalendarSidebar: true,
|
||||
showUTDiningPromo: true,
|
||||
allowMoreSchedules: false,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -50,6 +53,7 @@ export const initSettings = async () =>
|
||||
alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'),
|
||||
showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'),
|
||||
showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'),
|
||||
allowMoreSchedules: await OptionsStore.get('allowMoreSchedules'),
|
||||
}) satisfies IOptionsStore;
|
||||
|
||||
// Clothing retailer right
|
||||
|
||||
@@ -92,6 +92,7 @@ export default function Settings(): JSX.Element {
|
||||
const [loadAllCourses, setLoadAllCourses] = useState<boolean>(false);
|
||||
const [_enableDataRefreshing, setEnableDataRefreshing] = useState<boolean>(false);
|
||||
const [calendarNewTab, setCalendarNewTab] = useState<boolean>(false);
|
||||
const [increaseScheduleLimit, setIncreaseScheduleLimit] = useState<boolean>(false);
|
||||
|
||||
const showMigrationDialog = useMigrationDialog();
|
||||
|
||||
@@ -126,6 +127,7 @@ export default function Settings(): JSX.Element {
|
||||
enableScrollToLoad,
|
||||
enableDataRefreshing,
|
||||
alwaysOpenCalendarInNewTab,
|
||||
allowMoreSchedules,
|
||||
} = await initSettings();
|
||||
setEnableCourseStatusChips(enableCourseStatusChips);
|
||||
// setShowTimeLocation(enableTimeAndLocationInPopup);
|
||||
@@ -133,6 +135,7 @@ export default function Settings(): JSX.Element {
|
||||
setLoadAllCourses(enableScrollToLoad);
|
||||
setEnableDataRefreshing(enableDataRefreshing);
|
||||
setCalendarNewTab(alwaysOpenCalendarInNewTab);
|
||||
setIncreaseScheduleLimit(allowMoreSchedules);
|
||||
};
|
||||
|
||||
const initDS = async () => {
|
||||
@@ -187,6 +190,15 @@ export default function Settings(): JSX.Element {
|
||||
// console.log('alwaysOpenCalendarInNewTab', newValue);
|
||||
});
|
||||
|
||||
const l6 = OptionsStore.listen('alwaysOpenCalendarInNewTab', async ({ newValue }) => {
|
||||
setCalendarNewTab(newValue);
|
||||
// console.log('alwaysOpenCalendarInNewTab', newValue);
|
||||
});
|
||||
|
||||
const l7 = OptionsStore.listen('allowMoreSchedules', async ({ newValue }) => {
|
||||
setIncreaseScheduleLimit(newValue);
|
||||
});
|
||||
|
||||
// Remove listeners when the component is unmounted
|
||||
return () => {
|
||||
OptionsStore.removeListener(l1);
|
||||
@@ -194,6 +206,8 @@ export default function Settings(): JSX.Element {
|
||||
OptionsStore.removeListener(l3);
|
||||
OptionsStore.removeListener(l4);
|
||||
OptionsStore.removeListener(l5);
|
||||
OptionsStore.removeListener(l6);
|
||||
OptionsStore.removeListener(l7);
|
||||
|
||||
DevStore.removeListener(ds_l1);
|
||||
|
||||
@@ -449,6 +463,25 @@ export default function Settings(): JSX.Element {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className='max-w-xs'>
|
||||
<Text variant='h4' className='text-ut-burntorange font-semibold'>
|
||||
Allow more than 10 schedules
|
||||
</Text>
|
||||
<p className='text-sm text-gray-600'>
|
||||
Allow bypassing the 10-schedule limit. Intended for advisors or staff who
|
||||
need to create many schedules on behalf of students.
|
||||
</p>
|
||||
</div>
|
||||
<SwitchButton
|
||||
isChecked={increaseScheduleLimit}
|
||||
onChange={() => {
|
||||
setIncreaseScheduleLimit(!increaseScheduleLimit);
|
||||
OptionsStore.set('allowMoreSchedules', !increaseScheduleLimit);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider size='auto' orientation='horizontal' />
|
||||
|
||||
<div className='flex items-center justify-between'>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { background } from '@shared/messages';
|
||||
import { OptionsStore } from '@shared/storage/OptionsStore';
|
||||
import { CRX_PAGES } from '@shared/types/CRXPages';
|
||||
import useSchedules from '@views/hooks/useSchedules';
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { Button } from '../components/common/Button';
|
||||
import { usePrompt } from '../components/common/DialogProvider/DialogProvider';
|
||||
@@ -17,8 +20,33 @@ const SCHEDULE_LIMIT = 10;
|
||||
export function useEnforceScheduleLimit(): () => boolean {
|
||||
const [, schedules] = useSchedules();
|
||||
const showDialog = usePrompt();
|
||||
const [allowMoreSchedules, setAllowMoreSchedules] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
(async () => {
|
||||
try {
|
||||
const val = await OptionsStore.get('allowMoreSchedules');
|
||||
if (mounted) setAllowMoreSchedules(val ?? false);
|
||||
} catch (err) {
|
||||
console.error('Failed to read allowMoreSchedules from OptionsStore:', err);
|
||||
}
|
||||
})();
|
||||
|
||||
const listener = OptionsStore.listen('allowMoreSchedules', async ({ newValue }) => {
|
||||
setAllowMoreSchedules(newValue);
|
||||
});
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
OptionsStore.removeListener(listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return useCallback(() => {
|
||||
// If user has enabled bypass, allow creating more schedules
|
||||
if (allowMoreSchedules) return true;
|
||||
|
||||
if (schedules.length >= SCHEDULE_LIMIT) {
|
||||
showDialog({
|
||||
title: `You have too many schedules!`,
|
||||
@@ -27,19 +55,33 @@ export function useEnforceScheduleLimit(): () => boolean {
|
||||
<>
|
||||
To encourage organization,{' '}
|
||||
<span className='text-ut-burntorange'>please consider deleting any unused schedules</span> you
|
||||
may have.
|
||||
may have. You can increase the limit in the settings if it’s really necessary.
|
||||
</>
|
||||
),
|
||||
|
||||
buttons: close => (
|
||||
<Button variant='filled' color='ut-burntorange' onClick={close}>
|
||||
I understand
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
variant='outline'
|
||||
color='ut-black'
|
||||
onClick={() => {
|
||||
close();
|
||||
// open options/settings page so user can enable bypass if they are advising staff
|
||||
const url = chrome.runtime.getURL(CRX_PAGES.OPTIONS);
|
||||
background.openNewTab({ url });
|
||||
}}
|
||||
>
|
||||
Open Settings
|
||||
</Button>
|
||||
<Button variant='filled' color='ut-burntorange' onClick={close}>
|
||||
I understand
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, [schedules, showDialog]);
|
||||
}, [schedules, showDialog, allowMoreSchedules]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user