Skip to content

Commit

Permalink
improvement: display "last reconciled" timestamp in tooltip
Browse files Browse the repository at this point in the history
relocate the "last reconciled" timestamp from the account balances header to a tooltip displayed when hovering over the "Reconcile" button
  • Loading branch information
tostasmistas committed Mar 3, 2025
1 parent a42b559 commit 7b263f7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 51 deletions.
48 changes: 2 additions & 46 deletions packages/desktop-client/src/components/accounts/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { useTranslation } from 'react-i18next';
import { Button } from '@actual-app/components/button';
import { Text } from '@actual-app/components/text';
import { View } from '@actual-app/components/view';
import { formatDistanceToNow } from 'date-fns';
import * as locales from 'date-fns/locale';
import { useHover } from 'usehooks-ts';

import { useCachedSchedules } from 'loot-core/client/data-hooks/schedules';
Expand All @@ -14,9 +12,7 @@ import { getScheduledAmount } from 'loot-core/shared/schedules';
import { isPreviewId } from 'loot-core/shared/transactions';
import { type AccountEntity } from 'loot-core/types/models';

import { useGlobalPref } from '../../hooks/useGlobalPref';
import { useSelectedItems } from '../../hooks/useSelected';
import { SvgLockClosed } from '../../icons/v1';
import { SvgArrowButtonRight1 } from '../../icons/v2';
import { theme } from '../../style';
import { PrivacyFilter } from '../PrivacyFilter';
Expand Down Expand Up @@ -147,23 +143,11 @@ function FilteredBalance({ filteredAmount }: FilteredBalanceProps) {
);
}

const tsToRelativeTime = (ts: string | null, language: string): string => {
if (!ts) return 'Unknown';

const parsed = new Date(parseInt(ts, 10));
const locale =
locales[language.replace('-', '') as keyof typeof locales] ??
locales['enUS'];

return formatDistanceToNow(parsed, { addSuffix: true, locale });
};

type MoreBalancesProps = {
balanceQuery: { name: `balance-query-${string}`; query: Query };
lastReconciled?: string | null;
};

function MoreBalances({ balanceQuery, lastReconciled }: MoreBalancesProps) {
function MoreBalances({ balanceQuery }: MoreBalancesProps) {
const { t } = useTranslation();

const cleared = useSheetValue<'balance', `balance-query-${string}-cleared`>({
Expand All @@ -179,33 +163,10 @@ function MoreBalances({ balanceQuery, lastReconciled }: MoreBalancesProps) {
query: balanceQuery.query.filter({ cleared: false }),
});

const [language] = useGlobalPref('language');

return (
<View style={{ flexDirection: 'row' }}>
<DetailedBalance name={t('Cleared total:')} balance={cleared ?? 0} />
<DetailedBalance name={t('Uncleared total:')} balance={uncleared ?? 0} />
<Text
style={{
marginLeft: 15,
borderRadius: 4,
padding: '4px 6px',
color: theme.pillText,
backgroundColor: theme.pillBackground,
}}
>
<SvgLockClosed
style={{
width: 11,
height: 11,
color: theme.pillText,
marginRight: 5,
}}
/>
{lastReconciled
? `${t('Reconciled')} ${tsToRelativeTime(lastReconciled, language || 'en-US')}`
: t('Not yet reconciled')}
</Text>
</View>
);
}
Expand Down Expand Up @@ -291,12 +252,7 @@ export function Balances({
/>
</Button>

{showExtraBalances && (
<MoreBalances
balanceQuery={balanceQuery}
lastReconciled={account?.last_reconciled}
/>
)}
{showExtraBalances && <MoreBalances balanceQuery={balanceQuery} />}

{selectedItems.size > 0 && (
<SelectedBalance selectedItems={selectedItems} account={account} />
Expand Down
29 changes: 24 additions & 5 deletions packages/desktop-client/src/components/accounts/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,18 @@ import { Menu } from '@actual-app/components/menu';
import { Popover } from '@actual-app/components/popover';
import { Stack } from '@actual-app/components/stack';
import { styles } from '@actual-app/components/styles';
import { Tooltip } from '@actual-app/components/tooltip';
import { View } from '@actual-app/components/view';

import { tsToRelativeTime } from 'loot-core/shared/util';
import {
type AccountEntity,
type RuleConditionEntity,
type TransactionEntity,
type TransactionFilterEntity,
} from 'loot-core/types/models';

import { useGlobalPref } from '../../hooks/useGlobalPref';
import { useLocalPref } from '../../hooks/useLocalPref';
import { useSplitsExpanded } from '../../hooks/useSplitsExpanded';
import { useSyncServerStatus } from '../../hooks/useSyncServerStatus';
Expand Down Expand Up @@ -185,6 +188,8 @@ export function AccountHeader({
onMakeAsNonSplitTransactions,
}: AccountHeaderProps) {
const { t } = useTranslation();
const [language] = useGlobalPref('language');

const [menuOpen, setMenuOpen] = useState(false);
const [reconcileOpen, setReconcileOpen] = useState(false);
const searchInput = useRef<HTMLInputElement>(null);
Expand Down Expand Up @@ -374,19 +379,33 @@ export function AccountHeader({
onMakeAsNonSplitTransactions={onMakeAsNonSplitTransactions}
/>
)}
<View style={{ flex: '0 0 auto' }}>
<View style={{ flex: '0 0 auto', marginLeft: 10 }}>
{account && (
<>
<Tooltip
style={{
...styles.tooltip,
marginBottom: 10,
}}
content={
account?.last_reconciled
? `${t('Reconciled')} ${tsToRelativeTime(account.last_reconciled, language || 'en-US')}`
: t('Not yet reconciled')
}
placement="top"
triggerProps={{
isDisabled: reconcileOpen,
}}
>
<Button
ref={reconcileRef}
variant="bare"
aria-label={t('Reconcile')}
style={{ padding: 6, marginLeft: 10 }}
style={{ padding: 6 }}
onPress={() => {
setReconcileOpen(true);
}}
>
<View title={t('Reconcile')}>
<View>
<SvgLockClosed width={14} height={14} />
</View>
</Button>
Expand All @@ -403,7 +422,7 @@ export function AccountHeader({
onReconcile={onReconcile}
/>
</Popover>
</>
</Tooltip>
)}
</View>
<Button
Expand Down
16 changes: 16 additions & 0 deletions packages/loot-core/src/shared/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// @ts-strict-ignore
import { formatDistanceToNow } from 'date-fns';
import * as locales from 'date-fns/locale';

export function last<T>(arr: Array<T>) {
return arr[arr.length - 1];
}
Expand Down Expand Up @@ -481,3 +484,16 @@ export function sortByKey<T>(arr: T[], key: keyof T): T[] {
return 0;
});
}

// Date utilities

export function tsToRelativeTime(ts: string | null, language: string): string {
if (!ts) return 'Unknown';

const parsed = new Date(parseInt(ts, 10));
const locale =
locales[language.replace('-', '') as keyof typeof locales] ??
locales['enUS'];

return formatDistanceToNow(parsed, { addSuffix: true, locale });
}

0 comments on commit 7b263f7

Please sign in to comment.