diff --git a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx index c8733e81790b546c284aac86101b30b272a89f25..c5d0a2462b42d6fb6f1e7209c66adbb8fe2f0502 100644 --- a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx +++ b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx @@ -22,7 +22,7 @@ import { } from 'loot-core/src/types/models'; import { useCategories } from '../../hooks/useCategories'; -import { useMetadataPref } from '../../hooks/useMetadataPref'; +import { useSyncedPref } from '../../hooks/useSyncedPref'; import { SvgSplit } from '../../icons/v0'; import { useResponsive } from '../../ResponsiveProvider'; import { type CSSProperties, theme, styles } from '../../style'; @@ -379,7 +379,7 @@ function CategoryItem({ borderTop: `1px solid ${theme.pillBorder}`, } : {}; - const [budgetType = 'rollover'] = useMetadataPref('budgetType'); + const [budgetType = 'rollover'] = useSyncedPref('budgetType'); const balanceBinding = budgetType === 'rollover' diff --git a/packages/desktop-client/src/components/budget/index.tsx b/packages/desktop-client/src/components/budget/index.tsx index e1ecb6e9ba92b5fd17dafb161c9ce5f952e7f581..af22d5b6e473a48c9abaaae5e0ae18db70910741 100644 --- a/packages/desktop-client/src/components/budget/index.tsx +++ b/packages/desktop-client/src/components/budget/index.tsx @@ -24,8 +24,8 @@ import * as monthUtils from 'loot-core/src/shared/months'; import { useCategories } from '../../hooks/useCategories'; import { useGlobalPref } from '../../hooks/useGlobalPref'; import { useLocalPref } from '../../hooks/useLocalPref'; -import { useMetadataPref } from '../../hooks/useMetadataPref'; import { useNavigate } from '../../hooks/useNavigate'; +import { useSyncedPref } from '../../hooks/useSyncedPref'; import { styles } from '../../style'; import { View } from '../common/View'; import { NamespaceContext } from '../spreadsheet/NamespaceContext'; @@ -78,7 +78,7 @@ function BudgetInner(props: BudgetInnerProps) { start: startMonth, end: startMonth, }); - const [budgetType = 'rollover'] = useMetadataPref('budgetType'); + const [budgetType = 'rollover'] = useSyncedPref('budgetType'); const [maxMonthsPref] = useGlobalPref('maxMonths'); const maxMonths = maxMonthsPref || 1; const [initialized, setInitialized] = useState(false); diff --git a/packages/desktop-client/src/components/budget/util.ts b/packages/desktop-client/src/components/budget/util.ts index 239a5ba15bc30f79ad85e366b1ed53fc75941248..c8f7c61856b6da0193fe41ac1aadcacba779d45c 100644 --- a/packages/desktop-client/src/components/budget/util.ts +++ b/packages/desktop-client/src/components/budget/util.ts @@ -4,7 +4,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import * as monthUtils from 'loot-core/src/shared/months'; import { type Handlers } from 'loot-core/src/types/handlers'; import { type CategoryGroupEntity } from 'loot-core/src/types/models'; -import { type MetadataPrefs } from 'loot-core/src/types/prefs'; +import { type SyncedPrefs } from 'loot-core/src/types/prefs'; import { type CSSProperties, styles, theme } from '../../style'; import { type DropPosition } from '../sort'; @@ -141,7 +141,7 @@ export function getScrollbarWidth() { } export async function prewarmMonth( - budgetType: MetadataPrefs['budgetType'], + budgetType: SyncedPrefs['budgetType'], spreadsheet: ReturnType<typeof useSpreadsheet>, month: string, ) { @@ -156,7 +156,7 @@ export async function prewarmMonth( } export async function prewarmAllMonths( - budgetType: MetadataPrefs['budgetType'], + budgetType: SyncedPrefs['budgetType'], spreadsheet: ReturnType<typeof useSpreadsheet>, bounds: { start: string; end: string }, startMonth: string, @@ -174,17 +174,3 @@ export async function prewarmAllMonths( months.map(month => prewarmMonth(budgetType, spreadsheet, month)), ); } - -export async function switchBudgetType( - newBudgetType: MetadataPrefs['budgetType'], - spreadsheet: ReturnType<typeof useSpreadsheet>, - bounds: { start: string; end: string }, - startMonth: string, - onSuccess: () => Promise<void> | undefined, -) { - spreadsheet.disableObservers(); - await send('budget-set-type', { type: newBudgetType }); - await prewarmAllMonths(newBudgetType, spreadsheet, bounds, startMonth); - spreadsheet.enableObservers(); - await onSuccess?.(); -} diff --git a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx index bcef3cfa2af1c4d0be1b58d08c457983319d9179..5d2e1c892aa5bb89b98b43aa52d88dc27b3f1cfc 100644 --- a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx +++ b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx @@ -12,9 +12,9 @@ import * as monthUtils from 'loot-core/src/shared/months'; import { useCategories } from '../../../hooks/useCategories'; import { useFeatureFlag } from '../../../hooks/useFeatureFlag'; import { useLocalPref } from '../../../hooks/useLocalPref'; -import { useMetadataPref } from '../../../hooks/useMetadataPref'; import { useNavigate } from '../../../hooks/useNavigate'; import { useNotes } from '../../../hooks/useNotes'; +import { useSyncedPref } from '../../../hooks/useSyncedPref'; import { useUndo } from '../../../hooks/useUndo'; import { SvgLogo } from '../../../icons/logo'; import { SvgExpandArrow } from '../../../icons/v0'; @@ -225,7 +225,7 @@ function BudgetCell({ }) { const dispatch = useDispatch(); const { showUndoNotification } = useUndo(); - const [budgetType = 'rollover'] = useMetadataPref('budgetType'); + const [budgetType = 'rollover'] = useSyncedPref('budgetType'); const categoryBudgetMenuModal = `${budgetType}-budget-menu`; const categoryNotes = useNotes(category.id); @@ -358,7 +358,7 @@ const ExpenseCategory = memo(function ExpenseCategory({ const goalTemp = useSheetValue(goal); const goalValue = isGoalTemplatesEnabled ? goalTemp : null; - const [budgetType = 'rollover'] = useMetadataPref('budgetType'); + const [budgetType = 'rollover'] = useSyncedPref('budgetType'); const dispatch = useDispatch(); const { showUndoNotification } = useUndo(); const { list: categories } = useCategories(); diff --git a/packages/desktop-client/src/components/mobile/budget/index.tsx b/packages/desktop-client/src/components/mobile/budget/index.tsx index cb89707082c75b8dda2bd4cb75311c1bad3da0c6..ebb6062384fcb1227828737bcb62419d9608985e 100644 --- a/packages/desktop-client/src/components/mobile/budget/index.tsx +++ b/packages/desktop-client/src/components/mobile/budget/index.tsx @@ -23,7 +23,6 @@ import * as monthUtils from 'loot-core/src/shared/months'; import { useCategories } from '../../../hooks/useCategories'; import { useLocalPref } from '../../../hooks/useLocalPref'; -import { useMetadataPref } from '../../../hooks/useMetadataPref'; import { useSetThemeColor } from '../../../hooks/useSetThemeColor'; import { useSyncedPref } from '../../../hooks/useSyncedPref'; import { AnimatedLoading } from '../../../icons/AnimatedLoading'; @@ -43,7 +42,7 @@ export function Budget() { useSetThemeColor(theme.mobileViewTheme); const { list: categories, grouped: categoryGroups } = useCategories(); - const [budgetTypePref] = useMetadataPref('budgetType'); + const [budgetTypePref] = useSyncedPref('budgetType'); const budgetType = isBudgetType(budgetTypePref) ? budgetTypePref : 'rollover'; const spreadsheet = useSpreadsheet(); diff --git a/packages/desktop-client/src/components/settings/BudgetTypeSettings.tsx b/packages/desktop-client/src/components/settings/BudgetTypeSettings.tsx index 7bc50ec0134c32e4f8a6e150f8e7627d39c115e4..c66463cec02417d365e1878c80cf9ae9f86ee4b4 100644 --- a/packages/desktop-client/src/components/settings/BudgetTypeSettings.tsx +++ b/packages/desktop-client/src/components/settings/BudgetTypeSettings.tsx @@ -1,58 +1,27 @@ -import React, { useState } from 'react'; -import { useDispatch } from 'react-redux'; +import React from 'react'; -import { loadPrefs } from 'loot-core/src/client/actions'; -import { useSpreadsheet } from 'loot-core/src/client/SpreadsheetProvider'; -import * as monthUtils from 'loot-core/src/shared/months'; - -import { useLocalPref } from '../../hooks/useLocalPref'; -import { useMetadataPref } from '../../hooks/useMetadataPref'; -import { switchBudgetType } from '../budget/util'; -import { ButtonWithLoading } from '../common/Button2'; +import { useSyncedPref } from '../../hooks/useSyncedPref'; +import { Button } from '../common/Button2'; import { Link } from '../common/Link'; import { Text } from '../common/Text'; import { Setting } from './UI'; export function BudgetTypeSettings() { - const dispatch = useDispatch(); - const [budgetType = 'rollover'] = useMetadataPref('budgetType'); - const [loading, setLoading] = useState(false); - - const currentMonth = monthUtils.currentMonth(); - const [startMonthPref] = useLocalPref('budget.startMonth'); - const startMonth = startMonthPref || currentMonth; - const spreadsheet = useSpreadsheet(); + const [budgetType = 'rollover', setBudgetType] = useSyncedPref('budgetType'); function onSwitchType() { - setLoading(true); - - if (!loading) { - const newBudgetType = budgetType === 'rollover' ? 'report' : 'rollover'; - - switchBudgetType( - newBudgetType, - spreadsheet, - { - start: startMonth, - end: startMonth, - }, - startMonth, - async () => { - dispatch(loadPrefs()); - setLoading(false); - }, - ); - } + const newBudgetType = budgetType === 'rollover' ? 'report' : 'rollover'; + setBudgetType(newBudgetType); } return ( <Setting primaryAction={ - <ButtonWithLoading isLoading={loading} onPress={onSwitchType}> + <Button onPress={onSwitchType}> Switch to {budgetType === 'report' ? 'envelope' : 'tracking'}{' '} budgeting - </ButtonWithLoading> + </Button> } > <Text> diff --git a/packages/desktop-client/src/components/settings/Experimental.tsx b/packages/desktop-client/src/components/settings/Experimental.tsx index 58ccc41d79d5a812b160d29bda199553504b38b8..fa6da21cf849652fbd9728b8edd6f6ffc14306f4 100644 --- a/packages/desktop-client/src/components/settings/Experimental.tsx +++ b/packages/desktop-client/src/components/settings/Experimental.tsx @@ -4,7 +4,6 @@ import { Trans, useTranslation } from 'react-i18next'; import type { FeatureFlag } from 'loot-core/src/types/prefs'; import { useFeatureFlag } from '../../hooks/useFeatureFlag'; -import { useMetadataPref } from '../../hooks/useMetadataPref'; import { useSyncedPref } from '../../hooks/useSyncedPref'; import { theme } from '../../style'; import { Link } from '../common/Link'; @@ -70,7 +69,7 @@ function FeatureToggle({ function ReportBudgetFeature() { const { t } = useTranslation(); - const [budgetType = 'rollover'] = useMetadataPref('budgetType'); + const [budgetType = 'rollover'] = useSyncedPref('budgetType'); const enabled = useFeatureFlag('reportBudget'); const blockToggleOff = budgetType === 'report' && enabled; return ( diff --git a/packages/loot-core/migrations/1723665565000_prefs.js b/packages/loot-core/migrations/1723665565000_prefs.js index cd52e78a226d883dc085f8aa1631afd6caffa51f..fa0ef1e32d2e905831bf0a0f20ab6f71e92fe1e7 100644 --- a/packages/loot-core/migrations/1723665565000_prefs.js +++ b/packages/loot-core/migrations/1723665565000_prefs.js @@ -12,7 +12,7 @@ const SYNCED_PREF_KEYS = [ /^csv-has-header-/, /^ofx-fallback-missing-payee-/, /^flip-amount-/, - // 'budgetType', // TODO: uncomment when `budgetType` moves from metadata to synced prefs + 'budgetType', /^flags\./, ]; diff --git a/packages/loot-core/src/server/budget/actions.ts b/packages/loot-core/src/server/budget/actions.ts index 88ef2f47f45c2bc729bbe075746a56bc33f112b9..28b803e727bd7155803439ec42f912acfa7f4182 100644 --- a/packages/loot-core/src/server/budget/actions.ts +++ b/packages/loot-core/src/server/budget/actions.ts @@ -2,7 +2,6 @@ import * as monthUtils from '../../shared/months'; import { safeNumber } from '../../shared/util'; import * as db from '../db'; -import * as prefs from '../prefs'; import * as sheet from '../sheet'; import { batchMessages } from '../sync'; @@ -28,12 +27,14 @@ function calcBufferedAmount( } function getBudgetTable(): string { - const { budgetType } = prefs.getPrefs() || {}; - return budgetType === 'report' ? 'reflect_budgets' : 'zero_budgets'; + return isReflectBudget() ? 'reflect_budgets' : 'zero_budgets'; } export function isReflectBudget(): boolean { - const { budgetType } = prefs.getPrefs(); + const budgetType = + db.firstSync(`SELECT value FROM preferences WHERE id = ?`, [ + 'budgetType', + ]) ?? 'rollover'; return budgetType === 'report'; } diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts index f3b84fa9a3527825f07c1a58bef4f3f4ab1c5dd7..96dcd85522d688f3bce81a6163f6669cfe5ae195 100644 --- a/packages/loot-core/src/server/main.ts +++ b/packages/loot-core/src/server/main.ts @@ -268,20 +268,6 @@ handlers['report-budget-month'] = async function ({ month }) { return values; }; -handlers['budget-set-type'] = async function ({ type }) { - if (!prefs.BUDGET_TYPES.includes(type)) { - throw new Error('Invalid budget type: ' + type); - } - - // It's already the same; don't do anything - if (type === prefs.getPrefs().budgetType) { - return; - } - - // Save prefs - return prefs.savePrefs({ budgetType: type }); -}; - handlers['category-create'] = mutator(async function ({ name, groupId, @@ -1991,7 +1977,11 @@ async function loadBudget(id) { } // This is a bit leaky, but we need to set the initial budget type - sheet.get().meta().budgetType = prefs.getPrefs().budgetType; + const { value: budgetType = 'rollover' } = + (await db.first('SELECT value from preferences WHERE id = ?', [ + 'budgetType', + ])) ?? {}; + sheet.get().meta().budgetType = budgetType; await budget.createAllBudgets(); // Load all the in-memory state diff --git a/packages/loot-core/src/server/prefs.ts b/packages/loot-core/src/server/prefs.ts index b353acfbe34c87dafbeac7bf6df5108c5320630d..14fd72ddce083bb404f621a69d6b4032796d0906 100644 --- a/packages/loot-core/src/server/prefs.ts +++ b/packages/loot-core/src/server/prefs.ts @@ -44,7 +44,7 @@ export async function savePrefs( // Sync whitelisted prefs const messages: Message[] = Object.keys(prefsToSet) .map(key => { - if (key === 'budgetType' || key === 'budgetName') { + if (key === 'budgetName') { return { dataset: 'prefs', row: key, diff --git a/packages/loot-core/src/server/sheet.ts b/packages/loot-core/src/server/sheet.ts index cad83f701c1e517c614ca79335afeeba94d79f9d..b0729ba5cdf3bb2eb4fe0b6d717d9b0a9ad52710 100644 --- a/packages/loot-core/src/server/sheet.ts +++ b/packages/loot-core/src/server/sheet.ts @@ -6,7 +6,6 @@ import * as sqlite from '../platform/server/sqlite'; import { sheetForMonth } from '../shared/months'; import * as Platform from './platform'; -import * as prefs from './prefs'; import { Spreadsheet } from './spreadsheet/spreadsheet'; import { resolveName } from './spreadsheet/util'; @@ -196,7 +195,10 @@ export async function loadUserBudgets(db): Promise<void> { // TODO: Clear out the cache here so make sure future loads of the app // don't load any extra values that aren't set here - const { budgetType } = prefs.getPrefs() || {}; + const { value: budgetType = 'rollover' } = + (await db.first('SELECT value from preferences WHERE id = ?', [ + 'budgetType', + ])) ?? {}; const table = budgetType === 'report' ? 'reflect_budgets' : 'zero_budgets'; const budgets = await db.all(` diff --git a/packages/loot-core/src/server/sync/index.ts b/packages/loot-core/src/server/sync/index.ts index 843da6e4480ae64ac8d583d203c902bbf27179c7..e50a1735c36db72cd47e39e7e8d8fa8f4223e2b1 100644 --- a/packages/loot-core/src/server/sync/index.ts +++ b/packages/loot-core/src/server/sync/index.ts @@ -359,6 +359,11 @@ export const applyMessages = sequential(async (messages: Message[]) => { currentMerkle = merkle.insert(currentMerkle, timestamp); } + + // Special treatment for some synced prefs + if (dataset === 'preferences' && row === 'budgetType') { + setBudgetType(value); + } } if (checkSyncingMode('enabled')) { @@ -384,11 +389,6 @@ export const applyMessages = sequential(async (messages: Message[]) => { // Save any synced prefs if (Object.keys(prefsToSet).length > 0) { prefs.savePrefs(prefsToSet, { avoidSync: true }); - - if (prefsToSet.budgetType) { - setBudgetType(prefsToSet.budgetType); - } - connection.send('prefs-updated'); } diff --git a/packages/loot-core/src/types/prefs.d.ts b/packages/loot-core/src/types/prefs.d.ts index eb0700a57020357c76f818d8d017ebc09f6054b0..311482687faca9a6ccb6ff8dcfbe17f117fe28a6 100644 --- a/packages/loot-core/src/types/prefs.d.ts +++ b/packages/loot-core/src/types/prefs.d.ts @@ -12,6 +12,7 @@ export type FeatureFlag = */ export type SyncedPrefs = Partial< Record< + | 'budgetType' | 'firstDayOfWeekIdx' | 'dateFormat' | 'numberFormat' @@ -39,8 +40,6 @@ export type SyncedPrefs = Partial< * core database. */ export type MetadataPrefs = Partial<{ - // TODO: move budgetType to SyncedPrefs - budgetType: string; budgetName: string; id: string; lastUploaded: string; diff --git a/packages/loot-core/src/types/server-handlers.d.ts b/packages/loot-core/src/types/server-handlers.d.ts index 51967882f0e59e0d7cf4e30b2112e37d5ddc32b4..5a5c589f64d1e55610e6d573f6cdc135cf1cf6c5 100644 --- a/packages/loot-core/src/types/server-handlers.d.ts +++ b/packages/loot-core/src/types/server-handlers.d.ts @@ -73,8 +73,6 @@ export interface ServerHandlers { }[] >; - 'budget-set-type': (arg: { type }) => Promise<unknown>; - 'category-create': (arg: { name; groupId; diff --git a/upcoming-release-notes/3352.md b/upcoming-release-notes/3352.md index 72bc482ec69097f99ec74ed72044901460662dcc..c99e63939d27433187e6fa9934997bdd9da4eec0 100644 --- a/upcoming-release-notes/3352.md +++ b/upcoming-release-notes/3352.md @@ -3,4 +3,4 @@ category: Maintenance authors: [nmathey] --- -Support translations in Translation support for desktop-client/src/components/budget/BalanceWithCarryover.tsx \ No newline at end of file +Support translations in Translation support for desktop-client/src/components/budget/BalanceWithCarryover.tsx diff --git a/upcoming-release-notes/3427.md b/upcoming-release-notes/3427.md new file mode 100644 index 0000000000000000000000000000000000000000..9624e7a039d36ebf72086bafb700b70bb4504663 --- /dev/null +++ b/upcoming-release-notes/3427.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +SyncedPrefs: move budget type to synced preferences.