From 024ab748dbc7d4371866ee1070a99193199551ec Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 23 Oct 2023 09:45:06 +0700 Subject: [PATCH 01/63] fix: 30062 --- src/pages/home/ReportScreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 81000c2dab92..9b1a72f90b9f 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -317,7 +317,7 @@ function ReportScreen({ prevOnyxReportID === routeReportID && !onyxReportID && prevReport.statusNum === CONST.REPORT.STATUS.OPEN && - (report.statusNum === CONST.REPORT.STATUS.CLOSED || (!report.statusNum && !prevReport.parentReportID))) + (report.statusNum === CONST.REPORT.STATUS.CLOSED || (!report.statusNum && !prevReport.parentReportID && prevReport.chatType === CONST.REPORT.CHAT_TYPE.POLICY_ROOM))) ) { Navigation.dismissModal(); if (Navigation.getTopmostReportId() === prevOnyxReportID) { From bb077b6853ac71cb443529a0f5423477c91dcc99 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 25 Oct 2023 16:44:49 +0200 Subject: [PATCH 02/63] 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 03/63] 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 04/63] 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 8b91fa45e7e62c656691fbb413b67f592531962e Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 6 Nov 2023 17:47:58 +0700 Subject: [PATCH 05/63] fix: 30801 --- src/libs/actions/Policy.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 9b33ff9b086e..a2f4ec79f0ff 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -976,7 +976,7 @@ function generateCustomUnitID() { /** * @returns {Object} */ -function buildOptimisticCustomUnits() { +function buildOptimisticCustomUnits(currency) { const customUnitID = generateCustomUnitID(); const customUnitRateID = generateCustomUnitID(); const customUnits = { @@ -991,6 +991,7 @@ function buildOptimisticCustomUnits() { customUnitRateID, name: CONST.CUSTOM_UNITS.DEFAULT_RATE, rate: CONST.CUSTOM_UNITS.MILEAGE_IRS_RATE * CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET, + currency, }, }, }, @@ -1013,7 +1014,8 @@ function buildOptimisticCustomUnits() { */ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', policyID = generatePolicyID(), makeMeAdmin = false) { const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); - const {customUnits} = buildOptimisticCustomUnits(); + const outputCurrency = lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD) + const {customUnits} = buildOptimisticCustomUnits(outputCurrency); const optimisticData = [ { @@ -1026,7 +1028,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol role: CONST.POLICY.ROLE.ADMIN, owner: sessionEmail, isPolicyExpenseChatEnabled: true, - outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD), + outputCurrency, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, customUnits, makeMeAdmin, @@ -1059,7 +1061,8 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', policyID = generatePolicyID()) { const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); - const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(); + const outputCurrency = lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD); + const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(outputCurrency); const { announceChatReportID, @@ -1105,7 +1108,7 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName role: CONST.POLICY.ROLE.ADMIN, owner: sessionEmail, isPolicyExpenseChatEnabled: true, - outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD), + outputCurrency, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, customUnits, }, From a567b1cf98466435c9053acfe77c9d8f9b7695a8 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 10 Nov 2023 15:47:28 +0700 Subject: [PATCH 06/63] build optimistic custom unit when create workspace --- src/libs/actions/Policy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index a2f4ec79f0ff..f1a17f8b898e 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -974,6 +974,7 @@ function generateCustomUnitID() { } /** + * @param {String} currency * @returns {Object} */ function buildOptimisticCustomUnits(currency) { @@ -1014,7 +1015,7 @@ function buildOptimisticCustomUnits(currency) { */ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', policyID = generatePolicyID(), makeMeAdmin = false) { const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); - const outputCurrency = lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD) + const outputCurrency = lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD); const {customUnits} = buildOptimisticCustomUnits(outputCurrency); const optimisticData = [ From e5fb0a1651a797ff7e7912efa70d3661285eaafe Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 10 Nov 2023 16:30:16 +0700 Subject: [PATCH 07/63] fix test --- src/libs/actions/Policy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 091f2930a5b9..55a734bda72e 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1049,7 +1049,7 @@ function generateCustomUnitID() { * @returns {Object} */ function buildOptimisticCustomUnits(currency) { - const customUnitID = generateCustomUnitID(); + const customUnitID = generateCustomUnitID(); const customUnitRateID = generateCustomUnitID(); const customUnits = { [customUnitID]: { From 87c7e12a28e93c1be58974ece82f79fbb72590b4 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 10 Nov 2023 16:30:47 +0700 Subject: [PATCH 08/63] fix lint --- src/libs/actions/Policy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 55a734bda72e..091f2930a5b9 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1049,7 +1049,7 @@ function generateCustomUnitID() { * @returns {Object} */ function buildOptimisticCustomUnits(currency) { - const customUnitID = generateCustomUnitID(); + const customUnitID = generateCustomUnitID(); const customUnitRateID = generateCustomUnitID(); const customUnits = { [customUnitID]: { From 2b581aa94578977be79c249126cf47c27a321b66 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 10 Nov 2023 16:54:03 +0700 Subject: [PATCH 09/63] fix test --- src/libs/actions/Policy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 091f2930a5b9..961181612a81 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1048,7 +1048,7 @@ function generateCustomUnitID() { * @param {String} currency * @returns {Object} */ -function buildOptimisticCustomUnits(currency) { +function buildOptimisticCustomUnits(currency) { const customUnitID = generateCustomUnitID(); const customUnitRateID = generateCustomUnitID(); const customUnits = { From 697adae78bcb04e2480e3f8f5aba6dbe5cbf50b9 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 10 Nov 2023 16:54:25 +0700 Subject: [PATCH 10/63] fix lint --- src/libs/actions/Policy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 961181612a81..091f2930a5b9 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1048,7 +1048,7 @@ function generateCustomUnitID() { * @param {String} currency * @returns {Object} */ -function buildOptimisticCustomUnits(currency) { +function buildOptimisticCustomUnits(currency) { const customUnitID = generateCustomUnitID(); const customUnitRateID = generateCustomUnitID(); const customUnits = { From 17f7b490f324e9dc399fce46d32b05ae411e8331 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 14 Nov 2023 12:14:15 +0700 Subject: [PATCH 11/63] move output currency --- src/libs/actions/Policy.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 5d5c937e46f6..b11df545fc64 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1045,12 +1045,14 @@ function generateCustomUnitID() { } /** - * @param {String} currency + * * @returns {Object} */ -function buildOptimisticCustomUnits(currency) { +function buildOptimisticCustomUnits() { + const currency = lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD); const customUnitID = generateCustomUnitID(); const customUnitRateID = generateCustomUnitID(); + const customUnits = { [customUnitID]: { customUnitID, @@ -1073,6 +1075,7 @@ function buildOptimisticCustomUnits(currency) { customUnits, customUnitID, customUnitRateID, + outputCurrency: currency, }; } @@ -1086,8 +1089,7 @@ function buildOptimisticCustomUnits(currency) { */ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', policyID = generatePolicyID(), makeMeAdmin = false) { const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); - const outputCurrency = lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD); - const {customUnits} = buildOptimisticCustomUnits(outputCurrency); + const {customUnits, outputCurrency} = buildOptimisticCustomUnits(); const optimisticData = [ { @@ -1133,8 +1135,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', policyID = generatePolicyID()) { const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); - const outputCurrency = lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD); - const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(outputCurrency); + const {customUnits, customUnitID, customUnitRateID, outputCurrency} = buildOptimisticCustomUnits(); const { announceChatReportID, From c2ebb368ea9aacd44108cfa48b1f4e9c1f417106 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Tue, 14 Nov 2023 15:46:06 +0100 Subject: [PATCH 12/63] [TS migration] Migrate 'OfflineIndicator.js' component --- src/components/OfflineIndicator.js | 67 ----------------------------- src/components/OfflineIndicator.tsx | 63 +++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 67 deletions(-) delete mode 100644 src/components/OfflineIndicator.js create mode 100644 src/components/OfflineIndicator.tsx diff --git a/src/components/OfflineIndicator.js b/src/components/OfflineIndicator.js deleted file mode 100644 index 9cacc3621790..000000000000 --- a/src/components/OfflineIndicator.js +++ /dev/null @@ -1,67 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import {View} from 'react-native'; -import compose from '@libs/compose'; -import stylePropTypes from '@styles/stylePropTypes'; -import styles from '@styles/styles'; -import * as StyleUtils from '@styles/StyleUtils'; -import variables from '@styles/variables'; -import Icon from './Icon'; -import * as Expensicons from './Icon/Expensicons'; -import networkPropTypes from './networkPropTypes'; -import {withNetwork} from './OnyxProvider'; -import Text from './Text'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; -import withWindowDimensions from './withWindowDimensions'; - -const propTypes = { - /** Information about the network */ - network: networkPropTypes.isRequired, - - /** Optional styles for container element that will override the default styling for the offline indicator */ - // eslint-disable-next-line react/forbid-prop-types - containerStyles: PropTypes.arrayOf(PropTypes.object), - - /** Optional styles for the container */ - style: stylePropTypes, - - /** Is the window width narrow, like on a mobile device */ - isSmallScreenWidth: PropTypes.bool.isRequired, - - ...withLocalizePropTypes, -}; - -const defaultProps = { - containerStyles: [], - style: [], -}; - -const setStyles = (containerStyles, isSmallScreenWidth) => { - if (containerStyles.length) { - return containerStyles; - } - return isSmallScreenWidth ? styles.offlineIndicatorMobile : styles.offlineIndicator; -}; - -function OfflineIndicator(props) { - if (!props.network.isOffline) { - return null; - } - - return ( - - - {props.translate('common.youAppearToBeOffline')} - - ); -} - -OfflineIndicator.propTypes = propTypes; -OfflineIndicator.defaultProps = defaultProps; -OfflineIndicator.displayName = 'OfflineIndicator'; - -export default compose(withWindowDimensions, withLocalize, withNetwork())(OfflineIndicator); diff --git a/src/components/OfflineIndicator.tsx b/src/components/OfflineIndicator.tsx new file mode 100644 index 000000000000..197f63ff17aa --- /dev/null +++ b/src/components/OfflineIndicator.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import {StyleProp, View, ViewStyle} from 'react-native'; +import {OnyxEntry} from 'react-native-onyx/lib/types'; +import compose from '@libs/compose'; +import styles from '@styles/styles'; +import variables from '@styles/variables'; +import type {Network} from '@src/types/onyx'; +import Icon from './Icon'; +import * as Expensicons from './Icon/Expensicons'; +import {withNetwork} from './OnyxProvider'; +import Text from './Text'; +import withLocalize from './withLocalize'; +import withWindowDimensions from './withWindowDimensions'; + +type OfflineIndicatorProps = { + /** Information about the network */ + network: OnyxEntry; + + /** Optional styles for container element that will override the default styling for the offline indicator */ + containerStyles?: StyleProp; + + /** Optional styles for the container */ + style?: StyleProp; + + /** Is the window width narrow, like on a mobile device */ + isSmallScreenWidth: boolean; + + // TODO: remove after withLocalize migrated + /** Returns translated string for given locale and phrase */ + translate: (value: string) => string; +}; + +const setStyles = (containerStyles: StyleProp, isSmallScreenWidth: boolean): StyleProp => { + if (!!containerStyles && ((Array.isArray(containerStyles) && containerStyles.length) || Object.keys(containerStyles).length)) { + return containerStyles; + } + + return isSmallScreenWidth ? styles.offlineIndicatorMobile : styles.offlineIndicator; +}; + +function OfflineIndicator({network, isSmallScreenWidth, translate, style = [], containerStyles = []}: OfflineIndicatorProps) { + if (!network?.isOffline) { + return null; + } + + return ( + + + {translate('common.youAppearToBeOffline')} + + ); +} + +OfflineIndicator.displayName = 'OfflineIndicator'; + +// TODO: remove when withWindowDimensions, withLocalize are migrated +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +export default compose(withWindowDimensions, withLocalize, withNetwork())(OfflineIndicator); From d8acbd9b11864de410df5772475af88cf79888bd Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Fri, 17 Nov 2023 14:44:31 +0100 Subject: [PATCH 13/63] Fix TS issues --- src/components/OfflineIndicator.tsx | 35 ++++++++++++----------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/components/OfflineIndicator.tsx b/src/components/OfflineIndicator.tsx index 197f63ff17aa..7b980b663d04 100644 --- a/src/components/OfflineIndicator.tsx +++ b/src/components/OfflineIndicator.tsx @@ -1,34 +1,29 @@ import React from 'react'; import {StyleProp, View, ViewStyle} from 'react-native'; import {OnyxEntry} from 'react-native-onyx/lib/types'; -import compose from '@libs/compose'; import styles from '@styles/styles'; import variables from '@styles/variables'; import type {Network} from '@src/types/onyx'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; +import type {LocaleContextProps} from './LocaleContextProvider'; import {withNetwork} from './OnyxProvider'; import Text from './Text'; import withLocalize from './withLocalize'; import withWindowDimensions from './withWindowDimensions'; +import type {WindowDimensionsProps} from './withWindowDimensions/types'; -type OfflineIndicatorProps = { - /** Information about the network */ - network: OnyxEntry; +type OfflineIndicatorProps = LocaleContextProps & + WindowDimensionsProps & { + /** Information about the network */ + network: OnyxEntry; - /** Optional styles for container element that will override the default styling for the offline indicator */ - containerStyles?: StyleProp; + /** Optional styles for container element that will override the default styling for the offline indicator */ + containerStyles?: StyleProp; - /** Optional styles for the container */ - style?: StyleProp; - - /** Is the window width narrow, like on a mobile device */ - isSmallScreenWidth: boolean; - - // TODO: remove after withLocalize migrated - /** Returns translated string for given locale and phrase */ - translate: (value: string) => string; -}; + /** Optional styles for the container */ + style?: StyleProp; + }; const setStyles = (containerStyles: StyleProp, isSmallScreenWidth: boolean): StyleProp => { if (!!containerStyles && ((Array.isArray(containerStyles) && containerStyles.length) || Object.keys(containerStyles).length)) { @@ -38,7 +33,7 @@ const setStyles = (containerStyles: StyleProp, isSmallScreenWidth: bo return isSmallScreenWidth ? styles.offlineIndicatorMobile : styles.offlineIndicator; }; -function OfflineIndicator({network, isSmallScreenWidth, translate, style = [], containerStyles = []}: OfflineIndicatorProps) { +function OfflineIndicator({network, isSmallScreenWidth, translate, style, containerStyles}: OfflineIndicatorProps) { if (!network?.isOffline) { return null; } @@ -57,7 +52,5 @@ function OfflineIndicator({network, isSmallScreenWidth, translate, style = [], c OfflineIndicator.displayName = 'OfflineIndicator'; -// TODO: remove when withWindowDimensions, withLocalize are migrated -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -export default compose(withWindowDimensions, withLocalize, withNetwork())(OfflineIndicator); +// TODO: use `compose` function for HOCs composing once TypeScript issues are resolved. +export default withNetwork()(withLocalize(withWindowDimensions(OfflineIndicator))); From bbe702f59339b9bb039c126c2f019700228c43d9 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Fri, 17 Nov 2023 18:11:07 +0100 Subject: [PATCH 14/63] Update styles check --- src/components/OfflineIndicator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/OfflineIndicator.tsx b/src/components/OfflineIndicator.tsx index 7b980b663d04..b333fb5bb1bb 100644 --- a/src/components/OfflineIndicator.tsx +++ b/src/components/OfflineIndicator.tsx @@ -26,7 +26,7 @@ type OfflineIndicatorProps = LocaleContextProps & }; const setStyles = (containerStyles: StyleProp, isSmallScreenWidth: boolean): StyleProp => { - if (!!containerStyles && ((Array.isArray(containerStyles) && containerStyles.length) || Object.keys(containerStyles).length)) { + if (containerStyles) { return containerStyles; } From 895605ea41cd58d98a895590f797056ea4bcc1e2 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Mon, 20 Nov 2023 10:11:56 +0100 Subject: [PATCH 15/63] Replace HOCs with hooks usage --- src/components/OfflineIndicator.tsx | 37 +++++++++++++---------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/components/OfflineIndicator.tsx b/src/components/OfflineIndicator.tsx index b333fb5bb1bb..ba0cf1860915 100644 --- a/src/components/OfflineIndicator.tsx +++ b/src/components/OfflineIndicator.tsx @@ -1,29 +1,21 @@ import React from 'react'; import {StyleProp, View, ViewStyle} from 'react-native'; -import {OnyxEntry} from 'react-native-onyx/lib/types'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import styles from '@styles/styles'; import variables from '@styles/variables'; -import type {Network} from '@src/types/onyx'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; -import type {LocaleContextProps} from './LocaleContextProvider'; -import {withNetwork} from './OnyxProvider'; import Text from './Text'; -import withLocalize from './withLocalize'; -import withWindowDimensions from './withWindowDimensions'; -import type {WindowDimensionsProps} from './withWindowDimensions/types'; -type OfflineIndicatorProps = LocaleContextProps & - WindowDimensionsProps & { - /** Information about the network */ - network: OnyxEntry; +type OfflineIndicatorProps = { + /** Optional styles for container element that will override the default styling for the offline indicator */ + containerStyles?: StyleProp; - /** Optional styles for container element that will override the default styling for the offline indicator */ - containerStyles?: StyleProp; - - /** Optional styles for the container */ - style?: StyleProp; - }; + /** Optional styles for the container */ + style?: StyleProp; +}; const setStyles = (containerStyles: StyleProp, isSmallScreenWidth: boolean): StyleProp => { if (containerStyles) { @@ -33,8 +25,12 @@ const setStyles = (containerStyles: StyleProp, isSmallScreenWidth: bo return isSmallScreenWidth ? styles.offlineIndicatorMobile : styles.offlineIndicator; }; -function OfflineIndicator({network, isSmallScreenWidth, translate, style, containerStyles}: OfflineIndicatorProps) { - if (!network?.isOffline) { +function OfflineIndicator({style, containerStyles}: OfflineIndicatorProps) { + const {translate} = useLocalize(); + const {isOffline} = useNetwork(); + const {isSmallScreenWidth} = useWindowDimensions(); + + if (!isOffline) { return null; } @@ -52,5 +48,4 @@ function OfflineIndicator({network, isSmallScreenWidth, translate, style, contai OfflineIndicator.displayName = 'OfflineIndicator'; -// TODO: use `compose` function for HOCs composing once TypeScript issues are resolved. -export default withNetwork()(withLocalize(withWindowDimensions(OfflineIndicator))); +export default OfflineIndicator; From 34ecf9874d1d22cedb716c0f60936e56462a51aa Mon Sep 17 00:00:00 2001 From: dukenv0307 <129500732+dukenv0307@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:44:32 +0700 Subject: [PATCH 16/63] Update src/libs/actions/Policy.js Co-authored-by: Eugene Voloshchak --- src/libs/actions/Policy.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index b11df545fc64..de6afe5a3dd1 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1045,7 +1045,6 @@ function generateCustomUnitID() { } /** - * * @returns {Object} */ function buildOptimisticCustomUnits() { From 46c7ce22ba4568d9b07d6054d56d2f67decd1a2e Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 21 Nov 2023 17:50:30 +0100 Subject: [PATCH 17/63] create buildOptimisticPolicyRecentlyUsedTags --- src/libs/actions/Policy.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 4df510d44db7..e374b6727551 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -88,6 +88,13 @@ Onyx.connect({ callback: (val) => (allRecentlyUsedCategories = val), }); +let allRecentlyUsedTags = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS, + waitForCollectionCallback: true, + callback: (val) => (allRecentlyUsedTags = val), +}); + let networkStatus = {}; Onyx.connect({ key: ONYXKEYS.NETWORK, @@ -1458,6 +1465,21 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) { return lodashUnion([category], policyRecentlyUsedCategories); } +/** + * @param {String} policyID + * @param {String} tag + * @returns {Object} + */ +function buildOptimisticPolicyRecentlyUsedTags(policyID, tag) { + if (!policyID || !tag) { + return []; + } + + const policyRecentlyUsedTags = lodashGet(allRecentlyUsedTags, `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`, []); + + return lodashUnion([tag], policyRecentlyUsedTags); +} + export { removeMembers, addMembersToWorkspace, @@ -1489,5 +1511,6 @@ export { dismissAddedWithPrimaryLoginMessages, openDraftWorkspaceRequest, buildOptimisticPolicyRecentlyUsedCategories, + buildOptimisticPolicyRecentlyUsedTags, createDraftInitialWorkspace, }; From a8350b9fd7aaeeea002bc595b5e9f19f59d2b6b1 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 21 Nov 2023 17:50:49 +0100 Subject: [PATCH 18/63] prepare create split bill methods --- src/libs/actions/IOU.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 6347f45549c7..cc98a05127b7 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -909,11 +909,12 @@ function requestMoney( * @param {String} comment * @param {String} currency * @param {String} category + * @param {String} tag * @param {String} existingSplitChatReportID - the report ID where the split bill happens, could be a group chat or a workspace chat * * @return {Object} */ -function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID = '') { +function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, tag, existingSplitChatReportID = '') { const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID)); const existingSplitChatReport = @@ -941,6 +942,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco undefined, undefined, category, + tag, ); // Note: The created action must be optimistically generated before the IOU action so there's no chance that the created action appears after the IOU action in the chat @@ -1131,6 +1133,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco undefined, undefined, category, + tag, ); // STEP 4: Build optimistic reportActions. We need: @@ -1184,6 +1187,13 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category); } + // Add tag to optimistic policy recently used tags when a participant is a workspace + let optimisticPolicyRecentlyUsedTags = []; + if (isPolicyExpenseChat) { + // TODO: Implement + optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, category); + } + // STEP 5: Build Onyx Data const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( oneOnOneChatReport, @@ -1195,7 +1205,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco oneOnOnePersonalDetailListAction, oneOnOneReportPreviewAction, optimisticPolicyRecentlyUsedCategories, - {}, + optimisticPolicyRecentlyUsedTags, isNewOneOnOneChatReport, shouldCreateNewOneOnOneIOUReport, ); @@ -1245,10 +1255,11 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco * @param {String} comment * @param {String} currency * @param {String} category + * @param {String} tag * @param {String} existingSplitChatReportID - Either a group DM or a workspace chat */ -function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID = '') { - const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID); +function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, tag, existingSplitChatReportID = '') { + const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, tag, existingSplitChatReportID); API.write( 'SplitBill', { @@ -1258,6 +1269,7 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount, currency, comment, category, + tag, transactionID: splitData.transactionID, reportActionID: splitData.reportActionID, createdReportActionID: splitData.createdReportActionID, @@ -1279,9 +1291,10 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount, * @param {String} comment * @param {String} currency * @param {String} category + * @param {String} tag */ -function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category) { - const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category); +function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, tag) { + const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, tag); API.write( 'SplitBillAndOpenReport', @@ -1292,6 +1305,7 @@ function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccou currency, comment, category, + tag, transactionID: splitData.transactionID, reportActionID: splitData.reportActionID, createdReportActionID: splitData.createdReportActionID, From 13bad5bfb1515a6ae663629f7a05480350e4d1a1 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 21 Nov 2023 17:51:10 +0100 Subject: [PATCH 19/63] add tags within components --- src/components/MoneyRequestConfirmationList.js | 2 +- src/pages/iou/SplitBillDetailsPage.js | 2 ++ src/pages/iou/steps/MoneyRequestConfirmPage.js | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 6cf1b7e6cef1..d0ce641a1a8c 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -240,7 +240,7 @@ function MoneyRequestConfirmationList(props) { const policyTagList = lodashGet(policyTag, 'tags', {}); const policyTagListName = lodashGet(policyTag, 'name', translate('common.tag')); // A flag for showing the tags field - const shouldShowTags = props.isPolicyExpenseChat && OptionsListUtils.hasEnabledOptions(_.values(policyTagList)); + const shouldShowTags = props.isPolicyExpenseChat && (props.iouTag || OptionsListUtils.hasEnabledOptions(_.values(policyTagList))); // A flag for showing the billable field const shouldShowBillable = !lodashGet(props.policy, 'disabledFields.defaultBillable', true); diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 2ebe96d60ed8..b582ae2b1396 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -101,6 +101,7 @@ function SplitBillDetailsPage(props) { merchant: splitMerchant, created: splitCreated, category: splitCategory, + tag: splitTag, } = isEditingSplitBill && props.draftTransaction ? ReportUtils.getTransactionDetails(props.draftTransaction) : ReportUtils.getTransactionDetails(props.transaction); const onConfirm = useCallback( @@ -134,6 +135,7 @@ function SplitBillDetailsPage(props) { iouCreated={splitCreated} iouMerchant={splitMerchant} iouCategory={splitCategory} + iouTag={splitTag} iouType={CONST.IOU.TYPE.SPLIT} isReadOnly={!isEditingSplitBill} shouldShowSmartScanFields diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js index a69abeb94089..aae288155409 100644 --- a/src/pages/iou/steps/MoneyRequestConfirmPage.js +++ b/src/pages/iou/steps/MoneyRequestConfirmPage.js @@ -239,6 +239,7 @@ function MoneyRequestConfirmPage(props) { trimmedComment, props.iou.currency, props.iou.category, + props.iou.tag, reportID, ); return; @@ -254,6 +255,7 @@ function MoneyRequestConfirmPage(props) { trimmedComment, props.iou.currency, props.iou.category, + props.iou.tag, ); return; } @@ -277,6 +279,7 @@ function MoneyRequestConfirmPage(props) { props.currentUserPersonalDetails.accountID, props.iou.currency, props.iou.category, + props.iou.tag, props.iou.receiptPath, props.iou.receiptFilename, isDistanceRequest, From 77fceacf7d38f4767626b8466fb8e41093d2405b Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 22 Nov 2023 02:15:07 +0530 Subject: [PATCH 20/63] Duplicate room name error when room created --- src/libs/actions/Report.js | 45 +++++++++---------- src/pages/workspace/WorkspaceNewRoomPage.js | 49 ++++++++++++++++++++- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index ac45a1e3f3be..a95c41bdab76 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1550,26 +1550,7 @@ function navigateToConciergeChat(ignoreConciergeReportID = false) { * @param {String} writeCapability * @param {String} welcomeMessage */ -function addPolicyReport(policyID, reportName, visibility, writeCapability = CONST.REPORT.WRITE_CAPABILITIES.ALL, welcomeMessage = '') { - const participants = [currentUserAccountID]; - const parsedWelcomeMessage = ReportUtils.getParsedComment(welcomeMessage); - const policyReport = ReportUtils.buildOptimisticChatReport( - participants, - reportName, - CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - policyID, - CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, - false, - '', - visibility, - writeCapability, - - // The room might contain all policy members so notifying always should be opt-in only. - CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY, - '', - '', - parsedWelcomeMessage, - ); +function addPolicyReport(policyReport) { const createdReportAction = ReportUtils.buildOptimisticCreatedReportAction(CONST.POLICY.OWNER_EMAIL_FAKE); // Onyx.set is used on the optimistic data so that it is present before navigating to the workspace room. With Onyx.merge the workspace room reportID is not present when @@ -1591,6 +1572,11 @@ function addPolicyReport(policyID, reportName, visibility, writeCapability = CON key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${policyReport.reportID}`, value: {[createdReportAction.reportActionID]: createdReportAction}, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.NEW_ROOM_FORM, + value: {isLoading: true}, + }, ]; const successData = [ { @@ -1611,6 +1597,11 @@ function addPolicyReport(policyID, reportName, visibility, writeCapability = CON }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.NEW_ROOM_FORM, + value: {isLoading: false}, + }, ]; const failureData = [ { @@ -1622,22 +1613,26 @@ function addPolicyReport(policyID, reportName, visibility, writeCapability = CON }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.NEW_ROOM_FORM, + value: {isLoading: false}, + }, ]; API.write( 'AddWorkspaceRoom', { policyID: policyReport.policyID, - reportName, - visibility, + reportName: policyReport.reportName, + visibility: policyReport.visibility, reportID: policyReport.reportID, createdReportActionID: createdReportAction.reportActionID, - writeCapability, - welcomeMessage: parsedWelcomeMessage, + writeCapability: policyReport.writeCapability, + welcomeMessage: policyReport.welcomeMessage, }, {optimisticData, successData, failureData}, ); - Navigation.dismissModal(policyReport.reportID); } /** diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index df78539bf665..6bac70202657 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -27,8 +27,10 @@ import useThemeStyles from '@styles/useThemeStyles'; import variables from '@styles/variables'; import * as App from '@userActions/App'; import * as Report from '@userActions/Report'; +import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import usePrevious from '@hooks/usePrevious'; const propTypes = { /** All reports shared with the user */ @@ -69,6 +71,13 @@ const defaultProps = { policies: {}, }; +function clearNewRoomFormError() { + Onyx.set(ONYXKEYS.FORMS.NEW_ROOM_FORM, { + isLoading: false, + errorFields: {}, + }); +} + function WorkspaceNewRoomPage(props) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -77,6 +86,7 @@ function WorkspaceNewRoomPage(props) { const [visibility, setVisibility] = useState(CONST.REPORT.VISIBILITY.RESTRICTED); const [policyID, setPolicyID] = useState(null); const [writeCapability, setWriteCapability] = useState(CONST.REPORT.WRITE_CAPABILITIES.ALL); + const wasLoading = usePrevious(props.formData.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const isPolicyAdmin = useMemo(() => { if (!policyID) { @@ -85,14 +95,45 @@ function WorkspaceNewRoomPage(props) { return ReportUtils.isPolicyAdmin(policyID, props.policies); }, [policyID, props.policies]); + const [newRoomReportID, setNewRoomReportID] = useState(undefined); /** * @param {Object} values - form input values passed by the Form component */ const submit = (values) => { - Report.addPolicyReport(policyID, values.roomName, visibility, writeCapability, values.welcomeMessage); + const participants = [props.session.accountID]; + const parsedWelcomeMessage = ReportUtils.getParsedComment(values.welcomeMessage); + const policyReport = ReportUtils.buildOptimisticChatReport( + participants, + values.roomName, + CONST.REPORT.CHAT_TYPE.POLICY_ROOM, + policyID, + CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, + false, + '', + visibility, + writeCapability || CONST.REPORT.WRITE_CAPABILITIES.ALL, + + // The room might contain all policy members so notifying always should be opt-in only. + CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY, + '', + '', + parsedWelcomeMessage, + ); + setNewRoomReportID(policyReport.reportID); + Report.addPolicyReport(policyReport); }; + useEffect(() => { + return clearNewRoomFormError; + }, []); + + useEffect(() => { + if (((wasLoading && !props.formData.isLoading) || (isOffline && props.formData.isLoading)) && _.isEmpty(props.formData.errorFields)) { + Navigation.dismissModal(newRoomReportID); + } + }, [props.formData]); + useEffect(() => { if (isPolicyAdmin) { return; @@ -265,5 +306,11 @@ export default compose( reports: { key: ONYXKEYS.COLLECTION.REPORT, }, + formData: { + key: ONYXKEYS.FORMS.NEW_ROOM_FORM + }, + session: { + key: ONYXKEYS.SESSION, + } }), )(WorkspaceNewRoomPage); From b91ca76ea8c653855d572b9ddfef3e638d151b27 Mon Sep 17 00:00:00 2001 From: someone-here Date: Wed, 22 Nov 2023 02:56:01 +0530 Subject: [PATCH 21/63] Fix lint --- src/libs/actions/Report.js | 14 ++++-- src/pages/workspace/WorkspaceNewRoomPage.js | 51 ++++++++++++++------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index a95c41bdab76..8267f1518797 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1544,11 +1544,7 @@ function navigateToConciergeChat(ignoreConciergeReportID = false) { /** * Add a policy report (workspace room) optimistically and navigate to it. * - * @param {String} policyID - * @param {String} reportName - * @param {String} visibility - * @param {String} writeCapability - * @param {String} welcomeMessage + * @param {Object} policyReport */ function addPolicyReport(policyReport) { const createdReportAction = ReportUtils.buildOptimisticCreatedReportAction(CONST.POLICY.OWNER_EMAIL_FAKE); @@ -2501,6 +2497,13 @@ function searchInServer(searchInput) { debouncedSearchInServer(searchInput); } +function clearNewRoomFormError() { + Onyx.set(ONYXKEYS.FORMS.NEW_ROOM_FORM, { + isLoading: false, + errorFields: {}, + }); +} + export { searchInServer, addComment, @@ -2562,4 +2565,5 @@ export { openRoomMembersPage, savePrivateNotesDraft, getDraftPrivateNote, + clearNewRoomFormError, }; diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 6bac70202657..6f30942cf825 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -16,9 +16,11 @@ import withNavigationFocus from '@components/withNavigationFocus'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import usePrevious from '@hooks/usePrevious'; import useWindowDimensions from '@hooks/useWindowDimensions'; import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; +import Navigation from '@libs/Navigation/Navigation'; import Permissions from '@libs/Permissions'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -27,10 +29,8 @@ import useThemeStyles from '@styles/useThemeStyles'; import variables from '@styles/variables'; import * as App from '@userActions/App'; import * as Report from '@userActions/Report'; -import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import usePrevious from '@hooks/usePrevious'; const propTypes = { /** All reports shared with the user */ @@ -64,19 +64,34 @@ const propTypes = { /** Whether navigation is focused */ isFocused: PropTypes.bool.isRequired, + + /** Form state for NEW_ROOM_FORM */ + formState: PropTypes.shape({ + /** Loading state for the form */ + isLoading: PropTypes.bool, + + /** Field errors in the form */ + errorFields: PropTypes.objectOf(PropTypes.objectOf(PropTypes.string)), + }), + + /** Session details for the user */ + session: PropTypes.shape({ + /** accountID of current user */ + accountID: PropTypes.number, + }), }; const defaultProps = { betas: [], reports: {}, policies: {}, -}; - -function clearNewRoomFormError() { - Onyx.set(ONYXKEYS.FORMS.NEW_ROOM_FORM, { + formState: { isLoading: false, errorFields: {}, - }); -} + }, + session: { + accountID: 0, + }, +}; function WorkspaceNewRoomPage(props) { const styles = useThemeStyles(); @@ -86,7 +101,7 @@ function WorkspaceNewRoomPage(props) { const [visibility, setVisibility] = useState(CONST.REPORT.VISIBILITY.RESTRICTED); const [policyID, setPolicyID] = useState(null); const [writeCapability, setWriteCapability] = useState(CONST.REPORT.WRITE_CAPABILITIES.ALL); - const wasLoading = usePrevious(props.formData.isLoading); + const wasLoading = usePrevious(props.formState.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const isPolicyAdmin = useMemo(() => { if (!policyID) { @@ -113,7 +128,7 @@ function WorkspaceNewRoomPage(props) { '', visibility, writeCapability || CONST.REPORT.WRITE_CAPABILITIES.ALL, - + // The room might contain all policy members so notifying always should be opt-in only. CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY, '', @@ -125,14 +140,16 @@ function WorkspaceNewRoomPage(props) { }; useEffect(() => { - return clearNewRoomFormError; + Report.clearNewRoomFormError(); }, []); useEffect(() => { - if (((wasLoading && !props.formData.isLoading) || (isOffline && props.formData.isLoading)) && _.isEmpty(props.formData.errorFields)) { - Navigation.dismissModal(newRoomReportID); + if (!(((wasLoading && !props.formState.isLoading) || (isOffline && props.formState.isLoading)) && _.isEmpty(props.formState.errorFields))) { + return; } - }, [props.formData]); + Navigation.dismissModal(newRoomReportID); + // eslint-disable-next-line react-hooks/exhaustive-deps -- we just want this to update on changing the form State + }, [props.formState]); useEffect(() => { if (isPolicyAdmin) { @@ -306,11 +323,11 @@ export default compose( reports: { key: ONYXKEYS.COLLECTION.REPORT, }, - formData: { - key: ONYXKEYS.FORMS.NEW_ROOM_FORM + formState: { + key: ONYXKEYS.FORMS.NEW_ROOM_FORM, }, session: { key: ONYXKEYS.SESSION, - } + }, }), )(WorkspaceNewRoomPage); From 32a043b738828e54cd7e8c96fe5d907449bed2e1 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 22 Nov 2023 14:26:45 +0700 Subject: [PATCH 22/63] hide create menu when opening concierge chat by deeplink --- .../sidebar/SidebarScreen/FloatingActionButtonAndPopover.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 739f7e3e0295..7116075b17e7 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -130,11 +130,11 @@ function FloatingActionButtonAndPopover(props) { */ const hideCreateMenu = useCallback( () => { + setIsCreateMenuActive(false); if (!isCreateMenuActive) { return; } props.onHideCreateMenu(); - setIsCreateMenuActive(false); }, // eslint-disable-next-line react-hooks/exhaustive-deps [isCreateMenuActive], @@ -187,7 +187,7 @@ function FloatingActionButtonAndPopover(props) { Date: Wed, 22 Nov 2023 15:53:43 +0100 Subject: [PATCH 23/63] handle expense chat by one more property --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index db836549234d..fa214c6403b3 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -394,7 +394,7 @@ function isUserCreatedPolicyRoom(report) { * @returns {Boolean} */ function isPolicyExpenseChat(report) { - return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || report.isPolicyExpenseChat; } /** Wether the provided report belongs to a Control policy and is an epxense chat From 8c5f20b4df58cbc8b17826e899a07cd5ef2ae2a5 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 22 Nov 2023 15:57:47 +0100 Subject: [PATCH 24/63] implement buildOptimisticPolicyRecentlyUsedTags properly --- src/libs/actions/Policy.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index e374b6727551..f645d8dfc053 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1475,9 +1475,14 @@ function buildOptimisticPolicyRecentlyUsedTags(policyID, tag) { return []; } - const policyRecentlyUsedTags = lodashGet(allRecentlyUsedTags, `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`, []); + const policyRecentlyUsedTags = lodashGet(allRecentlyUsedTags, `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`, {}); + // For now it only uses the first tag of the policy, since multi-tags are not yet supported + const tagListKey = _.first(_.keys(policyRecentlyUsedTags)); - return lodashUnion([tag], policyRecentlyUsedTags); + return { + ...policyRecentlyUsedTags, + [tagListKey]: lodashUnion([tag], lodashGet(policyRecentlyUsedTags, [tagListKey], [])), + }; } export { From e8cc3ae102c61c9addbbb8d9cd42b8ae60f2ba36 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 22 Nov 2023 15:58:13 +0100 Subject: [PATCH 25/63] integrate buildOptimisticPolicyRecentlyUsedTags --- src/libs/actions/IOU.js | 56 ++++++----------------------------------- 1 file changed, 7 insertions(+), 49 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 833f1a28982c..4d5335ac8b31 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -63,34 +63,6 @@ Onyx.connect({ }, }); -let allRecentlyUsedTags = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - allRecentlyUsedTags = {}; - return; - } - - allRecentlyUsedTags = value; - }, -}); - -let allPolicyTags = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_TAGS, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - allPolicyTags = {}; - return; - } - - allPolicyTags = value; - }, -}); - let userAccountID = ''; let currentUserEmail = ''; Onyx.connect({ @@ -516,15 +488,9 @@ function getMoneyRequestInformation( optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); } - const optimisticPolicyRecentlyUsedTags = {}; - const policyTags = allPolicyTags[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${iouReport.policyID}`]; - const recentlyUsedPolicyTags = allRecentlyUsedTags[`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`]; - - if (policyTags) { - // For now it only uses the first tag of the policy, since multi-tags are not yet supported - const tagListKey = _.first(_.keys(policyTags)); - const uniquePolicyRecentlyUsedTags = recentlyUsedPolicyTags ? _.filter(recentlyUsedPolicyTags[tagListKey], (recentlyUsedPolicyTag) => recentlyUsedPolicyTag !== tag) : []; - optimisticPolicyRecentlyUsedTags[tagListKey] = [tag, ...uniquePolicyRecentlyUsedTags]; + let optimisticPolicyRecentlyUsedTags = {}; + if (tag) { + optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); } // If there is an existing transaction (which is the case for distance requests), then the data from the existing transaction @@ -1200,10 +1166,9 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco } // Add tag to optimistic policy recently used tags when a participant is a workspace - let optimisticPolicyRecentlyUsedTags = []; + let optimisticPolicyRecentlyUsedTags = {}; if (isPolicyExpenseChat) { - // TODO: Implement - optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, category); + optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag); } // STEP 5: Build Onyx Data @@ -1307,7 +1272,6 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount, */ function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, tag) { const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, tag); - API.write( 'SplitBillAndOpenReport', { @@ -1847,15 +1811,9 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans updatedChatReport.lastMessageHtml = messageText; } - const optimisticPolicyRecentlyUsedTags = {}; + let optimisticPolicyRecentlyUsedTags = {}; if (_.has(transactionChanges, 'tag')) { - const tagListName = transactionChanges.tagListName; - const recentlyUsedPolicyTags = allRecentlyUsedTags[`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`]; - - const uniquePolicyRecentlyUsedTags = recentlyUsedPolicyTags - ? _.filter(recentlyUsedPolicyTags[tagListName], (recentlyUsedPolicyTag) => recentlyUsedPolicyTag !== transactionChanges.tag) - : []; - optimisticPolicyRecentlyUsedTags[tagListName] = [transactionChanges.tag, ...uniquePolicyRecentlyUsedTags]; + optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, transactionChanges.tag); } const isScanning = TransactionUtils.hasReceipt(updatedTransaction) && TransactionUtils.isReceiptBeingScanned(updatedTransaction); From d55f2ef886b0360b6c67ae5da6c1778c832f0190 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 22 Nov 2023 16:03:42 +0100 Subject: [PATCH 26/63] check isPolicyExpenseChat safely --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index fa214c6403b3..675349712f6a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -394,7 +394,7 @@ function isUserCreatedPolicyRoom(report) { * @returns {Boolean} */ function isPolicyExpenseChat(report) { - return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || report.isPolicyExpenseChat; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || lodashGet(report, 'isPolicyExpenseChat', false); } /** Wether the provided report belongs to a Control policy and is an epxense chat From ec204b54e30a92413a406f438a3f878999b81cc7 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 22 Nov 2023 16:34:27 +0100 Subject: [PATCH 27/63] fix taking tag list name --- src/libs/actions/Policy.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index f645d8dfc053..d37b208be16f 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -88,6 +88,20 @@ Onyx.connect({ callback: (val) => (allRecentlyUsedCategories = val), }); +let allPolicyTags = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY_TAGS, + waitForCollectionCallback: true, + callback: (value) => { + if (!value) { + allPolicyTags = {}; + return; + } + + allPolicyTags = value; + }, +}); + let allRecentlyUsedTags = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS, @@ -1475,9 +1489,10 @@ function buildOptimisticPolicyRecentlyUsedTags(policyID, tag) { return []; } - const policyRecentlyUsedTags = lodashGet(allRecentlyUsedTags, `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`, {}); + const policyTags = lodashGet(allPolicyTags, `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {}); // For now it only uses the first tag of the policy, since multi-tags are not yet supported - const tagListKey = _.first(_.keys(policyRecentlyUsedTags)); + const tagListKey = _.first(_.keys(policyTags)); + const policyRecentlyUsedTags = lodashGet(allRecentlyUsedTags, `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`, {}); return { ...policyRecentlyUsedTags, 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 28/63] 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 29/63] 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 30/63] 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 31/63] 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 32/63] 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 33/63] 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 10:45:55 +0700 Subject: [PATCH 34/63] add name value --- src/pages/iou/WaypointEditor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/WaypointEditor.js b/src/pages/iou/WaypointEditor.js index ecc56fbae80f..241d7d269537 100644 --- a/src/pages/iou/WaypointEditor.js +++ b/src/pages/iou/WaypointEditor.js @@ -144,6 +144,7 @@ function WaypointEditor({route: {params: {iouType = '', transactionID = '', wayp lat: null, lng: null, address: waypointValue, + name: waypointValue }; saveWaypoint(waypoint); } @@ -163,7 +164,7 @@ function WaypointEditor({route: {params: {iouType = '', transactionID = '', wayp lat: values.lat, lng: values.lng, address: values.address, - name: values.name, + name: values.name || null, }; saveWaypoint(waypoint); From 609ca3db629a88613a3b06989e7077ffbe61b525 Mon Sep 17 00:00:00 2001 From: Dylan Date: Mon, 27 Nov 2023 11:04:46 +0700 Subject: [PATCH 35/63] fix lint --- src/pages/iou/WaypointEditor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/WaypointEditor.js b/src/pages/iou/WaypointEditor.js index 241d7d269537..4be3ef005a24 100644 --- a/src/pages/iou/WaypointEditor.js +++ b/src/pages/iou/WaypointEditor.js @@ -144,7 +144,7 @@ function WaypointEditor({route: {params: {iouType = '', transactionID = '', wayp lat: null, lng: null, address: waypointValue, - name: waypointValue + name: waypointValue, }; saveWaypoint(waypoint); } From 3182e9bfc5dc5bf1ddd0f93fe235d21a96c06160 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 27 Nov 2023 15:31:29 +0100 Subject: [PATCH 36/63] simplify optimistic tag syntax --- src/libs/actions/IOU.js | 15 +++------------ src/libs/actions/Policy.js | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 4d5335ac8b31..4212199c5620 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -488,10 +488,7 @@ function getMoneyRequestInformation( optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); } - let optimisticPolicyRecentlyUsedTags = {}; - if (tag) { - optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); - } + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); // If there is an existing transaction (which is the case for distance requests), then the data from the existing transaction // needs to be manually merged into the optimistic transaction. This is because buildOnyxDataForMoneyRequest() uses `Onyx.set()` for the transaction @@ -1166,10 +1163,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco } // Add tag to optimistic policy recently used tags when a participant is a workspace - let optimisticPolicyRecentlyUsedTags = {}; - if (isPolicyExpenseChat) { - optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag); - } + const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {}; // STEP 5: Build Onyx Data const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( @@ -1811,10 +1805,7 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans updatedChatReport.lastMessageHtml = messageText; } - let optimisticPolicyRecentlyUsedTags = {}; - if (_.has(transactionChanges, 'tag')) { - optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, transactionChanges.tag); - } + const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, transactionChanges.tag); const isScanning = TransactionUtils.hasReceipt(updatedTransaction) && TransactionUtils.isReceiptBeingScanned(updatedTransaction); diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 69035804bee7..7268f5690ecc 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1491,7 +1491,7 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) { */ function buildOptimisticPolicyRecentlyUsedTags(policyID, tag) { if (!policyID || !tag) { - return []; + return {}; } const policyTags = lodashGet(allPolicyTags, `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {}); From 26b7ba9db255bb25d902cc8c61624d4180d930ab Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 27 Nov 2023 15:34:08 +0100 Subject: [PATCH 37/63] simplify optimistic category syntax --- src/libs/actions/IOU.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 4212199c5620..79cf4cc57381 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -483,10 +483,7 @@ function getMoneyRequestInformation( billable, ); - let optimisticPolicyRecentlyUsedCategories = []; - if (category) { - optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); - } + const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, tag); @@ -1157,10 +1154,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco } // Add category to optimistic policy recently used categories when a participant is a workspace - let optimisticPolicyRecentlyUsedCategories = []; - if (isPolicyExpenseChat) { - optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category); - } + const optimisticPolicyRecentlyUsedCategories = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category) : []; // Add tag to optimistic policy recently used tags when a participant is a workspace const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {}; From 5283111f989062e22e450cf0a92b7766938a058a Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 27 Nov 2023 17:20:51 +0100 Subject: [PATCH 38/63] 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 af4fe4d398bf5df1b64084bbc86435b1d894cb8f Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 28 Nov 2023 20:54:01 +0800 Subject: [PATCH 39/63] 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 40/63] 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: Wed, 29 Nov 2023 13:02:15 +0700 Subject: [PATCH 41/63] add dependency --- src/pages/home/ReportScreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index c3369471ec52..e62cda016710 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -338,7 +338,7 @@ function ReportScreen({ fetchReportIfNeeded(); ComposerActions.setShouldShowComposeInput(true); - }, [route, report, errors, fetchReportIfNeeded, prevReport.reportID, prevUserLeavingStatus, userLeavingStatus, prevReport.statusNum, prevReport.parentReportID]); + }, [route, report, errors, fetchReportIfNeeded, prevReport.reportID, prevUserLeavingStatus, userLeavingStatus, prevReport.statusNum, prevReport.parentReportID, prevReport.chatType]); useEffect(() => { if (!ReportUtils.isValidReportIDFromPath(reportID)) { From 616a4be46818667c50dba43b1454314f794f1490 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 29 Nov 2023 15:18:13 +0700 Subject: [PATCH 42/63] show create menu when going back --- .../sidebar/SidebarScreen/FloatingActionButtonAndPopover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index d9c17819537a..21e712c418e6 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -125,10 +125,10 @@ function FloatingActionButtonAndPopover(props) { */ const hideCreateMenu = useCallback( () => { - setIsCreateMenuActive(false); if (!isCreateMenuActive) { return; } + setIsCreateMenuActive(false); props.onHideCreateMenu(); }, // eslint-disable-next-line react-hooks/exhaustive-deps From d582dafa83a10b3b7f28d19f0b609e43131ce17a Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Wed, 29 Nov 2023 13:38:37 +0100 Subject: [PATCH 43/63] Updates after merging main --- src/components/OfflineIndicator.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/components/OfflineIndicator.tsx b/src/components/OfflineIndicator.tsx index ba0cf1860915..b402caa2c750 100644 --- a/src/components/OfflineIndicator.tsx +++ b/src/components/OfflineIndicator.tsx @@ -1,9 +1,9 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import {StyleProp, View, ViewStyle} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import styles from '@styles/styles'; +import useThemeStyles from '@styles/useThemeStyles'; import variables from '@styles/variables'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; @@ -17,25 +17,26 @@ type OfflineIndicatorProps = { style?: StyleProp; }; -const setStyles = (containerStyles: StyleProp, isSmallScreenWidth: boolean): StyleProp => { - if (containerStyles) { - return containerStyles; - } - - return isSmallScreenWidth ? styles.offlineIndicatorMobile : styles.offlineIndicator; -}; - function OfflineIndicator({style, containerStyles}: OfflineIndicatorProps) { + const styles = useThemeStyles(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); const {isSmallScreenWidth} = useWindowDimensions(); + const computedStyles = useMemo((): StyleProp => { + if (containerStyles) { + return containerStyles; + } + + return isSmallScreenWidth ? styles.offlineIndicatorMobile : styles.offlineIndicator; + }, [containerStyles, isSmallScreenWidth, styles.offlineIndicatorMobile, styles.offlineIndicator]); + if (!isOffline) { return null; } return ( - + Date: Fri, 1 Dec 2023 03:39:23 +0800 Subject: [PATCH 44/63] 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 dea9ed463c2b400377eff6f2da3c17d84e617dc8 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 30 Nov 2023 14:02:47 -0700 Subject: [PATCH 45/63] Remove side-loading of parent report action --- src/components/AvatarWithDisplayName.js | 92 ++++++++++++++++--------- 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index de6d6b8ef6e2..bb8bb79c09d1 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -1,18 +1,21 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React from 'react'; +import React, {useCallback, useRef, useEffect} from 'react'; import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import reportPropTypes from '@pages/reportPropTypes'; import * as StyleUtils from '@styles/StyleUtils'; +import reportPropTypes from '@pages/reportPropTypes'; +import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; import useTheme from '@styles/themes/useTheme'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import DisplayNames from './DisplayNames'; import MultipleAvatars from './MultipleAvatars'; @@ -45,6 +48,10 @@ const propTypes = { shouldEnableDetailPageNavigation: PropTypes.bool, + /* Onyx Props */ + /** All of the actions of the report */ + parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + ...windowDimensionsPropTypes, ...withLocalizePropTypes, }; @@ -53,41 +60,12 @@ const defaultProps = { personalDetails: {}, policy: {}, report: {}, + parentReportActions: {}, isAnonymous: false, size: CONST.AVATAR_SIZE.DEFAULT, shouldEnableDetailPageNavigation: false, }; -const showActorDetails = (report, shouldEnableDetailPageNavigation = false) => { - // We should navigate to the details page if the report is a IOU/expense report - if (shouldEnableDetailPageNavigation) { - return ReportUtils.navigateToDetailsPage(report); - } - - if (ReportUtils.isExpenseReport(report)) { - Navigation.navigate(ROUTES.PROFILE.getRoute(report.ownerAccountID)); - return; - } - - if (ReportUtils.isIOUReport(report)) { - Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(report.reportID)); - return; - } - - if (ReportUtils.isChatThread(report)) { - const parentReportAction = ReportActionsUtils.getParentReportAction(report); - const actorAccountID = lodashGet(parentReportAction, 'actorAccountID', -1); - // in an ideal situation account ID won't be 0 - if (actorAccountID > 0) { - Navigation.navigate(ROUTES.PROFILE.getRoute(actorAccountID)); - return; - } - } - - // report detail route is added as fallback but based on the current implementation this route won't be executed - Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); -}; - function AvatarWithDisplayName(props) { const theme = useTheme(); const styles = useThemeStyles(); @@ -102,13 +80,47 @@ function AvatarWithDisplayName(props) { const isExpenseRequest = ReportUtils.isExpenseRequest(props.report); const defaultSubscriptSize = isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : props.size; const avatarBorderColor = props.isAnonymous ? theme.highlightBG : theme.componentBG; + const actorAccountID = useRef(null); + + useEffect(() => { + const parentReportAction = lodashGet(props.parentReportActions, [props.report.parentReportActionID], {}); + actorAccountID.current = lodashGet(parentReportAction, 'actorAccountID', -1); + }, [props]); + + const showActorDetails = useCallback(() => { + // We should navigate to the details page if the report is a IOU/expense report + if (props.shouldEnableDetailPageNavigation) { + return ReportUtils.navigateToDetailsPage(props.report); + } + + if (ReportUtils.isExpenseReport(props.report)) { + Navigation.navigate(ROUTES.PROFILE.getRoute(props.report.ownerAccountID)); + return; + } + + if (ReportUtils.isIOUReport(props.report)) { + Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID)); + return; + } + + if (ReportUtils.isChatThread(props.report)) { + // In an ideal situation account ID won't be 0 + if (actorAccountID.current > 0) { + Navigation.navigate(ROUTES.PROFILE.getRoute(actorAccountID.current)); + return; + } + } + + // Report detail route is added as fallback but based on the current implementation this route won't be executed + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); + }, [props]); const headerView = ( {Boolean(props.report && title) && ( showActorDetails(props.report, props.shouldEnableDetailPageNavigation)} + onPress={showActorDetails} accessibilityLabel={title} role={CONST.ACCESSIBILITY_ROLE.BUTTON} > @@ -175,4 +187,16 @@ AvatarWithDisplayName.propTypes = propTypes; AvatarWithDisplayName.displayName = 'AvatarWithDisplayName'; AvatarWithDisplayName.defaultProps = defaultProps; -export default compose(withWindowDimensions, withLocalize)(AvatarWithDisplayName); +export default compose( + withWindowDimensions, + withLocalize, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + parentReportActions: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, + canEvict: false, + }, + }), +)(AvatarWithDisplayName); From a1562004b31ced6633296cd93c998def494b2b3f Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 30 Nov 2023 14:10:11 -0700 Subject: [PATCH 46/63] Destructure props and remove unused props --- src/components/AvatarWithDisplayName.js | 83 ++++++++++++------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index bb8bb79c09d1..baa546e5b6a2 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -4,10 +4,8 @@ import React, {useCallback, useRef, useEffect} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as StyleUtils from '@styles/StyleUtils'; import reportPropTypes from '@pages/reportPropTypes'; @@ -24,8 +22,6 @@ import participantPropTypes from './participantPropTypes'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import SubscriptAvatar from './SubscriptAvatar'; import Text from './Text'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; -import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; const propTypes = { /** The report currently being looked at */ @@ -51,9 +47,6 @@ const propTypes = { /* Onyx Props */ /** All of the actions of the report */ parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), - - ...windowDimensionsPropTypes, - ...withLocalizePropTypes, }; const defaultProps = { @@ -66,44 +59,52 @@ const defaultProps = { shouldEnableDetailPageNavigation: false, }; -function AvatarWithDisplayName(props) { +function AvatarWithDisplayName({ + report, + policy, + size, + isAnonymous, + parentReportActions, + personalDetails, + shouldEnableDetailPageNavigation, +}) { const theme = useTheme(); const styles = useThemeStyles(); - const title = ReportUtils.getReportName(props.report); - const subtitle = ReportUtils.getChatRoomSubtitle(props.report); - const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(props.report); - const isMoneyRequestOrReport = ReportUtils.isMoneyRequestReport(props.report) || ReportUtils.isMoneyRequest(props.report); - const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policy); - const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs([props.report.ownerAccountID], props.personalDetails); + const title = ReportUtils.getReportName(report); + const subtitle = ReportUtils.getChatRoomSubtitle(report); + const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(report); + const isMoneyRequestOrReport = ReportUtils.isMoneyRequestReport(report) || ReportUtils.isMoneyRequest(report); + const icons = ReportUtils.getIcons(report, personalDetails, policy); + const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs([report.ownerAccountID], personalDetails); const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(_.values(ownerPersonalDetails), false); - const shouldShowSubscriptAvatar = ReportUtils.shouldReportShowSubscript(props.report); - const isExpenseRequest = ReportUtils.isExpenseRequest(props.report); - const defaultSubscriptSize = isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : props.size; - const avatarBorderColor = props.isAnonymous ? theme.highlightBG : theme.componentBG; - const actorAccountID = useRef(null); + const shouldShowSubscriptAvatar = ReportUtils.shouldReportShowSubscript(report); + const isExpenseRequest = ReportUtils.isExpenseRequest(report); + const defaultSubscriptSize = isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : size; + const avatarBorderColor = isAnonymous ? theme.highlightBG : theme.componentBG; + const actorAccountID = useRef(null); useEffect(() => { - const parentReportAction = lodashGet(props.parentReportActions, [props.report.parentReportActionID], {}); + const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID], {}); actorAccountID.current = lodashGet(parentReportAction, 'actorAccountID', -1); - }, [props]); + }, [parentReportActions, report]); const showActorDetails = useCallback(() => { // We should navigate to the details page if the report is a IOU/expense report - if (props.shouldEnableDetailPageNavigation) { - return ReportUtils.navigateToDetailsPage(props.report); + if (shouldEnableDetailPageNavigation) { + return ReportUtils.navigateToDetailsPage(report); } - if (ReportUtils.isExpenseReport(props.report)) { - Navigation.navigate(ROUTES.PROFILE.getRoute(props.report.ownerAccountID)); + if (ReportUtils.isExpenseReport(report)) { + Navigation.navigate(ROUTES.PROFILE.getRoute(report.ownerAccountID)); return; } - if (ReportUtils.isIOUReport(props.report)) { - Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID)); + if (ReportUtils.isIOUReport(report)) { + Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(report.reportID)); return; } - if (ReportUtils.isChatThread(props.report)) { + if (ReportUtils.isChatThread(report)) { // In an ideal situation account ID won't be 0 if (actorAccountID.current > 0) { Navigation.navigate(ROUTES.PROFILE.getRoute(actorAccountID.current)); @@ -112,12 +113,12 @@ function AvatarWithDisplayName(props) { } // Report detail route is added as fallback but based on the current implementation this route won't be executed - Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID)); - }, [props]); + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)); + }, [report, shouldEnableDetailPageNavigation]); const headerView = ( - {Boolean(props.report && title) && ( + {Boolean(report && title) && ( )} @@ -145,13 +146,13 @@ function AvatarWithDisplayName(props) { displayNamesWithTooltips={displayNamesWithTooltips} tooltipEnabled numberOfLines={1} - textStyles={[props.isAnonymous ? styles.headerAnonymousFooter : styles.headerText, styles.pre]} - shouldUseFullTitle={isMoneyRequestOrReport || props.isAnonymous} + textStyles={[isAnonymous ? styles.headerAnonymousFooter : styles.headerText, styles.pre]} + shouldUseFullTitle={isMoneyRequestOrReport || isAnonymous} /> {!_.isEmpty(parentNavigationSubtitleData) && ( )} {!_.isEmpty(subtitle) && ( @@ -168,13 +169,13 @@ function AvatarWithDisplayName(props) { ); - if (!props.shouldEnableDetailPageNavigation) { + if (!shouldEnableDetailPageNavigation) { return headerView; } return ( ReportUtils.navigateToDetailsPage(props.report)} + onPress={() => ReportUtils.navigateToDetailsPage(report)} style={[styles.flexRow, styles.alignItemsCenter, styles.flex1]} accessibilityLabel={title} role={CONST.ACCESSIBILITY_ROLE.BUTTON} @@ -187,10 +188,7 @@ AvatarWithDisplayName.propTypes = propTypes; AvatarWithDisplayName.displayName = 'AvatarWithDisplayName'; AvatarWithDisplayName.defaultProps = defaultProps; -export default compose( - withWindowDimensions, - withLocalize, - withOnyx({ +export default withOnyx({ session: { key: ONYXKEYS.SESSION, }, @@ -198,5 +196,4 @@ export default compose( key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, canEvict: false, }, - }), -)(AvatarWithDisplayName); + })(AvatarWithDisplayName); From 7025f47116f8d7f651a292f6052a1b34380e4491 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 30 Nov 2023 14:46:31 -0700 Subject: [PATCH 47/63] Fix style --- src/components/AvatarWithDisplayName.js | 32 ++++++++++--------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index baa546e5b6a2..89d74a6ad3bb 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -1,15 +1,15 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {useCallback, useRef, useEffect} from 'react'; +import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import * as StyleUtils from '@styles/StyleUtils'; -import reportPropTypes from '@pages/reportPropTypes'; import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; +import reportPropTypes from '@pages/reportPropTypes'; +import * as StyleUtils from '@styles/StyleUtils'; import useTheme from '@styles/themes/useTheme'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; @@ -59,15 +59,7 @@ const defaultProps = { shouldEnableDetailPageNavigation: false, }; -function AvatarWithDisplayName({ - report, - policy, - size, - isAnonymous, - parentReportActions, - personalDetails, - shouldEnableDetailPageNavigation, -}) { +function AvatarWithDisplayName({report, policy, size, isAnonymous, parentReportActions, personalDetails, shouldEnableDetailPageNavigation}) { const theme = useTheme(); const styles = useThemeStyles(); const title = ReportUtils.getReportName(report); @@ -189,11 +181,11 @@ AvatarWithDisplayName.displayName = 'AvatarWithDisplayName'; AvatarWithDisplayName.defaultProps = defaultProps; export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - parentReportActions: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, - canEvict: false, - }, - })(AvatarWithDisplayName); + session: { + key: ONYXKEYS.SESSION, + }, + parentReportActions: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, + canEvict: false, + }, +})(AvatarWithDisplayName); From 2afc843b82620521f7049bd00fcd490bc574d895 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Thu, 30 Nov 2023 16:04:25 -0700 Subject: [PATCH 48/63] 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 87c6c7de3681dbe7499834a910378e55ea24f77b Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 30 Nov 2023 16:40:12 -0700 Subject: [PATCH 49/63] pass policyID in splitDetailsPage --- src/pages/iou/SplitBillDetailsPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index d1fe21d8cf4e..337c921e4210 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -144,6 +144,7 @@ function SplitBillDetailsPage(props) { transactionID={props.transaction.transactionID} onConfirm={onConfirm} isPolicyExpenseChat={ReportUtils.isPolicyExpenseChat(props.report)} + policyID={ReportUtils.isPolicyExpenseChat(props.report) && props.report.policyID} /> )} From 6b1c3a8d08f3b6323056dd4f2cbe0cea88d1d6c8 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 1 Dec 2023 10:28:05 +0700 Subject: [PATCH 50/63] 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 2783bbf691cdca50acecc89299d7f2dc3e3d14d1 Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 1 Dec 2023 10:42:53 +0700 Subject: [PATCH 51/63] update name to null when offline --- src/pages/iou/WaypointEditor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/WaypointEditor.js b/src/pages/iou/WaypointEditor.js index 4be3ef005a24..40c9f2f425a1 100644 --- a/src/pages/iou/WaypointEditor.js +++ b/src/pages/iou/WaypointEditor.js @@ -144,7 +144,7 @@ function WaypointEditor({route: {params: {iouType = '', transactionID = '', wayp lat: null, lng: null, address: waypointValue, - name: waypointValue, + name: null, }; saveWaypoint(waypoint); } From 0171212d57083cd01e3174c4e0d2c5adab29a2ff Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 1 Dec 2023 10:54:00 +0700 Subject: [PATCH 52/63] 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 6ff5bceb8cad20dee0386c345985a5249e203b49 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 1 Dec 2023 11:14:18 +0100 Subject: [PATCH 53/63] 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 54/63] 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 55/63] 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 56/63] 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 57/63] 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 58/63] 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 9070a4eb08231e538030a2e783883805546a3dd0 Mon Sep 17 00:00:00 2001 From: Adam Horodyski Date: Wed, 22 Nov 2023 14:47:54 +0100 Subject: [PATCH 59/63] chore: ensure stable references on renderItem for emoji and mention suggestions --- src/components/EmojiSuggestions.tsx | 51 +++++++------ src/components/MentionSuggestions.tsx | 105 +++++++++++++------------- 2 files changed, 81 insertions(+), 75 deletions(-) diff --git a/src/components/EmojiSuggestions.tsx b/src/components/EmojiSuggestions.tsx index 1f14a63462bd..f141624699ed 100644 --- a/src/components/EmojiSuggestions.tsx +++ b/src/components/EmojiSuggestions.tsx @@ -1,4 +1,4 @@ -import React, {ReactElement} from 'react'; +import React, {ReactElement, useCallback} from 'react'; import {View} from 'react-native'; import type {SimpleEmoji} from '@libs/EmojiTrie'; import * as EmojiUtils from '@libs/EmojiUtils'; @@ -48,30 +48,33 @@ function EmojiSuggestions({emojis, onSelect, prefix, isEmojiPickerLarge, preferr /** * Render an emoji suggestion menu item component. */ - const renderSuggestionMenuItem = (item: SimpleEmoji): ReactElement => { - const styledTextArray = getStyledTextArray(item.name, prefix); + const renderSuggestionMenuItem = useCallback( + (item: SimpleEmoji): ReactElement => { + const styledTextArray = getStyledTextArray(item.name, prefix); - return ( - - {EmojiUtils.getEmojiCodeWithSkinColor(item, preferredSkinToneIndex)} - - : - {styledTextArray.map(({text, isColored}) => ( - - {text} - - ))} - : - - - ); - }; + return ( + + {EmojiUtils.getEmojiCodeWithSkinColor(item, preferredSkinToneIndex)} + + : + {styledTextArray.map(({text, isColored}) => ( + + {text} + + ))} + : + + + ); + }, + [styles, theme, prefix, preferredSkinToneIndex], + ); return ( { - const isIcon = item.text === CONST.AUTO_COMPLETE_SUGGESTER.HERE_TEXT; - const styledDisplayName = getStyledTextArray(item.text, prefix); - const styledHandle = item.text === item.alternateText ? undefined : getStyledTextArray(item.alternateText, prefix); - - return ( - - - + const renderSuggestionMenuItem = useCallback( + (item: Mention) => { + const isIcon = item.text === CONST.AUTO_COMPLETE_SUGGESTER.HERE_TEXT; + const styledDisplayName = getStyledTextArray(item.text, prefix); + const styledHandle = item.text === item.alternateText ? undefined : getStyledTextArray(item.alternateText, prefix); + + return ( + + + + + + {styledDisplayName?.map(({text, isColored}, i) => ( + + {text} + + ))} + + + {styledHandle?.map( + ({text, isColored}, i) => + Boolean(text) && ( + + {text} + + ), + )} + - - {styledDisplayName?.map(({text, isColored}, i) => ( - - {text} - - ))} - - - {styledHandle?.map( - ({text, isColored}, i) => - Boolean(text) && ( - - {text} - - ), - )} - - - ); - }; + ); + }, + [styles, theme, prefix], + ); return ( Date: Fri, 1 Dec 2023 12:30:44 +0000 Subject: [PATCH 60/63] 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 61/63] 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 62/63] 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))} + /> From e056672266b7a09d782209987ec7e9be94e7ea8c Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Fri, 1 Dec 2023 10:41:17 -0700 Subject: [PATCH 63/63] Remove unused Onyx key --- src/components/AvatarWithDisplayName.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index 89d74a6ad3bb..9d7e6467e804 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -181,9 +181,6 @@ AvatarWithDisplayName.displayName = 'AvatarWithDisplayName'; AvatarWithDisplayName.defaultProps = defaultProps; export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, parentReportActions: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, canEvict: false,