diff --git a/components/StrategySelector.tsx b/components/StrategySelector.tsx index 6ede15e..d3e5ed0 100644 --- a/components/StrategySelector.tsx +++ b/components/StrategySelector.tsx @@ -1,3 +1,4 @@ + import React, { useState, useRef, useEffect } from 'react'; import { SyncStrategy, RegexReplacement, SyncState, ScheduleSettings, ScheduleMode } from '../types'; import { @@ -61,6 +62,25 @@ const STRATEGIES: StrategyOption[] = [ const WEEK_DAYS = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; +// Helper to determine the actual mode and settings that would be saved based on the current UI state +const deriveEffectiveSchedule = (schedule: ScheduleSettings, tab: ScheduleMode): ScheduleSettings => { + const derived = { ...schedule }; + + if (tab === ScheduleMode.CRON) { + derived.mode = derived.cronExpression.trim() !== '' ? ScheduleMode.CRON : ScheduleMode.DISABLED; + } else { + // For Daily/Weekly + // If the mode matches the tab, we keep it (Enabled). + // If the mode doesn't match (e.g. it was CRON or DISABLED), then in the context of this tab, it is effectively Disabled until the user checks the box. + if (derived.mode === tab) { + derived.mode = tab; + } else { + derived.mode = ScheduleMode.DISABLED; + } + } + return derived; +}; + interface StrategySelectorProps { currentStrategy: SyncStrategy; onSelect: (strategy: SyncStrategy, label: string) => void; @@ -123,10 +143,13 @@ const StrategySelector: React.FC = ({ setIsRegexDirty(isDifferent); }, [localReplacements, savedRegexReplacements]); + // Check dirty state for Schedule (including Active Tab changes) useEffect(() => { - const isDifferent = JSON.stringify(localSchedule) !== JSON.stringify(savedSchedule); + // We calculate what the "effective" schedule would be if we saved right now. + const effectiveLocal = deriveEffectiveSchedule(localSchedule, activeTab); + const isDifferent = JSON.stringify(effectiveLocal) !== JSON.stringify(savedSchedule); setIsScheduleDirty(isDifferent); - }, [localSchedule, savedSchedule]); + }, [localSchedule, savedSchedule, activeTab]); const selectedOption = STRATEGIES.find(s => s.value === currentStrategy) || STRATEGIES[0]; @@ -140,6 +163,11 @@ const StrategySelector: React.FC = ({ return () => document.removeEventListener('mousedown', handleClickOutside); }, []); + // Determine if tabs have changed from the saved state + const initialTab = savedSchedule.mode === ScheduleMode.DISABLED ? ScheduleMode.CRON : savedSchedule.mode; + const hasTabChanged = activeTab !== initialTab; + const isScheduleActionable = isScheduleDirty || hasTabChanged; + const handleSelect = (strategy: StrategyOption) => { if (isLocked) return; onSelect(strategy.value, strategy.label); @@ -196,37 +224,23 @@ const StrategySelector: React.FC = ({ setLocalSchedule(JSON.parse(JSON.stringify(savedSchedule))); if (savedSchedule.mode !== ScheduleMode.DISABLED) { setActiveTab(savedSchedule.mode); + } else { + setActiveTab(ScheduleMode.CRON); } }; const handleSaveScheduleClick = async () => { if (isLocked) return; - let settingsToSave = { ...localSchedule }; - - // Logic to determine mode based on active Tab and checkbox state - if (activeTab === ScheduleMode.CRON) { - if (settingsToSave.cronExpression.trim() !== '') { - settingsToSave.mode = ScheduleMode.CRON; - } else { - // Empty cron -> disabled - settingsToSave.mode = ScheduleMode.DISABLED; - } - } - - // For Daily/Weekly, enforce: Save commits what is seen in the active tab. - if (activeTab !== ScheduleMode.CRON) { - // If the mode matches the active tab, it's enabled. Otherwise disabled. - if (localSchedule.mode !== activeTab) { - settingsToSave.mode = ScheduleMode.DISABLED; - } - } + // Determine the effective settings based on the current view (tab) and inputs + const settingsToSave = deriveEffectiveSchedule(localSchedule, activeTab); // Call API const success = await onSaveSchedule(settingsToSave); if (success) { setLocalSchedule(settingsToSave); - setIsScheduleDirty(false); + // Dirty state is cleared by the useEffect prop update, or we can clear it optimistically here if needed, + // but useEffect [savedSchedule] handles it correctly. } }; @@ -554,9 +568,9 @@ const StrategySelector: React.FC = ({