From 88389839856eccf3c3225248a4bc3150a3cfb49b Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 23 Aug 2023 16:26:39 +0700 Subject: [PATCH 001/250] fix: wrong currency in request money pageafter login --- src/libs/actions/IOU.js | 10 ++++++++++ src/pages/iou/steps/NewRequestAmountPage.js | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index ee9afa8b0eb8..799dab521bf7 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -21,6 +21,7 @@ import * as ErrorUtils from '../ErrorUtils'; import * as UserUtils from '../UserUtils'; import * as Report from './Report'; import * as NumberUtils from '../NumberUtils'; +import * as SessionUtils from '../SessionUtils'; let allReports; Onyx.connect({ @@ -51,11 +52,20 @@ Onyx.connect({ }, }); +let shouldResetIOUAfterLogin = true; let currentUserPersonalDetails = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { currentUserPersonalDetails = lodashGet(val, userAccountID, {}); + if (val && SessionUtils.didUserLogInDuringSession() && shouldResetIOUAfterLogin) { + // eslint-disable-next-line no-use-before-define + resetMoneyRequestInfo(); + shouldResetIOUAfterLogin = false; + Onyx.merge(ONYXKEYS.IOU, { + didInitCurrency: true, + }); + } }, }); diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index e0199d72b01a..1c35c39bb4a8 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -20,6 +20,7 @@ import FullPageNotFoundView from '../../../components/BlockingViews/FullPageNotF import styles from '../../../styles/styles'; import HeaderWithBackButton from '../../../components/HeaderWithBackButton'; import ScreenWrapper from '../../../components/ScreenWrapper'; +import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator'; const propTypes = { route: PropTypes.shape({ @@ -172,6 +173,10 @@ function NewRequestAmountPage({route, iou, report}) { /> ); + if (!lodashGet(iou, 'didInitCurrency', false)) { + return ; + } + // ScreenWrapper is only needed in edit mode because we have a dedicated route for the edit amount page (MoneyRequestEditAmountPage). // The rest of the cases this component is rendered through which has it's own ScreenWrapper if (!isEditing) { From 52edc8d39b7df59f5f6d1a9cc3c319f37c6db033 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 29 Aug 2023 00:29:29 +0700 Subject: [PATCH 002/250] fix loader on already logged in --- src/libs/actions/IOU.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index e5cf474ab8bf..a74409dcdf00 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -21,7 +21,6 @@ import * as ErrorUtils from '../ErrorUtils'; import * as UserUtils from '../UserUtils'; import * as Report from './Report'; import * as NumberUtils from '../NumberUtils'; -import * as SessionUtils from '../SessionUtils'; let allReports; Onyx.connect({ @@ -52,20 +51,29 @@ Onyx.connect({ }, }); +let didInitCurrency = false; +Onyx.connect({ + key: ONYXKEYS.IOU, + callback: (val) => { + didInitCurrency = lodashGet(val, 'didInitCurrency'); + }, +}); + let shouldResetIOUAfterLogin = true; let currentUserPersonalDetails = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { currentUserPersonalDetails = lodashGet(val, userAccountID, {}); - if (val && SessionUtils.didUserLogInDuringSession() && shouldResetIOUAfterLogin) { - // eslint-disable-next-line no-use-before-define - resetMoneyRequestInfo(); - shouldResetIOUAfterLogin = false; - Onyx.merge(ONYXKEYS.IOU, { - didInitCurrency: true, - }); + if (!val || !shouldResetIOUAfterLogin || didInitCurrency) { + return; } + // eslint-disable-next-line no-use-before-define + resetMoneyRequestInfo(); + shouldResetIOUAfterLogin = false; + Onyx.merge(ONYXKEYS.IOU, { + didInitCurrency: true, + }); }, }); From 118ec38f2cfc2d406a0a5ead0339bae50c4aa335 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 6 Sep 2023 21:00:18 +0200 Subject: [PATCH 003/250] ref: inital migration to TS --- .../{Transaction.js => Transaction.ts} | 50 ++++++++----------- src/types/onyx/Transaction.ts | 5 ++ 2 files changed, 26 insertions(+), 29 deletions(-) rename src/libs/actions/{Transaction.js => Transaction.ts} (81%) diff --git a/src/libs/actions/Transaction.js b/src/libs/actions/Transaction.ts similarity index 81% rename from src/libs/actions/Transaction.js rename to src/libs/actions/Transaction.ts index b16e8c8753ac..f58db4915e77 100644 --- a/src/libs/actions/Transaction.js +++ b/src/libs/actions/Transaction.ts @@ -5,14 +5,15 @@ import lodashHas from 'lodash/has'; import ONYXKEYS from '../../ONYXKEYS'; import * as CollectionUtils from '../CollectionUtils'; import * as API from '../API'; +import {RecentWaypoints, Transaction} from '../../types/onyx'; -let recentWaypoints = []; +let recentWaypoints: RecentWaypoints[] = []; Onyx.connect({ key: ONYXKEYS.NVP_RECENT_WAYPOINTS, - callback: (val) => (recentWaypoints = val || []), + callback: (val) => (recentWaypoints = val ?? []), }); -const allTransactions = {}; +const allTransactions: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, callback: (transaction, key) => { @@ -24,10 +25,7 @@ Onyx.connect({ }, }); -/** - * @param {String} transactionID - */ -function createInitialWaypoints(transactionID) { +function createInitialWaypoints(transactionID: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, { comment: { waypoints: { @@ -40,14 +38,11 @@ function createInitialWaypoints(transactionID) { /** * Add a stop to the transaction - * - * @param {String} transactionID - * @param {Number} newLastIndex */ -function addStop(transactionID) { - const transaction = lodashGet(allTransactions, transactionID, {}); - const existingWaypoints = lodashGet(transaction, 'comment.waypoints', {}); - const newLastIndex = _.size(existingWaypoints); +function addStop(transactionID: string) { + const transaction = allTransactions?.[transactionID] ?? {}; + const existingWaypoints = transaction?.comment?.waypoints ?? {}; + const newLastIndex = Object.keys(existingWaypoints).length; Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, { comment: { @@ -69,11 +64,8 @@ function addStop(transactionID) { /** * Saves the selected waypoint to the transaction - * @param {String} transactionID - * @param {String} index - * @param {Object} waypoint */ -function saveWaypoint(transactionID, index, waypoint) { +function saveWaypoint(transactionID: string, index: string, waypoint: RecentWaypoints) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, { comment: { waypoints: { @@ -82,7 +74,8 @@ function saveWaypoint(transactionID, index, waypoint) { }, // Empty out errors when we're saving a new waypoint as this indicates the user is updating their input errorFields: { - route: null, + // TODO: check if its ok to put undefined + route: undefined, }, // Clear the existing route so that we don't show an old route @@ -102,20 +95,21 @@ function saveWaypoint(transactionID, index, waypoint) { return; } - const recentWaypointAlreadyExists = _.find(recentWaypoints, (recentWaypoint) => recentWaypoint.address === waypoint.address); + const recentWaypointAlreadyExists = recentWaypoints.find((recentWaypoint) => recentWaypoint.address === waypoint.address); if (!recentWaypointAlreadyExists) { + // TODO: Should we leave this? const clonedWaypoints = _.clone(recentWaypoints); clonedWaypoints.unshift(waypoint); Onyx.merge(ONYXKEYS.NVP_RECENT_WAYPOINTS, clonedWaypoints.slice(0, 5)); } } -function removeWaypoint(transactionID, currentIndex) { +function removeWaypoint(transactionID: string, currentIndex: string) { // Index comes from the route params and is a string const index = Number(currentIndex); - const transaction = lodashGet(allTransactions, transactionID, {}); - const existingWaypoints = lodashGet(transaction, 'comment.waypoints', {}); - const totalWaypoints = _.size(existingWaypoints); + const transaction = allTransactions?.[transactionID] ?? {}; + const existingWaypoints = transaction?.comment?.waypoints ?? {}; + const totalWaypoints = Object.keys(existingWaypoints).length; // Prevents removing the starting or ending waypoint but clear the stored address only if there are only two waypoints if (totalWaypoints === 2 && (index === 0 || index === totalWaypoints - 1)) { @@ -123,10 +117,10 @@ function removeWaypoint(transactionID, currentIndex) { return; } - const waypointValues = _.values(existingWaypoints); + const waypointValues = Object.values(existingWaypoints); waypointValues.splice(index, 1); - const reIndexedWaypoints = {}; + const reIndexedWaypoints: Record = {}; waypointValues.forEach((waypoint, idx) => { reIndexedWaypoints[`waypoint${idx}`] = waypoint; }); @@ -155,10 +149,8 @@ function removeWaypoint(transactionID, currentIndex) { /** * Gets the route for a set of waypoints * Used so we can generate a map view of the provided waypoints - * @param {String} transactionID - * @param {Object} waypoints */ -function getRoute(transactionID, waypoints) { +function getRoute(transactionID: string, waypoints: RecentWaypoints) { API.read( 'GetRoute', { diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 9e6cd603472f..2314b6230506 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,9 +1,11 @@ import {ValueOf} from 'type-fest'; import * as OnyxCommon from './OnyxCommon'; import CONST from '../../CONST'; +import RecentWaypoints from './RecentWaypoints'; type Comment = { comment?: string; + waypoints?: Record; }; type Transaction = { @@ -25,6 +27,9 @@ type Transaction = { source?: string; state?: ValueOf; }; + // TODO: fix unknown type + routes: Record; + errorFields: OnyxCommon.ErrorFields; }; export default Transaction; From 28532e794dcf3f8a8a7e0114cb1697bb11cfd347 Mon Sep 17 00:00:00 2001 From: VH Date: Thu, 7 Sep 2023 18:48:41 +0700 Subject: [PATCH 004/250] Pass preferredLocale when sign in with google or apple id --- src/libs/actions/Session/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index aa5ff229267f..c61bf7b3005a 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -35,6 +35,12 @@ Onyx.connect({ callback: (val) => (credentials = val || {}), }); +let preferredLocale; +Onyx.connect({ + key: ONYXKEYS.NVP_PREFERRED_LOCALE, + callback: (val) => (preferredLocale = val), +}); + /** * Clears the Onyx store and redirects user to the sign in page */ @@ -244,7 +250,7 @@ function beginSignIn(login) { */ function beginAppleSignIn(idToken) { const {optimisticData, successData, failureData} = signInAttemptState(); - API.write('SignInWithApple', {idToken}, {optimisticData, successData, failureData}); + API.write('SignInWithApple', {idToken, preferredLocale}, {optimisticData, successData, failureData}); } /** @@ -255,7 +261,7 @@ function beginAppleSignIn(idToken) { */ function beginGoogleSignIn(token) { const {optimisticData, successData, failureData} = signInAttemptState(); - API.write('SignInWithGoogle', {token}, {optimisticData, successData, failureData}); + API.write('SignInWithGoogle', {token, preferredLocale}, {optimisticData, successData, failureData}); } /** From 5ad1310ce0d6bd2e0a32e807f3687e3015dff859 Mon Sep 17 00:00:00 2001 From: VH Date: Thu, 7 Sep 2023 23:01:14 +0700 Subject: [PATCH 005/250] Fix linter --- src/libs/actions/Session/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index c61bf7b3005a..f570bfc79db6 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -35,10 +35,10 @@ Onyx.connect({ callback: (val) => (credentials = val || {}), }); -let preferredLocale; +let nvpPreferredLocale; Onyx.connect({ key: ONYXKEYS.NVP_PREFERRED_LOCALE, - callback: (val) => (preferredLocale = val), + callback: (val) => (nvpPreferredLocale = val), }); /** @@ -250,7 +250,7 @@ function beginSignIn(login) { */ function beginAppleSignIn(idToken) { const {optimisticData, successData, failureData} = signInAttemptState(); - API.write('SignInWithApple', {idToken, preferredLocale}, {optimisticData, successData, failureData}); + API.write('SignInWithApple', {idToken, preferredLocale: nvpPreferredLocale}, {optimisticData, successData, failureData}); } /** @@ -261,7 +261,7 @@ function beginAppleSignIn(idToken) { */ function beginGoogleSignIn(token) { const {optimisticData, successData, failureData} = signInAttemptState(); - API.write('SignInWithGoogle', {token, preferredLocale}, {optimisticData, successData, failureData}); + API.write('SignInWithGoogle', {token, preferredLocale: nvpPreferredLocale}, {optimisticData, successData, failureData}); } /** From b74d73f18ceec1db82a733d669101a2f440d2e3b Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Mon, 11 Sep 2023 12:58:02 +0200 Subject: [PATCH 006/250] ref: small refactors --- src/libs/actions/Transaction.ts | 10 ++++------ src/types/onyx/RecentWaypoints.ts | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index f58db4915e77..2d250cfc3902 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -1,7 +1,6 @@ -import _ from 'underscore'; import Onyx from 'react-native-onyx'; -import lodashGet from 'lodash/get'; import lodashHas from 'lodash/has'; +import lodashClone from 'lodash/clone'; import ONYXKEYS from '../../ONYXKEYS'; import * as CollectionUtils from '../CollectionUtils'; import * as API from '../API'; @@ -95,10 +94,9 @@ function saveWaypoint(transactionID: string, index: string, waypoint: RecentWayp return; } - const recentWaypointAlreadyExists = recentWaypoints.find((recentWaypoint) => recentWaypoint.address === waypoint.address); + const recentWaypointAlreadyExists = recentWaypoints.find((recentWaypoint) => recentWaypoint?.address === waypoint?.address); if (!recentWaypointAlreadyExists) { - // TODO: Should we leave this? - const clonedWaypoints = _.clone(recentWaypoints); + const clonedWaypoints = lodashClone(recentWaypoints); clonedWaypoints.unshift(waypoint); Onyx.merge(ONYXKEYS.NVP_RECENT_WAYPOINTS, clonedWaypoints.slice(0, 5)); } @@ -113,7 +111,7 @@ function removeWaypoint(transactionID: string, currentIndex: string) { // Prevents removing the starting or ending waypoint but clear the stored address only if there are only two waypoints if (totalWaypoints === 2 && (index === 0 || index === totalWaypoints - 1)) { - saveWaypoint(transactionID, index, null); + saveWaypoint(transactionID, index.toString(), null); return; } diff --git a/src/types/onyx/RecentWaypoints.ts b/src/types/onyx/RecentWaypoints.ts index 75780ef861e5..2b33997982c5 100644 --- a/src/types/onyx/RecentWaypoints.ts +++ b/src/types/onyx/RecentWaypoints.ts @@ -7,6 +7,6 @@ type RecentWaypoints = { /** The longitude of the waypoint */ lng: number; -}; +} | null; export default RecentWaypoints; From 0b9ca6ddc4513dba1f49223dc960fba9077810e8 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Mon, 11 Sep 2023 15:59:22 +0200 Subject: [PATCH 007/250] fix: added a errorFields field into Transaction type --- src/types/onyx/Transaction.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 6011120d2d45..398f808842b0 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -31,6 +31,7 @@ type Transaction = { created: string; pendingAction: OnyxCommon.PendingAction; errors: OnyxCommon.Errors; + errorFields: OnyxCommon.ErrorFields; modifiedAmount?: number; modifiedCreated?: string; modifiedCurrency?: string; From 1b995a9495829526209d2163e9b8a015fe876466 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Mon, 11 Sep 2023 16:41:59 +0200 Subject: [PATCH 008/250] fix: added null to coordinates type --- src/types/onyx/Transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 398f808842b0..85fe51e58b4f 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -9,7 +9,7 @@ type Comment = { }; type Geometry = { - coordinates: number[][]; + coordinates: number[][] | null; type: 'LineString'; }; From 61009460ef6fbea15fea9462f9b74e8afd406397 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Mon, 11 Sep 2023 17:35:49 +0200 Subject: [PATCH 009/250] fix: added needed fields into newTransaction object --- src/libs/actions/Transaction.ts | 4 +++- src/types/onyx/Transaction.ts | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 2d250cfc3902..6d2387143e99 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -126,7 +126,7 @@ function removeWaypoint(transactionID: string, currentIndex: string) { // Onyx.merge won't remove the null nested object values, this is a workaround // to remove nested keys while also preserving other object keys // Doing a deep clone of the transaction to avoid mutating the original object and running into a cache issue when using Onyx.set - const newTransaction = { + const newTransaction: Transaction = { ...transaction, comment: { ...transaction.comment, @@ -135,8 +135,10 @@ function removeWaypoint(transactionID: string, currentIndex: string) { // Clear the existing route so that we don't show an old route routes: { route0: { + distance: null, geometry: { coordinates: null, + type: '', }, }, }, diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 85fe51e58b4f..3a7bf3ac2eb7 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -8,13 +8,15 @@ type Comment = { waypoints?: Record; }; +type GeometryType = 'LineString' | ''; + type Geometry = { coordinates: number[][] | null; - type: 'LineString'; + type: GeometryType; }; type Route = { - distance: number; + distance: number | null; geometry: Geometry; }; From 1ddba1be4b590cf0c4d52417dbe353fc2ba016a8 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Mon, 11 Sep 2023 21:41:50 +0200 Subject: [PATCH 010/250] Bump reanimated to 3.5.0 --- ios/Podfile.lock | 4 ++-- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2bea672171fe..1c041db94691 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.4.0): + - RNReanimated (3.5.0): - DoubleConversion - FBLazyVector - glog @@ -1298,7 +1298,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: 020859659f64be2d30849a1fe88c821a7c3e0cbf + RNReanimated: fd0dc9a5889bfac6c45a922b26c902dc6185b4dc RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d diff --git a/package-lock.json b/package-lock.json index cd763dffefbe..aa5702b52e34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -94,7 +94,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "3.4.0", + "react-native-reanimated": "^3.5.0", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", @@ -41013,9 +41013,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.4.0.tgz", - "integrity": "sha512-B5cZJseoIkYlZTRBRN0xuU1NBxUza/6GSHhiEBQfbOufWVlUMMcWUecIRVglW49l8d2wXbfCdQlNyVoFqmHkaQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.0.tgz", + "integrity": "sha512-om2AfxCD0YyBvGADJ5Ql38CKIJ8MXZTTpve1jt94TcRjLHXui24wYomoumSnnBQEfeRDzjwpmFdqcLtJ5mU5Pg==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -76740,9 +76740,9 @@ "requires": {} }, "react-native-reanimated": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.4.0.tgz", - "integrity": "sha512-B5cZJseoIkYlZTRBRN0xuU1NBxUza/6GSHhiEBQfbOufWVlUMMcWUecIRVglW49l8d2wXbfCdQlNyVoFqmHkaQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.0.tgz", + "integrity": "sha512-om2AfxCD0YyBvGADJ5Ql38CKIJ8MXZTTpve1jt94TcRjLHXui24wYomoumSnnBQEfeRDzjwpmFdqcLtJ5mU5Pg==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", diff --git a/package.json b/package.json index 6666fd19cf7a..59ef49d40199 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "3.4.0", + "react-native-reanimated": "3.5.0", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", From 54f479b4b42993379797b7d411eee6ba6021e1d8 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Tue, 12 Sep 2023 10:09:29 +0200 Subject: [PATCH 011/250] fix: resolved review comments --- src/libs/actions/Transaction.ts | 5 ++--- src/types/onyx/OnyxCommon.ts | 2 +- src/types/onyx/Transaction.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 6d2387143e99..1e4d85bc126e 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -73,8 +73,7 @@ function saveWaypoint(transactionID: string, index: string, waypoint: RecentWayp }, // Empty out errors when we're saving a new waypoint as this indicates the user is updating their input errorFields: { - // TODO: check if its ok to put undefined - route: undefined, + route: null, }, // Clear the existing route so that we don't show an old route @@ -150,7 +149,7 @@ function removeWaypoint(transactionID: string, currentIndex: string) { * Gets the route for a set of waypoints * Used so we can generate a map view of the provided waypoints */ -function getRoute(transactionID: string, waypoints: RecentWaypoints) { +function getRoute(transactionID: string, waypoints: Record) { API.read( 'GetRoute', { diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index 36e9c6ae74ea..db82edcb98ff 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -4,7 +4,7 @@ import CONST from '../../CONST'; type PendingAction = ValueOf; -type ErrorFields = Record>; +type ErrorFields = Record | null>; type Errors = Record; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 3a7bf3ac2eb7..8e1449906cbf 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -33,7 +33,7 @@ type Transaction = { created: string; pendingAction: OnyxCommon.PendingAction; errors: OnyxCommon.Errors; - errorFields: OnyxCommon.ErrorFields; + errorFields?: OnyxCommon.ErrorFields; modifiedAmount?: number; modifiedCreated?: string; modifiedCurrency?: string; From 85a12fa4f260eee0d86e3dba590a545d344a70fc Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Tue, 12 Sep 2023 12:13:46 +0200 Subject: [PATCH 012/250] fix: rename type to RecentWaypoint --- src/ONYXKEYS.ts | 2 +- src/libs/actions/Transaction.ts | 11 ++++++----- .../onyx/{RecentWaypoints.ts => RecentWaypoint.ts} | 6 +++--- src/types/onyx/Transaction.ts | 6 ++++-- src/types/onyx/index.ts | 4 ++-- 5 files changed, 16 insertions(+), 13 deletions(-) rename src/types/onyx/{RecentWaypoints.ts => RecentWaypoint.ts} (73%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index b978f06dbfd9..cacdc9545ca8 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -330,7 +330,7 @@ type OnyxValues = { [ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE]: OnyxTypes.BlockedFromConcierge; [ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string; [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: Record; - [ONYXKEYS.NVP_RECENT_WAYPOINTS]: OnyxTypes.RecentWaypoints[]; + [ONYXKEYS.NVP_RECENT_WAYPOINTS]: OnyxTypes.RecentWaypoint[]; [ONYXKEYS.PUSH_NOTIFICATIONS_ENABLED]: boolean; [ONYXKEYS.PLAID_DATA]: OnyxTypes.PlaidData; [ONYXKEYS.IS_PLAID_DISABLED]: boolean; diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 1e4d85bc126e..47010ba275b3 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -4,9 +4,10 @@ import lodashClone from 'lodash/clone'; import ONYXKEYS from '../../ONYXKEYS'; import * as CollectionUtils from '../CollectionUtils'; import * as API from '../API'; -import {RecentWaypoints, Transaction} from '../../types/onyx'; +import {RecentWaypoint, Transaction} from '../../types/onyx'; +import {WaypointCollection} from '../../types/onyx/Transaction'; -let recentWaypoints: RecentWaypoints[] = []; +let recentWaypoints: RecentWaypoint[] = []; Onyx.connect({ key: ONYXKEYS.NVP_RECENT_WAYPOINTS, callback: (val) => (recentWaypoints = val ?? []), @@ -64,7 +65,7 @@ function addStop(transactionID: string) { /** * Saves the selected waypoint to the transaction */ -function saveWaypoint(transactionID: string, index: string, waypoint: RecentWaypoints) { +function saveWaypoint(transactionID: string, index: string, waypoint: RecentWaypoint | null) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, { comment: { waypoints: { @@ -117,7 +118,7 @@ function removeWaypoint(transactionID: string, currentIndex: string) { const waypointValues = Object.values(existingWaypoints); waypointValues.splice(index, 1); - const reIndexedWaypoints: Record = {}; + const reIndexedWaypoints: WaypointCollection = {}; waypointValues.forEach((waypoint, idx) => { reIndexedWaypoints[`waypoint${idx}`] = waypoint; }); @@ -149,7 +150,7 @@ function removeWaypoint(transactionID: string, currentIndex: string) { * Gets the route for a set of waypoints * Used so we can generate a map view of the provided waypoints */ -function getRoute(transactionID: string, waypoints: Record) { +function getRoute(transactionID: string, waypoints: WaypointCollection) { API.read( 'GetRoute', { diff --git a/src/types/onyx/RecentWaypoints.ts b/src/types/onyx/RecentWaypoint.ts similarity index 73% rename from src/types/onyx/RecentWaypoints.ts rename to src/types/onyx/RecentWaypoint.ts index 2b33997982c5..79aded8ede98 100644 --- a/src/types/onyx/RecentWaypoints.ts +++ b/src/types/onyx/RecentWaypoint.ts @@ -1,4 +1,4 @@ -type RecentWaypoints = { +type RecentWaypoint = { /** The full address of the waypoint */ address: string; @@ -7,6 +7,6 @@ type RecentWaypoints = { /** The longitude of the waypoint */ lng: number; -} | null; +}; -export default RecentWaypoints; +export default RecentWaypoint; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 8e1449906cbf..4df5377d309b 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,11 +1,12 @@ import {ValueOf} from 'type-fest'; import * as OnyxCommon from './OnyxCommon'; import CONST from '../../CONST'; -import RecentWaypoints from './RecentWaypoints'; +import RecentWaypoint from './RecentWaypoint'; +type WaypointCollection = Record; type Comment = { comment?: string; - waypoints?: Record; + waypoints?: WaypointCollection; }; type GeometryType = 'LineString' | ''; @@ -46,3 +47,4 @@ type Transaction = { }; export default Transaction; +export type {WaypointCollection}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index d908c0b36ce1..97909da5fb47 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -43,7 +43,7 @@ import ReportActionReactions from './ReportActionReactions'; import SecurityGroup from './SecurityGroup'; import Transaction from './Transaction'; import Form, {AddDebitCardForm} from './Form'; -import RecentWaypoints from './RecentWaypoints'; +import RecentWaypoint from './RecentWaypoint'; import RecentlyUsedCategories from './RecentlyUsedCategories'; export type { @@ -93,6 +93,6 @@ export type { Form, AddDebitCardForm, OnyxUpdatesFromServer, - RecentWaypoints, + RecentWaypoint, RecentlyUsedCategories, }; From 34760eb7852235bee549808bb6cb38d7eb19ae78 Mon Sep 17 00:00:00 2001 From: Thiago Brezinski Date: Tue, 12 Sep 2023 13:08:23 +0100 Subject: [PATCH 013/250] fix(selection-list): highlight on lists with 1 section --- .../SelectionList/BaseSelectionList.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js index b76ded8a542f..1b45f0d42e5c 100644 --- a/src/components/SelectionList/BaseSelectionList.js +++ b/src/components/SelectionList/BaseSelectionList.js @@ -167,15 +167,13 @@ function BaseSelectionList({ listRef.current.scrollToLocation({sectionIndex: adjustedSectionIndex, itemIndex, animated, viewOffset: variables.contentHeaderHeight}); }; - const selectRow = (item, index) => { + const selectRow = (item) => { // In single-selection lists we don't care about updating the focused index, because the list is closed after selecting an item if (canSelectMultiple) { - if (sections.length === 1) { - // If the list has only 1 section (e.g. Workspace Members list), we always focus the next available item - const nextAvailableIndex = _.findIndex(flattenedSections.allOptions, (option, i) => i > index && !option.isDisabled); - setFocusedIndex(nextAvailableIndex); - } else { - // If the list has multiple sections (e.g. Workspace Invite list), we focus the first one after all the selected (selected items are always at the top) + if (sections.length > 1) { + // If the list has only 1 section (e.g. Workspace Members list), we do nothing. + // If the list has multiple sections (e.g. Workspace Invite list), we focus the first one after all the selected (selected items are always at the top). + const selectedOptionsCount = item.isSelected ? flattenedSections.selectedOptions.length - 1 : flattenedSections.selectedOptions.length + 1; setFocusedIndex(selectedOptionsCount); @@ -196,7 +194,7 @@ function BaseSelectionList({ return; } - selectRow(focusedOption, focusedIndex); + selectRow(focusedOption); }; /** @@ -250,7 +248,7 @@ function BaseSelectionList({ selectRow(item, index)} + onSelectRow={() => selectRow(item)} onDismissError={onDismissError} /> ); @@ -261,7 +259,7 @@ function BaseSelectionList({ item={item} isFocused={isFocused} isDisabled={isDisabled} - onSelectRow={() => selectRow(item, index)} + onSelectRow={() => selectRow(item)} /> ); }; From 0a4b9501e3519dc877d8706d61c7ab5c9bfaa786 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Tue, 12 Sep 2023 14:27:04 +0200 Subject: [PATCH 014/250] Bump to 3.5.1 --- ios/Podfile.lock | 4 ++-- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 1c041db94691..99f77ea908d1 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.5.0): + - RNReanimated (3.5.1): - DoubleConversion - FBLazyVector - glog @@ -1298,7 +1298,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: fd0dc9a5889bfac6c45a922b26c902dc6185b4dc + RNReanimated: 99aa8c96151abbc2d7e737a56ec62aca709f0c92 RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d diff --git a/package-lock.json b/package-lock.json index aa5702b52e34..3784b4a01e9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -94,7 +94,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "^3.5.0", + "react-native-reanimated": "^3.5.1", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", @@ -41013,9 +41013,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.0.tgz", - "integrity": "sha512-om2AfxCD0YyBvGADJ5Ql38CKIJ8MXZTTpve1jt94TcRjLHXui24wYomoumSnnBQEfeRDzjwpmFdqcLtJ5mU5Pg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.1.tgz", + "integrity": "sha512-ZBTOKibTn1IR5IaoQkpPCibuao5SjXR6Pzx+KHM50wrvBnL1PecsnQjmL2VEj8hbwshrzgRGgGt1XM82DKrykw==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -76740,9 +76740,9 @@ "requires": {} }, "react-native-reanimated": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.0.tgz", - "integrity": "sha512-om2AfxCD0YyBvGADJ5Ql38CKIJ8MXZTTpve1jt94TcRjLHXui24wYomoumSnnBQEfeRDzjwpmFdqcLtJ5mU5Pg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.1.tgz", + "integrity": "sha512-ZBTOKibTn1IR5IaoQkpPCibuao5SjXR6Pzx+KHM50wrvBnL1PecsnQjmL2VEj8hbwshrzgRGgGt1XM82DKrykw==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", diff --git a/package.json b/package.json index 59ef49d40199..fbdc85a4ba63 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "3.5.0", + "react-native-reanimated": "^3.5.1", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", From 2e71d6530c664746954087c09366346ef9c31a30 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Tue, 12 Sep 2023 14:29:18 +0200 Subject: [PATCH 015/250] Add patch to fix typecheck --- patches/react-native-reanimated+3.5.1.patch | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 patches/react-native-reanimated+3.5.1.patch diff --git a/patches/react-native-reanimated+3.5.1.patch b/patches/react-native-reanimated+3.5.1.patch new file mode 100644 index 000000000000..69c8f7028a58 --- /dev/null +++ b/patches/react-native-reanimated+3.5.1.patch @@ -0,0 +1,11 @@ +diff --git a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts +index 4df2481..cca7f1a 100644 +--- a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts ++++ b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts +@@ -40,5 +40,5 @@ export function isReducedMotion() { + ? isWindowAvailable() + ? !window.matchMedia('(prefers-reduced-motion: no-preference)').matches + : false +- : global._REANIMATED_IS_REDUCED_MOTION ?? false; ++ : (global as any)._REANIMATED_IS_REDUCED_MOTION ?? false; + } From 67c2a5f7fe67c2dfe2574af00056dc07885418a2 Mon Sep 17 00:00:00 2001 From: Thiago Brezinski Date: Tue, 12 Sep 2023 13:59:40 +0100 Subject: [PATCH 016/250] chore: make function call concise --- src/components/SelectionList/BaseSelectionList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js index 1b45f0d42e5c..230de8e75dcc 100644 --- a/src/components/SelectionList/BaseSelectionList.js +++ b/src/components/SelectionList/BaseSelectionList.js @@ -248,7 +248,7 @@ function BaseSelectionList({ selectRow(item)} + onSelectRow={selectRow} onDismissError={onDismissError} /> ); @@ -259,7 +259,7 @@ function BaseSelectionList({ item={item} isFocused={isFocused} isDisabled={isDisabled} - onSelectRow={() => selectRow(item)} + onSelectRow={selectRow} /> ); }; From d0b45ec023085952b7c7ae131c0378827b63c1f1 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 12 Sep 2023 14:30:53 -0400 Subject: [PATCH 017/250] allow other types of notifications --- src/libs/actions/Report.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 85552fa14a56..8c8c48a20153 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1566,12 +1566,6 @@ function shouldShowReportActionNotification(reportID, action = null, isRemote = return false; } - // Don't show a notification if no comment exists - if (action && !_.some(action.message, (f) => f.type === 'COMMENT')) { - Log.info(`${tag} No notification because no comments exist for the current action`); - return false; - } - return true; } From 93a5891659703faeb8a88b5a506d2257e8058930 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 12 Sep 2023 14:43:32 -0400 Subject: [PATCH 018/250] rename action to reportAction --- src/libs/actions/Report.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 8c8c48a20153..fed4efd2e3d2 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1571,23 +1571,23 @@ function shouldShowReportActionNotification(reportID, action = null, isRemote = /** * @param {String} reportID - * @param {Object} action + * @param {Object} reportAction */ -function showReportActionNotification(reportID, action) { - if (!shouldShowReportActionNotification(reportID, action)) { +function showReportActionNotification(reportID, reportAction) { + if (!shouldShowReportActionNotification(reportID, reportAction)) { return; } Log.info('[LocalNotification] Creating notification'); LocalNotification.showCommentNotification({ report: allReports[reportID], - reportAction: action, + reportAction, onClick: () => { // Navigate to this report onClick Navigation.navigate(ROUTES.getReportRoute(reportID)); }, }); - notifyNewAction(reportID, action.actorAccountID, action.reportActionID); + notifyNewAction(reportID, reportAction.actorAccountID, reportAction.reportActionID); } /** From 6a86285381622159f3f91239c212945cf52752f4 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Tue, 12 Sep 2023 21:15:30 +0200 Subject: [PATCH 019/250] fix: check if waypoint is not null --- src/libs/actions/Transaction.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 47010ba275b3..16a974db25ff 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -93,9 +93,8 @@ function saveWaypoint(transactionID: string, index: string, waypoint: RecentWayp if (!lodashHas(waypoint, 'lat') || !lodashHas(waypoint, 'lng')) { return; } - const recentWaypointAlreadyExists = recentWaypoints.find((recentWaypoint) => recentWaypoint?.address === waypoint?.address); - if (!recentWaypointAlreadyExists) { + if (!recentWaypointAlreadyExists && waypoint !== null) { const clonedWaypoints = lodashClone(recentWaypoints); clonedWaypoints.unshift(waypoint); Onyx.merge(ONYXKEYS.NVP_RECENT_WAYPOINTS, clonedWaypoints.slice(0, 5)); @@ -108,7 +107,6 @@ function removeWaypoint(transactionID: string, currentIndex: string) { const transaction = allTransactions?.[transactionID] ?? {}; const existingWaypoints = transaction?.comment?.waypoints ?? {}; const totalWaypoints = Object.keys(existingWaypoints).length; - // Prevents removing the starting or ending waypoint but clear the stored address only if there are only two waypoints if (totalWaypoints === 2 && (index === 0 || index === totalWaypoints - 1)) { saveWaypoint(transactionID, index.toString(), null); From cabe7a55afc8eb71f284d104145e13fdbe7c89b0 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 12 Sep 2023 15:41:39 -0400 Subject: [PATCH 020/250] use formatting for modified expense notifications --- .../LocalNotification/BrowserNotifications.js | 9 +++++++ .../LocalNotification/index.desktop.js | 5 ++++ .../LocalNotification/index.native.js | 1 + .../LocalNotification/index.website.js | 5 ++++ src/libs/actions/Report.js | 24 ++++++++++++------- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js index e55c0430fe17..11c857abc972 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -128,6 +128,15 @@ export default { }); }, + pushModifiedExpenseNotification({report, reportAction, onClick}) { + push({ + title: report.reportName, + body: ReportUtils.getModifiedExpenseMessage(reportAction), + delay: 0, + onClick, + }); + }, + /** * Create a notification to indicate that an update is available. */ diff --git a/src/libs/Notification/LocalNotification/index.desktop.js b/src/libs/Notification/LocalNotification/index.desktop.js index 2bef51cea0a6..6e526da2bd1f 100644 --- a/src/libs/Notification/LocalNotification/index.desktop.js +++ b/src/libs/Notification/LocalNotification/index.desktop.js @@ -8,7 +8,12 @@ function showUpdateAvailableNotification() { BrowserNotifications.pushUpdateAvailableNotification(); } +function showModifiedExpenseNotification({report, reportAction, onClick}) { + BrowserNotifications.pushModifiedExpenseNotification({report, reportAction, onClick}); +} + export default { showCommentNotification, showUpdateAvailableNotification, + showModifiedExpenseNotification, }; diff --git a/src/libs/Notification/LocalNotification/index.native.js b/src/libs/Notification/LocalNotification/index.native.js index bbc4f48744b6..1f1771e619a5 100644 --- a/src/libs/Notification/LocalNotification/index.native.js +++ b/src/libs/Notification/LocalNotification/index.native.js @@ -2,4 +2,5 @@ export default { showCommentNotification: () => {}, showUpdateAvailableNotification: () => {}, + showModifiedExpenseNotification: () => {}, }; diff --git a/src/libs/Notification/LocalNotification/index.website.js b/src/libs/Notification/LocalNotification/index.website.js index 3410b3144caf..ef5ee101b16d 100644 --- a/src/libs/Notification/LocalNotification/index.website.js +++ b/src/libs/Notification/LocalNotification/index.website.js @@ -8,7 +8,12 @@ function showUpdateAvailableNotification() { BrowserNotifications.pushUpdateAvailableNotification(); } +function showModifiedExpenseNotification({report, reportAction, onClick}) { + BrowserNotifications.pushModifiedExpenseNotification({report, reportAction, onClick}); +} + export default { showCommentNotification, showUpdateAvailableNotification, + showModifiedExpenseNotification, }; diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index fed4efd2e3d2..4479b0982f23 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1579,14 +1579,22 @@ function showReportActionNotification(reportID, reportAction) { } Log.info('[LocalNotification] Creating notification'); - LocalNotification.showCommentNotification({ - report: allReports[reportID], - reportAction, - onClick: () => { - // Navigate to this report onClick - Navigation.navigate(ROUTES.getReportRoute(reportID)); - }, - }); + const report = allReports[reportID]; + + if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { + LocalNotification.showModifiedExpenseNotification({ + report, + reportAction, + onClick: () => Navigation.navigate(ROUTES.getReportRoute(reportID)), + }); + } else { + LocalNotification.showCommentNotification({ + report, + reportAction, + onClick: () => Navigation.navigate(ROUTES.getReportRoute(reportID)), + }); + } + notifyNewAction(reportID, reportAction.actorAccountID, reportAction.reportActionID); } From ada24327e5eb114e46177363ecc1815999550386 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 12 Sep 2023 18:35:42 -0400 Subject: [PATCH 021/250] only allow some types of actions for notifications --- src/libs/actions/Report.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 4479b0982f23..2965594488ca 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1566,6 +1566,11 @@ function shouldShowReportActionNotification(reportID, action = null, isRemote = return false; } + // Only show notifications for supported types of report actions + if (action && !_.contains([CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE], action.actionName)) { + return false; + } + return true; } From d74bc4e2f0a00898b858f5dec6880b36824a782d Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 12 Sep 2023 18:49:55 -0400 Subject: [PATCH 022/250] use report action user as title --- .../Notification/LocalNotification/BrowserNotifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js index 11c857abc972..99e274d42d1f 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -128,9 +128,9 @@ export default { }); }, - pushModifiedExpenseNotification({report, reportAction, onClick}) { + pushModifiedExpenseNotification({reportAction, onClick}) { push({ - title: report.reportName, + title: _.map(reportAction.person, (f) => f.text).join(), body: ReportUtils.getModifiedExpenseMessage(reportAction), delay: 0, onClick, From 1cc8736ba4b105d6241f72e34afb82937d13b351 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 12 Sep 2023 19:13:01 -0400 Subject: [PATCH 023/250] use icon on web --- .../Notification/LocalNotification/BrowserNotifications.js | 3 ++- src/libs/Notification/LocalNotification/index.website.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js index 99e274d42d1f..811ed7fabce0 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -128,12 +128,13 @@ export default { }); }, - pushModifiedExpenseNotification({reportAction, onClick}) { + pushModifiedExpenseNotification({reportAction, onClick}, usesIcon = false) { push({ title: _.map(reportAction.person, (f) => f.text).join(), body: ReportUtils.getModifiedExpenseMessage(reportAction), delay: 0, onClick, + icon: usesIcon ? EXPENSIFY_ICON_URL : '', }); }, diff --git a/src/libs/Notification/LocalNotification/index.website.js b/src/libs/Notification/LocalNotification/index.website.js index ef5ee101b16d..6c2a409ccdcb 100644 --- a/src/libs/Notification/LocalNotification/index.website.js +++ b/src/libs/Notification/LocalNotification/index.website.js @@ -9,7 +9,7 @@ function showUpdateAvailableNotification() { } function showModifiedExpenseNotification({report, reportAction, onClick}) { - BrowserNotifications.pushModifiedExpenseNotification({report, reportAction, onClick}); + BrowserNotifications.pushModifiedExpenseNotification({report, reportAction, onClick}, true); } export default { From b6be9920ffe509a385418a63840867559888285a Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 12 Sep 2023 19:22:37 -0400 Subject: [PATCH 024/250] log reason for no notification --- src/libs/actions/Report.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 2965594488ca..17fa6a5bc9bc 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1568,6 +1568,7 @@ function shouldShowReportActionNotification(reportID, action = null, isRemote = // Only show notifications for supported types of report actions if (action && !_.contains([CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE], action.actionName)) { + Log.info(`${tag} No notification because this action type is not supported`, false, {actionName: action.actionName}); return false; } From 8e9a7ab23365c555160984331f7af1fd230fc910 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 13 Sep 2023 16:21:17 +0200 Subject: [PATCH 025/250] [TS migration] Migrate 'CloseAccount.js' lib to TypeScript --- src/libs/actions/{CloseAccount.js => CloseAccount.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/libs/actions/{CloseAccount.js => CloseAccount.ts} (100%) diff --git a/src/libs/actions/CloseAccount.js b/src/libs/actions/CloseAccount.ts similarity index 100% rename from src/libs/actions/CloseAccount.js rename to src/libs/actions/CloseAccount.ts From 6db3f487c899ce4ddbacf3526cad27a4b27ab7b0 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Wed, 13 Sep 2023 17:55:04 -0400 Subject: [PATCH 026/250] use the alert in the payload as the notification message --- .../CustomNotificationProvider.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index 0ba77f809b19..c60476ad3f0a 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -106,7 +106,8 @@ protected NotificationCompat.Builder onExtendBuilder(@NonNull Context context, @ if (payload.containsKey(ONYX_DATA_KEY)) { Objects.requireNonNull(payload.get(ONYX_DATA_KEY)).isNull(); Log.d(TAG, "payload contains onxyData"); - applyMessageStyle(context, builder, payload, arguments.getNotificationId()); + String alert = message.getExtra(PushMessage.EXTRA_ALERT); + applyMessageStyle(context, builder, payload, arguments.getNotificationId(), alert); } } catch (Exception e) { Log.e(TAG, "Failed to parse conversation, falling back to default notification style. SendID=" + message.getSendId(), e); @@ -163,7 +164,7 @@ public Bitmap getCroppedBitmap(Bitmap bitmap) { * @param payload Notification payload, which contains all the data we need to build the notifications. * @param notificationID Current notification ID */ - private void applyMessageStyle(@NonNull Context context, NotificationCompat.Builder builder, JsonMap payload, int notificationID) { + private void applyMessageStyle(@NonNull Context context, NotificationCompat.Builder builder, JsonMap payload, int notificationID, String alert) { long reportID = payload.get("reportID").getLong(-1); if (reportID == -1) { return; @@ -181,7 +182,9 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil String name = messageData.get("person").getList().get(0).getMap().get("text").getString(); String avatar = messageData.get("avatar").getString(); String accountID = Integer.toString(messageData.get("actorAccountID").getInt(-1)); - String message = messageData.get("message").getList().get(0).getMap().get("text").getString(); + + // Use the formatted alert message from the backend. Otherwise fallback on the message in the Onyx data. + String message = alert != null ? alert : messageData.get("message").getList().get(0).getMap().get("text").getString(); String conversationName = payload.get("roomName") == null ? "" : payload.get("roomName").getString(""); // Retrieve or create the Person object who sent the latest report comment From 74a8de34a7aa01a55e428ce5cdb503a9cb9bbaf4 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 14 Sep 2023 12:47:16 +0800 Subject: [PATCH 027/250] use default style --- src/components/AvatarWithDisplayName.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index e82dbe05a6d0..6151775aaf3f 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -112,7 +112,6 @@ function AvatarWithDisplayName(props) { )} From 007ff215ff5d0b2f7de5fa42d1655b065274262a Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 14 Sep 2023 13:51:15 +0800 Subject: [PATCH 028/250] remove unused import --- src/components/AvatarWithDisplayName.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index 6151775aaf3f..a6c630b775f7 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -17,7 +17,6 @@ import DisplayNames from './DisplayNames'; import compose from '../libs/compose'; import * as OptionsListUtils from '../libs/OptionsListUtils'; import Text from './Text'; -import * as StyleUtils from '../styles/StyleUtils'; import ParentNavigationSubtitle from './ParentNavigationSubtitle'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import Navigation from '../libs/Navigation/Navigation'; From cc0c7e2d1eabc828a0abb61fc9cbebc8692cc1e2 Mon Sep 17 00:00:00 2001 From: Thiago Brezinski Date: Thu, 14 Sep 2023 11:29:26 +0100 Subject: [PATCH 029/250] fix(selection-list): remove active item highlight --- src/components/SelectionList/RadioListItem.js | 1 - src/components/SelectionList/UserListItem.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/SelectionList/RadioListItem.js b/src/components/SelectionList/RadioListItem.js index 92e3e84b66c8..4adf582b30d4 100644 --- a/src/components/SelectionList/RadioListItem.js +++ b/src/components/SelectionList/RadioListItem.js @@ -17,7 +17,6 @@ function RadioListItem({item, isFocused = false, isDisabled = false, onSelectRow accessibilityRole="button" hoverDimmingValue={1} hoverStyle={styles.hoveredComponentBG} - focusStyle={styles.hoveredComponentBG} > diff --git a/src/components/SelectionList/UserListItem.js b/src/components/SelectionList/UserListItem.js index dd90fc750510..f701b1873cbe 100644 --- a/src/components/SelectionList/UserListItem.js +++ b/src/components/SelectionList/UserListItem.js @@ -62,7 +62,6 @@ function UserListItem({item, isFocused = false, showTooltip, onSelectRow, onDism accessibilityState={{checked: item.isSelected}} hoverDimmingValue={1} hoverStyle={styles.hoveredComponentBG} - focusStyle={styles.hoveredComponentBG} > Date: Thu, 14 Sep 2023 21:40:37 +0800 Subject: [PATCH 030/250] fix second avatar border color does not match the background if the option is focused --- src/components/OptionRow.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index 50aff23dc9d0..8c4d52f79c13 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -206,18 +206,14 @@ class OptionRow extends Component { ) : ( ))} From a8cc185eb6a164979a08371dc2548433d653dc1f Mon Sep 17 00:00:00 2001 From: Thiago Brezinski Date: Thu, 14 Sep 2023 16:15:15 +0100 Subject: [PATCH 031/250] fix(selection-list): remove active item highlight --- src/components/Button/index.js | 1 + src/components/SelectionList/BaseSelectionList.js | 5 ++++- src/components/SelectionList/RadioListItem.js | 1 - src/components/SelectionList/UserListItem.js | 1 - src/hooks/useActiveElement/index.js | 6 ++++++ src/hooks/useActiveElement/index.native.js | 5 +++++ 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/Button/index.js b/src/components/Button/index.js index bfde528a4750..0d19691d1256 100644 --- a/src/components/Button/index.js +++ b/src/components/Button/index.js @@ -305,6 +305,7 @@ class Button extends Component { ]} nativeID={this.props.nativeID} accessibilityLabel={this.props.accessibilityLabel} + accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON} hoverDimmingValue={1} > {this.renderContent()} diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js index 6699e56e54f6..895272ba18ef 100644 --- a/src/components/SelectionList/BaseSelectionList.js +++ b/src/components/SelectionList/BaseSelectionList.js @@ -135,6 +135,9 @@ function BaseSelectionList({ }; }, [canSelectMultiple, sections]); + // Disable `Enter` hotkey if the active element is a button or checkbox + const shouldDisableHotkeys = activeElement && [CONST.ACCESSIBILITY_ROLE.BUTTON, CONST.ACCESSIBILITY_ROLE.CHECKBOX].includes(activeElement.role); + // If `initiallyFocusedOptionKey` is not passed, we fall back to `-1`, to avoid showing the highlight on the first member const [focusedIndex, setFocusedIndex] = useState(() => _.findIndex(flattenedSections.allOptions, (option) => option.keyForList === initiallyFocusedOptionKey)); @@ -287,7 +290,7 @@ function BaseSelectionList({ useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ENTER, selectFocusedOption, { captureOnInputs: true, shouldBubble: () => !flattenedSections.allOptions[focusedIndex], - isActive: !activeElement, + isActive: !shouldDisableHotkeys, }); /** Calls confirm action when pressing CTRL (CMD) + Enter */ diff --git a/src/components/SelectionList/RadioListItem.js b/src/components/SelectionList/RadioListItem.js index 92e3e84b66c8..4adf582b30d4 100644 --- a/src/components/SelectionList/RadioListItem.js +++ b/src/components/SelectionList/RadioListItem.js @@ -17,7 +17,6 @@ function RadioListItem({item, isFocused = false, isDisabled = false, onSelectRow accessibilityRole="button" hoverDimmingValue={1} hoverStyle={styles.hoveredComponentBG} - focusStyle={styles.hoveredComponentBG} > diff --git a/src/components/SelectionList/UserListItem.js b/src/components/SelectionList/UserListItem.js index dd90fc750510..f701b1873cbe 100644 --- a/src/components/SelectionList/UserListItem.js +++ b/src/components/SelectionList/UserListItem.js @@ -62,7 +62,6 @@ function UserListItem({item, isFocused = false, showTooltip, onSelectRow, onDism accessibilityState={{checked: item.isSelected}} hoverDimmingValue={1} hoverStyle={styles.hoveredComponentBG} - focusStyle={styles.hoveredComponentBG} > Date: Fri, 15 Sep 2023 12:11:45 +0800 Subject: [PATCH 032/250] ignore scroll callback if triggered by text update --- .../ReportActionCompose/ComposerWithSuggestions.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 3b5b181d2fcb..696627a13947 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -125,6 +125,7 @@ function ComposerWithSuggestions({ const textInputRef = useRef(null); const insertedEmojisRef = useRef([]); + const shouldIgnoreScrollCallback = useRef(false); /** * Update frequently used emojis list. We debounce this method in the constructor so that UpdateFrequentlyUsedEmojis @@ -175,6 +176,7 @@ function ComposerWithSuggestions({ */ const updateComment = useCallback( (commentValue, shouldDebounceSaveComment) => { + shouldIgnoreScrollCallback.current = true; const {text: newComment, emojis} = EmojiUtils.replaceAndExtractEmojis(commentValue, preferredSkinTone, preferredLocale); if (!_.isEmpty(emojis)) { @@ -314,13 +316,16 @@ function ComposerWithSuggestions({ [suggestionsRef], ); - const updateShouldShowSuggestionMenuToFalse = useCallback(() => { - if (!suggestionsRef.current) { + const hideSuggestionMenu = useCallback(() => { + if (!suggestionsRef.current || shouldIgnoreScrollCallback.current) { + shouldIgnoreScrollCallback.current = false; return; } suggestionsRef.current.updateShouldShowSuggestionMenuToFalse(false); }, [suggestionsRef]); + const debouncedHideSuggestionMenu = useMemo(() => _.debounce(hideSuggestionMenu, 200, true), [hideSuggestionMenu]); + const setShouldBlockSuggestionCalcToFalse = useCallback(() => { if (!suggestionsRef.current) { return false; @@ -494,7 +499,7 @@ function ComposerWithSuggestions({ } setComposerHeight(composerLayoutHeight); }} - onScroll={updateShouldShowSuggestionMenuToFalse} + onScroll={debouncedHideSuggestionMenu} /> From c004c4cccb367afaceaa1bfb459f9026e41ba512 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Fri, 15 Sep 2023 10:18:16 +0200 Subject: [PATCH 033/250] ref: move RenameExpensifyNewsStatus to TS --- ...meExpensifyNewsStatus.js => RenameExpensifyNewsStatus.ts} | 5 +++-- src/types/onyx/User.ts | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) rename src/libs/migrations/{RenameExpensifyNewsStatus.js => RenameExpensifyNewsStatus.ts} (83%) diff --git a/src/libs/migrations/RenameExpensifyNewsStatus.js b/src/libs/migrations/RenameExpensifyNewsStatus.ts similarity index 83% rename from src/libs/migrations/RenameExpensifyNewsStatus.js rename to src/libs/migrations/RenameExpensifyNewsStatus.ts index 421879b0e8ad..fd8c2cc62b61 100644 --- a/src/libs/migrations/RenameExpensifyNewsStatus.js +++ b/src/libs/migrations/RenameExpensifyNewsStatus.ts @@ -1,5 +1,4 @@ import Onyx from 'react-native-onyx'; -import _ from 'underscore'; import ONYXKEYS from '../../ONYXKEYS'; import Log from '../Log'; @@ -15,8 +14,9 @@ export default function () { Onyx.disconnect(connectionID); // Fail early here because there is nothing to migrate - if (!user || _.isNull(user.expensifyNewsStatus) || _.isUndefined(user.expensifyNewsStatus)) { + if (user?.expensifyNewsStatus === null || user?.expensifyNewsStatus === undefined) { Log.info('[Migrate Onyx] Skipped migration RenameExpensifyNewsStatus'); + // @ts-expect-error In that case we don't need to resolve anything return resolve(); } @@ -26,6 +26,7 @@ export default function () { isSubscribedToNewsletter: user.expensifyNewsStatus, }).then(() => { Log.info('[Migrate Onyx] Ran migration RenameExpensifyNewsStatus'); + // @ts-expect-error In that case we don't need to resolve anything resolve(); }); }, diff --git a/src/types/onyx/User.ts b/src/types/onyx/User.ts index f770b22b2272..097915490476 100644 --- a/src/types/onyx/User.ts +++ b/src/types/onyx/User.ts @@ -25,6 +25,7 @@ type User = { /** Whether the form is being submitted */ loading?: boolean; + expensifyNewsStatus?: boolean | null; }; export default User; From 4e9e40d959af817d302413ebfca5530c53e0ba89 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Fri, 15 Sep 2023 15:30:23 +0200 Subject: [PATCH 034/250] Add types --- src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts diff --git a/src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts b/src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts new file mode 100644 index 000000000000..6616a13d8d23 --- /dev/null +++ b/src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts @@ -0,0 +1,4 @@ +// to keep same behavior from before migration +// eslint-disable-next-line @typescript-eslint/naming-convention +type GetOSAndName = () => {device_name: string | undefined; os_version: string | undefined}; +export default GetOSAndName; From 807a802b29b8202757afc6326b1d5b56b9a9f584 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Fri, 15 Sep 2023 16:23:13 +0200 Subject: [PATCH 035/250] Migrate getOSAndName to typescript --- .../actions/Device/getDeviceInfo/getOSAndName/index.js | 4 ---- .../getOSAndName/{index.native.js => index.native.ts} | 9 +++++++-- .../actions/Device/getDeviceInfo/getOSAndName/index.ts | 10 ++++++++++ 3 files changed, 17 insertions(+), 6 deletions(-) delete mode 100644 src/libs/actions/Device/getDeviceInfo/getOSAndName/index.js rename src/libs/actions/Device/getDeviceInfo/getOSAndName/{index.native.js => index.native.ts} (61%) create mode 100644 src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts diff --git a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.js b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.js deleted file mode 100644 index 29b004412f64..000000000000 --- a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.js +++ /dev/null @@ -1,4 +0,0 @@ -// Don't import this file with '* as Device'. It's known to make VSCode IntelliSense crash. -import {getOSAndName} from 'expensify-common/lib/Device'; - -export default getOSAndName; diff --git a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.js b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.ts similarity index 61% rename from src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.js rename to src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.ts index 11d59abea1f1..455487d056f2 100644 --- a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.js +++ b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.ts @@ -1,11 +1,16 @@ import Str from 'expensify-common/lib/str'; import RNDeviceInfo from 'react-native-device-info'; +import GetOSAndName from './types'; -export default function getOSAndName() { +const getOSAndName: GetOSAndName = () => { const deviceName = RNDeviceInfo.getDeviceNameSync(); const prettyName = `${Str.UCFirst(RNDeviceInfo.getManufacturerSync() || '')} ${deviceName}`; return { + // eslint-disable-next-line @typescript-eslint/naming-convention device_name: RNDeviceInfo.isEmulatorSync() ? `Emulator - ${prettyName}` : prettyName, + // eslint-disable-next-line @typescript-eslint/naming-convention os_version: RNDeviceInfo.getSystemVersion(), }; -} +}; + +export default getOSAndName; diff --git a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts new file mode 100644 index 000000000000..5155fc07afb2 --- /dev/null +++ b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts @@ -0,0 +1,10 @@ +import {getOSAndName as libGetOSAndName} from 'expensify-common/lib/Device'; +import GetOSAndName from './types'; + +const getOSAndName: GetOSAndName = () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const {device_name, os_version} = libGetOSAndName(); + // eslint-disable-next-line @typescript-eslint/naming-convention + return {device_name, os_version}; +}; +export default getOSAndName; From e052a02f65675d2a98e1632aa923fa44802194f9 Mon Sep 17 00:00:00 2001 From: Dustin Stringer Date: Fri, 15 Sep 2023 10:34:55 -0400 Subject: [PATCH 036/250] Fix: portion of text shown when changing IOU value --- src/components/TextInput/BaseTextInput.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 9d122fb7ccf1..7487efe4c3eb 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -398,11 +398,10 @@ function BaseTextInput(props) { This Text component is intentionally positioned out of the screen. */} {(props.autoGrow || props.autoGrowHeight) && ( - // Add +2 to width so that the first digit of amount do not cut off on mWeb - https://github.com/Expensify/App/issues/8158. { - setTextInputWidth(e.nativeEvent.layout.width + 2); + setTextInputWidth(e.nativeEvent.layout.width); setTextInputHeight(e.nativeEvent.layout.height); }} > From 3c9fbf791b3244f21ab7452aa2471d99db059ea3 Mon Sep 17 00:00:00 2001 From: VH Date: Fri, 15 Sep 2023 22:54:57 +0700 Subject: [PATCH 037/250] Use preferredLocale from Onyx because it's not part of sign in form --- .../ValidateCode/ValidateCodeModal.js | 2 +- src/libs/actions/Session/index.js | 17 ++++++++--------- src/pages/ValidateLoginPage/index.js | 5 +---- src/pages/ValidateLoginPage/index.website.js | 4 +--- .../ValidateCodeForm/BaseValidateCodeForm.js | 11 +++-------- 5 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/components/ValidateCode/ValidateCodeModal.js b/src/components/ValidateCode/ValidateCodeModal.js index eabb21eea4a9..ceebc54a47af 100644 --- a/src/components/ValidateCode/ValidateCodeModal.js +++ b/src/components/ValidateCode/ValidateCodeModal.js @@ -39,7 +39,7 @@ const defaultProps = { }; function ValidateCodeModal(props) { - const signInHere = useCallback(() => Session.signInWithValidateCode(props.accountID, props.code, props.preferredLocale), [props.accountID, props.code, props.preferredLocale]); + const signInHere = useCallback(() => Session.signInWithValidateCode(props.accountID, props.code), [props.accountID, props.code]); return ( diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index b250c35cf664..117a092c3875 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -45,10 +45,10 @@ Onyx.connect({ callback: (val) => (credentials = val || {}), }); -let nvpPreferredLocale; +let preferredLocale; Onyx.connect({ key: ONYXKEYS.NVP_PREFERRED_LOCALE, - callback: (val) => (nvpPreferredLocale = val), + callback: (val) => (preferredLocale = val), }); /** @@ -260,7 +260,7 @@ function beginSignIn(login) { */ function beginAppleSignIn(idToken) { const {optimisticData, successData, failureData} = signInAttemptState(); - API.write('SignInWithApple', {idToken, preferredLocale: nvpPreferredLocale}, {optimisticData, successData, failureData}); + API.write('SignInWithApple', {idToken, preferredLocale}, {optimisticData, successData, failureData}); } /** @@ -271,7 +271,7 @@ function beginAppleSignIn(idToken) { */ function beginGoogleSignIn(token) { const {optimisticData, successData, failureData} = signInAttemptState(); - API.write('SignInWithGoogle', {token, preferredLocale: nvpPreferredLocale}, {optimisticData, successData, failureData}); + API.write('SignInWithGoogle', {token, preferredLocale}, {optimisticData, successData, failureData}); } /** @@ -327,9 +327,8 @@ function signInWithShortLivedAuthToken(email, authToken) { * * @param {String} validateCode 6 digit code required for login * @param {String} [twoFactorAuthCode] - * @param {String} [preferredLocale] Indicates which language to use when the user lands in the app */ -function signIn(validateCode, twoFactorAuthCode, preferredLocale = CONST.LOCALES.DEFAULT) { +function signIn(validateCode, twoFactorAuthCode) { const optimisticData = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -386,7 +385,7 @@ function signIn(validateCode, twoFactorAuthCode, preferredLocale = CONST.LOCALES }); } -function signInWithValidateCode(accountID, code, preferredLocale = CONST.LOCALES.DEFAULT, twoFactorAuthCode = '') { +function signInWithValidateCode(accountID, code, twoFactorAuthCode = '') { // If this is called from the 2fa step, get the validateCode directly from onyx // instead of the one passed from the component state because the state is changing when this method is called. const validateCode = twoFactorAuthCode ? credentials.validateCode : code; @@ -462,8 +461,8 @@ function signInWithValidateCode(accountID, code, preferredLocale = CONST.LOCALES }); } -function signInWithValidateCodeAndNavigate(accountID, validateCode, preferredLocale = CONST.LOCALES.DEFAULT, twoFactorAuthCode = '') { - signInWithValidateCode(accountID, validateCode, preferredLocale, twoFactorAuthCode); +function signInWithValidateCodeAndNavigate(accountID, validateCode, twoFactorAuthCode = '') { + signInWithValidateCode(accountID, validateCode, twoFactorAuthCode); Navigation.navigate(ROUTES.HOME); } diff --git a/src/pages/ValidateLoginPage/index.js b/src/pages/ValidateLoginPage/index.js index 561c8512ca3d..0af978172822 100644 --- a/src/pages/ValidateLoginPage/index.js +++ b/src/pages/ValidateLoginPage/index.js @@ -6,7 +6,6 @@ import {propTypes as validateLinkPropTypes, defaultProps as validateLinkDefaultP import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; import ONYXKEYS from '../../ONYXKEYS'; import * as Session from '../../libs/actions/Session'; -import useLocalize from '../../hooks/useLocalize'; import Navigation from '../../libs/Navigation/Navigation'; const propTypes = { @@ -35,8 +34,6 @@ const defaultProps = { }; function ValidateLoginPage(props) { - const {preferredLocale} = useLocalize(); - useEffect(() => { const accountID = lodashGet(props.route.params, 'accountID', ''); const validateCode = lodashGet(props.route.params, 'validateCode', ''); @@ -46,7 +43,7 @@ function ValidateLoginPage(props) { // because we don't want to block the user with the interstitial page. Navigation.goBack(false); } else { - Session.signInWithValidateCodeAndNavigate(accountID, validateCode, preferredLocale); + Session.signInWithValidateCodeAndNavigate(accountID, validateCode); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/pages/ValidateLoginPage/index.website.js b/src/pages/ValidateLoginPage/index.website.js index 323779a7d420..4ac12b3193f3 100644 --- a/src/pages/ValidateLoginPage/index.website.js +++ b/src/pages/ValidateLoginPage/index.website.js @@ -7,7 +7,6 @@ import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndica import ValidateCodeModal from '../../components/ValidateCode/ValidateCodeModal'; import ONYXKEYS from '../../ONYXKEYS'; import * as Session from '../../libs/actions/Session'; -import useLocalize from '../../hooks/useLocalize'; import ExpiredValidateCodeModal from '../../components/ValidateCode/ExpiredValidateCodeModal'; import Navigation from '../../libs/Navigation/Navigation'; import CONST from '../../CONST'; @@ -49,7 +48,6 @@ const defaultProps = { }; function ValidateLoginPage(props) { - const {preferredLocale} = useLocalize(); const login = lodashGet(props, 'credentials.login', null); const autoAuthState = lodashGet(props, 'session.autoAuthState', CONST.AUTO_AUTH_STATE.NOT_STARTED); const accountID = lodashGet(props.route.params, 'accountID', ''); @@ -71,7 +69,7 @@ function ValidateLoginPage(props) { } // The user has initiated the sign in process on the same browser, in another tab. - Session.signInWithValidateCode(accountID, validateCode, preferredLocale); + Session.signInWithValidateCode(accountID, validateCode); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js index 51cb287f9564..c38e4dd3c4dd 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js @@ -51,9 +51,6 @@ const propTypes = { authToken: PropTypes.string, }), - /** Indicates which locale the user currently has selected */ - preferredLocale: PropTypes.string, - /** Information about the network */ network: networkPropTypes.isRequired, @@ -69,7 +66,6 @@ const defaultProps = { session: { authToken: null, }, - preferredLocale: CONST.LOCALES.DEFAULT, }; function BaseValidateCodeForm(props) { @@ -228,11 +224,11 @@ function BaseValidateCodeForm(props) { const accountID = lodashGet(props.credentials, 'accountID'); if (accountID) { - Session.signInWithValidateCode(accountID, validateCode, props.preferredLocale, twoFactorAuthCode); + Session.signInWithValidateCode(accountID, validateCode, twoFactorAuthCode); } else { - Session.signIn(validateCode, twoFactorAuthCode, props.preferredLocale); + Session.signIn(validateCode, twoFactorAuthCode); } - }, [props.account, props.credentials, props.preferredLocale, twoFactorAuthCode, validateCode]); + }, [props.account, props.credentials, twoFactorAuthCode, validateCode]); return ( <> @@ -323,7 +319,6 @@ export default compose( withOnyx({ account: {key: ONYXKEYS.ACCOUNT}, credentials: {key: ONYXKEYS.CREDENTIALS}, - preferredLocale: {key: ONYXKEYS.NVP_PREFERRED_LOCALE}, session: {key: ONYXKEYS.SESSION}, }), withNetwork(), From d385296c394ec73967850e0e42f5ddd5ff537564 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Fri, 15 Sep 2023 18:11:58 +0200 Subject: [PATCH 038/250] Bump to 3.5.2 to fix release crash --- ios/Podfile.lock | 4 ++-- package-lock.json | 14 +++++++------- package.json | 6 +++--- ...1.patch => react-native-reanimated+3.5.2.patch} | 0 4 files changed, 12 insertions(+), 12 deletions(-) rename patches/{react-native-reanimated+3.5.1.patch => react-native-reanimated+3.5.2.patch} (100%) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 1b39c43809f6..1d20b93a3a39 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.5.1): + - RNReanimated (3.5.2): - DoubleConversion - FBLazyVector - glog @@ -1298,7 +1298,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: 99aa8c96151abbc2d7e737a56ec62aca709f0c92 + RNReanimated: 2491645f0883526f4470d8b5c761308709ba31f8 RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d diff --git a/package-lock.json b/package-lock.json index 9ca93346d61f..bfb5ad3518e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,7 +99,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "^3.5.1", + "react-native-reanimated": "^3.5.2", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", @@ -40696,9 +40696,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.1.tgz", - "integrity": "sha512-ZBTOKibTn1IR5IaoQkpPCibuao5SjXR6Pzx+KHM50wrvBnL1PecsnQjmL2VEj8hbwshrzgRGgGt1XM82DKrykw==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.2.tgz", + "integrity": "sha512-Uv9imJ6ZC7F/tTSpjjfo/0AZlw19Lag63+MUqF6p483LOoRkYtYP3JmtVV402mQWfhL1LPMeyAu/1spRjPKCCQ==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -76177,9 +76177,9 @@ "requires": {} }, "react-native-reanimated": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.1.tgz", - "integrity": "sha512-ZBTOKibTn1IR5IaoQkpPCibuao5SjXR6Pzx+KHM50wrvBnL1PecsnQjmL2VEj8hbwshrzgRGgGt1XM82DKrykw==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.2.tgz", + "integrity": "sha512-Uv9imJ6ZC7F/tTSpjjfo/0AZlw19Lag63+MUqF6p483LOoRkYtYP3JmtVV402mQWfhL1LPMeyAu/1spRjPKCCQ==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", diff --git a/package.json b/package.json index 3fcbe801e47a..48e9c878dd44 100644 --- a/package.json +++ b/package.json @@ -61,9 +61,9 @@ "@formatjs/intl-pluralrules": "^5.2.2", "@gorhom/portal": "^1.0.14", "@invertase/react-native-apple-authentication": "^2.2.2", - "@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52", "@kie/act-js": "^2.0.1", "@kie/mock-github": "^1.0.0", + "@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52", "@onfido/react-native-sdk": "7.4.0", "@react-native-async-storage/async-storage": "^1.17.10", "@react-native-camera-roll/camera-roll": "5.4.0", @@ -81,9 +81,9 @@ "@react-navigation/stack": "6.3.16", "@react-ng/bounds-observer": "^0.2.1", "@rnmapbox/maps": "^10.0.11", + "@types/node": "^18.14.0", "@ua/react-native-airship": "^15.2.6", "awesome-phonenumber": "^5.4.0", - "@types/node": "^18.14.0", "babel-plugin-transform-remove-console": "^6.9.4", "babel-polyfill": "^6.26.0", "canvas-size": "^1.2.6", @@ -141,7 +141,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "^3.5.1", + "react-native-reanimated": "^3.5.2", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", diff --git a/patches/react-native-reanimated+3.5.1.patch b/patches/react-native-reanimated+3.5.2.patch similarity index 100% rename from patches/react-native-reanimated+3.5.1.patch rename to patches/react-native-reanimated+3.5.2.patch From 1e2afb2362be1f8f4d821163fd10eac79e1457f3 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Fri, 15 Sep 2023 18:49:55 +0200 Subject: [PATCH 039/250] Remove autogenerated imports in patch --- patches/react-native-reanimated+3.5.2.patch | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/patches/react-native-reanimated+3.5.2.patch b/patches/react-native-reanimated+3.5.2.patch index 69c8f7028a58..c509e4c4cd2e 100644 --- a/patches/react-native-reanimated+3.5.2.patch +++ b/patches/react-native-reanimated+3.5.2.patch @@ -1,3 +1,44 @@ +diff --git a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js +index 0027008..2aea2ff 100644 +--- a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js ++++ b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js +@@ -1,15 +1,15 @@ + import './publicGlobals'; +-export { runOnJS, runOnUI, createWorkletRuntime, WorkletRuntime, makeMutable, makeShareableCloneRecursive, isReanimated3, isConfigured, enableLayoutAnimations, getViewProp } from './core'; +-export { useAnimatedProps, useEvent, useHandler, useWorkletCallback, useSharedValue, useReducedMotion, useAnimatedStyle, useAnimatedGestureHandler, GestureHandlers, useAnimatedReaction, AnimatedRef, useAnimatedRef, useAnimatedScrollHandler, ScrollHandler, ScrollHandlers, useDerivedValue, DerivedValue, useAnimatedSensor, useFrameCallback, FrameCallback, useAnimatedKeyboard, useScrollViewOffset } from './hook'; +-export { DelayAnimation, RepeatAnimation, SequenceAnimation, StyleLayoutAnimation, cancelAnimation, defineAnimation, withTiming, WithTimingConfig, TimingAnimation, withSpring, WithSpringConfig, SpringAnimation, withDecay, WithDecayConfig, DecayAnimation, withDelay, withRepeat, withSequence } from './animation'; +-export { Extrapolation, ExtrapolationConfig, ExtrapolationType, interpolate, clamp } from './interpolation'; +-export { Extrapolate, InterpolationOptions, interpolateColor, ColorSpace, InterpolateConfig, useInterpolateConfig, InterpolateRGB, InterpolateHSV } from './interpolateColor'; +-export { EasingFunction, EasingFn, EasingFunctionFactory, EasingFactoryFn, Easing } from './Easing'; ++export { runOnJS, runOnUI, createWorkletRuntime, makeMutable, makeShareableCloneRecursive, isReanimated3, isConfigured, enableLayoutAnimations, getViewProp } from './core'; ++export { useAnimatedProps, useEvent, useHandler, useWorkletCallback, useSharedValue, useReducedMotion, useAnimatedStyle, useAnimatedGestureHandler, useAnimatedReaction, useAnimatedRef, useAnimatedScrollHandler, useDerivedValue, useAnimatedSensor, useFrameCallback, useAnimatedKeyboard, useScrollViewOffset } from './hook'; ++export { cancelAnimation, defineAnimation, withTiming, withSpring, withDecay, withDelay, withRepeat, withSequence } from './animation'; ++export { interpolate, clamp } from './interpolation'; ++export { Extrapolate, interpolateColor, useInterpolateConfig } from './interpolateColor'; ++export { Easing } from './Easing'; + export { measure, dispatchCommand, scrollTo, setGestureState } from './NativeMethods'; + export { setNativeProps } from './SetNativeProps'; +-export { isColor, processColor, ParsedColorArray, convertToRGBA } from './Colors'; ++export { isColor, processColor, convertToRGBA } from './Colors'; + export { createAnimatedPropAdapter } from './PropAdapters'; +-export { BaseAnimationBuilder, ComplexAnimationBuilder, Keyframe, LayoutAnimation, EntryAnimationsValues, ExitAnimationsValues, EntryExitAnimationFunction, LayoutAnimationsValues, LayoutAnimationFunction, ILayoutAnimationBuilder, IEntryExitAnimationBuilder, ++export { BaseAnimationBuilder, ComplexAnimationBuilder, Keyframe, + // Flip + FlipInXUp, FlipInYLeft, FlipInXDown, FlipInYRight, FlipInEasyX, FlipInEasyY, FlipOutXUp, FlipOutYLeft, FlipOutXDown, FlipOutYRight, FlipOutEasyX, FlipOutEasyY, + // Stretch +@@ -34,9 +34,7 @@ RollInLeft, RollInRight, RollOutLeft, RollOutRight, + Layout, LinearTransition, FadingTransition, SequencedTransition, JumpingTransition, CurvedTransition, EntryExitTransition, combineTransition, + // SET + SharedTransition, SharedTransitionType } from './layoutReanimation'; +-export { getRelativeCoords, ComponentCoords, isSharedValue } from './utils'; +-export { StyleProps, SharedValue, AnimatableValueObject, AnimatableValue, AnimationObject, Animation, SensorType, IOSReferenceFrame, SensorConfig, AnimatedSensor, AnimationCallback, Value3D, ValueRotation, InterfaceOrientation, KeyboardState, AnimatedKeyboardInfo, MeasuredDimensions, AnimatedKeyboardOptions, ReduceMotion } from './commonTypes'; +-export { FrameInfo } from './frameCallback'; ++export { getRelativeCoords, isSharedValue } from './utils'; ++export { SensorType, IOSReferenceFrame, InterfaceOrientation, KeyboardState, ReduceMotion } from './commonTypes'; + export { getUseOfValueInStyleWarning } from './pluginUtils'; +-export { withReanimatedTimer, advanceAnimationByTime, advanceAnimationByFrame, setUpTests, getAnimatedStyle } from './jestUtils'; + //# sourceMappingURL=index.js.map +\ No newline at end of file diff --git a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts index 4df2481..cca7f1a 100644 --- a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts From 0223dc59a7193af5c44003fc885be02676b0be0d Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Sat, 16 Sep 2023 00:03:40 -0400 Subject: [PATCH 040/250] add comment for matching the backend --- src/libs/ReportUtils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c95bf505879d..c88d0828b195 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1495,6 +1495,9 @@ function getProperSchemaForModifiedExpenseMessage(newValue, oldValue, valueName, /** * Get the report action message when expense has been modified. * + * ModifiedExpense::getNewDotComment in Web-Expensify should match this. + * If we change this function be sure to update the backend as well. + * * @param {Object} reportAction * @returns {String} */ From 8abc7dd30504483df5134224ec98f0e357b6b0a4 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 16 Sep 2023 16:28:19 +0800 Subject: [PATCH 041/250] use different border color for anonymous report footer --- src/components/AvatarWithDisplayName.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index a6c630b775f7..97ef5ac741f5 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -17,6 +17,7 @@ import DisplayNames from './DisplayNames'; import compose from '../libs/compose'; import * as OptionsListUtils from '../libs/OptionsListUtils'; import Text from './Text'; +import * as StyleUtils from '../styles/StyleUtils'; import ParentNavigationSubtitle from './ParentNavigationSubtitle'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import Navigation from '../libs/Navigation/Navigation'; @@ -90,6 +91,7 @@ function AvatarWithDisplayName(props) { 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 ? themeColors.highlightBG : themeColors.componentBG; return ( @@ -102,7 +104,7 @@ function AvatarWithDisplayName(props) { > {shouldShowSubscriptAvatar ? ( )} From 215ae1a062d04da93344e74823f9c883cfbc87e0 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Sun, 17 Sep 2023 19:52:05 +0200 Subject: [PATCH 042/250] [TS migration] Migrate 'PusherConnectionManager.js' lib to TypeScript --- ...nnectionManager.js => PusherConnectionManager.ts} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename src/libs/{PusherConnectionManager.js => PusherConnectionManager.ts} (86%) diff --git a/src/libs/PusherConnectionManager.js b/src/libs/PusherConnectionManager.ts similarity index 86% rename from src/libs/PusherConnectionManager.js rename to src/libs/PusherConnectionManager.ts index a391a4973fd4..557c0e024e9f 100644 --- a/src/libs/PusherConnectionManager.js +++ b/src/libs/PusherConnectionManager.ts @@ -1,4 +1,4 @@ -import lodashGet from 'lodash/get'; +import {ValueOf} from 'type-fest'; import * as Pusher from './Pusher/pusher'; import * as Session from './actions/Session'; import Log from './Log'; @@ -11,8 +11,8 @@ function init() { * current valid token to generate the signed auth response * needed to subscribe to Pusher channels. */ - Pusher.registerCustomAuthorizer((channel) => ({ - authorize: (socketID, callback) => { + Pusher.registerCustomAuthorizer((channel: {name: string}) => ({ + authorize: (socketID: string, callback: () => void) => { Session.authenticatePusher(socketID, channel.name, callback); }, })); @@ -20,11 +20,11 @@ function init() { /** * @params {string} eventName */ - Pusher.registerSocketEventCallback((eventName, error) => { + Pusher.registerSocketEventCallback((eventName: string, error: {type: ValueOf; data: {code: number}}) => { switch (eventName) { case 'error': { - const errorType = lodashGet(error, 'type'); - const code = lodashGet(error, 'data.code'); + const errorType = error?.type; + const code = error?.data?.code; if (errorType === CONST.ERROR.PUSHER_ERROR && code === 1006) { // 1006 code happens when a websocket connection is closed. There may or may not be a reason attached indicating why the connection was closed. // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5 From 9ed14a9f8a33dc4bfb3be1da98c55012269460cc Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Mon, 18 Sep 2023 14:34:06 +0800 Subject: [PATCH 043/250] fix selecting the wrong report action to notify for --- src/libs/ReportActionsUtils.js | 5 +++++ src/libs/actions/Report.js | 2 +- src/libs/actions/User.js | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index fde847bd9bfc..d02f10cbf123 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -630,6 +630,10 @@ function isReportActionAttachment(reportAction) { return _.has(reportAction, 'isAttachment') ? reportAction.isAttachment : isReportMessageAttachment(message); } +function isNotifiableReportAction(reportAction) { + return reportAction && _.contains([CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE], reportAction.actionName); +} + export { getSortedReportActions, getLastVisibleAction, @@ -668,4 +672,5 @@ export { isTaskAction, getAllReportActions, isReportActionAttachment, + isNotifiableReportAction, }; diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 4d984502ab71..4536fae1fe34 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1567,7 +1567,7 @@ function shouldShowReportActionNotification(reportID, action = null, isRemote = } // Only show notifications for supported types of report actions - if (action && !_.contains([CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE], action.actionName)) { + if (!ReportActionsUtils.isNotifiableReportAction(action)) { Log.info(`${tag} No notification because this action type is not supported`, false, {actionName: action.actionName}); return false; } diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 7482c13268e4..df7cf04abac5 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -531,8 +531,8 @@ function triggerNotifications(onyxUpdates) { const reportID = update.key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, ''); const reportActions = _.values(update.value); - const sortedReportActions = ReportActionsUtils.getSortedReportActions(reportActions); - Report.showReportActionNotification(reportID, _.last(sortedReportActions)); + const notifiableActions = _.filter(reportActions, (action) => ReportActionsUtils.isNotifiableReportAction(action)); + _.each(notifiableActions, (action) => Report.showReportActionNotification(reportID, action)); }); } From e93422ca0c9eb153e3f43f549ff3b191be8cd6c0 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 18 Sep 2023 09:10:29 +0200 Subject: [PATCH 044/250] Change DEFAULT_CLOSE_ACCOUNT_DATA --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index ced657b06e19..64c0872a38d9 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -735,7 +735,7 @@ const CONST = { }, DEFAULT_TIME_ZONE: {automatic: true, selected: 'America/Los_Angeles'}, DEFAULT_ACCOUNT_DATA: {errors: null, success: '', isLoading: false}, - DEFAULT_CLOSE_ACCOUNT_DATA: {errors: {}, success: '', isLoading: false}, + DEFAULT_CLOSE_ACCOUNT_DATA: {errors: null, success: '', isLoading: false}, FORMS: { LOGIN_FORM: 'LoginForm', VALIDATE_CODE_FORM: 'ValidateCodeForm', From eceb13fe9c214cec0e66acdb5fccc8ad2347bf55 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Mon, 18 Sep 2023 18:07:28 +0800 Subject: [PATCH 045/250] suppress false positives --- src/libs/ReportActionsUtils.js | 1 + src/libs/actions/User.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index d02f10cbf123..bd64158184ed 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -630,6 +630,7 @@ function isReportActionAttachment(reportAction) { return _.has(reportAction, 'isAttachment') ? reportAction.isAttachment : isReportMessageAttachment(message); } +// eslint-disable-next-line rulesdir/no-negated-variables function isNotifiableReportAction(reportAction) { return reportAction && _.contains([CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, CONST.REPORT.ACTIONS.TYPE.IOU, CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE], reportAction.actionName); } diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index df7cf04abac5..d629b4ae0fbf 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -531,6 +531,8 @@ function triggerNotifications(onyxUpdates) { const reportID = update.key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, ''); const reportActions = _.values(update.value); + + // eslint-disable-next-line rulesdir/no-negated-variables const notifiableActions = _.filter(reportActions, (action) => ReportActionsUtils.isNotifiableReportAction(action)); _.each(notifiableActions, (action) => Report.showReportActionNotification(reportID, action)); }); From ecb746cf287dd0fdc20154011957f73bd997e3d2 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Fri, 8 Sep 2023 06:37:22 +0530 Subject: [PATCH 046/250] map loding when online --- src/components/DistanceRequest.js | 5 ++++- src/setup/platformSetup/index.website.js | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/DistanceRequest.js b/src/components/DistanceRequest.js index 966f700e25d4..43c6ea3a294e 100644 --- a/src/components/DistanceRequest.js +++ b/src/components/DistanceRequest.js @@ -154,9 +154,12 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken, const scrollContainerMaxHeight = variables.optionRowHeight * MAX_WAYPOINTS_TO_DISPLAY + halfMenuItemHeight; useEffect(() => { + if (isOffline || mapboxAccessToken.token) { + return; + } MapboxToken.init(); return MapboxToken.stop; - }, []); + }, [mapboxAccessToken.token, isOffline]); useEffect(() => { if (!iou.transactionID || !_.isEmpty(waypoints)) { diff --git a/src/setup/platformSetup/index.website.js b/src/setup/platformSetup/index.website.js index e859005c9abe..0b3a45b0b3ba 100644 --- a/src/setup/platformSetup/index.website.js +++ b/src/setup/platformSetup/index.website.js @@ -3,6 +3,10 @@ import {AppRegistry} from 'react-native'; // This is a polyfill for InternetExplorer to support the modern KeyboardEvent.key and KeyboardEvent.code instead of KeyboardEvent.keyCode import 'shim-keyboard-event-key'; +// load all chunk file map when online +import 'react-map-gl'; +import 'mapbox-gl/dist/mapbox-gl.css'; + import checkForUpdates from '../../libs/checkForUpdates'; import Config from '../../CONFIG'; import DateUtils from '../../libs/DateUtils'; From a2fe761450e346bd7f33d0dfdeafe03d7bc554bc Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Fri, 8 Sep 2023 07:39:15 +0530 Subject: [PATCH 047/250] load chunk on desktop --- src/setup/platformSetup/index.desktop.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/setup/platformSetup/index.desktop.js b/src/setup/platformSetup/index.desktop.js index a1585065e142..cf9e591935ce 100644 --- a/src/setup/platformSetup/index.desktop.js +++ b/src/setup/platformSetup/index.desktop.js @@ -4,6 +4,9 @@ import LocalNotification from '../../libs/Notification/LocalNotification'; import * as KeyboardShortcuts from '../../libs/actions/KeyboardShortcuts'; import DateUtils from '../../libs/DateUtils'; import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS'; +// load all chunk file map when online +import 'react-map-gl'; +import 'mapbox-gl/dist/mapbox-gl.css'; export default function () { AppRegistry.runApplication(Config.APP_NAME, { From bd340bbaa81accd87eb88ad44f04f631389a7ae4 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Tue, 12 Sep 2023 09:24:54 +0530 Subject: [PATCH 048/250] map view updated --- src/components/MapView/MapView.web.tsx | 1 + src/setup/platformSetup/index.desktop.js | 3 --- src/setup/platformSetup/index.website.js | 4 ---- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/components/MapView/MapView.web.tsx b/src/components/MapView/MapView.web.tsx index d1b26df8b00e..a95ed6aa9e47 100644 --- a/src/components/MapView/MapView.web.tsx +++ b/src/components/MapView/MapView.web.tsx @@ -66,6 +66,7 @@ const MapView = forwardRef( > Date: Mon, 18 Sep 2023 07:32:52 +0530 Subject: [PATCH 049/250] update module import --- src/components/MapView/MapView.web.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MapView/MapView.web.tsx b/src/components/MapView/MapView.web.tsx index a95ed6aa9e47..fc2c97bd8e80 100644 --- a/src/components/MapView/MapView.web.tsx +++ b/src/components/MapView/MapView.web.tsx @@ -6,6 +6,7 @@ import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useState} from 'react'; import {View} from 'react-native'; import Map, {MapRef, Marker} from 'react-map-gl'; +import mapboxgl from 'mapbox-gl'; import responder from './responder'; import utils from './utils'; @@ -66,7 +67,7 @@ const MapView = forwardRef( > Date: Mon, 18 Sep 2023 22:31:34 +0530 Subject: [PATCH 050/250] move logic to maptoken --- src/components/DistanceRequest.js | 5 +---- src/libs/actions/MapboxToken.js | 15 +++++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/components/DistanceRequest.js b/src/components/DistanceRequest.js index 43c6ea3a294e..966f700e25d4 100644 --- a/src/components/DistanceRequest.js +++ b/src/components/DistanceRequest.js @@ -154,12 +154,9 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken, const scrollContainerMaxHeight = variables.optionRowHeight * MAX_WAYPOINTS_TO_DISPLAY + halfMenuItemHeight; useEffect(() => { - if (isOffline || mapboxAccessToken.token) { - return; - } MapboxToken.init(); return MapboxToken.stop; - }, [mapboxAccessToken.token, isOffline]); + }, []); useEffect(() => { if (!iou.transactionID || !_.isEmpty(waypoints)) { diff --git a/src/libs/actions/MapboxToken.js b/src/libs/actions/MapboxToken.js index 2ce56eb1a11e..fc6f351996e4 100644 --- a/src/libs/actions/MapboxToken.js +++ b/src/libs/actions/MapboxToken.js @@ -46,7 +46,7 @@ const hasTokenExpired = () => moment().isAfter(currentToken.expiration); const clearToken = () => { console.debug('[MapboxToken] Deleting the token stored in Onyx'); - + currentToken = null; // Use Onyx.set() to delete the key from Onyx, which will trigger a new token to be retrieved from the API. Onyx.set(ONYXKEYS.MAPBOX_ACCESS_TOKEN, null); }; @@ -126,9 +126,16 @@ const init = () => { callback: (val) => { // When the network reconnects, check if the token has expired. If it has, then clearing the token will // trigger the fetch of a new one - if (network && network.isOffline && val && !val.isOffline && !isCurrentlyFetchingToken && hasTokenExpired()) { - console.debug('[MapboxToken] Token is expired after network came online'); - clearToken(); + if (network && network.isOffline && val && !val.isOffline) { + if (_.isEmpty(currentToken)) { + console.debug('[MapboxToken] Token does not exist so fetching one'); + // eslint-disable-next-line rulesdir/no-multiple-api-calls + API.read('GetMapboxAccessToken'); + isCurrentlyFetchingToken = true; + } else if (!isCurrentlyFetchingToken && hasTokenExpired()) { + console.debug('[MapboxToken] Token is expired after network came online'); + clearToken(); + } } network = val; }, From 5b7f27e0f993e742b707107ea5fa47df29c6b8fc Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Tue, 19 Sep 2023 08:41:56 +0530 Subject: [PATCH 051/250] remove unwanted code --- src/libs/actions/MapboxToken.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/MapboxToken.js b/src/libs/actions/MapboxToken.js index fc6f351996e4..c0d7010b383c 100644 --- a/src/libs/actions/MapboxToken.js +++ b/src/libs/actions/MapboxToken.js @@ -46,7 +46,6 @@ const hasTokenExpired = () => moment().isAfter(currentToken.expiration); const clearToken = () => { console.debug('[MapboxToken] Deleting the token stored in Onyx'); - currentToken = null; // Use Onyx.set() to delete the key from Onyx, which will trigger a new token to be retrieved from the API. Onyx.set(ONYXKEYS.MAPBOX_ACCESS_TOKEN, null); }; From 64d17c11376dcf05f2c7930108fa2bb4208df72c Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Tue, 19 Sep 2023 08:42:30 +0530 Subject: [PATCH 052/250] fix(#26046): cache detecting logic moved to Image component. Signed-off-by: Krishna Gupta --- src/components/Image/index.js | 29 +++++++++++++++++++--- src/components/ImageWithSizeCalculation.js | 26 ++----------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 7434c16c6491..f05c60186a2a 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,4 +1,4 @@ -import React, {useEffect, useMemo} from 'react'; +import React, {useEffect, useMemo, useRef, useState} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; @@ -8,7 +8,10 @@ import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; function Image(props) { - const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; + const {source: propsSource, isAuthTokenRequired, onLoad, session, onLoadStart = () => {}, onLoadEnd = () => {}} = props; + + const [isLoading, setIsLoading] = useState(false); + const isLoadedRef = useRef(null); /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. @@ -41,14 +44,34 @@ function Image(props) { }); }, [onLoad, source]); + /** Delay the loader to detect whether the image is being loaded from the cache or the internet. */ + useEffect(() => { + if (isLoadedRef.current || !isLoading) { + return; + } + const timeout = _.delay(() => { + if (!isLoading || isLoadedRef.current) { + return; + } + onLoadStart(); + }, 200); + return () => clearTimeout(timeout); + }, [isLoading, onLoadStart]); + // Omit the props which the underlying RNImage won't use - const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); + const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired', 'onLoadStart', 'onLoadEnd']); return ( setIsLoading(true)} + onLoadEnd={() => { + onLoadEnd(); + setIsLoading(false); + isLoadedRef.current = true; + }} /> ); } diff --git a/src/components/ImageWithSizeCalculation.js b/src/components/ImageWithSizeCalculation.js index 6aa87d07f23e..57b933380b88 100644 --- a/src/components/ImageWithSizeCalculation.js +++ b/src/components/ImageWithSizeCalculation.js @@ -1,5 +1,4 @@ -import _ from 'underscore'; -import React, {useState, useRef, useEffect} from 'react'; +import React, {useState} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import Log from '../libs/Log'; @@ -39,8 +38,6 @@ const defaultProps = { * */ function ImageWithSizeCalculation(props) { - const isLoadedRef = useRef(null); - const [isImageCached, setIsImageCached] = useState(true); const [isLoading, setIsLoading] = useState(false); const onError = () => { @@ -48,27 +45,12 @@ function ImageWithSizeCalculation(props) { }; const imageLoadedSuccessfully = (event) => { - isLoadedRef.current = true; props.onMeasure({ width: event.nativeEvent.width, height: event.nativeEvent.height, }); }; - /** Delay the loader to detect whether the image is being loaded from the cache or the internet. */ - useEffect(() => { - if (isLoadedRef.current || !isLoading) { - return; - } - const timeout = _.delay(() => { - if (!isLoading || isLoadedRef.current) { - return; - } - setIsImageCached(false); - }, 200); - return () => clearTimeout(timeout); - }, [isLoading]); - return ( { - if (isLoadedRef.current || isLoading) { - return; - } setIsLoading(true); }} onLoadEnd={() => { setIsLoading(false); - setIsImageCached(true); }} onError={onError} onLoad={imageLoadedSuccessfully} /> - {isLoading && !isImageCached && } + {isLoading && } ); } From f5eb8354061e49631d21d2f5266f65ae44cb7507 Mon Sep 17 00:00:00 2001 From: Dustin Stringer Date: Tue, 19 Sep 2023 00:35:39 -0400 Subject: [PATCH 053/250] Fixed rendering of BaseTextInput using autoGrow --- src/components/TextInput/BaseTextInput.js | 5 ++++- src/styles/styles.js | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 0fd2ad935f4c..cce8bda03591 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -399,10 +399,13 @@ function BaseTextInput(props) { This Text component is intentionally positioned out of the screen. */} {(props.autoGrow || props.autoGrowHeight) && ( + // Add +32 to width so that text is not cut off due to the cursor or when changing the value + // https://github.com/Expensify/App/issues/8158 + // https://github.com/Expensify/App/issues/26628 { - setTextInputWidth(e.nativeEvent.layout.width); + setTextInputWidth(e.nativeEvent.layout.width + 32); setTextInputHeight(e.nativeEvent.layout.height); }} > diff --git a/src/styles/styles.js b/src/styles/styles.js index 8ff1731945b2..46240542cede 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2680,6 +2680,9 @@ const styles = (theme) => ({ fontSize: variables.iouAmountTextSize, color: theme.heading, lineHeight: variables.inputHeight, + // This margin counteracts the additional size given to the autoGrow text in BaseTextInput.js + // It fixes issue https://github.com/Expensify/App/issues/26628 + marginLeft: 32 }, iouAmountTextInput: addOutlineWidth( From bef2289446b6601643706cbd4fa3ccde16c9f27e Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Tue, 19 Sep 2023 12:27:40 +0530 Subject: [PATCH 054/250] fix(#26046): loader on top of carousel image. Signed-off-by: Krishna Gupta --- .../Pager/AttachmentCarouselPage.js | 39 ++++++++++++++----- src/components/Image/index.js | 7 +++- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js index b1a844e4172d..06827e00c8ad 100644 --- a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js +++ b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js @@ -1,5 +1,5 @@ /* eslint-disable es/no-optional-chaining */ -import React, {useContext, useEffect, useState} from 'react'; +import React, {useContext, useEffect, useRef, useState} from 'react'; import {ActivityIndicator, PixelRatio, StyleSheet, View} from 'react-native'; import PropTypes from 'prop-types'; import Image from '../../../Image'; @@ -46,13 +46,16 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI }, [initialIsActive]); const [initialActivePageLoad, setInitialActivePageLoad] = useState(isActive); - const [isImageLoading, setIsImageLoading] = useState(true); - const [showFallback, setShowFallback] = useState(isImageLoading); + const isImageLoaded = useRef(null); + const [isImageLoading, setIsImageLoading] = useState(false); + const [isFallbackLoading, setIsFallbackLoading] = useState(false); + const [showFallback, setShowFallback] = useState(true); // We delay hiding the fallback image while image transformer is still rendering useEffect(() => { - if (isImageLoading) setShowFallback(true); + if (isImageLoading || showFallback) setShowFallback(true); else setTimeout(() => setShowFallback(false), 100); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isImageLoading]); return ( @@ -73,8 +76,14 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI source={{uri: source}} style={dimensions == null ? undefined : {width: dimensions.imageWidth, height: dimensions.imageHeight}} isAuthTokenRequired={isAuthTokenRequired} - onLoadStart={() => setIsImageLoading(true)} - onLoadEnd={() => setIsImageLoading(false)} + onLoadStart={() => { + setIsImageLoading(true); + }} + onLoadEnd={() => { + setShowFallback(false); + setIsImageLoading(false); + isImageLoaded.current = true; + }} onLoad={(evt) => { const imageWidth = (evt.nativeEvent?.width || 0) / PixelRatio.get(); const imageHeight = (evt.nativeEvent?.height || 0) / PixelRatio.get(); @@ -100,8 +109,10 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI // On the initial render of the active page, the onLoadEnd event is never fired. // That's why we instead set isImageLoading to false in the onLoad event. if (initialActivePageLoad) { - setIsImageLoading(false); setInitialActivePageLoad(false); + setIsImageLoading(false); + setTimeout(() => setShowFallback(false), 100); + isImageLoaded.current = true; } }} /> @@ -110,12 +121,20 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI )} {/* Keep rendering the image without gestures as fallback while ImageTransformer is loading the image */} - {(!isActive || showFallback) && ( + {(showFallback || !isActive) && ( setIsImageLoading(true)} + onLoadStart={() => { + setIsImageLoading(true); + if (isImageLoaded.current) return; + setIsFallbackLoading(true); + }} + onLoadEnd={() => { + if (isImageLoaded.current) return; + setIsFallbackLoading(false); + }} onLoad={(evt) => { const imageWidth = evt.nativeEvent.width; const imageHeight = evt.nativeEvent.height; @@ -141,7 +160,7 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI )} {/* Show activity indicator while ImageTransfomer is still loading the image. */} - {isActive && isImageLoading && ( + {isActive && isFallbackLoading && !isImageLoaded.current && ( clearTimeout(timeout); - }, [isLoading, onLoadStart]); + }, [isLoading]); // Omit the props which the underlying RNImage won't use const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired', 'onLoadStart', 'onLoadEnd']); @@ -67,10 +67,13 @@ function Image(props) { {...forwardedProps} source={source} onLoadStart={() => setIsLoading(true)} + onLoad={() => { + isLoadedRef.current = true; + }} onLoadEnd={() => { - onLoadEnd(); setIsLoading(false); isLoadedRef.current = true; + onLoadEnd(); }} /> ); From ca1dbc809ed85277cd47cac7c2d173ebee6bebfe Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 19 Sep 2023 15:27:57 +0700 Subject: [PATCH 055/250] fix: 27252 Profile pic gets removed in offline mode --- src/components/Avatar.js | 6 +++--- src/components/AvatarWithImagePicker.js | 2 +- src/components/AvatarWithIndicator.js | 7 ++++++- src/components/LHNOptionsList/OptionRowLHNData.js | 1 + src/components/MentionSuggestions.js | 1 + src/components/MultipleAvatars.js | 6 +++++- src/components/RoomHeaderAvatars.js | 2 ++ src/components/SelectionList/UserListItem.js | 1 + src/components/SubscriptAvatar.js | 2 ++ src/components/UserDetailsTooltip/index.web.js | 1 + src/components/avatarPropTypes.js | 1 + src/components/menuItemPropTypes.js | 2 +- src/libs/ReportUtils.js | 8 ++++++++ src/libs/actions/PersonalDetails.js | 1 + src/pages/DetailsPage.js | 1 + src/pages/ProfilePage.js | 2 ++ .../home/report/ReportActionCompose/SuggestionMention.js | 1 + src/pages/home/report/ReportActionItemSingle.js | 3 ++- src/pages/home/sidebar/PressableAvatarWithIndicator.js | 1 + src/pages/settings/InitialSettingsPage.js | 1 + src/pages/settings/Profile/LoungeAccessPage.js | 1 + src/pages/settings/Profile/ProfilePage.js | 3 ++- 22 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index b96e60dd56d1..ac206b971a6e 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -40,7 +40,7 @@ const propTypes = { /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. * If the avatar is type === workspace, this fallback icon will be ignored and decided based on the name prop. */ - fallbackIcon: PropTypes.func, + fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), /** Denotes whether it is an avatar or a workspace avatar */ type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]), @@ -88,7 +88,7 @@ function Avatar(props) { pointerEvents="none" style={props.containerStyles} > - {_.isFunction(props.source) || imageError ? ( + {_.isFunction(props.source) || (imageError && _.isFunction(fallbackAvatar)) ? ( setImageError(true)} /> diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 3a43ede5a8f4..2b72e7600dc3 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -60,7 +60,7 @@ const propTypes = { size: PropTypes.oneOf([CONST.AVATAR_SIZE.LARGE, CONST.AVATAR_SIZE.DEFAULT]), /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon: PropTypes.func, + fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), /** Denotes whether it is an avatar or a workspace avatar */ type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]), diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js index b59f67a45b7b..72f09ce7cfc2 100644 --- a/src/components/AvatarWithIndicator.js +++ b/src/components/AvatarWithIndicator.js @@ -6,6 +6,7 @@ import styles from '../styles/styles'; import Tooltip from './Tooltip'; import * as UserUtils from '../libs/UserUtils'; import Indicator from './Indicator'; +import * as Expensicons from './Icon/Expensicons'; const propTypes = { /** URL for the avatar */ @@ -13,17 +14,21 @@ const propTypes = { /** To show a tooltip on hover */ tooltipText: PropTypes.string, + + /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ + fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), }; const defaultProps = { tooltipText: '', + fallbackIcon: Expensicons.FallbackAvatar, }; function AvatarWithIndicator(props) { return ( - + diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 2c51d6332946..fe0506c7f55b 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -156,6 +156,7 @@ const personalDetailsSelector = (personalDetails) => firstName: personalData.firstName, status: personalData.status, avatar: UserUtils.getAvatar(personalData.avatar, personalData.accountID), + fallbackIcon: personalData.fallbackIcon }; return finalPersonalDetails; }, diff --git a/src/components/MentionSuggestions.js b/src/components/MentionSuggestions.js index 11df8a597ded..b3374279f66b 100644 --- a/src/components/MentionSuggestions.js +++ b/src/components/MentionSuggestions.js @@ -81,6 +81,7 @@ function MentionSuggestions(props) { name={item.icons[0].name} type={item.icons[0].type} fill={themeColors.success} + fallbackIcon={item.icons[0].fallbackIcon} /> @@ -184,6 +185,7 @@ function MultipleAvatars(props) { size={props.size} name={icon.name} type={icon.type} + fallbackIcon={icon.fallbackIcon} /> @@ -249,6 +251,7 @@ function MultipleAvatars(props) { imageStyles={[singleAvatarStyle]} name={props.icons[0].name} type={props.icons[0].type} + fallbackIcon={props.icons[0].fallbackIcon} /> @@ -270,6 +273,7 @@ function MultipleAvatars(props) { imageStyles={[singleAvatarStyle]} name={props.icons[1].name} type={props.icons[1].type} + fallbackIcon={props.icons[1].fallbackIcon} /> diff --git a/src/components/RoomHeaderAvatars.js b/src/components/RoomHeaderAvatars.js index af594dc2415a..92f294f056c7 100644 --- a/src/components/RoomHeaderAvatars.js +++ b/src/components/RoomHeaderAvatars.js @@ -49,6 +49,7 @@ function RoomHeaderAvatars(props) { size={CONST.AVATAR_SIZE.LARGE} name={props.icons[0].name} type={props.icons[0].type} + fallbackIcon={props.icons[0].fallbackIcon} /> )} @@ -93,6 +94,7 @@ function RoomHeaderAvatars(props) { containerStyles={[...iconStyle, StyleUtils.getAvatarBorderRadius(CONST.AVATAR_SIZE.LARGE_BORDERED, icon.type)]} name={icon.name} type={icon.type} + fallbackIcon={icon.fallbackIcon} /> )} diff --git a/src/components/SelectionList/UserListItem.js b/src/components/SelectionList/UserListItem.js index 014e0cf879a5..511dc16be636 100644 --- a/src/components/SelectionList/UserListItem.js +++ b/src/components/SelectionList/UserListItem.js @@ -25,6 +25,7 @@ function UserListItem({item, isFocused = false, showTooltip, onSelectRow, onDism source={lodashGet(item, 'avatar.source', '')} name={lodashGet(item, 'avatar.name', item.text)} type={lodashGet(item, 'avatar.type', CONST.ICON_TYPE_AVATAR)} + fallbackIcon={lodashGet(item, 'avatar.fallbackIcon')} /> ); diff --git a/src/components/SubscriptAvatar.js b/src/components/SubscriptAvatar.js index 038484e3f42d..81864d6e5af2 100644 --- a/src/components/SubscriptAvatar.js +++ b/src/components/SubscriptAvatar.js @@ -60,6 +60,7 @@ function SubscriptAvatar(props) { size={props.size || CONST.AVATAR_SIZE.DEFAULT} name={props.mainAvatar.name} type={props.mainAvatar.type} + fallbackIcon={props.mainAvatar.fallbackIcon} /> @@ -83,6 +84,7 @@ function SubscriptAvatar(props) { fill={themeColors.iconSuccessFill} name={props.secondaryAvatar.name} type={props.secondaryAvatar.type} + fallbackIcon={props.secondaryAvatar.fallbackIcon} /> diff --git a/src/components/UserDetailsTooltip/index.web.js b/src/components/UserDetailsTooltip/index.web.js index 5fdae15184ac..b6a987316141 100644 --- a/src/components/UserDetailsTooltip/index.web.js +++ b/src/components/UserDetailsTooltip/index.web.js @@ -48,6 +48,7 @@ function UserDetailsTooltip(props) { source={props.icon ? props.icon.source : UserUtils.getAvatar(userAvatar, userAccountID)} type={props.icon ? props.icon.type : CONST.ICON_TYPE_AVATAR} name={props.icon ? props.icon.name : userLogin} + fallbackIcon={lodashGet(props.icon,'fallbackIcon')} /> {title} diff --git a/src/components/avatarPropTypes.js b/src/components/avatarPropTypes.js index 12ee5c622b4f..a07de54ff481 100644 --- a/src/components/avatarPropTypes.js +++ b/src/components/avatarPropTypes.js @@ -6,4 +6,5 @@ export default PropTypes.shape({ type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]), name: PropTypes.string, id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), }); diff --git a/src/components/menuItemPropTypes.js b/src/components/menuItemPropTypes.js index 53216ab7cdc7..b233f8c951b1 100644 --- a/src/components/menuItemPropTypes.js +++ b/src/components/menuItemPropTypes.js @@ -98,7 +98,7 @@ const propTypes = { interactive: PropTypes.bool, /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon: PropTypes.func, + fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), /** Avatars to show on the right of the menu item */ floatRightAvatars: PropTypes.arrayOf(avatarPropTypes), diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 4b6512a543b0..8d1b5e4e18fe 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -924,6 +924,7 @@ function getIconsForParticipants(participants, personalDetails) { lodashGet(personalDetails, [accountID, 'displayName']) || lodashGet(personalDetails, [accountID, 'login'], ''), lodashGet(personalDetails, [accountID, 'firstName'], ''), avatarSource, + lodashGet(personalDetails, [accountID, 'fallBackIcon']), ]); } @@ -938,6 +939,7 @@ function getIconsForParticipants(participants, personalDetails) { source: sortedParticipantDetails[i][3], type: CONST.ICON_TYPE_AVATAR, name: sortedParticipantDetails[i][1], + fallBackIcon: sortedParticipantDetails[i][4] }; avatars.push(userIcon); } @@ -995,6 +997,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, id: parentReportAction.actorAccountID, type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'displayName'], ''), + fallbackIcon:lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']) }; return [memberIcon, workspaceIcon]; @@ -1009,6 +1012,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, source: UserUtils.getAvatar(lodashGet(personalDetails, [actorAccountID, 'avatar']), actorAccountID), name: actorDisplayName, type: CONST.ICON_TYPE_AVATAR, + fallbackIcon: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']) }; if (isWorkspaceThread(report)) { @@ -1023,6 +1027,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerAccountID, 'avatar']), report.ownerAccountID), type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''), + fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']) }; if (isWorkspaceTaskReport(report)) { @@ -1055,6 +1060,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, id: report.ownerAccountID, type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''), + fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']) }; return isExpenseReport(report) ? [memberIcon, workspaceIcon] : [workspaceIcon, memberIcon]; } @@ -1064,6 +1070,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, id: report.managerID, type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.managerID, 'displayName'], ''), + fallbackIcon: lodashGet(personalDetails, [report.managerID, 'fallbackIcon']) }; const ownerIcon = { @@ -1071,6 +1078,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerAccountID, 'avatar']), report.ownerAccountID), type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''), + fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']) }; return isPayer ? [managerIcon, ownerIcon] : [ownerIcon, managerIcon]; diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index dd80992e64a4..1c81f2d1be51 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -429,6 +429,7 @@ function updateAvatar(file) { avatar: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, originalFileName: null, }, + fallbackIcon: file.uri }, }, }, diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index 7873c4daa00c..59724c973510 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -160,6 +160,7 @@ function DetailsPage(props) { imageStyles={[styles.avatarLarge]} source={UserUtils.getAvatar(details.avatar, details.accountID)} size={CONST.AVATAR_SIZE.LARGE} + fallbackIcon={details.fallbackIcon} /> diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js index 19f2b1fdc0c6..4dafdfc82d35 100755 --- a/src/pages/ProfilePage.js +++ b/src/pages/ProfilePage.js @@ -110,6 +110,7 @@ function ProfilePage(props) { const displayName = details.displayName ? details.displayName : props.translate('common.hidden'); const avatar = lodashGet(details, 'avatar', UserUtils.getDefaultAvatar()); + const fallbackIcon = lodashGet(details, 'fallbackIcon', ''); const originalFileName = lodashGet(details, 'originalFileName', ''); const login = lodashGet(details, 'login', ''); const timezone = lodashGet(details, 'timezone', {}); @@ -175,6 +176,7 @@ function ProfilePage(props) { imageStyles={[styles.avatarLarge]} source={UserUtils.getAvatar(avatar, accountID)} size={CONST.AVATAR_SIZE.LARGE} + fallbackIcon={fallbackIcon} /> diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js index a76025b67b1e..93cc4a12dd81 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js @@ -169,6 +169,7 @@ function SuggestionMention({ name: detail.login, source: UserUtils.getAvatar(detail.avatar, detail.accountID), type: 'avatar', + fallbackIcon: detail.fallbackIcon }, ], }); diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index bfbce8aed336..319dc94edc3e 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -90,7 +90,7 @@ const showWorkspaceDetails = (reportID) => { function ReportActionItemSingle(props) { const actorAccountID = props.action.actorAccountID; let {displayName} = props.personalDetailsList[actorAccountID] || {}; - const {avatar, login, pendingFields, status} = props.personalDetailsList[actorAccountID] || {}; + const {avatar, login, pendingFields, status, fallbackIcon} = props.personalDetailsList[actorAccountID] || {}; let actorHint = (login || displayName || '').replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); const displayAllActors = useMemo(() => props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && props.iouReport, [props.action.actionName, props.iouReport]); const isWorkspaceActor = ReportUtils.isPolicyExpenseChat(props.report) && (!actorAccountID || displayAllActors); @@ -198,6 +198,7 @@ function ReportActionItemSingle(props) { source={icon.source} type={icon.type} name={icon.name} + fallbackIcon={fallbackIcon} /> diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js index ef6e663ce705..7b240c108e4e 100644 --- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js +++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js @@ -52,6 +52,7 @@ function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDeta diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index a67e7cbc122e..080ade2680fb 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -353,6 +353,7 @@ function InitialSettingsPage(props) { imageStyles={[styles.avatarLarge]} source={UserUtils.getAvatar(props.currentUserPersonalDetails.avatar, props.session.accountID)} size={CONST.AVATAR_SIZE.LARGE} + fallbackIcon={props.currentUserPersonalDetails.fallbackIcon} /> diff --git a/src/pages/settings/Profile/LoungeAccessPage.js b/src/pages/settings/Profile/LoungeAccessPage.js index ce047bd9ccae..bbea526ca29c 100644 --- a/src/pages/settings/Profile/LoungeAccessPage.js +++ b/src/pages/settings/Profile/LoungeAccessPage.js @@ -74,6 +74,7 @@ function LoungeAccessPage(props) { imageStyles={[styles.avatarLarge]} source={UserUtils.getAvatar(props.currentUserPersonalDetails.avatar, props.session.accountID)} size={CONST.AVATAR_SIZE.LARGE} + fallbackIcon={props.currentUserPersonalDetails.fallbackIcon} /> { App.openProfile(props.currentUserPersonalDetails); }, [props.currentUserPersonalDetails]); - + return ( {_.map(profileSettingsOptions, (detail, index) => ( From dee6a5405e523a34b57f6347e741a6a316ebe80f Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 19 Sep 2023 15:40:58 +0700 Subject: [PATCH 056/250] fix lint --- src/components/Avatar.js | 4 ++-- src/components/AvatarWithImagePicker.js | 2 +- src/components/AvatarWithIndicator.js | 7 +++++-- src/components/LHNOptionsList/OptionRowLHNData.js | 2 +- src/components/MultipleAvatars.js | 2 +- src/components/UserDetailsTooltip/index.web.js | 2 +- src/components/avatarPropTypes.js | 2 +- src/components/menuItemPropTypes.js | 2 +- src/libs/ReportUtils.js | 14 +++++++------- src/libs/actions/PersonalDetails.js | 2 +- .../ReportActionCompose/SuggestionMention.js | 2 +- src/pages/settings/Profile/ProfilePage.js | 2 +- 12 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index ac206b971a6e..a27073be15f0 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -40,7 +40,7 @@ const propTypes = { /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. * If the avatar is type === workspace, this fallback icon will be ignored and decided based on the name prop. */ - fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), + fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** Denotes whether it is an avatar or a workspace avatar */ type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]), @@ -106,7 +106,7 @@ function Avatar(props) { ) : ( setImageError(true)} /> diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 2b72e7600dc3..e633125812d6 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -60,7 +60,7 @@ const propTypes = { size: PropTypes.oneOf([CONST.AVATAR_SIZE.LARGE, CONST.AVATAR_SIZE.DEFAULT]), /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), + fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** Denotes whether it is an avatar or a workspace avatar */ type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]), diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js index 72f09ce7cfc2..5e7b8d1ee632 100644 --- a/src/components/AvatarWithIndicator.js +++ b/src/components/AvatarWithIndicator.js @@ -16,7 +16,7 @@ const propTypes = { tooltipText: PropTypes.string, /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), + fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), }; const defaultProps = { @@ -28,7 +28,10 @@ function AvatarWithIndicator(props) { return ( - + diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index fe0506c7f55b..e8e1f8e85978 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -156,7 +156,7 @@ const personalDetailsSelector = (personalDetails) => firstName: personalData.firstName, status: personalData.status, avatar: UserUtils.getAvatar(personalData.avatar, personalData.accountID), - fallbackIcon: personalData.fallbackIcon + fallbackIcon: personalData.fallbackIcon, }; return finalPersonalDetails; }, diff --git a/src/components/MultipleAvatars.js b/src/components/MultipleAvatars.js index ec6edd4d5f65..1cdacb5fc1cc 100644 --- a/src/components/MultipleAvatars.js +++ b/src/components/MultipleAvatars.js @@ -25,7 +25,7 @@ const propTypes = { secondAvatarStyle: PropTypes.arrayOf(PropTypes.object), /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), + fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** Prop to identify if we should load avatars vertically instead of diagonally */ shouldStackHorizontally: PropTypes.bool, diff --git a/src/components/UserDetailsTooltip/index.web.js b/src/components/UserDetailsTooltip/index.web.js index b6a987316141..99ab6d18c7b4 100644 --- a/src/components/UserDetailsTooltip/index.web.js +++ b/src/components/UserDetailsTooltip/index.web.js @@ -48,7 +48,7 @@ function UserDetailsTooltip(props) { source={props.icon ? props.icon.source : UserUtils.getAvatar(userAvatar, userAccountID)} type={props.icon ? props.icon.type : CONST.ICON_TYPE_AVATAR} name={props.icon ? props.icon.name : userLogin} - fallbackIcon={lodashGet(props.icon,'fallbackIcon')} + fallbackIcon={lodashGet(props.icon, 'fallbackIcon')} /> {title} diff --git a/src/components/avatarPropTypes.js b/src/components/avatarPropTypes.js index a07de54ff481..915eac995fcb 100644 --- a/src/components/avatarPropTypes.js +++ b/src/components/avatarPropTypes.js @@ -6,5 +6,5 @@ export default PropTypes.shape({ type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]), name: PropTypes.string, id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), + fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), }); diff --git a/src/components/menuItemPropTypes.js b/src/components/menuItemPropTypes.js index b233f8c951b1..6272a7a2ef7d 100644 --- a/src/components/menuItemPropTypes.js +++ b/src/components/menuItemPropTypes.js @@ -98,7 +98,7 @@ const propTypes = { interactive: PropTypes.bool, /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ - fallbackIcon: PropTypes.oneOfType([PropTypes.func,PropTypes.string]), + fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), /** Avatars to show on the right of the menu item */ floatRightAvatars: PropTypes.arrayOf(avatarPropTypes), diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 8d1b5e4e18fe..054f32654f11 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -939,7 +939,7 @@ function getIconsForParticipants(participants, personalDetails) { source: sortedParticipantDetails[i][3], type: CONST.ICON_TYPE_AVATAR, name: sortedParticipantDetails[i][1], - fallBackIcon: sortedParticipantDetails[i][4] + fallBackIcon: sortedParticipantDetails[i][4], }; avatars.push(userIcon); } @@ -997,7 +997,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, id: parentReportAction.actorAccountID, type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'displayName'], ''), - fallbackIcon:lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']) + fallbackIcon: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']), }; return [memberIcon, workspaceIcon]; @@ -1012,7 +1012,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, source: UserUtils.getAvatar(lodashGet(personalDetails, [actorAccountID, 'avatar']), actorAccountID), name: actorDisplayName, type: CONST.ICON_TYPE_AVATAR, - fallbackIcon: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']) + fallbackIcon: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']), }; if (isWorkspaceThread(report)) { @@ -1027,7 +1027,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerAccountID, 'avatar']), report.ownerAccountID), type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''), - fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']) + fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']), }; if (isWorkspaceTaskReport(report)) { @@ -1060,7 +1060,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, id: report.ownerAccountID, type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''), - fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']) + fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']), }; return isExpenseReport(report) ? [memberIcon, workspaceIcon] : [workspaceIcon, memberIcon]; } @@ -1070,7 +1070,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, id: report.managerID, type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.managerID, 'displayName'], ''), - fallbackIcon: lodashGet(personalDetails, [report.managerID, 'fallbackIcon']) + fallbackIcon: lodashGet(personalDetails, [report.managerID, 'fallbackIcon']), }; const ownerIcon = { @@ -1078,7 +1078,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false, source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerAccountID, 'avatar']), report.ownerAccountID), type: CONST.ICON_TYPE_AVATAR, name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''), - fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']) + fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']), }; return isPayer ? [managerIcon, ownerIcon] : [ownerIcon, managerIcon]; diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 1c81f2d1be51..201898324d07 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -429,7 +429,7 @@ function updateAvatar(file) { avatar: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, originalFileName: null, }, - fallbackIcon: file.uri + fallbackIcon: file.uri, }, }, }, diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js index 93cc4a12dd81..5dcef285bbe2 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js @@ -169,7 +169,7 @@ function SuggestionMention({ name: detail.login, source: UserUtils.getAvatar(detail.avatar, detail.accountID), type: 'avatar', - fallbackIcon: detail.fallbackIcon + fallbackIcon: detail.fallbackIcon, }, ], }); diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js index 6dfa8ee8eaba..50678972a90e 100755 --- a/src/pages/settings/Profile/ProfilePage.js +++ b/src/pages/settings/Profile/ProfilePage.js @@ -103,7 +103,7 @@ function ProfilePage(props) { useEffect(() => { App.openProfile(props.currentUserPersonalDetails); }, [props.currentUserPersonalDetails]); - + return ( Date: Tue, 19 Sep 2023 15:00:10 +0530 Subject: [PATCH 057/250] fix: useEffect missing dependency warning. Signed-off-by: Krishna Gupta --- src/components/Image/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 30c67bcd4d89..3cadac0157bb 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -56,6 +56,7 @@ function Image(props) { onLoadStart(); }, 200); return () => clearTimeout(timeout); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoading]); // Omit the props which the underlying RNImage won't use From 97320a0abbc04bfdd5395db4e0ca7d0de2f5d1ff Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 19 Sep 2023 05:06:29 -0500 Subject: [PATCH 058/250] fix: use of measureParentContainer instead of parentContainerRef --- .../BaseAutoCompleteSuggestions.js | 2 +- src/components/AutoCompleteSuggestions/index.js | 16 +++++++--------- src/styles/StyleUtils.ts | 6 ++---- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js index b4710f1f343e..40e08d876907 100644 --- a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js +++ b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js @@ -70,7 +70,7 @@ function BaseAutoCompleteSuggestions(props) { }); const innerHeight = CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT * props.suggestions.length; - const animatedStyles = useAnimatedStyle(() => StyleUtils.getAutoCompleteSuggestionContainerStyle(rowHeight.value, props.shouldIncludeReportRecipientLocalTimeHeight)); + const animatedStyles = useAnimatedStyle(() => StyleUtils.getAutoCompleteSuggestionContainerStyle(rowHeight.value)); useEffect(() => { rowHeight.value = withTiming(measureHeightOfSuggestionRows(props.suggestions.length, props.isSuggestionPickerLarge), { diff --git a/src/components/AutoCompleteSuggestions/index.js b/src/components/AutoCompleteSuggestions/index.js index b37fcd7181d9..54a2b7dad1fd 100644 --- a/src/components/AutoCompleteSuggestions/index.js +++ b/src/components/AutoCompleteSuggestions/index.js @@ -14,7 +14,7 @@ import useWindowDimensions from '../../hooks/useWindowDimensions'; * On the native platform, tapping on auto-complete suggestions will not blur the main input. */ -function AutoCompleteSuggestions({parentContainerRef, ...props}) { +function AutoCompleteSuggestions({measureParentContainer, ...props}) { const containerRef = React.useRef(null); const {windowHeight, windowWidth} = useWindowDimensions(); const [{width, left, bottom}, setContainerState] = React.useState({ @@ -37,11 +37,11 @@ function AutoCompleteSuggestions({parentContainerRef, ...props}) { }, []); React.useEffect(() => { - if (!parentContainerRef || !parentContainerRef.current) { + if (!measureParentContainer) { return; } - parentContainerRef.current.measureInWindow((x, y, w) => setContainerState({left: x, bottom: windowHeight - y, width: w})); - }, [parentContainerRef, windowHeight, windowWidth]); + measureParentContainer((x, y, w) => setContainerState({left: x, bottom: windowHeight - y, width: w})); + }, [measureParentContainer, windowHeight, windowWidth]); const componentToRender = ( ); - if (!width) { - return componentToRender; - } - - return ReactDOM.createPortal({componentToRender}, document.querySelector('body')); + return Boolean(width) && ( + ReactDOM.createPortal({componentToRender}, document.querySelector('body')) + ); } AutoCompleteSuggestions.propTypes = propTypes; diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts index ec06bb07c3fe..6dd023f634de 100644 --- a/src/styles/StyleUtils.ts +++ b/src/styles/StyleUtils.ts @@ -935,11 +935,9 @@ function getBaseAutoCompleteSuggestionContainerStyle({left, bottom, width}: {lef /** * Gets the correct position for auto complete suggestion container */ -function getAutoCompleteSuggestionContainerStyle(itemsHeight: number, shouldIncludeReportRecipientLocalTimeHeight: boolean): ViewStyle | CSSProperties { +function getAutoCompleteSuggestionContainerStyle(itemsHeight: number): ViewStyle | CSSProperties { 'worklet'; - const optionalPadding = shouldIncludeReportRecipientLocalTimeHeight ? CONST.RECIPIENT_LOCAL_TIME_HEIGHT : 0; - const padding = CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_PADDING + optionalPadding; const borderWidth = 2; const height = itemsHeight + 2 * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_INNER_PADDING + borderWidth; @@ -947,7 +945,7 @@ function getAutoCompleteSuggestionContainerStyle(itemsHeight: number, shouldIncl // we need to shift it by the suggester's height plus its padding and, if applicable, the height of the RecipientLocalTime view. return { overflow: 'hidden', - top: -(height + padding), + top: -(height + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_PADDING), height, }; } From c904b6d42493fc46d92c2de6d60eee8046e974fb Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 19 Sep 2023 05:09:40 -0500 Subject: [PATCH 059/250] fix: use portal for native platforms --- src/components/AutoCompleteSuggestions/index.native.js | 5 +++-- .../home/report/ReportActionCompose/ReportActionCompose.js | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/index.native.js b/src/components/AutoCompleteSuggestions/index.native.js index 514cec6cd844..588f44809a3b 100644 --- a/src/components/AutoCompleteSuggestions/index.native.js +++ b/src/components/AutoCompleteSuggestions/index.native.js @@ -1,10 +1,11 @@ import React from 'react'; +import {Portal} from '@gorhom/portal'; import BaseAutoCompleteSuggestions from './BaseAutoCompleteSuggestions'; import {propTypes} from './autoCompleteSuggestionsPropTypes'; -function AutoCompleteSuggestions({parentContainerRef, ...props}) { +function AutoCompleteSuggestions({measureParentContainer, ...props}) { // eslint-disable-next-line react/jsx-props-no-spreading - return ; + return } AutoCompleteSuggestions.propTypes = propTypes; diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index ddcd43cd8cd0..e872dc688dd5 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -5,6 +5,7 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import {useAnimatedRef} from 'react-native-reanimated'; +import {PortalHost} from '@gorhom/portal'; import styles from '../../../../styles/styles'; import ONYXKEYS from '../../../../ONYXKEYS'; import * as Report from '../../../../libs/actions/Report'; @@ -325,6 +326,7 @@ function ReportActionCompose({ ref={containerRef} style={[shouldShowReportRecipientLocalTime && !lodashGet(network, 'isOffline') && styles.chatItemComposeWithFirstRow, isComposerFullSize && styles.chatItemFullComposeRow]} > + Date: Tue, 19 Sep 2023 15:46:28 +0530 Subject: [PATCH 060/250] update function --- src/libs/actions/MapboxToken.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/MapboxToken.js b/src/libs/actions/MapboxToken.js index c0d7010b383c..0202488ed199 100644 --- a/src/libs/actions/MapboxToken.js +++ b/src/libs/actions/MapboxToken.js @@ -50,6 +50,12 @@ const clearToken = () => { Onyx.set(ONYXKEYS.MAPBOX_ACCESS_TOKEN, null); }; +const fetchToken = () => { + console.debug('[MapboxToken] Token does not exist so fetching one'); + API.read('GetMapboxAccessToken'); + isCurrentlyFetchingToken = true; +}; + const init = () => { if (connectionIDForToken) { console.debug('[MapboxToken] init() is already listening to Onyx so returning early'); @@ -82,9 +88,7 @@ const init = () => { // If the token is falsy or an empty object, the token needs to be retrieved from the API. // The API sets a token in Onyx with a 30 minute expiration. if (_.isEmpty(token)) { - console.debug('[MapboxToken] Token does not exist so fetching one'); - API.read('GetMapboxAccessToken'); - isCurrentlyFetchingToken = true; + fetchToken(); return; } @@ -127,10 +131,7 @@ const init = () => { // trigger the fetch of a new one if (network && network.isOffline && val && !val.isOffline) { if (_.isEmpty(currentToken)) { - console.debug('[MapboxToken] Token does not exist so fetching one'); - // eslint-disable-next-line rulesdir/no-multiple-api-calls - API.read('GetMapboxAccessToken'); - isCurrentlyFetchingToken = true; + fetchToken(); } else if (!isCurrentlyFetchingToken && hasTokenExpired()) { console.debug('[MapboxToken] Token is expired after network came online'); clearToken(); From 341efce627945305f8fe7a66b73c226619043fd9 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 19 Sep 2023 06:32:34 -0500 Subject: [PATCH 061/250] fix: remove unused props --- .../autoCompleteSuggestionsPropTypes.js | 3 --- src/components/EmojiSuggestions.js | 4 ---- src/components/MentionSuggestions.js | 4 ---- .../report/ReportActionCompose/ComposerWithSuggestions.js | 2 -- .../home/report/ReportActionCompose/ReportActionCompose.js | 1 - src/pages/home/report/ReportActionCompose/SuggestionEmoji.js | 2 -- .../home/report/ReportActionCompose/SuggestionMention.js | 2 -- src/pages/home/report/ReportActionCompose/Suggestions.js | 2 -- .../ReportActionCompose/composerWithSuggestionsProps.js | 3 --- src/pages/home/report/ReportActionCompose/suggestionProps.js | 3 --- 10 files changed, 26 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/autoCompleteSuggestionsPropTypes.js b/src/components/AutoCompleteSuggestions/autoCompleteSuggestionsPropTypes.js index 16040991a3d8..8c6dca1902c5 100644 --- a/src/components/AutoCompleteSuggestions/autoCompleteSuggestionsPropTypes.js +++ b/src/components/AutoCompleteSuggestions/autoCompleteSuggestionsPropTypes.js @@ -22,9 +22,6 @@ const propTypes = { * When this value is false, the suggester will have a height of 2.5 items. When this value is true, the height can be up to 5 items. */ isSuggestionPickerLarge: PropTypes.bool.isRequired, - /** Show that we should include ReportRecipientLocalTime view height */ - shouldIncludeReportRecipientLocalTimeHeight: PropTypes.bool.isRequired, - /** create accessibility label for each item */ accessibilityLabelExtractor: PropTypes.func.isRequired, diff --git a/src/components/EmojiSuggestions.js b/src/components/EmojiSuggestions.js index b06b0cc63eb8..d7f7a8d6091a 100644 --- a/src/components/EmojiSuggestions.js +++ b/src/components/EmojiSuggestions.js @@ -40,9 +40,6 @@ const propTypes = { * 2.5 items. When this value is true, the height can be up to 5 items. */ isEmojiPickerLarge: PropTypes.bool.isRequired, - /** Show that we should include ReportRecipientLocalTime view height */ - shouldIncludeReportRecipientLocalTimeHeight: PropTypes.bool.isRequired, - /** Stores user's preferred skin tone */ preferredSkinToneIndex: PropTypes.number.isRequired, @@ -102,7 +99,6 @@ function EmojiSuggestions(props) { highlightedSuggestionIndex={props.highlightedEmojiIndex} onSelect={props.onSelect} isSuggestionPickerLarge={props.isEmojiPickerLarge} - shouldIncludeReportRecipientLocalTimeHeight={props.shouldIncludeReportRecipientLocalTimeHeight} accessibilityLabelExtractor={keyExtractor} measureParentContainer={props.measureParentContainer} /> diff --git a/src/components/MentionSuggestions.js b/src/components/MentionSuggestions.js index 11df8a597ded..a85eb352b6db 100644 --- a/src/components/MentionSuggestions.js +++ b/src/components/MentionSuggestions.js @@ -41,9 +41,6 @@ const propTypes = { * When this value is false, the suggester will have a height of 2.5 items. When this value is true, the height can be up to 5 items. */ isMentionPickerLarge: PropTypes.bool.isRequired, - /** Show that we should include ReportRecipientLocalTime view height */ - shouldIncludeReportRecipientLocalTimeHeight: PropTypes.bool.isRequired, - /** Meaures the parent container's position and dimensions. */ measureParentContainer: PropTypes.func, }; @@ -125,7 +122,6 @@ function MentionSuggestions(props) { highlightedSuggestionIndex={props.highlightedMentionIndex} onSelect={props.onSelect} isSuggestionPickerLarge={props.isMentionPickerLarge} - shouldIncludeReportRecipientLocalTimeHeight={props.shouldIncludeReportRecipientLocalTimeHeight} accessibilityLabelExtractor={keyExtractor} measureParentContainer={props.measureParentContainer} /> diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 04757b0ff276..c85b4c0604d1 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -91,7 +91,6 @@ function ComposerWithSuggestions({ setIsFullComposerAvailable, setIsCommentEmpty, submitForm, - shouldShowReportRecipientLocalTime, shouldShowComposeInput, measureParentContainer, // Refs @@ -503,7 +502,6 @@ function ComposerWithSuggestions({ isComposerFullSize={isComposerFullSize} updateComment={updateComment} composerHeight={composerHeight} - shouldShowReportRecipientLocalTime={shouldShowReportRecipientLocalTime} onInsertedEmoji={onInsertedEmoji} measureParentContainer={measureParentContainer} // Input diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index e872dc688dd5..d91645589931 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -389,7 +389,6 @@ function ReportActionCompose({ setIsFullComposerAvailable={setIsFullComposerAvailable} setIsCommentEmpty={setIsCommentEmpty} submitForm={submitForm} - shouldShowReportRecipientLocalTime={shouldShowReportRecipientLocalTime} shouldShowComposeInput={shouldShowComposeInput} onFocus={onFocus} onBlur={onBlur} diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js index a760627e53cc..910a338c83b6 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js @@ -58,7 +58,6 @@ function SuggestionEmoji({ setSelection, updateComment, isComposerFullSize, - shouldShowReportRecipientLocalTime, isAutoSuggestionPickerLarge, forwardedRef, resetKeyboardInput, @@ -235,7 +234,6 @@ function SuggestionEmoji({ isComposerFullSize={isComposerFullSize} preferredSkinToneIndex={preferredSkinTone} isEmojiPickerLarge={isAutoSuggestionPickerLarge} - shouldIncludeReportRecipientLocalTimeHeight={shouldShowReportRecipientLocalTime} measureParentContainer={measureParentContainer} /> ); diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js index a76025b67b1e..2a464b3bddb3 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js @@ -51,7 +51,6 @@ function SuggestionMention({ personalDetails, updateComment, composerHeight, - shouldShowReportRecipientLocalTime, forwardedRef, isAutoSuggestionPickerLarge, measureParentContainer, @@ -284,7 +283,6 @@ function SuggestionMention({ isComposerFullSize={isComposerFullSize} isMentionPickerLarge={isAutoSuggestionPickerLarge} composerHeight={composerHeight} - shouldIncludeReportRecipientLocalTimeHeight={shouldShowReportRecipientLocalTime} measureParentContainer={measureParentContainer} /> ); diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.js b/src/pages/home/report/ReportActionCompose/Suggestions.js index 60cb9de4ccfb..a00bd342b17d 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.js +++ b/src/pages/home/report/ReportActionCompose/Suggestions.js @@ -36,7 +36,6 @@ function Suggestions({ setSelection, updateComment, composerHeight, - shouldShowReportRecipientLocalTime, forwardedRef, onInsertedEmoji, resetKeyboardInput, @@ -105,7 +104,6 @@ function Suggestions({ isComposerFullSize, updateComment, composerHeight, - shouldShowReportRecipientLocalTime, isAutoSuggestionPickerLarge, measureParentContainer, }; diff --git a/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js b/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js index b8d9f0b6d816..0c8f36114c44 100644 --- a/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js +++ b/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js @@ -74,9 +74,6 @@ const propTypes = { /** A method to call when the form is submitted */ submitForm: PropTypes.func.isRequired, - /** Whether the recipient local time is shown or not */ - shouldShowReportRecipientLocalTime: PropTypes.bool.isRequired, - /** Whether the compose input is shown or not */ shouldShowComposeInput: PropTypes.bool.isRequired, diff --git a/src/pages/home/report/ReportActionCompose/suggestionProps.js b/src/pages/home/report/ReportActionCompose/suggestionProps.js index 12447929b980..815a1c5619f5 100644 --- a/src/pages/home/report/ReportActionCompose/suggestionProps.js +++ b/src/pages/home/report/ReportActionCompose/suggestionProps.js @@ -22,9 +22,6 @@ const baseProps = { /** Callback to update the comment draft */ updateComment: PropTypes.func.isRequired, - /** Flag whether we need to consider the participants */ - shouldShowReportRecipientLocalTime: PropTypes.bool.isRequired, - /** Meaures the parent container's position and dimensions. */ measureParentContainer: PropTypes.func.isRequired, }; From 6b5621dc2fd3fdb7fbbb2520104a5a84d7d0eb97 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 19 Sep 2023 06:43:51 -0500 Subject: [PATCH 062/250] fix: prettier --- src/components/AutoCompleteSuggestions/index.js | 3 ++- src/components/AutoCompleteSuggestions/index.native.js | 6 +++++- .../home/report/ReportActionCompose/ReportActionCompose.js | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/index.js b/src/components/AutoCompleteSuggestions/index.js index 54a2b7dad1fd..9234d04f4507 100644 --- a/src/components/AutoCompleteSuggestions/index.js +++ b/src/components/AutoCompleteSuggestions/index.js @@ -51,7 +51,8 @@ function AutoCompleteSuggestions({measureParentContainer, ...props}) { /> ); - return Boolean(width) && ( + return ( + Boolean(width) && ReactDOM.createPortal({componentToRender}, document.querySelector('body')) ); } diff --git a/src/components/AutoCompleteSuggestions/index.native.js b/src/components/AutoCompleteSuggestions/index.native.js index 588f44809a3b..002435cba14b 100644 --- a/src/components/AutoCompleteSuggestions/index.native.js +++ b/src/components/AutoCompleteSuggestions/index.native.js @@ -5,7 +5,11 @@ import {propTypes} from './autoCompleteSuggestionsPropTypes'; function AutoCompleteSuggestions({measureParentContainer, ...props}) { // eslint-disable-next-line react/jsx-props-no-spreading - return + return ( + + + + ); } AutoCompleteSuggestions.propTypes = propTypes; diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index d91645589931..f1de1b476335 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -326,7 +326,7 @@ function ReportActionCompose({ ref={containerRef} style={[shouldShowReportRecipientLocalTime && !lodashGet(network, 'isOffline') && styles.chatItemComposeWithFirstRow, isComposerFullSize && styles.chatItemFullComposeRow]} > - + Date: Tue, 19 Sep 2023 06:51:21 -0500 Subject: [PATCH 063/250] fix: lint error --- src/components/AutoCompleteSuggestions/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AutoCompleteSuggestions/index.native.js b/src/components/AutoCompleteSuggestions/index.native.js index 002435cba14b..f5ff4636f395 100644 --- a/src/components/AutoCompleteSuggestions/index.native.js +++ b/src/components/AutoCompleteSuggestions/index.native.js @@ -4,9 +4,9 @@ import BaseAutoCompleteSuggestions from './BaseAutoCompleteSuggestions'; import {propTypes} from './autoCompleteSuggestionsPropTypes'; function AutoCompleteSuggestions({measureParentContainer, ...props}) { - // eslint-disable-next-line react/jsx-props-no-spreading return ( + {/* eslint-disable-next-line react/jsx-props-no-spreading */} ); From 429e119a3929616dd99565359c27ee76048c5075 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Tue, 19 Sep 2023 14:11:18 +0200 Subject: [PATCH 064/250] [TS migration] Migrate 'PusherConnectionManager.js' lib to TypeScript --- src/libs/PusherConnectionManager.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/PusherConnectionManager.ts b/src/libs/PusherConnectionManager.ts index 557c0e024e9f..f5dfc623fc14 100644 --- a/src/libs/PusherConnectionManager.ts +++ b/src/libs/PusherConnectionManager.ts @@ -4,6 +4,8 @@ import * as Session from './actions/Session'; import Log from './Log'; import CONST from '../CONST'; +type EventCallbackError = {type: ValueOf; data: {code: number}}; + function init() { /** * When authTokens expire they will automatically be refreshed. @@ -17,10 +19,7 @@ function init() { }, })); - /** - * @params {string} eventName - */ - Pusher.registerSocketEventCallback((eventName: string, error: {type: ValueOf; data: {code: number}}) => { + Pusher.registerSocketEventCallback((eventName: string, error: EventCallbackError) => { switch (eventName) { case 'error': { const errorType = error?.type; From af2a3bd776ee04eef6ac4558ba97df5b772eebaa Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 19 Sep 2023 20:54:32 +0200 Subject: [PATCH 065/250] Update react-native-onyx --- package-lock.json | 28 ++++++++++++++++------------ package.json | 4 ++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c93a456cc5f..1e9687b35761 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,10 +87,10 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.76", + "react-native-onyx": "^1.0.84", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", - "react-native-performance": "^4.0.0", + "react-native-performance": "^5.1.0", "react-native-permissions": "^3.0.1", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", "react-native-plaid-link-sdk": "^10.0.0", @@ -40362,9 +40362,9 @@ } }, "node_modules/react-native-onyx": { - "version": "1.0.76", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.76.tgz", - "integrity": "sha512-mcMlYQCo1B/kom+4hu7CQKKLwvPFjQAJsVIzV2s9aa8XKNlcnYiJbfuM6RSJ1fFmSIeud4Y66rhv4/oWUkSl5A==", + "version": "1.0.84", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.84.tgz", + "integrity": "sha512-qQ+o+qS5ucZLbKbG5kI0UsC42N4h1Pprg/1D7PqjDeVanS3iUv33rT4fbrHuar77g0DSTA1/M8bC2WmYrShS9A==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -40377,8 +40377,9 @@ "peerDependencies": { "idb-keyval": "^6.2.1", "react": ">=18.1.0", + "react-dom": ">=18.1.0", "react-native-device-info": "^10.3.0", - "react-native-performance": "^4.0.0", + "react-native-performance": "^5.1.0", "react-native-quick-sqlite": "^8.0.0-beta.2" }, "peerDependenciesMeta": { @@ -40420,8 +40421,9 @@ } }, "node_modules/react-native-performance": { - "version": "4.0.0", - "license": "MIT", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-5.1.0.tgz", + "integrity": "sha512-rq/YBf0/GptSOM/Lj64/1yRq8uN2YE0psFB16wFbYBbTcIEp/0rrgN2HyS5lhvfBOFgKoDRWQ53jHSCb+QJ5eA==", "peerDependencies": { "react-native": "*" } @@ -75738,9 +75740,9 @@ } }, "react-native-onyx": { - "version": "1.0.76", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.76.tgz", - "integrity": "sha512-mcMlYQCo1B/kom+4hu7CQKKLwvPFjQAJsVIzV2s9aa8XKNlcnYiJbfuM6RSJ1fFmSIeud4Y66rhv4/oWUkSl5A==", + "version": "1.0.84", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.84.tgz", + "integrity": "sha512-qQ+o+qS5ucZLbKbG5kI0UsC42N4h1Pprg/1D7PqjDeVanS3iUv33rT4fbrHuar77g0DSTA1/M8bC2WmYrShS9A==", "requires": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -75763,7 +75765,9 @@ } }, "react-native-performance": { - "version": "4.0.0", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-5.1.0.tgz", + "integrity": "sha512-rq/YBf0/GptSOM/Lj64/1yRq8uN2YE0psFB16wFbYBbTcIEp/0rrgN2HyS5lhvfBOFgKoDRWQ53jHSCb+QJ5eA==", "requires": {} }, "react-native-performance-flipper-reporter": { diff --git a/package.json b/package.json index 6899bc70e9d2..f9f2d6dc4e82 100644 --- a/package.json +++ b/package.json @@ -127,10 +127,10 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.76", + "react-native-onyx": "^1.0.84", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", - "react-native-performance": "^4.0.0", + "react-native-performance": "^5.1.0", "react-native-permissions": "^3.0.1", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", "react-native-plaid-link-sdk": "^10.0.0", From b009310e644892fdb88d005222b19e1a7aa2158b Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 20 Sep 2023 10:34:16 +0700 Subject: [PATCH 066/250] prevent request money if waypoint is empty --- .../MoneyRequestParticipantsPage.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 1d9f12a9cdbb..fcee4d77a854 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -52,6 +52,8 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType.current, selectedTab); const isSplitRequest = iou.id === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT; const [headerTitle, setHeaderTitle] = useState(); + const transaction = TransactionUtils.getTransaction(props.iou.transactionID); + const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})) useEffect(() => { if (isDistanceRequest) { @@ -75,7 +77,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request if (prevMoneyRequestId.current !== iou.id) { // The ID is cleared on completing a request. In that case, we will do nothing - if (iou.id && !isDistanceRequest && !isSplitRequest && !isNewReportIDSelectedLocally.current) { + if (iou.id && (!isDistanceRequest || (isDistanceRequest && isEmptyWaypoint)) && !isSplitRequest && !isNewReportIDSelectedLocally.current) { navigateBack(true); } return; @@ -87,7 +89,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { if (shouldReset) { IOU.resetMoneyRequestInfo(moneyRequestId); } - if (!isDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { + if ((!isDistanceRequest || (isDistanceRequest && isEmptyWaypoint)) && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { navigateBack(true); } From 1433235f1f3da9fbd7e4ac575a164432914e5292 Mon Sep 17 00:00:00 2001 From: ginsuma <13113013+ginsuma@users.noreply.github.com> Date: Wed, 20 Sep 2023 12:47:58 +0700 Subject: [PATCH 067/250] Fix different grayness in MoneyRequestView and TaskView --- .../ReportActionItem/MoneyRequestView.js | 16 ++++++++------- src/pages/home/report/ReportActionItem.js | 20 ++++++++----------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index d8b15653d8af..aff4159bbcdb 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -108,13 +108,15 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans {hasReceipt && ( - - - + + + + + )} - - - + ); } @@ -538,12 +536,10 @@ function ReportActionItem(props) { } return ( - - - + ); } if (ReportUtils.isExpenseReport(props.report) || ReportUtils.isIOUReport(props.report)) { From d9ab01755e8a016cecc814fe18aa4dbdc9429508 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 14:04:24 +0800 Subject: [PATCH 068/250] fix suggestion menu hides on typing --- src/hooks/useDebounce.js | 16 +++++++++++++ .../ComposerWithSuggestions.js | 24 ++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 src/hooks/useDebounce.js diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js new file mode 100644 index 000000000000..0ca06cdbb197 --- /dev/null +++ b/src/hooks/useDebounce.js @@ -0,0 +1,16 @@ +import {useEffect, useRef} from 'react'; +import _ from 'underscore'; + +export default function useDebounce(func, wait, immediate) { + const debouncedFnRef = useRef(); + + useEffect(() => { + const debouncedFn = _.debounce(func, wait, immediate); + + debouncedFnRef.current = debouncedFn; + + return debouncedFn.cancel; + }, [func, wait, immediate]); + + return debouncedFnRef.current; +} diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 38ee1ab1d513..c4bea207cb75 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -33,6 +33,7 @@ import compose from '../../../../libs/compose'; import withKeyboardState from '../../../../components/withKeyboardState'; import {propTypes, defaultProps} from './composerWithSuggestionsProps'; import focusWithDelay from '../../../../libs/focusWithDelay'; +import useDebounce from '../../../../hooks/useDebounce'; const {RNTextInputReset} = NativeModules; @@ -125,7 +126,7 @@ function ComposerWithSuggestions({ const textInputRef = useRef(null); const insertedEmojisRef = useRef([]); - const shouldIgnoreScrollCallback = useRef(false); + const isScrollLikelyLayoutTriggered = useRef(false); /** * Update frequently used emojis list. We debounce this method in the constructor so that UpdateFrequentlyUsedEmojis @@ -136,6 +137,16 @@ function ComposerWithSuggestions({ insertedEmojisRef.current = []; }, []); + const debouncedLowerIsScrollLikelyLayoutTriggered = useDebounce( + useCallback(() => (isScrollLikelyLayoutTriggered.current = false), []), + 500, + ); + + const raiseIsScrollLikelyLayoutTriggered = useCallback(() => { + isScrollLikelyLayoutTriggered.current = true; + debouncedLowerIsScrollLikelyLayoutTriggered(); + }, [debouncedLowerIsScrollLikelyLayoutTriggered]); + const onInsertedEmoji = useCallback( (emojiObject) => { insertedEmojisRef.current = [...insertedEmojisRef.current, emojiObject]; @@ -176,7 +187,7 @@ function ComposerWithSuggestions({ */ const updateComment = useCallback( (commentValue, shouldDebounceSaveComment) => { - shouldIgnoreScrollCallback.current = true; + raiseIsScrollLikelyLayoutTriggered(); const {text: newComment, emojis} = EmojiUtils.replaceAndExtractEmojis(commentValue, preferredSkinTone, preferredLocale); if (!_.isEmpty(emojis)) { @@ -214,7 +225,7 @@ function ComposerWithSuggestions({ debouncedBroadcastUserIsTyping(reportID); } }, - [debouncedUpdateFrequentlyUsedEmojis, preferredLocale, preferredSkinTone, reportID, setIsCommentEmpty], + [debouncedUpdateFrequentlyUsedEmojis, preferredLocale, preferredSkinTone, reportID, setIsCommentEmpty, raiseIsScrollLikelyLayoutTriggered], ); /** @@ -317,15 +328,12 @@ function ComposerWithSuggestions({ ); const hideSuggestionMenu = useCallback(() => { - if (!suggestionsRef.current || shouldIgnoreScrollCallback.current) { - shouldIgnoreScrollCallback.current = false; + if (!suggestionsRef.current || isScrollLikelyLayoutTriggered.current) { return; } suggestionsRef.current.updateShouldShowSuggestionMenuToFalse(false); }, [suggestionsRef]); - const debouncedHideSuggestionMenu = useMemo(() => _.debounce(hideSuggestionMenu, 200, true), [hideSuggestionMenu]); - const setShouldBlockSuggestionCalcToFalse = useCallback(() => { if (!suggestionsRef.current) { return false; @@ -499,7 +507,7 @@ function ComposerWithSuggestions({ } setComposerHeight(composerLayoutHeight); }} - onScroll={debouncedHideSuggestionMenu} + onScroll={hideSuggestionMenu} /> From d133c4d14d5a40de8f2d391335ecc43985d6032b Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 20 Sep 2023 13:37:15 +0700 Subject: [PATCH 069/250] fix lint --- .../MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index fcee4d77a854..d5c9a388dfa2 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -53,7 +53,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const isSplitRequest = iou.id === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT; const [headerTitle, setHeaderTitle] = useState(); const transaction = TransactionUtils.getTransaction(props.iou.transactionID); - const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})) + const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})); useEffect(() => { if (isDistanceRequest) { From 7adde9fb87a0f89bd047a7b6d77293d810aa1ce0 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 20 Sep 2023 13:44:46 +0700 Subject: [PATCH 070/250] fix lint --- .../MoneyRequestParticipantsPage.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index d5c9a388dfa2..ad600a2e329f 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -17,6 +17,8 @@ import * as IOU from '../../../../libs/actions/IOU'; import * as MoneyRequestUtils from '../../../../libs/MoneyRequestUtils'; import {iouPropTypes, iouDefaultProps} from '../../propTypes'; import useLocalize from '../../../../hooks/useLocalize'; +import * as TransactionUtils from '../../../../libs/TransactionUtils'; + const propTypes = { /** React Navigation route */ @@ -52,7 +54,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType.current, selectedTab); const isSplitRequest = iou.id === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT; const [headerTitle, setHeaderTitle] = useState(); - const transaction = TransactionUtils.getTransaction(props.iou.transactionID); + const transaction = TransactionUtils.getTransaction(iou.transactionID); const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})); useEffect(() => { From d88b6d84cdcef90e41a1f688ee7e37c6dd002b6c Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 20 Sep 2023 13:50:46 +0700 Subject: [PATCH 071/250] fix lint --- .../MoneyRequestParticipantsPage.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index ad600a2e329f..580ddd195ae8 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -19,7 +19,6 @@ import {iouPropTypes, iouDefaultProps} from '../../propTypes'; import useLocalize from '../../../../hooks/useLocalize'; import * as TransactionUtils from '../../../../libs/TransactionUtils'; - const propTypes = { /** React Navigation route */ route: PropTypes.shape({ @@ -98,7 +97,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { return () => { prevMoneyRequestId.current = iou.id; }; - }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest]); + }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, isEmptyWaypoint]); return ( Date: Wed, 20 Sep 2023 10:55:32 +0300 Subject: [PATCH 072/250] Customizing the isToday & isTomorrow & isYesterday functions to consider timezones --- src/libs/DateUtils.js | 52 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js index b33a1b1b2a73..8ec19834e790 100644 --- a/src/libs/DateUtils.js +++ b/src/libs/DateUtils.js @@ -4,11 +4,10 @@ import {es, enGB} from 'date-fns/locale'; import { formatDistanceToNow, subMinutes, + addDays, + subDays, isBefore, subMilliseconds, - isToday, - isTomorrow, - isYesterday, startOfWeek, endOfWeek, format, @@ -85,6 +84,47 @@ function getLocalDateFromDatetime(locale, datetime, currentSelectedTimezone = ti return utcToZonedTime(parsedDatetime, currentSelectedTimezone); } +/** + * Checks if a given date is today in the specified time zone. + * + * @param {Date} date - The date to compare. + * @param {String} timeZone - The time zone to consider. + * @returns {Boolean} True if the date is today; otherwise, false. + */ +function isToday(date, timeZone) { + const currentDate = new Date(); + const currentDateInTimeZone = utcToZonedTime(currentDate, timeZone); + return isSameDay(date, currentDateInTimeZone); +} + +/** + * Checks if a given date is tomorrow in the specified time zone. + * + * @param {Date} date - The date to compare. + * @param {String} timeZone - The time zone to consider. + * @returns {Boolean} True if the date is tomorrow; otherwise, false. + */ +function isTomorrow(date, timeZone) { + const currentDate = new Date(); + const tomorrow = addDays(currentDate, 1); // Get the date for tomorrow in the current time zone + const tomorrowInTimeZone = utcToZonedTime(tomorrow, timeZone); + return isSameDay(date, tomorrowInTimeZone); +} + +/** + * Checks if a given date is yesterday in the specified time zone. + * + * @param {Date} date - The date to compare. + * @param {String} timeZone - The time zone to consider. + * @returns {Boolean} True if the date is yesterday; otherwise, false. + */ +function isYesterday(date, timeZone) { + const currentDate = new Date(); + const yesterday = subDays(currentDate, 1); // Get the date for yesterday in the current time zone + const yesterdayInTimeZone = utcToZonedTime(yesterday, timeZone); + return isSameDay(date, yesterdayInTimeZone); +} + /** * Formats an ISO-formatted datetime string to local date and time string * @@ -117,13 +157,13 @@ function datetimeToCalendarTime(locale, datetime, includeTimeZone = false, curre yesterdayAt = yesterdayAt.toLowerCase(); } - if (isToday(date)) { + if (isToday(date, currentSelectedTimezone)) { return `${todayAt} ${format(date, CONST.DATE.LOCAL_TIME_FORMAT)}${tz}`; } - if (isTomorrow(date)) { + if (isTomorrow(date, currentSelectedTimezone)) { return `${tomorrowAt} ${format(date, CONST.DATE.LOCAL_TIME_FORMAT)}${tz}`; } - if (isYesterday(date)) { + if (isYesterday(date, currentSelectedTimezone)) { return `${yesterdayAt} ${format(date, CONST.DATE.LOCAL_TIME_FORMAT)}${tz}`; } if (date >= startOfCurrentWeek && date <= endOfCurrentWeek) { From a187423e51e24f12ce9b0c0623796ef484236bea Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 16:37:36 +0800 Subject: [PATCH 073/250] add jsdoc --- src/hooks/useDebounce.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index 0ca06cdbb197..40b21d38451e 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -1,6 +1,12 @@ import {useEffect, useRef} from 'react'; import _ from 'underscore'; +/** + * @param {*} func Function to debounce `waitMS` ms. + * @param {*} wait The number of milliseconds to wait before `func` can be invoked again. + * @param {*} immediate True if `func` should be invoked on the leading edge of `waitMS` instead of the trailing edge. + * @returns + */ export default function useDebounce(func, wait, immediate) { const debouncedFnRef = useRef(); From 3a577e623ab57f10a8ee719656b5ab1b9609b8d1 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 16:37:42 +0800 Subject: [PATCH 074/250] add comment --- .../report/ReportActionCompose/ComposerWithSuggestions.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index c4bea207cb75..ed98356da970 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -137,6 +137,13 @@ function ComposerWithSuggestions({ insertedEmojisRef.current = []; }, []); + /** + * Reset isScrollLikelyLayoutTriggered to false. + * + * The function is debounced with a handpicked wait time to address 2 issues: + * 1. There is a slight delay between onChangeText and onScroll + * 2. Layout change will trigger onScroll multiple times + */ const debouncedLowerIsScrollLikelyLayoutTriggered = useDebounce( useCallback(() => (isScrollLikelyLayoutTriggered.current = false), []), 500, From 762e549db02675d4e28124d34cd3d55e24ea1499 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 16:39:50 +0800 Subject: [PATCH 075/250] use lodash debounce --- src/hooks/useDebounce.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index 40b21d38451e..f78eb2ae84b6 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -1,5 +1,5 @@ import {useEffect, useRef} from 'react'; -import _ from 'underscore'; +import lodashDebounce from 'lodash/debounce'; /** * @param {*} func Function to debounce `waitMS` ms. @@ -11,7 +11,7 @@ export default function useDebounce(func, wait, immediate) { const debouncedFnRef = useRef(); useEffect(() => { - const debouncedFn = _.debounce(func, wait, immediate); + const debouncedFn = lodashDebounce(func, wait, immediate); debouncedFnRef.current = debouncedFn; From c212e9e2237377378c2c4172113ff3892ad0811a Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 16:42:18 +0800 Subject: [PATCH 076/250] update params and jsdoc --- src/hooks/useDebounce.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index f78eb2ae84b6..09cb79dfc440 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -2,21 +2,24 @@ import {useEffect, useRef} from 'react'; import lodashDebounce from 'lodash/debounce'; /** - * @param {*} func Function to debounce `waitMS` ms. - * @param {*} wait The number of milliseconds to wait before `func` can be invoked again. - * @param {*} immediate True if `func` should be invoked on the leading edge of `waitMS` instead of the trailing edge. - * @returns + * @param {Function} func The function to debounce. + * @param {Number} wait The number of milliseconds to delay. + * @param {Object} options The options object. + * @param {Boolean} options.leading Specify invoking on the leading edge of the timeout. + * @param {Number} options.maxWait The maximum time func is allowed to be delayed before it’s invoked. + * @param {Boolean} options.trailing Specify invoking on the trailing edge of the timeout. + * @returns Returns the new debounced function. */ -export default function useDebounce(func, wait, immediate) { +export default function useDebounce(func, wait, options) { const debouncedFnRef = useRef(); useEffect(() => { - const debouncedFn = lodashDebounce(func, wait, immediate); + const debouncedFn = lodashDebounce(func, wait, options); debouncedFnRef.current = debouncedFn; return debouncedFn.cancel; - }, [func, wait, immediate]); + }, [func, wait, options]); return debouncedFnRef.current; } From 2f93e7670757f4eba44ce2ff0b7598be5c163d6d Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 16:44:31 +0800 Subject: [PATCH 077/250] add comment --- .../home/report/ReportActionCompose/ComposerWithSuggestions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index ed98356da970..9bdc6e3251da 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -126,6 +126,8 @@ function ComposerWithSuggestions({ const textInputRef = useRef(null); const insertedEmojisRef = useRef([]); + + // A flag to indicate whether onScroll callback is likely triggered by layout change or not const isScrollLikelyLayoutTriggered = useRef(false); /** From 81d66d4bfc2592d9c93d1e30a60b82a60a12a3f5 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 16:45:46 +0800 Subject: [PATCH 078/250] update comment --- .../home/report/ReportActionCompose/ComposerWithSuggestions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 9bdc6e3251da..0e40d1d1cb14 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -127,7 +127,7 @@ function ComposerWithSuggestions({ const textInputRef = useRef(null); const insertedEmojisRef = useRef([]); - // A flag to indicate whether onScroll callback is likely triggered by layout change or not + // A flag to indicate whether the onScroll callback is likely triggered by a layout change (caused by text change) or not const isScrollLikelyLayoutTriggered = useRef(false); /** From a6a03e1538e4de0c9219aa8ea2fc5149b6cf0df4 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 17:10:24 +0800 Subject: [PATCH 079/250] make sure debounced fn is not undefined before calling it --- src/hooks/useDebounce.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index 09cb79dfc440..d6ff20a1e91b 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -8,7 +8,7 @@ import lodashDebounce from 'lodash/debounce'; * @param {Boolean} options.leading Specify invoking on the leading edge of the timeout. * @param {Number} options.maxWait The maximum time func is allowed to be delayed before it’s invoked. * @param {Boolean} options.trailing Specify invoking on the trailing edge of the timeout. - * @returns Returns the new debounced function. + * @returns Returns a function to call the debounced function. */ export default function useDebounce(func, wait, options) { const debouncedFnRef = useRef(); @@ -21,5 +21,11 @@ export default function useDebounce(func, wait, options) { return debouncedFn.cancel; }, [func, wait, options]); - return debouncedFnRef.current; + return (...args) => { + const debouncedFn = debouncedFnRef.current; + + if (debouncedFn) { + debouncedFn(...args); + } + }; } From ce36e646656402094f7ad8737557a7481dea15c9 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 20 Sep 2023 11:14:32 +0200 Subject: [PATCH 080/250] fix: removed not needed onyx migration --- src/libs/migrateOnyx.js | 2 -- .../migrations/RenameExpensifyNewsStatus.ts | 35 ------------------- 2 files changed, 37 deletions(-) delete mode 100644 src/libs/migrations/RenameExpensifyNewsStatus.ts diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js index 9389a9b66fbc..a58bb79a26f9 100644 --- a/src/libs/migrateOnyx.js +++ b/src/libs/migrateOnyx.js @@ -4,7 +4,6 @@ import AddEncryptedAuthToken from './migrations/AddEncryptedAuthToken'; import RenameActiveClientsKey from './migrations/RenameActiveClientsKey'; import RenamePriorityModeKey from './migrations/RenamePriorityModeKey'; import MoveToIndexedDB from './migrations/MoveToIndexedDB'; -import RenameExpensifyNewsStatus from './migrations/RenameExpensifyNewsStatus'; import AddLastVisibleActionCreated from './migrations/AddLastVisibleActionCreated'; import KeyReportActionsByReportActionID from './migrations/KeyReportActionsByReportActionID'; import PersonalDetailsByAccountID from './migrations/PersonalDetailsByAccountID'; @@ -20,7 +19,6 @@ export default function () { RenameActiveClientsKey, RenamePriorityModeKey, AddEncryptedAuthToken, - RenameExpensifyNewsStatus, AddLastVisibleActionCreated, KeyReportActionsByReportActionID, PersonalDetailsByAccountID, diff --git a/src/libs/migrations/RenameExpensifyNewsStatus.ts b/src/libs/migrations/RenameExpensifyNewsStatus.ts deleted file mode 100644 index fd8c2cc62b61..000000000000 --- a/src/libs/migrations/RenameExpensifyNewsStatus.ts +++ /dev/null @@ -1,35 +0,0 @@ -import Onyx from 'react-native-onyx'; -import ONYXKEYS from '../../ONYXKEYS'; -import Log from '../Log'; - -// This migration changes the name of the Onyx key user.expensifyNewsStatus from expensifyNewsStatus to isSubscribedToNewsletter -export default function () { - return new Promise((resolve) => { - // Connect to the USER key in Onyx to get the value of expensifyNewsStatus - // then set that value as isSubscribedToNewsletter - // finally remove expensifyNewsStatus by setting the value to null - const connectionID = Onyx.connect({ - key: ONYXKEYS.USER, - callback: (user) => { - Onyx.disconnect(connectionID); - - // Fail early here because there is nothing to migrate - if (user?.expensifyNewsStatus === null || user?.expensifyNewsStatus === undefined) { - Log.info('[Migrate Onyx] Skipped migration RenameExpensifyNewsStatus'); - // @ts-expect-error In that case we don't need to resolve anything - return resolve(); - } - - // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.merge(ONYXKEYS.USER, { - expensifyNewsStatus: null, - isSubscribedToNewsletter: user.expensifyNewsStatus, - }).then(() => { - Log.info('[Migrate Onyx] Ran migration RenameExpensifyNewsStatus'); - // @ts-expect-error In that case we don't need to resolve anything - resolve(); - }); - }, - }); - }); -} From 34b682590100951da4ba06e0a098016719f9b98c Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 17:17:17 +0800 Subject: [PATCH 081/250] add return type --- src/hooks/useDebounce.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index d6ff20a1e91b..266ea5d3058a 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -8,7 +8,7 @@ import lodashDebounce from 'lodash/debounce'; * @param {Boolean} options.leading Specify invoking on the leading edge of the timeout. * @param {Number} options.maxWait The maximum time func is allowed to be delayed before it’s invoked. * @param {Boolean} options.trailing Specify invoking on the trailing edge of the timeout. - * @returns Returns a function to call the debounced function. + * @returns {Function} Returns a function to call the debounced function. */ export default function useDebounce(func, wait, options) { const debouncedFnRef = useRef(); From dfa7435cc1211b81a5e359a72c683db980e07e8b Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 17:32:36 +0800 Subject: [PATCH 082/250] prettier --- .../home/report/ReportActionCompose/ComposerWithSuggestions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 847f3146a7b8..53c71aa82f94 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -141,7 +141,7 @@ function ComposerWithSuggestions({ /** * Reset isScrollLikelyLayoutTriggered to false. - * + * * The function is debounced with a handpicked wait time to address 2 issues: * 1. There is a slight delay between onChangeText and onScroll * 2. Layout change will trigger onScroll multiple times From 6f2fbfcabe8ab623377b5e506190248b8b639577 Mon Sep 17 00:00:00 2001 From: ginsuma <13113013+ginsuma@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:45:18 +0700 Subject: [PATCH 083/250] Clean code --- src/components/ReportActionItem/MoneyRequestView.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index aff4159bbcdb..6e46ee25359e 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -96,6 +96,8 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans } const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction); + const pendingAction = lodashGet(transaction, 'pendingAction'); + const getPendingFieldAction = (fieldPath) => lodashGet(transaction, fieldPath) || pendingAction; return ( @@ -108,7 +110,7 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans {hasReceipt && ( - + )} - + - + - + - + Date: Wed, 20 Sep 2023 18:27:11 +0800 Subject: [PATCH 084/250] update comment --- src/hooks/useDebounce.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index 266ea5d3058a..7a44ad4deb1b 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -2,6 +2,10 @@ import {useEffect, useRef} from 'react'; import lodashDebounce from 'lodash/debounce'; /** + * Create and return a debounced function. + * + * Make sure to pass a stable function reference to prevent recreating the debounced function on each render. + * * @param {Function} func The function to debounce. * @param {Number} wait The number of milliseconds to delay. * @param {Object} options The options object. From 364fb226f8c29706f18231d34d740fa5fdd82e33 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 20 Sep 2023 12:29:47 +0200 Subject: [PATCH 085/250] ref: reverted changes from User type --- src/types/onyx/User.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/onyx/User.ts b/src/types/onyx/User.ts index 097915490476..f770b22b2272 100644 --- a/src/types/onyx/User.ts +++ b/src/types/onyx/User.ts @@ -25,7 +25,6 @@ type User = { /** Whether the form is being submitted */ loading?: boolean; - expensifyNewsStatus?: boolean | null; }; export default User; From 76b9cc7cf578e263a82d27e860281e0a31c2c9b3 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 18:37:07 +0800 Subject: [PATCH 086/250] prettier --- src/hooks/useDebounce.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index 7a44ad4deb1b..ccafb832e7ab 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -3,9 +3,9 @@ import lodashDebounce from 'lodash/debounce'; /** * Create and return a debounced function. - * + * * Make sure to pass a stable function reference to prevent recreating the debounced function on each render. - * + * * @param {Function} func The function to debounce. * @param {Number} wait The number of milliseconds to delay. * @param {Object} options The options object. From f91c354ba259f226d1859fdf23e5a4d814d28bf4 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 20 Sep 2023 13:02:20 +0200 Subject: [PATCH 087/250] fix: resolve comment --- src/libs/actions/Transaction.ts | 1 - src/types/onyx/Transaction.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 4196fb4c3281..89e7fc06cafa 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -133,7 +133,6 @@ function removeWaypoint(transactionID: string, currentIndex: string) { route0: { distance: null, geometry: { - type: '', coordinates: null, }, }, diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 4df5377d309b..8ed915cea4a4 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -9,11 +9,11 @@ type Comment = { waypoints?: WaypointCollection; }; -type GeometryType = 'LineString' | ''; +type GeometryType = 'LineString'; type Geometry = { coordinates: number[][] | null; - type: GeometryType; + type?: GeometryType; }; type Route = { From e50ffdb5d0c74cef7f62c14c4d3ed6378f5a1295 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 20 Sep 2023 19:07:38 +0700 Subject: [PATCH 088/250] fix: 22388 --- src/pages/iou/steps/NewRequestAmountPage.js | 26 +++++++-------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index 6712a8c7cd81..bc1dd6e2f3f6 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -69,24 +69,17 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { const currency = currentCurrency || iou.currency; - const focusTextInput = () => { - // Component may not be initialized due to navigation transitions - // Wait until interactions are complete before trying to focus - InteractionManager.runAfterInteractions(() => { - // Focus text input - if (!textInput.current) { + const focusTimeoutRef = useRef(null); + + useFocusEffect(useCallback(() => { + focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); + return () => { + if (!focusTimeoutRef.current) { return; } - - textInput.current.focus(); - }); - }; - - useFocusEffect( - useCallback(() => { - focusTextInput(); - }, []), - ); + clearTimeout(focusTimeoutRef.current); + }; + }, [])); // Check and dismiss modal useEffect(() => { @@ -175,7 +168,6 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { {({safeAreaPaddingBottomStyle}) => ( From 4b71ed2c879a645c75c20f93ca1ae43d318b5e05 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 20 Sep 2023 21:26:43 +0800 Subject: [PATCH 089/250] update comment --- src/hooks/useDebounce.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index ccafb832e7ab..137c41e8bfb1 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -4,7 +4,8 @@ import lodashDebounce from 'lodash/debounce'; /** * Create and return a debounced function. * - * Make sure to pass a stable function reference to prevent recreating the debounced function on each render. + * Every time the identity of any of the arguments changes, the debounce operation will restart (canceling any ongoing debounce). + * This is especially important in the case of func. To prevent that, pass stable references. * * @param {Function} func The function to debounce. * @param {Number} wait The number of milliseconds to delay. From 0eba8a5c228014fbe85b01182a744e766a51fb97 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Wed, 20 Sep 2023 15:42:28 +0200 Subject: [PATCH 090/250] [TS migration] Migrate 'CurrencyUtils.js' lib --- .../{CurrencyUtils.js => CurrencyUtils.ts} | 60 +++++++------------ 1 file changed, 22 insertions(+), 38 deletions(-) rename src/libs/{CurrencyUtils.js => CurrencyUtils.ts} (68%) diff --git a/src/libs/CurrencyUtils.js b/src/libs/CurrencyUtils.ts similarity index 68% rename from src/libs/CurrencyUtils.js rename to src/libs/CurrencyUtils.ts index 6cbb0db7661b..bc0c8cb77aca 100644 --- a/src/libs/CurrencyUtils.js +++ b/src/libs/CurrencyUtils.ts @@ -1,16 +1,18 @@ -import _ from 'underscore'; -import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; import CONST from '../CONST'; import BaseLocaleListener from './Localize/LocaleListener/BaseLocaleListener'; import * as NumberFormatUtils from './NumberFormatUtils'; +import {Currency} from '../types/onyx'; + +type CurrencyList = Record; + +let currencyList: CurrencyList = {}; -let currencyList = {}; Onyx.connect({ key: ONYXKEYS.CURRENCY_LIST, callback: (val) => { - if (_.isEmpty(val)) { + if (!val || Object.keys(val).length === 0) { return; } @@ -23,56 +25,45 @@ Onyx.connect({ * For currencies that have decimal places > 2, floor to 2 instead: * https://github.com/Expensify/App/issues/15878#issuecomment-1496291464 * - * @param {String} currency - IOU currency - * @returns {Number} + * @param currency - IOU currency */ -function getCurrencyDecimals(currency = CONST.CURRENCY.USD) { - const decimals = lodashGet(currencyList, [currency, 'decimals']); - return _.isUndefined(decimals) ? 2 : decimals; +function getCurrencyDecimals(currency: string = CONST.CURRENCY.USD): number { + const decimals = currencyList?.[currency]?.decimals; + return decimals ?? 2; } /** * Returns the currency's minor unit quantity * e.g. Cent in USD * - * @param {String} currency - IOU currency - * @returns {Number} + * @param currency - IOU currency */ -function getCurrencyUnit(currency = CONST.CURRENCY.USD) { +function getCurrencyUnit(currency: string = CONST.CURRENCY.USD): number { return 10 ** getCurrencyDecimals(currency); } /** * Get localized currency symbol for currency(ISO 4217) Code - * - * @param {String} currencyCode - * @returns {String} */ -function getLocalizedCurrencySymbol(currencyCode) { +function getLocalizedCurrencySymbol(currencyCode: string): string | undefined { const parts = NumberFormatUtils.formatToParts(BaseLocaleListener.getPreferredLocale(), 0, { style: 'currency', currency: currencyCode, }); - return _.find(parts, (part) => part.type === 'currency').value; + return parts.find((part) => part.type === 'currency')?.value; } /** * Get the currency symbol for a currency(ISO 4217) Code - * - * @param {String} currencyCode - * @returns {String|undefined} */ -function getCurrencySymbol(currencyCode) { - return lodashGet(currencyList, [currencyCode, 'symbol']); +function getCurrencySymbol(currencyCode: string): string | undefined { + return currencyList?.[currencyCode]?.symbol; } /** * Whether the currency symbol is left-to-right. - * - * @param {String} currencyCode - * @returns {Boolean} */ -function isCurrencySymbolLTR(currencyCode) { +function isCurrencySymbolLTR(currencyCode: string): boolean { const parts = NumberFormatUtils.formatToParts(BaseLocaleListener.getPreferredLocale(), 0, { style: 'currency', currency: currencyCode, @@ -88,11 +79,8 @@ function isCurrencySymbolLTR(currencyCode) { * when doing math operations. * * @note we do not currently support any currencies with more than two decimal places. Decimal past the second place will be rounded. Sorry Tunisia :( - * - * @param {Number} amountAsFloat - * @returns {Number} */ -function convertToBackendAmount(amountAsFloat) { +function convertToBackendAmount(amountAsFloat: number): number { return Math.round(amountAsFloat * 100); } @@ -100,11 +88,8 @@ function convertToBackendAmount(amountAsFloat) { * Takes an amount in "cents" as an integer and converts it to a floating point amount used in the frontend. * * @note we do not support any currencies with more than two decimal places. - * - * @param {Number} amountAsInt - * @returns {Number} */ -function convertToFrontendAmount(amountAsInt) { +function convertToFrontendAmount(amountAsInt: number): number { return Math.trunc(amountAsInt) / 100.0; } @@ -112,11 +97,10 @@ function convertToFrontendAmount(amountAsInt) { * Given an amount in the "cents", convert it to a string for display in the UI. * The backend always handle things in "cents" (subunit equal to 1/100) * - * @param {Number} amountInCents – should be an integer. Anything after a decimal place will be dropped. - * @param {String} currency - * @returns {String} + * @param amountInCents – should be an integer. Anything after a decimal place will be dropped. + * @param currency - IOU currency */ -function convertToDisplayString(amountInCents, currency = CONST.CURRENCY.USD) { +function convertToDisplayString(amountInCents: number, currency: string = CONST.CURRENCY.USD): string { const convertedAmount = convertToFrontendAmount(amountInCents); return NumberFormatUtils.format(BaseLocaleListener.getPreferredLocale(), convertedAmount, { style: 'currency', From 3deab5e032cbc4c090f906ca38b18b2b91d688b1 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Wed, 20 Sep 2023 16:57:31 +0200 Subject: [PATCH 091/250] Bump reanimated to 3.5.3 --- ios/Podfile.lock | 4 +- package-lock.json | 34 ++++++++------ package.json | 2 +- patches/react-native-reanimated+3.5.2.patch | 52 --------------------- 4 files changed, 23 insertions(+), 69 deletions(-) delete mode 100644 patches/react-native-reanimated+3.5.2.patch diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 1d20b93a3a39..9c14d69aca55 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.5.2): + - RNReanimated (3.5.3): - DoubleConversion - FBLazyVector - glog @@ -1298,7 +1298,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: 2491645f0883526f4470d8b5c761308709ba31f8 + RNReanimated: e037aac4d8b0055a399f5af065e8210f6c8cc900 RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d diff --git a/package-lock.json b/package-lock.json index bfb5ad3518e8..68ca30f17289 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,7 +99,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "^3.5.2", + "react-native-reanimated": "^3.5.3", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", @@ -1777,10 +1777,11 @@ } }, "node_modules/@babel/plugin-transform-object-assign": { - "version": "7.18.6", - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.22.5.tgz", + "integrity": "sha512-iDhx9ARkXq4vhZ2CYOSnQXkmxkDgosLi3J8Z17mKz7LyzthtkdVchLD7WZ3aXeCuvJDOW3+1I5TpJmwIbF9MKQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -40696,9 +40697,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.2.tgz", - "integrity": "sha512-Uv9imJ6ZC7F/tTSpjjfo/0AZlw19Lag63+MUqF6p483LOoRkYtYP3JmtVV402mQWfhL1LPMeyAu/1spRjPKCCQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.3.tgz", + "integrity": "sha512-zjGJL2rgYLiEqIwaIOd+/dgRZzot4wKUvKk0ZXeWY7SJg4Bp+9yQTOT98Jx6b1/Cga2YY71i0tIu3hanLajGAQ==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -40718,7 +40719,8 @@ }, "node_modules/react-native-reanimated/node_modules/convert-source-map": { "version": "2.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/react-native-render-html": { "version": "6.3.1", @@ -49140,9 +49142,11 @@ } }, "@babel/plugin-transform-object-assign": { - "version": "7.18.6", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.22.5.tgz", + "integrity": "sha512-iDhx9ARkXq4vhZ2CYOSnQXkmxkDgosLi3J8Z17mKz7LyzthtkdVchLD7WZ3aXeCuvJDOW3+1I5TpJmwIbF9MKQ==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-object-rest-spread": { @@ -76177,9 +76181,9 @@ "requires": {} }, "react-native-reanimated": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.2.tgz", - "integrity": "sha512-Uv9imJ6ZC7F/tTSpjjfo/0AZlw19Lag63+MUqF6p483LOoRkYtYP3JmtVV402mQWfhL1LPMeyAu/1spRjPKCCQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.3.tgz", + "integrity": "sha512-zjGJL2rgYLiEqIwaIOd+/dgRZzot4wKUvKk0ZXeWY7SJg4Bp+9yQTOT98Jx6b1/Cga2YY71i0tIu3hanLajGAQ==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -76188,7 +76192,9 @@ }, "dependencies": { "convert-source-map": { - "version": "2.0.0" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" } } }, diff --git a/package.json b/package.json index 48e9c878dd44..dabb5d0afde9 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "^3.5.2", + "react-native-reanimated": "^3.5.3", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", diff --git a/patches/react-native-reanimated+3.5.2.patch b/patches/react-native-reanimated+3.5.2.patch deleted file mode 100644 index c509e4c4cd2e..000000000000 --- a/patches/react-native-reanimated+3.5.2.patch +++ /dev/null @@ -1,52 +0,0 @@ -diff --git a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js -index 0027008..2aea2ff 100644 ---- a/node_modules/react-native-reanimated/lib/module/reanimated2/index.js -+++ b/node_modules/react-native-reanimated/lib/module/reanimated2/index.js -@@ -1,15 +1,15 @@ - import './publicGlobals'; --export { runOnJS, runOnUI, createWorkletRuntime, WorkletRuntime, makeMutable, makeShareableCloneRecursive, isReanimated3, isConfigured, enableLayoutAnimations, getViewProp } from './core'; --export { useAnimatedProps, useEvent, useHandler, useWorkletCallback, useSharedValue, useReducedMotion, useAnimatedStyle, useAnimatedGestureHandler, GestureHandlers, useAnimatedReaction, AnimatedRef, useAnimatedRef, useAnimatedScrollHandler, ScrollHandler, ScrollHandlers, useDerivedValue, DerivedValue, useAnimatedSensor, useFrameCallback, FrameCallback, useAnimatedKeyboard, useScrollViewOffset } from './hook'; --export { DelayAnimation, RepeatAnimation, SequenceAnimation, StyleLayoutAnimation, cancelAnimation, defineAnimation, withTiming, WithTimingConfig, TimingAnimation, withSpring, WithSpringConfig, SpringAnimation, withDecay, WithDecayConfig, DecayAnimation, withDelay, withRepeat, withSequence } from './animation'; --export { Extrapolation, ExtrapolationConfig, ExtrapolationType, interpolate, clamp } from './interpolation'; --export { Extrapolate, InterpolationOptions, interpolateColor, ColorSpace, InterpolateConfig, useInterpolateConfig, InterpolateRGB, InterpolateHSV } from './interpolateColor'; --export { EasingFunction, EasingFn, EasingFunctionFactory, EasingFactoryFn, Easing } from './Easing'; -+export { runOnJS, runOnUI, createWorkletRuntime, makeMutable, makeShareableCloneRecursive, isReanimated3, isConfigured, enableLayoutAnimations, getViewProp } from './core'; -+export { useAnimatedProps, useEvent, useHandler, useWorkletCallback, useSharedValue, useReducedMotion, useAnimatedStyle, useAnimatedGestureHandler, useAnimatedReaction, useAnimatedRef, useAnimatedScrollHandler, useDerivedValue, useAnimatedSensor, useFrameCallback, useAnimatedKeyboard, useScrollViewOffset } from './hook'; -+export { cancelAnimation, defineAnimation, withTiming, withSpring, withDecay, withDelay, withRepeat, withSequence } from './animation'; -+export { interpolate, clamp } from './interpolation'; -+export { Extrapolate, interpolateColor, useInterpolateConfig } from './interpolateColor'; -+export { Easing } from './Easing'; - export { measure, dispatchCommand, scrollTo, setGestureState } from './NativeMethods'; - export { setNativeProps } from './SetNativeProps'; --export { isColor, processColor, ParsedColorArray, convertToRGBA } from './Colors'; -+export { isColor, processColor, convertToRGBA } from './Colors'; - export { createAnimatedPropAdapter } from './PropAdapters'; --export { BaseAnimationBuilder, ComplexAnimationBuilder, Keyframe, LayoutAnimation, EntryAnimationsValues, ExitAnimationsValues, EntryExitAnimationFunction, LayoutAnimationsValues, LayoutAnimationFunction, ILayoutAnimationBuilder, IEntryExitAnimationBuilder, -+export { BaseAnimationBuilder, ComplexAnimationBuilder, Keyframe, - // Flip - FlipInXUp, FlipInYLeft, FlipInXDown, FlipInYRight, FlipInEasyX, FlipInEasyY, FlipOutXUp, FlipOutYLeft, FlipOutXDown, FlipOutYRight, FlipOutEasyX, FlipOutEasyY, - // Stretch -@@ -34,9 +34,7 @@ RollInLeft, RollInRight, RollOutLeft, RollOutRight, - Layout, LinearTransition, FadingTransition, SequencedTransition, JumpingTransition, CurvedTransition, EntryExitTransition, combineTransition, - // SET - SharedTransition, SharedTransitionType } from './layoutReanimation'; --export { getRelativeCoords, ComponentCoords, isSharedValue } from './utils'; --export { StyleProps, SharedValue, AnimatableValueObject, AnimatableValue, AnimationObject, Animation, SensorType, IOSReferenceFrame, SensorConfig, AnimatedSensor, AnimationCallback, Value3D, ValueRotation, InterfaceOrientation, KeyboardState, AnimatedKeyboardInfo, MeasuredDimensions, AnimatedKeyboardOptions, ReduceMotion } from './commonTypes'; --export { FrameInfo } from './frameCallback'; -+export { getRelativeCoords, isSharedValue } from './utils'; -+export { SensorType, IOSReferenceFrame, InterfaceOrientation, KeyboardState, ReduceMotion } from './commonTypes'; - export { getUseOfValueInStyleWarning } from './pluginUtils'; --export { withReanimatedTimer, advanceAnimationByTime, advanceAnimationByFrame, setUpTests, getAnimatedStyle } from './jestUtils'; - //# sourceMappingURL=index.js.map -\ No newline at end of file -diff --git a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts -index 4df2481..cca7f1a 100644 ---- a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts -+++ b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts -@@ -40,5 +40,5 @@ export function isReducedMotion() { - ? isWindowAvailable() - ? !window.matchMedia('(prefers-reduced-motion: no-preference)').matches - : false -- : global._REANIMATED_IS_REDUCED_MOTION ?? false; -+ : (global as any)._REANIMATED_IS_REDUCED_MOTION ?? false; - } From ee8c075337667b0ae419034053d381b66662d355 Mon Sep 17 00:00:00 2001 From: Viktoryia Kliushun Date: Wed, 20 Sep 2023 17:41:29 +0200 Subject: [PATCH 092/250] Remove extra type --- src/libs/CurrencyUtils.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/libs/CurrencyUtils.ts b/src/libs/CurrencyUtils.ts index bc0c8cb77aca..0f6dc08b42b3 100644 --- a/src/libs/CurrencyUtils.ts +++ b/src/libs/CurrencyUtils.ts @@ -1,13 +1,10 @@ import Onyx from 'react-native-onyx'; -import ONYXKEYS from '../ONYXKEYS'; +import ONYXKEYS, {OnyxValues} from '../ONYXKEYS'; import CONST from '../CONST'; import BaseLocaleListener from './Localize/LocaleListener/BaseLocaleListener'; import * as NumberFormatUtils from './NumberFormatUtils'; -import {Currency} from '../types/onyx'; -type CurrencyList = Record; - -let currencyList: CurrencyList = {}; +let currencyList: OnyxValues[typeof ONYXKEYS.CURRENCY_LIST] = {}; Onyx.connect({ key: ONYXKEYS.CURRENCY_LIST, From 9ae84b4f6c26abb6376915057c1c65e50c88a44c Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Wed, 20 Sep 2023 17:47:06 +0200 Subject: [PATCH 093/250] Fix types by adding globals.d.ts --- patches/react-native-reanimated+3.5.3.patch | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 patches/react-native-reanimated+3.5.3.patch diff --git a/patches/react-native-reanimated+3.5.3.patch b/patches/react-native-reanimated+3.5.3.patch new file mode 100644 index 000000000000..cf6ee2e271c2 --- /dev/null +++ b/patches/react-native-reanimated+3.5.3.patch @@ -0,0 +1,10 @@ +diff --git a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts +index 4df2481..2be308f 100644 +--- a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts ++++ b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts +@@ -1,4 +1,5 @@ + import { Platform } from 'react-native'; ++import './globals.d.ts' + + export function isJest(): boolean { + return !!process.env.JEST_WORKER_ID; From e416c34821adda0a9b2f2cc871574fae4284b24f Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 21 Sep 2023 02:05:36 +0800 Subject: [PATCH 094/250] unpack options args --- src/hooks/useDebounce.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index 137c41e8bfb1..2d6ad83bedab 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -17,14 +17,15 @@ import lodashDebounce from 'lodash/debounce'; */ export default function useDebounce(func, wait, options) { const debouncedFnRef = useRef(); + const {leading, maxWait, trailing} = options || {}; useEffect(() => { - const debouncedFn = lodashDebounce(func, wait, options); + const debouncedFn = lodashDebounce(func, wait, {leading, maxWait, trailing}); debouncedFnRef.current = debouncedFn; return debouncedFn.cancel; - }, [func, wait, options]); + }, [func, wait, leading, maxWait, trailing]); return (...args) => { const debouncedFn = debouncedFnRef.current; From eda02a0807499330fb3b5015000f3ecef8dafc63 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 20 Sep 2023 19:52:55 +0000 Subject: [PATCH 095/250] Fix Copying Sent Money Report Action text copies the wrong text --- .../report/ContextMenu/ContextMenuActions.js | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 173bda0e5221..8abfe2555019 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -207,11 +207,34 @@ export default [ const transaction = TransactionUtils.getTransaction(originalMessage.IOUTransactionID); const {amount, currency, comment} = ReportUtils.getTransactionDetails(transaction); const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); - const displaymessage = Localize.translateLocal('iou.requestedAmount', { - formattedAmount, - comment, - }); - Clipboard.setString(displaymessage); + let displayMessage; + if (ReportActionsUtils.isSentMoneyReportAction(reportAction)) { + const iouReport = ReportUtils.getReport(originalMessage.IOUReportID); + const payerName = ReportUtils.getDisplayNameForParticipant(iouReport.managerID, true); + let translationKey; + switch (originalMessage.paymentType) { + case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: + translationKey = 'iou.paidElsewhereWithAmount'; + break; + case CONST.IOU.PAYMENT_TYPE.PAYPAL_ME: + translationKey = 'iou.paidUsingPaypalWithAmount'; + break; + case CONST.IOU.PAYMENT_TYPE.EXPENSIFY: + case CONST.IOU.PAYMENT_TYPE.VBBA: + translationKey = 'iou.paidUsingExpensifyWithAmount'; + break; + default: + translationKey = ''; + break; + } + displayMessage = Localize.translateLocal(translationKey, {amount: formattedAmount, payer: payerName}); + } else { + displayMessage = Localize.translateLocal('iou.requestedAmount', { + formattedAmount, + comment, + }); + } + Clipboard.setString(displayMessage); } else if (content) { const parser = new ExpensiMark(); if (!Clipboard.canSetHtml()) { From 540dfa154de61ab9421d6fc0c0a3089d2b5ae2ff Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 20 Sep 2023 21:05:43 +0000 Subject: [PATCH 096/250] Fix Copying Sent Money Report Action text copies the wrong text --- .../home/report/ContextMenu/ContextMenuActions.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 8abfe2555019..d965fe457d76 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -204,13 +204,12 @@ export default [ Clipboard.setString(modifyExpenseMessage); } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { const originalMessage = _.get(reportAction, 'originalMessage', {}); - const transaction = TransactionUtils.getTransaction(originalMessage.IOUTransactionID); - const {amount, currency, comment} = ReportUtils.getTransactionDetails(transaction); - const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); let displayMessage; if (ReportActionsUtils.isSentMoneyReportAction(reportAction)) { - const iouReport = ReportUtils.getReport(originalMessage.IOUReportID); - const payerName = ReportUtils.getDisplayNameForParticipant(iouReport.managerID, true); + const {amount, currency, IOUReportID} = originalMessage; + const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); + const iouReport = ReportUtils.getReport(IOUReportID); + const payerName = ReportActionsUtils.getDisplayNameForParticipant(iouReport.managerID, true); let translationKey; switch (originalMessage.paymentType) { case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: @@ -229,6 +228,9 @@ export default [ } displayMessage = Localize.translateLocal(translationKey, {amount: formattedAmount, payer: payerName}); } else { + const transaction = TransactionUtils.getTransaction(originalMessage.IOUTransactionID); + const {amount, currency, comment} = ReportUtils.getTransactionDetails(transaction); + const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); displayMessage = Localize.translateLocal('iou.requestedAmount', { formattedAmount, comment, From 0167ae13c1d1d5fa6fe6cf6c852e400e14ec3877 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 20 Sep 2023 21:25:53 +0000 Subject: [PATCH 097/250] using getDisplayNameForParticipant function lib from ReportUtils instead of ReportActionsUtils --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index d965fe457d76..9ee801fbd4a6 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -205,11 +205,11 @@ export default [ } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { const originalMessage = _.get(reportAction, 'originalMessage', {}); let displayMessage; - if (ReportActionsUtils.isSentMoneyReportAction(reportAction)) { + if (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY) { const {amount, currency, IOUReportID} = originalMessage; const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); const iouReport = ReportUtils.getReport(IOUReportID); - const payerName = ReportActionsUtils.getDisplayNameForParticipant(iouReport.managerID, true); + const payerName = ReportUtils.getDisplayNameForParticipant(iouReport.managerID, true); let translationKey; switch (originalMessage.paymentType) { case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: From 7ebcd09ecedf35b2e1f3bc2a9a6365dfacb0f6c1 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 20 Sep 2023 23:38:22 +0200 Subject: [PATCH 098/250] Move custom authorizer channel into separate type --- src/libs/PusherConnectionManager.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/PusherConnectionManager.ts b/src/libs/PusherConnectionManager.ts index f5dfc623fc14..4ab08d6dc760 100644 --- a/src/libs/PusherConnectionManager.ts +++ b/src/libs/PusherConnectionManager.ts @@ -5,6 +5,7 @@ import Log from './Log'; import CONST from '../CONST'; type EventCallbackError = {type: ValueOf; data: {code: number}}; +type CustomAuthorizerChannel = {name: string}; function init() { /** @@ -13,7 +14,7 @@ function init() { * current valid token to generate the signed auth response * needed to subscribe to Pusher channels. */ - Pusher.registerCustomAuthorizer((channel: {name: string}) => ({ + Pusher.registerCustomAuthorizer((channel: CustomAuthorizerChannel) => ({ authorize: (socketID: string, callback: () => void) => { Session.authenticatePusher(socketID, channel.name, callback); }, From 665740f0f828a3c319103d8ac8bcd4032a551c63 Mon Sep 17 00:00:00 2001 From: Dustin Stringer Date: Wed, 20 Sep 2023 23:10:34 -0400 Subject: [PATCH 099/250] Removed 32 pixel margin on iouAmountText --- src/styles/styles.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/styles/styles.js b/src/styles/styles.js index 46240542cede..8ff1731945b2 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2680,9 +2680,6 @@ const styles = (theme) => ({ fontSize: variables.iouAmountTextSize, color: theme.heading, lineHeight: variables.inputHeight, - // This margin counteracts the additional size given to the autoGrow text in BaseTextInput.js - // It fixes issue https://github.com/Expensify/App/issues/26628 - marginLeft: 32 }, iouAmountTextInput: addOutlineWidth( From f8550327c3ed20c47a68f8dccc3f1429b0cac665 Mon Sep 17 00:00:00 2001 From: Dustin Stringer Date: Wed, 20 Sep 2023 23:11:15 -0400 Subject: [PATCH 100/250] Added additional autoGrow width for Safari browser --- src/components/TextInput/BaseTextInput.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index cce8bda03591..3fae15a99ee1 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -21,6 +21,7 @@ import isInputAutoFilled from '../../libs/isInputAutoFilled'; import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback'; import withLocalize from '../withLocalize'; import useNativeDriver from '../../libs/useNativeDriver'; +import * as Browser from '../../libs/Browser'; function BaseTextInput(props) { const inputValue = props.value || props.defaultValue || ''; @@ -399,13 +400,17 @@ function BaseTextInput(props) { This Text component is intentionally positioned out of the screen. */} {(props.autoGrow || props.autoGrowHeight) && ( - // Add +32 to width so that text is not cut off due to the cursor or when changing the value + // Add +2 to width on Safari browsers so that text is not cut off due to the cursor or when changing the value // https://github.com/Expensify/App/issues/8158 // https://github.com/Expensify/App/issues/26628 { - setTextInputWidth(e.nativeEvent.layout.width + 32); + let additionalWidth = 0 + if (Browser.isMobileSafari() || Browser.isSafari()) { + additionalWidth = 2; + } + setTextInputWidth(e.nativeEvent.layout.width + additionalWidth); setTextInputHeight(e.nativeEvent.layout.height); }} > From 322201c843b9e77be98924950619eaf7a1e1440a Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 21 Sep 2023 10:43:29 +0700 Subject: [PATCH 101/250] edit the route of new task page --- src/ROUTES.ts | 2 -- src/libs/Navigation/linkingConfig.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2c37116db395..6b26ec95b101 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -121,8 +121,6 @@ export default { getMoneyRequestTagRoute: (iouType: string, reportID = '') => `${iouType}/new/tag/${reportID}`, SPLIT_BILL_DETAILS: `r/:reportID/split/:reportActionID`, getSplitBillDetailsRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}`, - getNewTaskRoute: (reportID: string) => `${NEW_TASK}/${reportID}`, - NEW_TASK_WITH_REPORT_ID: `${NEW_TASK}/:reportID?`, TASK_TITLE: 'r/:reportID/title', TASK_DESCRIPTION: 'r/:reportID/description', TASK_ASSIGNEE: 'r/:reportID/assignee', diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index f4420330fbd9..5cf8170632b8 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -263,7 +263,7 @@ export default { }, NewTask: { screens: { - NewTask_Root: ROUTES.NEW_TASK_WITH_REPORT_ID, + NewTask_Root: ROUTES.NEW_TASK, NewTask_TaskAssigneeSelector: ROUTES.NEW_TASK_ASSIGNEE, NewTask_TaskShareDestinationSelector: ROUTES.NEW_TASK_SHARE_DESTINATION, NewTask_Details: ROUTES.NEW_TASK_DETAILS, From 8248196c7d93c56952664c9d6ae2b5290147bc87 Mon Sep 17 00:00:00 2001 From: Hans Date: Thu, 21 Sep 2023 13:29:02 +0700 Subject: [PATCH 102/250] fix duplicate participant name and avatar --- src/pages/home/report/ReportActionItemSingle.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index bfbce8aed336..7d71ad00a0f3 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -114,14 +114,15 @@ function ReportActionItemSingle(props) { let secondaryAvatar = {}; const primaryDisplayName = displayName; if (displayAllActors) { - const secondaryUserDetails = props.personalDetailsList[props.iouReport.ownerAccountID] || {}; + const secondaryAccountId = props.iouReport.ownerAccountID === actorAccountID ? props.iouReport.managerID : props.iouReport.ownerAccountID; + const secondaryUserDetails = props.personalDetailsList[secondaryAccountId] || {}; const secondaryDisplayName = lodashGet(secondaryUserDetails, 'displayName', ''); displayName = `${primaryDisplayName} & ${secondaryDisplayName}`; secondaryAvatar = { - source: UserUtils.getAvatar(secondaryUserDetails.avatar, props.iouReport.ownerAccountID), + source: UserUtils.getAvatar(secondaryUserDetails.avatar, secondaryAccountId), type: CONST.ICON_TYPE_AVATAR, name: secondaryDisplayName, - id: props.iouReport.ownerAccountID, + id: secondaryAccountId, }; } else if (!isWorkspaceActor) { secondaryAvatar = ReportUtils.getIcons(props.report, {})[props.report.isOwnPolicyExpenseChat ? 0 : 1]; From c535d03c84322eaaf64f809cb49f6f3eb8de3ce6 Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Thu, 21 Sep 2023 08:35:55 +0200 Subject: [PATCH 103/250] Handle the green dot indicator for canceled tasks --- src/components/LHNOptionsList/OptionRowLHN.js | 4 ++-- src/components/LHNOptionsList/OptionRowLHNData.js | 2 +- src/libs/ReportUtils.js | 12 ++++++++++-- src/libs/SidebarUtils.js | 6 +++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index f5a293701454..da1eaad2f0c2 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -104,8 +104,8 @@ function OptionRowLHN(props) { const shouldShowGreenDotIndicator = !hasBrickError && (optionItem.isUnreadWithMention || - ReportUtils.isWaitingForIOUActionFromCurrentUser(optionItem) || - (optionItem.isTaskReport && optionItem.isTaskAssignee && !optionItem.isCompletedTaskReport && !optionItem.isArchivedRoom)); + optionItem.isWaitingForTaskCompleteFromAssignee || + ReportUtils.isWaitingForIOUActionFromCurrentUser(optionItem)); /** * Show the ReportActionContextMenu modal popover. diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 2c51d6332946..345ba288c42d 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -106,7 +106,7 @@ function OptionRowLHNData({ const optionItem = useMemo(() => { // Note: ideally we'd have this as a dependent selector in onyx! - const item = SidebarUtils.getOptionData(fullReport, reportActions, personalDetails, preferredLocale, policy); + const item = SidebarUtils.getOptionData(fullReport, reportActions, personalDetails, preferredLocale, policy, parentReportAction); if (deepEqual(item, optionItemRef.current)) { return optionItemRef.current; } diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index edf646d0266b..384a2037fbe9 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1215,8 +1215,15 @@ function isWaitingForIOUActionFromCurrentUser(report) { return false; } -function isWaitingForTaskCompleteFromAssignee(report) { - return isTaskReport(report) && isReportManager(report) && isOpenTaskReport(report); +/** + * Checks if a report is an open task report assigned to current user. + * + * @param {Object} report + * @param {Object} parentReportAction - The parent report action of the report (Used to check if the task has been canceled) + * @returns {Boolean} + */ +function isWaitingForTaskCompleteFromAssignee(report, parentReportAction = {}) { + return isTaskReport(report) && isReportManager(report) && isOpenTaskReport(report, parentReportAction); } /** @@ -3701,4 +3708,5 @@ export { getReportPreviewDisplayTransactions, getTransactionsWithReceipts, hasMissingSmartscanFields, + isWaitingForTaskCompleteFromAssignee, }; diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index f645697690e6..0ea632aa7d63 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -210,9 +210,10 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p * @param {Object} personalDetails * @param {String} preferredLocale * @param {Object} [policy] + * @param {Object} parentReportAction * @returns {Object} */ -function getOptionData(report, reportActions, personalDetails, preferredLocale, policy) { +function getOptionData(report, reportActions, personalDetails, preferredLocale, policy, parentReportAction) { // When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for // this method to be called after the Onyx data has been cleared out. In that case, it's fine to do // a null check here and return early. @@ -266,8 +267,7 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, result.isChatRoom = ReportUtils.isChatRoom(report); result.isTaskReport = ReportUtils.isTaskReport(report); if (result.isTaskReport) { - result.isCompletedTaskReport = ReportUtils.isCompletedTaskReport(report); - result.isTaskAssignee = ReportUtils.isReportManager(report); + result.isWaitingForTaskCompleteFromAssignee = ReportUtils.isWaitingForTaskCompleteFromAssignee(report, parentReportAction); } result.isArchivedRoom = ReportUtils.isArchivedRoom(report); result.isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report); From 847ba127b829df6770a6b2b2f23f179e044aff0c Mon Sep 17 00:00:00 2001 From: Pavlo Tsimura Date: Thu, 21 Sep 2023 08:48:47 +0200 Subject: [PATCH 104/250] Formatting --- src/components/LHNOptionsList/OptionRowLHN.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js index da1eaad2f0c2..91b582221171 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.js +++ b/src/components/LHNOptionsList/OptionRowLHN.js @@ -102,10 +102,7 @@ function OptionRowLHN(props) { const hasBrickError = optionItem.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR; const defaultSubscriptSize = optionItem.isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : CONST.AVATAR_SIZE.DEFAULT; const shouldShowGreenDotIndicator = - !hasBrickError && - (optionItem.isUnreadWithMention || - optionItem.isWaitingForTaskCompleteFromAssignee || - ReportUtils.isWaitingForIOUActionFromCurrentUser(optionItem)); + !hasBrickError && (optionItem.isUnreadWithMention || optionItem.isWaitingForTaskCompleteFromAssignee || ReportUtils.isWaitingForIOUActionFromCurrentUser(optionItem)); /** * Show the ReportActionContextMenu modal popover. From 6ec282dee0c0d549073c0621ce25bd4315815ba1 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 21 Sep 2023 08:50:06 +0200 Subject: [PATCH 105/250] Fix App displays waypoint address page briefly on click on Go back to Home page --- src/pages/iou/WaypointEditor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/WaypointEditor.js b/src/pages/iou/WaypointEditor.js index e34730acccea..b3980935c7b4 100644 --- a/src/pages/iou/WaypointEditor.js +++ b/src/pages/iou/WaypointEditor.js @@ -4,7 +4,7 @@ import lodashGet from 'lodash/get'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; -import {useIsFocused} from '@react-navigation/native'; +import {useNavigation} from '@react-navigation/native'; import AddressSearch from '../../components/AddressSearch'; import ScreenWrapper from '../../components/ScreenWrapper'; import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; @@ -76,7 +76,7 @@ const defaultProps = { function WaypointEditor({transactionID, route: {params: {iouType = '', waypointIndex = ''} = {}} = {}, transaction, recentWaypoints}) { const {windowWidth} = useWindowDimensions(); const [isDeleteStopModalOpen, setIsDeleteStopModalOpen] = useState(false); - const isFocused = useIsFocused(); + const isFocused = useNavigation().isFocused(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); const textInput = useRef(null); From 2c788c662cbd9dc682af7d703d708c0a5ed23479 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 21 Sep 2023 09:35:48 +0200 Subject: [PATCH 106/250] Refactor useNavigation hook --- ios/tmp.xcconfig | 10 +++++++++- src/pages/iou/WaypointEditor.js | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ios/tmp.xcconfig b/ios/tmp.xcconfig index 8b137891791f..2f2502669450 100644 --- a/ios/tmp.xcconfig +++ b/ios/tmp.xcconfig @@ -1 +1,9 @@ - +NEW_EXPENSIFY_URL=https:/$()/new.expensify.com/ +SECURE_EXPENSIFY_URL=https:/$()/secure.expensify.com/ +EXPENSIFY_URL=https:/$()/www.expensify.com/ +EXPENSIFY_PARTNER_NAME=chat-expensify-com +EXPENSIFY_PARTNER_PASSWORD=e21965746fd75f82bb66 +PUSHER_APP_KEY=268df511a204fbb60884 +USE_WEB_PROXY=false +ENVIRONMENT=production +SEND_CRASH_REPORTS=true diff --git a/src/pages/iou/WaypointEditor.js b/src/pages/iou/WaypointEditor.js index b3980935c7b4..c214290b46fd 100644 --- a/src/pages/iou/WaypointEditor.js +++ b/src/pages/iou/WaypointEditor.js @@ -76,7 +76,8 @@ const defaultProps = { function WaypointEditor({transactionID, route: {params: {iouType = '', waypointIndex = ''} = {}} = {}, transaction, recentWaypoints}) { const {windowWidth} = useWindowDimensions(); const [isDeleteStopModalOpen, setIsDeleteStopModalOpen] = useState(false); - const isFocused = useNavigation().isFocused(); + const navigation = useNavigation(); + const isFocused = navigation.isFocused(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); const textInput = useRef(null); From 5b1939860def2080c21d9a2f07f10810b94451aa Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 21 Sep 2023 09:45:54 +0200 Subject: [PATCH 107/250] Clear tmp.xcconfig --- ios/tmp.xcconfig | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ios/tmp.xcconfig b/ios/tmp.xcconfig index 2f2502669450..e69de29bb2d1 100644 --- a/ios/tmp.xcconfig +++ b/ios/tmp.xcconfig @@ -1,9 +0,0 @@ -NEW_EXPENSIFY_URL=https:/$()/new.expensify.com/ -SECURE_EXPENSIFY_URL=https:/$()/secure.expensify.com/ -EXPENSIFY_URL=https:/$()/www.expensify.com/ -EXPENSIFY_PARTNER_NAME=chat-expensify-com -EXPENSIFY_PARTNER_PASSWORD=e21965746fd75f82bb66 -PUSHER_APP_KEY=268df511a204fbb60884 -USE_WEB_PROXY=false -ENVIRONMENT=production -SEND_CRASH_REPORTS=true From 944d6ae36e0bc39da6679c4187807cec979f6bf8 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Thu, 21 Sep 2023 09:48:37 +0200 Subject: [PATCH 108/250] Clear tmp.xcconfig x2 --- ios/tmp.xcconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/tmp.xcconfig b/ios/tmp.xcconfig index e69de29bb2d1..8b137891791f 100644 --- a/ios/tmp.xcconfig +++ b/ios/tmp.xcconfig @@ -0,0 +1 @@ + From e7d3272a218e02567eff58ad4450304999208bfa Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Thu, 21 Sep 2023 15:39:06 +0530 Subject: [PATCH 109/250] fix: lint warning. Signed-off-by: Krishna Gupta --- .../AttachmentCarousel/Pager/AttachmentCarouselPage.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js index cec6237744a2..b94f456f3a7e 100644 --- a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js +++ b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js @@ -56,8 +56,11 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI // We delay hiding the fallback image while image transformer is still rendering useEffect(() => { - if (isImageLoading || showFallback) setShowFallback(true); - else setTimeout(() => setShowFallback(false), 100); + if (isImageLoading || showFallback) { + setShowFallback(true); + } else { + setTimeout(() => setShowFallback(false), 100); + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isImageLoading]); From cfd953503cad90186836a5415613e723e3b54c77 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Thu, 21 Sep 2023 15:58:17 +0530 Subject: [PATCH 110/250] fix: lint warning. Signed-off-by: Krishna Gupta --- .../AttachmentCarousel/Pager/AttachmentCarouselPage.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js index b94f456f3a7e..f7da8cfce894 100644 --- a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js +++ b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js @@ -134,11 +134,15 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI isAuthTokenRequired={isAuthTokenRequired} onLoadStart={() => { setIsImageLoading(true); - if (isImageLoaded.current) return; + if (isImageLoaded.current) { + return; + } setIsFallbackLoading(true); }} onLoadEnd={() => { - if (isImageLoaded.current) return; + if (isImageLoaded.current) { + return; + } setIsFallbackLoading(false); }} onLoad={(evt) => { From fee898ec5c0ad16077669dca728acd8503ab4648 Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Thu, 21 Sep 2023 12:30:30 +0100 Subject: [PATCH 111/250] feat: support for editing a tag of a money request --- src/CONST.ts | 1 + .../ReportActionItem/MoneyRequestView.js | 38 ++++++++++++- src/libs/ReportUtils.js | 11 ++++ src/libs/TransactionUtils.js | 16 ++++++ src/libs/actions/IOU.js | 4 +- src/pages/EditRequestPage.js | 54 ++++++++++++++++--- src/pages/EditRequestTagPage.js | 53 ++++++++++++++++++ 7 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 src/pages/EditRequestTagPage.js diff --git a/src/CONST.ts b/src/CONST.ts index eed1b98ae551..e20ca428ee34 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1360,6 +1360,7 @@ const CONST = { MERCHANT: 'merchant', CATEGORY: 'category', RECEIPT: 'receipt', + TAG: 'tag', }, FOOTER: { EXPENSE_MANAGEMENT_URL: `${USE_EXPENSIFY_URL}/expense-management`, diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 178cab75a0c2..853b998fc5c6 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -1,5 +1,6 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; +import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; import lodashValues from 'lodash/values'; @@ -32,6 +33,7 @@ import * as TransactionUtils from '../../libs/TransactionUtils'; import OfflineWithFeedback from '../OfflineWithFeedback'; import categoryPropTypes from '../categoryPropTypes'; import SpacerView from '../SpacerView'; +import tagPropTypes from '../tagPropTypes'; const propTypes = { /** The report currently being looked at */ @@ -53,6 +55,15 @@ const propTypes = { /** The transaction associated with the transactionThread */ transaction: transactionPropTypes, + /** Collection of tags attached to a policy */ + policyTags: PropTypes.objectOf( + PropTypes.shape({ + name: PropTypes.string, + required: PropTypes.bool, + tags: PropTypes.objectOf(tagPropTypes), + }), + ), + ...withCurrentUserPersonalDetailsPropTypes, }; @@ -65,9 +76,10 @@ const defaultProps = { currency: CONST.CURRENCY.USD, comment: {comment: ''}, }, + policyTags: {}, }; -function MoneyRequestView({betas, report, parentReport, policyCategories, shouldShowHorizontalRule, transaction}) { +function MoneyRequestView({report, betas, parentReport, policyCategories, shouldShowHorizontalRule, transaction, policyTags}) { const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); @@ -80,6 +92,7 @@ function MoneyRequestView({betas, report, parentReport, policyCategories, should comment: transactionDescription, merchant: transactionMerchant, category: transactionCategory, + tag: transactionTag, } = ReportUtils.getTransactionDetails(transaction); const isEmptyMerchant = transactionMerchant === '' || transactionMerchant === CONST.TRANSACTION.UNKNOWN_MERCHANT || transactionMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; @@ -89,8 +102,14 @@ function MoneyRequestView({betas, report, parentReport, policyCategories, should const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction); // A flag for verifying that the current report is a sub-report of a workspace chat const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); - // A flag for showing categories + + // Fetches only the first tag, for now + const policyTagKey = _.first(_.keys(policyTags)); + const policyTagsList = lodashGet(policyTags, [policyTagKey, 'tags'], {}); + + // Flags for showing categories and tags const shouldShowCategory = isPolicyExpenseChat && Permissions.canUseCategories(betas) && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories))); + const shouldShowTag = isPolicyExpenseChat && Permissions.canUseTags(betas) && (transactionTag || OptionsListUtils.hasEnabledOptions(lodashValues(policyTagsList))); let description = `${translate('iou.amount')} • ${translate('iou.cash')}`; if (isSettled) { @@ -200,6 +219,18 @@ function MoneyRequestView({betas, report, parentReport, policyCategories, should /> )} + {shouldShowTag && ( + + Navigation.navigate(ROUTES.getEditRequestRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.TAG))} + /> + + )} `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`, + }, }), )(MoneyRequestView); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index a5af66f08460..4a9eff1e1b60 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1329,6 +1329,7 @@ function getTransactionDetails(transaction) { comment: TransactionUtils.getDescription(transaction), merchant: TransactionUtils.getMerchant(transaction), category: TransactionUtils.getCategory(transaction), + tag: TransactionUtils.getTag(transaction), }; } @@ -1580,6 +1581,11 @@ function getModifiedExpenseMessage(reportAction) { if (hasModifiedCategory) { return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true); } + + const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); + if (hasModifiedTag) { + return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.tag, reportActionOriginalMessage.oldTag, Localize.translateLocal('common.tag'), true); + } } /** @@ -1625,6 +1631,11 @@ function getModifiedExpenseOriginalMessage(oldTransaction, transactionChanges, i originalMessage.category = transactionChanges.category; } + if (_.has(transactionChanges, 'tag')) { + originalMessage.oldTag = TransactionUtils.getTag(oldTransaction); + originalMessage.tag = transactionChanges.tag; + } + return originalMessage; } diff --git a/src/libs/TransactionUtils.js b/src/libs/TransactionUtils.js index 5dcfbc467c20..e3fe84ff1af8 100644 --- a/src/libs/TransactionUtils.js +++ b/src/libs/TransactionUtils.js @@ -151,6 +151,10 @@ function getUpdatedTransaction(transaction, transactionChanges, isFromExpenseRep updatedTransaction.category = transactionChanges.category; } + if (_.has(transactionChanges, 'tag')) { + updatedTransaction.tag = transactionChanges.tag; + } + if (shouldStopSmartscan && _.has(transaction, 'receipt') && !_.isEmpty(transaction.receipt) && lodashGet(transaction, 'receipt.state') !== CONST.IOU.RECEIPT_STATE.OPEN) { updatedTransaction.receipt.state = CONST.IOU.RECEIPT_STATE.OPEN; } @@ -162,6 +166,7 @@ function getUpdatedTransaction(transaction, transactionChanges, isFromExpenseRep ...(_.has(transactionChanges, 'currency') && {currency: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), ...(_.has(transactionChanges, 'merchant') && {merchant: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), ...(_.has(transactionChanges, 'category') && {category: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), + ...(_.has(transactionChanges, 'tag') && {merchant: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), }; return updatedTransaction; @@ -253,6 +258,16 @@ function getCategory(transaction) { return lodashGet(transaction, 'category', ''); } +/** + * Return the tag from the transaction. This "tag" field has no "modified" complement. + * + * @param {Object} transaction + * @return {String} + */ +function getTag(transaction) { + return lodashGet(transaction, 'tag', ''); +} + /** * Return the created field from the transaction, return the modifiedCreated if present. * @@ -399,6 +414,7 @@ export { getMerchant, getCreated, getCategory, + getTag, getLinkedTransaction, getAllReportTransactions, hasReceipt, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 36d512c8d843..e93272cca8f2 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1192,6 +1192,7 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC currency: null, merchant: null, category: null, + tag: null, }, }, }, @@ -1230,7 +1231,7 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC ]; // STEP 6: Call the API endpoint - const {created, amount, currency, comment, merchant, category} = ReportUtils.getTransactionDetails(updatedTransaction); + const {created, amount, currency, comment, merchant, category, tag} = ReportUtils.getTransactionDetails(updatedTransaction); API.write( 'EditMoneyRequest', { @@ -1242,6 +1243,7 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC comment, merchant, category, + tag, }, {optimisticData, successData, failureData}, ); diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index fedbc61a6e15..4fcfa7398d57 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -1,26 +1,29 @@ import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; +import _ from 'underscore'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import compose from '../libs/compose'; import CONST from '../CONST'; -import Navigation from '../libs/Navigation/Navigation'; import ONYXKEYS from '../ONYXKEYS'; +import compose from '../libs/compose'; +import Navigation from '../libs/Navigation/Navigation'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; import * as ReportUtils from '../libs/ReportUtils'; import * as TransactionUtils from '../libs/TransactionUtils'; import * as Policy from '../libs/actions/Policy'; +import * as IOU from '../libs/actions/IOU'; +import * as CurrencyUtils from '../libs/CurrencyUtils'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../components/withCurrentUserPersonalDetails'; +import tagPropTypes from '../components/tagPropTypes'; +import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; import EditRequestDescriptionPage from './EditRequestDescriptionPage'; import EditRequestMerchantPage from './EditRequestMerchantPage'; import EditRequestCreatedPage from './EditRequestCreatedPage'; import EditRequestAmountPage from './EditRequestAmountPage'; import EditRequestReceiptPage from './EditRequestReceiptPage'; -import reportPropTypes from './reportPropTypes'; -import * as IOU from '../libs/actions/IOU'; -import * as CurrencyUtils from '../libs/CurrencyUtils'; -import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; import EditRequestCategoryPage from './EditRequestCategoryPage'; +import EditRequestTagPage from './EditRequestTagPage'; +import reportPropTypes from './reportPropTypes'; const propTypes = { /** Route from navigation */ @@ -35,6 +38,7 @@ const propTypes = { }), }).isRequired, + /** Onyx props */ /** The report object for the thread report */ report: reportPropTypes, @@ -56,6 +60,15 @@ const propTypes = { email: PropTypes.string, }), + /** Collection of tags attached to a policy */ + policyTags: PropTypes.objectOf( + PropTypes.shape({ + name: PropTypes.string, + required: PropTypes.bool, + tags: PropTypes.objectOf(tagPropTypes), + }), + ), + ...withCurrentUserPersonalDetailsPropTypes, }; @@ -66,9 +79,10 @@ const defaultProps = { session: { email: null, }, + policyTags: {}, }; -function EditRequestPage({report, route, parentReport, policy, session}) { +function EditRequestPage({report, route, parentReport, policy, session, policyTags}) { const parentReportAction = ReportActionsUtils.getParentReportAction(report); const transaction = TransactionUtils.getLinkedTransaction(parentReportAction); const { @@ -77,6 +91,7 @@ function EditRequestPage({report, route, parentReport, policy, session}) { comment: transactionDescription, merchant: transactionMerchant, category: transactionCategory, + tag: transactionTag, } = ReportUtils.getTransactionDetails(transaction); const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; @@ -92,6 +107,9 @@ function EditRequestPage({report, route, parentReport, policy, session}) { const isRequestor = ReportUtils.isMoneyRequestReport(parentReport) && lodashGet(session, 'accountID', null) === parentReportAction.actorAccountID; const canEdit = !isSettled && !isDeleted && (isAdmin || isRequestor); + // For now, it always defaults to the first tag of the policy + const tagName = _.first(_.keys(policyTags)); + // Dismiss the modal when the request is paid or deleted useEffect(() => { if (canEdit) { @@ -196,6 +214,25 @@ function EditRequestPage({report, route, parentReport, policy, session}) { ); } + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.TAG) { + return ( + { + let updatedTag = transactionChanges.tag; + + // In case the same tag has been selected, reset the tag. + if (transactionTag === updatedTag) { + updatedTag = ''; + } + editMoneyRequest({tag: updatedTag}); + }} + /> + ); + } + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.RECEIPT) { return ( `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, }, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, + }, }), )(EditRequestPage); diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js new file mode 100644 index 000000000000..72ed072eec16 --- /dev/null +++ b/src/pages/EditRequestTagPage.js @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Navigation from '../libs/Navigation/Navigation'; +import useLocalize from '../hooks/useLocalize'; +import ScreenWrapper from '../components/ScreenWrapper'; +import HeaderWithBackButton from '../components/HeaderWithBackButton'; +import TagPicker from '../components/TagPicker'; + +const propTypes = { + /** Transaction default tag value */ + defaultTag: PropTypes.string.isRequired, + + /** The policyID we are getting tags for */ + policyID: PropTypes.string.isRequired, + + /** The tag name to which the default tag belongs to */ + tagName: PropTypes.string.isRequired, + + /** Callback to fire when the Save button is pressed */ + onSubmit: PropTypes.func.isRequired, +}; + +function EditRequestTagPage({defaultTag, policyID, tagName, onSubmit}) { + const {translate} = useLocalize(); + + const selectTag = (tag) => { + onSubmit({tag: tag.searchText}); + }; + + return ( + + + + + + ); +} + +EditRequestTagPage.propTypes = propTypes; +EditRequestTagPage.displayName = 'EditRequestTagPage'; + +export default EditRequestTagPage; From 0b1c63eb17f6aaf89d8365916a3f0e1c78dc253b Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 21 Sep 2023 17:06:27 +0530 Subject: [PATCH 112/250] use provided description for hubs --- docs/_data/_routes.yml | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/_data/_routes.yml b/docs/_data/_routes.yml index 20582b6b8c7e..1cea22074cc0 100644 --- a/docs/_data/_routes.yml +++ b/docs/_data/_routes.yml @@ -16,62 +16,62 @@ platforms: - href: account-settings title: Account Settings icon: /assets/images/gears.svg - description: With only a couple of clicks, split bills with your friends or coworkers. + description: Discover how to personalize your profile, add secondary logins, and grant delegated access to employees with our comprehensive guide on Account Settings. - href: bank-accounts-and-credit-cards title: Bank Accounts & Credit Cards icon: /assets/images/bank-card.svg - description: Request money for work expenses, bills, or a night out with friends. + description: Find out how to connect Expensify to your financial institutions, track credit card transactions, and best practices for reconciling company cards. - href: billing-and-subscriptions title: Billing & Subscriptions icon: /assets/images/money-wings.svg - description: Best practices for how to best deploy Expensify for your business + description: Here is where you can review Expensify's billing and subscription options, plan types, and payment methods. - href: expense-and-report-features title: Expense & Report Features icon: /assets/images/money-receipt.svg - description: Everything else you're looking for is right here. + description: From enabling automatic expense auditing to tracking attendees, here is where you can review tips and tutorials to streamline expense management. - href: expensify-card title: Expensify Card icon: /assets/images/hand-card.svg - description: Request money for work expenses, bills, or a night out with friends. + description: Explore how the Expensify Card combines convenience and security to enhance everyday business transactions. Discover how to apply for, oversee, and maximize your card perks here. - href: exports title: Exports icon: /assets/images/monitor.svg - description: Best practices for how to best deploy Expensify for your business + description: From exporting reports to creating custom templates, here is where you can learn more about Expensify's versatile export options. - href: get-paid-back title: Get Paid Back - description: Everything else you're looking for is right here. icon: /assets/images/money-into-wallet.svg + description: Whether you submit an expense report or an invoice, find out here how to ensure a smooth and timely payback process every time. - href: getting-started title: Getting Started - description: Everything else you're looking for is right here. icon: /assets/images/accounting.svg + description: From setting up your account to ensuring you get the most out of Expensify’s suite of features, click here to get started on streamlining your expense management journey. - href: integrations title: Integrations - description: Everything else you're looking for is right here. icon: /assets/images/workflow.svg + description: Enhance Expensify’s capabilities by integrating it with your accounting or HR software. Here is where you can learn more about creating a synchronized financial management ecosystem. - href: manage-employees-and-report-approvals title: Manage Employees & Report Approvals icon: /assets/images/envelope-receipt.svg - description: Everything else you're looking for is right here. + description: Master the art of overseeing employees and reports by utilizing Expensify’s automation features and approval workflows. - href: policy-and-domain-settings title: Policy & Domain Setting icon: /assets/images/shield.svg - description: Everything else you're looking for is right here. + description: Discover how to set up and manage policies, define user permissions, and implement compliance rules to maintain a secure and compliant financial management landscape. - href: send-payments title: Send Payments icon: /assets/images/money-wings.svg - description: Everything else you're looking for is right here. + description: Uncover step-by-step guidance on sending direct reimbursements to employees, paying an invoice to a vendor, and utilizing third-party payment options. - href: new-expensify title: New Expensify @@ -84,59 +84,59 @@ platforms: - href: account-settings title: Account Settings icon: /assets/images/gears.svg - description: With only a couple of clicks, split bills with your friends or coworkers. + description: Discover how to personalize your profile, add secondary logins, and grant delegated access to employees with our comprehensive guide on Account Settings. - href: bank-accounts-and-credit-cards title: Bank Accounts & Credit Cards icon: /assets/images/bank-card.svg - description: description + description: Find out how to connect Expensify to your financial institutions, track credit card transactions, and best practices for reconciling company cards. - href: billing-and-plan-types title: Billing & Plan Types icon: /assets/images/money-wings.svg - description: description + description: Here is where you can review Expensify's billing and subscription options, plan types, and payment methods. - href: expense-and-report-features title: Expense & Report Features icon: /assets/images/money-receipt.svg - description: description + description: From enabling automatic expense auditing to tracking attendees, here is where you can review tips and tutorials to streamline expense management. - href: expensify-card title: Expensify Card icon: /assets/images/hand-card.svg - description: description + description: Explore how the Expensify Card combines convenience and security to enhance everyday business transactions. Discover how to apply for, oversee, and maximize your card perks here. - href: exports title: Exports icon: /assets/images/monitor.svg - description: description + description: From exporting reports to creating custom templates, here is where you can learn more about Expensify's versatile export options. - href: get-paid-back title: Get Paid Back icon: /assets/images/money-into-wallet.svg - description: description + description: Whether you submit an expense report or an invoice, find out here how to ensure a smooth and timely payback process every time. - href: getting-started title: Getting Started icon: /assets/images/accounting.svg - description: description + description: From setting up your account to ensuring you get the most out of Expensify’s suite of features, click here to get started on streamlining your expense management journey. - href: integrations title: Integrations icon: /assets/images/workflow.svg - description: description + description: Enhance Expensify’s capabilities by integrating it with your accounting or HR software. Here is where you can learn more about creating a synchronized financial management ecosystem. - href: manage-employees-and-report-approvals title: Manage Employees & Report Approvals icon: /assets/images/envelope-receipt.svg - description: description + description: Master the art of overseeing employees and reports by utilizing Expensify’s automation features and approval workflows. - href: send-payments title: Send Payments icon: /assets/images/money-wings.svg - description: description. + description: Uncover step-by-step guidance on sending direct reimbursements to employees, paying an invoice to a vendor, and utilizing third-party payment options. - href: workspace-and-domain-settings title: Workspace & Domain Settings icon: /assets/images/shield.svg - description: description. + description: Discover how to set up and manage workspaces, define user permissions, and implement compliance rules to maintain a secure and compliant financial management landscape. From 489b600412f09679243789a5260642a53360beac Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 21 Sep 2023 19:46:13 +0800 Subject: [PATCH 113/250] make trailing default to true --- src/hooks/useDebounce.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js index 2d6ad83bedab..8995a0443b85 100644 --- a/src/hooks/useDebounce.js +++ b/src/hooks/useDebounce.js @@ -17,7 +17,7 @@ import lodashDebounce from 'lodash/debounce'; */ export default function useDebounce(func, wait, options) { const debouncedFnRef = useRef(); - const {leading, maxWait, trailing} = options || {}; + const {leading, maxWait, trailing = true} = options || {}; useEffect(() => { const debouncedFn = lodashDebounce(func, wait, {leading, maxWait, trailing}); From 0e2f4c65cda9228491c1f569d4e0e1c48ffdb124 Mon Sep 17 00:00:00 2001 From: Wojciech Stanisz Date: Thu, 21 Sep 2023 13:57:11 +0200 Subject: [PATCH 114/250] Bump to 3.5.4 --- ios/Podfile.lock | 4 ++-- package-lock.json | 14 +++++++------- package.json | 2 +- patches/react-native-reanimated+3.5.3.patch | 10 ---------- 4 files changed, 10 insertions(+), 20 deletions(-) delete mode 100644 patches/react-native-reanimated+3.5.3.patch diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9c14d69aca55..7f84639798da 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -783,7 +783,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.5.3): + - RNReanimated (3.5.4): - DoubleConversion - FBLazyVector - glog @@ -1298,7 +1298,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: e037aac4d8b0055a399f5af065e8210f6c8cc900 + RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87 RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d diff --git a/package-lock.json b/package-lock.json index 68ca30f17289..65f027329834 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,7 +99,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "^3.5.3", + "react-native-reanimated": "^3.5.4", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", @@ -40697,9 +40697,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.3.tgz", - "integrity": "sha512-zjGJL2rgYLiEqIwaIOd+/dgRZzot4wKUvKk0ZXeWY7SJg4Bp+9yQTOT98Jx6b1/Cga2YY71i0tIu3hanLajGAQ==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.4.tgz", + "integrity": "sha512-8we9LLDO1o4Oj9/DICeEJ2K1tjfqkJagqQUglxeUAkol/HcEJ6PGxIrpBcNryLqCDYEcu6FZWld/FzizBIw6bg==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -76181,9 +76181,9 @@ "requires": {} }, "react-native-reanimated": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.3.tgz", - "integrity": "sha512-zjGJL2rgYLiEqIwaIOd+/dgRZzot4wKUvKk0ZXeWY7SJg4Bp+9yQTOT98Jx6b1/Cga2YY71i0tIu3hanLajGAQ==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.4.tgz", + "integrity": "sha512-8we9LLDO1o4Oj9/DICeEJ2K1tjfqkJagqQUglxeUAkol/HcEJ6PGxIrpBcNryLqCDYEcu6FZWld/FzizBIw6bg==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", diff --git a/package.json b/package.json index dabb5d0afde9..5f5ecc234b56 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "react-native-plaid-link-sdk": "^10.0.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "^3.5.3", + "react-native-reanimated": "^3.5.4", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", diff --git a/patches/react-native-reanimated+3.5.3.patch b/patches/react-native-reanimated+3.5.3.patch deleted file mode 100644 index cf6ee2e271c2..000000000000 --- a/patches/react-native-reanimated+3.5.3.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts -index 4df2481..2be308f 100644 ---- a/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts -+++ b/node_modules/react-native-reanimated/src/reanimated2/PlatformChecker.ts -@@ -1,4 +1,5 @@ - import { Platform } from 'react-native'; -+import './globals.d.ts' - - export function isJest(): boolean { - return !!process.env.JEST_WORKER_ID; From cdb89ea6677b003063c00892dc7b4d446f9fb0eb Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Thu, 21 Sep 2023 14:35:18 +0100 Subject: [PATCH 115/250] feat: pass tag list name to the modified expense message --- .../MoneyRequestConfirmationList.js | 11 +++--- .../ReportActionItem/MoneyRequestView.js | 8 ++--- src/libs/PolicyUtils.js | 35 +++++++++++++++++++ src/libs/ReportUtils.js | 8 ++++- src/pages/EditRequestPage.js | 8 ++--- src/pages/iou/MoneyRequestTagPage.js | 8 ++--- 6 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 13471407914f..b9a744b2e71c 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -38,6 +38,7 @@ import transactionPropTypes from './transactionPropTypes'; import DistanceRequestUtils from '../libs/DistanceRequestUtils'; import * as IOU from '../libs/actions/IOU'; import * as TransactionUtils from '../libs/TransactionUtils'; +import * as PolicyUtils from '../libs/PolicyUtils'; const propTypes = { /** Callback to inform parent modal of success */ @@ -202,12 +203,12 @@ function MoneyRequestConfirmationList(props) { const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories)); // Fetches the first tag list of the policy - const tagListKey = _.first(_.keys(props.policyTags)); - const tagList = lodashGet(props.policyTags, [tagListKey, 'tags'], []); - const tagListName = lodashGet(props.policyTags, [tagListKey, 'name'], ''); + const policyTag = PolicyUtils.getTag(props.policyTags); + const policyTagList = lodashGet(policyTag, 'tags', {}); + const policyTagListName = lodashGet(policyTag, 'name', translate('common.tag')); const canUseTags = Permissions.canUseTags(props.betas); // A flag for showing the tags field - const shouldShowTags = isPolicyExpenseChat && canUseTags && _.any(tagList, (tag) => tag.enabled); + const shouldShowTags = isPolicyExpenseChat && canUseTags && OptionsListUtils.hasEnabledOptions(_.values(policyTagList)); // A flag for showing the billable field const shouldShowBillable = canUseTags && !lodashGet(props.policy, 'disabledFields.defaultBillable', true); @@ -541,7 +542,7 @@ function MoneyRequestConfirmationList(props) { Navigation.navigate(ROUTES.getMoneyRequestTagRoute(props.iouType, props.reportID))} style={[styles.moneyRequestMenuItem, styles.mb2]} disabled={didConfirm || props.isReadOnly} diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 853b998fc5c6..0c996e19bf60 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -1,6 +1,5 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; -import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; import lodashValues from 'lodash/values'; @@ -18,6 +17,7 @@ import * as ReportUtils from '../../libs/ReportUtils'; import * as OptionsListUtils from '../../libs/OptionsListUtils'; import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; import * as StyleUtils from '../../styles/StyleUtils'; +import * as PolicyUtils from '../../libs/PolicyUtils'; import CONST from '../../CONST'; import * as Expensicons from '../Icon/Expensicons'; import iouReportPropTypes from '../../pages/iouReportPropTypes'; @@ -104,8 +104,8 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); // Fetches only the first tag, for now - const policyTagKey = _.first(_.keys(policyTags)); - const policyTagsList = lodashGet(policyTags, [policyTagKey, 'tags'], {}); + const policyTag = PolicyUtils.getTag(policyTags); + const policyTagsList = lodashGet(policyTag, 'tags', {}); // Flags for showing categories and tags const shouldShowCategory = isPolicyExpenseChat && Permissions.canUseCategories(betas) && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories))); @@ -222,7 +222,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should {shouldShowTag && ( { @@ -218,7 +218,7 @@ function EditRequestPage({report, route, parentReport, policy, session, policyTa return ( { let updatedTag = transactionChanges.tag; @@ -227,7 +227,7 @@ function EditRequestPage({report, route, parentReport, policy, session, policyTa if (transactionTag === updatedTag) { updatedTag = ''; } - editMoneyRequest({tag: updatedTag}); + editMoneyRequest({tag: updatedTag, tagListName}); }} /> ); diff --git a/src/pages/iou/MoneyRequestTagPage.js b/src/pages/iou/MoneyRequestTagPage.js index c9b5eb4f8f6f..f3f002250180 100644 --- a/src/pages/iou/MoneyRequestTagPage.js +++ b/src/pages/iou/MoneyRequestTagPage.js @@ -6,6 +6,7 @@ import {withOnyx} from 'react-native-onyx'; import compose from '../../libs/compose'; import ROUTES from '../../ROUTES'; import * as IOU from '../../libs/actions/IOU'; +import * as PolicyUtils from '../../libs/PolicyUtils'; import Navigation from '../../libs/Navigation/Navigation'; import useLocalize from '../../hooks/useLocalize'; import ScreenWrapper from '../../components/ScreenWrapper'; @@ -60,8 +61,7 @@ function MoneyRequestTagPage({route, report, policyTags, iou}) { // Fetches the first tag list of the policy const tagListKey = _.first(_.keys(policyTags)); - const tagList = lodashGet(policyTags, tagListKey, {}); - const tagListName = lodashGet(tagList, 'name', translate('common.tag')); + const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); const navigateBack = () => { Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, report.reportID)); @@ -82,10 +82,10 @@ function MoneyRequestTagPage({route, report, policyTags, iou}) { shouldEnableMaxHeight > - {translate('iou.tagSelection', {tagName: tagListName})} + {translate('iou.tagSelection', {tagName: policyTagListName})} Date: Thu, 21 Sep 2023 20:55:56 +0700 Subject: [PATCH 116/250] run prettier --- src/pages/iou/steps/NewRequestAmountPage.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index 5d92464aa9cf..8b4d73f0aee0 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -71,15 +71,17 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { const focusTimeoutRef = useRef(null); - useFocusEffect(useCallback(() => { - focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); - return () => { - if (!focusTimeoutRef.current) { - return; - } - clearTimeout(focusTimeoutRef.current); - }; - }, [])); + useFocusEffect( + useCallback(() => { + focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); + return () => { + if (!focusTimeoutRef.current) { + return; + } + clearTimeout(focusTimeoutRef.current); + }; + }, []), + ); // Check and dismiss modal useEffect(() => { From 8735f7147395550c19a1738f008460431193c8ac Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Thu, 21 Sep 2023 15:12:27 +0100 Subject: [PATCH 117/250] feat: update recently used tags on edit money request --- src/components/TagPicker/index.js | 3 ++- src/libs/PolicyUtils.js | 18 ++++++++++++++++++ src/libs/actions/IOU.js | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/components/TagPicker/index.js b/src/components/TagPicker/index.js index c46ca1b57b22..8e7cf11f7e5a 100644 --- a/src/components/TagPicker/index.js +++ b/src/components/TagPicker/index.js @@ -7,6 +7,7 @@ import ONYXKEYS from '../../ONYXKEYS'; import styles from '../../styles/styles'; import useLocalize from '../../hooks/useLocalize'; import * as OptionsListUtils from '../../libs/OptionsListUtils'; +import * as PolicyUtils from '../../libs/PolicyUtils'; import OptionsSelector from '../OptionsSelector'; import {propTypes, defaultProps} from './tagPickerPropTypes'; @@ -15,7 +16,7 @@ function TagPicker({selectedTag, tag, policyTags, policyRecentlyUsedTags, onSubm const [searchValue, setSearchValue] = useState(''); const policyRecentlyUsedTagsList = lodashGet(policyRecentlyUsedTags, tag, []); - const policyTagList = lodashGet(policyTags, [tag, 'tags'], {}); + const policyTagList = PolicyUtils.getTagList(policyTags, tag); const policyTagsCount = _.size(_.filter(policyTagList, (policyTag) => policyTag.enabled)); const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD; diff --git a/src/libs/PolicyUtils.js b/src/libs/PolicyUtils.js index bf1ca1c4168f..616e3dba2d64 100644 --- a/src/libs/PolicyUtils.js +++ b/src/libs/PolicyUtils.js @@ -199,6 +199,23 @@ function getTagListName(policyTags) { return lodashGet(policyTags, [_.first(policyTagKeys), 'name'], ''); } +/** + * Fetches the tags of a policy for a specific key. Defaults to the first tag if no key is provided. + * + * @param {Object} policyTags + * @param {String} [tagKey] + * @returns {String} + */ +function getTagList(policyTags, tagKey) { + if (!policyTags) { + return {}; + } + + const policyTagKey = tagKey || _.first(_.keys(policyTags)); + + return lodashGet(policyTags, [policyTagKey, 'tags'], {}); +} + export { getActivePolicies, hasPolicyMemberError, @@ -214,4 +231,5 @@ export { getIneligibleInvitees, getTag, getTagListName, + getTagList, }; diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index e93272cca8f2..9d9be6ee8ba5 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1147,6 +1147,17 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC updatedChatReport.lastMessageHtml = messageText; } + const optimisticPolicyRecentlyUsedTags = {}; + if (_.has(transactionChanges, 'tag')) { + const tagListName = transactionChanges.tagListName; + const recentlyUsedPolicyTags = allRecentlyUsedTags[`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`]; + + if (recentlyUsedPolicyTags) { + const uniquePolicyRecentlyUsedTags = _.filter(recentlyUsedPolicyTags[tagListName], (recentlyUsedPolicyTag) => recentlyUsedPolicyTag !== transactionChanges.tag); + optimisticPolicyRecentlyUsedTags[tagListName] = [transactionChanges.tag, ...uniquePolicyRecentlyUsedTags]; + } + } + // STEP 4: Compose the optimistic data const optimisticData = [ { @@ -1173,6 +1184,14 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC }, ]; + if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`, + value: optimisticPolicyRecentlyUsedTags, + }); + } + const successData = [ { onyxMethod: Onyx.METHOD.MERGE, From b45e8962563330795aba5652beb0e1c89570a092 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Thu, 21 Sep 2023 16:15:58 +0200 Subject: [PATCH 118/250] chore: check for lint error --- src/libs/migrateOnyx.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js index a58bb79a26f9..23153fea0be2 100644 --- a/src/libs/migrateOnyx.js +++ b/src/libs/migrateOnyx.js @@ -18,6 +18,7 @@ export default function () { MoveToIndexedDB, RenameActiveClientsKey, RenamePriorityModeKey, + AddEncryptedAuthToken, AddLastVisibleActionCreated, KeyReportActionsByReportActionID, From 3006ce9911ed651b3b33a032c8b30a9c55ec2b24 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Thu, 21 Sep 2023 16:16:19 +0200 Subject: [PATCH 119/250] chore: revert change --- src/libs/migrateOnyx.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js index 23153fea0be2..a58bb79a26f9 100644 --- a/src/libs/migrateOnyx.js +++ b/src/libs/migrateOnyx.js @@ -18,7 +18,6 @@ export default function () { MoveToIndexedDB, RenameActiveClientsKey, RenamePriorityModeKey, - AddEncryptedAuthToken, AddLastVisibleActionCreated, KeyReportActionsByReportActionID, From 48f589ec3ead94b8b207a3cd930aa0d3f3f6c644 Mon Sep 17 00:00:00 2001 From: Thiago Brezinski Date: Thu, 21 Sep 2023 15:41:18 +0100 Subject: [PATCH 120/250] fix(selection-list): remove highlight when pressing --- .../SelectionList/BaseSelectionList.js | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js index e0e4f8740cff..fb9d27323735 100644 --- a/src/components/SelectionList/BaseSelectionList.js +++ b/src/components/SelectionList/BaseSelectionList.js @@ -171,21 +171,35 @@ function BaseSelectionList({ listRef.current.scrollToLocation({sectionIndex: adjustedSectionIndex, itemIndex, animated, viewOffset: variables.contentHeaderHeight}); }; - const selectRow = (item) => { + /** + * Logic to run when a row is selected, either with click/press or keyboard hotkeys. + * + * @param item - the list item + * @param {Boolean} shouldUnfocusRow - flag to decide if we should unfocus all rows. True when selecting a row with click or press (not keyboard) + */ + const selectRow = (item, shouldUnfocusRow = false) => { // In single-selection lists we don't care about updating the focused index, because the list is closed after selecting an item if (canSelectMultiple) { if (sections.length > 1) { // If the list has only 1 section (e.g. Workspace Members list), we do nothing. - // If the list has multiple sections (e.g. Workspace Invite list), we focus the first one after all the selected (selected items are always at the top). - + // If the list has multiple sections (e.g. Workspace Invite list), and `shouldUnfocusRow` is false, + // we focus the first one after all the selected (selected items are always at the top). const selectedOptionsCount = item.isSelected ? flattenedSections.selectedOptions.length - 1 : flattenedSections.selectedOptions.length + 1; - setFocusedIndex(selectedOptionsCount); + + if (!shouldUnfocusRow) { + setFocusedIndex(selectedOptionsCount); + } if (!item.isSelected) { // If we're selecting an item, scroll to it's position at the top, so we can see it scrollToIndex(Math.max(selectedOptionsCount - 1, 0), true); } } + + if (shouldUnfocusRow) { + // Unfocus all rows when selecting row with click/press + setFocusedIndex(-1); + } } onSelectRow(item); @@ -255,7 +269,7 @@ function BaseSelectionList({ selectRow(item, true)} onDismissError={onDismissError} showTooltip={showTooltip} /> @@ -267,7 +281,7 @@ function BaseSelectionList({ item={item} isFocused={isItemFocused} isDisabled={isDisabled} - onSelectRow={selectRow} + onSelectRow={() => selectRow(item, true)} /> ); }; From 7e7de605209d1034c2bd3b10c1f5d60b3a12a7fc Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 21 Sep 2023 23:15:03 +0800 Subject: [PATCH 121/250] set map text color to black --- src/components/MapView/MapView.web.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/MapView/MapView.web.tsx b/src/components/MapView/MapView.web.tsx index ce13cee10f54..209928ab0499 100644 --- a/src/components/MapView/MapView.web.tsx +++ b/src/components/MapView/MapView.web.tsx @@ -11,6 +11,8 @@ import responder from './responder'; import utils from './utils'; import CONST from '../../CONST'; +import * as StyleUtils from '../../styles/StyleUtils'; +import themeColors from '../../styles/themes/default'; import Direction from './Direction'; import {MapViewHandle, MapViewProps} from './MapViewTypes'; @@ -87,6 +89,7 @@ const MapView = forwardRef( latitude: initialState.location[1], zoom: initialState.zoom, }} + style={StyleUtils.getTextColorStyle(themeColors.shadow) as React.CSSProperties} mapStyle={styleURL} > {waypoints?.map(({coordinate, markerComponent, id}) => { From abf3a3dd8f4d9c9c8a9fc6985b36f4c6af170826 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 21 Sep 2023 21:02:57 +0530 Subject: [PATCH 122/250] use provided description for hubs --- docs/_data/_routes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_data/_routes.yml b/docs/_data/_routes.yml index 1cea22074cc0..45703ea955ec 100644 --- a/docs/_data/_routes.yml +++ b/docs/_data/_routes.yml @@ -139,4 +139,4 @@ platforms: - href: workspace-and-domain-settings title: Workspace & Domain Settings icon: /assets/images/shield.svg - description: Discover how to set up and manage workspaces, define user permissions, and implement compliance rules to maintain a secure and compliant financial management landscape. + description: Discover how to set up and manage your workspace, define user permissions, and implement domain-level rules. From 063244aadd2e0fbdde02fc99709e1a4e6db2125f Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Thu, 21 Sep 2023 16:49:10 +0100 Subject: [PATCH 123/250] fix: better prop types and small fixes --- src/components/MoneyRequestConfirmationList.js | 8 +------- .../ReportActionItem/MoneyRequestView.js | 10 ++-------- src/components/TagPicker/tagPickerPropTypes.js | 7 +------ src/components/tagPropTypes.js | 10 +++++++++- src/libs/PolicyUtils.js | 14 +++++++------- src/libs/TransactionUtils.js | 2 +- src/pages/EditRequestPage.js | 8 +------- src/pages/iou/MoneyRequestTagPage.js | 7 +------ 8 files changed, 23 insertions(+), 43 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index b9a744b2e71c..1ebc4461c961 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -143,13 +143,7 @@ const propTypes = { policyCategories: PropTypes.objectOf(categoryPropTypes), /** Collection of tags attached to a policy */ - policyTags: PropTypes.objectOf( - PropTypes.shape({ - name: PropTypes.string, - required: PropTypes.bool, - tags: PropTypes.objectOf(tagPropTypes), - }), - ), + policyTags: tagPropTypes, }; const defaultProps = { diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 0c996e19bf60..b673881c1922 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -56,13 +56,7 @@ const propTypes = { transaction: transactionPropTypes, /** Collection of tags attached to a policy */ - policyTags: PropTypes.objectOf( - PropTypes.shape({ - name: PropTypes.string, - required: PropTypes.bool, - tags: PropTypes.objectOf(tagPropTypes), - }), - ), + policyTags: tagPropTypes, ...withCurrentUserPersonalDetailsPropTypes, }; @@ -222,7 +216,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should {shouldShowTag && ( Date: Thu, 21 Sep 2023 23:22:48 +0700 Subject: [PATCH 124/250] fix lint --- src/pages/iou/steps/NewRequestAmountPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index 8b4d73f0aee0..32f4e6066063 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -1,5 +1,5 @@ import React, {useCallback, useEffect, useRef} from 'react'; -import {InteractionManager, View} from 'react-native'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import {useFocusEffect} from '@react-navigation/native'; From dfeabc8bfc329abd5f98c180474a68c93b2c3d89 Mon Sep 17 00:00:00 2001 From: Hans Date: Thu, 21 Sep 2023 23:45:15 +0700 Subject: [PATCH 125/250] add comment for secondaryAccountId --- src/pages/home/report/ReportActionItemSingle.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 7d71ad00a0f3..a220f17d3e8b 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -114,6 +114,7 @@ function ReportActionItemSingle(props) { let secondaryAvatar = {}; const primaryDisplayName = displayName; if (displayAllActors) { + // When we merge IOUs into one, if ownerAccountID is also actorAccountID, we should use managerID instead to prevent duplicate information. const secondaryAccountId = props.iouReport.ownerAccountID === actorAccountID ? props.iouReport.managerID : props.iouReport.ownerAccountID; const secondaryUserDetails = props.personalDetailsList[secondaryAccountId] || {}; const secondaryDisplayName = lodashGet(secondaryUserDetails, 'displayName', ''); From ec40451e00d3239e35eb02b18d0f78d945e030a9 Mon Sep 17 00:00:00 2001 From: Thiago Brezinski Date: Thu, 21 Sep 2023 18:01:26 +0100 Subject: [PATCH 126/250] chore: fix jsdoc --- src/components/SelectionList/BaseSelectionList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js index fb9d27323735..f1de4a04e78d 100644 --- a/src/components/SelectionList/BaseSelectionList.js +++ b/src/components/SelectionList/BaseSelectionList.js @@ -174,7 +174,7 @@ function BaseSelectionList({ /** * Logic to run when a row is selected, either with click/press or keyboard hotkeys. * - * @param item - the list item + * @param {Object} item - the list item * @param {Boolean} shouldUnfocusRow - flag to decide if we should unfocus all rows. True when selecting a row with click or press (not keyboard) */ const selectRow = (item, shouldUnfocusRow = false) => { From 6f3221da0284f148e3d8d8354fee78614e7c6472 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:36:32 +0000 Subject: [PATCH 127/250] Fix Copying IOU Report Action text copies a wrong text --- src/libs/ReportUtils.js | 46 ++++++++++++++++++- .../report/ContextMenu/ContextMenuActions.js | 37 +-------------- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 7916630d7b4e..cbd41816af09 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -557,7 +557,7 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim if (ignoreDomainRooms) { // We allow public announce rooms, admins, and announce rooms through since we bypass the default rooms beta for them. - // Check where ReportUtils.findLastAccessedReport is called in MainDrawerNavigator.js for more context. + // Check where findLastAccessedReport is called in MainDrawerNavigator.js for more context. // Domain rooms are now the only type of default room that are on the defaultRooms beta. sortedReports = _.filter( sortedReports, @@ -3517,6 +3517,49 @@ function getReportPreviewDisplayTransactions(reportPreviewAction) { ); } +/** + * Return iou report action display message + * + * @param {Object} reportAction report action + * @returns {String} + */ +function getIouReportActionDisplayMessage(reportAction) { + const originalMessage = _.get(reportAction, 'originalMessage', {}); + let displayMessage; + if (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY) { + const {amount, currency, IOUReportID} = originalMessage; + const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); + const iouReport = getReport(IOUReportID); + const payerName = isExpenseReport(iouReport) ? getPolicyName(iouReport, false, getPolicyName(iouReport)) : getDisplayNameForParticipant(iouReport.managerID); + let translationKey; + switch (originalMessage.paymentType) { + case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: + translationKey = 'iou.paidElsewhereWithAmount'; + break; + case CONST.IOU.PAYMENT_TYPE.PAYPAL_ME: + translationKey = 'iou.paidUsingPaypalWithAmount'; + break; + case CONST.IOU.PAYMENT_TYPE.EXPENSIFY: + case CONST.IOU.PAYMENT_TYPE.VBBA: + translationKey = 'iou.paidUsingExpensifyWithAmount'; + break; + default: + translationKey = ''; + break; + } + displayMessage = Localize.translateLocal(translationKey, {amount: formattedAmount, payer: payerName}); + } else { + const transaction = TransactionUtils.getTransaction(originalMessage.IOUTransactionID); + const {amount, currency, comment} = getTransactionDetails(transaction); + const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); + displayMessage = Localize.translateLocal('iou.requestedAmount', { + formattedAmount, + comment, + }); + } + return displayMessage; +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -3657,4 +3700,5 @@ export { getReportPreviewDisplayTransactions, getTransactionsWithReceipts, hasMissingSmartscanFields, + getIouReportActionDisplayMessage, }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 9ee801fbd4a6..eafc0e03bc9b 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -22,9 +22,6 @@ import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickE import Navigation from '../../../../libs/Navigation/Navigation'; import ROUTES from '../../../../ROUTES'; import * as Task from '../../../../libs/actions/Task'; -import * as Localize from '../../../../libs/Localize'; -import * as TransactionUtils from '../../../../libs/TransactionUtils'; -import * as CurrencyUtils from '../../../../libs/CurrencyUtils'; /** * Gets the HTML version of the message in an action. @@ -203,39 +200,7 @@ export default [ const modifyExpenseMessage = ReportUtils.getModifiedExpenseMessage(reportAction); Clipboard.setString(modifyExpenseMessage); } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { - const originalMessage = _.get(reportAction, 'originalMessage', {}); - let displayMessage; - if (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY) { - const {amount, currency, IOUReportID} = originalMessage; - const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); - const iouReport = ReportUtils.getReport(IOUReportID); - const payerName = ReportUtils.getDisplayNameForParticipant(iouReport.managerID, true); - let translationKey; - switch (originalMessage.paymentType) { - case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: - translationKey = 'iou.paidElsewhereWithAmount'; - break; - case CONST.IOU.PAYMENT_TYPE.PAYPAL_ME: - translationKey = 'iou.paidUsingPaypalWithAmount'; - break; - case CONST.IOU.PAYMENT_TYPE.EXPENSIFY: - case CONST.IOU.PAYMENT_TYPE.VBBA: - translationKey = 'iou.paidUsingExpensifyWithAmount'; - break; - default: - translationKey = ''; - break; - } - displayMessage = Localize.translateLocal(translationKey, {amount: formattedAmount, payer: payerName}); - } else { - const transaction = TransactionUtils.getTransaction(originalMessage.IOUTransactionID); - const {amount, currency, comment} = ReportUtils.getTransactionDetails(transaction); - const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); - displayMessage = Localize.translateLocal('iou.requestedAmount', { - formattedAmount, - comment, - }); - } + const displayMessage = ReportUtils.getIouReportActionDisplayMessage(reportAction); Clipboard.setString(displayMessage); } else if (content) { const parser = new ExpensiMark(); From 4c9641df241afb970b5d142bae214c1f5f999712 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:44:13 +0000 Subject: [PATCH 128/250] correct comment --- 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 cbd41816af09..82cd9047654c 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -557,7 +557,7 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim if (ignoreDomainRooms) { // We allow public announce rooms, admins, and announce rooms through since we bypass the default rooms beta for them. - // Check where findLastAccessedReport is called in MainDrawerNavigator.js for more context. + // Check where ReportUtils.findLastAccessedReport is called in MainDrawerNavigator.js for more context. // Domain rooms are now the only type of default room that are on the defaultRooms beta. sortedReports = _.filter( sortedReports, From d1bfcf468dec20875e0201330fa34d5c888975b2 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 21 Sep 2023 19:57:35 +0200 Subject: [PATCH 129/250] Fix tests after onyx update --- tests/ui/UnreadIndicatorsTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 6a64dda85b37..eadc94da6e37 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -369,6 +369,7 @@ describe('Unread Indicators', () => { // Tap the new report option and navigate back to the sidebar again via the back button return navigateToSidebarOption(0); }) + .then(waitForBatchedUpdates) .then(() => { // Verify that report we navigated to appears in a "read" state while the original unread report still shows as unread const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); From d031bd877682a10327c987383c569bdbd661a046 Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 22 Sep 2023 07:02:28 +0700 Subject: [PATCH 130/250] dry code --- .../MoneyRequestParticipantsPage.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 580ddd195ae8..4e7ff612587b 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -55,6 +55,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const [headerTitle, setHeaderTitle] = useState(); const transaction = TransactionUtils.getTransaction(iou.transactionID); const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})); + const shouldNavigateBack = !isDistanceRequest || (isDistanceRequest && isEmptyWaypoint) useEffect(() => { if (isDistanceRequest) { @@ -78,7 +79,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request if (prevMoneyRequestId.current !== iou.id) { // The ID is cleared on completing a request. In that case, we will do nothing - if (iou.id && (!isDistanceRequest || (isDistanceRequest && isEmptyWaypoint)) && !isSplitRequest && !isNewReportIDSelectedLocally.current) { + if (iou.id && shouldNavigateBack && !isSplitRequest && !isNewReportIDSelectedLocally.current) { navigateBack(true); } return; @@ -90,7 +91,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { if (shouldReset) { IOU.resetMoneyRequestInfo(moneyRequestId); } - if ((!isDistanceRequest || (isDistanceRequest && isEmptyWaypoint)) && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { + if (shouldNavigateBack && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { navigateBack(true); } From 6f96e156ebcd3230a2596bff512b8b0fedcba478 Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 22 Sep 2023 07:14:08 +0700 Subject: [PATCH 131/250] clear name --- .../MoneyRequestParticipantsPage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 751839102761..1f4aca09a343 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -56,7 +56,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const [headerTitle, setHeaderTitle] = useState(); const transaction = TransactionUtils.getTransaction(iou.transactionID); const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})); - const shouldNavigateBack = !isDistanceRequest || (isDistanceRequest && isEmptyWaypoint) + const isNotValidDistanceRequest = !isDistanceRequest || (isDistanceRequest && isEmptyWaypoint); useEffect(() => { if (isDistanceRequest) { @@ -92,7 +92,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request if (prevMoneyRequestId.current !== iou.id) { // The ID is cleared on completing a request. In that case, we will do nothing - if (iou.id && shouldNavigateBack && !isSplitRequest && !isNewReportIDSelectedLocally.current) { + if (iou.id && isNotValidDistanceRequest && !isSplitRequest && !isNewReportIDSelectedLocally.current) { navigateBack(true); } return; @@ -104,7 +104,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { if (shouldReset) { IOU.resetMoneyRequestInfo(moneyRequestId); } - if (shouldNavigateBack && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { + if (isNotValidDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { navigateBack(true); } From d7ee1d2f8b32e2a4f51c1f704b44d4abc38af1aa Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 22 Sep 2023 07:26:27 +0700 Subject: [PATCH 132/250] clear name --- .../MoneyRequestParticipantsPage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 1f4aca09a343..227443648539 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -56,7 +56,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const [headerTitle, setHeaderTitle] = useState(); const transaction = TransactionUtils.getTransaction(iou.transactionID); const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})); - const isNotValidDistanceRequest = !isDistanceRequest || (isDistanceRequest && isEmptyWaypoint); + const isInvalidDistanceRequest = !isDistanceRequest || (isDistanceRequest && isEmptyWaypoint); useEffect(() => { if (isDistanceRequest) { @@ -92,7 +92,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request if (prevMoneyRequestId.current !== iou.id) { // The ID is cleared on completing a request. In that case, we will do nothing - if (iou.id && isNotValidDistanceRequest && !isSplitRequest && !isNewReportIDSelectedLocally.current) { + if (iou.id && isInvalidDistanceRequest && !isSplitRequest && !isNewReportIDSelectedLocally.current) { navigateBack(true); } return; @@ -104,7 +104,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { if (shouldReset) { IOU.resetMoneyRequestInfo(moneyRequestId); } - if (isNotValidDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { + if (isInvalidDistanceRequest && ((iou.amount === 0 && !iou.receiptPath) || shouldReset)) { navigateBack(true); } From 812ea40f75d1a5af5d2c7ad4e329c1538f08c878 Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 22 Sep 2023 07:31:22 +0700 Subject: [PATCH 133/250] clean logic --- .../MoneyRequestParticipantsPage.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 227443648539..dfba903edfaf 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -56,8 +56,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const [headerTitle, setHeaderTitle] = useState(); const transaction = TransactionUtils.getTransaction(iou.transactionID); const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})); - const isInvalidDistanceRequest = !isDistanceRequest || (isDistanceRequest && isEmptyWaypoint); - + const isInvalidDistanceRequest = !isDistanceRequest || isEmptyWaypoint; useEffect(() => { if (isDistanceRequest) { setHeaderTitle(translate('common.distance')); From d26408c87a7cc1f3296453f412e2060e3634e6f2 Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 22 Sep 2023 07:35:21 +0700 Subject: [PATCH 134/250] correct dependency --- .../MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index dfba903edfaf..90a135c082c5 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -110,7 +110,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { return () => { prevMoneyRequestId.current = iou.id; }; - }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, isEmptyWaypoint]); + }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, isInvalidDistanceRequest]); return ( Date: Fri, 22 Sep 2023 07:39:51 +0700 Subject: [PATCH 135/250] move isInvalidDistanceRequest to useEffect --- .../MoneyRequestParticipantsPage.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 90a135c082c5..a806200f99f7 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -56,7 +56,6 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { const [headerTitle, setHeaderTitle] = useState(); const transaction = TransactionUtils.getTransaction(iou.transactionID); const isEmptyWaypoint = _.isEmpty(lodashGet(transaction, 'comment.waypoint.waypoint0', {})); - const isInvalidDistanceRequest = !isDistanceRequest || isEmptyWaypoint; useEffect(() => { if (isDistanceRequest) { setHeaderTitle(translate('common.distance')); @@ -88,6 +87,8 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { }; useEffect(() => { + const isInvalidDistanceRequest = !isDistanceRequest || isEmptyWaypoint; + // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request if (prevMoneyRequestId.current !== iou.id) { // The ID is cleared on completing a request. In that case, we will do nothing @@ -110,7 +111,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) { return () => { prevMoneyRequestId.current = iou.id; }; - }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, isInvalidDistanceRequest]); + }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, isEmptyWaypoint]); return ( Date: Fri, 22 Sep 2023 07:34:16 +0530 Subject: [PATCH 136/250] revert back changes. Signed-off-by: Krishna Gupta --- src/components/Image/index.js | 33 ++-------------------- src/components/ImageWithSizeCalculation.js | 26 +++++++++++++++-- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 3cadac0157bb..7434c16c6491 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,4 +1,4 @@ -import React, {useEffect, useMemo, useRef, useState} from 'react'; +import React, {useEffect, useMemo} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; @@ -8,10 +8,7 @@ import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; function Image(props) { - const {source: propsSource, isAuthTokenRequired, onLoad, session, onLoadStart = () => {}, onLoadEnd = () => {}} = props; - - const [isLoading, setIsLoading] = useState(false); - const isLoadedRef = useRef(null); + const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. @@ -44,38 +41,14 @@ function Image(props) { }); }, [onLoad, source]); - /** Delay the loader to detect whether the image is being loaded from the cache or the internet. */ - useEffect(() => { - if (isLoadedRef.current || !isLoading) { - return; - } - const timeout = _.delay(() => { - if (!isLoading || isLoadedRef.current) { - return; - } - onLoadStart(); - }, 200); - return () => clearTimeout(timeout); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isLoading]); - // Omit the props which the underlying RNImage won't use - const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired', 'onLoadStart', 'onLoadEnd']); + const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); return ( setIsLoading(true)} - onLoad={() => { - isLoadedRef.current = true; - }} - onLoadEnd={() => { - setIsLoading(false); - isLoadedRef.current = true; - onLoadEnd(); - }} /> ); } diff --git a/src/components/ImageWithSizeCalculation.js b/src/components/ImageWithSizeCalculation.js index 57b933380b88..6aa87d07f23e 100644 --- a/src/components/ImageWithSizeCalculation.js +++ b/src/components/ImageWithSizeCalculation.js @@ -1,4 +1,5 @@ -import React, {useState} from 'react'; +import _ from 'underscore'; +import React, {useState, useRef, useEffect} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import Log from '../libs/Log'; @@ -38,6 +39,8 @@ const defaultProps = { * */ function ImageWithSizeCalculation(props) { + const isLoadedRef = useRef(null); + const [isImageCached, setIsImageCached] = useState(true); const [isLoading, setIsLoading] = useState(false); const onError = () => { @@ -45,12 +48,27 @@ function ImageWithSizeCalculation(props) { }; const imageLoadedSuccessfully = (event) => { + isLoadedRef.current = true; props.onMeasure({ width: event.nativeEvent.width, height: event.nativeEvent.height, }); }; + /** Delay the loader to detect whether the image is being loaded from the cache or the internet. */ + useEffect(() => { + if (isLoadedRef.current || !isLoading) { + return; + } + const timeout = _.delay(() => { + if (!isLoading || isLoadedRef.current) { + return; + } + setIsImageCached(false); + }, 200); + return () => clearTimeout(timeout); + }, [isLoading]); + return ( { + if (isLoadedRef.current || isLoading) { + return; + } setIsLoading(true); }} onLoadEnd={() => { setIsLoading(false); + setIsImageCached(true); }} onError={onError} onLoad={imageLoadedSuccessfully} /> - {isLoading && } + {isLoading && !isImageCached && } ); } From adbad054a1e4706c0f609ee1c24cc4c0ab4a4586 Mon Sep 17 00:00:00 2001 From: Zany Renney <56830058+zanyrenney@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:17:46 +0100 Subject: [PATCH 137/250] Update Accessibility.md added a sentence to ensure that our new changes for the bug reporter to provided a screen recording are reflected --- .github/ISSUE_TEMPLATE/Accessibility.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Accessibility.md b/.github/ISSUE_TEMPLATE/Accessibility.md index 36a64aa25b43..1323e2c17e78 100644 --- a/.github/ISSUE_TEMPLATE/Accessibility.md +++ b/.github/ISSUE_TEMPLATE/Accessibility.md @@ -34,7 +34,7 @@ What can we do to fix the issue? -Which of our officially supported platforms is this issue occurring on? +Which of our officially supported platforms is this issue occurring on? Please only tick the box if you have provided a screen-recording in the thread for each platform: - [ ] Android / native - [ ] Android / Chrome - [ ] iOS / native From 8c2ec626a7e278062554e5c20cab6f8a7edd9785 Mon Sep 17 00:00:00 2001 From: c3024 Date: Fri, 22 Sep 2023 10:51:10 +0530 Subject: [PATCH 138/250] remove duplicate back icon, add clear message --- src/pages/workspace/WorkspaceNewRoomPage.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 89a3e854578d..c031fa8e6073 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -5,7 +5,9 @@ import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import withNavigationFocus, {withNavigationFocusPropTypes} from '../../components/withNavigationFocus'; import * as Report from '../../libs/actions/Report'; +import * as App from '../../libs/actions/App'; import useLocalize from '../../hooks/useLocalize'; +import useWindowDimensions from '../../hooks/useWindowDimensions'; import styles from '../../styles/styles'; import RoomNameInput from '../../components/RoomNameInput'; import Picker from '../../components/Picker'; @@ -69,6 +71,7 @@ const defaultProps = { function WorkspaceNewRoomPage(props) { const {translate} = useLocalize(); + const {isSmallScreenWidth} = useWindowDimensions(); const [visibility, setVisibility] = useState(CONST.REPORT.VISIBILITY.RESTRICTED); const [policyID, setPolicyID] = useState(null); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); @@ -144,7 +147,12 @@ function WorkspaceNewRoomPage(props) { ); return ( - + App.createWorkspaceAndNavigateToIt('', false, '', false, !isSmallScreenWidth)} + > Date: Fri, 22 Sep 2023 10:55:12 +0530 Subject: [PATCH 139/250] fix: Emoji suggestions is not displayed between '~~' & '__'. Signed-off-by: Krishna Gupta --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index eed1b98ae551..41d5f7bba89a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1230,7 +1230,7 @@ const CONST = { SPECIAL_CHAR_OR_EMOJI: // eslint-disable-next-line no-misleading-character-class - /[\n\s,/?"{}[\]()&^%\\;`$=#<>!*\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu, + /[\n\s,/?"{}[\]()&_~^%\\;`$=#<>!*\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu, SPACE_OR_EMOJI: // eslint-disable-next-line no-misleading-character-class From 5d9649c668f9424e0a698be5c1520e03b580e7a1 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 22 Sep 2023 13:38:17 +0700 Subject: [PATCH 140/250] fix: infiniti loading --- src/components/AttachmentModal.js | 1 + .../AttachmentView/AttachmentViewImage/index.js | 3 ++- src/components/Attachments/AttachmentView/index.js | 11 ++++++++++- src/components/Avatar.js | 8 ++++++-- src/components/AvatarWithImagePicker.js | 1 + src/components/ImageView/index.js | 7 ++++++- src/libs/actions/PersonalDetails.js | 2 ++ src/pages/ProfilePage.js | 1 + 8 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 946b5e2ddec9..6a250c05e805 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -395,6 +395,7 @@ function AttachmentModal(props) { file={file} onToggleKeyboard={updateConfirmButtonVisibility} isWorkspaceAvatar={props.isWorkspaceAvatar} + fallbackSource={props.fallbackSource} /> ) )} diff --git a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js index 7de4417a4efc..48ac954ced7f 100755 --- a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js +++ b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js @@ -12,13 +12,14 @@ const propTypes = { ...withLocalizePropTypes, }; -function AttachmentViewImage({source, file, isAuthTokenRequired, loadComplete, onPress, isImage, onScaleChanged, translate}) { +function AttachmentViewImage({source, file, isAuthTokenRequired, loadComplete, onPress, isImage, onScaleChanged, translate, onError}) { const children = ( ); return onPress ? ( diff --git a/src/components/Attachments/AttachmentView/index.js b/src/components/Attachments/AttachmentView/index.js index 47353d915060..1fc579977c9d 100755 --- a/src/components/Attachments/AttachmentView/index.js +++ b/src/components/Attachments/AttachmentView/index.js @@ -17,6 +17,7 @@ import AttachmentViewPdf from './AttachmentViewPdf'; import addEncryptedAuthTokenToURL from '../../../libs/addEncryptedAuthTokenToURL'; import * as StyleUtils from '../../../styles/StyleUtils'; import {attachmentViewPropTypes, attachmentViewDefaultProps} from './propTypes'; +import useNetwork from '../../../hooks/useNetwork'; const propTypes = { ...attachmentViewPropTypes, @@ -62,9 +63,14 @@ function AttachmentView({ translate, isFocused, isWorkspaceAvatar, + fallbackSource, }) { const [loadComplete, setLoadComplete] = useState(false); + const [imageError, setImageError] = useState(false); + + useNetwork({onReconnect: () => setImageError(false)}); + // Handles case where source is a component (ex: SVG) if (_.isFunction(source)) { let iconFillColor = ''; @@ -113,7 +119,7 @@ function AttachmentView({ if (isImage || (file && Str.isImage(file.name))) { return ( { + setImageError(true); + }} /> ); } diff --git a/src/components/Avatar.js b/src/components/Avatar.js index a27073be15f0..4f0eb60eb2e0 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useEffect, useState} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -66,6 +66,10 @@ function Avatar(props) { useNetwork({onReconnect: () => setImageError(false)}); + useEffect(() => { + setImageError(false); + }, [props.source]); + if (!props.source) { return null; } @@ -81,7 +85,7 @@ function Avatar(props) { const iconStyle = props.imageStyles && props.imageStyles.length ? [StyleUtils.getAvatarStyle(props.size), styles.bgTransparent, ...props.imageStyles] : undefined; const iconFillColor = isWorkspace ? StyleUtils.getDefaultWorkspaceAvatarColor(props.name).fill : props.fill; - const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(props.name) : props.fallbackIcon; + const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(props.name) : props.fallbackIcon || Expensicons.FallbackAvatar; return ( {({show}) => ( diff --git a/src/components/ImageView/index.js b/src/components/ImageView/index.js index e0dce180043b..1d90a5723016 100644 --- a/src/components/ImageView/index.js +++ b/src/components/ImageView/index.js @@ -22,13 +22,16 @@ const propTypes = { /** image file name */ fileName: PropTypes.string.isRequired, + + onError: PropTypes.func, }; const defaultProps = { isAuthTokenRequired: false, + onError: () => {}, }; -function ImageView({isAuthTokenRequired, url, fileName}) { +function ImageView({isAuthTokenRequired, url, fileName, onError}) { const [isLoading, setIsLoading] = useState(true); const [containerHeight, setContainerHeight] = useState(0); const [containerWidth, setContainerWidth] = useState(0); @@ -238,6 +241,7 @@ function ImageView({isAuthTokenRequired, url, fileName}) { resizeMode={zoomScale > 1 ? Image.resizeMode.center : Image.resizeMode.contain} onLoadStart={imageLoadingStart} onLoad={imageLoad} + onError={onError} /> {(isLoading || zoomScale === 0) && } @@ -268,6 +272,7 @@ function ImageView({isAuthTokenRequired, url, fileName}) { resizeMode={Image.resizeMode.contain} onLoadStart={imageLoadingStart} onLoad={imageLoad} + onError={onError} /> diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 201898324d07..69cf05b89b34 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -480,6 +480,7 @@ function deleteAvatar() { value: { [currentUserAccountID]: { avatar: defaultAvatar, + fallbackIcon: null, }, }, }, @@ -491,6 +492,7 @@ function deleteAvatar() { value: { [currentUserAccountID]: { avatar: allPersonalDetails[currentUserAccountID].avatar, + fallbackIcon: allPersonalDetails[currentUserAccountID].fallbackIcon, }, }, }, diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js index b0caac92e6c4..60d9d46f64b2 100755 --- a/src/pages/ProfilePage.js +++ b/src/pages/ProfilePage.js @@ -162,6 +162,7 @@ function ProfilePage(props) { source={UserUtils.getFullSizeAvatar(avatar, accountID)} isAuthTokenRequired originalFileName={originalFileName} + fallbackSource={fallbackIcon} > {({show}) => ( Date: Fri, 22 Sep 2023 12:50:03 +0530 Subject: [PATCH 141/250] add platform images --- .../account-details-expensify-classic.png | Bin 0 -> 24258 bytes .../images/account-details-new-expensify.png | Bin 0 -> 14583 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/assets/images/account-details-expensify-classic.png create mode 100644 docs/assets/images/account-details-new-expensify.png diff --git a/docs/assets/images/account-details-expensify-classic.png b/docs/assets/images/account-details-expensify-classic.png new file mode 100644 index 0000000000000000000000000000000000000000..70b9b5ace2c10df0d6626c9168ecc6233e8e2f46 GIT binary patch literal 24258 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

mtM=rxrUy+s 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 I5*+-$0GjaWi~s-t literal 0 HcmV?d00001 From 50caf0aee9c6ef9362967229a49eea45af7e1aad Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 13:05:27 +0530 Subject: [PATCH 142/250] use kansas font for title other than article --- docs/_includes/article-card.html | 2 +- docs/_includes/platform-card.html | 1 + docs/_sass/_main.scss | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/_includes/article-card.html b/docs/_includes/article-card.html index b6d8998c13ef..cddc93ac65fb 100644 --- a/docs/_includes/article-card.html +++ b/docs/_includes/article-card.html @@ -1,6 +1,6 @@

diff --git a/docs/_includes/platform-card.html b/docs/_includes/platform-card.html index d56a234a5c14..7e798094e7cc 100644 --- a/docs/_includes/platform-card.html +++ b/docs/_includes/platform-card.html @@ -8,6 +8,7 @@

{{ platform.title }}

{{ platform.description }}

+

{{ platform.url }}

diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index bc9d19bfca11..341a2ee72a84 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -512,6 +512,11 @@ button { } h3.title { + font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; + } + + h3.title, + h4.title { padding: 0; margin: 0; From f8a9b73e8e134772d62dab1e80e774217f73cffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Fri, 22 Sep 2023 11:37:01 +0200 Subject: [PATCH 143/250] compare strings instead of dates --- src/libs/SidebarUtils.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index f645697690e6..61d0394e3cdc 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -186,10 +186,32 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p draftReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); if (isInDefaultMode) { nonArchivedReports.sort( - (a, b) => new Date(b.lastVisibleActionCreated) - new Date(a.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()), + (a, b) => { + const stringA = a.lastVisibleActionCreated; + const stringB = b.lastVisibleActionCreated; + if (stringA < stringB) { + return -1; + } + if (stringA > stringB) { + return 1; + } + return a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()); + } ); // For archived reports ensure that most recent reports are at the top by reversing the order - archivedReports.sort((a, b) => new Date(a.lastVisibleActionCreated) - new Date(b.lastVisibleActionCreated)); + archivedReports.sort( + (a, b) => { + const stringA = a.lastVisibleActionCreated; + const stringB = b.lastVisibleActionCreated; + if (stringA < stringB) { + return -1; + } + if (stringA > stringB) { + return 1; + } + return 0; + } + ); } else { nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); archivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); From cdccdcd16c1874584b5a276b7634c557b1e3d238 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Fri, 22 Sep 2023 12:17:08 +0200 Subject: [PATCH 144/250] Fix the scale control is hidden on the map --- src/components/MapView/MapView.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index d9f51e111a43..e035dd1fe14b 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -71,6 +71,7 @@ const MapView = forwardRef(({accessToken, style, ma onMapIdle={setMapIdle} pitchEnabled={pitchEnabled} attributionPosition={{...styles.r2, ...styles.b2}} + scaleBarEnabled={false} logoPosition={{...styles.l2, ...styles.b2}} // eslint-disable-next-line {...responder.panHandlers} From 53e93fa99ff154ddf53114546007cd164cbd59d8 Mon Sep 17 00:00:00 2001 From: Yauheni Date: Fri, 22 Sep 2023 12:49:15 +0200 Subject: [PATCH 145/250] Fix spaces --- src/components/MapView/MapView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index e035dd1fe14b..9370cc95fb82 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -71,7 +71,7 @@ const MapView = forwardRef(({accessToken, style, ma onMapIdle={setMapIdle} pitchEnabled={pitchEnabled} attributionPosition={{...styles.r2, ...styles.b2}} - scaleBarEnabled={false} + scaleBarEnabled={false} logoPosition={{...styles.l2, ...styles.b2}} // eslint-disable-next-line {...responder.panHandlers} From 4ffde032a9737078cc4dace02e0b327cdca33679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Fri, 22 Sep 2023 12:53:26 +0200 Subject: [PATCH 146/250] fix order --- src/libs/SidebarUtils.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 61d0394e3cdc..ffbe72075099 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -190,10 +190,10 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p const stringA = a.lastVisibleActionCreated; const stringB = b.lastVisibleActionCreated; if (stringA < stringB) { - return -1; + return 1; } if (stringA > stringB) { - return 1; + return -1; } return a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()); } @@ -204,10 +204,10 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p const stringA = a.lastVisibleActionCreated; const stringB = b.lastVisibleActionCreated; if (stringA < stringB) { - return -1; + return 1; } if (stringA > stringB) { - return 1; + return -1; } return 0; } From 7786995f9a6390062b35cd3cff3f3f6fe25445ad Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Fri, 22 Sep 2023 12:54:14 +0200 Subject: [PATCH 147/250] Update comments --- .../actions/Device/getDeviceInfo/getOSAndName/index.native.ts | 2 ++ src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts | 2 ++ src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.ts b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.ts index 455487d056f2..bb9eb572570e 100644 --- a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.ts +++ b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.ts @@ -6,8 +6,10 @@ const getOSAndName: GetOSAndName = () => { const deviceName = RNDeviceInfo.getDeviceNameSync(); const prettyName = `${Str.UCFirst(RNDeviceInfo.getManufacturerSync() || '')} ${deviceName}`; return { + // Parameter names are predefined and we don't choose it here // eslint-disable-next-line @typescript-eslint/naming-convention device_name: RNDeviceInfo.isEmulatorSync() ? `Emulator - ${prettyName}` : prettyName, + // Parameter names are predefined and we don't choose it here // eslint-disable-next-line @typescript-eslint/naming-convention os_version: RNDeviceInfo.getSystemVersion(), }; diff --git a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts index 5155fc07afb2..d63c2fedc51d 100644 --- a/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts +++ b/src/libs/actions/Device/getDeviceInfo/getOSAndName/index.ts @@ -2,8 +2,10 @@ import {getOSAndName as libGetOSAndName} from 'expensify-common/lib/Device'; import GetOSAndName from './types'; const getOSAndName: GetOSAndName = () => { + // Parameter names are predefined and we don't choose it here // eslint-disable-next-line @typescript-eslint/naming-convention const {device_name, os_version} = libGetOSAndName(); + // Parameter names are predefined and we don't choose it here // eslint-disable-next-line @typescript-eslint/naming-convention return {device_name, os_version}; }; diff --git a/src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts b/src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts index 6616a13d8d23..2ca67c3c59c3 100644 --- a/src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts +++ b/src/libs/actions/Device/getDeviceInfo/getOSAndName/types.ts @@ -1,4 +1,4 @@ -// to keep same behavior from before migration +// Parameter names are predefined and we don't choose it here // eslint-disable-next-line @typescript-eslint/naming-convention type GetOSAndName = () => {device_name: string | undefined; os_version: string | undefined}; export default GetOSAndName; From 5245335cda6aef187a32d30140ce4fa6edf7926f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Fri, 22 Sep 2023 12:56:41 +0200 Subject: [PATCH 148/250] linting --- src/libs/SidebarUtils.js | 44 ++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index ffbe72075099..79bec62a1155 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -185,33 +185,29 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); draftReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); if (isInDefaultMode) { - nonArchivedReports.sort( - (a, b) => { - const stringA = a.lastVisibleActionCreated; - const stringB = b.lastVisibleActionCreated; - if (stringA < stringB) { - return 1; - } - if (stringA > stringB) { - return -1; - } - return a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()); + nonArchivedReports.sort((a, b) => { + const stringA = a.lastVisibleActionCreated; + const stringB = b.lastVisibleActionCreated; + if (stringA < stringB) { + return 1; } - ); + if (stringA > stringB) { + return -1; + } + return a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()); + }); // For archived reports ensure that most recent reports are at the top by reversing the order - archivedReports.sort( - (a, b) => { - const stringA = a.lastVisibleActionCreated; - const stringB = b.lastVisibleActionCreated; - if (stringA < stringB) { - return 1; - } - if (stringA > stringB) { - return -1; - } - return 0; + archivedReports.sort((a, b) => { + const stringA = a.lastVisibleActionCreated; + const stringB = b.lastVisibleActionCreated; + if (stringA < stringB) { + return 1; } - ); + if (stringA > stringB) { + return -1; + } + return 0; + }); } else { nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); archivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); From 7483d2dd952d1af12f6132628f2e3d5009ccbbd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Fri, 22 Sep 2023 13:11:21 +0200 Subject: [PATCH 149/250] applysuggestions --- src/libs/SidebarUtils.js | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 79bec62a1155..76e96de8542e 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -184,29 +184,22 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p pinnedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); draftReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); + const compareStringDates = (stringA, stringB) => { + if (stringA < stringB) { + return 1; + } + if (stringA > stringB) { + return -1; + } + return 0; + }; if (isInDefaultMode) { nonArchivedReports.sort((a, b) => { - const stringA = a.lastVisibleActionCreated; - const stringB = b.lastVisibleActionCreated; - if (stringA < stringB) { - return 1; - } - if (stringA > stringB) { - return -1; - } - return a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()); + return compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()); }); // For archived reports ensure that most recent reports are at the top by reversing the order archivedReports.sort((a, b) => { - const stringA = a.lastVisibleActionCreated; - const stringB = b.lastVisibleActionCreated; - if (stringA < stringB) { - return 1; - } - if (stringA > stringB) { - return -1; - } - return 0; + return compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated); }); } else { nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); From 53c0f76ae8b26c10eea71bbe73083e94c912ee9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Fri, 22 Sep 2023 13:23:12 +0200 Subject: [PATCH 150/250] fx linting --- src/libs/SidebarUtils.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 76e96de8542e..0366a6820970 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -194,13 +194,11 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p return 0; }; if (isInDefaultMode) { - nonArchivedReports.sort((a, b) => { - return compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()); - }); + nonArchivedReports.sort( + (a, b) => compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()), + ); // For archived reports ensure that most recent reports are at the top by reversing the order - archivedReports.sort((a, b) => { - return compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated); - }); + archivedReports.sort((a, b) => compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated)); } else { nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); archivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); From ccc817564a0f52524c7cc2530afc85bbee1504ea Mon Sep 17 00:00:00 2001 From: Dustin Stringer Date: Fri, 22 Sep 2023 09:26:42 -0400 Subject: [PATCH 151/250] Fixed file linting --- src/components/TextInput/BaseTextInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js index 3fae15a99ee1..efe7266a3f30 100644 --- a/src/components/TextInput/BaseTextInput.js +++ b/src/components/TextInput/BaseTextInput.js @@ -406,7 +406,7 @@ function BaseTextInput(props) { { - let additionalWidth = 0 + let additionalWidth = 0; if (Browser.isMobileSafari() || Browser.isSafari()) { additionalWidth = 2; } From ecf69331050544033646ed031b32cf9ec86e6c2f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 19:04:36 +0530 Subject: [PATCH 152/250] add hub card styling --- docs/_includes/hub-card.html | 2 +- docs/_sass/_main.scss | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/docs/_includes/hub-card.html b/docs/_includes/hub-card.html index b5188bda7670..2ad288d941a4 100644 --- a/docs/_includes/hub-card.html +++ b/docs/_includes/hub-card.html @@ -1,6 +1,6 @@ {% assign hub = include.hub %} {% assign platform = include.platform %} - +
{{ hub.href }} diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 341a2ee72a84..40e54ac1f2ba 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -527,6 +527,91 @@ button { + p.description { + padding: 0; + margin: 0; + font-weight: normal; + + &.with-min-height { + min-height: 68px; + + @include breakpoint($breakpoint-tablet) { + min-height: 48px; + } + } + } +} + +.hub-card { + display: flex; + flex-wrap: nowrap; + border-radius: 16px; + padding: 28px; + font-weight: 700; + cursor: pointer; + color: $color-text; + background-color: $color-highlightBG; + + &:hover { + background-color: darken($color-highlightBG, 1%); + } + + .row { + display: flex; + flex-basis:100%; + } + + .left-icon { + display: flex; + align-items: center; + padding-right: 28px; + + img { + width: 64px; + } + } + + .right-icon { + display: flex; + align-items: center; + padding-left: 16px; + } + + .submit-button { + display: flex; + align-items: center; + margin-top: 16px; + padding-left: 0; + + @include breakpoint($breakpoint-desktop) { + margin-top: 0; + padding-left: 16px; + } + } + + .body { + display: flex; + flex-wrap: nowrap; + flex-direction: column; + flex-grow: 2; + } + + h3.title { + font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; + } + + h3.title, + h4.title { + padding: 0; + margin: 0; + + &.with-margin { + margin: 0 0 4px 0; + } + } + + + p.description { padding: 0; margin: 0; From b0bdad61d495840f8ef683b0add4eb8d6527f499 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 13:50:18 +0000 Subject: [PATCH 153/250] remove paypal paymentType --- src/libs/ReportUtils.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 0f4b1882e901..4b7acd121d0b 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3611,9 +3611,6 @@ function getIouReportActionDisplayMessage(reportAction) { case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: translationKey = 'iou.paidElsewhereWithAmount'; break; - case CONST.IOU.PAYMENT_TYPE.PAYPAL_ME: - translationKey = 'iou.paidUsingPaypalWithAmount'; - break; case CONST.IOU.PAYMENT_TYPE.EXPENSIFY: case CONST.IOU.PAYMENT_TYPE.VBBA: translationKey = 'iou.paidUsingExpensifyWithAmount'; From 4ab98346051acc4a3339231b661c170a2e4f661d Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 19:54:37 +0530 Subject: [PATCH 154/250] add hub card styling --- docs/_includes/platform.html | 2 +- docs/_sass/_main.scss | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/_includes/platform.html b/docs/_includes/platform.html index f3867ee4f5b7..0323828f2d8c 100644 --- a/docs/_includes/platform.html +++ b/docs/_includes/platform.html @@ -5,7 +5,7 @@

{{ platform.hub-title }}

{{ site.data.routes.home.description }}

-
+
{% for hub in platform.hubs %} {% include hub-card.html hub=hub platform=selectedPlatform %} {% endfor %} diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 40e54ac1f2ba..728785f69d05 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -445,18 +445,26 @@ button { } } -.cards-group { +.cards-group, .platform-cards-group { display: grid; grid-template-columns: auto; row-gap: 20px; column-gap: 20px; padding-bottom: 20px; +} +.cards-group { @include breakpoint($breakpoint-desktop) { grid-template-columns: 50% 50%; } } +.platform-cards-group { + @include breakpoint($breakpoint-desktop) { + grid-template-columns: 33.33% 33.33% 33.33%; + } +} + .card { display: flex; flex-wrap: nowrap; @@ -546,7 +554,7 @@ button { display: flex; flex-wrap: nowrap; border-radius: 16px; - padding: 28px; + padding: 24px; font-weight: 700; cursor: pointer; color: $color-text; @@ -558,6 +566,7 @@ button { .row { display: flex; + flex-direction: column; flex-basis:100%; } @@ -567,7 +576,7 @@ button { padding-right: 28px; img { - width: 64px; + width: 68px; } } @@ -597,6 +606,7 @@ button { } h3.title { + font-size: 1.2em; font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; } @@ -606,7 +616,7 @@ button { margin: 0; &.with-margin { - margin: 0 0 4px 0; + margin: 20px 0 8px 0; } } From 02be8041ef9197e8183761ce6f17fd988d7b4228 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 19:58:20 +0530 Subject: [PATCH 155/250] fix typo in resource coming soon --- .../expensify-classic/account-settings/Account-Access.md | 2 +- .../expensify-classic/account-settings/Close-Account.md | 2 +- .../expensify-classic/account-settings/Merge-Accounts.md | 2 +- docs/articles/expensify-classic/account-settings/Preferences.md | 2 +- .../expensify-classic/account-settings/Profile-Settings.md | 2 +- .../Business-Bank-Accounts-AUS.md | 2 +- .../Business-Bank-Accounts-USD.md | 2 +- .../bank-accounts-and-credit-cards/Deposit-Accounts-AUS.md | 2 +- .../bank-accounts-and-credit-cards/Deposit-Accounts-USD.md | 2 +- .../bank-accounts-and-credit-cards/Global-Reimbursement.md | 2 +- .../bank-accounts-and-credit-cards/Personal-Credit-Cards.md | 2 +- .../bank-accounts-and-credit-cards/company-cards/ANZ.md | 2 +- .../bank-accounts-and-credit-cards/company-cards/Brex.md | 2 +- .../bank-accounts-and-credit-cards/company-cards/CSV-Import.md | 2 +- .../company-cards/Commercial-Card-Feeds.md | 2 +- .../company-cards/Connect-Company-Cards.md | 2 +- .../company-cards/Direct-Bank-Connections.md | 2 +- .../company-cards/Export-To-GL-Accounts.md | 2 +- .../company-cards/Reconciliation.md | 2 +- .../company-cards/Troubleshooting.md | 2 +- .../billing-and-subscriptions/Annual-Subscription.md | 2 +- .../billing-and-subscriptions/Billing-Owner.md | 2 +- .../billing-and-subscriptions/Change-Plan-Or-Subscription.md | 2 +- .../billing-and-subscriptions/Consolidated-Domain-Billing.md | 2 +- .../expensify-classic/billing-and-subscriptions/Free-Trial.md | 2 +- .../billing-and-subscriptions/Individual-Subscription.md | 2 +- .../expensify-classic/billing-and-subscriptions/Overview.md | 2 +- .../billing-and-subscriptions/Pay-Per-Use-Subscription.md | 2 +- .../expensify-classic/billing-and-subscriptions/Payment-Card.md | 2 +- .../expensify-classic/billing-and-subscriptions/Tax-Exempt.md | 2 +- .../expense-and-report-features/Attendee-Tracking.md | 2 +- .../expensify-classic/expense-and-report-features/Currency.md | 2 +- .../expense-and-report-features/Expense-Rules.md | 2 +- .../expense-and-report-features/Expense-Types.md | 2 +- .../expense-and-report-features/Report-Comments.md | 2 +- .../expense-and-report-features/The-Expenses-Page.md | 2 +- .../expense-and-report-features/The-Reports-Page.md | 2 +- .../expensify-classic/expensify-card/Auto-Reconciliation.md | 2 +- docs/articles/expensify-classic/expensify-card/CPA-Card.md | 2 +- docs/articles/expensify-classic/expensify-card/Card-Settings.md | 2 +- .../expensify-card/Connect-To-Indirect-Integration.md | 2 +- .../articles/expensify-classic/expensify-card/File-A-Dispute.md | 2 +- docs/articles/expensify-classic/expensify-card/Get-The-Card.md | 2 +- docs/articles/expensify-classic/expensify-card/Statements.md | 2 +- .../expensify-classic/expensify-card/The-Reports-Page.md | 2 +- docs/articles/expensify-classic/exports/Custom-Templates.md | 2 +- .../expensify-classic/exports/Default-Export-Templates.md | 2 +- docs/articles/expensify-classic/exports/The-Reports-Page.md | 2 +- docs/articles/expensify-classic/get-paid-back/Mileage.md | 2 +- docs/articles/expensify-classic/get-paid-back/Per-Diem.md | 2 +- .../expensify-classic/get-paid-back/Third-Party-Payments.md | 2 +- docs/articles/expensify-classic/get-paid-back/Trips.md | 2 +- .../expensify-classic/get-paid-back/expenses/Apply-Tax.md | 2 +- .../expensify-classic/get-paid-back/expenses/Create-Expenses.md | 2 +- .../expensify-classic/get-paid-back/expenses/Merge-Expenses.md | 2 +- .../expensify-classic/get-paid-back/expenses/Upload-Receipts.md | 2 +- .../expensify-classic/get-paid-back/reports/Create-A-Report.md | 2 +- .../expensify-classic/get-paid-back/reports/Reimbursements.md | 2 +- .../expensify-classic/getting-started/Best-Practices.md | 2 +- docs/articles/expensify-classic/getting-started/Employees.md | 2 +- .../expensify-classic/getting-started/Individual-Users.md | 2 +- .../expensify-classic/getting-started/Invite-Employees.md | 2 +- docs/articles/expensify-classic/getting-started/Plan-Types.md | 2 +- .../articles/expensify-classic/getting-started/Policy-Admins.md | 2 +- docs/articles/expensify-classic/getting-started/Security.md | 2 +- .../articles/expensify-classic/getting-started/Using-The-App.md | 2 +- .../expensify-classic/getting-started/tips-and-tricks.md | 2 +- .../integrations/accounting-integrations/Bill-dot-com.md | 2 +- .../integrations/accounting-integrations/FinancalForce.md | 2 +- .../integrations/accounting-integrations/NetSuite.md | 2 +- .../integrations/accounting-integrations/QuickBooks-Desktop.md | 2 +- .../integrations/accounting-integrations/QuickBooks-Online.md | 2 +- .../integrations/accounting-integrations/Sage-Intacct.md | 2 +- .../integrations/accounting-integrations/Xero.md | 2 +- .../expensify-classic/integrations/hr-integrations/ADP.md | 2 +- .../integrations/hr-integrations/Greenhouse.md | 2 +- .../expensify-classic/integrations/hr-integrations/Gusto.md | 2 +- .../integrations/hr-integrations/QuickBooks-Time.md | 2 +- .../expensify-classic/integrations/hr-integrations/Rippling.md | 2 +- .../expensify-classic/integrations/hr-integrations/Workday.md | 2 +- .../expensify-classic/integrations/hr-integrations/Zenefits.md | 2 +- .../integrations/other-integrations/Google-Apps-SSO.md | 2 +- .../expensify-classic/integrations/travel-integrations/Bolt.md | 2 +- .../integrations/travel-integrations/Egencia.md | 2 +- .../integrations/travel-integrations/Global-VaTax.md | 2 +- .../expensify-classic/integrations/travel-integrations/Grab.md | 2 +- .../integrations/travel-integrations/Hotel-Tonight.md | 2 +- .../expensify-classic/integrations/travel-integrations/Kayak.md | 2 +- .../expensify-classic/integrations/travel-integrations/Lyft.md | 2 +- .../integrations/travel-integrations/TrainLine.md | 2 +- .../integrations/travel-integrations/TravelPerk.md | 2 +- .../integrations/travel-integrations/Trip-Actions.md | 2 +- .../integrations/travel-integrations/TripCatcher.md | 2 +- .../expensify-classic/integrations/travel-integrations/Uber.md | 2 +- .../manage-employees-and-report-approvals/Adding-Users.md | 2 +- .../manage-employees-and-report-approvals/Approval-Workflows.md | 2 +- .../manage-employees-and-report-approvals/Approving-Reports.md | 2 +- .../manage-employees-and-report-approvals/User-Roles.md | 2 +- .../manage-employees-and-report-approvals/Vacation-Delegate.md | 2 +- .../expensify-classic/policy-and-domain-settings/Admins.md | 2 +- .../expensify-classic/policy-and-domain-settings/Categories.md | 2 +- .../policy-and-domain-settings/Domain-Admins.md | 2 +- .../policy-and-domain-settings/Domain-Members.md | 2 +- .../policy-and-domain-settings/Domains-Overview.md | 2 +- .../expensify-classic/policy-and-domain-settings/Expenses.md | 2 +- .../expensify-classic/policy-and-domain-settings/Invoicing.md | 2 +- .../expensify-classic/policy-and-domain-settings/Overview.md | 2 +- .../expensify-classic/policy-and-domain-settings/Per-Diem.md | 2 +- .../policy-and-domain-settings/Reimbursement.md | 2 +- .../expensify-classic/policy-and-domain-settings/Reports.md | 2 +- .../expensify-classic/policy-and-domain-settings/SAML.md | 2 +- .../expensify-classic/policy-and-domain-settings/Tags.md | 2 +- .../expensify-classic/policy-and-domain-settings/Tax.md | 2 +- .../expensify-classic/policy-and-domain-settings/Trips.md | 2 +- docs/articles/expensify-classic/send-payments/Pay-Bills.md | 2 +- docs/articles/expensify-classic/send-payments/Pay-Invoices.md | 2 +- .../expensify-classic/send-payments/Reimbursing-Reports.md | 2 +- .../expensify-classic/send-payments/Third-Party-Payments.md | 2 +- docs/articles/new-expensify/get-paid-back/Request-Money.md | 2 +- .../integrations/accounting-integrations/QuickBooks-Online.md | 2 +- 120 files changed, 120 insertions(+), 120 deletions(-) diff --git a/docs/articles/expensify-classic/account-settings/Account-Access.md b/docs/articles/expensify-classic/account-settings/Account-Access.md index f04b45c42639..b3126201715f 100644 --- a/docs/articles/expensify-classic/account-settings/Account-Access.md +++ b/docs/articles/expensify-classic/account-settings/Account-Access.md @@ -2,4 +2,4 @@ title: Account Access description: Account Access --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/account-settings/Close-Account.md b/docs/articles/expensify-classic/account-settings/Close-Account.md index cf5052fa56f1..5e18490fc357 100644 --- a/docs/articles/expensify-classic/account-settings/Close-Account.md +++ b/docs/articles/expensify-classic/account-settings/Close-Account.md @@ -2,4 +2,4 @@ title: Close Account description: Close Account --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/account-settings/Merge-Accounts.md b/docs/articles/expensify-classic/account-settings/Merge-Accounts.md index 1c5f22478e17..073c74346d75 100644 --- a/docs/articles/expensify-classic/account-settings/Merge-Accounts.md +++ b/docs/articles/expensify-classic/account-settings/Merge-Accounts.md @@ -2,4 +2,4 @@ title: Merge Accounts description: Merge Accounts --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/account-settings/Preferences.md b/docs/articles/expensify-classic/account-settings/Preferences.md index a3e53e1177a1..532da4d8a986 100644 --- a/docs/articles/expensify-classic/account-settings/Preferences.md +++ b/docs/articles/expensify-classic/account-settings/Preferences.md @@ -2,4 +2,4 @@ title: Preferences description: Preferences --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/account-settings/Profile-Settings.md b/docs/articles/expensify-classic/account-settings/Profile-Settings.md index bdc18036a46e..3b2a0b830926 100644 --- a/docs/articles/expensify-classic/account-settings/Profile-Settings.md +++ b/docs/articles/expensify-classic/account-settings/Profile-Settings.md @@ -2,4 +2,4 @@ title: Profile Settings description: Profile Settings --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-AUS.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-AUS.md index 44488defcd67..1c2edbbaefaa 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-AUS.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-AUS.md @@ -2,4 +2,4 @@ title: Business Bank Accounts - AUS description: Business Bank Accounts - AUS --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-USD.md index 218d6dcd1efa..375b00d62eac 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-USD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Business-Bank-Accounts-USD.md @@ -2,4 +2,4 @@ title: Business Bank Accounts - USD description: Business Bank Accounts - USD --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-AUS.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-AUS.md index dba02f6fc52c..9b42e3701310 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-AUS.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-AUS.md @@ -2,4 +2,4 @@ title: Deposit Accounts - AUS description: Deposit Accounts - AUS --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-USD.md index 8d3fe6e51484..19010be95980 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-USD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Deposit-Accounts-USD.md @@ -2,4 +2,4 @@ title: Deposit Accounts - USD description: Deposit Accounts - USD --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursement.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursement.md index 40bdfb7741ab..073d3a9bd700 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursement.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursement.md @@ -2,4 +2,4 @@ title: Global Reimbursement description: Global Reimbursement --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md index 016ca90ee7f7..f89729b69586 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md @@ -2,4 +2,4 @@ title: Personal Credit Cards description: Personal Credit Cards --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/ANZ.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/ANZ.md index 6bfc7b14c09a..7e6a76ecee24 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/ANZ.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/ANZ.md @@ -2,5 +2,5 @@ title: ANZ description: A guide to integrate with your ANZ card --- -## Resources Coming Soon! +## Resource Coming Soon! Coming Soon!! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Brex.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Brex.md index 7d5ad7bf0315..a060e37146a5 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Brex.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Brex.md @@ -2,4 +2,4 @@ title: Brex description: Brex --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md index db68d4431a3a..6debce6240ff 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md @@ -2,4 +2,4 @@ title: CSV Import description: CSV Import --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md index e49d0d61855c..25d11561755d 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md @@ -2,4 +2,4 @@ title: Commercial Card Feeds description: Commercial Card Feeds --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md index ecd4fc0a6538..112c3b9617c9 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-Company-Cards.md @@ -2,4 +2,4 @@ title: Connect Company Cards description: Connect Company Cards --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md index 6775b2684b61..f1d939ca9c89 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md @@ -2,4 +2,4 @@ title: Direct Bank Connections description: Direct Bank Connections --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Export-To-GL-Accounts.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Export-To-GL-Accounts.md index 58485888b921..85b534338b53 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Export-To-GL-Accounts.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Export-To-GL-Accounts.md @@ -2,4 +2,4 @@ title: Export to GL Accounts description: Export to GL Accounts --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md index be400ee2c13c..b51329f2a803 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md @@ -2,4 +2,4 @@ title: Reconciliation description: Reconciliation --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md index d9e0d1bb994b..e3d1307e6a05 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md @@ -2,4 +2,4 @@ title: Troubleshooting description: Troubleshooting --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Annual-Subscription.md b/docs/articles/expensify-classic/billing-and-subscriptions/Annual-Subscription.md index c80a0d57400d..8e2aa7d4a377 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Annual-Subscription.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Annual-Subscription.md @@ -2,4 +2,4 @@ title: Annual Subscription description: Annual Subscription --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md index 590fbc78007e..acb29d91e1d8 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md @@ -2,4 +2,4 @@ title: Billing-Owner description: Billing-Owner --- -## Resources Coming Soon! \ No newline at end of file +## Resource Coming Soon! \ No newline at end of file diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md b/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md index 2f593625a7d5..8ce4283dd17d 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md @@ -2,4 +2,4 @@ title: Change Plan or Subscription description: Change Plan or Subscription --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md b/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md index de6ec4a4a466..24edc553bd29 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md @@ -2,4 +2,4 @@ title: Consolidated Domain Billing description: Consolidated Domain Billing --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md b/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md index 8a7b7edd19d9..e08aaa3d6094 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md @@ -2,4 +2,4 @@ title: Free Trial description: Free Trial --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md b/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md index d6be489a1146..1ace758978aa 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md @@ -2,4 +2,4 @@ title: Individual Subscription description: Individual Subscription --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md b/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md index 3352c72167cd..963186916f01 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md @@ -2,4 +2,4 @@ title: Overview description: Overview --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md b/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md index be431a287557..77aca2a01678 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md @@ -2,4 +2,4 @@ title: Pay-per-use Subscription description: Pay-per-use Subscription --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md b/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md index 91c5d4e91eda..41a1fb96f56f 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Payment-Card.md @@ -2,4 +2,4 @@ title: Payment Card description: Payment Card --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md b/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md index c8f781cbd59b..c4948b5b3083 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md @@ -2,4 +2,4 @@ title: Tax Exempt description: Tax Exempt --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md b/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md index bc7fbdfe84aa..a5b0b26b2610 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md +++ b/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md @@ -2,4 +2,4 @@ title: Attendee Tracking description: Attendee Tracking --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/Currency.md b/docs/articles/expensify-classic/expense-and-report-features/Currency.md index 611365aa5013..e5c9096fa610 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/Currency.md +++ b/docs/articles/expensify-classic/expense-and-report-features/Currency.md @@ -2,4 +2,4 @@ title: Currency description: Currency --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md b/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md index 81c664497e14..304c93d1da6d 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md +++ b/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md @@ -2,4 +2,4 @@ title: Expense Rules description: Expense Rules --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md b/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md index a75209e4dfb1..3f2e49952c4a 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md +++ b/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md @@ -2,4 +2,4 @@ title: Expense Types description: Expense Types --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/Report-Comments.md b/docs/articles/expensify-classic/expense-and-report-features/Report-Comments.md index 3938c02bd333..b7ed120fb28b 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/Report-Comments.md +++ b/docs/articles/expensify-classic/expense-and-report-features/Report-Comments.md @@ -2,4 +2,4 @@ title: Report Comments description: Report Comments --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md index f202587568e5..f30dde9efc3d 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md +++ b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md @@ -2,4 +2,4 @@ title: The Expenses Page description: The Expenses Page --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md b/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md index 37da613e750a..e72abfcad51a 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md +++ b/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md @@ -2,4 +2,4 @@ title: The Reports Page description: The Reports Page --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md b/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md index e1d1a990b166..85202835a0e4 100644 --- a/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md +++ b/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md @@ -2,4 +2,4 @@ title: Auto-reconciliation description: Auto-reconciliation --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/CPA-Card.md b/docs/articles/expensify-classic/expensify-card/CPA-Card.md index 9f4c47a6a402..dfc1e71192db 100644 --- a/docs/articles/expensify-classic/expensify-card/CPA-Card.md +++ b/docs/articles/expensify-classic/expensify-card/CPA-Card.md @@ -2,4 +2,4 @@ title: CPA Card description: CPA Card --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/Card-Settings.md b/docs/articles/expensify-classic/expensify-card/Card-Settings.md index ff9a959d38aa..ab212354974a 100644 --- a/docs/articles/expensify-classic/expensify-card/Card-Settings.md +++ b/docs/articles/expensify-classic/expensify-card/Card-Settings.md @@ -2,4 +2,4 @@ title: Card Settings description: Card Settings --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/Connect-To-Indirect-Integration.md b/docs/articles/expensify-classic/expensify-card/Connect-To-Indirect-Integration.md index 0e05269f6501..9888edd139ac 100644 --- a/docs/articles/expensify-classic/expensify-card/Connect-To-Indirect-Integration.md +++ b/docs/articles/expensify-classic/expensify-card/Connect-To-Indirect-Integration.md @@ -2,4 +2,4 @@ title: Connect to Indirect Integration description: Connect to Indirect Integration --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/File-A-Dispute.md b/docs/articles/expensify-classic/expensify-card/File-A-Dispute.md index 296999410687..694bce3da059 100644 --- a/docs/articles/expensify-classic/expensify-card/File-A-Dispute.md +++ b/docs/articles/expensify-classic/expensify-card/File-A-Dispute.md @@ -2,4 +2,4 @@ title: File a Dispute description: File a Dispute --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/Get-The-Card.md b/docs/articles/expensify-classic/expensify-card/Get-The-Card.md index 9c8e804f6363..e5233a3732a3 100644 --- a/docs/articles/expensify-classic/expensify-card/Get-The-Card.md +++ b/docs/articles/expensify-classic/expensify-card/Get-The-Card.md @@ -2,4 +2,4 @@ title: Get the Card description: Get the Card --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/Statements.md b/docs/articles/expensify-classic/expensify-card/Statements.md index 602fa610dd0b..b48d303a1a9b 100644 --- a/docs/articles/expensify-classic/expensify-card/Statements.md +++ b/docs/articles/expensify-classic/expensify-card/Statements.md @@ -2,4 +2,4 @@ title: Statements description: Statements --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/expensify-card/The-Reports-Page.md b/docs/articles/expensify-classic/expensify-card/The-Reports-Page.md index 37da613e750a..e72abfcad51a 100644 --- a/docs/articles/expensify-classic/expensify-card/The-Reports-Page.md +++ b/docs/articles/expensify-classic/expensify-card/The-Reports-Page.md @@ -2,4 +2,4 @@ title: The Reports Page description: The Reports Page --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/exports/Custom-Templates.md b/docs/articles/expensify-classic/exports/Custom-Templates.md index 5dcfe58b09f5..e01450a730cf 100644 --- a/docs/articles/expensify-classic/exports/Custom-Templates.md +++ b/docs/articles/expensify-classic/exports/Custom-Templates.md @@ -2,4 +2,4 @@ title: Custom Templates description: Custom Templates --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/exports/Default-Export-Templates.md b/docs/articles/expensify-classic/exports/Default-Export-Templates.md index 4dcb624698af..7650cff38946 100644 --- a/docs/articles/expensify-classic/exports/Default-Export-Templates.md +++ b/docs/articles/expensify-classic/exports/Default-Export-Templates.md @@ -2,4 +2,4 @@ title: Default Export Templates description: Default Export Templates --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/exports/The-Reports-Page.md b/docs/articles/expensify-classic/exports/The-Reports-Page.md index 37da613e750a..e72abfcad51a 100644 --- a/docs/articles/expensify-classic/exports/The-Reports-Page.md +++ b/docs/articles/expensify-classic/exports/The-Reports-Page.md @@ -2,4 +2,4 @@ title: The Reports Page description: The Reports Page --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/Mileage.md b/docs/articles/expensify-classic/get-paid-back/Mileage.md index 381bc28626f9..248e80e1c115 100644 --- a/docs/articles/expensify-classic/get-paid-back/Mileage.md +++ b/docs/articles/expensify-classic/get-paid-back/Mileage.md @@ -2,4 +2,4 @@ title: Mileage description: Mileage --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/Per-Diem.md b/docs/articles/expensify-classic/get-paid-back/Per-Diem.md index e5a57fc62bdf..780e5969c441 100644 --- a/docs/articles/expensify-classic/get-paid-back/Per-Diem.md +++ b/docs/articles/expensify-classic/get-paid-back/Per-Diem.md @@ -2,4 +2,4 @@ title: Per Diem description: Per Diem --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/Third-Party-Payments.md b/docs/articles/expensify-classic/get-paid-back/Third-Party-Payments.md index d472e54778e1..a8cddcdfdd42 100644 --- a/docs/articles/expensify-classic/get-paid-back/Third-Party-Payments.md +++ b/docs/articles/expensify-classic/get-paid-back/Third-Party-Payments.md @@ -2,4 +2,4 @@ title: Third Party Payments description: Third Party Payments --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/Trips.md b/docs/articles/expensify-classic/get-paid-back/Trips.md index 3499865c4ee9..7efba1875a90 100644 --- a/docs/articles/expensify-classic/get-paid-back/Trips.md +++ b/docs/articles/expensify-classic/get-paid-back/Trips.md @@ -2,4 +2,4 @@ title: Trips description: Trips --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md b/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md index 224b622cec3f..36e0a2194d24 100644 --- a/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md +++ b/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md @@ -2,4 +2,4 @@ title: Apply Tax description: Apply Tax --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md b/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md index 8f4d035e1fe7..8323be7b8e3f 100644 --- a/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md +++ b/docs/articles/expensify-classic/get-paid-back/expenses/Create-Expenses.md @@ -2,4 +2,4 @@ title: Create Expenses description: Create Expenses --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md b/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md index c628244c9b2e..e7705a32f215 100644 --- a/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md +++ b/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md @@ -2,4 +2,4 @@ title: Merge Expenses description: Merge Expenses --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md b/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md index 2091b5f3e7f0..b71fd1a3c8bf 100644 --- a/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md +++ b/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md @@ -2,4 +2,4 @@ title: Upload Receipts description: Upload Receipts --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md b/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md index e6cc65290e73..fb4f756b2820 100644 --- a/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md +++ b/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md @@ -2,4 +2,4 @@ title: Create a Report description: Create a Report --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/get-paid-back/reports/Reimbursements.md b/docs/articles/expensify-classic/get-paid-back/reports/Reimbursements.md index 91c4459d2ebd..c2cc25b32373 100644 --- a/docs/articles/expensify-classic/get-paid-back/reports/Reimbursements.md +++ b/docs/articles/expensify-classic/get-paid-back/reports/Reimbursements.md @@ -2,4 +2,4 @@ title: Reimbursements description: Reimbursements --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Best-Practices.md b/docs/articles/expensify-classic/getting-started/Best-Practices.md index 16b284ae60df..b02ea9d68fe6 100644 --- a/docs/articles/expensify-classic/getting-started/Best-Practices.md +++ b/docs/articles/expensify-classic/getting-started/Best-Practices.md @@ -2,4 +2,4 @@ title: Best Practices description: Best Practices --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Employees.md b/docs/articles/expensify-classic/getting-started/Employees.md index f139c40be926..6d3c2dc705e1 100644 --- a/docs/articles/expensify-classic/getting-started/Employees.md +++ b/docs/articles/expensify-classic/getting-started/Employees.md @@ -2,4 +2,4 @@ title: Employees description: Employees --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Individual-Users.md b/docs/articles/expensify-classic/getting-started/Individual-Users.md index 2e152ea515d7..de7a527df010 100644 --- a/docs/articles/expensify-classic/getting-started/Individual-Users.md +++ b/docs/articles/expensify-classic/getting-started/Individual-Users.md @@ -2,4 +2,4 @@ title: Individual Users description: Individual Users --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Invite-Employees.md b/docs/articles/expensify-classic/getting-started/Invite-Employees.md index 5cdb8eb086b0..73dc7b8274f0 100644 --- a/docs/articles/expensify-classic/getting-started/Invite-Employees.md +++ b/docs/articles/expensify-classic/getting-started/Invite-Employees.md @@ -2,4 +2,4 @@ title: Invite Employees description: Invite Employees --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Plan-Types.md b/docs/articles/expensify-classic/getting-started/Plan-Types.md index 7bb725a1aa35..f0323947ee12 100644 --- a/docs/articles/expensify-classic/getting-started/Plan-Types.md +++ b/docs/articles/expensify-classic/getting-started/Plan-Types.md @@ -2,4 +2,4 @@ title: Plan-Types description: Plan-Types --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Policy-Admins.md b/docs/articles/expensify-classic/getting-started/Policy-Admins.md index 91d56b0c4f71..484350f101a5 100644 --- a/docs/articles/expensify-classic/getting-started/Policy-Admins.md +++ b/docs/articles/expensify-classic/getting-started/Policy-Admins.md @@ -2,4 +2,4 @@ title: Policy Admins description: Policy Admins --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Security.md b/docs/articles/expensify-classic/getting-started/Security.md index 41451e2ba958..5a0036e3e161 100644 --- a/docs/articles/expensify-classic/getting-started/Security.md +++ b/docs/articles/expensify-classic/getting-started/Security.md @@ -2,4 +2,4 @@ title: Security description: Security --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/Using-The-App.md b/docs/articles/expensify-classic/getting-started/Using-The-App.md index 37767ea9d78d..7fa57abbdf61 100644 --- a/docs/articles/expensify-classic/getting-started/Using-The-App.md +++ b/docs/articles/expensify-classic/getting-started/Using-The-App.md @@ -2,4 +2,4 @@ title: Using the App description: Using the App --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/getting-started/tips-and-tricks.md b/docs/articles/expensify-classic/getting-started/tips-and-tricks.md index d85c7f3a0cb9..4d9150deb4c5 100644 --- a/docs/articles/expensify-classic/getting-started/tips-and-tricks.md +++ b/docs/articles/expensify-classic/getting-started/tips-and-tricks.md @@ -2,4 +2,4 @@ title: Tips and Tricks description: Tips and Tricks --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Bill-dot-com.md b/docs/articles/expensify-classic/integrations/accounting-integrations/Bill-dot-com.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/Bill-dot-com.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/Bill-dot-com.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/FinancalForce.md b/docs/articles/expensify-classic/integrations/accounting-integrations/FinancalForce.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/FinancalForce.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/FinancalForce.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md b/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md b/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md b/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/hr-integrations/ADP.md b/docs/articles/expensify-classic/integrations/hr-integrations/ADP.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/hr-integrations/ADP.md +++ b/docs/articles/expensify-classic/integrations/hr-integrations/ADP.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/hr-integrations/Greenhouse.md b/docs/articles/expensify-classic/integrations/hr-integrations/Greenhouse.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/hr-integrations/Greenhouse.md +++ b/docs/articles/expensify-classic/integrations/hr-integrations/Greenhouse.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/hr-integrations/Gusto.md b/docs/articles/expensify-classic/integrations/hr-integrations/Gusto.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/hr-integrations/Gusto.md +++ b/docs/articles/expensify-classic/integrations/hr-integrations/Gusto.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/hr-integrations/QuickBooks-Time.md b/docs/articles/expensify-classic/integrations/hr-integrations/QuickBooks-Time.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/hr-integrations/QuickBooks-Time.md +++ b/docs/articles/expensify-classic/integrations/hr-integrations/QuickBooks-Time.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/hr-integrations/Rippling.md b/docs/articles/expensify-classic/integrations/hr-integrations/Rippling.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/hr-integrations/Rippling.md +++ b/docs/articles/expensify-classic/integrations/hr-integrations/Rippling.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/hr-integrations/Workday.md b/docs/articles/expensify-classic/integrations/hr-integrations/Workday.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/hr-integrations/Workday.md +++ b/docs/articles/expensify-classic/integrations/hr-integrations/Workday.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/hr-integrations/Zenefits.md b/docs/articles/expensify-classic/integrations/hr-integrations/Zenefits.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/hr-integrations/Zenefits.md +++ b/docs/articles/expensify-classic/integrations/hr-integrations/Zenefits.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/other-integrations/Google-Apps-SSO.md b/docs/articles/expensify-classic/integrations/other-integrations/Google-Apps-SSO.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/other-integrations/Google-Apps-SSO.md +++ b/docs/articles/expensify-classic/integrations/other-integrations/Google-Apps-SSO.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Bolt.md b/docs/articles/expensify-classic/integrations/travel-integrations/Bolt.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Bolt.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Bolt.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Egencia.md b/docs/articles/expensify-classic/integrations/travel-integrations/Egencia.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Egencia.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Egencia.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Global-VaTax.md b/docs/articles/expensify-classic/integrations/travel-integrations/Global-VaTax.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Global-VaTax.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Global-VaTax.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Grab.md b/docs/articles/expensify-classic/integrations/travel-integrations/Grab.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Grab.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Grab.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Hotel-Tonight.md b/docs/articles/expensify-classic/integrations/travel-integrations/Hotel-Tonight.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Hotel-Tonight.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Hotel-Tonight.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Kayak.md b/docs/articles/expensify-classic/integrations/travel-integrations/Kayak.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Kayak.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Kayak.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Lyft.md b/docs/articles/expensify-classic/integrations/travel-integrations/Lyft.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Lyft.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Lyft.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/TrainLine.md b/docs/articles/expensify-classic/integrations/travel-integrations/TrainLine.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/TrainLine.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/TrainLine.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/TravelPerk.md b/docs/articles/expensify-classic/integrations/travel-integrations/TravelPerk.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/TravelPerk.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/TravelPerk.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md b/docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/TripCatcher.md b/docs/articles/expensify-classic/integrations/travel-integrations/TripCatcher.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/TripCatcher.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/TripCatcher.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md b/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md +++ b/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Adding-Users.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Adding-Users.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Adding-Users.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Adding-Users.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approval-Workflows.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approval-Workflows.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approval-Workflows.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approval-Workflows.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Approving-Reports.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/User-Roles.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md index e10e0fafb77d..e107734216f5 100644 --- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md +++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md @@ -2,7 +2,7 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! Kayak.md Lyft.md TrainLine.md TravelPerk.md Trip Actions.md TripCatcher.md Uber.md \ No newline at end of file diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Admins.md b/docs/articles/expensify-classic/policy-and-domain-settings/Admins.md index 8c1267068d6b..cea96cfe2057 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Admins.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Admins.md @@ -2,4 +2,4 @@ title: Admins description: Admins --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Categories.md b/docs/articles/expensify-classic/policy-and-domain-settings/Categories.md index 00ade2b9d04f..0db022f400d3 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Categories.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Categories.md @@ -2,4 +2,4 @@ title: Categories description: Categories --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md b/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Admins.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md b/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Domain-Members.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Domains-Overview.md b/docs/articles/expensify-classic/policy-and-domain-settings/Domains-Overview.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Domains-Overview.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Domains-Overview.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Expenses.md b/docs/articles/expensify-classic/policy-and-domain-settings/Expenses.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Expenses.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Expenses.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md b/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Overview.md b/docs/articles/expensify-classic/policy-and-domain-settings/Overview.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Overview.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Overview.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Per-Diem.md b/docs/articles/expensify-classic/policy-and-domain-settings/Per-Diem.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Per-Diem.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Per-Diem.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Reimbursement.md b/docs/articles/expensify-classic/policy-and-domain-settings/Reimbursement.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Reimbursement.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Reimbursement.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Reports.md b/docs/articles/expensify-classic/policy-and-domain-settings/Reports.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Reports.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Reports.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/SAML.md b/docs/articles/expensify-classic/policy-and-domain-settings/SAML.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/SAML.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/SAML.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Tags.md b/docs/articles/expensify-classic/policy-and-domain-settings/Tags.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Tags.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Tags.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Tax.md b/docs/articles/expensify-classic/policy-and-domain-settings/Tax.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Tax.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Tax.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Trips.md b/docs/articles/expensify-classic/policy-and-domain-settings/Trips.md index 4c91b7095a4a..3ee1c8656b4b 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Trips.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Trips.md @@ -2,4 +2,4 @@ title: Coming Soon description: Coming Soon --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/send-payments/Pay-Bills.md b/docs/articles/expensify-classic/send-payments/Pay-Bills.md index e319196eb4bd..41c0146126ba 100644 --- a/docs/articles/expensify-classic/send-payments/Pay-Bills.md +++ b/docs/articles/expensify-classic/send-payments/Pay-Bills.md @@ -2,4 +2,4 @@ title: Pay Bills description: Pay Bills --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/send-payments/Pay-Invoices.md b/docs/articles/expensify-classic/send-payments/Pay-Invoices.md index 0ea4d28a731a..e5e6799c268c 100644 --- a/docs/articles/expensify-classic/send-payments/Pay-Invoices.md +++ b/docs/articles/expensify-classic/send-payments/Pay-Invoices.md @@ -2,4 +2,4 @@ title: Pay Invoices description: Pay Invoices --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md b/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md index 6c3309310ba8..834d0b159931 100644 --- a/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md +++ b/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md @@ -2,4 +2,4 @@ title: Reimbursing Reports description: Reimbursing Reports --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md b/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md index 4b1166cc9c00..f61f26d91059 100644 --- a/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md +++ b/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md @@ -2,7 +2,7 @@ title: Third Party Payments description: Third Party Payments --- -## Resources Coming Soon! +## Resource Coming Soon! \ No newline at end of file diff --git a/docs/articles/new-expensify/get-paid-back/Request-Money.md b/docs/articles/new-expensify/get-paid-back/Request-Money.md index 55a3f3c8172e..dc6de6656cc9 100644 --- a/docs/articles/new-expensify/get-paid-back/Request-Money.md +++ b/docs/articles/new-expensify/get-paid-back/Request-Money.md @@ -2,4 +2,4 @@ title: Request Money description: Request Money --- -## Resources Coming Soon! +## Resource Coming Soon! diff --git a/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md b/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md index ed4d127d5c26..aa5f40ee4e5d 100644 --- a/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md +++ b/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md @@ -2,4 +2,4 @@ title: QuickBooks Online description: QuickBooks Online --- -## Resources Coming Soon! +## Resource Coming Soon! From 0deecc606ab79f182e09b4a2c598a5f90d54e235 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:46:26 +0000 Subject: [PATCH 156/250] fix payer name --- 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 4b7acd121d0b..dd5007b61af5 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3605,7 +3605,7 @@ function getIouReportActionDisplayMessage(reportAction) { const {amount, currency, IOUReportID} = originalMessage; const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency); const iouReport = getReport(IOUReportID); - const payerName = isExpenseReport(iouReport) ? getPolicyName(iouReport, false, getPolicyName(iouReport)) : getDisplayNameForParticipant(iouReport.managerID); + const payerName = isExpenseReport(iouReport) ? getPolicyName(iouReport) : getDisplayNameForParticipant(iouReport.managerID); let translationKey; switch (originalMessage.paymentType) { case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: From 2c27eee8891d5e45f640809958f5786377d411d2 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 22:38:37 +0530 Subject: [PATCH 157/250] use correct images --- .../account-details-expensify-classic.png | Bin 24258 -> 0 bytes .../images/account-details-new-expensify.png | Bin 14583 -> 0 bytes docs/assets/images/settings-new-dot.svg | 88 +++++++++ docs/assets/images/settings-old-dot.svg | 187 ++++++++++++++++++ 4 files changed, 275 insertions(+) delete mode 100644 docs/assets/images/account-details-expensify-classic.png delete mode 100644 docs/assets/images/account-details-new-expensify.png create mode 100644 docs/assets/images/settings-new-dot.svg create mode 100644 docs/assets/images/settings-old-dot.svg diff --git a/docs/assets/images/account-details-expensify-classic.png b/docs/assets/images/account-details-expensify-classic.png deleted file mode 100644 index 70b9b5ace2c10df0d6626c9168ecc6233e8e2f46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24258 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 From c6283ec7060318f286acd6bb9a89f379f369b883 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 23:09:03 +0530 Subject: [PATCH 161/250] add select button to platform card --- docs/_sass/_main.scss | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 79c509efd838..75922c7704f9 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -603,11 +603,25 @@ button { flex-wrap: nowrap; flex-direction: column; flex-grow: 2; + + .header { + display: flex; + align-items: center; + justify-content: space-between; + + .select-button { + display: flex; + .success { + align-items: flex-end; + font-size: 0.8em; + } + } + } } h3.title { font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; - font-size: 1.2em; + font-size: 1.4em; font-weight: normal; } @@ -623,12 +637,16 @@ button { p.description, p.url { - padding: 0 0 20px 0; margin: 0; font-weight: normal; } + p.description { + padding: 20px 0 20px 0; + } + p.url { + padding: 0; font-size: 0.8em; color: $color-gray-label; } From 6e296be8cfb4c0d1d2632056d4f5bb26ed8a7e48 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 23:09:10 +0530 Subject: [PATCH 162/250] add select button to platform card --- docs/_includes/platform-card.html | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/_includes/platform-card.html b/docs/_includes/platform-card.html index 450a306c9df6..1d341a7d331d 100644 --- a/docs/_includes/platform-card.html +++ b/docs/_includes/platform-card.html @@ -3,17 +3,22 @@
-

{{ platform.title }}

-

{{ platform.url }}

+
+
+

{{ platform.title }}

+

{{ platform.url }}

+
+
+ +
+
+

{{ platform.description }}

-
{{ platform.href }}
+ + From a69315c80a52657a75b255d28b66ada019083ed4 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 23:15:50 +0530 Subject: [PATCH 163/250] enable push to production --- .github/workflows/deployExpensifyHelp.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/deployExpensifyHelp.yml b/.github/workflows/deployExpensifyHelp.yml index 11f4897ab322..ca7345ef9462 100644 --- a/.github/workflows/deployExpensifyHelp.yml +++ b/.github/workflows/deployExpensifyHelp.yml @@ -2,6 +2,10 @@ name: Deploy ExpensifyHelp on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From 168329018c6d0cb6579adcad7bc602eb943c7a1f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 23:25:19 +0530 Subject: [PATCH 164/250] change hub font weight --- docs/_sass/_main.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 75922c7704f9..3a5be400854d 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -708,8 +708,9 @@ button { } h3.title { - font-size: 1.2em; font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; + font-size: 1.2em; + font-weight: normal; } h3.title, From 1e3e7525031aaa1aa6f2653b8b69630e12876343 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 01:19:36 +0530 Subject: [PATCH 165/250] rm whitespace --- docs/_includes/platform-card.html | 2 -- docs/_sass/_main.scss | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/_includes/platform-card.html b/docs/_includes/platform-card.html index 1d341a7d331d..7123f18a679a 100644 --- a/docs/_includes/platform-card.html +++ b/docs/_includes/platform-card.html @@ -20,5 +20,3 @@

{{ platform.title }}

mtM=rxrUy+s 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 I5*+-$0GjaWi~s-t diff --git a/docs/assets/images/settings-new-dot.svg b/docs/assets/images/settings-new-dot.svg new file mode 100644 index 000000000000..13338fc72362 --- /dev/null +++ b/docs/assets/images/settings-new-dot.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/images/settings-old-dot.svg b/docs/assets/images/settings-old-dot.svg new file mode 100644 index 000000000000..89302b65c70d --- /dev/null +++ b/docs/assets/images/settings-old-dot.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f7f2dc96f69fe79b420937cafe88b6cd723a58a3 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 22:38:44 +0530 Subject: [PATCH 158/250] use correct images --- docs/_data/_routes.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/_data/_routes.yml b/docs/_data/_routes.yml index 45703ea955ec..11218a907ec6 100644 --- a/docs/_data/_routes.yml +++ b/docs/_data/_routes.yml @@ -7,9 +7,10 @@ platforms: - href: expensify-classic title: Expensify Classic hub-title: Expensify Classic - Help & Resources - url: expensify.com - description: Your account settings will look something like this - image: /assets/images/paper-airplane.svg + url: www.expensify.com + description: >- + Your account settings will look something like this: + image: /assets/images/settings-old-dot.svg # Hubs are comprised of sections and articles. Sections contain multiple related articles, but there can be standalone articles as well hubs: @@ -77,8 +78,9 @@ platforms: title: New Expensify hub-title: New Expensify - Help & Resources url: new.expensify.com - description: Your account settings will look something like this - image: /assets/images/paper-airplane.svg + description: >- + Your account settings will look something like this: + image: /assets/images/settings-new-dot.svg hubs: - href: account-settings From e33eb7b3e4541ee399e857f404e2771e5e28cc88 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 22:39:16 +0530 Subject: [PATCH 159/250] style platform blub --- docs/_sass/_main.scss | 86 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 728785f69d05..79c509efd838 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -550,6 +550,90 @@ button { } } +.platform-card { + display: flex; + flex-wrap: nowrap; + border-radius: 16px; + padding: 28px; + font-weight: 700; + cursor: pointer; + color: $color-text; + background-color: $color-highlightBG; + + &:hover { + background-color: darken($color-highlightBG, 1%); + } + + .row { + display: flex; + flex-direction: column; + flex-basis:100%; + } + + .platform-screenshot { + display: flex; + align-items: center; + + img { + border-radius: 12px; + width: 100%; + } + } + + .right-icon { + display: flex; + align-items: center; + padding-left: 16px; + } + + .submit-button { + display: flex; + align-items: center; + margin-top: 16px; + padding-left: 0; + + @include breakpoint($breakpoint-desktop) { + margin-top: 0; + padding-left: 16px; + } + } + + .body { + display: flex; + flex-wrap: nowrap; + flex-direction: column; + flex-grow: 2; + } + + h3.title { + font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; + font-size: 1.2em; + font-weight: normal; + } + + h3.title, + h4.title { + padding: 0; + margin: 0; + + &.with-margin { + margin: 0 0 4px 0; + } + } + + p.description, + p.url { + padding: 0 0 20px 0; + margin: 0; + font-weight: normal; + } + + p.url { + font-size: 0.8em; + color: $color-gray-label; + } +} + .hub-card { display: flex; flex-wrap: nowrap; @@ -620,8 +704,6 @@ button { } } - - p.description { padding: 0; margin: 0; From 661d633520f2c80f56fed9b4a8684c9414703c3a Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Fri, 22 Sep 2023 22:39:35 +0530 Subject: [PATCH 160/250] use platform style --- docs/_includes/platform-card.html | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/_includes/platform-card.html b/docs/_includes/platform-card.html index 7e798094e7cc..450a306c9df6 100644 --- a/docs/_includes/platform-card.html +++ b/docs/_includes/platform-card.html @@ -1,14 +1,19 @@ {% assign platform = site.data.routes.platforms | where: "href", include.href | first %} - +

- - diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 3a5be400854d..fcecc0846ce7 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -533,8 +533,6 @@ button { } } - - p.description { padding: 0; margin: 0; @@ -710,7 +708,7 @@ button { h3.title { font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; font-size: 1.2em; - font-weight: normal; + font-weight: normala; } h3.title, From 72cd4f7b41154fffbc0f784ccd2f71da34d826c0 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 01:20:44 +0530 Subject: [PATCH 166/250] fix typo --- docs/_sass/_main.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index fcecc0846ce7..b4cb8a1f3ac5 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -708,7 +708,7 @@ button { h3.title { font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif; font-size: 1.2em; - font-weight: normala; + font-weight: normal; } h3.title, From d8af4935076230ce99bc84b02d1dfd5ad4877362 Mon Sep 17 00:00:00 2001 From: akamefi202 Date: Fri, 22 Sep 2023 16:22:01 -0400 Subject: [PATCH 167/250] update mention suggestion --- src/pages/home/report/ReportActionCompose/SuggestionMention.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js index a76025b67b1e..08afc8179626 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js @@ -199,7 +199,7 @@ function SuggestionMention({ } const leftString = value.substring(0, indexOfLastNonWhitespaceCharAfterTheCursor); - const words = leftString.split(CONST.REGEX.SPECIAL_CHAR_OR_EMOJI); + const words = leftString.split(CONST.REGEX.SPACE_OR_EMOJI); const lastWord = _.last(words); let atSignIndex; From 9c823823afc38b8e6505a5502ff051e3244b33ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Sat, 23 Sep 2023 10:57:56 +0200 Subject: [PATCH 168/250] apply suggestions --- src/libs/SidebarUtils.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 0366a6820970..c87ea042e580 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -71,6 +71,16 @@ function isSidebarLoadedReady() { return sidebarIsReadyPromise; } +function compareStringDates(stringA, stringB) { + if (stringA < stringB) { + return -1; + } + if (stringA > stringB) { + return 1; + } + return 0; +} + function setIsSidebarLoadedReady() { resolveSidebarIsReadyPromise(); } @@ -184,21 +194,13 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p pinnedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); draftReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); - const compareStringDates = (stringA, stringB) => { - if (stringA < stringB) { - return 1; - } - if (stringA > stringB) { - return -1; - } - return 0; - }; + if (isInDefaultMode) { nonArchivedReports.sort( - (a, b) => compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()), + (a, b) => compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()), ); // For archived reports ensure that most recent reports are at the top by reversing the order - archivedReports.sort((a, b) => compareStringDates(a.lastVisibleActionCreated, b.lastVisibleActionCreated)); + archivedReports.sort((a, b) => compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated)); } else { nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); archivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase())); From 834f927457211ece3d9c8e4f0d96de8162517ca7 Mon Sep 17 00:00:00 2001 From: c3024 Date: Sat, 23 Sep 2023 15:42:50 +0530 Subject: [PATCH 169/250] linkkey --- src/pages/workspace/WorkspaceNewRoomPage.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index c031fa8e6073..e6c2d09f6069 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -7,7 +7,6 @@ import withNavigationFocus, {withNavigationFocusPropTypes} from '../../component import * as Report from '../../libs/actions/Report'; import * as App from '../../libs/actions/App'; import useLocalize from '../../hooks/useLocalize'; -import useWindowDimensions from '../../hooks/useWindowDimensions'; import styles from '../../styles/styles'; import RoomNameInput from '../../components/RoomNameInput'; import Picker from '../../components/Picker'; @@ -71,7 +70,6 @@ const defaultProps = { function WorkspaceNewRoomPage(props) { const {translate} = useLocalize(); - const {isSmallScreenWidth} = useWindowDimensions(); const [visibility, setVisibility] = useState(CONST.REPORT.VISIBILITY.RESTRICTED); const [policyID, setPolicyID] = useState(null); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); @@ -151,7 +149,7 @@ function WorkspaceNewRoomPage(props) { shouldShow={!Permissions.canUsePolicyRooms(props.betas) || !workspaceOptions.length} shouldShowBackButton={false} linkKey="workspace.emptyWorkspace.title" - onLinkPress={() => App.createWorkspaceAndNavigateToIt('', false, '', false, !isSmallScreenWidth)} + onLinkPress={() => App.createWorkspaceAndNavigateToIt('', false, '', false, false)} > Date: Sat, 23 Sep 2023 19:14:20 +0530 Subject: [PATCH 170/250] show getting started at top --- docs/_data/_routes.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/_data/_routes.yml b/docs/_data/_routes.yml index 11218a907ec6..5666514b419e 100644 --- a/docs/_data/_routes.yml +++ b/docs/_data/_routes.yml @@ -14,6 +14,11 @@ platforms: # Hubs are comprised of sections and articles. Sections contain multiple related articles, but there can be standalone articles as well hubs: + - href: getting-started + title: Getting Started + icon: /assets/images/accounting.svg + description: From setting up your account to ensuring you get the most out of Expensify’s suite of features, click here to get started on streamlining your expense management journey. + - href: account-settings title: Account Settings icon: /assets/images/gears.svg @@ -49,11 +54,6 @@ platforms: icon: /assets/images/money-into-wallet.svg description: Whether you submit an expense report or an invoice, find out here how to ensure a smooth and timely payback process every time. - - href: getting-started - title: Getting Started - icon: /assets/images/accounting.svg - description: From setting up your account to ensuring you get the most out of Expensify’s suite of features, click here to get started on streamlining your expense management journey. - - href: integrations title: Integrations icon: /assets/images/workflow.svg @@ -83,6 +83,11 @@ platforms: image: /assets/images/settings-new-dot.svg hubs: + - href: getting-started + title: Getting Started + icon: /assets/images/accounting.svg + description: From setting up your account to ensuring you get the most out of Expensify’s suite of features, click here to get started on streamlining your expense management journey. + - href: account-settings title: Account Settings icon: /assets/images/gears.svg @@ -118,11 +123,6 @@ platforms: icon: /assets/images/money-into-wallet.svg description: Whether you submit an expense report or an invoice, find out here how to ensure a smooth and timely payback process every time. - - href: getting-started - title: Getting Started - icon: /assets/images/accounting.svg - description: From setting up your account to ensuring you get the most out of Expensify’s suite of features, click here to get started on streamlining your expense management journey. - - href: integrations title: Integrations icon: /assets/images/workflow.svg From db5e5069309382cae0ec68aabdbf602b5a3e3754 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 20:26:09 +0530 Subject: [PATCH 171/250] add a new page for sections --- .../{account-settings.html => account-settings/index.html} | 0 .../hubs/bank-accounts-and-credit-cards/company-cards.html | 6 ++++++ .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../hubs/{expensify-card.html => expensify-card/index.html} | 0 .../hubs/{exports.html => exports/index.html} | 0 .../hubs/{get-paid-back.html => get-paid-back/index.html} | 0 .../{getting-started.html => getting-started/index.html} | 0 .../hubs/{integrations.html => integrations/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../hubs/{send-payments.html => send-payments/index.html} | 0 13 files changed, 6 insertions(+) rename docs/expensify-classic/hubs/{account-settings.html => account-settings/index.html} (100%) create mode 100644 docs/expensify-classic/hubs/bank-accounts-and-credit-cards/company-cards.html rename docs/expensify-classic/hubs/{bank-accounts-and-credit-cards.html => bank-accounts-and-credit-cards/index.html} (100%) rename docs/expensify-classic/hubs/{billing-and-subscriptions.html => billing-and-subscriptions/index.html} (100%) rename docs/expensify-classic/hubs/{expense-and-report-features.html => expense-and-report-features/index.html} (100%) rename docs/expensify-classic/hubs/{expensify-card.html => expensify-card/index.html} (100%) rename docs/expensify-classic/hubs/{exports.html => exports/index.html} (100%) rename docs/expensify-classic/hubs/{get-paid-back.html => get-paid-back/index.html} (100%) rename docs/expensify-classic/hubs/{getting-started.html => getting-started/index.html} (100%) rename docs/expensify-classic/hubs/{integrations.html => integrations/index.html} (100%) rename docs/expensify-classic/hubs/{manage-employees-and-report-approvals.html => manage-employees-and-report-approvals/index.html} (100%) rename docs/expensify-classic/hubs/{policy-and-domain-settings.html => policy-and-domain-settings/index.html} (100%) rename docs/expensify-classic/hubs/{send-payments.html => send-payments/index.html} (100%) diff --git a/docs/expensify-classic/hubs/account-settings.html b/docs/expensify-classic/hubs/account-settings/index.html similarity index 100% rename from docs/expensify-classic/hubs/account-settings.html rename to docs/expensify-classic/hubs/account-settings/index.html diff --git a/docs/expensify-classic/hubs/bank-accounts-and-credit-cards/company-cards.html b/docs/expensify-classic/hubs/bank-accounts-and-credit-cards/company-cards.html new file mode 100644 index 000000000000..ddaab970c790 --- /dev/null +++ b/docs/expensify-classic/hubs/bank-accounts-and-credit-cards/company-cards.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Company Cards +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/bank-accounts-and-credit-cards.html b/docs/expensify-classic/hubs/bank-accounts-and-credit-cards/index.html similarity index 100% rename from docs/expensify-classic/hubs/bank-accounts-and-credit-cards.html rename to docs/expensify-classic/hubs/bank-accounts-and-credit-cards/index.html diff --git a/docs/expensify-classic/hubs/billing-and-subscriptions.html b/docs/expensify-classic/hubs/billing-and-subscriptions/index.html similarity index 100% rename from docs/expensify-classic/hubs/billing-and-subscriptions.html rename to docs/expensify-classic/hubs/billing-and-subscriptions/index.html diff --git a/docs/expensify-classic/hubs/expense-and-report-features.html b/docs/expensify-classic/hubs/expense-and-report-features/index.html similarity index 100% rename from docs/expensify-classic/hubs/expense-and-report-features.html rename to docs/expensify-classic/hubs/expense-and-report-features/index.html diff --git a/docs/expensify-classic/hubs/expensify-card.html b/docs/expensify-classic/hubs/expensify-card/index.html similarity index 100% rename from docs/expensify-classic/hubs/expensify-card.html rename to docs/expensify-classic/hubs/expensify-card/index.html diff --git a/docs/expensify-classic/hubs/exports.html b/docs/expensify-classic/hubs/exports/index.html similarity index 100% rename from docs/expensify-classic/hubs/exports.html rename to docs/expensify-classic/hubs/exports/index.html diff --git a/docs/expensify-classic/hubs/get-paid-back.html b/docs/expensify-classic/hubs/get-paid-back/index.html similarity index 100% rename from docs/expensify-classic/hubs/get-paid-back.html rename to docs/expensify-classic/hubs/get-paid-back/index.html diff --git a/docs/expensify-classic/hubs/getting-started.html b/docs/expensify-classic/hubs/getting-started/index.html similarity index 100% rename from docs/expensify-classic/hubs/getting-started.html rename to docs/expensify-classic/hubs/getting-started/index.html diff --git a/docs/expensify-classic/hubs/integrations.html b/docs/expensify-classic/hubs/integrations/index.html similarity index 100% rename from docs/expensify-classic/hubs/integrations.html rename to docs/expensify-classic/hubs/integrations/index.html diff --git a/docs/expensify-classic/hubs/manage-employees-and-report-approvals.html b/docs/expensify-classic/hubs/manage-employees-and-report-approvals/index.html similarity index 100% rename from docs/expensify-classic/hubs/manage-employees-and-report-approvals.html rename to docs/expensify-classic/hubs/manage-employees-and-report-approvals/index.html diff --git a/docs/expensify-classic/hubs/policy-and-domain-settings.html b/docs/expensify-classic/hubs/policy-and-domain-settings/index.html similarity index 100% rename from docs/expensify-classic/hubs/policy-and-domain-settings.html rename to docs/expensify-classic/hubs/policy-and-domain-settings/index.html diff --git a/docs/expensify-classic/hubs/send-payments.html b/docs/expensify-classic/hubs/send-payments/index.html similarity index 100% rename from docs/expensify-classic/hubs/send-payments.html rename to docs/expensify-classic/hubs/send-payments/index.html From 3b760cfe403a2141177194986af086c816fe1b98 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 20:26:29 +0530 Subject: [PATCH 172/250] add a new page for sections --- .../hubs/{account-settings.html => account-settings/index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../index.html} | 0 .../hubs/{expensify-card.html => expensify-card/index.html} | 0 docs/new-expensify/hubs/{exports.html => exports/index.html} | 0 .../hubs/{get-paid-back.html => get-paid-back/index.html} | 0 .../hubs/{getting-started.html => getting-started/index.html} | 0 .../hubs/{integrations.html => integrations/index.html} | 0 .../index.html} | 0 .../hubs/{send-payments.html => send-payments/index.html} | 0 .../index.html} | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename docs/new-expensify/hubs/{account-settings.html => account-settings/index.html} (100%) rename docs/new-expensify/hubs/{bank-accounts-and-credit-cards.html => bank-accounts-and-credit-cards/index.html} (100%) rename docs/new-expensify/hubs/{billing-and-plan-types.html => billing-and-plan-types/index.html} (100%) rename docs/new-expensify/hubs/{expense-and-report-features.html => expense-and-report-features/index.html} (100%) rename docs/new-expensify/hubs/{expensify-card.html => expensify-card/index.html} (100%) rename docs/new-expensify/hubs/{exports.html => exports/index.html} (100%) rename docs/new-expensify/hubs/{get-paid-back.html => get-paid-back/index.html} (100%) rename docs/new-expensify/hubs/{getting-started.html => getting-started/index.html} (100%) rename docs/new-expensify/hubs/{integrations.html => integrations/index.html} (100%) rename docs/new-expensify/hubs/{manage-employees-and-report-approvals.html => manage-employees-and-report-approvals/index.html} (100%) rename docs/new-expensify/hubs/{send-payments.html => send-payments/index.html} (100%) rename docs/new-expensify/hubs/{workspace-and-domain-settings.html => workspace-and-domain-settings/index.html} (100%) diff --git a/docs/new-expensify/hubs/account-settings.html b/docs/new-expensify/hubs/account-settings/index.html similarity index 100% rename from docs/new-expensify/hubs/account-settings.html rename to docs/new-expensify/hubs/account-settings/index.html diff --git a/docs/new-expensify/hubs/bank-accounts-and-credit-cards.html b/docs/new-expensify/hubs/bank-accounts-and-credit-cards/index.html similarity index 100% rename from docs/new-expensify/hubs/bank-accounts-and-credit-cards.html rename to docs/new-expensify/hubs/bank-accounts-and-credit-cards/index.html diff --git a/docs/new-expensify/hubs/billing-and-plan-types.html b/docs/new-expensify/hubs/billing-and-plan-types/index.html similarity index 100% rename from docs/new-expensify/hubs/billing-and-plan-types.html rename to docs/new-expensify/hubs/billing-and-plan-types/index.html diff --git a/docs/new-expensify/hubs/expense-and-report-features.html b/docs/new-expensify/hubs/expense-and-report-features/index.html similarity index 100% rename from docs/new-expensify/hubs/expense-and-report-features.html rename to docs/new-expensify/hubs/expense-and-report-features/index.html diff --git a/docs/new-expensify/hubs/expensify-card.html b/docs/new-expensify/hubs/expensify-card/index.html similarity index 100% rename from docs/new-expensify/hubs/expensify-card.html rename to docs/new-expensify/hubs/expensify-card/index.html diff --git a/docs/new-expensify/hubs/exports.html b/docs/new-expensify/hubs/exports/index.html similarity index 100% rename from docs/new-expensify/hubs/exports.html rename to docs/new-expensify/hubs/exports/index.html diff --git a/docs/new-expensify/hubs/get-paid-back.html b/docs/new-expensify/hubs/get-paid-back/index.html similarity index 100% rename from docs/new-expensify/hubs/get-paid-back.html rename to docs/new-expensify/hubs/get-paid-back/index.html diff --git a/docs/new-expensify/hubs/getting-started.html b/docs/new-expensify/hubs/getting-started/index.html similarity index 100% rename from docs/new-expensify/hubs/getting-started.html rename to docs/new-expensify/hubs/getting-started/index.html diff --git a/docs/new-expensify/hubs/integrations.html b/docs/new-expensify/hubs/integrations/index.html similarity index 100% rename from docs/new-expensify/hubs/integrations.html rename to docs/new-expensify/hubs/integrations/index.html diff --git a/docs/new-expensify/hubs/manage-employees-and-report-approvals.html b/docs/new-expensify/hubs/manage-employees-and-report-approvals/index.html similarity index 100% rename from docs/new-expensify/hubs/manage-employees-and-report-approvals.html rename to docs/new-expensify/hubs/manage-employees-and-report-approvals/index.html diff --git a/docs/new-expensify/hubs/send-payments.html b/docs/new-expensify/hubs/send-payments/index.html similarity index 100% rename from docs/new-expensify/hubs/send-payments.html rename to docs/new-expensify/hubs/send-payments/index.html diff --git a/docs/new-expensify/hubs/workspace-and-domain-settings.html b/docs/new-expensify/hubs/workspace-and-domain-settings/index.html similarity index 100% rename from docs/new-expensify/hubs/workspace-and-domain-settings.html rename to docs/new-expensify/hubs/workspace-and-domain-settings/index.html From 5858fe04ab95b34cecee7d6b9e73e094fb950cb8 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 20:26:49 +0530 Subject: [PATCH 173/250] add section card --- docs/_includes/section-card.html | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/_includes/section-card.html diff --git a/docs/_includes/section-card.html b/docs/_includes/section-card.html new file mode 100644 index 000000000000..9500983d4d28 --- /dev/null +++ b/docs/_includes/section-card.html @@ -0,0 +1,8 @@ + +
+

{{ include.title }}

+
+
+ +
+
From f91ca7df4dd05680f0210dab1ef61b52a66b1f27 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 20:27:06 +0530 Subject: [PATCH 174/250] add section page --- docs/_includes/section.html | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/_includes/section.html diff --git a/docs/_includes/section.html b/docs/_includes/section.html new file mode 100644 index 000000000000..786e7d997462 --- /dev/null +++ b/docs/_includes/section.html @@ -0,0 +1,23 @@ +{% assign urlArray = page.url | replace: '/', ' ' | split: " " %} + +{% assign activePlatform = urlArray[0] %} +{% assign platform = site.data.routes.platforms | where: "href", activePlatform | first %} + +{% assign activeHub = urlArray[2] %} +{% assign hub = platform.hubs | where: "href", activeHub | first %} + +{% assign activeSection = urlArray[3] | remove: ".html" %} +{% assign section = hub.sections | where: "href", activeSection | first %} + +

+ {{ section.title }} +

+ +
+
+ {% for article in section.articles %} + {% assign article_href = section.href | append: '/' | append: article.href %} + {% include article-card.html hub=hub.href href=article_href title=article.title platform=activePlatform %} + {% endfor %} +
+
From 2ade03a567701a5503b296e3c65066f9eb3fb7ad Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 20:27:26 +0530 Subject: [PATCH 175/250] dont show articles inside a section on hub page --- docs/_includes/hub.html | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/docs/_includes/hub.html b/docs/_includes/hub.html index 6b0b0e590b19..75b3617cc89e 100644 --- a/docs/_includes/hub.html +++ b/docs/_includes/hub.html @@ -22,17 +22,12 @@

{% endif %} -{% for section in hub.sections %} -
-

- {{ section.title }} -

- -
- {% for article in section.articles %} - {% assign article_href = section.href | append: '/' | append: article.href %} - {% include article-card.html hub=hub.href href=article_href title=article.title platform=activePlatform %} +{% if hub.sections %} +
+
+ {% for section in hub.sections %} + {% include section-card.html platform=activePlatform hub=hub.href section=section.href title=section.title %} {% endfor %} -
-
-{% endfor %} + +

+{% endif %} \ No newline at end of file From 7592d58e2206561f3b422c65e5ec7ba21bd2b620 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 20:37:02 +0530 Subject: [PATCH 176/250] add exisiting sections --- docs/expensify-classic/hubs/get-paid-back/expenses.html | 6 ++++++ docs/expensify-classic/hubs/get-paid-back/reports.html | 6 ++++++ .../hubs/getting-started/approved-accountants.html | 6 ++++++ docs/expensify-classic/hubs/getting-started/playbooks.html | 6 ++++++ docs/expensify-classic/hubs/getting-started/support.html | 6 ++++++ .../hubs/getting-started/tips-and-tricks.html | 6 ++++++ .../hubs/integrations/accounting-integrations.html | 6 ++++++ .../hubs/integrations/hr-integrations.html | 6 ++++++ .../hubs/integrations/other-integrations.html | 6 ++++++ .../hubs/integrations/travel-integrations.html | 6 ++++++ 10 files changed, 60 insertions(+) create mode 100644 docs/expensify-classic/hubs/get-paid-back/expenses.html create mode 100644 docs/expensify-classic/hubs/get-paid-back/reports.html create mode 100644 docs/expensify-classic/hubs/getting-started/approved-accountants.html create mode 100644 docs/expensify-classic/hubs/getting-started/playbooks.html create mode 100644 docs/expensify-classic/hubs/getting-started/support.html create mode 100644 docs/expensify-classic/hubs/getting-started/tips-and-tricks.html create mode 100644 docs/expensify-classic/hubs/integrations/accounting-integrations.html create mode 100644 docs/expensify-classic/hubs/integrations/hr-integrations.html create mode 100644 docs/expensify-classic/hubs/integrations/other-integrations.html create mode 100644 docs/expensify-classic/hubs/integrations/travel-integrations.html diff --git a/docs/expensify-classic/hubs/get-paid-back/expenses.html b/docs/expensify-classic/hubs/get-paid-back/expenses.html new file mode 100644 index 000000000000..4a2490ff5b9f --- /dev/null +++ b/docs/expensify-classic/hubs/get-paid-back/expenses.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Expenses +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/get-paid-back/reports.html b/docs/expensify-classic/hubs/get-paid-back/reports.html new file mode 100644 index 000000000000..f15cd01635c0 --- /dev/null +++ b/docs/expensify-classic/hubs/get-paid-back/reports.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Reports +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/getting-started/approved-accountants.html b/docs/expensify-classic/hubs/getting-started/approved-accountants.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/expensify-classic/hubs/getting-started/approved-accountants.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/getting-started/playbooks.html b/docs/expensify-classic/hubs/getting-started/playbooks.html new file mode 100644 index 000000000000..bb78d574df7e --- /dev/null +++ b/docs/expensify-classic/hubs/getting-started/playbooks.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Playbooks +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/getting-started/support.html b/docs/expensify-classic/hubs/getting-started/support.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/expensify-classic/hubs/getting-started/support.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/getting-started/tips-and-tricks.html b/docs/expensify-classic/hubs/getting-started/tips-and-tricks.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/expensify-classic/hubs/getting-started/tips-and-tricks.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/integrations/accounting-integrations.html b/docs/expensify-classic/hubs/integrations/accounting-integrations.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/expensify-classic/hubs/integrations/accounting-integrations.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/integrations/hr-integrations.html b/docs/expensify-classic/hubs/integrations/hr-integrations.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/expensify-classic/hubs/integrations/hr-integrations.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/integrations/other-integrations.html b/docs/expensify-classic/hubs/integrations/other-integrations.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/expensify-classic/hubs/integrations/other-integrations.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} diff --git a/docs/expensify-classic/hubs/integrations/travel-integrations.html b/docs/expensify-classic/hubs/integrations/travel-integrations.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/expensify-classic/hubs/integrations/travel-integrations.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} From 9c40f627017bc1349aa2c58dc1c0fefad0f8843f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 20:37:13 +0530 Subject: [PATCH 177/250] add exisiting sections --- docs/new-expensify/hubs/getting-started/chat.html | 6 ++++++ .../hubs/integrations/account-integrations.html | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 docs/new-expensify/hubs/getting-started/chat.html create mode 100644 docs/new-expensify/hubs/integrations/account-integrations.html diff --git a/docs/new-expensify/hubs/getting-started/chat.html b/docs/new-expensify/hubs/getting-started/chat.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/new-expensify/hubs/getting-started/chat.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} diff --git a/docs/new-expensify/hubs/integrations/account-integrations.html b/docs/new-expensify/hubs/integrations/account-integrations.html new file mode 100644 index 000000000000..1d311ff3c67c --- /dev/null +++ b/docs/new-expensify/hubs/integrations/account-integrations.html @@ -0,0 +1,6 @@ +--- +layout: default +title: Support +--- + +{% include section.html %} From db8a6a30f054132a3aafcdd87bfded044ca28d2a Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 21:00:58 +0530 Subject: [PATCH 178/250] fix: lhn for section --- docs/_includes/lhn-template.html | 37 ++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/docs/_includes/lhn-template.html b/docs/_includes/lhn-template.html index 015c8211e5b2..082948dfb32c 100644 --- a/docs/_includes/lhn-template.html +++ b/docs/_includes/lhn-template.html @@ -1,5 +1,13 @@ -{% assign activePlatform = page.url | replace:'/',' ' | truncatewords: 1 | remove:'...' %} -{% assign activeHub = page.url | remove: activePlatform | remove: "/hubs/" | remove: "/" | remove: ".html" %} +{% assign urlArray = page.url | replace: '/', ' ' | split: " " %} + +{% assign activePlatform = urlArray[0] %} +{% assign platform = site.data.routes.platforms | where: "href", activePlatform | first %} + +{% assign activeHub = urlArray[2] %} +{% assign hub = platform.hubs | where: "href", activeHub | first %} + +{% assign activeSection = urlArray[3] | remove: ".html" %} +{% assign section = hub.sections | where: "href", activeSection | first %}
  • - {{ section.title }} -
      - {% for article in section.articles %} - {% assign article_href = section.href | append: '/' | append: article.href %} - {% include lhn-article-link.html platform=activePlatform hub=hub.href href=article_href title=article.title %} - {% endfor %} -
    + {% if section.href == activeSection %} + + + {{ section.title }} + +
      + {% for article in section.articles %} + {% assign article_href = section.href | append: '/' | append: article.href %} + {% include lhn-article-link.html platform=activePlatform hub=hub.href href=article_href title=article.title %} + {% endfor %} +
    + {% else %} + + + {{ section.title }} + + {% endif %} +
  • {% endfor %}
From f84959f61fb53ddc6f0afe443323c3a7797c1c7e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 21:06:54 +0530 Subject: [PATCH 179/250] show sections before articles --- docs/_includes/hub.html | 20 ++++++++++---------- docs/_includes/lhn-template.html | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/_includes/hub.html b/docs/_includes/hub.html index 75b3617cc89e..be8b8a8d0385 100644 --- a/docs/_includes/hub.html +++ b/docs/_includes/hub.html @@ -12,16 +12,6 @@

{{ hub.description }}

-{% if hub.articles %} -
-
- {% for article in hub.articles %} - {% include article-card.html hub=hub.href href=article.href title=article.title platform=activePlatform %} - {% endfor %} -
-
-{% endif %} - {% if hub.sections %}
@@ -30,4 +20,14 @@

{% endfor %}

+{% endif %} + +{% if hub.articles %} +
+
+ {% for article in hub.articles %} + {% include article-card.html hub=hub.href href=article.href title=article.title platform=activePlatform %} + {% endfor %} +
+
{% endif %} \ No newline at end of file diff --git a/docs/_includes/lhn-template.html b/docs/_includes/lhn-template.html index 082948dfb32c..bcaec3c3095a 100644 --- a/docs/_includes/lhn-template.html +++ b/docs/_includes/lhn-template.html @@ -33,10 +33,6 @@ {{ hub.title }}

    - {% for article in hub.articles %} - {% include lhn-article-link.html platform=activePlatform hub=hub.href href=article.href title=article.title %} - {% endfor %} - {% for section in hub.sections %}
  • {% if section.href == activeSection %} @@ -59,6 +55,10 @@
  • {% endfor %} + + {% for article in hub.articles %} + {% include lhn-article-link.html platform=activePlatform hub=hub.href href=article.href title=article.title %} + {% endfor %}
{% else %}
  • From 0a9a15e7cd9f1e2721ee867d59b6b8e6a2bf8fc6 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 21:08:06 +0530 Subject: [PATCH 180/250] rm dupe article --- .../expensify-classic/getting-started/tips-and-tricks.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 docs/articles/expensify-classic/getting-started/tips-and-tricks.md diff --git a/docs/articles/expensify-classic/getting-started/tips-and-tricks.md b/docs/articles/expensify-classic/getting-started/tips-and-tricks.md deleted file mode 100644 index 4d9150deb4c5..000000000000 --- a/docs/articles/expensify-classic/getting-started/tips-and-tricks.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Tips and Tricks -description: Tips and Tricks ---- -## Resource Coming Soon! From d952ad17a3e93f67fc76c53ad16d6e01b68c4947 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 23 Sep 2023 21:14:37 +0530 Subject: [PATCH 181/250] feat: allow navigating to a selected link in LHN --- docs/_includes/lhn-template.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/_includes/lhn-template.html b/docs/_includes/lhn-template.html index bcaec3c3095a..456a68fc8d2f 100644 --- a/docs/_includes/lhn-template.html +++ b/docs/_includes/lhn-template.html @@ -21,17 +21,17 @@ {% for platform in site.data.routes.platforms %} {% if platform.href == activePlatform %}
  • - + {% for hub in platform.hubs %}