From fd857e72213f76804c836e1a8901f705de907b5d Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Wed, 11 Oct 2023 20:11:05 +0300 Subject: [PATCH 01/66] Feat: update the report when a payment is refunded --- src/CONST.ts | 4 ++++ src/components/ReportActionItem/MoneyRequestPreview.js | 2 ++ src/languages/en.ts | 3 +++ src/languages/es.ts | 3 +++ src/languages/types.ts | 3 +++ src/pages/home/report/ReportActionItem.js | 6 ++++++ 6 files changed, 21 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index 23957827d140..91942313fa47 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -486,6 +486,7 @@ const CONST = { IOU: 'IOU', MODIFIEDEXPENSE: 'MODIFIEDEXPENSE', REIMBURSEMENTQUEUED: 'REIMBURSEMENTQUEUED', + REIMBURSEMENTDEQUEUED: 'REIMBURSEMENTDEQUEUED', RENAMED: 'RENAMED', REPORTPREVIEW: 'REPORTPREVIEW', SUBMITTED: 'SUBMITTED', @@ -1118,6 +1119,9 @@ const CONST = { DOCX: 'docx', SVG: 'svg', }, + CANCEL_REASON: { + PAYMENT_EXPIRED: 'CANCEL_REASON_PAYMENT_EXPIRED' + }, }, GROWL: { diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 35215cadd15d..783c52c0553b 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -206,6 +206,8 @@ function MoneyRequestPreview(props) { message += ` • ${props.translate('iou.pending')}`; } else if (ReportUtils.isSettled(props.iouReport.reportID)) { message += ` • ${props.translate('iou.settledExpensify')}`; + } else if(props.iouReport.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + message += ` • ${props.translate('iou.canceled')}`; } return message; }; diff --git a/src/languages/en.ts b/src/languages/en.ts index 7133ed88579e..3f47db2ecffd 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -76,6 +76,7 @@ import type { TagSelectionParams, TranslationBase, WalletProgramParams, + CanceledRequestParams, } from './types'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; @@ -522,6 +523,7 @@ export default { pay: 'Pay', viewDetails: 'View details', pending: 'Pending', + canceled: 'Canceled', deleteReceipt: 'Delete receipt', receiptScanning: 'Receipt scan in progress…', receiptMissingDetails: 'Receipt missing details', @@ -545,6 +547,7 @@ export default { managerApproved: ({manager}: ManagerApprovedParams) => `${manager} approved:`, payerSettled: ({amount}: PayerSettledParams) => `paid ${amount}`, waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started settling up, payment is held until ${submitterDisplayName} adds a bank account`, + canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) => `Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`, settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) => `${submitterDisplayName} added a bank account. The ${amount} payment has been made.`, paidElsewhereWithAmount: ({payer, amount}: PaidElsewhereWithAmountParams) => `${payer} paid ${amount} elsewhere`, diff --git a/src/languages/es.ts b/src/languages/es.ts index a98ddfaff7d0..db8e0d7c43c7 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -76,6 +76,7 @@ import type { TagSelectionParams, EnglishTranslation, WalletProgramParams, + CanceledRequestParams, } from './types'; /* eslint-disable max-len */ @@ -514,6 +515,7 @@ export default { pay: 'Pagar', viewDetails: 'Ver detalles', pending: 'Pendiente', + canceled: 'Canceled', deleteReceipt: 'Eliminar recibo', receiptScanning: 'Escaneo de recibo en curso…', receiptMissingDetails: 'Recibo con campos vacíos', @@ -537,6 +539,7 @@ export default { managerApproved: ({manager}: ManagerApprovedParams) => `${manager} aprobó:`, payerSettled: ({amount}: PayerSettledParams) => `pagó ${amount}`, waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inicio el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`, + canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) => `Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`, settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) => `${submitterDisplayName} añadió una cuenta bancaria. El pago de ${amount} se ha realizado.`, paidElsewhereWithAmount: ({payer, amount}: PaidElsewhereWithAmountParams) => `${payer} pagó ${amount} de otra forma`, diff --git a/src/languages/types.ts b/src/languages/types.ts index 3ee504ccddd7..b3ce20500f85 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -122,6 +122,8 @@ type PayerSettledParams = {amount: number}; type WaitingOnBankAccountParams = {submitterDisplayName: string}; +type CanceledRequestParams = {amount: string, submitterDisplayName: string} + type SettledAfterAddedBankAccountParams = {submitterDisplayName: string; amount: string}; type PaidElsewhereWithAmountParams = {payer: string; amount: string}; @@ -277,6 +279,7 @@ export type { ManagerApprovedParams, PayerSettledParams, WaitingOnBankAccountParams, + CanceledRequestParams, SettledAfterAddedBankAccountParams, PaidElsewhereWithAmountParams, PaidWithExpensifyWithAmountParams, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index d0e84499a443..36c8476df976 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -70,6 +70,7 @@ import themeColors from '../../../styles/themes/default'; import ReportActionItemBasicMessage from './ReportActionItemBasicMessage'; import RenderHTML from '../../../components/RenderHTML'; import ReportAttachmentsContext from './ReportAttachmentsContext'; +import * as CurrencyUtils from "../../../libs/CurrencyUtils"; const propTypes = { ...windowDimensionsPropTypes, @@ -361,6 +362,11 @@ function ReportActionItem(props) { ) : null} ); + } else if(props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED) { + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.iouReport.ownerAccountID, 'displayName'], props.iouReport.ownerEmail); + const amount = CurrencyUtils.convertToDisplayString(props.iouReport.total, props.iouReport.currency); + + children = ; } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { children = ; } else { From 2b33b90d6da6399626bcaafac99dbaee4592a1b3 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Wed, 11 Oct 2023 20:49:27 +0300 Subject: [PATCH 02/66] run prettier --- src/CONST.ts | 2 +- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- src/languages/en.ts | 3 ++- src/languages/es.ts | 3 ++- src/languages/types.ts | 2 +- src/pages/home/report/ReportActionItem.js | 4 ++-- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 91942313fa47..308d83766d93 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1120,7 +1120,7 @@ const CONST = { SVG: 'svg', }, CANCEL_REASON: { - PAYMENT_EXPIRED: 'CANCEL_REASON_PAYMENT_EXPIRED' + PAYMENT_EXPIRED: 'CANCEL_REASON_PAYMENT_EXPIRED', }, }, diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 783c52c0553b..a408041dbf5c 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -206,7 +206,7 @@ function MoneyRequestPreview(props) { message += ` • ${props.translate('iou.pending')}`; } else if (ReportUtils.isSettled(props.iouReport.reportID)) { message += ` • ${props.translate('iou.settledExpensify')}`; - } else if(props.iouReport.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + } else if (props.iouReport.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { message += ` • ${props.translate('iou.canceled')}`; } return message; diff --git a/src/languages/en.ts b/src/languages/en.ts index 3f47db2ecffd..e5ab33014b4a 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -547,7 +547,8 @@ export default { managerApproved: ({manager}: ManagerApprovedParams) => `${manager} approved:`, payerSettled: ({amount}: PayerSettledParams) => `paid ${amount}`, waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started settling up, payment is held until ${submitterDisplayName} adds a bank account`, - canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) => `Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`, + canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) => + `Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`, settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) => `${submitterDisplayName} added a bank account. The ${amount} payment has been made.`, paidElsewhereWithAmount: ({payer, amount}: PaidElsewhereWithAmountParams) => `${payer} paid ${amount} elsewhere`, diff --git a/src/languages/es.ts b/src/languages/es.ts index db8e0d7c43c7..c88d6fb290ac 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -539,7 +539,8 @@ export default { managerApproved: ({manager}: ManagerApprovedParams) => `${manager} aprobó:`, payerSettled: ({amount}: PayerSettledParams) => `pagó ${amount}`, waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inicio el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`, - canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) => `Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`, + canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) => + `Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`, settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) => `${submitterDisplayName} añadió una cuenta bancaria. El pago de ${amount} se ha realizado.`, paidElsewhereWithAmount: ({payer, amount}: PaidElsewhereWithAmountParams) => `${payer} pagó ${amount} de otra forma`, diff --git a/src/languages/types.ts b/src/languages/types.ts index b3ce20500f85..4ba148a7869d 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -122,7 +122,7 @@ type PayerSettledParams = {amount: number}; type WaitingOnBankAccountParams = {submitterDisplayName: string}; -type CanceledRequestParams = {amount: string, submitterDisplayName: string} +type CanceledRequestParams = {amount: string; submitterDisplayName: string}; type SettledAfterAddedBankAccountParams = {submitterDisplayName: string; amount: string}; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 36c8476df976..5c52670fd37e 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -70,7 +70,7 @@ import themeColors from '../../../styles/themes/default'; import ReportActionItemBasicMessage from './ReportActionItemBasicMessage'; import RenderHTML from '../../../components/RenderHTML'; import ReportAttachmentsContext from './ReportAttachmentsContext'; -import * as CurrencyUtils from "../../../libs/CurrencyUtils"; +import * as CurrencyUtils from '../../../libs/CurrencyUtils'; const propTypes = { ...windowDimensionsPropTypes, @@ -362,7 +362,7 @@ function ReportActionItem(props) { ) : null} ); - } else if(props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED) { + } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED) { const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.iouReport.ownerAccountID, 'displayName'], props.iouReport.ownerEmail); const amount = CurrencyUtils.convertToDisplayString(props.iouReport.total, props.iouReport.currency); From 0aac629c63aede00570c19eef26e3275812c0b35 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Wed, 11 Oct 2023 23:44:42 +0300 Subject: [PATCH 03/66] prevent crash by checking key existence --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index a408041dbf5c..fc294c3ffeda 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -206,7 +206,7 @@ function MoneyRequestPreview(props) { message += ` • ${props.translate('iou.pending')}`; } else if (ReportUtils.isSettled(props.iouReport.reportID)) { message += ` • ${props.translate('iou.settledExpensify')}`; - } else if (props.iouReport.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + } else if (props.iouReport.originalMessage && props.iouReport.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { message += ` • ${props.translate('iou.canceled')}`; } return message; From b7986d4975e834a3642655634bf9884b66285fcb Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Wed, 11 Oct 2023 23:57:24 +0300 Subject: [PATCH 04/66] Add es translations --- src/languages/es.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 500cc529304c..d0e5efa00c12 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -519,7 +519,7 @@ export default { pay: 'Pagar', viewDetails: 'Ver detalles', pending: 'Pendiente', - canceled: 'Canceled', + canceled: 'Canceló', posted: 'Contabilizado', deleteReceipt: 'Eliminar recibo', receiptScanning: 'Escaneo de recibo en curso…', @@ -545,7 +545,7 @@ export default { payerSettled: ({amount}: PayerSettledParams) => `pagó ${amount}`, waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inicio el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`, canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) => - `Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`, + `Canceló el pago ${amount}, porque ${submitterDisplayName} no habilitó su billetera Expensify en un plazo de 30 días.`, settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) => `${submitterDisplayName} añadió una cuenta bancaria. El pago de ${amount} se ha realizado.`, paidElsewhereWithAmount: ({payer, amount}: PaidElsewhereWithAmountParams) => `${payer} pagó ${amount} de otra forma`, From 444b732a645942f6fbc91d94ea2ec58f83d49f5a Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Thu, 12 Oct 2023 00:17:24 +0300 Subject: [PATCH 05/66] use report action value --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index aa19c8536446..b557325e8505 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -216,7 +216,7 @@ function MoneyRequestPreview(props) { message += ` • ${props.translate('iou.approved')}`; } else if (props.iouReport.isWaitingOnBankAccount) { message += ` • ${props.translate('iou.pending')}`; - } else if (props.iouReport.originalMessage && props.iouReport.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + } else if (props.action.originalMessage && props.action.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { message += ` • ${props.translate('iou.canceled')}`; } return message; From 99d4202ea5fd271146a47f77b4459b1498a9a885 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Tue, 17 Oct 2023 17:44:47 +0300 Subject: [PATCH 06/66] use props.report value for amount and name --- src/pages/home/report/ReportActionItem.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index f51b0645cd7f..45621297ed98 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -363,8 +363,8 @@ function ReportActionItem(props) { ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED) { - const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.iouReport.ownerAccountID, 'displayName'], props.iouReport.ownerEmail); - const amount = CurrencyUtils.convertToDisplayString(props.iouReport.total, props.iouReport.currency); + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); + const amount = CurrencyUtils.convertToDisplayString(props.report.total, props.report.currency); children = ; } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { From b389a83bf0ddf0379780722a5360afb4e64c4b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Tue, 24 Oct 2023 08:43:03 -0300 Subject: [PATCH 07/66] Rename AvatarWithIndicator to TSX --- .../{AvatarWithIndicator.js => AvatarWithIndicator.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/components/{AvatarWithIndicator.js => AvatarWithIndicator.tsx} (100%) diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.tsx similarity index 100% rename from src/components/AvatarWithIndicator.js rename to src/components/AvatarWithIndicator.tsx From 18b8449e060243355c22510694531a57cc64d0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Tue, 24 Oct 2023 08:47:02 -0300 Subject: [PATCH 08/66] Migrate AvatarWithIndicator to TS --- src/components/AvatarWithIndicator.tsx | 36 ++++++++++++-------------- src/libs/UserUtils.ts | 6 ++--- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/components/AvatarWithIndicator.tsx b/src/components/AvatarWithIndicator.tsx index 5e7b8d1ee632..c29507b9dcc5 100644 --- a/src/components/AvatarWithIndicator.tsx +++ b/src/components/AvatarWithIndicator.tsx @@ -1,36 +1,34 @@ import React from 'react'; import {View} from 'react-native'; -import PropTypes from 'prop-types'; -import Avatar from './Avatar'; -import styles from '../styles/styles'; -import Tooltip from './Tooltip'; +import {SvgProps} from 'react-native-svg'; import * as UserUtils from '../libs/UserUtils'; -import Indicator from './Indicator'; +import styles from '../styles/styles'; +import Avatar from './Avatar'; import * as Expensicons from './Icon/Expensicons'; +import Indicator from './Indicator'; +import Tooltip from './Tooltip'; -const propTypes = { +type AvatarWithIndicatorProps = { /** URL for the avatar */ - source: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, + source: string | React.FC; /** To show a tooltip on hover */ - tooltipText: PropTypes.string, + tooltipText?: string; /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), -}; - -const defaultProps = { - tooltipText: '', - fallbackIcon: Expensicons.FallbackAvatar, + fallbackIcon?: string | React.FC; }; -function AvatarWithIndicator(props) { +function AvatarWithIndicator({source, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar}: AvatarWithIndicatorProps) { return ( - + @@ -38,8 +36,6 @@ function AvatarWithIndicator(props) { ); } -AvatarWithIndicator.defaultProps = defaultProps; -AvatarWithIndicator.propTypes = propTypes; AvatarWithIndicator.displayName = 'AvatarWithIndicator'; export default AvatarWithIndicator; diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts index 15bf3c0f1029..572c4597b514 100644 --- a/src/libs/UserUtils.ts +++ b/src/libs/UserUtils.ts @@ -104,7 +104,7 @@ function getDefaultAvatarURL(accountID: string | number = '', isNewDot = false): * Given a user's avatar path, returns true if user doesn't have an avatar or if URL points to a default avatar * @param [avatarURL] - the avatar source from user's personalDetails */ -function isDefaultAvatar(avatarURL?: string): boolean { +function isDefaultAvatar(avatarURL?: React.FC | string): boolean { if (typeof avatarURL === 'string') { if (avatarURL.includes('images/avatars/avatar_') || avatarURL.includes('images/avatars/default-avatar_') || avatarURL.includes('images/avatars/user/default')) { return true; @@ -131,7 +131,7 @@ function isDefaultAvatar(avatarURL?: string): boolean { * @param avatarURL - the avatar source from user's personalDetails * @param accountID - the accountID of the user */ -function getAvatar(avatarURL: string, accountID: number): React.FC | string { +function getAvatar(avatarURL: React.FC | string, accountID?: number): React.FC | string { return isDefaultAvatar(avatarURL) ? getDefaultAvatar(accountID) : avatarURL; } @@ -162,7 +162,7 @@ function getFullSizeAvatar(avatarURL: string, accountID: number): React.FC. This adds the _128 at the end of the * source URL (before the file type) if it doesn't exist there already. */ -function getSmallSizeAvatar(avatarURL: string, accountID: number): React.FC | string { +function getSmallSizeAvatar(avatarURL: React.FC | string, accountID?: number): React.FC | string { const source = getAvatar(avatarURL, accountID); if (typeof source !== 'string') { return source; From cebcf98619b38ebeabcf3a75c23c171a8e75836f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Wed, 25 Oct 2023 06:23:36 -0300 Subject: [PATCH 09/66] Rename params to better name --- src/libs/UserUtils.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts index 572c4597b514..50fc95c8416a 100644 --- a/src/libs/UserUtils.ts +++ b/src/libs/UserUtils.ts @@ -102,21 +102,21 @@ function getDefaultAvatarURL(accountID: string | number = '', isNewDot = false): /** * Given a user's avatar path, returns true if user doesn't have an avatar or if URL points to a default avatar - * @param [avatarURL] - the avatar source from user's personalDetails + * @param [avatarSource] - the avatar source from user's personalDetails */ -function isDefaultAvatar(avatarURL?: React.FC | string): boolean { - if (typeof avatarURL === 'string') { - if (avatarURL.includes('images/avatars/avatar_') || avatarURL.includes('images/avatars/default-avatar_') || avatarURL.includes('images/avatars/user/default')) { +function isDefaultAvatar(avatarSource?: React.FC | string): boolean { + if (typeof avatarSource === 'string') { + if (avatarSource.includes('images/avatars/avatar_') || avatarSource.includes('images/avatars/default-avatar_') || avatarSource.includes('images/avatars/user/default')) { return true; } // We use a hardcoded "default" Concierge avatar - if (avatarURL === CONST.CONCIERGE_ICON_URL_2021 || avatarURL === CONST.CONCIERGE_ICON_URL) { + if (avatarSource === CONST.CONCIERGE_ICON_URL_2021 || avatarSource === CONST.CONCIERGE_ICON_URL) { return true; } } - if (!avatarURL) { + if (!avatarSource) { // If null URL, we should also use a default avatar return true; } @@ -128,11 +128,11 @@ function isDefaultAvatar(avatarURL?: React.FC | string): boolean { * Provided a source URL, if source is a default avatar, return the associated SVG. * Otherwise, return the URL pointing to a user-uploaded avatar. * - * @param avatarURL - the avatar source from user's personalDetails + * @param avatarSource - the avatar source from user's personalDetails * @param accountID - the accountID of the user */ -function getAvatar(avatarURL: React.FC | string, accountID?: number): React.FC | string { - return isDefaultAvatar(avatarURL) ? getDefaultAvatar(accountID) : avatarURL; +function getAvatar(avatarSource: React.FC | string, accountID?: number): React.FC | string { + return isDefaultAvatar(avatarSource) ? getDefaultAvatar(accountID) : avatarSource; } /** @@ -150,8 +150,8 @@ function getAvatarUrl(avatarURL: string, accountID: number): string { * Avatars uploaded by users will have a _128 appended so that the asset server returns a small version. * This removes that part of the URL so the full version of the image can load. */ -function getFullSizeAvatar(avatarURL: string, accountID: number): React.FC | string { - const source = getAvatar(avatarURL, accountID); +function getFullSizeAvatar(avatarSource: React.FC | string, accountID: number): React.FC | string { + const source = getAvatar(avatarSource, accountID); if (typeof source !== 'string') { return source; } @@ -162,8 +162,8 @@ function getFullSizeAvatar(avatarURL: string, accountID: number): React.FC. This adds the _128 at the end of the * source URL (before the file type) if it doesn't exist there already. */ -function getSmallSizeAvatar(avatarURL: React.FC | string, accountID?: number): React.FC | string { - const source = getAvatar(avatarURL, accountID); +function getSmallSizeAvatar(avatarSource: React.FC | string, accountID?: number): React.FC | string { + const source = getAvatar(avatarSource, accountID); if (typeof source !== 'string') { return source; } From 8e34982d458f2d6a7f115a1dc58c1960c6093ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Wed, 25 Oct 2023 10:38:52 -0300 Subject: [PATCH 10/66] Create AvatarSource type --- src/components/AvatarWithIndicator.tsx | 6 +++--- src/libs/UserUtils.ts | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/AvatarWithIndicator.tsx b/src/components/AvatarWithIndicator.tsx index c29507b9dcc5..e5100f084bd0 100644 --- a/src/components/AvatarWithIndicator.tsx +++ b/src/components/AvatarWithIndicator.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {View} from 'react-native'; -import {SvgProps} from 'react-native-svg'; import * as UserUtils from '../libs/UserUtils'; +import {AvatarSource} from '../libs/UserUtils'; import styles from '../styles/styles'; import Avatar from './Avatar'; import * as Expensicons from './Icon/Expensicons'; @@ -10,13 +10,13 @@ import Tooltip from './Tooltip'; type AvatarWithIndicatorProps = { /** URL for the avatar */ - source: string | React.FC; + source: AvatarSource; /** To show a tooltip on hover */ tooltipText?: string; /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon?: string | React.FC; + fallbackIcon?: AvatarSource; }; function AvatarWithIndicator({source, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar}: AvatarWithIndicatorProps) { diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts index 50fc95c8416a..6d068b89305f 100644 --- a/src/libs/UserUtils.ts +++ b/src/libs/UserUtils.ts @@ -8,6 +8,8 @@ import Login from '../types/onyx/Login'; type AvatarRange = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24; +type AvatarSource = React.FC | string; + type LoginListIndicator = ValueOf | ''; /** @@ -104,7 +106,7 @@ function getDefaultAvatarURL(accountID: string | number = '', isNewDot = false): * Given a user's avatar path, returns true if user doesn't have an avatar or if URL points to a default avatar * @param [avatarSource] - the avatar source from user's personalDetails */ -function isDefaultAvatar(avatarSource?: React.FC | string): boolean { +function isDefaultAvatar(avatarSource?: AvatarSource): boolean { if (typeof avatarSource === 'string') { if (avatarSource.includes('images/avatars/avatar_') || avatarSource.includes('images/avatars/default-avatar_') || avatarSource.includes('images/avatars/user/default')) { return true; @@ -131,7 +133,7 @@ function isDefaultAvatar(avatarSource?: React.FC | string): boolean { * @param avatarSource - the avatar source from user's personalDetails * @param accountID - the accountID of the user */ -function getAvatar(avatarSource: React.FC | string, accountID?: number): React.FC | string { +function getAvatar(avatarSource: AvatarSource, accountID?: number): AvatarSource { return isDefaultAvatar(avatarSource) ? getDefaultAvatar(accountID) : avatarSource; } @@ -150,7 +152,7 @@ function getAvatarUrl(avatarURL: string, accountID: number): string { * Avatars uploaded by users will have a _128 appended so that the asset server returns a small version. * This removes that part of the URL so the full version of the image can load. */ -function getFullSizeAvatar(avatarSource: React.FC | string, accountID: number): React.FC | string { +function getFullSizeAvatar(avatarSource: AvatarSource, accountID: number): AvatarSource { const source = getAvatar(avatarSource, accountID); if (typeof source !== 'string') { return source; @@ -162,7 +164,7 @@ function getFullSizeAvatar(avatarSource: React.FC | string, accountID: * Small sized avatars end with _128.. This adds the _128 at the end of the * source URL (before the file type) if it doesn't exist there already. */ -function getSmallSizeAvatar(avatarSource: React.FC | string, accountID?: number): React.FC | string { +function getSmallSizeAvatar(avatarSource: AvatarSource, accountID?: number): AvatarSource { const source = getAvatar(avatarSource, accountID); if (typeof source !== 'string') { return source; @@ -202,3 +204,4 @@ export { getFullSizeAvatar, generateAccountID, }; +export type {AvatarSource}; From bb077b6853ac71cb443529a0f5423477c91dcc99 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 25 Oct 2023 16:44:49 +0200 Subject: [PATCH 11/66] Rename files --- src/components/{TestToolMenu.js => TestToolMenu.tsx} | 0 src/components/{TestToolsModal.js => TestToolsModal.tsx} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/components/{TestToolMenu.js => TestToolMenu.tsx} (100%) rename src/components/{TestToolsModal.js => TestToolsModal.tsx} (100%) diff --git a/src/components/TestToolMenu.js b/src/components/TestToolMenu.tsx similarity index 100% rename from src/components/TestToolMenu.js rename to src/components/TestToolMenu.tsx diff --git a/src/components/TestToolsModal.js b/src/components/TestToolsModal.tsx similarity index 100% rename from src/components/TestToolsModal.js rename to src/components/TestToolsModal.tsx From 8bff041e052fa5fd5e449a3857b8c963b16d03e6 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 25 Oct 2023 17:11:12 +0200 Subject: [PATCH 12/66] Migrate TestToolMenu and TestToolsModal --- src/components/TestToolMenu.tsx | 55 ++++++++++++------------------- src/components/TestToolsModal.tsx | 29 ++++------------ 2 files changed, 28 insertions(+), 56 deletions(-) diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx index 474e4c9bb10c..496c90fe9341 100644 --- a/src/components/TestToolMenu.tsx +++ b/src/components/TestToolMenu.tsx @@ -1,7 +1,5 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; -import lodashGet from 'lodash/get'; +import {OnyxEntry, withOnyx} from 'react-native-onyx'; import styles from '../styles/styles'; import Switch from './Switch'; import Text from './Text'; @@ -11,40 +9,31 @@ import * as Session from '../libs/actions/Session'; import ONYXKEYS from '../ONYXKEYS'; import Button from './Button'; import TestToolRow from './TestToolRow'; -import networkPropTypes from './networkPropTypes'; import compose from '../libs/compose'; import {withNetwork} from './OnyxProvider'; import * as ApiUtils from '../libs/ApiUtils'; import CONFIG from '../CONFIG'; +import NetworkOnyx from '../types/onyx/Network'; +import UserOnyx from '../types/onyx/User'; -const propTypes = { +type TestToolMenuOnyxProps = { /** User object in Onyx */ - user: PropTypes.shape({ - /** Whether we should use the staging version of the secure API server */ - shouldUseStagingServer: PropTypes.bool, - }), + user: OnyxEntry; +}; +type TestToolMenuProps = TestToolMenuOnyxProps & { /** Network object in Onyx */ - network: networkPropTypes.isRequired, + network: OnyxEntry; }; -const defaultProps = { - user: { - // The default value is environment specific and can't be set with `defaultProps` (ENV is not resolved yet) - // When undefined (during render) STAGING defaults to `true`, other envs default to `false` - shouldUseStagingServer: undefined, - }, -}; +const USER_DEFAULT = {shouldUseStagingServer: undefined, isSubscribedToNewsletter: false, validated: false, isFromPublicDomain: false, isUsingExpensifyCard: false}; + +function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { + const shouldUseStagingServer = user?.shouldUseStagingServer ?? ApiUtils.isUsingStagingApi(); -function TestToolMenu(props) { return ( <> - - Test Preferences - + Test Preferences {/* Option to switch between staging and default api endpoints. This enables QA, internal testers and external devs to take advantage of sandbox environments for 3rd party services like Plaid and Onfido. @@ -53,8 +42,8 @@ function TestToolMenu(props) { User.setShouldUseStagingServer(!lodashGet(props, 'user.shouldUseStagingServer', ApiUtils.isUsingStagingApi()))} + isOn={shouldUseStagingServer} + onToggle={() => User.setShouldUseStagingServer(!shouldUseStagingServer)} /> )} @@ -63,8 +52,8 @@ function TestToolMenu(props) { Network.setShouldForceOffline(!props.network.shouldForceOffline)} + isOn={Boolean(network?.shouldForceOffline)} + onToggle={() => Network.setShouldForceOffline(!network?.shouldForceOffline)} /> @@ -72,8 +61,8 @@ function TestToolMenu(props) { Network.setShouldFailAllRequests(!props.network.shouldFailAllRequests)} + isOn={Boolean(network?.shouldFailAllRequests)} + onToggle={() => Network.setShouldFailAllRequests(!network?.shouldFailAllRequests)} /> @@ -98,15 +87,13 @@ function TestToolMenu(props) { ); } -TestToolMenu.propTypes = propTypes; -TestToolMenu.defaultProps = defaultProps; TestToolMenu.displayName = 'TestToolMenu'; export default compose( - withNetwork(), - withOnyx({ + withOnyx({ user: { key: ONYXKEYS.USER, }, }), + withNetwork(), )(TestToolMenu); diff --git a/src/components/TestToolsModal.tsx b/src/components/TestToolsModal.tsx index 43a74e48df5d..238db2379f01 100644 --- a/src/components/TestToolsModal.tsx +++ b/src/components/TestToolsModal.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; +import {OnyxEntry, withOnyx} from 'react-native-onyx'; import {View} from 'react-native'; import ONYXKEYS from '../ONYXKEYS'; import Modal from './Modal'; @@ -9,26 +8,17 @@ import toggleTestToolsModal from '../libs/actions/TestTool'; import TestToolMenu from './TestToolMenu'; import styles from '../styles/styles'; -const propTypes = { - /** Details about modal */ - modal: PropTypes.shape({ - /** Indicates when an Alert modal is about to be visible */ - willAlertModalBecomeVisible: PropTypes.bool, - }), - +type TestToolsModalOnyxProps = { /** Whether the test tools modal is open */ - isTestToolsModalOpen: PropTypes.bool, + isTestToolsModalOpen: OnyxEntry; }; -const defaultProps = { - modal: {}, - isTestToolsModalOpen: false, -}; +type TestToolsModalProps = TestToolsModalOnyxProps; -function TestToolsModal(props) { +function TestToolsModal({isTestToolsModalOpen = false}: TestToolsModalProps) { return ( @@ -39,14 +29,9 @@ function TestToolsModal(props) { ); } -TestToolsModal.propTypes = propTypes; -TestToolsModal.defaultProps = defaultProps; TestToolsModal.displayName = 'TestToolsModal'; -export default withOnyx({ - modal: { - key: ONYXKEYS.MODAL, - }, +export default withOnyx({ isTestToolsModalOpen: { key: ONYXKEYS.IS_TEST_TOOLS_MODAL_OPEN, }, From 586c1d17d0496a0d0a3a34c6fc695b0f09ca0046 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Fri, 27 Oct 2023 12:31:18 +0200 Subject: [PATCH 13/66] Type Text more accurate --- src/components/TestToolMenu.tsx | 7 ++++++- src/components/Text.tsx | 19 +++---------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx index 496c90fe9341..369ba5bb65b9 100644 --- a/src/components/TestToolMenu.tsx +++ b/src/components/TestToolMenu.tsx @@ -33,7 +33,12 @@ function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { return ( <> - Test Preferences + + Test Preferences + {/* Option to switch between staging and default api endpoints. This enables QA, internal testers and external devs to take advantage of sandbox environments for 3rd party services like Plaid and Onfido. diff --git a/src/components/Text.tsx b/src/components/Text.tsx index 60a59aae1520..598a01c6a46b 100644 --- a/src/components/Text.tsx +++ b/src/components/Text.tsx @@ -1,12 +1,12 @@ import React, {ForwardedRef} from 'react'; // eslint-disable-next-line no-restricted-imports -import {Text as RNText} from 'react-native'; +import {Text as RNText, TextProps as RNTextProps, StyleSheet} from 'react-native'; import type {TextStyle} from 'react-native'; import fontFamily from '../styles/fontFamily'; import themeColors from '../styles/themes/default'; import variables from '../styles/variables'; -type TextProps = { +type TextProps = RNTextProps & { /** The color of the text */ color?: string; @@ -21,31 +21,18 @@ type TextProps = { /** The family of the font to use */ family?: keyof typeof fontFamily; - - /** Any additional styles to apply */ - style?: TextStyle | TextStyle[]; }; function Text( {color = themeColors.text, fontSize = variables.fontSizeNormal, textAlign = 'left', children = null, family = 'EXP_NEUE', style = {}, ...props}: TextProps, ref: ForwardedRef, ) { - // If the style prop is an array of styles, we need to mix them all together - const mergedStyles = !Array.isArray(style) - ? style - : style.reduce( - (finalStyles, s) => ({ - ...finalStyles, - ...s, - }), - {}, - ); const componentStyle: TextStyle = { color, fontSize, textAlign, fontFamily: fontFamily[family], - ...mergedStyles, + ...StyleSheet.flatten(style), }; if (!componentStyle.lineHeight && componentStyle.fontSize === variables.fontSizeNormal) { From 98380131c8ef28ce6fff549cd370b6937209c2ba Mon Sep 17 00:00:00 2001 From: John Schuster Date: Fri, 27 Oct 2023 15:11:31 -0500 Subject: [PATCH 14/66] Delete docs/articles/new-expensify/getting-started/Expensify-Lounge.md --- .../getting-started/Expensify-Lounge.md | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 docs/articles/new-expensify/getting-started/Expensify-Lounge.md diff --git a/docs/articles/new-expensify/getting-started/Expensify-Lounge.md b/docs/articles/new-expensify/getting-started/Expensify-Lounge.md deleted file mode 100644 index bdccbe927769..000000000000 --- a/docs/articles/new-expensify/getting-started/Expensify-Lounge.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Welcome to the Expensify Lounge! -description: How to get the most out of the Expensify Lounge. -redirect_from: articles/other/Expensify-Lounge/ ---- - - -# What is the Expensify Lounge? -The Expensify Lounge is a place where people go to Get Shit Done. It's a beautiful environment with great coffee and a group of people to collaborate with. Check out this guide on how to best utilize the Expensify Lounge! - -# The Two Rules -### Rule #1 - Get Shit Done - -The Lounge is a space for people to get work done. It is optimized to be the perfect environment for you to focus on your work, collaborate with others, and advance your most wild and creative ideas. To make this a reality, we ask our members to keep the following in mind: - -- **#focus** - Use the space for how it was designed and do not distract from others' focus. The space is beautiful, social, and collaborative, but it was created to help our members work effectively. -- **#urgency** - Working remotely is great, but there's nothing like real-time collaboration with your colleagues. Use the lounge to meet with co-workers IRL to continue the progress on whatever it is you're working on. -- **#results** - Don't mistake time for effort or effort for output. Upon arrival, visualize what you want to accomplish, and don't leave until it's done. - -## Rule #2 - Don’t Ruin it for Everyone Else - -We want this place to be incredible, innovative, and always elvoving. To achieve that, we have some general guidelines: - -- **#writeitdown** - If you can help others learn from you, do so. Write a blog post, a document, or a post in Expensify Chat to share with others. This includes making the Expensify Lounge a better space. Feel free to write down any improvements so we can make it better. -- **#showup** - If you are in the lounge, be fully present. Meet others, and collaborate in social rooms. The point is to build a community of people who are focused on getting shit done; you’ll get out what you put in. -- **#oneteam** - Providing an inclusive community is our priority, and we do not tolerate any form of discrimination. Aim to go out of your way to include people who want to be included. -- **#nocreeps** - Do not make people feel uncomfortable with your words or actions. If you are made to feel uncomfortable or notice this happening to someone else, you can use the escalation process outlined in the FAQ section. - -# How to Use the Expensify Lounge -Keeping those two rules in mind, below is a guide on how our members can get the most out of the lounge. - -### Rule #1 - Getting Shit Done -- **Order drinks from Concierge** - [Write Concierge here](https://new.expensify.com/concierge) to ask lounge questions or order beverages. Concierge will bring your order directly to you! -- **Using an office** - Offices are first come, first serve. If an office is open, feel free to use it! Please keep office use to under an hour. We currently do not allow reserving offices. -- **Lounge hours** - The lounge will be open from 8am-6pm PT, Monday through Friday and closed on some major holidays. You can review our Google Maps profile to check our holiday hours. -- **Make the lounge better** - Make any suggestions to improve the lounge experience in [#announce - Expensify Lounge](https://new.expensify.com/r/8292963527436014). - -## Rule #2 - Not Ruining it for Everyone Else -- **Offices are for calls** - Please do not occupy an office unless you have a call or collaborative meeting happening, and don't stay in an office for longer than an hour. -- **Respect other people** - Please do not be too loud or distracting while others are trying to work. While collaborating in Expensify Chat, be respectful of others’ viewpoints and keep a positive environment. -- **Stay home if you’re sick** - If you feel sick, please do not visit the lounge, or consider wearing a mask in public areas. -- **If you see something, say something** - If you are made to feel uncomfortable or witness others being made uncomfortable, let Concierge know. If this is happening in Expensify Chat, use our moderation tools (outlined below in the FAQ) to apply the applicable level of moderation. - -We’re so happy you are here to live rich, have fun, and save the world with us. Now, go enjoy the Expensify Lounge, and let's Get Shit Done! - -# FAQs - -#### What is Concierge? - -Concierge is our automated system that answers member questions in real-time. Questions regarding the local lounge will be routed directly to the lounge's Concierge. You can send Concierge a message if you have a drink request or general questions. They’ll take care of everything for you! - -#### Who is invited to the Expensify Lounge? - -Everyone is invited to the Expensify Lounge! Whether you're an existing customer, or you're someone looking for a great space to Get Shit Done, we'd love to have you. - -#### How do I escalate something that's making me or someone else uncomfortable? - -If you see something in Expensify Chat that should be escalated, you can use the escalation feature to mark a chat as: -- **Spam or Inconsiderate**: This will send a whisper to the sender of the message warning them of the violation, and the message will have a flag applied to it which will be visible to all users. Concierge will not review these flags. -- **Intimidating or Bullying**: The message will be immediately hidden, and the content will be reviewed by our team. After reviewing the message, and it's confirmed intimidation or bullying, the message will be permanently hidden and we'll communicate the violation to the sender of the message. -- **Harassment or Assault**: The message will be immediately hidden and reviewed by our team. The user will be sent a message to warning them of the violation, and Concierge can block the user if that's deemed necessary. - -If you witness something in-person, please write to Concierge referencing which lounge you are in, and they will escalate the issue appropriately. - -#### Where are other Expensify Lounge locations? - -Right now, we only have the San Francisco Lounge, but be on the lookout for more coming soon! From 84f47089566e6961b6324bcb4d7293367996bd70 Mon Sep 17 00:00:00 2001 From: John Schuster Date: Fri, 27 Oct 2023 15:14:14 -0500 Subject: [PATCH 15/66] Update Expensify-Card-Perks.md --- .../expensify-card/Expensify-Card-Perks.md | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md b/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md index 5c9761b7ff1d..8bcc11fbf167 100644 --- a/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md +++ b/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md @@ -6,22 +6,12 @@ description: Get the most out of your Expensify Card with exclusive perks! # Overview The Expensify Card is packed with perks, both native to our Card program and through exclusive discounts with partnering solutions. The Expensify Card’s primary perks include: -- Access to our premiere Expensify Lounge (with more locations coming soon) - Swipe to Win, where every swipe has a chance to win fun personalized gifts for you and your closest friends and family members -- And unbeatable cash back incentive with each swipe +- Unbeatable cash back incentive with each swipe Below, we’ll cover all of our exclusive offers in more detail and how to claim discounts with our partners. # Expensify Card Perks -## Access to the Expensify Lounge -Our [world-class lounge](https://use.expensify.com/lounge) is now open for Expensify members and guests to enjoy! - -We invite you to visit our sleek San Francisco lounge, where sweeping city views provide the perfect backdrop for a morning coffee to start your day. - -Enjoy complimentary cocktails and snacks in a vibrant atmosphere with blazing-fast WiFi. Whether you want a place to focus on work, socialize with other members, or simply kick back and relax – our lounge is ready and waiting to welcome you. - -You can sign up for free [here](https://use.expensify.com) if you’re not an Expensify member. If you have any questions, reach out to concierge@expensify.com and [check this out](https://use.expensify.com/lounge) for more info. - ## Swipe to Win Swipe to Win is a new [Expensify Card](https://use.expensify.com/company-credit-card) perk that gives cardholders the chance to send a gift to a friend, family member, or essential worker on the frontlines! @@ -221,27 +211,3 @@ Stripe Atlas helps removes obstacles typically associated with starting a busine **Receive $100 off Stripe Atlas and get access to a startup toolkit and special offers on additional Strip Atlas services.** **How to redeem:** Sign up with your Expensify Card. - -# FAQ - -## Where is the Expensify Lounge? -The Expensify Lounge is located on the 16th floor of 88 Kearny Street in San Francisco, California, 94108. This is currently our only lounge location, but keep an eye out for more work lounges popping up soon! - -## When is the Expensify Lounge open? -The lounge is open 8 a.m. to 6 p.m. from Monday through Friday, except for national holidays. Capacity is limited, and we are admitting loungers on a first-come, first-served basis, so make sure to get there early! - -## Who can use the lounge workplace? -Customers with an Expensify subscription can use Expensify’s lounge workplace, and any partner who has completed [ExpensifyApproved! University!](https://university.expensify.com/users/sign_in?next=%2Fdashboard) - - - - -# FAQ -This section covers the useful but not as vital information, it should capture commonly queried elements which do not organically form part of the About or How-to sections. - -- What's idiosyncratic or potentially confusing about this feature? -- Is there anything unique about how this feature relates to billing/activity? -- If this feature is released, are there any common confusions that can't be solved by improvements to the product itself? -- Similarly, if this feature hasn't been released, can you predict and pre-empt any potential confusion? -- Is there any general troubleshooting for this feature? - - Note: troubleshooting should generally go in the FAQ, but if there is extensive troubleshooting, such as with integrations, that will be housed in a separate page, stored with and linked from the main page for that feature. From 9a6375a8ed3a0cfabab3efaa7184ab0f50ad8bf8 Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 28 Oct 2023 16:30:31 +0700 Subject: [PATCH 16/66] fix: 30254 --- .../ComposerWithSuggestions.js | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 3972b21b91a7..d01d91f206bd 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -124,6 +124,22 @@ function ComposerWithSuggestions({ const isEmptyChat = useMemo(() => _.size(reportActions) === 1, [reportActions]); const parentAction = ReportActionsUtils.getParentReportAction(report); const shouldAutoFocus = !modal.isVisible && (shouldFocusInputOnScreenFocus || (isEmptyChat && !ReportActionsUtils.isTransactionThread(parentAction))) && shouldShowComposeInput; + const textInputRef = useRef(null); + const shouldAutoFocusRef = useRef(false); + + shouldAutoFocusRef.current = shouldAutoFocus; + + const prevIsFocused = usePrevious(isFocused); + + useEffect(() => { + if (!prevIsFocused && isFocused) { + setTimeout(() => { + if (shouldAutoFocusRef.current) { + textInputRef.current.focus(); + } + }, CONST.ANIMATED_TRANSITION); + } + }, [isFocused, prevIsFocused]); const valueRef = useRef(value); valueRef.current = value; @@ -134,8 +150,7 @@ function ComposerWithSuggestions({ })); const [composerHeight, setComposerHeight] = useState(0); - - const textInputRef = useRef(null); + const insertedEmojisRef = useRef([]); // A flag to indicate whether the onScroll callback is likely triggered by a layout change (caused by text change) or not @@ -478,7 +493,7 @@ function ComposerWithSuggestions({ }, [focusComposerOnKeyPress, navigation, setUpComposeFocusManager]); const prevIsModalVisible = usePrevious(modal.isVisible); - const prevIsFocused = usePrevious(isFocused); + useEffect(() => { if (modal.isVisible && !prevIsModalVisible) { // eslint-disable-next-line no-param-reassign From 331e2a80c1be738b3382aa8a1030c15a2e6397cc Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 7 Nov 2023 17:12:27 +0700 Subject: [PATCH 17/66] fix lint --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 7f2ef5a0fb4a..64414f1d89e5 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -153,7 +153,7 @@ function ComposerWithSuggestions({ })); const [composerHeight, setComposerHeight] = useState(0); - + const insertedEmojisRef = useRef([]); // A flag to indicate whether the onScroll callback is likely triggered by a layout change (caused by text change) or not From 2b7be0a1c964084bf6143fb47eef948a8ae7b067 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 7 Nov 2023 17:34:46 +0700 Subject: [PATCH 18/66] refactor code --- .../ComposerWithSuggestions.js | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 64414f1d89e5..f6e97a838cf2 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -127,22 +127,6 @@ function ComposerWithSuggestions({ const isEmptyChat = useMemo(() => _.size(reportActions) === 1, [reportActions]); const parentAction = ReportActionsUtils.getParentReportAction(report); const shouldAutoFocus = !modal.isVisible && (shouldFocusInputOnScreenFocus || (isEmptyChat && !ReportActionsUtils.isTransactionThread(parentAction))) && shouldShowComposeInput; - const textInputRef = useRef(null); - const shouldAutoFocusRef = useRef(false); - - shouldAutoFocusRef.current = shouldAutoFocus; - - const prevIsFocused = usePrevious(isFocused); - - useEffect(() => { - if (!prevIsFocused && isFocused) { - setTimeout(() => { - if (shouldAutoFocusRef.current) { - textInputRef.current.focus(); - } - }, CONST.ANIMATED_TRANSITION); - } - }, [isFocused, prevIsFocused]); const valueRef = useRef(value); valueRef.current = value; @@ -154,6 +138,7 @@ function ComposerWithSuggestions({ const [composerHeight, setComposerHeight] = useState(0); + const textInputRef = useRef(null); const insertedEmojisRef = useRef([]); // A flag to indicate whether the onScroll callback is likely triggered by a layout change (caused by text change) or not @@ -547,6 +532,7 @@ function ComposerWithSuggestions({ }, [focusComposerOnKeyPress, navigation, setUpComposeFocusManager]); const prevIsModalVisible = usePrevious(modal.isVisible); + const prevIsFocused = usePrevious(isFocused); useEffect(() => { if (modal.isVisible && !prevIsModalVisible) { @@ -566,6 +552,24 @@ function ComposerWithSuggestions({ } focus(); }, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal.isVisible, isNextModalWillOpenRef]); + + const shouldAutoFocusRef = useRef(false); + shouldAutoFocusRef.current = shouldAutoFocus; + + useEffect(() => { + if (prevIsFocused || !isFocused) { + return; + } + // Focus composer when navigating from another screen + const focusTimeout = setTimeout(() => { + if (!shouldAutoFocusRef.current) { + return; + } + textInputRef.current.focus(); + }, CONST.ANIMATED_TRANSITION); + return () => clearTimeout(focusTimeout); + }, [isFocused, prevIsFocused]); + useEffect(() => { // Scrolls the composer to the bottom and sets the selection to the end, so that longer drafts are easier to edit updateMultilineInputRange(textInputRef.current, shouldAutoFocus); From 4294da8d50d5a1ce762695e8b9273934e135cb18 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 7 Nov 2023 17:35:36 +0700 Subject: [PATCH 19/66] fix lint --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index f6e97a838cf2..0b572bce2d81 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -533,7 +533,6 @@ function ComposerWithSuggestions({ const prevIsModalVisible = usePrevious(modal.isVisible); const prevIsFocused = usePrevious(isFocused); - useEffect(() => { if (modal.isVisible && !prevIsModalVisible) { // eslint-disable-next-line no-param-reassign @@ -555,7 +554,6 @@ function ComposerWithSuggestions({ const shouldAutoFocusRef = useRef(false); shouldAutoFocusRef.current = shouldAutoFocus; - useEffect(() => { if (prevIsFocused || !isFocused) { return; From 5464fc524817ebf58b06e5079a0961a652823fa6 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 8 Nov 2023 16:24:25 +0700 Subject: [PATCH 20/66] remove clearTimeout --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 224dae018204..a38d88c1c5ec 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -507,13 +507,12 @@ function ComposerWithSuggestions({ return; } // Focus composer when navigating from another screen - const focusTimeout = setTimeout(() => { + setTimeout(() => { if (!shouldAutoFocusRef.current) { return; } textInputRef.current.focus(); }, CONST.ANIMATED_TRANSITION); - return () => clearTimeout(focusTimeout); }, [isFocused, prevIsFocused]); useEffect(() => { From 839326e399ff4753f5c026ff96d81715c5ce826c Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Fri, 10 Nov 2023 19:08:07 +0300 Subject: [PATCH 21/66] update 'reason' to 'cancellationReason' --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index f7c647fb4c86..c22b204dd80f 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -219,7 +219,7 @@ function MoneyRequestPreview(props) { message += ` • ${props.translate('iou.approved')}`; } else if (props.iouReport.isWaitingOnBankAccount) { message += ` • ${props.translate('iou.pending')}`; - } else if (props.action.originalMessage && props.action.originalMessage.reason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + } else if (props.action.originalMessage && props.action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { message += ` • ${props.translate('iou.canceled')}`; } return message; From f2c59f35b7f2e99005951a96e2f2c2b545fe518d Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Fri, 10 Nov 2023 19:15:11 +0300 Subject: [PATCH 22/66] remove usage of report.ownerEmail and add condition for canceled case --- src/components/ReportActionItem/MoneyRequestView.js | 6 ++++-- src/pages/home/report/ReportActionItem.js | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 4b69f14213a2..7130e3d41928 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -77,7 +77,7 @@ const defaultProps = { policyTags: {}, }; -function MoneyRequestView({report, betas, parentReport, policyCategories, shouldShowHorizontalRule, transaction, policyTags, policy}) { +function MoneyRequestView({report, betas, parentReport, policyCategories, shouldShowHorizontalRule, transaction, policyTags, policy, action}) { const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); const parentReportAction = ReportActionsUtils.getParentReportAction(report); @@ -136,7 +136,9 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should if (!isDistanceRequest) { amountDescription += ` • ${translate('iou.cash')}`; } - if (isSettled) { + if(props.action && props.action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + amountDescription += ` • ${translate('iou.canceled')}`; + } else if (isSettled) { amountDescription += ` • ${translate('iou.settledExpensify')}`; } else if (report.isWaitingOnBankAccount) { amountDescription += ` • ${translate('iou.pending')}`; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index df56d38dc2dd..448e0ae166c9 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -415,7 +415,7 @@ function ReportActionItem(props) { ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED) { - const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails, [props.report.ownerAccountID, 'displayName']); const amount = CurrencyUtils.convertToDisplayString(props.report.total, props.report.currency); children = ; @@ -572,6 +572,7 @@ function ReportActionItem(props) { content = ( From 0b1f90b76f37a60097f3ea0f4139cca3c86f91d2 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Fri, 10 Nov 2023 19:20:33 +0300 Subject: [PATCH 23/66] fix lint --- src/components/ReportActionItem/MoneyRequestView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 7130e3d41928..68656c6f40fe 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -136,7 +136,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should if (!isDistanceRequest) { amountDescription += ` • ${translate('iou.cash')}`; } - if(props.action && props.action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + if(action && action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { amountDescription += ` • ${translate('iou.canceled')}`; } else if (isSettled) { amountDescription += ` • ${translate('iou.settledExpensify')}`; From a4013f10ce3981cf83583103006f05748ad1bfe5 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Fri, 10 Nov 2023 19:21:47 +0300 Subject: [PATCH 24/66] run prettier --- src/components/ReportActionItem/MoneyRequestView.js | 2 +- src/pages/home/report/ReportActionItem.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 68656c6f40fe..0df83a6c36c9 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -136,7 +136,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should if (!isDistanceRequest) { amountDescription += ` • ${translate('iou.cash')}`; } - if(action && action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + if (action && action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { amountDescription += ` • ${translate('iou.canceled')}`; } else if (isSettled) { amountDescription += ` • ${translate('iou.settledExpensify')}`; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 448e0ae166c9..43526d7ee5c4 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -74,7 +74,7 @@ import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import reportActionPropTypes from './reportActionPropTypes'; import ReportAttachmentsContext from './ReportAttachmentsContext'; -import * as CurrencyUtils from '../../../libs/CurrencyUtils'; +import * as CurrencyUtils from '@libs/CurrencyUtils'; const propTypes = { ...windowDimensionsPropTypes, From 97d8c5eb14f6bf902535d23e9074dd29a44582b9 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Fri, 10 Nov 2023 19:26:18 +0300 Subject: [PATCH 25/66] lint! --- src/pages/home/report/ReportActionItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 43526d7ee5c4..bbd368fa6734 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -58,6 +58,7 @@ import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import * as CurrencyUtils from '@libs/CurrencyUtils'; import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground'; import * as ContextMenuActions from './ContextMenu/ContextMenuActions'; import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMenu'; @@ -74,7 +75,6 @@ import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import reportActionPropTypes from './reportActionPropTypes'; import ReportAttachmentsContext from './ReportAttachmentsContext'; -import * as CurrencyUtils from '@libs/CurrencyUtils'; const propTypes = { ...windowDimensionsPropTypes, From 2f0af0c67c0a664d363bcb25559bf6c211f215fd Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Mon, 13 Nov 2023 12:51:30 +0300 Subject: [PATCH 26/66] fix crash --- src/components/ReportActionItem/MoneyRequestView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 0df83a6c36c9..b51a55082e0a 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -136,7 +136,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should if (!isDistanceRequest) { amountDescription += ` • ${translate('iou.cash')}`; } - if (action && action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + if (action && action.originalMessage && action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { amountDescription += ` • ${translate('iou.canceled')}`; } else if (isSettled) { amountDescription += ` • ${translate('iou.settledExpensify')}`; From ef72ec73c244a94611a892ed91edfab9b73669d0 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Mon, 13 Nov 2023 12:51:51 +0300 Subject: [PATCH 27/66] run prettier --- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/pages/home/report/ReportActionItem.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 32143a9ae73a..2dcf373a3182 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -9,6 +9,7 @@ import type { BeginningOfChatHistoryAnnounceRoomPartOneParams, BeginningOfChatHistoryAnnounceRoomPartTwo, BeginningOfChatHistoryDomainRoomPartOneParams, + CanceledRequestParams, CharacterLimitParams, ConfirmThatParams, DateShouldBeAfterParams, @@ -78,7 +79,6 @@ import type { WelcomeToRoomParams, WeSentYouMagicSignInLinkParams, ZipCodeExampleFormatParams, - CanceledRequestParams, } from './types'; type StateValue = { diff --git a/src/languages/es.ts b/src/languages/es.ts index 7e3e7d89fdb5..5486898ca63b 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -8,6 +8,7 @@ import type { BeginningOfChatHistoryAnnounceRoomPartOneParams, BeginningOfChatHistoryAnnounceRoomPartTwo, BeginningOfChatHistoryDomainRoomPartOneParams, + CanceledRequestParams, CharacterLimitParams, ConfirmThatParams, DateShouldBeAfterParams, @@ -77,7 +78,6 @@ import type { WelcomeToRoomParams, WeSentYouMagicSignInLinkParams, ZipCodeExampleFormatParams, - CanceledRequestParams, } from './types'; /* eslint-disable max-len */ diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index bbd368fa6734..031aebdb3512 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -34,6 +34,7 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withW import usePrevious from '@hooks/usePrevious'; import compose from '@libs/compose'; import ControlSelection from '@libs/ControlSelection'; +import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import focusTextInputAfterAnimation from '@libs/focusTextInputAfterAnimation'; import Navigation from '@libs/Navigation/Navigation'; @@ -58,7 +59,6 @@ import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import * as CurrencyUtils from '@libs/CurrencyUtils'; import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground'; import * as ContextMenuActions from './ContextMenu/ContextMenuActions'; import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMenu'; From 816a67c8ba0a3f89d870445cd8f8fe54b92f5720 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 15 Nov 2023 16:17:24 +0700 Subject: [PATCH 28/66] refactor to handle focus in the same useEffect --- .../ComposerWithSuggestions.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 288df7775f65..c3981fabb15d 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -489,7 +489,7 @@ function ComposerWithSuggestions({ // We want to focus or refocus the input when a modal has been closed or the underlying screen is refocused. // We avoid doing this on native platforms since the software keyboard popping // open creates a jarring and broken UX. - if (!(willBlurTextInputOnTapOutside && !isNextModalWillOpenRef.current && !modal.isVisible && isFocused && (prevIsModalVisible || !prevIsFocused))) { + if (!((willBlurTextInputOnTapOutside || shouldAutoFocus) && !isNextModalWillOpenRef.current && !modal.isVisible && isFocused && (prevIsModalVisible || !prevIsFocused))) { return; } @@ -500,21 +500,6 @@ function ComposerWithSuggestions({ focus(); }, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal.isVisible, isNextModalWillOpenRef]); - const shouldAutoFocusRef = useRef(false); - shouldAutoFocusRef.current = shouldAutoFocus; - useEffect(() => { - if (prevIsFocused || !isFocused) { - return; - } - // Focus composer when navigating from another screen - setTimeout(() => { - if (!shouldAutoFocusRef.current) { - return; - } - textInputRef.current.focus(); - }, CONST.ANIMATED_TRANSITION); - }, [isFocused, prevIsFocused]); - useEffect(() => { // Scrolls the composer to the bottom and sets the selection to the end, so that longer drafts are easier to edit updateMultilineInputRange(textInputRef.current, shouldAutoFocus); From f671ed37edf01b6c64ca85f92b377c15b3303132 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 15 Nov 2023 17:44:51 +0700 Subject: [PATCH 29/66] fix lint --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index c3981fabb15d..3e8dd7372bc3 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -498,6 +498,7 @@ function ComposerWithSuggestions({ return; } focus(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal.isVisible, isNextModalWillOpenRef]); useEffect(() => { From f185e0cd52483728434c3b8b808af3ba8e42613a Mon Sep 17 00:00:00 2001 From: maddylewis <38016013+maddylewis@users.noreply.github.com> Date: Sun, 26 Nov 2023 11:33:02 -0500 Subject: [PATCH 30/66] Delete docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md this file isn't needed - delting --- .../billing-and-subscriptions/Payment-Card.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md b/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md deleted file mode 100644 index 41a1fb96f56f..000000000000 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Payment Card -description: Payment Card ---- -## Resource Coming Soon! From 06d785c661a8400aeab33943da4b9d8c09bbd82a Mon Sep 17 00:00:00 2001 From: maddylewis <38016013+maddylewis@users.noreply.github.com> Date: Sun, 26 Nov 2023 11:35:08 -0500 Subject: [PATCH 31/66] Delete docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md deleting file - it's not needed --- .../workspace-and-domain-settings/Coming-Soon.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md diff --git a/docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md b/docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/new-expensify/workspace-and-domain-settings/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- From e17c27c332f439b96d33f997b9ddb8633e9ec7c4 Mon Sep 17 00:00:00 2001 From: maddylewis <38016013+maddylewis@users.noreply.github.com> Date: Sun, 26 Nov 2023 11:36:18 -0500 Subject: [PATCH 32/66] Delete docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md not needed - deleting --- .../expensify-partner-program/Coming-Soon.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md diff --git a/docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md b/docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md deleted file mode 100644 index 6b85bb0364b5..000000000000 --- a/docs/articles/expensify-classic/expensify-partner-program/Coming-Soon.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- From a75178aa3746f04e9b71d6e6e44574f7def6337e Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Sun, 26 Nov 2023 18:21:59 +0100 Subject: [PATCH 33/66] Change Boolean to '!!' --- src/components/TestToolMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx index 2dfc060171f1..6a3efb0c26ce 100644 --- a/src/components/TestToolMenu.tsx +++ b/src/components/TestToolMenu.tsx @@ -57,7 +57,7 @@ function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { Network.setShouldForceOffline(!network?.shouldForceOffline)} /> @@ -66,7 +66,7 @@ function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { Network.setShouldFailAllRequests(!network?.shouldFailAllRequests)} /> From 6ec7fbc71fa4e4e9aa00089b5baab2a071a9c8ba Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Sun, 26 Nov 2023 18:33:42 +0100 Subject: [PATCH 34/66] Import react in testmenu --- src/components/TestToolMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx index 6a3efb0c26ce..e40d8f473cdf 100644 --- a/src/components/TestToolMenu.tsx +++ b/src/components/TestToolMenu.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import {OnyxEntry, withOnyx} from 'react-native-onyx'; import * as ApiUtils from '@libs/ApiUtils'; import compose from '@libs/compose'; From b9c56f4aefe3be7619a2d2a4e398252dfcf49cdf Mon Sep 17 00:00:00 2001 From: c3024 Date: Mon, 27 Nov 2023 07:47:35 +0530 Subject: [PATCH 35/66] remove red dot for settled requests --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- src/components/ReportActionItem/ReportPreview.js | 2 +- src/libs/OptionsListUtils.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 07aba132be0e..ea0e2d3a489b 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -282,7 +282,7 @@ function MoneyRequestPreview(props) { {getPreviewHeaderText() + (isSettled ? ` • ${getSettledMessage()}` : '')} - {hasFieldErrors && ( + {!isSettled && hasFieldErrors && ( {getPreviewMessage()} - {hasErrors && ( + {!iouSettled && hasErrors && ( Date: Mon, 27 Nov 2023 17:20:51 +0100 Subject: [PATCH 36/66] Define a type for default value --- src/components/TestToolMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx index e40d8f473cdf..53953b861d7d 100644 --- a/src/components/TestToolMenu.tsx +++ b/src/components/TestToolMenu.tsx @@ -26,7 +26,7 @@ type TestToolMenuProps = TestToolMenuOnyxProps & { network: OnyxEntry; }; -const USER_DEFAULT = {shouldUseStagingServer: undefined, isSubscribedToNewsletter: false, validated: false, isFromPublicDomain: false, isUsingExpensifyCard: false}; +const USER_DEFAULT: UserOnyx = {shouldUseStagingServer: undefined, isSubscribedToNewsletter: false, validated: false, isFromPublicDomain: false, isUsingExpensifyCard: false}; function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { const shouldUseStagingServer = user?.shouldUseStagingServer ?? ApiUtils.isUsingStagingApi(); From ac9c935f210dd7288b7e313fa1909808e4e2e554 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 28 Nov 2023 02:31:22 +0700 Subject: [PATCH 37/66] add shouldAutoFocus to dependencies --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index f052c929c5e9..86a99812ad01 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -491,6 +491,7 @@ function ComposerWithSuggestions({ const prevIsModalVisible = usePrevious(modal.isVisible); const prevIsFocused = usePrevious(isFocused); useEffect(() => { + console.log('abcdef'); if (modal.isVisible && !prevIsModalVisible) { // eslint-disable-next-line no-param-reassign isNextModalWillOpenRef.current = false; @@ -507,8 +508,7 @@ function ComposerWithSuggestions({ return; } focus(true); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal.isVisible, isNextModalWillOpenRef]); + }, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal.isVisible, isNextModalWillOpenRef, shouldAutoFocus]); useEffect(() => { // Scrolls the composer to the bottom and sets the selection to the end, so that longer drafts are easier to edit From 6b785819b0bea0bea261eeb06487ecce5fddf08b Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Tue, 28 Nov 2023 12:32:06 +0300 Subject: [PATCH 38/66] add type in OriginalMessage for Dequeued action --- src/types/onyx/OriginalMessage.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 014cd67a9a2a..34b908e7ed56 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -178,6 +178,11 @@ type OriginalMessageReimbursementQueued = { originalMessage: unknown; }; +type OriginalMessageReimbursementDequeued = { + actionName: typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED; + originalMessage: unknown; +}; + type OriginalMessage = | OriginalMessageApproved | OriginalMessageIOU @@ -192,7 +197,8 @@ type OriginalMessage = | OriginalMessagePolicyChangeLog | OriginalMessagePolicyTask | OriginalMessageModifiedExpense - | OriginalMessageReimbursementQueued; + | OriginalMessageReimbursementQueued + | OriginalMessageReimbursementDequeued; export default OriginalMessage; export type {ChronosOOOEvent, Decision, Reaction, ActionName}; From 899ee0a44dab710ab01d92bd5773a93fddd894fe Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Tue, 28 Nov 2023 12:37:33 +0300 Subject: [PATCH 39/66] update report preview based on dequeued action --- src/components/ReportActionItem/MoneyRequestPreview.js | 5 +++-- src/components/ReportActionItem/MoneyRequestView.js | 5 +++-- src/libs/ReportActionsUtils.ts | 10 ++++++++++ src/pages/home/report/ReportActionItem.js | 1 - 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index c22b204dd80f..ba9f7f1b256c 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -166,6 +166,7 @@ function MoneyRequestPreview(props) { const isDistanceRequest = TransactionUtils.isDistanceRequest(props.transaction); const isExpensifyCardTransaction = TransactionUtils.isExpensifyCardTransaction(props.transaction); const isSettled = ReportUtils.isSettled(props.iouReport.reportID); + const isCancelled = ReportActionsUtils.isReimbursementDeQueuedAction(props.iouReport.reportID); const isDeleted = lodashGet(props.action, 'pendingAction', null) === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; // Show the merchant for IOUs and expenses only if they are custom or not related to scanning smartscan @@ -219,7 +220,7 @@ function MoneyRequestPreview(props) { message += ` • ${props.translate('iou.approved')}`; } else if (props.iouReport.isWaitingOnBankAccount) { message += ` • ${props.translate('iou.pending')}`; - } else if (props.action.originalMessage && props.action.originalMessage.cancellationReason === CONST.IOU.CANCEL_REASON.PAYMENT_EXPIRED) { + } else if (isCancelled) { message += ` • ${props.translate('iou.canceled')}`; } return message; @@ -279,7 +280,7 @@ function MoneyRequestPreview(props) { - {getPreviewHeaderText() + (isSettled ? ` • ${getSettledMessage()}` : '')} + {getPreviewHeaderText() + (isSettled && !isCancelled ? ` • ${getSettledMessage()}` : '')} {hasFieldErrors && ( ) { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTQUEUED; } +function isReimbursementDeQueuedAction(reportID: string): boolean { + if (!allReportActions) { + return false + } + + const reportAction = Object.values(allReportActions[`${reportID}`] ?? {}); + return reportAction.some(action => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED); +} + /** * Returns whether the comment is a thread parent message/the first message in a thread */ @@ -657,4 +666,5 @@ export { shouldReportActionBeVisible, shouldReportActionBeVisibleAsLastAction, getFirstVisibleReportActionID, + isReimbursementDeQueuedAction }; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 031aebdb3512..f5322aa9aabb 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -572,7 +572,6 @@ function ReportActionItem(props) { content = ( From 40b9818f640c9900a9ee139102e7848bf0c3f020 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Tue, 28 Nov 2023 13:14:14 +0300 Subject: [PATCH 40/66] missed condition --- src/components/ReportActionItem/MoneyRequestView.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 1448dec82bc6..a204b9d89d27 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -134,6 +134,9 @@ function MoneyRequestView({report, parentReport, policyCategories, shouldShowHor if (TransactionUtils.isPending(transaction)) { amountDescription += ` • ${translate('iou.pending')}`; } + if(isCancelled) { + amountDescription += ` • ${translate('iou.canceled')}`; + } } else { if (!isDistanceRequest) { amountDescription += ` • ${translate('iou.cash')}`; From 8cccd753054d19641c45c1cfd40f5b4c18f26341 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Tue, 28 Nov 2023 13:30:51 +0300 Subject: [PATCH 41/66] run prettier --- src/components/ReportActionItem/MoneyRequestView.js | 4 ++-- src/libs/ReportActionsUtils.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index a204b9d89d27..2599f348be71 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -134,14 +134,14 @@ function MoneyRequestView({report, parentReport, policyCategories, shouldShowHor if (TransactionUtils.isPending(transaction)) { amountDescription += ` • ${translate('iou.pending')}`; } - if(isCancelled) { + if (isCancelled) { amountDescription += ` • ${translate('iou.canceled')}`; } } else { if (!isDistanceRequest) { amountDescription += ` • ${translate('iou.cash')}`; } - if(isCancelled) { + if (isCancelled) { amountDescription += ` • ${translate('iou.canceled')}`; } else if (isSettled) { amountDescription += ` • ${translate('iou.settledExpensify')}`; diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index c05b6de631ca..99055f55af29 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -111,11 +111,11 @@ function isChannelLogMemberAction(reportAction: OnyxEntry) { function isReimbursementDeQueuedAction(reportID: string): boolean { if (!allReportActions) { - return false + return false; } const reportAction = Object.values(allReportActions[`${reportID}`] ?? {}); - return reportAction.some(action => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED); + return reportAction.some((action) => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED); } /** @@ -707,7 +707,7 @@ export { hasRequestFromCurrentAccount, getFirstVisibleReportActionID, isChannelLogMemberAction, - isReimbursementDeQueuedAction + isReimbursementDeQueuedAction, }; export type {LastVisibleMessage}; From d5c4dbeb4c0cb0e6bff1177659a1b7f24f6b9d0d Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Tue, 28 Nov 2023 13:39:19 +0300 Subject: [PATCH 42/66] add condition to handle canceled case --- src/libs/ReportUtils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d93661778b83..bb9f1598630f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1684,6 +1684,10 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.pending')}`; } + if(report?.reportID && ReportActionsUtils.isReimbursementDeQueuedAction(report.reportID)) { + return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.canceled')}`; + } + if (hasNonReimbursableTransactions(report?.reportID)) { return Localize.translateLocal('iou.payerSpentAmount', {payer: payerName, amount: formattedAmount}); } From 30f43e41c874b2a36b104dfb34741080e52b1c74 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Tue, 28 Nov 2023 13:57:06 +0300 Subject: [PATCH 43/66] lint! --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index bb9f1598630f..e8354c16b547 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1684,7 +1684,7 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.pending')}`; } - if(report?.reportID && ReportActionsUtils.isReimbursementDeQueuedAction(report.reportID)) { + if (report?.reportID && ReportActionsUtils.isReimbursementDeQueuedAction(report.reportID)) { return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.canceled')}`; } From af4fe4d398bf5df1b64084bbc86435b1d894cb8f Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 28 Nov 2023 20:54:01 +0800 Subject: [PATCH 44/66] add missing onyx subscription --- src/components/ReportActionItem/TaskView.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/TaskView.js b/src/components/ReportActionItem/TaskView.js index ac82f310f3f8..b01d656d9123 100644 --- a/src/components/ReportActionItem/TaskView.js +++ b/src/components/ReportActionItem/TaskView.js @@ -2,6 +2,7 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useEffect} from 'react'; import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; import Checkbox from '@components/Checkbox'; import Hoverable from '@components/Hoverable'; import Icon from '@components/Icon'; @@ -27,6 +28,7 @@ import useThemeStyles from '@styles/useThemeStyles'; import * as Session from '@userActions/Session'; import * as Task from '@userActions/Task'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; const propTypes = { @@ -185,4 +187,13 @@ function TaskView(props) { TaskView.propTypes = propTypes; TaskView.displayName = 'TaskView'; -export default compose(withWindowDimensions, withLocalize, withCurrentUserPersonalDetails)(TaskView); +export default compose( + withWindowDimensions, + withLocalize, + withCurrentUserPersonalDetails, + withOnyx({ + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + }), +)(TaskView); From 103781a3996b3de62c41db7a567b99067bc04d8a Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 28 Nov 2023 20:54:22 +0800 Subject: [PATCH 45/66] add owner account id to participant --- src/components/LHNOptionsList/LHNOptionsList.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.js b/src/components/LHNOptionsList/LHNOptionsList.js index 0d300c5e2179..987faf2b3120 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.js +++ b/src/components/LHNOptionsList/LHNOptionsList.js @@ -117,7 +117,13 @@ function LHNOptionsList({ const transactionID = lodashGet(itemParentReportAction, ['originalMessage', 'IOUTransactionID'], ''); const itemTransaction = transactionID ? transactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] : {}; const itemComment = draftComments[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`] || ''; - const participantsPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(itemFullReport.participantAccountIDs, personalDetails); + const participants = [...(itemFullReport.participantAccountIDs || [])]; + + if (itemFullReport.ownerAccountID > 0) { + participants.push(itemFullReport.ownerAccountID); + } + + const participantsPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants, personalDetails); return ( Date: Tue, 28 Nov 2023 16:36:38 +0300 Subject: [PATCH 46/66] fix LHN last message text preview --- .../ReportActionItem/MoneyRequestPreview.js | 2 +- src/components/ReportActionItem/MoneyRequestView.js | 2 +- src/libs/OptionsListUtils.js | 2 ++ src/libs/ReportActionsUtils.ts | 10 +++++++++- src/libs/ReportUtils.ts | 13 ++++++++++++- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 4b333359f38b..09baa9322ff4 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -167,7 +167,7 @@ function MoneyRequestPreview(props) { const isDistanceRequest = TransactionUtils.isDistanceRequest(props.transaction); const isExpensifyCardTransaction = TransactionUtils.isExpensifyCardTransaction(props.transaction); const isSettled = ReportUtils.isSettled(props.iouReport.reportID); - const isCancelled = ReportActionsUtils.isReimbursementDeQueuedAction(props.iouReport.reportID); + const isCancelled = ReportActionsUtils.isReimbursementDeQueued(props.iouReport.reportID); const isDeleted = lodashGet(props.action, 'pendingAction', null) === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; // Show the merchant for IOUs and expenses only if they are custom or not related to scanning smartscan diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 2599f348be71..2674b332f949 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -109,7 +109,7 @@ function MoneyRequestView({report, parentReport, policyCategories, shouldShowHor // Flags for allowing or disallowing editing a money request const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); - const isCancelled = ReportActionsUtils.isReimbursementDeQueuedAction(moneyRequestReport.reportID); + const isCancelled = ReportActionsUtils.isReimbursementDeQueued(moneyRequestReport.reportID); const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction); const canEditAmount = canEdit && !isSettled && !isCardTransaction; diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index c616587c3983..e3b6ec77380e 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -397,6 +397,8 @@ function getLastMessageTextForReport(report) { lastMessageTextFromReport = ReportUtils.getReportPreviewMessage(iouReport, lastIOUMoneyReport, true, ReportUtils.isChatReport(report)); } else if (ReportActionUtils.isReimbursementQueuedAction(lastReportAction)) { lastMessageTextFromReport = ReportUtils.getReimbursementQueuedActionMessage(lastReportAction, report); + } else if (ReportActionUtils.isReimbursementDeQueuedAction(lastReportAction)) { + lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(report); } else if (ReportActionUtils.isDeletedParentAction(lastReportAction) && ReportUtils.isChatReport(report)) { lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction); } else if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml, translationKey: report.lastMessageTranslationKey})) { diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 99055f55af29..dd6e70033571 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -109,7 +109,10 @@ function isChannelLogMemberAction(reportAction: OnyxEntry) { ); } -function isReimbursementDeQueuedAction(reportID: string): boolean { +/** + * Returns whether the report is dequeued only using reportID + */ +function isReimbursementDeQueued(reportID: string): boolean { if (!allReportActions) { return false; } @@ -118,6 +121,10 @@ function isReimbursementDeQueuedAction(reportID: string): boolean { return reportAction.some((action) => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED); } +function isReimbursementDeQueuedAction(reportAction: OnyxEntry): boolean { + return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED; +} + /** * Returns whether the comment is a thread parent message/the first message in a thread */ @@ -707,6 +714,7 @@ export { hasRequestFromCurrentAccount, getFirstVisibleReportActionID, isChannelLogMemberAction, + isReimbursementDeQueued, isReimbursementDeQueuedAction, }; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e8354c16b547..8c9afeb6b280 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1480,6 +1480,16 @@ function getReimbursementQueuedActionMessage(reportAction: OnyxEntry): string { + const submitterDisplayName = getDisplayNameForParticipant(report?.ownerAccountID, true) ?? ''; + const amount = CurrencyUtils.convertToDisplayString(report?.total ?? 0, report?.currency); + + return Localize.translateLocal('iou.canceledRequest', {submitterDisplayName, amount}); +} + /** * Returns the last visible message for a given report after considering the given optimistic actions * @@ -1684,7 +1694,7 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.pending')}`; } - if (report?.reportID && ReportActionsUtils.isReimbursementDeQueuedAction(report.reportID)) { + if (report?.reportID && ReportActionsUtils.isReimbursementDeQueued(report.reportID)) { return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.canceled')}`; } @@ -4380,6 +4390,7 @@ export { shouldUseFullTitleToDisplay, parseReportRouteParams, getReimbursementQueuedActionMessage, + getReimbursementDeQueuedActionMessage, getPersonalDetailsForAccountID, getChannelLogMemberMessage, getRoom, From a08dadda2cfbd0449113a195f7117d442d9ef3df Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 29 Nov 2023 04:03:43 +0700 Subject: [PATCH 47/66] remove log --- .../ComposerWithSuggestions/ComposerWithSuggestions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 86a99812ad01..23fe26fb4cb5 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -491,7 +491,6 @@ function ComposerWithSuggestions({ const prevIsModalVisible = usePrevious(modal.isVisible); const prevIsFocused = usePrevious(isFocused); useEffect(() => { - console.log('abcdef'); if (modal.isVisible && !prevIsModalVisible) { // eslint-disable-next-line no-param-reassign isNextModalWillOpenRef.current = false; From 55903d64c61a1b7cf1a7bd480374f4535babc4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Wed, 29 Nov 2023 18:20:58 -0300 Subject: [PATCH 48/66] Use AvatarSource in ReportAction --- src/types/onyx/ReportAction.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 891a0ffcb7b8..64e1eb0b7c88 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -1,5 +1,5 @@ -import {SvgProps} from 'react-native-svg'; import {ValueOf} from 'type-fest'; +import {AvatarSource} from '@libs/UserUtils'; import CONST from '@src/CONST'; import * as OnyxCommon from './OnyxCommon'; import OriginalMessage, {Decision, Reaction} from './OriginalMessage'; @@ -85,7 +85,7 @@ type ReportActionBase = { /** accountIDs of the people to which the whisper was sent to (if any). Returns empty array if it is not a whisper */ whisperedToAccountIDs?: number[]; - avatar?: string | React.FC; + avatar?: AvatarSource; automatic?: boolean; @@ -145,4 +145,4 @@ type ReportAction = ReportActionBase & OriginalMessage; type ReportActions = Record; export default ReportAction; -export type {ReportActions, Message}; +export type {Message, ReportActions}; From 4eea09e2f17aa0b82ea1bc34816dc45c2d86aa14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Wed, 29 Nov 2023 18:27:32 -0300 Subject: [PATCH 49/66] Minor fixes in UserUtils docs --- src/libs/UserUtils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts index 036eeff82b83..29a43bcf711d 100644 --- a/src/libs/UserUtils.ts +++ b/src/libs/UserUtils.ts @@ -105,7 +105,7 @@ function getDefaultAvatarURL(accountID: string | number = '', isNewDot = false): /** * Given a user's avatar path, returns true if user doesn't have an avatar or if URL points to a default avatar - * @param [avatarSource] - the avatar source from user's personalDetails + * @param avatarSource - the avatar source from user's personalDetails */ function isDefaultAvatar(avatarSource?: AvatarSource): boolean { if (typeof avatarSource === 'string') { @@ -120,7 +120,7 @@ function isDefaultAvatar(avatarSource?: AvatarSource): boolean { } if (!avatarSource) { - // If null URL, we should also use a default avatar + // If null source, we should also use a default avatar return true; } @@ -128,8 +128,8 @@ function isDefaultAvatar(avatarSource?: AvatarSource): boolean { } /** - * Provided a source URL, if source is a default avatar, return the associated SVG. - * Otherwise, return the URL pointing to a user-uploaded avatar. + * Provided an avatar source, if source is a default avatar, return the associated SVG. + * Otherwise, return the URL or SVG pointing to the user-uploaded avatar. * * @param avatarSource - the avatar source from user's personalDetails * @param accountID - the accountID of the user From fef6485b899c7ed07fb22fb293aebc5b6978e337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Wed, 29 Nov 2023 18:32:17 -0300 Subject: [PATCH 50/66] Remove .ruby-version --- ios/.ruby-version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 ios/.ruby-version diff --git a/ios/.ruby-version b/ios/.ruby-version deleted file mode 100644 index a603bb50a29e..000000000000 --- a/ios/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.7.5 From 555ddcb309e218bf619dd308f6b7e515081c519c Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Thu, 30 Nov 2023 11:45:17 +0300 Subject: [PATCH 51/66] use isCancelledIOU and remove redundant function --- .../ReportActionItem/MoneyRequestPreview.js | 5 ++--- src/components/ReportActionItem/MoneyRequestView.js | 2 +- src/libs/ReportActionsUtils.ts | 13 ------------- src/libs/ReportUtils.ts | 2 +- src/types/onyx/Report.ts | 3 +++ 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 09baa9322ff4..1855152ef640 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -167,7 +167,6 @@ function MoneyRequestPreview(props) { const isDistanceRequest = TransactionUtils.isDistanceRequest(props.transaction); const isExpensifyCardTransaction = TransactionUtils.isExpensifyCardTransaction(props.transaction); const isSettled = ReportUtils.isSettled(props.iouReport.reportID); - const isCancelled = ReportActionsUtils.isReimbursementDeQueued(props.iouReport.reportID); const isDeleted = lodashGet(props.action, 'pendingAction', null) === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; // Show the merchant for IOUs and expenses only if they are custom or not related to scanning smartscan @@ -221,7 +220,7 @@ function MoneyRequestPreview(props) { message += ` • ${props.translate('iou.approved')}`; } else if (props.iouReport.isWaitingOnBankAccount) { message += ` • ${props.translate('iou.pending')}`; - } else if (isCancelled) { + } else if (props.iouReport.isCancelledIOU) { message += ` • ${props.translate('iou.canceled')}`; } return message; @@ -283,7 +282,7 @@ function MoneyRequestPreview(props) { - {getPreviewHeaderText() + (isSettled && !isCancelled ? ` • ${getSettledMessage()}` : '')} + {getPreviewHeaderText() + (isSettled && !props.iouReport.isCancelledIOU ? ` • ${getSettledMessage()}` : '')} {hasFieldErrors && ( ) { ); } -/** - * Returns whether the report is dequeued only using reportID - */ -function isReimbursementDeQueued(reportID: string): boolean { - if (!allReportActions) { - return false; - } - - const reportAction = Object.values(allReportActions[`${reportID}`] ?? {}); - return reportAction.some((action) => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED); -} - function isReimbursementDeQueuedAction(reportAction: OnyxEntry): boolean { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED; } @@ -714,7 +702,6 @@ export { hasRequestFromCurrentAccount, getFirstVisibleReportActionID, isChannelLogMemberAction, - isReimbursementDeQueued, isReimbursementDeQueuedAction, }; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8c9afeb6b280..b6c7b3a34c33 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1694,7 +1694,7 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.pending')}`; } - if (report?.reportID && ReportActionsUtils.isReimbursementDeQueued(report.reportID)) { + if (report?.isCancelledIOU) { return `${payerPaidAmountMessage} • ${Localize.translateLocal('iou.canceled')}`; } diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 81a92c4bf603..d656f79a6a71 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -118,6 +118,9 @@ type Report = { /** Whether the report is waiting on a bank account */ isWaitingOnBankAccount?: boolean; + /** Whether the report is cancelled */ + isCancelledIOU?: boolean; + /** Whether the last message was deleted */ isLastMessageDeletedParentAction?: boolean; From 75ad8c4aabb0a4accafc7da09d10bb15b029d4b5 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Thu, 30 Nov 2023 11:50:51 +0300 Subject: [PATCH 52/66] run prettier --- src/types/onyx/Report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index d656f79a6a71..418607a4e9b4 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -119,7 +119,7 @@ type Report = { isWaitingOnBankAccount?: boolean; /** Whether the report is cancelled */ - isCancelledIOU?: boolean; + isCancelledIOU?: boolean; /** Whether the last message was deleted */ isLastMessageDeletedParentAction?: boolean; From cd3ae078927702e8b56f7d58cfa4d88d520f24d9 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 1 Dec 2023 03:39:23 +0800 Subject: [PATCH 53/66] always include owner account id --- src/components/LHNOptionsList/LHNOptionsList.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.js b/src/components/LHNOptionsList/LHNOptionsList.js index 987faf2b3120..cee68be23a00 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.js +++ b/src/components/LHNOptionsList/LHNOptionsList.js @@ -117,11 +117,7 @@ function LHNOptionsList({ const transactionID = lodashGet(itemParentReportAction, ['originalMessage', 'IOUTransactionID'], ''); const itemTransaction = transactionID ? transactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] : {}; const itemComment = draftComments[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`] || ''; - const participants = [...(itemFullReport.participantAccountIDs || [])]; - - if (itemFullReport.ownerAccountID > 0) { - participants.push(itemFullReport.ownerAccountID); - } + const participants = [...(itemFullReport.participantAccountIDs || []), itemFullReport.ownerAccountID]; const participantsPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants, personalDetails); From 2afc843b82620521f7049bd00fcd490bc574d895 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Thu, 30 Nov 2023 16:04:25 -0700 Subject: [PATCH 54/66] Add a checkout for Slack error message when deploy fails --- .github/workflows/platformDeploy.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index 7cf6523ce908..e96a80c9d692 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -341,6 +341,9 @@ jobs: if: ${{ failure() }} needs: [android, desktop, iOS, web] steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Post Slack message on failure uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main with: From 6b1c3a8d08f3b6323056dd4f2cbe0cea88d1d6c8 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 1 Dec 2023 10:28:05 +0700 Subject: [PATCH 55/66] fix note editor open --- src/pages/ReportDetailsPage.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 442276b19a0b..4cd3bdd71bbe 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, {useMemo} from 'react'; +import React, {useEffect, useMemo} from 'react'; import {ScrollView, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -9,6 +9,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MultipleAvatars from '@components/MultipleAvatars'; +import {withNetwork} from '@components/OnyxProvider'; import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle'; import participantPropTypes from '@components/participantPropTypes'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; @@ -76,6 +77,18 @@ function ReportDetailsPage(props) { const isGroupDMChat = useMemo(() => ReportUtils.isDM(props.report) && participants.length > 1, [props.report, participants.length]); + const isPrivateNotesFetchTriggered = !_.isUndefined(props.report.isLoadingPrivateNotes); + + useEffect(() => { + // Do not fetch private notes if isLoadingPrivateNotes is already defined, or if network is offline. + if (isPrivateNotesFetchTriggered || props.network.isOffline) { + return; + } + + Report.getReportPrivateNote(props.report.reportID); + // eslint-disable-next-line react-hooks/exhaustive-deps -- do not add report.isLoadingPrivateNotes to dependencies + }, [props.report.reportID, props.network.isOffline, isPrivateNotesFetchTriggered]); + const menuItems = useMemo(() => { const items = []; @@ -249,6 +262,7 @@ ReportDetailsPage.defaultProps = defaultProps; export default compose( withLocalize, withReportOrNotFound(), + withNetwork(), withOnyx({ personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, From 0171212d57083cd01e3174c4e0d2c5adab29a2ff Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 1 Dec 2023 10:54:00 +0700 Subject: [PATCH 56/66] fix remove used comment --- src/pages/ReportDetailsPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 4cd3bdd71bbe..88583ab15529 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -86,7 +86,6 @@ function ReportDetailsPage(props) { } Report.getReportPrivateNote(props.report.reportID); - // eslint-disable-next-line react-hooks/exhaustive-deps -- do not add report.isLoadingPrivateNotes to dependencies }, [props.report.reportID, props.network.isOffline, isPrivateNotesFetchTriggered]); const menuItems = useMemo(() => { From b7075a42787d5950451cbd8f5406520d9c3ce920 Mon Sep 17 00:00:00 2001 From: Monil Bhavsar Date: Fri, 1 Dec 2023 14:06:52 +0530 Subject: [PATCH 57/66] Use lib methods and mimic well --- tests/unit/CalendarPickerTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/CalendarPickerTest.js b/tests/unit/CalendarPickerTest.js index 92092acc4cd7..4e564b970832 100644 --- a/tests/unit/CalendarPickerTest.js +++ b/tests/unit/CalendarPickerTest.js @@ -1,5 +1,5 @@ import {fireEvent, render, within} from '@testing-library/react-native'; -import {addYears, subYears} from 'date-fns'; +import {addMonths, addYears, subYears} from 'date-fns'; import CalendarPicker from '../../src/components/NewDatePicker/CalendarPicker'; import CONST from '../../src/CONST'; import DateUtils from '../../src/libs/DateUtils'; @@ -64,7 +64,7 @@ describe('CalendarPicker', () => { fireEvent.press(getByTestId('next-month-arrow')); - const nextMonth = new Date().getMonth() + 1; + const nextMonth = addMonths(new Date(), 1).getMonth(); expect(getByText(monthNames[nextMonth])).toBeTruthy(); }); From 6ff5bceb8cad20dee0386c345985a5249e203b49 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 11:14:18 +0100 Subject: [PATCH 58/66] implement custom useSafeAreaInsets and adapt SafeAreaConsumer on Android --- .../SafeAreaConsumer/index.android.tsx | 42 +++++++++++++++++++ .../index.tsx} | 18 ++------ src/components/SafeAreaConsumer/types.ts | 17 ++++++++ src/hooks/useSafeAreaInsets/index.android.ts | 14 +++++++ src/hooks/useSafeAreaInsets/index.ts | 4 ++ 5 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 src/components/SafeAreaConsumer/index.android.tsx rename src/components/{SafeAreaConsumer.tsx => SafeAreaConsumer/index.tsx} (69%) create mode 100644 src/components/SafeAreaConsumer/types.ts create mode 100644 src/hooks/useSafeAreaInsets/index.android.ts create mode 100644 src/hooks/useSafeAreaInsets/index.ts diff --git a/src/components/SafeAreaConsumer/index.android.tsx b/src/components/SafeAreaConsumer/index.android.tsx new file mode 100644 index 000000000000..472c2f037d29 --- /dev/null +++ b/src/components/SafeAreaConsumer/index.android.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +// eslint-disable-next-line no-restricted-imports +import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; +import StatusBar from '@libs/StatusBar'; +import * as StyleUtils from '@styles/StyleUtils'; +import SafeAreaConsumerProps from './types'; + +/** + * This component is a light wrapper around the SafeAreaInsetsContext.Consumer. There are several places where we + * may need not just the insets, but the computed styles so we save a few lines of code with this. + */ +function SafeAreaConsumer({children}: SafeAreaConsumerProps) { + return ( + + {(insets) => { + const insetsWithDefault = insets ?? { + top: 0, + bottom: 0, + left: 0, + right: 0, + }; + + const androidInsets = { + ...insetsWithDefault, + top: StatusBar.currentHeight ?? insetsWithDefault.top, + }; + + const {paddingTop, paddingBottom} = StyleUtils.getSafeAreaPadding(androidInsets ?? undefined); + return children({ + paddingTop, + paddingBottom, + insets: androidInsets ?? undefined, + safeAreaPaddingBottomStyle: {paddingBottom}, + }); + }} + + ); +} + +SafeAreaConsumer.displayName = 'SafeAreaConsumer'; + +export default SafeAreaConsumer; diff --git a/src/components/SafeAreaConsumer.tsx b/src/components/SafeAreaConsumer/index.tsx similarity index 69% rename from src/components/SafeAreaConsumer.tsx rename to src/components/SafeAreaConsumer/index.tsx index 7df73dbdb65f..f515d6697bb4 100644 --- a/src/components/SafeAreaConsumer.tsx +++ b/src/components/SafeAreaConsumer/index.tsx @@ -1,20 +1,8 @@ import React from 'react'; -import type {DimensionValue} from 'react-native'; -import {EdgeInsets, SafeAreaInsetsContext} from 'react-native-safe-area-context'; +// eslint-disable-next-line no-restricted-imports +import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; import * as StyleUtils from '@styles/StyleUtils'; - -type ChildrenProps = { - paddingTop?: DimensionValue; - paddingBottom?: DimensionValue; - insets?: EdgeInsets; - safeAreaPaddingBottomStyle: { - paddingBottom?: DimensionValue; - }; -}; - -type SafeAreaConsumerProps = { - children: React.FC; -}; +import SafeAreaConsumerProps from './types'; /** * This component is a light wrapper around the SafeAreaInsetsContext.Consumer. There are several places where we diff --git a/src/components/SafeAreaConsumer/types.ts b/src/components/SafeAreaConsumer/types.ts new file mode 100644 index 000000000000..bc81de96a082 --- /dev/null +++ b/src/components/SafeAreaConsumer/types.ts @@ -0,0 +1,17 @@ +import {DimensionValue} from 'react-native'; +import {EdgeInsets} from 'react-native-safe-area-context'; + +type ChildrenProps = { + paddingTop?: DimensionValue; + paddingBottom?: DimensionValue; + insets?: EdgeInsets; + safeAreaPaddingBottomStyle: { + paddingBottom?: DimensionValue; + }; +}; + +type SafeAreaConsumerProps = { + children: React.FC; +}; + +export default SafeAreaConsumerProps; diff --git a/src/hooks/useSafeAreaInsets/index.android.ts b/src/hooks/useSafeAreaInsets/index.android.ts new file mode 100644 index 000000000000..55a83d425543 --- /dev/null +++ b/src/hooks/useSafeAreaInsets/index.android.ts @@ -0,0 +1,14 @@ +// eslint-disable-next-line no-restricted-imports +import {EdgeInsets, useSafeAreaInsets as useSafeAreaInsetsInternal} from 'react-native-safe-area-context'; +import StatusBar from '@libs/StatusBar'; + +function useSafeAreaInsets(): EdgeInsets { + const insets = useSafeAreaInsetsInternal(); + + return { + ...insets, + top: StatusBar.currentHeight ?? insets.top, + }; +} + +export default useSafeAreaInsets; diff --git a/src/hooks/useSafeAreaInsets/index.ts b/src/hooks/useSafeAreaInsets/index.ts new file mode 100644 index 000000000000..6cc2f1818fe5 --- /dev/null +++ b/src/hooks/useSafeAreaInsets/index.ts @@ -0,0 +1,4 @@ +/* eslint-disable no-restricted-imports */ +import {useSafeAreaInsets} from 'react-native-safe-area-context'; + +export default useSafeAreaInsets; From 3855b85ddbd0515b00b680288d580b079a01eb2e Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 11:15:08 +0100 Subject: [PATCH 59/66] adapt all flows to use new components --- .../index.native.js | 14 ++- src/components/Modal/BaseModal.tsx | 2 +- src/components/PopoverWithoutOverlay/index.js | 93 +++++++++++-------- .../withWindowDimensions/index.native.tsx | 2 +- src/components/withWindowDimensions/index.tsx | 2 +- src/pages/signin/SignInPage.js | 2 +- 6 files changed, 64 insertions(+), 51 deletions(-) diff --git a/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js b/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js index 4a2fa28082b6..1b59219f38be 100644 --- a/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js +++ b/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js @@ -1,6 +1,6 @@ import React from 'react'; import {Animated} from 'react-native'; -import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; +import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import * as StyleUtils from '@styles/StyleUtils'; import useThemeStyles from '@styles/useThemeStyles'; import growlNotificationContainerPropTypes from './growlNotificationContainerPropTypes'; @@ -11,14 +11,12 @@ const propTypes = { function GrowlNotificationContainer(props) { const styles = useThemeStyles(); + const insets = useSafeAreaInsets; + return ( - - {(insets) => ( - - {props.children} - - )} - + + {props.children} + ); } diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 7aeef4d97e31..653ce910da9f 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -1,8 +1,8 @@ import React, {forwardRef, useCallback, useEffect, useMemo, useRef} from 'react'; import {View} from 'react-native'; import ReactNativeModal from 'react-native-modal'; -import {useSafeAreaInsets} from 'react-native-safe-area-context'; import usePrevious from '@hooks/usePrevious'; +import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import useWindowDimensions from '@hooks/useWindowDimensions'; import ComposerFocusManager from '@libs/ComposerFocusManager'; import useNativeDriver from '@libs/useNativeDriver'; diff --git a/src/components/PopoverWithoutOverlay/index.js b/src/components/PopoverWithoutOverlay/index.js index fd162c78fe2c..57a2452c2be6 100644 --- a/src/components/PopoverWithoutOverlay/index.js +++ b/src/components/PopoverWithoutOverlay/index.js @@ -1,9 +1,9 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import {View} from 'react-native'; -import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; import {defaultProps, propTypes} from '@components/Popover/popoverPropTypes'; import {PopoverContext} from '@components/PopoverProvider'; import withWindowDimensions from '@components/withWindowDimensions'; +import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import getModalStyles from '@styles/getModalStyles'; import * as StyleUtils from '@styles/StyleUtils'; import useTheme from '@styles/themes/useTheme'; @@ -14,6 +14,7 @@ function Popover(props) { const theme = useTheme(); const styles = useThemeStyles(); const {onOpen, close} = React.useContext(PopoverContext); + const {insets} = useSafeAreaInsets(); const {modalStyle, modalContainerStyle, shouldAddTopSafeAreaMargin, shouldAddBottomSafeAreaMargin, shouldAddTopSafeAreaPadding, shouldAddBottomSafeAreaPadding} = getModalStyles( 'popover', { @@ -28,6 +29,47 @@ function Popover(props) { props.outerStyle, ); + const { + paddingTop: safeAreaPaddingTop, + paddingBottom: safeAreaPaddingBottom, + paddingLeft: safeAreaPaddingLeft, + paddingRight: safeAreaPaddingRight, + } = useMemo(() => StyleUtils.getSafeAreaPadding(insets), [insets]); + + const modalPaddingStyles = useMemo( + () => + StyleUtils.getModalPaddingStyles({ + safeAreaPaddingTop, + safeAreaPaddingBottom, + safeAreaPaddingLeft, + safeAreaPaddingRight, + shouldAddBottomSafeAreaMargin, + shouldAddTopSafeAreaMargin, + shouldAddBottomSafeAreaPadding, + shouldAddTopSafeAreaPadding, + modalContainerStyleMarginTop: modalContainerStyle.marginTop, + modalContainerStyleMarginBottom: modalContainerStyle.marginBottom, + modalContainerStylePaddingTop: modalContainerStyle.paddingTop, + modalContainerStylePaddingBottom: modalContainerStyle.paddingBottom, + insets, + }), + [ + insets, + modalContainerStyle.marginBottom, + modalContainerStyle.marginTop, + modalContainerStyle.paddingBottom, + modalContainerStyle.paddingTop, + safeAreaPaddingBottom, + safeAreaPaddingLeft, + safeAreaPaddingRight, + safeAreaPaddingTop, + shouldAddBottomSafeAreaMargin, + shouldAddBottomSafeAreaPadding, + shouldAddTopSafeAreaMargin, + shouldAddTopSafeAreaPadding, + ], + ); + React.useEffect(() => { let removeOnClose; if (props.isVisible) { @@ -64,44 +106,17 @@ function Popover(props) { style={[modalStyle, {zIndex: 1}]} ref={props.withoutOverlayRef} > - - {(insets) => { - const { - paddingTop: safeAreaPaddingTop, - paddingBottom: safeAreaPaddingBottom, - paddingLeft: safeAreaPaddingLeft, - paddingRight: safeAreaPaddingRight, - } = StyleUtils.getSafeAreaPadding(insets); - - const modalPaddingStyles = StyleUtils.getModalPaddingStyles({ - safeAreaPaddingTop, - safeAreaPaddingBottom, - safeAreaPaddingLeft, - safeAreaPaddingRight, - shouldAddBottomSafeAreaMargin, - shouldAddTopSafeAreaMargin, - shouldAddBottomSafeAreaPadding, - shouldAddTopSafeAreaPadding, - modalContainerStyleMarginTop: modalContainerStyle.marginTop, - modalContainerStyleMarginBottom: modalContainerStyle.marginBottom, - modalContainerStylePaddingTop: modalContainerStyle.paddingTop, - modalContainerStylePaddingBottom: modalContainerStyle.paddingBottom, - insets, - }); - return ( - - {props.children} - - ); + return ( + + ref={props.forwardedRef} + > + {props.children} + ); } diff --git a/src/components/withWindowDimensions/index.native.tsx b/src/components/withWindowDimensions/index.native.tsx index 0c9f61a45c0b..8ba385f72e4b 100644 --- a/src/components/withWindowDimensions/index.native.tsx +++ b/src/components/withWindowDimensions/index.native.tsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, {ComponentType, createContext, ForwardedRef, RefAttributes, useEffect, useMemo, useState} from 'react'; import {Dimensions} from 'react-native'; -import {useSafeAreaInsets} from 'react-native-safe-area-context'; +import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment'; import variables from '@styles/variables'; diff --git a/src/components/withWindowDimensions/index.tsx b/src/components/withWindowDimensions/index.tsx index 1479450deec4..aa9fc2181a36 100644 --- a/src/components/withWindowDimensions/index.tsx +++ b/src/components/withWindowDimensions/index.tsx @@ -2,7 +2,7 @@ import lodashDebounce from 'lodash/debounce'; import PropTypes from 'prop-types'; import React, {ComponentType, createContext, ForwardedRef, RefAttributes, useEffect, useMemo, useState} from 'react'; import {Dimensions} from 'react-native'; -import {useSafeAreaInsets} from 'react-native-safe-area-context'; +import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment'; import variables from '@styles/variables'; diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index e7499e2aef01..24b16177e6ff 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -3,11 +3,11 @@ import PropTypes from 'prop-types'; import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import {useSafeAreaInsets} from 'react-native-safe-area-context'; import _ from 'underscore'; import ColorSchemeWrapper from '@components/ColorSchemeWrapper'; import CustomStatusBar from '@components/CustomStatusBar'; import useLocalize from '@hooks/useLocalize'; +import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ActiveClientManager from '@libs/ActiveClientManager'; import getPlatform from '@libs/getPlatform'; From 502b907f208dda27cfa2b04888d24f4d4b74243e Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 11:15:22 +0100 Subject: [PATCH 60/66] add eslint rule --- .eslintrc.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index b76782af60f4..b71338d0c1a5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,6 +14,11 @@ const restrictedImportPaths = [ importNames: ['TouchableOpacity', 'TouchableWithoutFeedback', 'TouchableNativeFeedback', 'TouchableHighlight'], message: "Please use 'PressableWithFeedback' and/or 'PressableWithoutFeedback' from 'src/components/Pressable' instead.", }, + { + name: 'react-native-safe-area-context', + importNames: ['useSafeAreaInsets', 'SafeAreaConsumer', 'SafeAreaInsetsContext'], + message: "Please use 'useSafeAreaInsets' from 'src/hooks/useSafeAreaInset' and/or 'SafeAreaConsumer' from 'src/components/SafeAreaConsumer' instead.", + }, ]; const restrictedImportPatterns = [ From b50060af1545d5ffa8203769411ebe2be79bde67 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 11:15:39 +0100 Subject: [PATCH 61/66] update status bar appearance on different platforms --- src/components/CustomStatusBar/index.tsx | 6 +++--- .../updateStatusBarAppearance/index.android.ts | 10 ++++++++++ .../updateStatusBarAppearance/index.ios.ts | 10 ++++++++++ .../updateStatusBarAppearance/index.ts | 11 +++++++++++ .../updateStatusBarAppearance/types.ts | 8 ++++++++ 5 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts create mode 100644 src/components/CustomStatusBar/updateStatusBarAppearance/index.ios.ts create mode 100644 src/components/CustomStatusBar/updateStatusBarAppearance/index.ts create mode 100644 src/components/CustomStatusBar/updateStatusBarAppearance/types.ts diff --git a/src/components/CustomStatusBar/index.tsx b/src/components/CustomStatusBar/index.tsx index 2e4994378264..3b5022c60898 100644 --- a/src/components/CustomStatusBar/index.tsx +++ b/src/components/CustomStatusBar/index.tsx @@ -5,6 +5,7 @@ import {navigationRef} from '@libs/Navigation/Navigation'; import StatusBar from '@libs/StatusBar'; import useTheme from '@styles/themes/useTheme'; import CustomStatusBarContext from './CustomStatusBarContext'; +import updateStatusBarAppearance from './updateStatusBarAppearance'; type CustomStatusBarProps = { isNested: boolean; @@ -60,8 +61,7 @@ const CustomStatusBar: CustomStatusBarType = ({isNested = false}) => { statusBarStyle = screenTheme.statusBarStyle; } - StatusBar.setBackgroundColor(currentScreenBackgroundColor, true); - StatusBar.setBarStyle(statusBarStyle, true); + updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor, statusBarStyle}); }, [isDisabled, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle]); useEffect(() => { @@ -75,7 +75,7 @@ const CustomStatusBar: CustomStatusBarType = ({isNested = false}) => { return; } - StatusBar.setBarStyle(theme.statusBarStyle, true); + updateStatusBarAppearance({statusBarStyle: theme.statusBarStyle}); }, [isDisabled, theme.statusBarStyle]); if (isDisabled) { diff --git a/src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts b/src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts new file mode 100644 index 000000000000..265b18b3ae1a --- /dev/null +++ b/src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts @@ -0,0 +1,10 @@ +import StatusBar from '@libs/StatusBar'; +import UpdateStatusBarAppearanceProps from './types'; + +// eslint-disable-next-line @typescript-eslint/naming-convention +export default function updateStatusBarAppearance({statusBarStyle}: UpdateStatusBarAppearanceProps) { + StatusBar.setTranslucent(true); + if (statusBarStyle) { + StatusBar.setBarStyle(statusBarStyle, true); + } +} diff --git a/src/components/CustomStatusBar/updateStatusBarAppearance/index.ios.ts b/src/components/CustomStatusBar/updateStatusBarAppearance/index.ios.ts new file mode 100644 index 000000000000..61fcb056bba5 --- /dev/null +++ b/src/components/CustomStatusBar/updateStatusBarAppearance/index.ios.ts @@ -0,0 +1,10 @@ +import StatusBar from '@libs/StatusBar'; +import UpdateStatusBarAppearanceProps from './types'; + +// eslint-disable-next-line @typescript-eslint/naming-convention +export default function updateStatusBarAppearance({statusBarStyle}: UpdateStatusBarAppearanceProps) { + if (!statusBarStyle) { + return; + } + StatusBar.setBarStyle(statusBarStyle, true); +} diff --git a/src/components/CustomStatusBar/updateStatusBarAppearance/index.ts b/src/components/CustomStatusBar/updateStatusBarAppearance/index.ts new file mode 100644 index 000000000000..574efd90f0b5 --- /dev/null +++ b/src/components/CustomStatusBar/updateStatusBarAppearance/index.ts @@ -0,0 +1,11 @@ +import StatusBar from '@libs/StatusBar'; +import UpdateStatusBarAppearanceProps from './types'; + +export default function updateStatusBarAppearance({backgroundColor, statusBarStyle}: UpdateStatusBarAppearanceProps) { + if (backgroundColor) { + StatusBar.setBackgroundColor(backgroundColor, true); + } + if (statusBarStyle) { + StatusBar.setBarStyle(statusBarStyle, true); + } +} diff --git a/src/components/CustomStatusBar/updateStatusBarAppearance/types.ts b/src/components/CustomStatusBar/updateStatusBarAppearance/types.ts new file mode 100644 index 000000000000..3d16b5944a31 --- /dev/null +++ b/src/components/CustomStatusBar/updateStatusBarAppearance/types.ts @@ -0,0 +1,8 @@ +import {StatusBarStyle} from '@styles/styles'; + +type UpdateStatusBarAppearanceProps = { + backgroundColor?: string; + statusBarStyle?: StatusBarStyle; +}; + +export default UpdateStatusBarAppearanceProps; From 1ef614bc9d36c812310290ca5630279183f51a65 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 11:27:16 +0100 Subject: [PATCH 62/66] fix: android status bar translucent --- .../CustomStatusBar/updateStatusBarAppearance/index.android.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts b/src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts index 265b18b3ae1a..b7651d4549de 100644 --- a/src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts +++ b/src/components/CustomStatusBar/updateStatusBarAppearance/index.android.ts @@ -3,6 +3,7 @@ import UpdateStatusBarAppearanceProps from './types'; // eslint-disable-next-line @typescript-eslint/naming-convention export default function updateStatusBarAppearance({statusBarStyle}: UpdateStatusBarAppearanceProps) { + StatusBar.setBackgroundColor('transparent'); StatusBar.setTranslucent(true); if (statusBarStyle) { StatusBar.setBarStyle(statusBarStyle, true); From a8fa5f796ffef96b832cf0dbee1df247532af940 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 11:37:45 +0100 Subject: [PATCH 63/66] fix: wrong insets usage --- src/components/PopoverWithoutOverlay/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PopoverWithoutOverlay/index.js b/src/components/PopoverWithoutOverlay/index.js index 57a2452c2be6..e28cf39eaa8f 100644 --- a/src/components/PopoverWithoutOverlay/index.js +++ b/src/components/PopoverWithoutOverlay/index.js @@ -14,7 +14,7 @@ function Popover(props) { const theme = useTheme(); const styles = useThemeStyles(); const {onOpen, close} = React.useContext(PopoverContext); - const {insets} = useSafeAreaInsets(); + const insets = useSafeAreaInsets(); const {modalStyle, modalContainerStyle, shouldAddTopSafeAreaMargin, shouldAddBottomSafeAreaMargin, shouldAddTopSafeAreaPadding, shouldAddBottomSafeAreaPadding} = getModalStyles( 'popover', { From b143262a3279ccef566f7ebd69d87cf046e4dc17 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 1 Dec 2023 12:30:44 +0000 Subject: [PATCH 64/66] Update version to 1.4.7-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 28c983297c8b..2e735cbaf419 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,8 +91,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001040602 - versionName "1.4.6-2" + versionCode 1001040700 + versionName "1.4.7-0" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index c05fe7fbfeba..a01a04f71b3c 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.6 + 1.4.7 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.6.2 + 1.4.7.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 4c875f6d7ba2..095122c37ce4 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.6 + 1.4.7 CFBundleSignature ???? CFBundleVersion - 1.4.6.2 + 1.4.7.0 diff --git a/package-lock.json b/package-lock.json index b3a8c47f853c..65173ccec496 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.6-2", + "version": "1.4.7-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.6-2", + "version": "1.4.7-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 6412fd588bde..1693afc40b04 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.6-2", + "version": "1.4.7-0", "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.", From ea83f05277a6456cb30b95c2b7509c5940538e7b Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 15:05:53 +0100 Subject: [PATCH 65/66] Update index.js Co-authored-by: Fedi Rajhi --- src/components/PopoverWithoutOverlay/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/PopoverWithoutOverlay/index.js b/src/components/PopoverWithoutOverlay/index.js index e28cf39eaa8f..1c785d4b363f 100644 --- a/src/components/PopoverWithoutOverlay/index.js +++ b/src/components/PopoverWithoutOverlay/index.js @@ -106,7 +106,6 @@ function Popover(props) { style={[modalStyle, {zIndex: 1}]} ref={props.withoutOverlayRef} > - return ( Date: Fri, 1 Dec 2023 15:08:16 +0100 Subject: [PATCH 66/66] change buttons position --- src/pages/ShareCodePage.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js index d81593fb552a..c63db694159f 100644 --- a/src/pages/ShareCodePage.js +++ b/src/pages/ShareCodePage.js @@ -108,12 +108,6 @@ class ShareCodePage extends React.Component { onPress={() => Clipboard.setString(url)} /> - Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE))} - /> - {isNative && ( this.qrCodeRef.current?.download()} /> )} + + Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE))} + />