Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Mobile-Expensify
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1009045202
versionName "9.4.52-2"
versionCode 1009045204
versionName "9.4.52-4"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>9.4.52.2</string>
<string>9.4.52.4</string>
<key>FullStory</key>
<dict>
<key>OrgId</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NotificationServiceExtension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<key>CFBundleShortVersionString</key>
<string>9.4.52</string>
<key>CFBundleVersion</key>
<string>9.4.52.2</string>
<string>9.4.52.4</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/ShareViewController/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<key>CFBundleShortVersionString</key>
<string>9.4.52</string>
<key>CFBundleVersion</key>
<string>9.4.52.2</string>
<string>9.4.52.4</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "9.4.52-2",
"version": "9.4.52-4",
Comment thread
JS00001 marked this conversation as resolved.
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ function ReportPreviewHeader() {
[translate, numberOfRequests],
);

// A cancelled payment is a report level event and it isn't surfaced by the status badge, so we show it next to the expense count.
const supportingText = iouReport?.isCancelledIOU ? `${translate('iou.canceled')} ${CONST.DOT_SEPARATOR} ${expenseCount}` : expenseCount;

const reportStateNum = iouReport?.stateNum ?? action?.childStateNum;
const reportStatusNum = iouReport?.statusNum ?? action?.childStatusNum;

Expand Down Expand Up @@ -125,7 +122,7 @@ function ReportPreviewHeader() {
tooltipText={reportStatusTooltip}
/>
)}
{!shouldShowAccessPlaceHolder && <Text style={[styles.textLabelSupporting, styles.lh16]}>{supportingText}</Text>}
{!shouldShowAccessPlaceHolder && <Text style={[styles.textLabelSupporting, styles.lh16]}>{expenseCount}</Text>}
</View>
)
)}
Expand Down

Large diffs are not rendered by default.

93 changes: 66 additions & 27 deletions src/libs/TransactionPreviewUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
isCreatedMissing,
isDistanceRequest,
isFetchingWaypointsFromServer,
isManagedCardTransaction,
isMerchantMissing,
isOnHold,
isPending,
Expand Down Expand Up @@ -123,6 +124,10 @@ type TranslationPathOrText = {
text?: string;
};

const dotSeparator: TranslationPathOrText = {
text: ` ${CONST.DOT_SEPARATOR} `,
};

