Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useDisplayPayee hook to unify payee names in mobile and desktop. #4213

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react';

import { SchedulesProvider } from 'loot-core/client/data-hooks/schedules';
import {
useTransactions,
useTransactionsSearch,
Expand Down Expand Up @@ -113,19 +114,21 @@ export function CategoryTransactions({
}
padding={0}
>
<TransactionListWithBalances
isLoading={isLoading}
transactions={transactions}
balance={balance}
balanceCleared={balanceCleared}
balanceUncleared={balanceUncleared}
searchPlaceholder={`Search ${category.name}`}
onSearch={onSearch}
isLoadingMore={isLoadingMore}
onLoadMore={loadMoreTransactions}
onOpenTransaction={onOpenTransaction}
onRefresh={undefined}
/>
<SchedulesProvider>
<TransactionListWithBalances
isLoading={isLoading}
transactions={transactions}
balance={balance}
balanceCleared={balanceCleared}
balanceUncleared={balanceUncleared}
searchPlaceholder={`Search ${category.name}`}
onSearch={onSearch}
isLoadingMore={isLoadingMore}
onLoadMore={loadMoreTransactions}
onOpenTransaction={onOpenTransaction}
onRefresh={undefined}
/>
</SchedulesProvider>
</Page>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,22 @@ import {
useLongPress,
} from '@react-aria/interactions';

import { useCachedSchedules } from 'loot-core/client/data-hooks/schedules';
import { isPreviewId } from 'loot-core/src/shared/transactions';
import { integerToCurrency } from 'loot-core/src/shared/util';
import { type TransactionEntity } from 'loot-core/types/models';
import {
type AccountEntity,
type TransactionEntity,
} from 'loot-core/types/models';

import { useAccount } from '../../../hooks/useAccount';
import { useCategories } from '../../../hooks/useCategories';
import { useDisplayPayee } from '../../../hooks/useDisplayPayee';
import { usePayee } from '../../../hooks/usePayee';
import { SvgSplit } from '../../../icons/v0';
import { SvgLeftArrow2, SvgRightArrow2, SvgSplit } from '../../../icons/v0';
import {
SvgArrowsSynchronize,
SvgCalendar,
SvgCheckCircle1,
SvgLockClosed,
} from '../../../icons/v2';
Expand All @@ -31,12 +37,33 @@ import { Button } from '../../common/Button2';
import { Text } from '../../common/Text';
import { TextOneLine } from '../../common/TextOneLine';
import { View } from '../../common/View';
import { getPrettyPayee } from '../utils';

import { lookupName, Status } from './TransactionEdit';

const ROW_HEIGHT = 60;

const getTextStyle = ({
isPreview,
}: {
isPreview: boolean;
}): CSSProperties => ({
...styles.text,
fontSize: 14,
...(isPreview
? {
fontStyle: 'italic',
color: theme.pageTextLight,
}
: {}),
});

const getScheduleIconStyle = ({ isPreview }: { isPreview: boolean }) => ({
width: 12,
height: 12,
marginRight: 5,
color: isPreview ? theme.pageTextLight : theme.menuItemText,
});

type TransactionListItemProps = ComponentPropsWithoutRef<
typeof ListBoxItem<TransactionEntity>
> & {
Expand All @@ -54,6 +81,8 @@ export function TransactionListItem({
const { value: transaction } = props;

const payee = usePayee(transaction?.payee || '');
const displayPayee = useDisplayPayee({ transaction });

const account = useAccount(transaction?.account || '');
const transferAccount = useAccount(payee?.transfer_acct || '');
const isPreview = isPreviewId(transaction?.id || '');
Expand Down Expand Up @@ -90,19 +119,13 @@ export function TransactionListItem({
is_parent: isParent,
is_child: isChild,
notes,
schedule: scheduleId,
forceUpcoming,
} = transaction;

const previewStatus = forceUpcoming ? 'upcoming' : categoryId;

const isAdded = newTransactions.includes(id);
const categoryName = lookupName(categories, categoryId);
const prettyPayee = getPrettyPayee({
transaction,
payee,
transferAccount,
});
const specialCategory = account?.offbudget
? 'Off budget'
: transferAccount && !transferAccount.offbudget
Expand All @@ -112,17 +135,7 @@ export function TransactionListItem({
: null;

const prettyCategory = specialCategory || categoryName;

const textStyle: CSSProperties = {
...styles.text,
fontSize: 14,
...(isPreview
? {
fontStyle: 'italic',
color: theme.pageTextLight,
}
: {}),
};
const textStyle = getTextStyle({ isPreview });

return (
<ListBoxItem textValue={id} {...props}>
Expand Down Expand Up @@ -165,27 +178,23 @@ export function TransactionListItem({
>
<View style={{ flex: 1 }}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
{scheduleId && (
<SvgArrowsSynchronize
style={{
width: 12,
height: 12,
marginRight: 5,
color: textStyle.color || theme.menuItemText,
}}
/>
)}
<PayeeIcons
transaction={transaction}
transferAccount={transferAccount}
/>
<TextOneLine
style={{
...textStyle,
fontWeight: isAdded ? '600' : '400',
...(prettyPayee === '' && {
color: theme.tableTextLight,
fontStyle: 'italic',
}),
...(!displayPayee && !isPreview
? {
color: theme.pageTextLight,
fontStyle: 'italic',
}
: {}),
}}
>
{prettyPayee || '(No payee)'}
{displayPayee || '(No payee)'}
</TextOneLine>
</View>
{isPreview ? (
Expand Down Expand Up @@ -282,3 +291,39 @@ export function TransactionListItem({
</ListBoxItem>
);
}

type PayeeIconsProps = {
transaction: TransactionEntity;
transferAccount?: AccountEntity;
};

function PayeeIcons({ transaction, transferAccount }: PayeeIconsProps) {
const { id, schedule: scheduleId } = transaction;
const { isLoading: isSchedulesLoading, schedules = [] } =
useCachedSchedules();
const isPreview = isPreviewId(id);
const schedule = schedules.find(s => s.id === scheduleId);
const isScheduleRecurring =
schedule && schedule._date && !!schedule._date.frequency;

if (isSchedulesLoading) {
return null;
}

return (
<>
{schedule &&
(isScheduleRecurring ? (
<SvgArrowsSynchronize style={getScheduleIconStyle({ isPreview })} />
) : (
<SvgCalendar style={getScheduleIconStyle({ isPreview })} />
))}
{transferAccount &&
(transaction.amount > 0 ? (
<SvgLeftArrow2 style={{ width: 12, height: 12, marginRight: 5 }} />
) : (
<SvgRightArrow2 style={{ width: 12, height: 12, marginRight: 5 }} />
))}
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
} from 'loot-core/src/shared/util';

import { useContextMenu } from '../../hooks/useContextMenu';
import { useDisplayPayee } from '../../hooks/useDisplayPayee';
import { useMergedRefs } from '../../hooks/useMergedRefs';
import { usePrevious } from '../../hooks/usePrevious';
import { useProperFocus } from '../../hooks/useProperFocus';
Expand Down Expand Up @@ -344,32 +345,6 @@ const TransactionHeader = memo(

TransactionHeader.displayName = 'TransactionHeader';

function getPayeePretty(transaction, payee, transferAcct, numHiddenPayees = 0) {
const formatPayeeName = payeeName =>
numHiddenPayees > 0 ? `${payeeName} (+${numHiddenPayees} more)` : payeeName;

const { payee: payeeId } = transaction;

if (transferAcct) {
return (
<View
style={{
flexDirection: 'row',
alignItems: 'center',
}}
>
{formatPayeeName(transferAcct.name)}
</View>
);
} else if (payee) {
return formatPayeeName(payee.name);
} else if (payeeId && payeeId.startsWith('new:')) {
return formatPayeeName(payeeId.slice('new:'.length));
}

return '';
}

function StatusCell({
id,
focused,
Expand Down Expand Up @@ -497,49 +472,6 @@ function HeaderCell({
);
}

const useParentPayee = (
payees,
subtransactions,
transferAccountsByTransaction,
) =>
useMemo(() => {
if (!subtransactions) {
return null;
}

const { counts, mostCommonPayeeTransaction } =
subtransactions?.reduce(
({ counts, ...result }, sub) => {
if (sub.payee) {
counts[sub.payee] = (counts[sub.payee] || 0) + 1;
if (counts[sub.payee] > result.maxCount) {
return {
counts,
maxCount: counts[sub.payee],
mostCommonPayeeTransaction: sub,
};
}
}
return { counts, ...result };
},
{ counts: {}, maxCount: 0, mostCommonPayeeTransaction: null },
) || {};

if (!mostCommonPayeeTransaction) {
return 'Split (no payee)';
}

const mostCommonPayee =
getPayeesById(payees)[mostCommonPayeeTransaction.payee];
const numDistinctPayees = Object.keys(counts).length;
return getPayeePretty(
mostCommonPayeeTransaction,
mostCommonPayee,
transferAccountsByTransaction[mostCommonPayeeTransaction.id],
numDistinctPayees - 1,
);
}, [subtransactions, payees, transferAccountsByTransaction]);

function PayeeCell({
id,
payee,
Expand All @@ -549,7 +481,6 @@ function PayeeCell({
transferAccountsByTransaction,
valueStyle,
transaction,
subtransactions,
importedPayee,
isPreview,
onEdit,
Expand All @@ -563,14 +494,10 @@ function PayeeCell({

const dispatch = useDispatch();

const parentPayee = useParentPayee(
payees,
subtransactions,
transferAccountsByTransaction,
);

const transferAccount = transferAccountsByTransaction[transaction.id];

const displayPayee = useDisplayPayee({ transaction });

return transaction.is_parent ? (
<Cell
name="payee"
Expand Down Expand Up @@ -651,10 +578,10 @@ function PayeeCell({
placement="bottom"
triggerProps={{ delay: 750 }}
>
{parentPayee}
{displayPayee}
</Tooltip>
) : (
parentPayee
displayPayee
)}
</Text>
</View>
Expand All @@ -680,11 +607,10 @@ function PayeeCell({
}
}}
formatter={() => {
const payeeName = getPayeePretty(transaction, payee, transferAccount);
if (!payeeName && isPreview) {
if (!displayPayee && isPreview) {
return '(No payee)';
}
return payeeName;
return displayPayee;
}}
unexposedContent={props => {
const payeeName = (
Expand Down Expand Up @@ -1307,7 +1233,6 @@ const Transaction = memo(function Transaction({
)}
valueStyle={valueStyle}
transaction={transaction}
subtransactions={subtransactions}
transferAccountsByTransaction={transferAccountsByTransaction}
importedPayee={importedPayee}
isPreview={isPreview}
Expand Down
Loading