diff --git a/.github/workflows/beta-release.yml b/.github/workflows/beta-release.yml index 5fe51c4..81c7a7a 100644 --- a/.github/workflows/beta-release.yml +++ b/.github/workflows/beta-release.yml @@ -9,6 +9,8 @@ on: paths-ignore: - '.github/workflows/**' - '**/*.md' + - '*.md' + - '.gitignore' permissions: contents: write @@ -72,11 +74,11 @@ jobs: run: npm run build:${{ matrix.target }} env: CSC_IDENTITY_AUTO_DISCOVERY: false - FEEDBACK_FORM_URL: ${{ secrets.FEEDBACK_FORM_URL }} - FEEDBACK_FORM_ENTRY_EMAIL: ${{ secrets.FEEDBACK_FORM_ENTRY_EMAIL }} - FEEDBACK_FORM_ENTRY_CATEGORY: ${{ secrets.FEEDBACK_FORM_ENTRY_CATEGORY }} - FEEDBACK_FORM_ENTRY_SUBJECT: ${{ secrets.FEEDBACK_FORM_ENTRY_SUBJECT }} - FEEDBACK_FORM_ENTRY_DETAILS: ${{ secrets.FEEDBACK_FORM_ENTRY_DETAILS }} + FEEDBACK_FORM_URL: ${{ vars.FEEDBACK_FORM_URL }} + FEEDBACK_FORM_ENTRY_EMAIL: ${{ vars.FEEDBACK_FORM_ENTRY_EMAIL }} + FEEDBACK_FORM_ENTRY_CATEGORY: ${{ vars.FEEDBACK_FORM_ENTRY_CATEGORY }} + FEEDBACK_FORM_ENTRY_SUBJECT: ${{ vars.FEEDBACK_FORM_ENTRY_SUBJECT }} + FEEDBACK_FORM_ENTRY_DETAILS: ${{ vars.FEEDBACK_FORM_ENTRY_DETAILS }} - name: Upload beta artifacts uses: actions/upload-artifact@v4 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6089910..255a836 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,8 @@ on: paths-ignore: - '.github/workflows/**' - '**/*.md' + - '*.md' + - '.gitignore' jobs: build: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0b20abb..e3a0411 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,8 @@ on: paths-ignore: - '.github/workflows/**' - '**/*.md' + - '*.md' + - '.gitignore' permissions: contents: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 59838bf..b0ec7d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,8 @@ on: paths-ignore: - '.github/workflows/**' - '**/*.md' + - '*.md' + - '.gitignore' jobs: test: diff --git a/.github/workflows/validate-version.yml b/.github/workflows/validate-version.yml index 39733a3..dacba84 100644 --- a/.github/workflows/validate-version.yml +++ b/.github/workflows/validate-version.yml @@ -9,6 +9,8 @@ on: paths-ignore: - '.github/workflows/**' - '**/*.md' + - '*.md' + - '.gitignore' jobs: check-version: diff --git a/src/components/PlanDashboard/PlanDashboard.tsx b/src/components/PlanDashboard/PlanDashboard.tsx index 1fb26a2..28c38c5 100644 --- a/src/components/PlanDashboard/PlanDashboard.tsx +++ b/src/components/PlanDashboard/PlanDashboard.tsx @@ -22,6 +22,7 @@ import SettingsModal from '../modals/SettingsModal'; import AccountsModal from '../modals/AccountsModal'; import ExportModal from '../modals/ExportModal'; import FeedbackModal from '../modals/FeedbackModal'; +import ViewModeSettingsModal from '../modals/ViewModeSettingsModal'; import { PlanTabs, TabManagementModal } from './PlanTabs'; import PlanSearchOverlay from './PlanSearchOverlay'; import PlanHistoryOverlay from './PlanHistoryOverlay'; @@ -29,6 +30,7 @@ import { Toast, Modal, Button, ConfirmDialog, ErrorDialog, FileRelinkModal, Form import { initializeTabConfigs, getVisibleTabs, getHiddenTabs, toggleTabVisibility, reorderTabs, normalizeLegacyTabId } from '../../utils/tabManagement'; import { getPayFrequencyViewMode } from '../../utils/payPeriod'; import { sanitizeFavoriteViewModes } from '../../utils/viewModePreferences'; +import type { SelectableViewMode } from '../../types/viewMode'; import { useGlobalKeyboardShortcuts } from '../../hooks'; import type { SearchResult } from '../../utils/planSearch'; import { getActionHandler, type SearchActionContext } from '../../utils/searchRegistry'; @@ -95,9 +97,8 @@ const isElementVisibleInContainer = (element: HTMLElement, container: HTMLElemen ); }; -const getFirstVisibleFavoriteMode = (): ViewMode => { - const favorites = sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites); - return favorites[0]; +const getFirstVisibleFavoriteMode = (favorites: SelectableViewMode[]): ViewMode => { + return favorites[0] as ViewMode; }; const isEditableTarget = (target: EventTarget | null): boolean => { @@ -148,24 +149,24 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o const [shouldScrollToRetirement, setShouldScrollToRetirement] = useState(false); const [pendingTabScroll, setPendingTabScroll] = useState<{ tab: TabId; position: TabScrollPosition } | null>(null); const [displayMode, setDisplayMode] = useState(() => { + const favorites = sanitizeFavoriteViewModes(budgetData?.settings?.viewModeFavorites); if (budgetData?.settings?.displayMode) { - return sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites).includes( - budgetData.settings.displayMode as never, - ) + return favorites.includes(budgetData.settings.displayMode as never) ? budgetData.settings.displayMode - : getFirstVisibleFavoriteMode(); + : getFirstVisibleFavoriteMode(favorites); } const cadenceMode = getPayFrequencyViewMode(budgetData?.paySettings?.payFrequency ?? 'bi-weekly'); - return sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites).includes(cadenceMode as never) + return favorites.includes(cadenceMode as never) ? cadenceMode - : getFirstVisibleFavoriteMode(); + : getFirstVisibleFavoriteMode(favorites); }); const [showCopyModal, setShowCopyModal] = useState(false); const [newYear, setNewYear] = useState(''); const [copyYearError, setCopyYearError] = useState(null); const [showSettings, setShowSettings] = useState(false); const [settingsInitialSection, setSettingsInitialSection] = useState(undefined); + const [showViewModeSettings, setShowViewModeSettings] = useState(false); const [pendingPaySettingsFieldHighlight, setPendingPaySettingsFieldHighlight] = useState(undefined); const [paySettingsSearchRequestKey, setPaySettingsSearchRequestKey] = useState(0); const [pendingBillsSearchAction, setPendingBillsSearchAction] = useState< @@ -342,7 +343,6 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o const normalizedViewMode = normalizeLegacyTabId(viewMode); if (normalizedViewMode && VALID_TABS.includes(normalizedViewMode)) { - // eslint-disable-next-line react-hooks/set-state-in-effect setActiveTab(normalizedViewMode); initializedTabContextRef.current = tabRestoreContext; return; @@ -433,6 +433,21 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o historyStateKeyRef.current = nextHistoryKey; }, [activeTab, budgetData?.id, budgetData?.settings?.filePath, viewMode]); + useEffect(() => { + const handleViewModeAutoSwitched = (event: Event) => { + const customEvent = event as CustomEvent<{ message?: string }>; + setStatusToast({ + message: customEvent.detail?.message ?? 'View mode switched to match your pay frequency.', + type: 'success', + }); + }; + + window.addEventListener(APP_CUSTOM_EVENTS.viewModeAutoSwitched, handleViewModeAutoSwitched as EventListener); + return () => { + window.removeEventListener(APP_CUSTOM_EVENTS.viewModeAutoSwitched, handleViewModeAutoSwitched as EventListener); + }; + }, []); + useEffect(() => { if (viewMode || typeof window === 'undefined') return; @@ -456,21 +471,20 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o // Initialize tab position and display mode from budget settings useEffect(() => { if (budgetData?.settings?.tabPosition) { - // eslint-disable-next-line react-hooks/set-state-in-effect setTabPosition(budgetData.settings.tabPosition); } if (budgetData?.settings?.tabDisplayMode) { setTabDisplayMode(budgetData.settings.tabDisplayMode); } if (budgetData?.settings?.displayMode) { - const favorites = sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites); + const favorites = sanitizeFavoriteViewModes(budgetData.settings.viewModeFavorites); setDisplayMode( favorites.includes(budgetData.settings.displayMode as never) ? budgetData.settings.displayMode : favorites[0], ); } else if (budgetData?.paySettings?.payFrequency) { - const favorites = sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites); + const favorites = sanitizeFavoriteViewModes(budgetData.settings?.viewModeFavorites); const cadenceMode = getPayFrequencyViewMode(budgetData.paySettings.payFrequency); setDisplayMode(favorites.includes(cadenceMode as never) ? cadenceMode : favorites[0]); } @@ -478,22 +492,18 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o budgetData?.settings?.tabDisplayMode, budgetData?.settings?.tabPosition, budgetData?.settings?.displayMode, + budgetData?.settings?.viewModeFavorites, budgetData?.paySettings?.payFrequency, ]); + // When plan-specific favorites change, ensure displayMode is still in the list useEffect(() => { - const handleViewModeFavoritesChanged = () => { - const favorites = sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites); - if (!favorites.includes(displayMode as never)) { - setDisplayMode(favorites[0]); - } - }; - - window.addEventListener(APP_CUSTOM_EVENTS.viewModeFavoritesChanged, handleViewModeFavoritesChanged); - return () => { - window.removeEventListener(APP_CUSTOM_EVENTS.viewModeFavoritesChanged, handleViewModeFavoritesChanged); - }; - }, [displayMode]); + const favorites = sanitizeFavoriteViewModes(budgetData?.settings?.viewModeFavorites); + if (!favorites.includes(displayMode as never)) { + setDisplayMode(favorites[0]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [budgetData?.settings?.viewModeFavorites]); // Handle tab position changes const handleTabPositionChange = useCallback((newPosition: TabPosition) => { @@ -870,7 +880,6 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o planLoadingStartRef.current = Date.now(); } - // eslint-disable-next-line react-hooks/set-state-in-effect setShowPlanLoadingScreen(true); return; } @@ -1165,16 +1174,27 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o } else if (action.type === 'open-settings') { setSettingsInitialSection(action.sectionId); setShowSettings(true); + } else if (action.type === 'open-view-mode-settings') { + setShowViewModeSettings(true); } }, [openTabFromLink, selectTab, setPendingBillsSearchAction, setPendingBillsSearchTargetId, setBillsSearchRequestKey, setPendingLoansSearchAction, setPendingLoansSearchTargetId, setLoansSearchRequestKey, setPendingSavingsSearchAction, setPendingSavingsSearchTargetId, setSavingsSearchRequestKey, setTaxSearchOpenSettingsRequestKey, setShowAccountsModal, setShowSettings, setSettingsInitialSection, setScrollToAccountId, setPendingPaySettingsFieldHighlight, setPaySettingsSearchRequestKey], ); const handleOpenViewModeSettings = useCallback(() => { - setSettingsInitialSection('app-data-reset'); - setShowSettings(true); + setShowViewModeSettings(true); }, []); + const handleViewModeFavoritesChange = useCallback((newFavorites: SelectableViewMode[]) => { + if (!budgetData) return; + updateBudgetData({ + settings: { + ...budgetData.settings, + viewModeFavorites: newFavorites, + }, + }); + }, [budgetData, updateBudgetData]); + const handleOpenObjectHistory = useCallback((target: AuditHistoryTarget) => { setHistoryTarget(target); }, []); @@ -1632,6 +1652,7 @@ const PlanDashboard: React.FC = ({ onResetSetup, viewMode, o = ({ onResetSetup, viewMode, o }} /> + setShowViewModeSettings(false)} + favorites={sanitizeFavoriteViewModes(budgetData.settings.viewModeFavorites)} + onChange={handleViewModeFavoritesChange} + /> + {/* Edit Plan Metadata Modal */} { mode: T; onChange: (mode: T) => void; options?: ViewModeOption[]; + /** Plan-specific favorites; when provided, skips internal app-settings reads. */ + favorites?: SelectableViewMode[]; payCadenceMode?: T; payCadenceLabel?: string; onOpenViewModeSettings?: () => void; @@ -26,29 +27,13 @@ const ViewModeSelector = ({ mode, onChange, options, + favorites: favoritesProp, payCadenceMode, payCadenceLabel = 'Your Pay Frequency', onOpenViewModeSettings, disabled = false, }: ViewModeSelectorProps) => { - const [favoriteModes, setFavoriteModes] = useState(() => - sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites), - ); - - useEffect(() => { - if (options) return; - - const handleFavoritesChanged = () => { - setFavoriteModes( - sanitizeFavoriteViewModes(FileStorageService.getAppSettings().viewModeFavorites), - ); - }; - - window.addEventListener(APP_CUSTOM_EVENTS.viewModeFavoritesChanged, handleFavoritesChanged); - return () => { - window.removeEventListener(APP_CUSTOM_EVENTS.viewModeFavoritesChanged, handleFavoritesChanged); - }; - }, [options]); + const favoriteModes = favoritesProp ?? sanitizeFavoriteViewModes(undefined); const resolvedOptions = useMemo(() => { if (options) { @@ -59,7 +44,10 @@ const ViewModeSelector = ({ }, [options, favoriteModes, payCadenceMode]); const optionsWithCadence = useMemo(() => { - if (!payCadenceMode || options) { + // Only auto-add cadence tab when the user has not explicitly configured + // favorites (favouritesProp absent). When plan-specific favorites are + // provided, the user's checkbox selection is the authoritative list. + if (!payCadenceMode || options || favoritesProp !== undefined) { return resolvedOptions; } @@ -74,7 +62,7 @@ const ViewModeSelector = ({ } as ViewModeOption, ...resolvedOptions, ]; - }, [payCadenceMode, options, resolvedOptions]); + }, [payCadenceMode, options, favoritesProp, resolvedOptions]); return (
diff --git a/src/components/modals/PaySettingsModal/PaySettingsModal.tsx b/src/components/modals/PaySettingsModal/PaySettingsModal.tsx index afcad46..a4799f5 100644 --- a/src/components/modals/PaySettingsModal/PaySettingsModal.tsx +++ b/src/components/modals/PaySettingsModal/PaySettingsModal.tsx @@ -3,12 +3,15 @@ import { useBudget } from '../../../contexts/BudgetContext'; import { useAppDialogs } from '../../../hooks'; import type { BudgetData } from '../../../types/budget'; import type { PayFrequency } from '../../../types/frequencies'; +import type { SelectableViewMode } from '../../../types/viewMode'; import type { PaySettings } from '../../../types/payroll'; import type { AuditHistoryTarget } from '../../../types/audit'; import { convertBudgetAmounts } from '../../../services/budgetCurrencyConversion'; import { CURRENCIES, getCurrencySymbol } from '../../../utils/currency'; -import { getPaychecksPerYear } from '../../../utils/payPeriod'; +import { getDisplayModeLabel, getPaychecksPerYear, getPayFrequencyViewMode } from '../../../utils/payPeriod'; import { normalizeStoredAllocationAmount } from '../../../utils/allocationEditor'; +import { sanitizeFavoriteViewModes, syncFavoritesForCadence } from '../../../utils/viewModePreferences'; +import { APP_CUSTOM_EVENTS } from '../../../constants/events'; import { formatSuggestedLeftover, getSuggestedLeftoverPerPaycheck } from '../../../utils/paySuggestions'; import { Modal, Button, ErrorDialog, Dropdown, FormGroup, InputWithPrefix, FormattedNumberInput, RadioGroup } from '../../_shared'; import '../../_shared/payEditorShared.css'; @@ -248,6 +251,30 @@ const PaySettingsModal: React.FC = ({ isOpen, onClose, se }; } + // Sync view mode selector favorites when pay frequency changes so the new + // cadence tab appears at its canonical position in this plan's selector. + if (editPayFrequency !== budgetData.paySettings.payFrequency) { + const cadenceMode = getPayFrequencyViewMode(editPayFrequency) as SelectableViewMode; + const existingFavorites = sanitizeFavoriteViewModes(updatedBudget.settings.viewModeFavorites); + const newFavorites = syncFavoritesForCadence(existingFavorites, cadenceMode); + updatedBudget = { + ...updatedBudget, + settings: { + ...updatedBudget.settings, + displayMode: cadenceMode, + viewModeFavorites: newFavorites ?? existingFavorites, + }, + }; + + window.dispatchEvent( + new CustomEvent(APP_CUSTOM_EVENTS.viewModeAutoSwitched, { + detail: { + message: `View mode switched to ${getDisplayModeLabel(cadenceMode)}`, + }, + }), + ); + } + updateBudgetData(updatedBudget); setFieldErrors({}); diff --git a/src/components/modals/SettingsModal/SettingsModal.test.tsx b/src/components/modals/SettingsModal/SettingsModal.test.tsx index a64300d..d519de4 100644 --- a/src/components/modals/SettingsModal/SettingsModal.test.tsx +++ b/src/components/modals/SettingsModal/SettingsModal.test.tsx @@ -40,7 +40,6 @@ describe('SettingsModal', () => { stateCueMode: 'enhanced', fontScale: 1, glossaryTermsEnabled: true, - viewModeFavorites: ['weekly', 'monthly'], }), ); @@ -97,7 +96,6 @@ describe('SettingsModal', () => { stateCueMode: 'enhanced', fontScale: 1, glossaryTermsEnabled: true, - viewModeFavorites: ['weekly', 'monthly'], }), ); @@ -148,19 +146,6 @@ describe('SettingsModal', () => { expect(screen.getByRole('status')).toHaveTextContent('Showing matching presets for "ocean".'); }); - it('finds view mode favorites by cadence value and narrows visible options', async () => { - const user = userEvent.setup(); - renderSettingsModal(); - - await user.type(screen.getByLabelText(/search settings/i), 'quarterly'); - - expect(screen.getByRole('heading', { name: 'App Data and Reset' })).toBeInTheDocument(); - expect(screen.getByRole('heading', { name: 'View Mode Favorites' })).toBeInTheDocument(); - expect(screen.getByLabelText('Quarterly')).toBeInTheDocument(); - expect(screen.queryByLabelText('Weekly')).not.toBeInTheDocument(); - expect(screen.getByRole('status')).toHaveTextContent('Showing matching view modes for "quarterly".'); - }); - it('explains theme mode and preset distinctions in appearance settings', () => { renderSettingsModal(); diff --git a/src/components/modals/SettingsModal/SettingsModal.tsx b/src/components/modals/SettingsModal/SettingsModal.tsx index 28a6cf9..8d44884 100644 --- a/src/components/modals/SettingsModal/SettingsModal.tsx +++ b/src/components/modals/SettingsModal/SettingsModal.tsx @@ -5,10 +5,8 @@ import { APP_CUSTOM_EVENTS } from '../../../constants/events'; import { useAppDialogs } from '../../../hooks'; import { useTheme } from '../../../contexts/ThemeContext'; import type { AppearancePreset, ColorVisionMode, StateCueMode, ThemeMode } from '../../../types/appearance'; -import type { SelectableViewMode } from '../../../types/viewMode'; -import { Button, CheckboxGroup, Dropdown, ErrorDialog, InfoBox, Modal, PillToggle } from '../../_shared'; +import { Button, Dropdown, ErrorDialog, InfoBox, Modal, PillToggle } from '../../_shared'; import { FileStorageService } from '../../../services/fileStorage'; -import { MAX_VISIBLE_FAVORITE_VIEW_MODES, SELECTABLE_VIEW_MODES, sanitizeFavoriteViewModes } from '../../../utils/viewModePreferences'; import { normalizeAppearancePreset, normalizeColorVisionMode, @@ -34,7 +32,6 @@ interface SettingsState { stateCueMode: StateCueMode; fontScale: number; glossaryTermsEnabled: boolean; - viewModeFavorites: SelectableViewMode[]; } const COLOR_VISION_OPTIONS: Array<{ value: ColorVisionMode; label: string; description: string }> = [ @@ -63,23 +60,6 @@ interface SettingsSection { searchTerms: string; } -const formatViewModeLabel = (mode: SelectableViewMode): string => { - if (mode === 'bi-weekly') { - return 'Bi-weekly'; - } - - if (mode === 'semi-monthly') { - return 'Semi-monthly'; - } - - return mode.charAt(0).toUpperCase() + mode.slice(1); -}; - -const VIEW_MODE_OPTIONS = SELECTABLE_VIEW_MODES.map((mode) => ({ - value: mode, - label: formatViewModeLabel(mode), -})); - const SETTINGS_SECTIONS: SettingsSection[] = [ { id: 'appearance', @@ -102,10 +82,7 @@ const SETTINGS_SECTIONS: SettingsSection[] = [ { id: 'app-data-reset', title: 'App Data and Reset', - searchTerms: [ - 'view mode cadence favorites app data reset import backup', - VIEW_MODE_OPTIONS.map((option) => `${option.value} ${option.label}`).join(' '), - ].join(' '), + searchTerms: 'app data reset import backup', }, ]; @@ -129,7 +106,6 @@ const SettingsModal: React.FC = ({ isOpen, onClose, initialS stateCueMode: normalizeStateCueMode(appSettings.stateCueMode), fontScale: normalizeFontScale(appSettings.fontScale), glossaryTermsEnabled: appSettings.glossaryTermsEnabled !== false, - viewModeFavorites: sanitizeFavoriteViewModes(appSettings.viewModeFavorites), }); const [settings, setSettings] = useState(() => { @@ -149,7 +125,6 @@ const SettingsModal: React.FC = ({ isOpen, onClose, initialS stateCueMode: updated.stateCueMode, fontScale: updated.fontScale, glossaryTermsEnabled: updated.glossaryTermsEnabled, - viewModeFavorites: sanitizeFavoriteViewModes(updated.viewModeFavorites), }); }; @@ -224,18 +199,6 @@ const SettingsModal: React.FC = ({ isOpen, onClose, initialS window.dispatchEvent(new CustomEvent(APP_CUSTOM_EVENTS.glossaryTermsChanged, { detail: { enabled } })); }; - const handleViewModeFavoritesChange = (values: string[]) => { - const nextFavorites = sanitizeFavoriteViewModes(values).slice(0, MAX_VISIBLE_FAVORITE_VIEW_MODES) as SelectableViewMode[]; - - const updated = { - ...settings, - viewModeFavorites: nextFavorites, - }; - setSettings(updated); - persistSettings(updated); - window.dispatchEvent(new Event(APP_CUSTOM_EVENTS.viewModeFavoritesChanged)); - }; - const handleExportBackup = async () => { setBackingUp(true); try { @@ -286,7 +249,6 @@ const SettingsModal: React.FC = ({ isOpen, onClose, initialS window.dispatchEvent(new Event(APP_CUSTOM_EVENTS.themeModeChanged)); window.dispatchEvent(new Event(APP_CUSTOM_EVENTS.appearanceSettingsChanged)); window.dispatchEvent(new CustomEvent(APP_CUSTOM_EVENTS.glossaryTermsChanged, { detail: { enabled: newGlossary } })); - window.dispatchEvent(new Event(APP_CUSTOM_EVENTS.viewModeFavoritesChanged)); const reopenResult = await window.electronAPI.reopenWelcomeWindow(); if (!reopenResult.success) { throw new Error(reopenResult.error || 'Failed to reopen welcome window'); @@ -365,27 +327,6 @@ const SettingsModal: React.FC = ({ isOpen, onClose, initialS return APPEARANCE_PRESET_OPTIONS.filter((preset) => matchingAppearancePresetValues.has(preset.value)); }, [matchingAppearancePresetValues]); - const matchingViewModeValues = useMemo(() => { - if (searchTokens.length === 0) { - return null; - } - - const matches = VIEW_MODE_OPTIONS.filter((option) => { - const corpus = `${option.value} ${option.label}`.toLowerCase(); - return searchTokens.every((token) => corpus.includes(token)); - }).map((option) => option.value); - - return new Set(matches); - }, [searchTokens]); - - const visibleViewModeOptions = useMemo(() => { - if (!matchingViewModeValues || matchingViewModeValues.size === 0) { - return VIEW_MODE_OPTIONS; - } - - return VIEW_MODE_OPTIONS.filter((option) => matchingViewModeValues.has(option.value)); - }, [matchingViewModeValues]); - const visibleSectionIds = useMemo(() => new Set(visibleSections.map((section) => section.id)), [visibleSections]); useEffect(() => { @@ -440,7 +381,7 @@ const SettingsModal: React.FC = ({ isOpen, onClose, initialS isOpen={isOpen} onClose={onClose} contentClassName="settings-modal-content" - header="Settings" + header="App Settings" footer={