Compare commits

...

7 Commits

Author SHA1 Message Date
UnderKoen
326e632e11 chore: feedback
also adds padding to the name input field to make the consistent
2025-02-19 21:28:22 +01:00
Matt Fiddaman
a55c21db27 Merge branch 'master' into UnderKoen/reconcile-context-menu 2025-02-18 21:28:33 +00:00
UnderKoen
4a4b512935 fix: prev cleared 2025-02-16 15:00:05 +01:00
UnderKoen
f2e8c40535 Merge remote-tracking branch 'origin/master' into UnderKoen/reconcile-context-menu
# Conflicts:
#	packages/desktop-client/src/components/sidebar/Account.tsx
2025-02-16 14:30:28 +01:00
UnderKoen
478840b34a chore: lint 2025-01-28 22:00:15 +01:00
UnderKoen
8c158bcd63 chore: note 2025-01-28 21:55:53 +01:00
UnderKoen
ca9f62ac29 feat: reconcile on context menu 2025-01-28 21:45:08 +01:00
3 changed files with 89 additions and 15 deletions

View File

@@ -308,6 +308,7 @@ type AccountInternalProps = {
hideFraction: boolean; hideFraction: boolean;
accountsSyncing: string[]; accountsSyncing: string[];
dispatch: AppDispatch; dispatch: AppDispatch;
reconcileAmount: number | null;
}; };
type AccountInternalState = { type AccountInternalState = {
search: string; search: string;
@@ -369,12 +370,13 @@ class AccountInternal extends PureComponent<
filterConditionsOp: 'and', filterConditionsOp: 'and',
loading: true, loading: true,
workingHard: false, workingHard: false,
reconcileAmount: null, reconcileAmount: props.reconcileAmount,
transactions: [], transactions: [],
transactionCount: 0, transactionCount: 0,
showBalances: props.showBalances, showBalances: props.showBalances,
balances: null, balances: null,
showCleared: props.showCleared, showCleared: props.reconcileAmount == null ? props.showCleared : true,
prevShowCleared: props.showCleared,
showReconciled: props.showReconciled, showReconciled: props.showReconciled,
editingName: false, editingName: false,
nameError: '', nameError: '',
@@ -474,6 +476,15 @@ class AccountInternal extends PureComponent<
if (this.props.accountId !== prevProps.accountId) { if (this.props.accountId !== prevProps.accountId) {
this.setState({ sort: null, search: '', filterConditions: [] }); this.setState({ sort: null, search: '', filterConditions: [] });
} }
if (this.props.reconcileAmount !== prevProps.reconcileAmount) {
this.setState({
reconcileAmount: this.props.reconcileAmount,
showCleared:
this.props.reconcileAmount == null ? this.props.showCleared : true,
prevShowCleared: this.props.showCleared,
});
}
} }
componentWillUnmount() { componentWillUnmount() {
@@ -2022,6 +2033,7 @@ export function Account() {
categoryId={location?.state?.categoryId} categoryId={location?.state?.categoryId}
location={location} location={location}
savedFilters={savedFiters} savedFilters={savedFiters}
reconcileAmount={location?.state?.reconcileAmount ?? null}
/> />
</SplitsExpandedProvider> </SplitsExpandedProvider>
</SchedulesProvider> </SchedulesProvider>

View File

@@ -1,5 +1,6 @@
// @ts-strict-ignore // @ts-strict-ignore
import React, { type CSSProperties, useRef, useState } from 'react'; import React, { type CSSProperties, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { AlignedText } from '@actual-app/components/aligned-text'; import { AlignedText } from '@actual-app/components/aligned-text';
import { InitialFocus } from '@actual-app/components/initial-focus'; import { InitialFocus } from '@actual-app/components/initial-focus';
@@ -12,15 +13,20 @@ import { Tooltip } from '@actual-app/components/tooltip';
import { View } from '@actual-app/components/view'; import { View } from '@actual-app/components/view';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { openAccountCloseModal } from 'loot-core/client/actions'; import {
addNotification,
openAccountCloseModal,
} from 'loot-core/client/actions';
import * as Platform from 'loot-core/client/platform'; import * as Platform from 'loot-core/client/platform';
import { import {
reopenAccount, reopenAccount,
updateAccount, updateAccount,
} from 'loot-core/client/queries/queriesSlice'; } from 'loot-core/client/queries/queriesSlice';
import { currencyToInteger } from 'loot-core/shared/util';
import { type AccountEntity } from 'loot-core/types/models'; import { type AccountEntity } from 'loot-core/types/models';
import { useContextMenu } from '../../hooks/useContextMenu'; import { useContextMenu } from '../../hooks/useContextMenu';
import { useNavigate } from '../../hooks/useNavigate';
import { useNotes } from '../../hooks/useNotes'; import { useNotes } from '../../hooks/useNotes';
import { useDispatch } from '../../redux'; import { useDispatch } from '../../redux';
import { Input } from '../common/Input'; import { Input } from '../common/Input';
@@ -35,6 +41,8 @@ import {
} from '../sort'; } from '../sort';
import { type SheetFields, type Binding } from '../spreadsheet'; import { type SheetFields, type Binding } from '../spreadsheet';
import { CellValue } from '../spreadsheet/CellValue'; import { CellValue } from '../spreadsheet/CellValue';
import { useFormat } from '../spreadsheet/useFormat';
import { useSheetValue } from '../spreadsheet/useSheetValue';
export const accountNameStyle: CSSProperties = { export const accountNameStyle: CSSProperties = {
marginTop: -2, marginTop: -2,
@@ -78,6 +86,8 @@ export function Account<FieldName extends SheetFields<'account'>>({
onDragChange, onDragChange,
onDrop, onDrop,
}: AccountProps<FieldName>) { }: AccountProps<FieldName>) {
const { t } = useTranslation();
const type = account const type = account
? account.closed ? account.closed
? 'account-closed' ? 'account-closed'
@@ -105,11 +115,16 @@ export function Account<FieldName extends SheetFields<'account'>>({
const dispatch = useDispatch(); const dispatch = useDispatch();
const [isEditing, setIsEditing] = useState(false); const [isEditingName, setIsEditingName] = useState(false);
const [isEditingBalance, setIsEditingBalance] = useState(false);
const accountNote = useNotes(`account-${account?.id}`); const accountNote = useNotes(`account-${account?.id}`);
const needsTooltip = !!account?.id; const needsTooltip = !!account?.id;
const accountValue = useSheetValue(query);
const navigate = useNavigate();
const format = useFormat();
const accountRow = ( const accountRow = (
<View <View
innerRef={dropRef} innerRef={dropRef}
@@ -122,7 +137,7 @@ export function Account<FieldName extends SheetFields<'account'>>({
<Link <Link
variant="internal" variant="internal"
to={to} to={to}
isDisabled={isEditing} isDisabled={isEditingName}
style={{ style={{
...accountNameStyle, ...accountNameStyle,
...style, ...style,
@@ -184,14 +199,13 @@ export function Account<FieldName extends SheetFields<'account'>>({
} }
} }
left={ left={
isEditing ? ( isEditingName ? (
<InitialFocus> <InitialFocus>
<Input <Input
style={{ style={{
padding: 0,
width: '100%', width: '100%',
}} }}
onBlur={() => setIsEditing(false)} onBlur={() => setIsEditingName(false)}
onEnter={e => { onEnter={e => {
const inputEl = e.target as HTMLInputElement; const inputEl = e.target as HTMLInputElement;
const newAccountName = inputEl.value; const newAccountName = inputEl.value;
@@ -205,9 +219,9 @@ export function Account<FieldName extends SheetFields<'account'>>({
}), }),
); );
} }
setIsEditing(false); setIsEditingName(false);
}} }}
onEscape={() => setIsEditing(false)} onEscape={() => setIsEditingName(false)}
defaultValue={name} defaultValue={name}
/> />
</InitialFocus> </InitialFocus>
@@ -215,7 +229,44 @@ export function Account<FieldName extends SheetFields<'account'>>({
name name
) )
} }
right={<CellValue binding={query} type="financial" />} right={
isEditingBalance ? (
<InitialFocus>
<Input
style={{
width: '100%',
textAlign: 'right',
...styles.tnum,
}}
onBlur={() => setIsEditingBalance(false)}
onEnter={e => {
const inputEl = e.target as HTMLInputElement;
const newValue = inputEl.value;
if (newValue.trim() !== '') {
const v = currencyToInteger(newValue);
if (v === accountValue) {
dispatch(
addNotification({
type: 'message',
message:
'The new balance is the same as the current balance.',
}),
);
} else {
navigate(to, { state: { reconcileAmount: v } });
}
}
setIsEditingBalance(false);
}}
onEscape={() => setIsEditingBalance(false)}
defaultValue={format(accountValue, 'financial')}
/>
</InitialFocus>
) : (
<CellValue binding={query} type="financial" />
)
}
/> />
</Link> </Link>
{account && ( {account && (
@@ -240,17 +291,22 @@ export function Account<FieldName extends SheetFields<'account'>>({
break; break;
} }
case 'rename': { case 'rename': {
setIsEditing(true); setIsEditingName(true);
break;
}
case 'reconcile': {
setIsEditingBalance(true);
break; break;
} }
} }
setMenuOpen(false); setMenuOpen(false);
}} }}
items={[ items={[
{ name: 'rename', text: 'Rename' }, { name: 'rename', text: t('Rename') },
{ name: 'reconcile', text: t('Reconcile') },
account.closed account.closed
? { name: 'reopen', text: 'Reopen' } ? { name: 'reopen', text: t('Reopen') }
: { name: 'close', text: 'Close' }, : { name: 'close', text: t('Close') },
]} ]}
/> />
</Popover> </Popover>

View File

@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [UnderKoen]
---
Reconcile account on sidebar context menu