/**
* Normalize the last four digits to always return 4 characters.
* If the number is shorter than 4 digits, it will be padded with X's.
Expand Down Expand Up @@ -195,45 +200,52 @@ function getUniqueActionErrorsForTransaction(reportActions: OnyxTypes.ReportActi

function getTransactionPreviewTextAndTranslationPaths({
iouReport,
iouReportOwnerLogin,
policy,
transaction,
action,
violations,
transactionDetails,
isBillSplit,
shouldShowRBR,
shouldShowCanceledStatus,
violationMessage,
reportActions,
currentUserEmail,
currentUserAccountID,
originalTransaction,
convertToDisplayString,
}: {
iouReport: OnyxEntry<OnyxTypes.Report>;
iouReportOwnerLogin: string | undefined;
policy: OnyxEntry<OnyxTypes.Policy>;
transaction: OnyxEntry<OnyxTypes.Transaction>;
action: OnyxEntry<OnyxTypes.ReportAction>;
violations: OnyxTypes.TransactionViolations;
transactionDetails: Partial<TransactionDetails>;
isBillSplit: boolean;
shouldShowRBR: boolean;
/** Whether a cancelled payment has to be reported on this line, because the enclosing surface doesn't show it anywhere else */
shouldShowCanceledStatus: boolean;
violationMessage?: string;
reportActions?: OnyxTypes.ReportActions;
currentUserEmail: string;
currentUserAccountID: number;
originalTransaction?: OnyxEntry<OnyxTypes.Transaction>;
convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'];
}) {
const isFetchingWaypoints = isFetchingWaypointsFromServer(transaction);
const isTransactionOnHold = isOnHold(transaction);
const isTransactionMadeWithCard = isManagedCardTransaction(transaction);
const isMoneyRequestSettled = isSettled(iouReport?.reportID);
const isSettlementOrApprovalPartial = !!iouReport?.pendingFields?.partial;
const isPartialHold = isSettlementOrApprovalPartial && isTransactionOnHold;

// We don't use isOnHold because it's true for duplicated transaction too and we only want to show hold message if the transaction is truly on hold
const shouldShowHoldMessage = !(isMoneyRequestSettled && !isSettlementOrApprovalPartial) && !!transaction?.comment?.hold;
const isTransactionScanning = isScanning(transaction);
const hasFieldErrors = hasMissingSmartscanFields(transaction, iouReport);
const isGroupPolicy = isGroupPolicyUtil(policy);

const hasViolationsOfTypeNotice =
hasNoticeTypeViolation(transaction, violations, currentUserEmail ?? '', currentUserAccountID, iouReport, iouReportOwnerLogin, policy, true) && isGroupPolicy;
const hasActionWithErrors = hasActionWithErrorsForTransaction(iouReport?.reportID, transaction, reportActions);

const {amount: requestAmount, currency: requestCurrency} = transactionDetails;
Expand Down Expand Up @@ -294,42 +306,65 @@ function getTransactionPreviewTextAndTranslationPaths({
}
}

let previewTypeText: TranslationPathOrText = {translationPath: getExpenseTypeTranslationKey(getTransactionType(transaction))};
let previewHeaderText: TranslationPathOrText[] = [
{
translationPath: getExpenseTypeTranslationKey(getTransactionType(transaction)),
},
];

if (isTransactionScanning) {
previewTypeText = {translationPath: 'common.receipt'};
previewHeaderText = [{translationPath: 'common.receipt'}];
} else if (isBillSplit) {
previewTypeText = {translationPath: 'iou.split'};
previewHeaderText = [{translationPath: 'iou.split'}];
}

if (RBRMessage?.text === CONST.ERROR.BANK_ACCOUNT_SAME_DEPOSIT_AND_WITHDRAWAL_ERROR) {
RBRMessage = {translationPath: 'bankAccount.error.sameDepositAndWithdrawalAccount'};
RBRMessage = {
translationPath: 'bankAccount.error.sameDepositAndWithdrawalAccount',
};
}

RBRMessage ??= {text: ''};

let previewDateText: TranslationPathOrText | undefined;
if (!isCreatedMissing(transaction)) {
const created = getFormattedCreated(transaction);
const date = DateUtils.formatWithUTCTimeZone(created, DateUtils.doesDateBelongToAPastYear(created) ? CONST.DATE.MONTH_DAY_YEAR_ABBR_FORMAT : CONST.DATE.MONTH_DAY_ABBR_FORMAT);
previewDateText = {text: date};
previewHeaderText.unshift({text: date}, dotSeparator);
}

// Paid, Approved and Review required are intentionally omitted here because the report status badge and the violation
// row already show them, so repeating them on this line is noise. Canceled is the exception: it can't be derived from
// stateNum/statusNum, so surfaces without their own report status badge have to report it here.
const previewStatusText: TranslationPathOrText[] = [];

if (isPending(transaction)) {
previewStatusText.push({translationPath: 'iou.pending'});
previewHeaderText.push(dotSeparator, {translationPath: 'iou.pending'});
}

if (hasPendingRTERViolation(violations)) {
previewHeaderText.push(dotSeparator, {
translationPath: 'iou.pendingMatch',
});
}

let isPreviewHeaderTextComplete = false;

if (isMoneyRequestSettled && !iouReport?.isCancelledIOU && !isPartialHold && !hasActionWithErrors) {
previewHeaderText.push(dotSeparator, {
translationPath: isTransactionMadeWithCard ? 'common.done' : 'iou.settledExpensify',
});
isPreviewHeaderTextComplete = true;
}

if (shouldShowCanceledStatus && iouReport?.isCancelledIOU) {
previewStatusText.push({translationPath: 'iou.canceled'});
} else if (hasPendingRTERViolation(violations)) {
previewStatusText.push({translationPath: 'iou.pendingMatch'});
} else if (shouldShowHoldMessage) {
previewStatusText.push({translationPath: 'violations.hold'});
if (!isPreviewHeaderTextComplete) {
if (hasViolationsOfTypeNotice && transaction && !isReportApproved({report: iouReport}) && !isSettled(iouReport?.reportID)) {
previewHeaderText.push(dotSeparator, {
translationPath: 'violations.reviewRequired',
});
} else if (isExpenseReport(iouReport) && isGroupPolicyUtil(policy) && isReportApproved({report: iouReport}) && !isSettled(iouReport?.reportID) && !isPartialHold) {
previewHeaderText.push(dotSeparator, {translationPath: 'iou.approved'});
} else if (iouReport?.isCancelledIOU) {
previewHeaderText.push(dotSeparator, {translationPath: 'iou.canceled'});
} else if (shouldShowHoldMessage) {
previewHeaderText.push(dotSeparator, {
translationPath: 'violations.hold',
});
}
}

const amount = isBillSplit ? getAmount(originalTransaction ?? transaction) : requestAmount;
Expand All @@ -339,15 +374,15 @@ function getTransactionPreviewTextAndTranslationPaths({
}

const iouOriginalMessage: OnyxEntry<OnyxTypes.OriginalMessageIOU> = isMoneyRequestAction(action) ? (getOriginalMessage(action) ?? undefined) : undefined;
const displayDeleteAmountText: TranslationPathOrText = {text: convertToDisplayString(iouOriginalMessage?.amount, iouOriginalMessage?.currency)};
const displayDeleteAmountText: TranslationPathOrText = {
text: convertToDisplayString(iouOriginalMessage?.amount, iouOriginalMessage?.currency),
};

return {
RBRMessage,
displayAmountText,
displayDeleteAmountText,
previewDateText,
previewStatusText,
previewTypeText,
previewHeaderText,
};
}

Expand Down Expand Up @@ -382,8 +417,12 @@ function createTransactionPreviewConditionals({
}) {
const {amount: requestAmount, comment: requestComment, merchant, tag, category} = transactionDetails;

const requestMerchant = truncate(merchant, {length: CONST.REQUEST_PREVIEW.MAX_LENGTH});
const description = truncate(StringUtils.lineBreaksToSpaces(requestComment), {length: CONST.REQUEST_PREVIEW.MAX_LENGTH});
const requestMerchant = truncate(merchant, {
length: CONST.REQUEST_PREVIEW.MAX_LENGTH,
});
const description = truncate(StringUtils.lineBreaksToSpaces(requestComment), {
length: CONST.REQUEST_PREVIEW.MAX_LENGTH,
});

const isMoneyRequestSettled = isSettled(iouReport?.reportID);
const isApproved = isReportApproved({report: iouReport});
Expand Down
14 changes: 6 additions & 8 deletions tests/ui/MoneyRequestReportPreview.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,14 @@ const renderPage = ({isWhisper = false, isHovered = false}: Partial<MoneyRequest
);
};

const getTransactionDisplayAmountAndMetadataText = (transaction: Transaction) => {
const getTransactionDisplayAmountAndHeaderText = (transaction: Transaction) => {
const created = getFormattedCreated(transaction);
const date = DateUtils.formatWithUTCTimeZone(created, DateUtils.doesDateBelongToAPastYear(created) ? CONST.DATE.MONTH_DAY_YEAR_ABBR_FORMAT : CONST.DATE.MONTH_DAY_ABBR_FORMAT);
const isTransactionMadeWithCard = isManagedCardTransaction(transaction);
// The date leads the supporting line, which can also carry the category and the report status.
const transactionSupportingText = new RegExp(`^${date}`);
const transactionTypeText = isTransactionMadeWithCard ? TestHelper.translateLocal('iou.card') : TestHelper.translateLocal('iou.cash');
const cashOrCard = isTransactionMadeWithCard ? TestHelper.translateLocal('iou.card') : TestHelper.translateLocal('iou.cash');
const transactionHeaderText = `${date} ${CONST.DOT_SEPARATOR} ${cashOrCard}`;
const transactionDisplayAmount = TestHelper.convertToDisplayString(-transaction.amount, transaction.currency);
return {transactionSupportingText, transactionTypeText, transactionDisplayAmount};
return {transactionHeaderText, transactionDisplayAmount};
};

const setCurrentWidth = () => {
Expand Down Expand Up @@ -274,11 +273,10 @@ describe('MoneyRequestReportPreview', () => {
expect(screen.getByText(getReportName(mockIOUReport))).toBeOnTheScreen();

for (const transaction of arrayOfTransactions) {
const {transactionDisplayAmount, transactionSupportingText, transactionTypeText} = getTransactionDisplayAmountAndMetadataText(transaction);
const {transactionDisplayAmount, transactionHeaderText} = getTransactionDisplayAmountAndHeaderText(transaction);

expect(screen.getAllByText(transactionDisplayAmount).length).toBeGreaterThan(0);
expect(screen.getAllByText(transactionSupportingText)).toHaveLength(arrayOfTransactions.length);
expect(screen.getAllByText(transactionTypeText)).toHaveLength(arrayOfTransactions.length);
expect(screen.getAllByText(transactionHeaderText)).toHaveLength(arrayOfTransactions.length);
expect(screen.getAllByText(transaction.merchant)).toHaveLength(arrayOfTransactions.length);
}
});
Expand Down
Loading