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

fix: delete money request if failed to create chat #44142

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dcc9ac9
fix: delete money request if failed to create chat
dominictb Jun 21, 2024
ed0b37e
fix: add function to swap err message for local translation
dominictb Jun 21, 2024
caae66e
Merge remote-tracking branch 'origin/main' into fix/42950-clean-dist-…
dominictb Jun 22, 2024
7936055
fix: lint and prettier
dominictb Jun 22, 2024
68c4ca7
fix: check optimistic report before cleaning up money request
dominictb Jun 24, 2024
083c790
chore: add translation
dominictb Jun 24, 2024
5951c38
fix: lint
dominictb Jun 24, 2024
7a9c89b
Merge remote-tracking branch 'origin/main' into fix/42950-clean-dist-…
dominictb Jun 26, 2024
b383383
fix: improve translation key swapping logic
dominictb Jun 26, 2024
65bd81d
fix: comment
dominictb Jun 28, 2024
9b67b44
Merge remote-tracking branch 'origin/main' into fix/42950-clean-dist-…
dominictb Jul 4, 2024
041bed4
fix: set errors and IOUTransactionID to null
dominictb Jul 4, 2024
41768f4
fix: typescript issue
dominictb Jul 4, 2024
bd32dd9
Merge remote-tracking branch 'origin/main' into fix/42950-clean-dist-…
dominictb Jul 9, 2024
0590632
fix: resolve typescript issues
dominictb Jul 10, 2024
21eafea
fix: prettier
dominictb Jul 10, 2024
3730797
fix: update comments and clean up implementation
dominictb Jul 12, 2024
83c0c3f
Merge remote-tracking branch 'origin/main' into fix/42950-clean-dist-…
dominictb Jul 12, 2024
51b8106
Merge remote-tracking branch 'origin/main' into fix/42950-clean-dist-…
dominictb Jul 16, 2024
4b79f38
fix: revert "swapForTranslation" change
dominictb Jul 16, 2024
313b1ca
Merge remote-tracking branch 'origin/main' into fix/42950-clean-dist-…
dominictb Jul 17, 2024
6ea8fc6
Remove en translation messsage
dominictb Jul 17, 2024
d71f595
Remove es translation message
dominictb Jul 17, 2024
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
8 changes: 7 additions & 1 deletion src/components/LocaleContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ type LocaleContextProps = {
/** Returns translated string for given locale and phrase */
translate: <TKey extends TranslationPaths>(phraseKey: TKey, ...phraseParameters: Localize.PhraseParameters<Localize.Phrase<TKey>>) => string;

swapForTranslation: (message: string, messageLocale: Locale) => string;

/** Formats number formatted according to locale and options */
numberFormat: (number: number, options?: Intl.NumberFormatOptions) => string;

Expand Down Expand Up @@ -69,6 +71,7 @@ const LocaleContext = createContext<LocaleContextProps>({
toLocaleDigit: () => '',
toLocaleOrdinal: () => '',
fromLocaleDigit: () => '',
swapForTranslation: () => '',
preferredLocale: CONST.LOCALES.DEFAULT,
});

Expand Down Expand Up @@ -105,9 +108,12 @@ function LocaleContextProvider({preferredLocale, currentUserPersonalDetails = {}

const fromLocaleDigit = useMemo<LocaleContextProps['fromLocaleDigit']>(() => (localeDigit) => LocaleDigitUtils.fromLocaleDigit(locale, localeDigit), [locale]);

const swapForTranslation = useMemo<LocaleContextProps['swapForTranslation']>(() => (message, messageLocale) => Localize.swapForTranslation(locale, message, messageLocale), [locale]);

const contextValue = useMemo<LocaleContextProps>(
() => ({
translate,
swapForTranslation,
numberFormat,
datetimeToRelative,
datetimeToCalendarTime,
Expand All @@ -118,7 +124,7 @@ function LocaleContextProvider({preferredLocale, currentUserPersonalDetails = {}
fromLocaleDigit,
preferredLocale: locale,
}),
[translate, numberFormat, datetimeToRelative, datetimeToCalendarTime, updateLocale, formatPhoneNumber, toLocaleDigit, toLocaleOrdinal, fromLocaleDigit, locale],
[translate, swapForTranslation, numberFormat, datetimeToRelative, datetimeToCalendarTime, updateLocale, formatPhoneNumber, toLocaleDigit, toLocaleOrdinal, fromLocaleDigit, locale],
);

return <LocaleContext.Provider value={contextValue}>{children}</LocaleContext.Provider>;
Expand Down
25 changes: 20 additions & 5 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ function MoneyRequestView({
const styles = useThemeStyles();
const session = useSession();
const {isOffline} = useNetwork();
const {translate, toLocaleDigit} = useLocalize();
const {translate, toLocaleDigit, swapForTranslation} = useLocalize();
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);

const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '-1'];
Expand Down Expand Up @@ -349,10 +349,18 @@ function MoneyRequestView({
const shouldShowNotesViolations = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report);
const shouldShowReceiptHeader = isReceiptAllowed && (shouldShowReceiptEmptyState || hasReceipt);

const errors = {
...(transaction?.errorFields?.route ?? transaction?.errors),
...parentReportAction?.errors,
};
const errors = useMemo(() => {
const combinedErrors = {
...(transaction?.errorFields?.route ?? transaction?.errors),
...parentReportAction?.errors,
};
return Object.fromEntries(
Object.entries(combinedErrors).map(([key, value]) =>
// swap for translation for each error message
[key, swapForTranslation(value as string, 'en')],
),
);
}, [transaction?.errorFields?.route, transaction?.errors, parentReportAction?.errors, swapForTranslation]);

const tagList = policyTagLists.map(({name, orderWeight}, index) => {
const tagError = getErrorForField(
Expand Down Expand Up @@ -404,6 +412,13 @@ function MoneyRequestView({
if (!transaction?.transactionID) {
return;
}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
if ((!!report?.errorFields?.createChat || !!report.isOptimisticReport) && parentReportAction) {
dominictb marked this conversation as resolved.
Show resolved Hide resolved
const urlToNavigateBack = IOU.cleanUpMoneyRequest(transaction.transactionID, parentReportAction, true);
Navigation.goBack(urlToNavigateBack);
Comment on lines +416 to +417
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this caused the following issue: #50022
Details can be found in this proposal: #50022 (comment)
PR: #51940

return;
}

if (Object.values(transaction?.errors ?? {})?.find((error) => ErrorUtils.isReceiptError(error))) {
deleteTransaction(parentReport, parentReportAction);
}
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ export default {
atLeastTwoDifferentWaypoints: 'Please enter at least two different addresses.',
splitExpenseMultipleParticipantsErrorMessage: 'An expense cannot be split between a workspace and other members. Please update your selection.',
invalidMerchant: 'Please enter a correct merchant.',
workspaceNotAccessible: 'The workspace is no longer accessible. Please try again on a different workspace.',
dominictb marked this conversation as resolved.
Show resolved Hide resolved
},
waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started settling up. Payment is on hold until ${submitterDisplayName} enables their wallet.`,
enableWallet: 'Enable Wallet',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ export default {
atLeastTwoDifferentWaypoints: 'Por favor, introduce al menos dos direcciones diferentes.',
splitExpenseMultipleParticipantsErrorMessage: 'Solo puedes dividir un gasto entre un único espacio de trabajo o con usuarios individuales. Por favor, actualiza tu selección.',
invalidMerchant: 'Por favor, introduce un comerciante correcto.',
workspaceNotAccessible: 'El espacio de trabajo ya no está accesible. Por favor, intente de nuevo en un espacio de trabajo diferente.',
Copy link
Contributor

@sobitneupane sobitneupane Jun 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dominictb We need to verify the Spanish translation of the error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sent a message on Slack

},
waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inició el pago, pero no se procesará hasta que ${submitterDisplayName} active tu billetera`,
enableWallet: 'Habilitar Billetera',
Expand Down
19 changes: 18 additions & 1 deletion src/libs/Localize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,22 @@ function getDevicePreferredLocale(): Locale {
return RNLocalize.findBestAvailableLanguage([CONST.LOCALES.EN, CONST.LOCALES.ES])?.languageTag ?? CONST.LOCALES.DEFAULT;
}

export {translate, translateLocal, formatList, formatMessageElementList, getDevicePreferredLocale};
/**
* This function match the message in the translation mapping and return the translation.
neil-marcellini marked this conversation as resolved.
Show resolved Hide resolved
* @param locale - The locale to translate the message to.
* @param message - The message to translate.
* @param messageLocale - The locale of the message.
dominictb marked this conversation as resolved.
Show resolved Hide resolved
* @returns - translation of the message or the original message if no translation found
*/
function swapForTranslation(locale: Locale, message: string, messageLocale: Locale): string {
const language = messageLocale.substring(0, 2) as 'en' | 'es';
const matchedTranslationEntry = Object.entries(translations[language]).find(([, value]) => value === message) as [TranslationPaths, string] | undefined;
dominictb marked this conversation as resolved.
Show resolved Hide resolved
if (!matchedTranslationEntry) {
return message;
}

return translate(locale, matchedTranslationEntry[0]);
}

export {translate, translateLocal, formatList, formatMessageElementList, getDevicePreferredLocale, swapForTranslation};
export type {PhraseParameters, Phrase};
211 changes: 200 additions & 11 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5269,7 +5269,14 @@ function updateMoneyRequestAmountAndCurrency({
API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY, params, onyxData);
}

function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
/**
*
* @param transactionID - The transactionID of IOU
* @param reportAction - The reportAction of the transaction in the IOU report
* @param isSingleTransactionView - whether we are in the transaction thread report
* @return the url to navigate back once the money request is deleted
*/
function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
// STEP 1: Get all collections we're updating
const iouReportID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID : '-1';
const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null;
Expand Down Expand Up @@ -5362,6 +5369,196 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor
updatedReportPreviewAction.childMoneyRequestCount = reportPreviewAction.childMoneyRequestCount - 1;
}

let urlToNavigateBack: ReturnType<typeof ROUTES.REPORT_WITH_ID.getRoute> | undefined;

// STEP 7: Navigate the user depending on which page they are on and which resources were deleted
dominictb marked this conversation as resolved.
Show resolved Hide resolved
if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) {
// Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
urlToNavigateBack = ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID);
}

if (iouReport?.chatReportID && shouldDeleteIOUReport) {
// Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
urlToNavigateBack = ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID);
}
dominictb marked this conversation as resolved.
Show resolved Hide resolved

return {
shouldDeleteTransactionThread,
shouldDeleteIOUReport,
updatedReportAction,
updatedIOUReport,
updatedReportPreviewAction,
transactionThreadID,
transactionThread,
chatReport,
transaction,
transactionViolations,
reportPreviewAction,
iouReport,
urlToNavigateBack,
};
}

/**
*
* @param transactionID - The transactionID of IOU
* @param reportAction - The reportAction of the transaction in the IOU report
* @param isSingleTransactionView - whether we are in the transaction thread report
* @return the url to navigate back once the money request is deleted
*/
function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
const {
shouldDeleteTransactionThread,
shouldDeleteIOUReport,
updatedReportAction,
updatedIOUReport,
updatedReportPreviewAction,
transactionThreadID,
chatReport,
iouReport,
reportPreviewAction,
urlToNavigateBack,
} = prepareToCleanUpMoneyRequest(transactionID, reportAction, isSingleTransactionView);

// build Onyx data

// delete transaction
const onyxUpdates: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
value: null,
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
value: {
[reportAction.reportActionID]: shouldDeleteIOUReport
? null
: {
pendingAction: null,
},
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
value: {
[reportPreviewAction?.reportActionID ?? '-1']: {
pendingAction: null,
errors: null,
},
dominictb marked this conversation as resolved.
Show resolved Hide resolved
},
},
];

if (Permissions.canUseViolations(betas)) {
onyxUpdates.push({
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
value: null,
});
}

if (shouldDeleteTransactionThread) {
onyxUpdates.push(
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`,
value: null,
},
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`,
value: null,
},
);
}

onyxUpdates.push(
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
value: updatedReportAction,
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
value: updatedIOUReport,
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
value: {
[reportPreviewAction?.reportActionID ?? '-1']: updatedReportPreviewAction,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
value: ReportUtils.getOutstandingChildRequest(updatedIOUReport),
},
);

if (!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0) {
onyxUpdates.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
value: {
hasOutstandingChildRequest: false,
},
});
}

if (shouldDeleteIOUReport) {
onyxUpdates.push(
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
value: {
hasOutstandingChildRequest: false,
iouReportID: null,
lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '-1', {[reportPreviewAction?.reportActionID ?? '-1']: null})?.lastMessageText,
lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '-1', {[reportPreviewAction?.reportActionID ?? '-1']: null})?.created,
},
},
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
value: null,
},
);
}

