diff --git a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx index cd38afd5dc435b388d494a9cdc117fda1beebad3..41bc750bcb52ed6ccbdf6850e0919a8daaadc5d8 100644 --- a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx +++ b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx @@ -25,6 +25,7 @@ import { useSyncedPref } from '../../hooks/useSyncedPref'; import { SvgSplit } from '../../icons/v0'; import { useResponsive } from '../../ResponsiveProvider'; import { type CSSProperties, theme, styles } from '../../style'; +import { useRolloverSheetValue } from '../budget/rollover/RolloverComponents'; import { makeAmountFullStyle } from '../budget/util'; import { Text } from '../common/Text'; import { TextOneLine } from '../common/TextOneLine'; @@ -377,14 +378,17 @@ function CategoryItem({ : {}; const [budgetType = 'rollover'] = useSyncedPref('budgetType'); - const balance = useSheetValue( + const balanceBinding = budgetType === 'rollover' ? rolloverBudget.catBalance(item.id) - : reportBudget.catBalance(item.id), - ); + : reportBudget.catBalance(item.id); + const balance = useSheetValue< + 'rollover-budget' | 'report-budget', + typeof balanceBinding + >(balanceBinding); const isToBeBudgetedItem = item.id === 'to-be-budgeted'; - const toBudget = useSheetValue(rolloverBudget.toBudget); + const toBudget = useRolloverSheetValue(rolloverBudget.toBudget) ?? 0; return ( <div diff --git a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx index d90ae1f269ef1c484976a693e624b1c237f389bd..e3d018dad20e59a32abf1d817aada0d9849c3b05 100644 --- a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx +++ b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx @@ -21,11 +21,11 @@ type BalanceWithCarryoverProps = Omit< ComponentPropsWithoutRef<typeof CellValue>, 'binding' > & { - carryover: Binding; - balance: Binding; - goal: Binding; - budgeted: Binding; - longGoal: Binding; + carryover: Binding<'rollover-budget', 'carryover'>; + balance: Binding<'rollover-budget', 'leftover'>; + goal: Binding<'rollover-budget', 'goal'>; + budgeted: Binding<'rollover-budget', 'budget'>; + longGoal: Binding<'rollover-budget', 'long-goal'>; disabled?: boolean; carryoverIndicator?: ({ style }: CarryoverIndicatorProps) => JSX.Element; }; diff --git a/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx b/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx index 0673620ff3734c2f57700538483c2d2318da71ef..5917be96f451feff0ec2232cbe251df1f00f0dfc 100644 --- a/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx +++ b/packages/desktop-client/src/components/budget/report/BalanceMenu.tsx @@ -3,7 +3,8 @@ import React, { type ComponentPropsWithoutRef } from 'react'; import { reportBudget } from 'loot-core/src/client/queries'; import { Menu } from '../../common/Menu'; -import { useSheetValue } from '../../spreadsheet/useSheetValue'; + +import { useReportSheetValue } from './ReportComponents'; type BalanceMenuProps = Omit< ComponentPropsWithoutRef<typeof Menu>, @@ -18,7 +19,7 @@ export function BalanceMenu({ onCarryover, ...props }: BalanceMenuProps) { - const carryover = useSheetValue(reportBudget.catCarryover(categoryId)); + const carryover = useReportSheetValue(reportBudget.catCarryover(categoryId)); return ( <Menu {...props} diff --git a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx index b0f2345343ac92af078edfe1fc0d52ce9ebac977..ff9f429b3a81205501be6144b96f064550a0f53c 100644 --- a/packages/desktop-client/src/components/budget/report/ReportComponents.tsx +++ b/packages/desktop-client/src/components/budget/report/ReportComponents.tsx @@ -12,15 +12,37 @@ import { Button } from '../../common/Button2'; import { Popover } from '../../common/Popover'; import { Text } from '../../common/Text'; import { View } from '../../common/View'; -import { CellValue } from '../../spreadsheet/CellValue'; +import { type Binding, type SheetFields } from '../../spreadsheet'; +import { CellValue, type CellValueProps } from '../../spreadsheet/CellValue'; import { useFormat } from '../../spreadsheet/useFormat'; -import { Field, SheetCell } from '../../table'; +import { useSheetValue } from '../../spreadsheet/useSheetValue'; +import { Field, SheetCell, type SheetCellProps } from '../../table'; import { BalanceWithCarryover } from '../BalanceWithCarryover'; import { makeAmountGrey } from '../util'; import { BalanceMenu } from './BalanceMenu'; import { BudgetMenu } from './BudgetMenu'; +export const useReportSheetValue = < + FieldName extends SheetFields<'report-budget'>, +>( + binding: Binding<'report-budget', FieldName>, +) => { + return useSheetValue(binding); +}; + +const ReportCellValue = <FieldName extends SheetFields<'report-budget'>>( + props: CellValueProps<'report-budget', FieldName>, +) => { + return <CellValue {...props} />; +}; + +const ReportSheetCell = <FieldName extends SheetFields<'report-budget'>>( + props: SheetCellProps<'report-budget', FieldName>, +) => { + return <SheetCell {...props} />; +}; + const headerLabelStyle: CSSProperties = { flex: 1, padding: '0 5px', @@ -40,7 +62,7 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() { > <View style={headerLabelStyle}> <Text style={{ color: theme.pageTextLight }}>Budgeted</Text> - <CellValue + <ReportCellValue binding={reportBudget.totalBudgetedExpense} type="financial" style={{ color: theme.pageTextLight, fontWeight: 600 }} @@ -51,7 +73,7 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() { </View> <View style={headerLabelStyle}> <Text style={{ color: theme.pageTextLight }}>Spent</Text> - <CellValue + <ReportCellValue binding={reportBudget.totalSpent} type="financial" style={{ color: theme.pageTextLight, fontWeight: 600 }} @@ -59,7 +81,7 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() { </View> <View style={headerLabelStyle}> <Text style={{ color: theme.pageTextLight }}>Balance</Text> - <CellValue + <ReportCellValue binding={reportBudget.totalLeftover} type="financial" style={{ color: theme.pageTextLight, fontWeight: 600 }} @@ -108,7 +130,7 @@ export const GroupMonth = memo(function GroupMonth({ : theme.budgetHeaderOtherMonth, }} > - <SheetCell + <ReportSheetCell name="budgeted" width="flex" textAlign="right" @@ -118,7 +140,7 @@ export const GroupMonth = memo(function GroupMonth({ type: 'financial', }} /> - <SheetCell + <ReportSheetCell name="spent" width="flex" textAlign="right" @@ -129,7 +151,7 @@ export const GroupMonth = memo(function GroupMonth({ }} /> {!group.is_income && ( - <SheetCell + <ReportSheetCell name="balance" width="flex" textAlign="right" @@ -270,7 +292,7 @@ export const CategoryMonth = memo(function CategoryMonth({ </Popover> </View> )} - <SheetCell + <ReportSheetCell name="budget" exposed={editing} focused={editing} @@ -320,7 +342,7 @@ export const CategoryMonth = memo(function CategoryMonth({ data-testid="category-month-spent" onClick={() => onShowActivity(category.id, month)} > - <CellValue + <ReportCellValue binding={reportBudget.catSumAmount(category.id)} type="financial" getStyle={makeAmountGrey} diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx index 7edb74feeee23695e8f646dd9ec5bc1e91f91d5e..a19c936f17331def40b7c03a12212c86f95ba988 100644 --- a/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx +++ b/packages/desktop-client/src/components/budget/report/budgetsummary/BudgetTotal.tsx @@ -1,7 +1,6 @@ // @ts-strict-ignore import React, { type CSSProperties, - type ComponentProps, type ComponentType, type ReactNode, } from 'react'; @@ -9,22 +8,29 @@ import React, { import { theme, styles } from '../../../../style'; import { Text } from '../../../common/Text'; import { View } from '../../../common/View'; +import { type SheetFields, type Binding } from '../../../spreadsheet'; import { CellValue } from '../../../spreadsheet/CellValue'; -type BudgetTotalProps = { +type BudgetTotalProps< + CurrentField extends SheetFields<'report-budget'>, + TargetField extends SheetFields<'report-budget'>, +> = { title: ReactNode; - current: ComponentProps<typeof CellValue>['binding']; - target: ComponentProps<typeof CellValue>['binding']; + current: Binding<'report-budget', CurrentField>; + target: Binding<'report-budget', TargetField>; ProgressComponent: ComponentType<{ current; target }>; style?: CSSProperties; }; -export function BudgetTotal({ +export function BudgetTotal< + CurrentField extends SheetFields<'report-budget'>, + TargetField extends SheetFields<'report-budget'>, +>({ title, current, target, ProgressComponent, style, -}: BudgetTotalProps) { +}: BudgetTotalProps<CurrentField, TargetField>) { return ( <View style={{ diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx index 3aeb331203991ac3e846e07b25eee107e595c93e..7d3a8aeda11d2304d3482dfdc0bc8886a493ecf0 100644 --- a/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx +++ b/packages/desktop-client/src/components/budget/report/budgetsummary/ExpenseProgress.tsx @@ -1,19 +1,19 @@ -import React, { type ComponentProps } from 'react'; +import React from 'react'; import { theme } from '../../../../style'; -import { type CellValue } from '../../../spreadsheet/CellValue'; -import { useSheetValue } from '../../../spreadsheet/useSheetValue'; +import { type Binding } from '../../../spreadsheet'; +import { useReportSheetValue } from '../ReportComponents'; import { fraction } from './fraction'; import { PieProgress } from './PieProgress'; type ExpenseProgressProps = { - current: ComponentProps<typeof CellValue>['binding']; - target: ComponentProps<typeof CellValue>['binding']; + current: Binding<'report-budget', 'total-spent'>; + target: Binding<'report-budget', 'total-budgeted'>; }; export function ExpenseProgress({ current, target }: ExpenseProgressProps) { - let totalSpent = useSheetValue(current) || 0; - const totalBudgeted = useSheetValue(target) || 0; + let totalSpent = useReportSheetValue(current) || 0; + const totalBudgeted = useReportSheetValue(target) || 0; // Reverse total spent, and also set a bottom boundary of 0 (in case // income goes into an expense category and it's "positive", don't diff --git a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx index 883021b5efe7ee4ffbf2e7afa1ec1f0df0eb0e50..142f9b4772156d0d4ee4640683cb64a79bfe6232 100644 --- a/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx +++ b/packages/desktop-client/src/components/budget/report/budgetsummary/Saved.tsx @@ -11,16 +11,17 @@ import { Tooltip } from '../../../common/Tooltip'; import { View } from '../../../common/View'; import { PrivacyFilter } from '../../../PrivacyFilter'; import { useFormat } from '../../../spreadsheet/useFormat'; -import { useSheetValue } from '../../../spreadsheet/useSheetValue'; import { makeAmountFullStyle } from '../../util'; +import { useReportSheetValue } from '../ReportComponents'; type SavedProps = { projected: boolean; style?: CSSProperties; }; export function Saved({ projected, style }: SavedProps) { - const budgetedSaved = useSheetValue(reportBudget.totalBudgetedSaved) || 0; - const totalSaved = useSheetValue(reportBudget.totalSaved) || 0; + const budgetedSaved = + useReportSheetValue(reportBudget.totalBudgetedSaved) || 0; + const totalSaved = useReportSheetValue(reportBudget.totalSaved) || 0; const format = useFormat(); const saved = projected ? budgetedSaved : totalSaved; const isNegative = saved < 0; diff --git a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx index 34833347657b61dd8ab1dbd9fee4d474e7334217..c115e0747f551f931c972d40004ca33968b812dd 100644 --- a/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx +++ b/packages/desktop-client/src/components/budget/rollover/budgetsummary/ToBudgetMenu.tsx @@ -21,7 +21,7 @@ export function ToBudgetMenu({ onResetHoldBuffer, ...props }: ToBudgetMenuProps) { - const toBudget = useRolloverSheetValue(rolloverBudget.toBudget); + const toBudget = useRolloverSheetValue(rolloverBudget.toBudget) ?? 0; const forNextMonth = useRolloverSheetValue(rolloverBudget.forNextMonth); const items = [ ...(toBudget > 0 diff --git a/packages/desktop-client/src/components/modals/HoldBufferModal.tsx b/packages/desktop-client/src/components/modals/HoldBufferModal.tsx index 801c435f717182eb691253ee1cb95434693efccf..9cc1ffb1379af131bbfdb8abd5d9581560d65b83 100644 --- a/packages/desktop-client/src/components/modals/HoldBufferModal.tsx +++ b/packages/desktop-client/src/components/modals/HoldBufferModal.tsx @@ -17,7 +17,7 @@ type HoldBufferModalProps = { }; export function HoldBufferModal({ onSubmit }: HoldBufferModalProps) { - const available = useRolloverSheetValue(rolloverBudget.toBudget); + const available = useRolloverSheetValue(rolloverBudget.toBudget) ?? 0; const [amount, setAmount] = useState<number>(0); const _onSubmit = (newAmount: number) => { diff --git a/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx b/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx index b28976d6379e69cb0c295e6458cdaf0e3c8517f7..b842cd5dc2122c016f8947cf74992c8a456561e5 100644 --- a/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx +++ b/packages/desktop-client/src/components/modals/ReportBudgetMenuModal.tsx @@ -10,6 +10,7 @@ import { amountToInteger, integerToAmount } from 'loot-core/shared/util'; import { useCategory } from '../../hooks/useCategory'; import { type CSSProperties, theme, styles } from '../../style'; import { BudgetMenu } from '../budget/report/BudgetMenu'; +import { useReportSheetValue } from '../budget/report/ReportComponents'; import { Modal, ModalCloseButton, @@ -19,7 +20,6 @@ import { import { Text } from '../common/Text'; import { View } from '../common/View'; import { FocusableAmountInput } from '../mobile/transactions/FocusableAmountInput'; -import { useSheetValue } from '../spreadsheet/useSheetValue'; type ReportBudgetMenuModalProps = ComponentPropsWithoutRef< typeof BudgetMenu @@ -42,7 +42,7 @@ export function ReportBudgetMenuModal({ borderTop: `1px solid ${theme.pillBorder}`, }; - const budgeted = useSheetValue(reportBudget.catBudgeted(categoryId)); + const budgeted = useReportSheetValue(reportBudget.catBudgeted(categoryId)); const category = useCategory(categoryId); const [amountFocused, setAmountFocused] = useState(false); diff --git a/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx b/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx index 5abfafef6c74ae559d7660660a9918f3dca000c3..0c64e62687afdce8e5a8af1248810e9e82a99c06 100644 --- a/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx +++ b/packages/desktop-client/src/components/modals/RolloverBudgetSummaryModal.tsx @@ -23,10 +23,11 @@ export function RolloverBudgetSummaryModal({ }: RolloverBudgetSummaryModalProps) { const dispatch = useDispatch(); const prevMonthName = format(prevMonth(month), 'MMM'); - const sheetValue = useRolloverSheetValue({ - name: rolloverBudget.toBudget, - value: 0, - }); + const sheetValue = + useRolloverSheetValue({ + name: rolloverBudget.toBudget, + value: 0, + }) ?? 0; const openTransferAvailableModal = () => { dispatch( diff --git a/packages/desktop-client/src/components/spreadsheet/CellValue.tsx b/packages/desktop-client/src/components/spreadsheet/CellValue.tsx index ef1228c79910d7d7943d7e036b98b42476c3fa89..dd96739e3657085568a717e4a8e42ef6f24d4617 100644 --- a/packages/desktop-client/src/components/spreadsheet/CellValue.tsx +++ b/packages/desktop-client/src/components/spreadsheet/CellValue.tsx @@ -26,7 +26,10 @@ export type CellValueProps< ['data-testid']?: string; }; -export function CellValue({ +export function CellValue< + SheetName extends SheetNames, + FieldName extends SheetFields<SheetName>, +>({ binding, type, formatter, @@ -35,8 +38,7 @@ export function CellValue({ privacyFilter, 'data-testid': testId, ...props - // eslint-disable-next-line @typescript-eslint/no-explicit-any -}: CellValueProps<any, any>) { +}: CellValueProps<SheetName, FieldName>) { const { fullSheetName } = useSheetName(binding); const sheetValue = useSheetValue(binding); const format = useFormat(); diff --git a/packages/desktop-client/src/components/spreadsheet/index.ts b/packages/desktop-client/src/components/spreadsheet/index.ts index 429e50441fa949b64d64f352ee7a8e7a7c5103fe..e9ff3d7aa7ac4136ea6d168406bd693a33e75e79 100644 --- a/packages/desktop-client/src/components/spreadsheet/index.ts +++ b/packages/desktop-client/src/components/spreadsheet/index.ts @@ -23,7 +23,7 @@ export type Spreadsheets = { 'available-funds': number; 'last-month-overspent': number; buffered: number; - 'to-budget': number; + 'to-budget': number | null; 'from-last-month': number; 'total-budgeted': number; 'total-income': number; @@ -39,6 +39,29 @@ export type Spreadsheets = { goal: number; 'long-goal': number; }; + 'report-budget': { + // Common fields + 'uncategorized-amount': number; + 'uncategorized-balance': number; + + // Report fields + 'total-budgeted': number; + 'total-budget-income': number; + 'total-saved': number; + 'total-income': number; + 'total-spent': number; + 'real-saved': number; + 'total-leftover': number; + 'group-sum-amount': number; + 'group-budget': number; + 'group-leftover': number; + budget: number; + 'sum-amount': number; + leftover: number; + carryover: number; + goal: number; + 'long-goal': number; + }; }; export type SheetNames = keyof Spreadsheets & string; @@ -47,10 +70,8 @@ export type SheetFields<SheetName extends SheetNames> = keyof Spreadsheets[SheetName] & string; export type Binding< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - SheetName extends SheetNames = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - SheetFieldName extends SheetFields<SheetName> = any, + SheetName extends SheetNames, + SheetFieldName extends SheetFields<SheetName>, > = | SheetFieldName | { diff --git a/packages/desktop-client/src/components/spreadsheet/useSheetName.ts b/packages/desktop-client/src/components/spreadsheet/useSheetName.ts index 621efc523c6af1c838093970391a33eafc6a945d..2d5d287897756b062b1f73c118cf288e119fab46 100644 --- a/packages/desktop-client/src/components/spreadsheet/useSheetName.ts +++ b/packages/desktop-client/src/components/spreadsheet/useSheetName.ts @@ -3,7 +3,7 @@ import { useContext } from 'react'; import { NamespaceContext } from './NamespaceContext'; -import { type Binding } from '.'; +import { type SheetNames, type SheetFields, type Binding } from '.'; function unresolveName(name) { const idx = name.indexOf('!'); @@ -16,14 +16,17 @@ function unresolveName(name) { return { sheet: null, name }; } -export function useSheetName(binding: Binding) { +export function useSheetName< + SheetName extends SheetNames, + FieldName extends SheetFields<SheetName>, +>(binding: Binding<SheetName, FieldName>) { if (!binding) { throw new Error('Sheet binding is required'); } const isStringBinding = typeof binding === 'string'; - let bindingName = isStringBinding ? binding : binding.name; + let bindingName: string = isStringBinding ? binding : binding.name; if (global.IS_TESTING && !isStringBinding && !bindingName) { bindingName = binding.value.toString(); diff --git a/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts b/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts index 1b6c5c0c5bcc9a2ef024cd860dc01ba319dacfae..62061fede0c528f959f643f7fa8af22ba229eda5 100644 --- a/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts +++ b/packages/desktop-client/src/components/spreadsheet/useSheetValue.ts @@ -5,13 +5,26 @@ import { useSpreadsheet } from 'loot-core/src/client/SpreadsheetProvider'; import { useSheetName } from './useSheetName'; -import { type Binding } from '.'; - -export function useSheetValue(binding: Binding, onChange?: (result) => void) { +import { + type Spreadsheets, + type SheetFields, + type SheetNames, + type Binding, +} from '.'; + +export function useSheetValue< + SheetName extends SheetNames, + FieldName extends SheetFields<SheetName>, +>( + binding: Binding<SheetName, FieldName>, + onChange?: (result) => void, +): Spreadsheets[SheetName][FieldName] { const { sheetName, fullSheetName } = useSheetName(binding); const bindingObj = - typeof binding === 'string' ? { name: binding, value: null } : binding; + typeof binding === 'string' + ? { name: binding, value: null, query: undefined } + : binding; const spreadsheet = useSpreadsheet(); const [result, setResult] = useState({ diff --git a/packages/desktop-client/src/components/table.tsx b/packages/desktop-client/src/components/table.tsx index 4d47f531511be770ba77939f30bd5ce9b63d8485..c62d6111b697c15cd82e508e9111d328d6d82751 100644 --- a/packages/desktop-client/src/components/table.tsx +++ b/packages/desktop-client/src/components/table.tsx @@ -705,10 +705,8 @@ export type SheetCellProps< textAlign?: CSSProperties['textAlign']; }; export function SheetCell< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - SheetName extends SheetNames = any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - FieldName extends SheetFields<SheetName> = any, + SheetName extends SheetNames, + FieldName extends SheetFields<SheetName>, >({ valueProps, valueStyle, diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx index 9debc52197d4630a0916c3047b64194541cb20bc..157c31c89ac9458c167da161a62ef917176f7754 100644 --- a/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx @@ -28,7 +28,9 @@ import { ResponsiveProvider } from '../../ResponsiveProvider'; import { TransactionTable } from './TransactionsTable'; vi.mock('loot-core/src/platform/client/fetch'); -vi.mock('../../hooks/useFeatureFlag', () => vi.fn().mockReturnValue(false)); +vi.mock('../../hooks/useFeatureFlag', () => ({ + default: vi.fn().mockReturnValue(false), +})); const accounts = [generateAccount('Bank of America')]; const payees = [ diff --git a/packages/loot-core/src/client/queries.ts b/packages/loot-core/src/client/queries.ts index fef175374e07b7d4c619888308f267725211c41d..ec5e124977ca2ccf0fe588ecb46bb7598be18b05 100644 --- a/packages/loot-core/src/client/queries.ts +++ b/packages/loot-core/src/client/queries.ts @@ -26,6 +26,7 @@ type BudgetType<SheetName extends SheetNames> = Record< const accountParametrizedField = parametrizedField<'account'>(); const rolloverParametrizedField = parametrizedField<'rollover-budget'>(); +const reportParametrizedField = parametrizedField<'report-budget'>(); export function getAccountFilter(accountId: string, field = 'account') { if (accountId) { @@ -294,16 +295,16 @@ export const reportBudget = { totalSaved: 'real-saved', totalLeftover: 'total-leftover', - groupSumAmount: id => `group-sum-amount-${id}`, + groupSumAmount: reportParametrizedField('group-sum-amount'), groupIncomeReceived: 'total-income', - groupBudgeted: id => `group-budget-${id}`, - groupBalance: id => `group-leftover-${id}`, + groupBudgeted: reportParametrizedField('group-budget'), + groupBalance: reportParametrizedField('group-leftover'), - catBudgeted: id => `budget-${id}`, - catSumAmount: id => `sum-amount-${id}`, - catBalance: id => `leftover-${id}`, - catCarryover: id => `carryover-${id}`, - catGoal: id => `goal-${id}`, - catLongGoal: id => `long-goal-${id}`, -}; + catBudgeted: reportParametrizedField('budget'), + catSumAmount: reportParametrizedField('sum-amount'), + catBalance: reportParametrizedField('leftover'), + catCarryover: reportParametrizedField('carryover'), + catGoal: reportParametrizedField('goal'), + catLongGoal: reportParametrizedField('long-goal'), +} satisfies BudgetType<'report-budget'>; diff --git a/upcoming-release-notes/3097.md b/upcoming-release-notes/3097.md new file mode 100644 index 0000000000000000000000000000000000000000..46315010044a5a968659ec5c3fbe23f6cd4ca0c6 --- /dev/null +++ b/upcoming-release-notes/3097.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [jfdoming] +--- + +Support type-checking on spreadsheet fields (part 3)