From ece06a0bc920c36f11f7b64aba77000f00c9947a Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 20 Nov 2023 15:03:16 +0700 Subject: [PATCH 001/304] fix: login via deeplink should open modal in request money --- src/pages/EditRequestPage.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index 194cd2855dbd..e2f2d44127ca 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -3,8 +3,10 @@ import lodashValues from 'lodash/values'; import PropTypes from 'prop-types'; import React, {useEffect, useMemo} from 'react'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import categoryPropTypes from '@components/categoryPropTypes'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import ScreenWrapper from '@components/ScreenWrapper'; import tagPropTypes from '@components/tagPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; @@ -61,6 +63,9 @@ const propTypes = { /** Transaction that stores the request data */ transaction: transactionPropTypes, + + /** Indicates whether the app is loading initial data */ + isLoadingReportData: PropTypes.bool, }; const defaultProps = { @@ -70,11 +75,18 @@ const defaultProps = { policyTags: {}, parentReportActions: {}, transaction: {}, + isLoadingReportData: true, }; -function EditRequestPage({report, route, parentReport, policyCategories, policyTags, parentReportActions, transaction}) { +function EditRequestPage({report, route, parentReport, policyCategories, policyTags, parentReportActions, transaction, isLoadingReportData}) { const parentReportActionID = lodashGet(report, 'parentReportActionID', '0'); const parentReportAction = lodashGet(parentReportActions, parentReportActionID, {}); + + const isTransactionLoadingRoute = lodashGet(transaction, 'comment.isLoading', false); + const isTransactionLoading = lodashGet(transaction, 'isLoading', false); + + const isDataLoading = isLoadingReportData || isTransactionLoading || isTransactionLoadingRoute || _.isEmpty(transaction); + const { amount: transactionAmount, currency: transactionCurrency, @@ -107,7 +119,7 @@ function EditRequestPage({report, route, parentReport, policyCategories, policyT // Decides whether to allow or disallow editing a money request useEffect(() => { // Do not dismiss the modal, when a current user can edit this property of the money request. - if (ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, parentReport.reportID, fieldToEdit)) { + if (isDataLoading || ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, parentReport.reportID, fieldToEdit)) { return; } @@ -115,7 +127,11 @@ function EditRequestPage({report, route, parentReport, policyCategories, policyT Navigation.isNavigationReady().then(() => { Navigation.dismissModal(); }); - }, [parentReportAction, parentReport.reportID, fieldToEdit]); + }, [parentReportAction, parentReport.reportID, fieldToEdit, isDataLoading]); + + if (isDataLoading) { + return ; + } // Update the transaction object and close the modal function editMoneyRequest(transactionChanges) { @@ -276,6 +292,9 @@ export default compose( report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.threadReportID}`, }, + isLoadingReportData: { + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + }, }), // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file withOnyx({ From 585b3f997921f3ee9abf7380e037079dbc111465 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 20 Nov 2023 16:57:00 +0700 Subject: [PATCH 002/304] fix: conditions --- src/pages/EditRequestPage.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index e2f2d44127ca..56dabdc137b1 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -10,14 +10,17 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import ScreenWrapper from '@components/ScreenWrapper'; import tagPropTypes from '@components/tagPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; +import withWindowDimensions from '@components/withWindowDimensions'; import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as IOU from '@userActions/IOU'; +import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -66,6 +69,9 @@ const propTypes = { /** Indicates whether the app is loading initial data */ isLoadingReportData: PropTypes.bool, + + /** Is the window width narrow, like on a mobile device */ + isSmallScreenWidth: PropTypes.bool.isRequired, }; const defaultProps = { @@ -78,9 +84,10 @@ const defaultProps = { isLoadingReportData: true, }; -function EditRequestPage({report, route, parentReport, policyCategories, policyTags, parentReportActions, transaction, isLoadingReportData}) { +function EditRequestPage({report, route, parentReport, policyCategories, policyTags, parentReportActions, transaction, isLoadingReportData, isSmallScreenWidth}) { const parentReportActionID = lodashGet(report, 'parentReportActionID', '0'); const parentReportAction = lodashGet(parentReportActions, parentReportActionID, {}); + const parentReportID = lodashGet(report, 'parentReportID', '0'); const isTransactionLoadingRoute = lodashGet(transaction, 'comment.isLoading', false); const isTransactionLoading = lodashGet(transaction, 'isLoading', false); @@ -116,6 +123,18 @@ function EditRequestPage({report, route, parentReport, policyCategories, policyT // A flag for showing the tags page const shouldShowTags = isPolicyExpenseChat && (transactionTag || OptionsListUtils.hasEnabledOptions(lodashValues(policyTagList))); + const reportAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID); + + // For small screen, we don't call openReport API when we go to a sub report page by deeplink + // So we need to call openReport here for small screen + useEffect(() => { + if (!isSmallScreenWidth || (!_.isEmpty(report) && !_.isEmpty(reportAction))) { + return; + } + Report.openReport(route.params.threadReportID); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isSmallScreenWidth, route.params.threadReportID]); + // Decides whether to allow or disallow editing a money request useEffect(() => { // Do not dismiss the modal, when a current user can edit this property of the money request. @@ -288,6 +307,7 @@ EditRequestPage.displayName = 'EditRequestPage'; EditRequestPage.propTypes = propTypes; EditRequestPage.defaultProps = defaultProps; export default compose( + withWindowDimensions, withOnyx({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.threadReportID}`, From 7adeaefd99d45e64f56bb1ffdb2bb594acbcaee5 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 20 Nov 2023 18:36:20 +0700 Subject: [PATCH 003/304] open report when transaction is empty --- src/pages/EditRequestPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index 56dabdc137b1..dbfebc300eac 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -128,7 +128,7 @@ function EditRequestPage({report, route, parentReport, policyCategories, policyT // For small screen, we don't call openReport API when we go to a sub report page by deeplink // So we need to call openReport here for small screen useEffect(() => { - if (!isSmallScreenWidth || (!_.isEmpty(report) && !_.isEmpty(reportAction))) { + if (!isSmallScreenWidth || (!_.isEmpty(report) && !_.isEmpty(reportAction) && !_.isEmpty(transaction))) { return; } Report.openReport(route.params.threadReportID); From 002c90986ddad81fa5d59fa8b4963c40b51c225c Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 3 Jan 2024 14:46:11 +0700 Subject: [PATCH 004/304] fix lint --- src/pages/EditRequestPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index dbbdbd1d1db1..c4903fc3748c 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -143,7 +143,7 @@ function EditRequestPage({report, route, parentReport, policyCategories, policyT Navigation.isNavigationReady().then(() => { Navigation.dismissModal(); }); - }, [parentReportAction, parentReport.reportID, fieldToEdit, isDataLoading]); + }, [parentReportAction, parentReport.reportID, fieldToEdit, transaction, isDataLoading]); if (isDataLoading) { return ; From 58e7687e22d32a22de13fb8a7f35cf5c1dc9137c Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 3 Jan 2024 15:41:28 +0700 Subject: [PATCH 005/304] fix lint --- src/pages/EditRequestPage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index c4903fc3748c..344a0c8a7176 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -145,10 +145,6 @@ function EditRequestPage({report, route, parentReport, policyCategories, policyT }); }, [parentReportAction, parentReport.reportID, fieldToEdit, transaction, isDataLoading]); - if (isDataLoading) { - return ; - } - // Update the transaction object and close the modal function editMoneyRequest(transactionChanges) { IOU.editMoneyRequest(transaction, report.reportID, transactionChanges); @@ -184,6 +180,10 @@ function EditRequestPage({report, route, parentReport, policyCategories, policyT [transaction, report], ); + if (isDataLoading) { + return ; + } + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DESCRIPTION) { return ( Date: Thu, 11 Jan 2024 16:23:45 +0700 Subject: [PATCH 006/304] fix lint --- src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts index 53a3b1234e2c..d6c925cd749a 100644 --- a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts +++ b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts @@ -2,12 +2,12 @@ import {useEffect} from 'react'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import usePermissions from '@hooks/usePermissions'; +import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as App from '@userActions/App'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, Report, ReportMetadata} from '@src/types/onyx'; import type {ReportScreenWrapperProps} from './ReportScreenWrapper'; -import Navigation from '../Navigation'; type ReportScreenIDSetterComponentProps = { /** Available reports that would be displayed in this navigator */ From 2c9bc81253da3936fdb343b76f02283c462578d7 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 8 Apr 2024 15:36:35 +0700 Subject: [PATCH 007/304] add support for latin characters in emoji suggestion --- src/CONST.ts | 4 ++-- src/libs/EmojiTrie.ts | 6 +++++- src/libs/GetStyledTextArray.ts | 5 ++++- src/libs/StringUtils.ts | 11 ++++++++++- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index f9229d5185b4..d70d4c5d72d9 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1680,8 +1680,8 @@ const CONST = { // Extract attachment's source from the data's html string ATTACHMENT_DATA: /(data-expensify-source|data-name)="([^"]+)"/g, - EMOJI_NAME: /:[\w+-]+:/g, - EMOJI_SUGGESTIONS: /:[a-zA-Z0-9_+-]{1,40}$/, + EMOJI_NAME: /:[\p{L}0-9_+-]+:/gu, + EMOJI_SUGGESTIONS: /:[\p{L}0-9_+-]{1,40}$/u, AFTER_FIRST_LINE_BREAK: /\n.*/g, LINE_BREAK: /\r|\n/g, CODE_2FA: /^\d{6}$/, diff --git a/src/libs/EmojiTrie.ts b/src/libs/EmojiTrie.ts index d0f0b0dcfab6..4b4994125ef2 100644 --- a/src/libs/EmojiTrie.ts +++ b/src/libs/EmojiTrie.ts @@ -2,6 +2,7 @@ import emojis, {localeEmojis} from '@assets/emojis'; import type {Emoji, HeaderEmoji, PickerEmoji} from '@assets/emojis/types'; import CONST from '@src/CONST'; import Timing from './actions/Timing'; +import StringUtils from './StringUtils'; import Trie from './Trie'; type EmojiMetaData = { @@ -33,7 +34,10 @@ function addKeywordsToTrie(trie: Trie, keywords: string[], item: keywords.forEach((keyword) => { const keywordNode = trie.search(keyword); if (!keywordNode) { - trie.add(keyword, {suggestions: [{code: item.code, types: item.types, name}]}); + const keywordWithoutAccents = StringUtils.normalizeAccents(keyword); + if (keywordWithoutAccents !== keyword) { + trie.add(keywordWithoutAccents, {suggestions: [{code: item.code, types: item.types, name}]}); + } } else { const suggestion = {code: item.code, types: item.types, name}; const suggestions = shouldPrependKeyword ? [suggestion, ...(keywordNode.metaData.suggestions ?? [])] : [...(keywordNode.metaData.suggestions ?? []), suggestion]; diff --git a/src/libs/GetStyledTextArray.ts b/src/libs/GetStyledTextArray.ts index 9bc6ccc33b4c..ffae31dc861b 100644 --- a/src/libs/GetStyledTextArray.ts +++ b/src/libs/GetStyledTextArray.ts @@ -1,4 +1,5 @@ import Str from 'expensify-common/lib/str'; +import StringUtils from './StringUtils'; type StyledText = { text: string; @@ -8,7 +9,9 @@ type StyledText = { const getStyledTextArray = (name: string, prefix: string): StyledText[] => { const texts = []; const prefixLowercase = prefix.toLowerCase(); - const prefixLocation = name.toLowerCase().search(Str.escapeForRegExp(prefixLowercase)); + const prefixLocation = StringUtils.normalizeAccents(name) + .toLowerCase() + .search(Str.escapeForRegExp(StringUtils.normalizeAccents(prefixLowercase))); if (prefixLocation === 0 && prefix.length === name.length) { texts.push({text: name, isColored: true}); diff --git a/src/libs/StringUtils.ts b/src/libs/StringUtils.ts index 2fb918c7a233..c9fa40c4da8a 100644 --- a/src/libs/StringUtils.ts +++ b/src/libs/StringUtils.ts @@ -63,6 +63,15 @@ function removeInvisibleCharacters(value: string): string { return result.trim(); } +/** + * Remove accents/diacritics + * @param text - The input string + * @returns The string with all accents/diacritics removed + */ +function normalizeAccents(text: string) { + return text.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); +} + /** * Replace all CRLF with LF * @param value - The input string @@ -72,4 +81,4 @@ function normalizeCRLF(value?: string): string | undefined { return value?.replace(/\r\n/g, '\n'); } -export default {sanitizeString, isEmptyString, removeInvisibleCharacters, normalizeCRLF}; +export default {sanitizeString, isEmptyString, removeInvisibleCharacters, normalizeAccents, normalizeCRLF}; From 723d36568be6b1c1d8604caa75f9e577e3fb4c27 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 8 Apr 2024 17:33:26 +0700 Subject: [PATCH 008/304] add original keyword to trie --- src/libs/EmojiTrie.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/EmojiTrie.ts b/src/libs/EmojiTrie.ts index 4b4994125ef2..d51881e0e5d5 100644 --- a/src/libs/EmojiTrie.ts +++ b/src/libs/EmojiTrie.ts @@ -35,9 +35,8 @@ function addKeywordsToTrie(trie: Trie, keywords: string[], item: const keywordNode = trie.search(keyword); if (!keywordNode) { const keywordWithoutAccents = StringUtils.normalizeAccents(keyword); - if (keywordWithoutAccents !== keyword) { - trie.add(keywordWithoutAccents, {suggestions: [{code: item.code, types: item.types, name}]}); - } + const keywordToAdd = keywordWithoutAccents !== keyword ? keywordWithoutAccents : keyword; + trie.add(keywordToAdd, {suggestions: [{code: item.code, types: item.types, name}]}); } else { const suggestion = {code: item.code, types: item.types, name}; const suggestions = shouldPrependKeyword ? [suggestion, ...(keywordNode.metaData.suggestions ?? [])] : [...(keywordNode.metaData.suggestions ?? []), suggestion]; From af77cbf86ff775b5db0992b43df8a6ee5e161199 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 8 Apr 2024 17:34:12 +0700 Subject: [PATCH 009/304] add original keyword to trie --- src/libs/EmojiTrie.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/EmojiTrie.ts b/src/libs/EmojiTrie.ts index d51881e0e5d5..c0fd4434c48f 100644 --- a/src/libs/EmojiTrie.ts +++ b/src/libs/EmojiTrie.ts @@ -35,8 +35,10 @@ function addKeywordsToTrie(trie: Trie, keywords: string[], item: const keywordNode = trie.search(keyword); if (!keywordNode) { const keywordWithoutAccents = StringUtils.normalizeAccents(keyword); - const keywordToAdd = keywordWithoutAccents !== keyword ? keywordWithoutAccents : keyword; - trie.add(keywordToAdd, {suggestions: [{code: item.code, types: item.types, name}]}); + if (keywordWithoutAccents !== keyword) { + trie.add(keywordWithoutAccents, {suggestions: [{code: item.code, types: item.types, name}]}); + } + trie.add(keyword, {suggestions: [{code: item.code, types: item.types, name}]}); } else { const suggestion = {code: item.code, types: item.types, name}; const suggestions = shouldPrependKeyword ? [suggestion, ...(keywordNode.metaData.suggestions ?? [])] : [...(keywordNode.metaData.suggestions ?? []), suggestion]; From c24f80ab3dbb226e9c1425a2e3e15af6c655cc11 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 10 Apr 2024 13:29:44 +0700 Subject: [PATCH 010/304] reset code change --- .../AppNavigator/ReportScreenIDSetter.ts | 11 ------- src/pages/EditRequestPage.js | 32 ++----------------- 2 files changed, 2 insertions(+), 41 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts index c0f55b53e0c0..529f0f3d31a7 100644 --- a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts +++ b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts @@ -3,11 +3,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import usePermissions from '@hooks/usePermissions'; -<<<<<<< HEAD -import Navigation from '@libs/Navigation/Navigation'; -======= import {getPolicyMembersByIdWithoutCurrentUser} from '@libs/PolicyUtils'; ->>>>>>> main import * as ReportUtils from '@libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, PolicyMembers, Report, ReportMetadata} from '@src/types/onyx'; @@ -48,13 +44,6 @@ const getLastAccessedReportID = ( policyID?: string, policyMemberAccountIDs?: number[], ): string | undefined => { - const currentRoute = Navigation.getActiveRoute(); - const {reportID} = ReportUtils.parseReportRouteParams(currentRoute); - - if (reportID) { - return reportID; - } - const lastReport = ReportUtils.findLastAccessedReport( reports, ignoreDefaultRooms, diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index 2438abdcda88..d3941dca044e 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -2,24 +2,19 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo} from 'react'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import categoryPropTypes from '@components/categoryPropTypes'; -import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import ScreenWrapper from '@components/ScreenWrapper'; import tagPropTypes from '@components/tagPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; -import withWindowDimensions from '@components/withWindowDimensions'; import compose from '@libs/compose'; import * as IOUUtils from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as IOU from '@userActions/IOU'; -import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import EditRequestReceiptPage from './EditRequestReceiptPage'; @@ -62,12 +57,6 @@ const propTypes = { /** Transaction that stores the request data */ transaction: transactionPropTypes, - - /** Indicates whether the app is loading initial data */ - isLoadingReportData: PropTypes.bool, - - /** Is the window width narrow, like on a mobile device */ - isSmallScreenWidth: PropTypes.bool.isRequired, }; const defaultProps = { @@ -77,7 +66,6 @@ const defaultProps = { policyTags: {}, parentReportActions: {}, transaction: {}, - isLoadingReportData: true, }; function EditRequestPage({report, route, policy, policyCategories, policyTags, parentReportActions, transaction}) { @@ -98,22 +86,10 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p // A flag for showing the tags page const shouldShowTags = useMemo(() => isPolicyExpenseChat && (transactionTag || OptionsListUtils.hasEnabledTags(policyTagLists)), [isPolicyExpenseChat, policyTagLists, transactionTag]); - const reportAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID); - - // For small screen, we don't call openReport API when we go to a sub report page by deeplink - // So we need to call openReport here for small screen - useEffect(() => { - if (!isSmallScreenWidth || (!_.isEmpty(report) && !_.isEmpty(reportAction) && !_.isEmpty(transaction))) { - return; - } - Report.openReport(route.params.threadReportID); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isSmallScreenWidth, route.params.threadReportID]); - // Decides whether to allow or disallow editing a money request useEffect(() => { // Do not dismiss the modal, when a current user can edit this property of the money request. - if (isDataLoading || ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, fieldToEdit)) { + if (ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, fieldToEdit)) { return; } @@ -121,7 +97,7 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p Navigation.isNavigationReady().then(() => { Navigation.dismissModal(); }); - }, [parentReportAction, fieldToEdit, transaction, isDataLoading]); + }, [parentReportAction, fieldToEdit]); const saveTag = useCallback( ({tag: newTag}) => { @@ -179,14 +155,10 @@ EditRequestPage.displayName = 'EditRequestPage'; EditRequestPage.propTypes = propTypes; EditRequestPage.defaultProps = defaultProps; export default compose( - withWindowDimensions, withOnyx({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.threadReportID}`, }, - isLoadingReportData: { - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - }, }), // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file withOnyx({ From 07a70afe9c66abcb237a256f3a02c39cfda89821 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 10 Apr 2024 14:21:15 +0700 Subject: [PATCH 011/304] Fix not found page appear when openning edit page by deeplink --- .../iou/request/step/IOURequestStepDate.tsx | 6 ++--- .../step/IOURequestStepDescription.tsx | 6 ++--- .../step/withWritableReportOrNotFound.tsx | 26 +++++++++++++++++-- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepDate.tsx b/src/pages/iou/request/step/IOURequestStepDate.tsx index 682204a4510f..2e5089657e64 100644 --- a/src/pages/iou/request/step/IOURequestStepDate.tsx +++ b/src/pages/iou/request/step/IOURequestStepDate.tsx @@ -137,8 +137,8 @@ const IOURequestStepDateWithOnyx = withOnyx; + + isLoadingApp: OnyxEntry; }; type MoneyRequestRouteName = @@ -34,10 +38,25 @@ export default function , keyof WithWritableReportOrNotFoundOnyxProps>> { // eslint-disable-next-line rulesdir/no-negated-variables function WithWritableReportOrNotFound(props: TProps, ref: ForwardedRef) { - const {report = {reportID: ''}, route} = props; + const {report = {reportID: ''}, route, isLoadingApp = true} = props; const iouTypeParamIsInvalid = !Object.values(CONST.IOU.TYPE).includes(route.params?.iouType); + const isEditing = route.params?.action === CONST.IOU.ACTION.EDIT; const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report); + useEffect(() => { + if (Boolean(report?.reportID) || !route.params.reportID) { + return; + } + + ReportActions.openReport(route.params.reportID); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + if (isEditing && isLoadingApp) { + return ; + } + if (iouTypeParamIsInvalid || !canUserPerformWriteAction) { return ; } @@ -57,6 +76,9 @@ export default function `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID ?? '0'}`, }, + isLoadingApp: { + key: ONYXKEYS.IS_LOADING_APP, + }, })(forwardRef(WithWritableReportOrNotFound)); } From 46a6c3e52188ce55edad92a107ecbe4b930f825d Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Sun, 21 Apr 2024 18:07:24 +0530 Subject: [PATCH 012/304] Show console debug logs via test tools menu --- ios/Podfile | 17 ++ src/CONST.ts | 3 +- src/ROUTES.ts | 2 +- .../BaseClientSideLoggingToolMenu.tsx | 21 +- .../ConsoleComponents.tsx | 191 ++++++++++++++++++ .../ConsoleModal.tsx | 64 ++++++ .../index.android.tsx | 4 +- .../ClientSideLoggingToolMenu/index.ios.tsx | 4 +- .../ClientSideLoggingToolMenu/index.tsx | 4 +- src/components/Modal/index.tsx | 2 +- src/components/TestToolsModal.tsx | 2 +- src/libs/Navigation/types.ts | 1 + src/pages/settings/AboutPage/ConsolePage.tsx | 158 +-------------- .../ShareLogList/BaseShareLogList.tsx | 10 +- .../AboutPage/ShareLogList/index.native.tsx | 4 +- .../settings/AboutPage/ShareLogList/index.tsx | 4 +- src/pages/settings/AboutPage/ShareLogPage.tsx | 2 +- .../utils/generators/ModalStyleUtils.ts | 23 +++ 18 files changed, 345 insertions(+), 171 deletions(-) create mode 100644 src/components/ClientSideLoggingToolMenu/ConsoleComponents.tsx create mode 100644 src/components/ClientSideLoggingToolMenu/ConsoleModal.tsx diff --git a/ios/Podfile b/ios/Podfile index 4f00eb2adfdd..0c524878e5f7 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,3 +1,5 @@ +use_frameworks! :linkage => :static + require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking") # Set the type of Mapbox SDK to use # This value is used by $RNMapboxMaps @@ -111,6 +113,21 @@ target 'NewExpensify' do end end end + + deployment_target = '13.4' + + installer.generated_projects.each do |project| + project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = deployment_target + end + end + project.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = deployment_target + end + end + + `sed -i -e $'s/__IPHONE_10_0/__IPHONE_15_0/' #{installer.sandbox.root}/RCT-Folly/folly/portability/Time.h` end end diff --git a/src/CONST.ts b/src/CONST.ts index 2cd614b74816..4ded9e282d3e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -860,6 +860,7 @@ const CONST = { POPOVER: 'popover', RIGHT_DOCKED: 'right_docked', ONBOARDING: 'onboarding', + CENTERED_SMALL_AND_UNSWIPEABLE: 'centered_small_and_unswipeable' }, ANCHOR_ORIGIN_VERTICAL: { TOP: 'top', @@ -3100,7 +3101,7 @@ const CONST = { // Test tool menu parameters TEST_TOOL: { // Number of concurrent taps to open then the Test modal menu - NUMBER_OF_TAPS: 4, + NUMBER_OF_TAPS: 2, }, MENU_HELP_URLS: { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index ceb4c217cb6e..71e673aea994 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -175,7 +175,7 @@ const ROUTES = { SETTINGS_CONSOLE: 'settings/troubleshoot/console', SETTINGS_SHARE_LOG: { route: 'settings/troubleshoot/console/share-log', - getRoute: (source: string) => `settings/troubleshoot/console/share-log?source=${encodeURI(source)}` as const, + getRoute: (source: string, isViaTestToolsModal = false) => `settings/troubleshoot/console/share-log?source=${encodeURI(source)}&isViaTestToolsModal=${isViaTestToolsModal}` as const, }, SETTINGS_EXIT_SURVEY_REASON: 'settings/exit-survey/reason', diff --git a/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx b/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx index fcad770908a6..a6bb085c949a 100644 --- a/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx +++ b/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useState} from 'react'; import {Alert} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -12,6 +12,7 @@ import * as Console from '@libs/actions/Console'; import {parseStringifiedMessages} from '@libs/Console'; import ONYXKEYS from '@src/ONYXKEYS'; import type {CapturedLogs, Log} from '@src/types/onyx'; +import ConsoleModal from "@components/ClientSideLoggingToolMenu/ConsoleModal"; type BaseClientSideLoggingToolMenuOnyxProps = { /** Logs captured on the current device */ @@ -30,9 +31,11 @@ type BaseClientSideLoggingToolProps = { onDisableLogging: (logs: Log[]) => void; /** Action to run when enabling logging */ onEnableLogging?: () => void; + /** Boolean to know if this was opened via test tools modal */ + isViaTestToolsModal: boolean } & BaseClientSideLoggingToolMenuOnyxProps; -function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onShareLogs, onDisableLogging, onEnableLogging}: BaseClientSideLoggingToolProps) { +function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onShareLogs, onDisableLogging, onEnableLogging, isViaTestToolsModal, closeTestToolsModal}: BaseClientSideLoggingToolProps) { const {translate} = useLocalize(); const onToggle = () => { @@ -59,6 +62,8 @@ function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onS Console.disableLoggingAndFlushLogs(); }; const styles = useThemeStyles(); + const [isConsoleModalVisible, setIsConsoleModalVisible] = useState(false); + return ( <> @@ -68,6 +73,15 @@ function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onS onToggle={onToggle} /> + {!!shouldStoreLogs && isViaTestToolsModal && + + - )} - {/** + + {isHidden ? translate('moderation.revealMessage') : translate('moderation.hideMessage')} + + + )} + {/** These are the actionable buttons that appear at the bottom of a Concierge message for example: Invite a user mentioned but not a member of the room https://github.com/Expensify/App/issues/32741 */} - {actionableItemButtons.length > 0 && ( - - )} - - ) : ( - - )} + {actionableItemButtons.length > 0 && ( + + )} + + ) : ( + + )} + ); } diff --git a/src/pages/home/report/ReportAttachments.tsx b/src/pages/home/report/ReportAttachments.tsx index 82b49d1e260c..e6dbd760e5af 100644 --- a/src/pages/home/report/ReportAttachments.tsx +++ b/src/pages/home/report/ReportAttachments.tsx @@ -6,13 +6,14 @@ import ComposerFocusManager from '@libs/ComposerFocusManager'; import Navigation from '@libs/Navigation/Navigation'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; +import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -type ReportAttachmentsProps = StackScreenProps; +type ReportAttachmentsProps = StackScreenProps; function ReportAttachments({route}: ReportAttachmentsProps) { - const reportID = route.params.reportID; + const reportID = route.params.id; const report = ReportUtils.getReport(reportID); // In native the imported images sources are of type number. Ref: https://reactnative.dev/docs/image#imagesource @@ -20,7 +21,7 @@ function ReportAttachments({route}: ReportAttachmentsProps) { const onCarouselAttachmentChange = useCallback( (attachment: Attachment) => { - const routeToNavigate = ROUTES.REPORT_ATTACHMENTS.getRoute(reportID, String(attachment.source)); + const routeToNavigate = ROUTES.ATTACHMENTS.getRoute(reportID, CONST.ATTACHMENT_TYPE.REPORT, String(attachment.source)); Navigation.navigate(routeToNavigate); }, [reportID], From 68f91157f2db2f337a342ea6244151f4ad0cd90f Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 25 Apr 2024 12:35:11 +0700 Subject: [PATCH 019/304] fix navigation issue --- src/ROUTES.ts | 3 +- src/components/AttachmentContext.ts | 15 ++-- src/components/AttachmentModal.tsx | 11 +++ .../extractAttachmentsFromNote.ts | 80 +++++++++++++++++++ .../Attachments/AttachmentCarousel/index.tsx | 20 +++-- .../Attachments/AttachmentCarousel/types.ts | 8 ++ .../HTMLRenderers/ImageRenderer.tsx | 14 ++-- src/libs/Middleware/SaveResponseInOnyx.ts | 2 +- src/libs/Navigation/NavigationRoot.tsx | 2 +- src/libs/Navigation/linkTo.ts | 10 +-- src/libs/Navigation/linkingConfig/config.ts | 1 - .../linkingConfig/getAdaptedStateFromPath.ts | 1 - src/libs/Navigation/types.ts | 3 +- .../PrivateNotes/PrivateNotesListPage.tsx | 10 ++- src/pages/home/report/ReportActionItem.tsx | 2 +- src/pages/home/report/ReportAttachments.tsx | 11 ++- 16 files changed, 152 insertions(+), 41 deletions(-) create mode 100644 src/components/Attachments/AttachmentCarousel/extractAttachmentsFromNote.ts diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 47fe2516c7d7..2e65cee4ebb0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -227,7 +227,8 @@ const ROUTES = { }, ATTACHMENTS: { route: 'attachment', - getRoute: (id: string, type: ValueOf, url: string) => `attachment?source=${encodeURIComponent(url)}&type=${type}${id ? `&id=${id}` : ''}`, + getRoute: (reportID: string, type: ValueOf, url: string, accountID?: number) => + `attachment?source=${encodeURIComponent(url)}&type=${type}${reportID ? `&reportID=${reportID}` : ''}${accountID ? `&accountID=${accountID}` : ''}`, }, REPORT_PARTICIPANTS: { route: 'r/:reportID/participants', diff --git a/src/components/AttachmentContext.ts b/src/components/AttachmentContext.ts index 5fcb9ce7b0a4..4ed6bdc9084f 100644 --- a/src/components/AttachmentContext.ts +++ b/src/components/AttachmentContext.ts @@ -1,17 +1,22 @@ import {createContext} from 'react'; -import {ValueOf} from 'type-fest'; -import CONST from '@src/CONST'; +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; type AttachmentContextProps = { type?: ValueOf; - id?: string; + reportID?: string; + accountID?: number; }; const AttachmentContext = createContext({ type: undefined, - id: undefined, + reportID: undefined, + accountID: undefined, }); AttachmentContext.displayName = 'AttachmentContext'; -export {AttachmentContext}; +export { + // eslint-disable-next-line import/prefer-default-export + AttachmentContext, +}; diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index 7d13524b78df..39a4ead98e15 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -5,6 +5,7 @@ import {GestureHandlerRootView} from 'react-native-gesture-handler'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import {useSharedValue} from 'react-native-reanimated'; +import type {ValueOf} from 'type-fest'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -106,6 +107,12 @@ type AttachmentModalProps = AttachmentModalOnyxProps & { /** The report that has this attachment */ report?: OnyxEntry | EmptyObject; + /** The type of the attachment */ + type?: ValueOf; + + /** If the attachment originates from a note, the accountID will represent the author of that note. */ + accountID?: number; + /** Optional callback to fire when we want to do something after modal show. */ onModalShow?: () => void; @@ -163,6 +170,8 @@ function AttachmentModal({ onModalClose = () => {}, isLoading = false, shouldShowNotFoundPage = false, + type = undefined, + accountID = undefined, }: AttachmentModalProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -524,6 +533,8 @@ function AttachmentModal({ )} {!isEmptyObject(report) && !isReceiptAttachment ? ( { + if (name === 'video') { + const source = tryResolveUrlFromApiRoot(attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]); + if (uniqueSources.has(source)) { + return; + } + + uniqueSources.add(source); + const splittedUrl = attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE].split('/'); + attachments.unshift({ + source: tryResolveUrlFromApiRoot(attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]), + isAuthTokenRequired: Boolean(attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]), + file: {name: splittedUrl[splittedUrl.length - 1]}, + duration: Number(attribs[CONST.ATTACHMENT_DURATION_ATTRIBUTE]), + isReceipt: false, + hasBeenFlagged: false, + }); + return; + } + + if (name === 'img' && attribs.src) { + const expensifySource = attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]; + const source = tryResolveUrlFromApiRoot(expensifySource || attribs.src); + if (uniqueSources.has(source)) { + return; + } + + uniqueSources.add(source); + let fileName = attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || FileUtils.getFileName(`${source}`); + + // Public image URLs might lack a file extension in the source URL, without an extension our + // AttachmentView fails to recognize them as images and renders fallback content instead. + // We apply this small hack to add an image extension and ensure AttachmentView renders the image. + const fileInfo = FileUtils.splitExtensionFromFileName(fileName); + if (!fileInfo.fileExtension) { + fileName = `${fileInfo.fileName || 'image'}.jpg`; + } + + // By iterating actions in chronological order and prepending each attachment + // we ensure correct order of attachments even across actions with multiple attachments. + attachments.unshift({ + reportActionID: attribs['data-id'], + source, + isAuthTokenRequired: Boolean(expensifySource), + file: {name: fileName}, + isReceipt: false, + hasBeenFlagged: attribs['data-flagged'] === 'true', + }); + } + }, + }); + + htmlParser.write(targetNote); + htmlParser.end(); + + return attachments.reverse(); +} + +export default extractAttachmentsFromNote; diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index 3a7e0f19c4cd..64d694683b9b 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -19,6 +19,7 @@ import AttachmentCarouselCellRenderer from './AttachmentCarouselCellRenderer'; import CarouselActions from './CarouselActions'; import CarouselButtons from './CarouselButtons'; import CarouselItem from './CarouselItem'; +import extractAttachmentsFromNote from './extractAttachmentsFromNote'; import extractAttachmentsFromReport from './extractAttachmentsFromReport'; import type {AttachmentCaraouselOnyxProps, AttachmentCarouselProps, UpdatePageProps} from './types'; import useCarouselArrows from './useCarouselArrows'; @@ -29,7 +30,7 @@ const viewabilityConfig = { itemVisiblePercentThreshold: 95, }; -function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility}: AttachmentCarouselProps) { +function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, type, accountID}: AttachmentCarouselProps) { const theme = useTheme(); const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -49,19 +50,24 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, useEffect(() => { const parentReportAction = report.parentReportActionID && parentReportActions ? parentReportActions[report.parentReportActionID] : undefined; const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions ?? undefined); + let attachmentsFromNote: Attachment[] = []; + if (type === CONST.ATTACHMENT_TYPE.NOTE && accountID) { + attachmentsFromNote = extractAttachmentsFromNote(report.reportID, accountID); + } + const targetAttachments = type === CONST.ATTACHMENT_TYPE.REPORT ? attachmentsFromReport : attachmentsFromNote; - if (isEqual(attachments, attachmentsFromReport)) { + if (isEqual(attachments, targetAttachments)) { return; } - const initialPage = attachmentsFromReport.findIndex(compareImage); + const initialPage = targetAttachments.findIndex(compareImage); // Dismiss the modal when deleting an attachment during its display in preview. if (initialPage === -1 && attachments.find(compareImage)) { Navigation.dismissModal(); } else { setPage(initialPage); - setAttachments(attachmentsFromReport); + setAttachments(targetAttachments); // Update the download button visibility in the parent modal if (setDownloadButtonVisibility) { @@ -69,11 +75,11 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, } // Update the parent modal's state with the source and name from the mapped attachments - if (attachmentsFromReport[initialPage] !== undefined && onNavigate) { - onNavigate(attachmentsFromReport[initialPage]); + if (targetAttachments[initialPage] !== undefined && onNavigate) { + onNavigate(targetAttachments[initialPage]); } } - }, [reportActions, parentReportActions, compareImage, report.parentReportActionID, attachments, setDownloadButtonVisibility, onNavigate]); + }, [reportActions, parentReportActions, compareImage, report.parentReportActionID, attachments, setDownloadButtonVisibility, onNavigate, accountID, report.reportID]); /** Updates the page state when the user navigates between attachments */ const updatePage = useCallback( diff --git a/src/components/Attachments/AttachmentCarousel/types.ts b/src/components/Attachments/AttachmentCarousel/types.ts index 8ba3489a5fcf..d31ebbd328cd 100644 --- a/src/components/Attachments/AttachmentCarousel/types.ts +++ b/src/components/Attachments/AttachmentCarousel/types.ts @@ -1,6 +1,8 @@ import type {ViewToken} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import type {Attachment, AttachmentSource} from '@components/Attachments/types'; +import type CONST from '@src/CONST'; import type {Report, ReportActions} from '@src/types/onyx'; type UpdatePageProps = { @@ -28,6 +30,12 @@ type AttachmentCarouselProps = AttachmentCaraouselOnyxProps & { /** The report currently being looked at */ report: Report; + /** The type of the attachment */ + type?: ValueOf; + + /** If the attachment originates from a note, the accountID will represent the author of that note. */ + accountID?: number; + /** A callback that is called when swipe-down-to-close gesture happens */ onClose: () => void; }; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx index 4e78f127d06c..36238d635d83 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx @@ -80,17 +80,19 @@ function ImageRenderer({tnode}: ImageRendererProps) { {({anchor, report, action, checkIfContextMenuActive}) => ( - {({id, type}) => ( + {({reportID, accountID, type}) => ( { + if (!source || !type) { + return; + } let route = ''; - if (source && type) { - if (id) { - route = ROUTES.ATTACHMENTS?.getRoute(id, type, source); - Navigation.navigate(route); - } + if (reportID) { + route = ROUTES.ATTACHMENTS?.getRoute(reportID, type, source, accountID); } + + Navigation.navigate(route); }} onLongPress={(event) => showContextMenuForReport(event, anchor, report?.reportID ?? '', action, checkIfContextMenuActive, ReportUtils.isArchivedRoom(report))} shouldUseHapticsOnLongPress diff --git a/src/libs/Middleware/SaveResponseInOnyx.ts b/src/libs/Middleware/SaveResponseInOnyx.ts index 58052c971505..4f06f206eb37 100644 --- a/src/libs/Middleware/SaveResponseInOnyx.ts +++ b/src/libs/Middleware/SaveResponseInOnyx.ts @@ -33,7 +33,7 @@ const SaveResponseInOnyx: Middleware = (requestResponse, request) => OnyxUpdates.saveUpdateInformation(responseToApply); // Ensure the queue is paused while the client resolves the gap in onyx updates so that updates are guaranteed to happen in a specific order. - console.log("**********************", {command: request.command}) + return Promise.resolve({ ...response, shouldPauseQueue: true, diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 4c3084c5291a..f143d6b2bcc1 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -118,7 +118,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N if (!state) { return; } - console.log("777777777", state.routes) + const activeWorkspaceID = getPolicyIDFromState(state as NavigationState); // Performance optimization to avoid context consumers to delay first render setTimeout(() => { diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index e644127cac61..e08237c04601 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -148,23 +148,20 @@ export default function linkTo(navigation: NavigationContainerRef const onboardingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); const welcomeVideoModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR); const attachmentsScreen = state.routes.find((route) => route.name === SCREENS.ATTACHMENTS); - console.log('9999999999', state.routes); if (isNarrowLayout) { metainfo.isFullScreenNavigatorMandatory = false; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index b0df6085aff8..20e1be99d5a1 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -768,9 +768,10 @@ type AuthScreensParamList = SharedScreensParamList & { [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: NavigatorScreenParams; [SCREENS.CONCIERGE]: undefined; [SCREENS.ATTACHMENTS]: { - id: string; + reportID: string; source: string; type: ValueOf; + accountID: string; }; [SCREENS.PROFILE_AVATAR]: { accountID: string; diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.tsx b/src/pages/PrivateNotes/PrivateNotesListPage.tsx index f8121af32076..286c91d628fd 100644 --- a/src/pages/PrivateNotes/PrivateNotesListPage.tsx +++ b/src/pages/PrivateNotes/PrivateNotesListPage.tsx @@ -1,4 +1,4 @@ -import React, {useMemo} from 'react'; +import React, {useCallback, useMemo} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxCollection} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; @@ -30,24 +30,26 @@ type PrivateNotesListPageProps = WithReportAndPrivateNotesOrNotFoundProps & }; type NoteListItem = { - id: string; title: string; action: () => void; brickRoadIndicator: ValueOf | undefined; note: string; disabled: boolean; + reportID: string; + accountID: string; }; function PrivateNotesListPage({report, personalDetailsList, session}: PrivateNotesListPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const getAttachmentValue = useCallback((item: NoteListItem) => ({reportID: item.reportID, accountID: Number(item.accountID), type: CONST.ATTACHMENT_TYPE.NOTE}), []); /** * Gets the menu item for each workspace */ function getMenuItem(item: NoteListItem) { return ( - + { const privateNote = report.privateNotes?.[Number(accountID)]; return { + reportID: report.reportID, + accountID, title: Number(session?.accountID) === Number(accountID) ? translate('privateNotes.myNote') : personalDetailsList?.[accountID]?.login ?? '', action: () => Navigation.navigate(ROUTES.PRIVATE_NOTES_EDIT.getRoute(report.reportID, accountID)), brickRoadIndicator: privateNoteBrickRoadIndicator(Number(accountID)), diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index df303b763282..60b86c209c68 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -374,7 +374,7 @@ function ReportActionItem({ [report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport], ); - const attachmentContextValue = useMemo(() => ({id: report.reportID, type: CONST.ATTACHMENT_TYPE.REPORT}), [report.reportID]); + const attachmentContextValue = useMemo(() => ({reportID: report.reportID, type: CONST.ATTACHMENT_TYPE.REPORT}), [report.reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { const isWhisperResolution = (action?.originalMessage as OriginalMessageActionableMentionWhisper['originalMessage'])?.resolution !== null; diff --git a/src/pages/home/report/ReportAttachments.tsx b/src/pages/home/report/ReportAttachments.tsx index e6dbd760e5af..3ff472baee40 100644 --- a/src/pages/home/report/ReportAttachments.tsx +++ b/src/pages/home/report/ReportAttachments.tsx @@ -6,14 +6,15 @@ import ComposerFocusManager from '@libs/ComposerFocusManager'; import Navigation from '@libs/Navigation/Navigation'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; -import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; type ReportAttachmentsProps = StackScreenProps; function ReportAttachments({route}: ReportAttachmentsProps) { - const reportID = route.params.id; + const reportID = route.params.reportID; + const type = route.params.type; + const accountID = route.params.accountID; const report = ReportUtils.getReport(reportID); // In native the imported images sources are of type number. Ref: https://reactnative.dev/docs/image#imagesource @@ -21,14 +22,16 @@ function ReportAttachments({route}: ReportAttachmentsProps) { const onCarouselAttachmentChange = useCallback( (attachment: Attachment) => { - const routeToNavigate = ROUTES.ATTACHMENTS.getRoute(reportID, CONST.ATTACHMENT_TYPE.REPORT, String(attachment.source)); + const routeToNavigate = ROUTES.ATTACHMENTS.getRoute(reportID, type, String(attachment.source), Number(accountID)); Navigation.navigate(routeToNavigate); }, - [reportID], + [reportID, accountID, type], ); return ( Date: Thu, 25 Apr 2024 12:36:21 +0700 Subject: [PATCH 020/304] fix remove unused change --- src/libs/Middleware/SaveResponseInOnyx.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Middleware/SaveResponseInOnyx.ts b/src/libs/Middleware/SaveResponseInOnyx.ts index 4f06f206eb37..ffe4f8a9bea9 100644 --- a/src/libs/Middleware/SaveResponseInOnyx.ts +++ b/src/libs/Middleware/SaveResponseInOnyx.ts @@ -33,7 +33,6 @@ const SaveResponseInOnyx: Middleware = (requestResponse, request) => OnyxUpdates.saveUpdateInformation(responseToApply); // Ensure the queue is paused while the client resolves the gap in onyx updates so that updates are guaranteed to happen in a specific order. - return Promise.resolve({ ...response, shouldPauseQueue: true, From 07cb16f10664cdb345647401804793d455b2ef9a Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 25 Apr 2024 12:38:18 +0700 Subject: [PATCH 021/304] fix remove unused change --- src/libs/Navigation/NavigationRoot.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index f143d6b2bcc1..506eae2bdfd2 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -118,7 +118,6 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N if (!state) { return; } - const activeWorkspaceID = getPolicyIDFromState(state as NavigationState); // Performance optimization to avoid context consumers to delay first render setTimeout(() => { From 8d8867d24826a754f7abf6d1078dfb8a78c5f600 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 25 Apr 2024 14:32:11 +0700 Subject: [PATCH 022/304] fix remove unused change --- src/libs/Navigation/linkTo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index e08237c04601..863cb102add4 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -154,6 +154,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Thu, 25 Apr 2024 14:42:53 +0700 Subject: [PATCH 023/304] fix typecheck --- src/ROUTES.ts | 2 +- .../HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx | 7 +++---- .../Navigation/linkingConfig/getAdaptedStateFromPath.ts | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 249ba1c2571a..a1c609db6217 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -223,7 +223,7 @@ const ROUTES = { ATTACHMENTS: { route: 'attachment', getRoute: (reportID: string, type: ValueOf, url: string, accountID?: number) => - `attachment?source=${encodeURIComponent(url)}&type=${type}${reportID ? `&reportID=${reportID}` : ''}${accountID ? `&accountID=${accountID}` : ''}`, + `attachment?source=${encodeURIComponent(url)}&type=${type}${reportID ? `&reportID=${reportID}` : ''}${accountID ? `&accountID=${accountID}` : ''}` as const, }, REPORT_PARTICIPANTS: { route: 'r/:reportID/participants', diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx index 36238d635d83..221731bbeef6 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx @@ -87,12 +87,11 @@ function ImageRenderer({tnode}: ImageRendererProps) { if (!source || !type) { return; } - let route = ''; + if (reportID) { - route = ROUTES.ATTACHMENTS?.getRoute(reportID, type, source, accountID); + const route = ROUTES.ATTACHMENTS?.getRoute(reportID, type, source, accountID); + Navigation.navigate(route); } - - Navigation.navigate(route); }} onLongPress={(event) => showContextMenuForReport(event, anchor, report?.reportID ?? '', action, checkIfContextMenuActive, ReportUtils.isArchivedRoom(report))} shouldUseHapticsOnLongPress diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 4faa12696726..9a951bc4f9f2 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -306,7 +306,7 @@ function getAdaptedState(state: PartialState const matchingBottomTabRoute = getMatchingBottomTabRouteForState(state); routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); if (!isNarrowLayout) { - routes.push(createCentralPaneNavigator({name: SCREENS.REPORT, params: {reportID: reportAttachments.params?.id ?? ''}})); + routes.push(createCentralPaneNavigator({name: SCREENS.REPORT, params: {reportID: reportAttachments.params?.reportID ?? ''}})); } routes.push(reportAttachments); From c48b0aa66fccfbdf9e84733e8bdeb08a1b4a57f0 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 25 Apr 2024 14:49:50 +0700 Subject: [PATCH 024/304] fix lint --- src/components/Attachments/AttachmentCarousel/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index 64d694683b9b..6e8843472377 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -79,7 +79,7 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate(targetAttachments[initialPage]); } } - }, [reportActions, parentReportActions, compareImage, report.parentReportActionID, attachments, setDownloadButtonVisibility, onNavigate, accountID, report.reportID]); + }, [reportActions, parentReportActions, compareImage, report.parentReportActionID, attachments, setDownloadButtonVisibility, onNavigate, accountID, report.reportID, type]); /** Updates the page state when the user navigates between attachments */ const updatePage = useCallback( From aef525237d188ca52a7256b45bc2ece9f680f3d4 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 25 Apr 2024 15:39:59 +0700 Subject: [PATCH 025/304] fix native issue --- .../AttachmentCarousel/index.native.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/index.native.tsx b/src/components/Attachments/AttachmentCarousel/index.native.tsx index f6d63fc9307d..c97b16ca2988 100644 --- a/src/components/Attachments/AttachmentCarousel/index.native.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.native.tsx @@ -9,15 +9,17 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import CarouselButtons from './CarouselButtons'; +import extractAttachmentsFromNote from './extractAttachmentsFromNote'; import extractAttachmentsFromReport from './extractAttachmentsFromReport'; import type {AttachmentCarouselPagerHandle} from './Pager'; import AttachmentCarouselPager from './Pager'; import type {AttachmentCaraouselOnyxProps, AttachmentCarouselProps} from './types'; import useCarouselArrows from './useCarouselArrows'; -function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, onClose}: AttachmentCarouselProps) { +function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, onClose, type, accountID}: AttachmentCarouselProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const pagerRef = useRef(null); @@ -31,15 +33,19 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, useEffect(() => { const parentReportAction = report.parentReportActionID && parentReportActions ? parentReportActions[report.parentReportActionID] : undefined; const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions); - - const initialPage = attachmentsFromReport.findIndex(compareImage); + let attachmentsFromNote: Attachment[] = []; + if (type === CONST.ATTACHMENT_TYPE.NOTE && accountID) { + attachmentsFromNote = extractAttachmentsFromNote(report.reportID, accountID); + } + const targetAttachments = type === CONST.ATTACHMENT_TYPE.REPORT ? attachmentsFromReport : attachmentsFromNote; + const initialPage = targetAttachments.findIndex(compareImage); // Dismiss the modal when deleting an attachment during its display in preview. if (initialPage === -1 && attachments.find(compareImage)) { Navigation.dismissModal(); } else { setPage(initialPage); - setAttachments(attachmentsFromReport); + setAttachments(targetAttachments); // Update the download button visibility in the parent modal if (setDownloadButtonVisibility) { @@ -47,8 +53,8 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, } // Update the parent modal's state with the source and name from the mapped attachments - if (attachmentsFromReport[initialPage] !== undefined && onNavigate) { - onNavigate(attachmentsFromReport[initialPage]); + if (targetAttachments[initialPage] !== undefined && onNavigate) { + onNavigate(targetAttachments[initialPage]); } } // eslint-disable-next-line react-hooks/exhaustive-deps From 851f959154367ef5b46d71dcad94061e59078e8f Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Mon, 29 Apr 2024 16:57:03 +0530 Subject: [PATCH 026/304] Navigate to console page --- src/CONST.ts | 1 - src/ROUTES.ts | 5 +- .../BaseClientSideLoggingToolMenu.tsx | 22 +- .../ConsoleComponents.tsx | 193 ------------------ .../ConsoleModal.tsx | 44 ---- .../index.android.tsx | 2 +- .../ClientSideLoggingToolMenu/index.ios.tsx | 2 +- .../ClientSideLoggingToolMenu/index.tsx | 2 +- .../ClientSideLoggingToolMenu/types.ts | 2 - src/components/Modal/index.tsx | 2 +- src/components/TestToolsModal.tsx | 5 +- src/libs/Navigation/linkingConfig/config.ts | 2 +- src/libs/Navigation/types.ts | 4 +- src/pages/settings/AboutPage/ConsolePage.tsx | 179 +++++++++++++++- .../ShareLogList/BaseShareLogList.tsx | 8 +- .../AboutPage/ShareLogList/index.native.tsx | 4 +- .../settings/AboutPage/ShareLogList/index.tsx | 7 +- src/pages/settings/AboutPage/ShareLogPage.tsx | 7 +- .../Troubleshoot/TroubleshootPage.tsx | 2 +- .../utils/generators/ModalStyleUtils.ts | 23 --- 20 files changed, 214 insertions(+), 302 deletions(-) delete mode 100644 src/components/ClientSideLoggingToolMenu/ConsoleComponents.tsx delete mode 100644 src/components/ClientSideLoggingToolMenu/ConsoleModal.tsx diff --git a/src/CONST.ts b/src/CONST.ts index 893dc008786b..2cd614b74816 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -860,7 +860,6 @@ const CONST = { POPOVER: 'popover', RIGHT_DOCKED: 'right_docked', ONBOARDING: 'onboarding', - CENTERED_SMALL_AND_UNSWIPEABLE: 'centered_small_and_unswipeable' }, ANCHOR_ORIGIN_VERTICAL: { TOP: 'top', diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 71e673aea994..db9ae77fd0e8 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -172,7 +172,10 @@ const ROUTES = { SETTINGS_STATUS_CLEAR_AFTER_DATE: 'settings/profile/status/clear-after/date', SETTINGS_STATUS_CLEAR_AFTER_TIME: 'settings/profile/status/clear-after/time', SETTINGS_TROUBLESHOOT: 'settings/troubleshoot', - SETTINGS_CONSOLE: 'settings/troubleshoot/console', + SETTINGS_CONSOLE: { + route: 'settings/troubleshoot/console', + getRoute: (isViaTestToolsModal = false) => `settings/troubleshoot/console?isViaTestToolsModal=${isViaTestToolsModal}` as const, + }, SETTINGS_SHARE_LOG: { route: 'settings/troubleshoot/console/share-log', getRoute: (source: string, isViaTestToolsModal = false) => `settings/troubleshoot/console/share-log?source=${encodeURI(source)}&isViaTestToolsModal=${isViaTestToolsModal}` as const, diff --git a/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx b/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx index 9b5faac55bc4..7d27caa997f7 100644 --- a/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx +++ b/src/components/ClientSideLoggingToolMenu/BaseClientSideLoggingToolMenu.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React from 'react'; import {Alert} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -12,7 +12,8 @@ import * as Console from '@libs/actions/Console'; import {parseStringifiedMessages} from '@libs/Console'; import ONYXKEYS from '@src/ONYXKEYS'; import type {CapturedLogs, Log} from '@src/types/onyx'; -import ConsoleModal from "./ConsoleModal"; +import Navigation from "@navigation/Navigation"; +import ROUTES from "@src/ROUTES"; type BaseClientSideLoggingToolMenuOnyxProps = { /** Logs captured on the current device */ @@ -64,7 +65,6 @@ function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onS Console.disableLoggingAndFlushLogs(); }; const styles = useThemeStyles(); - const [isConsoleModalVisible, setIsConsoleModalVisible] = useState(false); return ( <> @@ -75,15 +75,18 @@ function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onS onToggle={onToggle} /> - {!!shouldStoreLogs && isViaTestToolsModal && + {!!shouldStoreLogs && isViaTestToolsModal && (