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 */
|
/** whether the promo should be shown */
|
||||||
showUTDiningPromo: boolean;
|
showUTDiningPromo: boolean;
|
||||||
|
/** whether users are allowed to bypass the 10 schedule limit */
|
||||||
|
allowMoreSchedules: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OptionsStore = createSyncStore<IOptionsStore>({
|
export const OptionsStore = createSyncStore<IOptionsStore>({
|
||||||
@@ -34,6 +36,7 @@ export const OptionsStore = createSyncStore<IOptionsStore>({
|
|||||||
alwaysOpenCalendarInNewTab: false,
|
alwaysOpenCalendarInNewTab: false,
|
||||||
showCalendarSidebar: true,
|
showCalendarSidebar: true,
|
||||||
showUTDiningPromo: true,
|
showUTDiningPromo: true,
|
||||||
|
allowMoreSchedules: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,6 +53,7 @@ export const initSettings = async () =>
|
|||||||
alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'),
|
alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'),
|
||||||
showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'),
|
showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'),
|
||||||
showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'),
|
showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'),
|
||||||
|
allowMoreSchedules: await OptionsStore.get('allowMoreSchedules'),
|
||||||
}) satisfies IOptionsStore;
|
}) satisfies IOptionsStore;
|
||||||
|
|
||||||
// Clothing retailer right
|
// Clothing retailer right
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ export default function Settings(): JSX.Element {
|
|||||||
const [loadAllCourses, setLoadAllCourses] = useState<boolean>(false);
|
const [loadAllCourses, setLoadAllCourses] = useState<boolean>(false);
|
||||||
const [_enableDataRefreshing, setEnableDataRefreshing] = useState<boolean>(false);
|
const [_enableDataRefreshing, setEnableDataRefreshing] = useState<boolean>(false);
|
||||||
const [calendarNewTab, setCalendarNewTab] = useState<boolean>(false);
|
const [calendarNewTab, setCalendarNewTab] = useState<boolean>(false);
|
||||||
|
const [increaseScheduleLimit, setIncreaseScheduleLimit] = useState<boolean>(false);
|
||||||
|
|
||||||
const showMigrationDialog = useMigrationDialog();
|
const showMigrationDialog = useMigrationDialog();
|
||||||
|
|
||||||
@@ -126,6 +127,7 @@ export default function Settings(): JSX.Element {
|
|||||||
enableScrollToLoad,
|
enableScrollToLoad,
|
||||||
enableDataRefreshing,
|
enableDataRefreshing,
|
||||||
alwaysOpenCalendarInNewTab,
|
alwaysOpenCalendarInNewTab,
|
||||||
|
allowMoreSchedules,
|
||||||
} = await initSettings();
|
} = await initSettings();
|
||||||
setEnableCourseStatusChips(enableCourseStatusChips);
|
setEnableCourseStatusChips(enableCourseStatusChips);
|
||||||
// setShowTimeLocation(enableTimeAndLocationInPopup);
|
// setShowTimeLocation(enableTimeAndLocationInPopup);
|
||||||
@@ -133,6 +135,7 @@ export default function Settings(): JSX.Element {
|
|||||||
setLoadAllCourses(enableScrollToLoad);
|
setLoadAllCourses(enableScrollToLoad);
|
||||||
setEnableDataRefreshing(enableDataRefreshing);
|
setEnableDataRefreshing(enableDataRefreshing);
|
||||||
setCalendarNewTab(alwaysOpenCalendarInNewTab);
|
setCalendarNewTab(alwaysOpenCalendarInNewTab);
|
||||||
|
setIncreaseScheduleLimit(allowMoreSchedules);
|
||||||
};
|
};
|
||||||
|
|
||||||
const initDS = async () => {
|
const initDS = async () => {
|
||||||
@@ -187,6 +190,15 @@ export default function Settings(): JSX.Element {
|
|||||||
// console.log('alwaysOpenCalendarInNewTab', newValue);
|
// 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
|
// Remove listeners when the component is unmounted
|
||||||
return () => {
|
return () => {
|
||||||
OptionsStore.removeListener(l1);
|
OptionsStore.removeListener(l1);
|
||||||
@@ -194,6 +206,8 @@ export default function Settings(): JSX.Element {
|
|||||||
OptionsStore.removeListener(l3);
|
OptionsStore.removeListener(l3);
|
||||||
OptionsStore.removeListener(l4);
|
OptionsStore.removeListener(l4);
|
||||||
OptionsStore.removeListener(l5);
|
OptionsStore.removeListener(l5);
|
||||||
|
OptionsStore.removeListener(l6);
|
||||||
|
OptionsStore.removeListener(l7);
|
||||||
|
|
||||||
DevStore.removeListener(ds_l1);
|
DevStore.removeListener(ds_l1);
|
||||||
|
|
||||||
@@ -449,6 +463,25 @@ export default function Settings(): JSX.Element {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</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' />
|
<Divider size='auto' orientation='horizontal' />
|
||||||
|
|
||||||
<div className='flex items-center justify-between'>
|
<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 useSchedules from '@views/hooks/useSchedules';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { Button } from '../components/common/Button';
|
import { Button } from '../components/common/Button';
|
||||||
import { usePrompt } from '../components/common/DialogProvider/DialogProvider';
|
import { usePrompt } from '../components/common/DialogProvider/DialogProvider';
|
||||||
@@ -17,8 +20,33 @@ const SCHEDULE_LIMIT = 10;
|
|||||||
export function useEnforceScheduleLimit(): () => boolean {
|
export function useEnforceScheduleLimit(): () => boolean {
|
||||||
const [, schedules] = useSchedules();
|
const [, schedules] = useSchedules();
|
||||||
const showDialog = usePrompt();
|
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(() => {
|
return useCallback(() => {
|
||||||
|
// If user has enabled bypass, allow creating more schedules
|
||||||
|
if (allowMoreSchedules) return true;
|
||||||
|
|
||||||
if (schedules.length >= SCHEDULE_LIMIT) {
|
if (schedules.length >= SCHEDULE_LIMIT) {
|
||||||
showDialog({
|
showDialog({
|
||||||
title: `You have too many schedules!`,
|
title: `You have too many schedules!`,
|
||||||
@@ -27,19 +55,33 @@ export function useEnforceScheduleLimit(): () => boolean {
|
|||||||
<>
|
<>
|
||||||
To encourage organization,{' '}
|
To encourage organization,{' '}
|
||||||
<span className='text-ut-burntorange'>please consider deleting any unused schedules</span> you
|
<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 => (
|
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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}, [schedules, showDialog]);
|
}, [schedules, showDialog, allowMoreSchedules]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user