Onyx.update(onyxUpdates);

return urlToNavigateBack;
}

/**
*
* @param transactionID - The transactionID of IOU
* @param reportAction - The reportAction of the transaction in the IOU report
* @param isSingleTransactionView - whether we are in the transaction thread report
* @return the url to navigate back once the money request is deleted
*/
function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
const {
shouldDeleteTransactionThread,
shouldDeleteIOUReport,
updatedReportAction,
updatedIOUReport,
updatedReportPreviewAction,
transactionThreadID,
transactionThread,
chatReport,
transaction,
transactionViolations,
iouReport,
reportPreviewAction,
urlToNavigateBack,
} = prepareToCleanUpMoneyRequest(transactionID, reportAction, isSingleTransactionView);

// STEP 5: Build Onyx data
const optimisticData: OnyxUpdate[] = [
{
Expand Down Expand Up @@ -5567,16 +5764,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor
API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData});
CachedPDFPaths.clearByKey(transactionID);

// STEP 7: Navigate the user depending on which page they are on and which resources were deleted
if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) {
// Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
return ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID);
}

if (iouReport?.chatReportID && shouldDeleteIOUReport) {
// Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
return ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID);
}
return urlToNavigateBack;
}

function deleteTrackExpense(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
Expand Down Expand Up @@ -6993,6 +7181,7 @@ export {
completeSplitBill,
createDistanceRequest,
createDraftTransaction,
cleanUpMoneyRequest,
deleteMoneyRequest,
deleteTrackExpense,
detachReceipt,
Expand Down
Loading