diff --git a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png index 2646cc85e09..38e8e4570aa 100644 Binary files a/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png and b/packages/desktop-client/e2e/budget.test.js-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png index e50ea3fe2f2..22186d83389 100644 Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-checks-that-settings-page-can-be-opened-2-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-from-accounts-id-page-1-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-from-accounts-id-page-1-chromium-linux.png index 8b6f637184d..6abd4082738 100644 Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-from-accounts-id-page-1-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-from-accounts-id-page-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-1-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-1-chromium-linux.png index 0cfdffe0d74..e2981f282c6 100644 Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-1-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-2-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-2-chromium-linux.png index 08644ff8375..65935ac1424 100644 Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-2-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-creates-a-transaction-via-footer-button-2-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png index a29cc002d92..90efef73ea0 100644 Binary files a/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png and b/packages/desktop-client/e2e/mobile.test.js-snapshots/Mobile-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/settings.test.js-snapshots/Settings-checks-the-page-visuals-1-chromium-linux.png b/packages/desktop-client/e2e/settings.test.js-snapshots/Settings-checks-the-page-visuals-1-chromium-linux.png index b25a320d879..514fef5fcd2 100644 Binary files a/packages/desktop-client/e2e/settings.test.js-snapshots/Settings-checks-the-page-visuals-1-chromium-linux.png and b/packages/desktop-client/e2e/settings.test.js-snapshots/Settings-checks-the-page-visuals-1-chromium-linux.png differ diff --git a/packages/desktop-client/package.json b/packages/desktop-client/package.json index 5bd8879c351..921766ab9e2 100644 --- a/packages/desktop-client/package.json +++ b/packages/desktop-client/package.json @@ -1,6 +1,6 @@ { "name": "@actual-app/web", - "version": "23.10.0", + "version": "23.11.0", "license": "MIT", "files": [ "build" diff --git a/packages/desktop-client/src/components/Titlebar.tsx b/packages/desktop-client/src/components/Titlebar.tsx index bab3123ba3f..587b3c2f2a0 100644 --- a/packages/desktop-client/src/components/Titlebar.tsx +++ b/packages/desktop-client/src/components/Titlebar.tsx @@ -41,15 +41,21 @@ import useSheetValue from './spreadsheet/useSheetValue'; import { ThemeSelector } from './ThemeSelector'; import { Tooltip } from './tooltips'; -export let TitlebarContext = createContext(null); +export type TitlebarContextValue = { + sendEvent: (msg: string) => void; + subscribe: (listener) => () => void; +}; + +export let TitlebarContext = createContext(null); type TitlebarProviderProps = { children?: ReactNode; }; + export function TitlebarProvider({ children }: TitlebarProviderProps) { let listeners = useRef([]); - function sendEvent(msg) { + function sendEvent(msg: string) { listeners.current.forEach(func => func(msg)); } diff --git a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx index bf7164aff9d..05641edfa81 100644 --- a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx +++ b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx @@ -7,6 +7,11 @@ import React, { import { css } from 'glamor'; +import { + type CategoryEntity, + type CategoryGroupEntity, +} from 'loot-core/src/types/models'; + import Split from '../../icons/v0/Split'; import { theme } from '../../style'; import Text from '../common/Text'; @@ -14,21 +19,8 @@ import View from '../common/View'; import Autocomplete, { defaultFilterSuggestion } from './Autocomplete'; -export type Category = { - id: string; - cat_group: unknown; - groupName: string; - name: string; -}; - -export type CategoryGroup = { - id: string; - name: string; - categories: Array; -}; - export type CategoryListProps = { - items: Array; + items: Array; getItemProps?: (arg: { item }) => Partial>; highlightedIndex: number; embedded: boolean; @@ -122,7 +114,7 @@ function CategoryList({ }} data-testid="category-item-group" > - {item.groupName} + {`${item.group?.name}`} )}
& { - categoryGroups: CategoryGroup[]; + categoryGroups: Array; showSplitOption?: boolean; groupHeaderStyle?: object; }; @@ -169,19 +161,23 @@ export default function CategoryAutocomplete({ groupHeaderStyle, ...props }: CategoryAutocompleteProps) { - let categorySuggestions = useMemo( + let categorySuggestions: Array< + CategoryEntity & { group?: CategoryGroupEntity } + > = useMemo( () => categoryGroups.reduce( (list, group) => list.concat( - group.categories.map(category => ({ - ...category, - groupName: group.name, - })), + group.categories + .filter(category => category.cat_group === group.id) + .map(category => ({ + ...category, + group: group, + })), ), - showSplitOption ? [{ id: 'split', name: '' }] : [], + showSplitOption ? [{ id: 'split', name: '' } as CategoryEntity] : [], ), - [categoryGroups], + [showSplitOption, categoryGroups], ); return ( diff --git a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx index 93d1df5312e..22e500cb673 100644 --- a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx +++ b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx @@ -1,6 +1,7 @@ import React, { type ComponentProps } from 'react'; import ArrowThinRight from '../../icons/v1/ArrowThinRight'; +import { type CSSProperties } from '../../style'; import View from '../common/View'; import CellValue from '../spreadsheet/CellValue'; import useSheetValue from '../spreadsheet/useSheetValue'; @@ -11,17 +12,23 @@ type BalanceWithCarryoverProps = { carryover: ComponentProps['binding']; balance: ComponentProps['binding']; disabled?: boolean; + style?: CSSProperties; + balanceStyle?: CSSProperties; + carryoverStyle?: CSSProperties; }; export default function BalanceWithCarryover({ carryover, balance, disabled, + style, + balanceStyle, + carryoverStyle, }: BalanceWithCarryoverProps) { let carryoverValue = useSheetValue(carryover); let balanceValue = useSheetValue(balance); return ( - <> + - {carryoverValue === true && ( + {carryoverValue && ( )} - + ); } diff --git a/packages/desktop-client/src/components/budget/BudgetPageHeader.js b/packages/desktop-client/src/components/budget/BudgetPageHeader.tsx similarity index 72% rename from packages/desktop-client/src/components/budget/BudgetPageHeader.js rename to packages/desktop-client/src/components/budget/BudgetPageHeader.tsx index 6f711901168..c5f3576c70b 100644 --- a/packages/desktop-client/src/components/budget/BudgetPageHeader.js +++ b/packages/desktop-client/src/components/budget/BudgetPageHeader.tsx @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import React, { type ComponentProps, memo } from 'react'; import * as monthUtils from 'loot-core/src/shared/months'; @@ -7,8 +7,15 @@ import View from '../common/View'; import { MonthPicker } from './MonthPicker'; import { getScrollbarWidth } from './util'; -const BudgetPageHeader = memo( - ({ startMonth, onMonthSelect, numMonths, monthBounds, style }) => { +type BudgetPageHeaderProps = { + startMonth: string; + onMonthSelect: (month: string) => void; + numMonths: number; + monthBounds: ComponentProps['monthBounds']; +}; + +const BudgetPageHeader = memo( + ({ startMonth, onMonthSelect, numMonths, monthBounds }) => { function getValidMonth(month) { let start = monthBounds.start; let end = monthUtils.subMonths(monthBounds.end, numMonths - 1); diff --git a/packages/desktop-client/src/components/budget/CategoryGroupsContext.js b/packages/desktop-client/src/components/budget/CategoryGroupsContext.js deleted file mode 100644 index b1d9eb6899e..00000000000 --- a/packages/desktop-client/src/components/budget/CategoryGroupsContext.js +++ /dev/null @@ -1,3 +0,0 @@ -import { createContext } from 'react'; - -export let CategoryGroupsContext = createContext([]); diff --git a/packages/desktop-client/src/components/budget/DynamicBudgetTable.js b/packages/desktop-client/src/components/budget/DynamicBudgetTable.js deleted file mode 100644 index fec4a397866..00000000000 --- a/packages/desktop-client/src/components/budget/DynamicBudgetTable.js +++ /dev/null @@ -1,111 +0,0 @@ -import React, { forwardRef, useEffect } from 'react'; -import { useSelector } from 'react-redux'; -import AutoSizer from 'react-virtualized-auto-sizer'; - -import { useActions } from '../../hooks/useActions'; -import View from '../common/View'; - -import { useBudgetMonthCount } from './BudgetMonthCountContext'; -import BudgetPageHeader from './BudgetPageHeader'; -import BudgetTable from './BudgetTable'; -import { CategoryGroupsContext } from './CategoryGroupsContext'; - -function getNumPossibleMonths(width) { - let estimatedTableWidth = width - 200; - - if (estimatedTableWidth < 500) { - return 1; - } else if (estimatedTableWidth < 750) { - return 2; - } else if (estimatedTableWidth < 1000) { - return 3; - } else if (estimatedTableWidth < 1250) { - return 4; - } else if (estimatedTableWidth < 1500) { - return 5; - } - - return 6; -} - -const DynamicBudgetTableInner = forwardRef( - ( - { - width, - height, - categoryGroups, - prewarmStartMonth, - startMonth, - maxMonths = 3, - monthBounds, - onMonthSelect: onMonthSelect_, - onPreload, - ...props - }, - ref, - ) => { - let prefs = useSelector(state => state.prefs.local); - let { setDisplayMax } = useBudgetMonthCount(); - let actions = useActions(); - - let numPossible = getNumPossibleMonths(width); - let numMonths = Math.min(numPossible, maxMonths); - let maxWidth = 200 + 500 * numMonths; - - useEffect(() => { - setDisplayMax(numPossible); - }, [numPossible]); - - function onMonthSelect(month) { - onMonthSelect_(month, numMonths); - } - - return ( - - - - - - - - - ); - }, -); - -export default forwardRef((props, ref) => { - return ( - - {({ width, height }) => ( - - )} - - ); -}); diff --git a/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx b/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx new file mode 100644 index 00000000000..51ab9df2761 --- /dev/null +++ b/packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx @@ -0,0 +1,118 @@ +import React, { forwardRef, useEffect, type ComponentProps } from 'react'; +import { useSelector } from 'react-redux'; +import AutoSizer from 'react-virtualized-auto-sizer'; + +import { useActions } from '../../hooks/useActions'; +import View from '../common/View'; + +import { useBudgetMonthCount } from './BudgetMonthCountContext'; +import BudgetPageHeader from './BudgetPageHeader'; +import BudgetTable from './BudgetTable'; + +function getNumPossibleMonths(width: number) { + let estimatedTableWidth = width - 200; + + if (estimatedTableWidth < 500) { + return 1; + } else if (estimatedTableWidth < 750) { + return 2; + } else if (estimatedTableWidth < 1000) { + return 3; + } else if (estimatedTableWidth < 1250) { + return 4; + } else if (estimatedTableWidth < 1500) { + return 5; + } + + return 6; +} + +type DynamicBudgetTableInnerProps = { + width: number; + height: number; +} & ComponentProps; + +const DynamicBudgetTableInner = forwardRef< + BudgetTable, + DynamicBudgetTableInnerProps +>( + ( + { + width, + height, + categoryGroups, + prewarmStartMonth, + startMonth, + maxMonths = 3, + monthBounds, + onMonthSelect: onMonthSelect_, + onPreload, + ...props + }, + ref, + ) => { + let prefs = useSelector(state => state.prefs.local); + let { setDisplayMax } = useBudgetMonthCount(); + let actions = useActions(); + + let numPossible = getNumPossibleMonths(width); + let numMonths = Math.min(numPossible, maxMonths); + let maxWidth = 200 + 500 * numMonths; + + useEffect(() => { + setDisplayMax(numPossible); + }, [numPossible]); + + function onMonthSelect(month) { + onMonthSelect_(month, numMonths); + } + + return ( + + + + + + + ); + }, +); + +export default forwardRef( + (props, ref) => { + return ( + + {({ width, height }) => ( + + )} + + ); + }, +); diff --git a/packages/desktop-client/src/components/budget/MobileBudget.js b/packages/desktop-client/src/components/budget/MobileBudget.js index 1499783b722..c992a255fce 100644 --- a/packages/desktop-client/src/components/budget/MobileBudget.js +++ b/packages/desktop-client/src/components/budget/MobileBudget.js @@ -363,11 +363,11 @@ class Budget extends Component { type={budgetType} month={currentMonth} monthBounds={bounds} - editMode={editMode} navigation={navigation} // refreshControl={ // // } + editMode={editMode} onEditMode={flag => this.setState({ editMode: flag })} onShowBudgetDetails={this.onShowBudgetDetails} onPrevMonth={this.onPrevMonth} @@ -382,6 +382,7 @@ class Budget extends Component { onReorderGroup={this.onReorderGroup} onOpenActionSheet={() => {}} //this.onOpenActionSheet} onBudgetAction={applyBudgetAction} + onRefresh={onRefresh} savePrefs={savePrefs} /> )} diff --git a/packages/desktop-client/src/components/budget/MobileBudgetTable.js b/packages/desktop-client/src/components/budget/MobileBudgetTable.js index 0deb57870a6..b650989f76e 100644 --- a/packages/desktop-client/src/components/budget/MobileBudgetTable.js +++ b/packages/desktop-client/src/components/budget/MobileBudgetTable.js @@ -1,4 +1,4 @@ -import React, { memo, useState } from 'react'; +import React, { memo, useEffect, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; import memoizeOne from 'memoize-one'; @@ -8,9 +8,7 @@ import * as monthUtils from 'loot-core/src/shared/months'; import ArrowThinLeft from '../../icons/v1/ArrowThinLeft'; import ArrowThinRight from '../../icons/v1/ArrowThinRight'; -import Close from '../../icons/v1/Close'; import DotsHorizontalTriple from '../../icons/v1/DotsHorizontalTriple'; -import EditPencil from '../../icons/v1/EditPencil'; import { useResponsive } from '../../ResponsiveProvider'; import { theme, styles } from '../../style'; import Button from '../common/Button'; @@ -20,6 +18,7 @@ import Label from '../common/Label'; import Menu from '../common/Menu'; import Text from '../common/Text'; import View from '../common/View'; +import PullToRefresh from '../responsive/PullToRefresh'; import { useServerURL } from '../ServerContext'; import CellValue from '../spreadsheet/CellValue'; import NamespaceContext from '../spreadsheet/NamespaceContext'; @@ -34,7 +33,10 @@ import { AmountInput } from '../util/AmountInput'; // } from '../mobile/AmountInput'; // import { DragDrop, Draggable, Droppable, DragDropHighlight } from './dragdrop'; +import BalanceWithCarryover from './BalanceWithCarryover'; import { ListItem, ROW_HEIGHT } from './MobileTable'; +import BalanceTooltip from './rollover/BalanceTooltip'; +import { makeAmountGrey } from './util'; function ToBudget({ toBudget, onClick }) { let amount = useSheetValue(toBudget); @@ -50,6 +52,7 @@ function ToBudget({ toBudget, onClick }) { ...styles.underlinedText, color: theme.formInputText, flexShrink: 0, + textAlign: 'left', }} /> {projected ? (