mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 12:43:09 -05:00
Compare commits
7 Commits
deps/25.11
...
UnderKoen/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
326e632e11 | ||
|
|
a55c21db27 | ||
|
|
4a4b512935 | ||
|
|
f2e8c40535 | ||
|
|
478840b34a | ||
|
|
8c158bcd63 | ||
|
|
ca9f62ac29 |
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
6
upcoming-release-notes/4252.md
Normal file
6
upcoming-release-notes/4252.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: Enhancements
|
||||||
|
authors: [UnderKoen]
|
||||||
|
---
|
||||||
|
|
||||||
|
Reconcile account on sidebar context menu
|
||||||
Reference in New Issue
Block a user