diff --git a/src/views/components/PopupMain.tsx b/src/views/components/PopupMain.tsx index 12d622bb5..999999a8e 100644 --- a/src/views/components/PopupMain.tsx +++ b/src/views/components/PopupMain.tsx @@ -7,6 +7,7 @@ import { openReportWindow } from '@shared/util/openReportWindow'; import Divider from '@views/components/common/Divider'; import List from '@views/components/common/List'; import Text from '@views/components/common/Text/Text'; +import { useEnforceScheduleLimit } from '@views/hooks/useEnforceScheduleLimit'; import useSchedules, { getActiveSchedule, replaceSchedule, switchSchedule } from '@views/hooks/useSchedules'; import { getUpdatedAtDateTimeString } from '@views/lib/getUpdatedAtDateTimeString'; import useKC_DABR_WASM from 'kc-dabr-wasm'; @@ -62,6 +63,13 @@ export default function PopupMain(): JSX.Element { // const [isRefreshing, setIsRefreshing] = useState(false); const [funny, setFunny] = useState(''); + const enforceScheduleLimit = useEnforceScheduleLimit(); + const handleAddSchedule = () => { + if (enforceScheduleLimit()) { + createSchedule('New Schedule'); + } + }; + useEffect(() => { const randomIndex = Math.floor(Math.random() * splashText.length); setFunny( @@ -128,7 +136,7 @@ export default function PopupMain(): JSX.Element { variant='filled' color='ut-burntorange' className='h-fit p-0 btn' - onClick={() => createSchedule('New Schedule')} + onClick={handleAddSchedule} > diff --git a/src/views/components/calendar/CalendarSchedules.tsx b/src/views/components/calendar/CalendarSchedules.tsx index 6a5052423..690b30be6 100644 --- a/src/views/components/calendar/CalendarSchedules.tsx +++ b/src/views/components/calendar/CalendarSchedules.tsx @@ -4,13 +4,12 @@ import { Button } from '@views/components/common/Button'; import List from '@views/components/common/List'; import ScheduleListItem from '@views/components/common/ScheduleListItem'; import Text from '@views/components/common/Text/Text'; +import { useEnforceScheduleLimit } from '@views/hooks/useEnforceScheduleLimit'; import useSchedules, { getActiveSchedule, switchSchedule } from '@views/hooks/useSchedules'; import React from 'react'; import AddSchedule from '~icons/material-symbols/add'; -import { usePrompt } from '../common/DialogProvider/DialogProvider'; - /** * Renders a component that displays a list of schedules. * @@ -19,32 +18,12 @@ import { usePrompt } from '../common/DialogProvider/DialogProvider'; */ export function CalendarSchedules() { const [, schedules] = useSchedules(); - const showDialog = usePrompt(); + const enforceScheduleLimit = useEnforceScheduleLimit(); const handleAddSchedule = () => { - if (schedules.length >= 10) { - showDialog({ - title: `You have 10 active schedules!`, - - description: ( - <> - To encourage organization,{' '} - please consider removing some unused schedules you - may have. - - ), - // eslint-disable-next-line react/no-unstable-nested-components - buttons: close => ( - - ), - }); - - return; + if (enforceScheduleLimit()) { + createSchedule('New Schedule'); } - - createSchedule('New Schedule'); }; return ( diff --git a/src/views/components/common/ScheduleListItem.tsx b/src/views/components/common/ScheduleListItem.tsx index 70672b153..24f07e4b1 100644 --- a/src/views/components/common/ScheduleListItem.tsx +++ b/src/views/components/common/ScheduleListItem.tsx @@ -4,6 +4,7 @@ import duplicateSchedule from '@pages/background/lib/duplicateSchedule'; import renameSchedule from '@pages/background/lib/renameSchedule'; import type { UserSchedule } from '@shared/types/UserSchedule'; import Text from '@views/components/common/Text/Text'; +import { useEnforceScheduleLimit } from '@views/hooks/useEnforceScheduleLimit'; import useSchedules from '@views/hooks/useSchedules'; import clsx from 'clsx'; import React, { useEffect, useMemo, useState } from 'react'; @@ -34,6 +35,12 @@ export default function ScheduleListItem({ schedule, dragHandleProps, onClick }: const [editorValue, setEditorValue] = useState(schedule.name); const showDialog = usePrompt(); + const enforceScheduleLimit = useEnforceScheduleLimit(); + const handleDuplicateSchedule = (scheduleId: string) => { + if (enforceScheduleLimit()) { + duplicateSchedule(scheduleId); + } + }; const editorRef = React.useRef(null); useEffect(() => { @@ -180,7 +187,7 @@ export default function ScheduleListItem({ schedule, dragHandleProps, onClick }: duplicateSchedule(schedule.id)} + onClick={() => handleDuplicateSchedule(schedule.id)} className='w-full rounded bg-transparent p-2 text-left data-[focus]:bg-gray-200/40' > Duplicate diff --git a/src/views/hooks/useEnforceScheduleLimit.tsx b/src/views/hooks/useEnforceScheduleLimit.tsx new file mode 100644 index 000000000..13d330d9a --- /dev/null +++ b/src/views/hooks/useEnforceScheduleLimit.tsx @@ -0,0 +1,45 @@ +import useSchedules from '@views/hooks/useSchedules'; +import React, { useCallback } from 'react'; + +import { Button } from '../components/common/Button'; +import { usePrompt } from '../components/common/DialogProvider/DialogProvider'; + +const SCHEDULE_LIMIT = 10; + +/** + * Hook that creates a function that enforces a maximum amount of schedules + * + * If a new schedule can be created without exceeding the limit, the function returns true + * Otherwise, display a prompt explaining the limit, and returns false + * + * @returns a function, () => boolean + */ +export function useEnforceScheduleLimit(): () => boolean { + const [, schedules] = useSchedules(); + const showDialog = usePrompt(); + + return useCallback(() => { + if (schedules.length >= SCHEDULE_LIMIT) { + showDialog({ + title: `You have ${SCHEDULE_LIMIT} active schedules!`, + + description: ( + <> + To encourage organization,{' '} + please consider removing some unused schedules you + may have. + + ), + + buttons: close => ( + + ), + }); + + return false; + } + return true; + }, [schedules, showDialog]); +}