From ae9861399b9879423252f6f274d40f398f409a42 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 6 Dec 2022 15:07:06 -0700 Subject: [PATCH 01/49] add reportID param --- src/libs/actions/IOU.js | 8 +++++--- src/pages/iou/IOUModal.js | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 7aa9a5dcda51..3dc6fe2e5e1e 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -242,10 +242,11 @@ function requestMoney(report, amount, currency, recipientEmail, participant, com * @param {String} comment * @param {String} currency * @param {String} locale + * @param {String} reportID * * @return {Object} */ -function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale) { +function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale, reportID = '') { const currentUserEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); const participantLogins = _.map(participants, participant => OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase()); const existingGroupChatReport = ReportUtils.getChatByParticipants(participantLogins); @@ -500,9 +501,10 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment * @param {String} comment * @param {String} currency * @param {String} locale + * @param {String} reportID */ -function splitBill(participants, currentUserLogin, amount, comment, currency, locale) { - const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale); +function splitBill(participants, currentUserLogin, amount, comment, currency, locale, reportID = '') { + const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale, reportID); API.write('SplitBill', { reportID: groupData.chatReportID, diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js index 34033ea98f8a..19e4321b9a0b 100755 --- a/src/pages/iou/IOUModal.js +++ b/src/pages/iou/IOUModal.js @@ -326,6 +326,7 @@ class IOUModal extends Component { this.state.comment, this.props.iou.selectedCurrencyCode, this.props.preferredLocale, + reportID, ); return; } From 9dd1fecf8b43c4f6d9f010944e08f3fd99fc55d5 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 6 Dec 2022 15:08:09 -0700 Subject: [PATCH 02/49] rename param --- src/libs/actions/IOU.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 3dc6fe2e5e1e..720e06fb14cb 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -242,11 +242,11 @@ function requestMoney(report, amount, currency, recipientEmail, participant, com * @param {String} comment * @param {String} currency * @param {String} locale - * @param {String} reportID + * @param {String} existingGroupChatReportID * * @return {Object} */ -function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale, reportID = '') { +function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale, existingGroupChatReportID = '') { const currentUserEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); const participantLogins = _.map(participants, participant => OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase()); const existingGroupChatReport = ReportUtils.getChatByParticipants(participantLogins); @@ -501,10 +501,10 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment * @param {String} comment * @param {String} currency * @param {String} locale - * @param {String} reportID + * @param {String} existingGroupChatReportID */ -function splitBill(participants, currentUserLogin, amount, comment, currency, locale, reportID = '') { - const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale, reportID); +function splitBill(participants, currentUserLogin, amount, comment, currency, locale, existingGroupChatReportID = '') { + const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale, existingGroupChatReportID); API.write('SplitBill', { reportID: groupData.chatReportID, From 68b626cd2221e1afeda5197edbb538d66124a5f3 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 6 Dec 2022 16:13:12 -0700 Subject: [PATCH 03/49] get existing group --- src/libs/actions/IOU.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 720e06fb14cb..d0d95964b5a1 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -249,7 +249,9 @@ function requestMoney(report, amount, currency, recipientEmail, participant, com function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, locale, existingGroupChatReportID = '') { const currentUserEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); const participantLogins = _.map(participants, participant => OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase()); - const existingGroupChatReport = ReportUtils.getChatByParticipants(participantLogins); + const existingGroupChatReport = existingGroupChatReportID + ? chatReports[`${ONYXKEYS.COLLECTION.REPORT}${existingGroupChatReportID}`] + : ReportUtils.getChatByParticipants(participantLogins); const groupChatReport = existingGroupChatReport || ReportUtils.buildOptimisticChatReport(participantLogins); const groupCreatedReportAction = existingGroupChatReport ? {} : ReportUtils.buildOptimisticCreatedReportAction(currentUserEmail); const groupChatReportMaxSequenceNumber = lodashGet(groupChatReport, 'maxSequenceNumber', 0); From 6aa864f092d6184057912cbc9766c3a01a52ef81 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 8 Dec 2022 15:43:57 -0700 Subject: [PATCH 04/49] rm hasMultipleParticipants logic --- src/libs/actions/IOU.js | 114 +++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 66 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index d0d95964b5a1..c085d1e6a11b 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -337,7 +337,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment } // If we only have one participant, the oneOnOneChatReport is the groupChatReport - const existingOneOnOneChatReport = hasMultipleParticipants ? ReportUtils.getChatByParticipants([email]) : groupChatReport; + const existingOneOnOneChatReport = ReportUtils.getChatByParticipants([email]); const oneOnOneChatReport = existingOneOnOneChatReport || ReportUtils.buildOptimisticChatReport([email]); let oneOnOneIOUReport; let existingIOUReport = null; @@ -385,77 +385,59 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment createChat: existingOneOnOneChatReport ? null : CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }; - // If we only have one other participant, we just need to update onyxData for the groupChatReport and add an iouReportAction of type = create - // If we have more participants, we need to push the new oneOnOneChaReport, the create reportAction and iouReportAction of type = create to onyxData - if (!hasMultipleParticipants) { - optimisticData[0].value = oneOnOneChatReport; - optimisticData[1].value = { - ...optimisticData[1].value, - [oneOnOneIOUReportAction.sequenceNumber]: oneOnOneIOUReportAction, - }; - successData[1].value = { - ...successData[1].value, - [oneOnOneIOUReportAction.sequenceNumber]: {pendingAction: null}, - }; - failureData[1].value = { - ...failureData[1].value, - [oneOnOneIOUReportAction.sequenceNumber]: {pendingAction: null}, - }; - } else { - optimisticData.push( - { - onyxMethod: existingOneOnOneChatReport ? CONST.ONYX.METHOD.MERGE : CONST.ONYX.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.reportID}`, - value: oneOnOneChatReport, - }, - { - onyxMethod: existingOneOnOneChatReport ? CONST.ONYX.METHOD.MERGE : CONST.ONYX.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oneOnOneChatReport.reportID}`, - value: { - ...oneOnOneCreatedReportAction, - [oneOnOneIOUReportAction.sequenceNumber]: oneOnOneIOUReportAction, - }, + optimisticData.push( + { + onyxMethod: existingOneOnOneChatReport ? CONST.ONYX.METHOD.MERGE : CONST.ONYX.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.reportID}`, + value: oneOnOneChatReport, + }, + { + onyxMethod: existingOneOnOneChatReport ? CONST.ONYX.METHOD.MERGE : CONST.ONYX.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oneOnOneChatReport.reportID}`, + value: { + ...oneOnOneCreatedReportAction, + [oneOnOneIOUReportAction.sequenceNumber]: oneOnOneIOUReportAction, }, - ); + }, + ); - successData.push( - { - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.reportID}`, - value: {pendingFields: {createChat: null}}, - }, - { - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oneOnOneChatReport.reportID}`, - value: { - 0: {pendingAction: null}, - [oneOnOneIOUReportAction.sequenceNumber]: {pendingAction: null}, - }, + successData.push( + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.reportID}`, + value: {pendingFields: {createChat: null}}, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oneOnOneChatReport.reportID}`, + value: { + 0: {pendingAction: null}, + [oneOnOneIOUReportAction.sequenceNumber]: {pendingAction: null}, }, - ); + }, + ); - failureData.push( - { - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.reportID}`, - value: { - pendingFields: {createChat: null}, - hasOutstandingIOU: existingOneOnOneChatReport ? existingOneOnOneChatReport.hasOutstandingIOU : false, - iouReportID: existingOneOnOneChatReport ? existingOneOnOneChatReport.iouReportID : null, - maxSequenceNumber: oneOnOneChatReportMaxSequenceNumber, - lastReadSequenceNumber: oneOnOneChatReportMaxSequenceNumber, - }, + failureData.push( + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.reportID}`, + value: { + pendingFields: {createChat: null}, + hasOutstandingIOU: existingOneOnOneChatReport ? existingOneOnOneChatReport.hasOutstandingIOU : false, + iouReportID: existingOneOnOneChatReport ? existingOneOnOneChatReport.iouReportID : null, + maxSequenceNumber: oneOnOneChatReportMaxSequenceNumber, + lastReadSequenceNumber: oneOnOneChatReportMaxSequenceNumber, }, - { - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oneOnOneChatReport.reportID}`, - value: { - 0: {pendingAction: null}, - [oneOnOneIOUReportAction.sequenceNumber]: {pendingAction: null}, - }, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oneOnOneChatReport.reportID}`, + value: { + 0: {pendingAction: null}, + [oneOnOneIOUReportAction.sequenceNumber]: {pendingAction: null}, }, - ); - } + }, + ); // Regardless of the number of participants, we always want to push the iouReport update to onyxData optimisticData.push({ From 5380b4ac1d8da1bdb212f45229c6b0849fbd5402 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 8 Dec 2022 16:07:11 -0700 Subject: [PATCH 05/49] fix logic with single participant --- src/libs/actions/IOU.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index c085d1e6a11b..71bc551fffa0 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -336,8 +336,8 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment return; } - // If we only have one participant, the oneOnOneChatReport is the groupChatReport - const existingOneOnOneChatReport = ReportUtils.getChatByParticipants([email]); + // If we only have one participant and the request was iniated from the global create menu, i.e. !existingGroupChatReportID, the oneOnOneChatReport is the groupChatReport + const existingOneOnOneChatReport = (!hasMultipleParticipants && !existingGroupChatReportID) ? groupChatReport : ReportUtils.getChatByParticipants([email]); const oneOnOneChatReport = existingOneOnOneChatReport || ReportUtils.buildOptimisticChatReport([email]); let oneOnOneIOUReport; let existingIOUReport = null; From 96d554432a7132c3f59028ee5a4bbaa3c4577281 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 9 Dec 2022 08:46:39 -0700 Subject: [PATCH 06/49] fix typo --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 71bc551fffa0..0751999ccb4e 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -336,7 +336,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment return; } - // If we only have one participant and the request was iniated from the global create menu, i.e. !existingGroupChatReportID, the oneOnOneChatReport is the groupChatReport + // If we only have one participant and the request was initiated from the global create menu, i.e. !existingGroupChatReportID, the oneOnOneChatReport is the groupChatReport const existingOneOnOneChatReport = (!hasMultipleParticipants && !existingGroupChatReportID) ? groupChatReport : ReportUtils.getChatByParticipants([email]); const oneOnOneChatReport = existingOneOnOneChatReport || ReportUtils.buildOptimisticChatReport([email]); let oneOnOneIOUReport; From 34a17f5947d367232f80535a1f55d2a7ddee6152 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 9 Dec 2022 15:21:48 -0700 Subject: [PATCH 07/49] Only highlight emojis once we start using hte keyboard or hovering --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 2d97a24439fa..38e699a4bd2d 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -386,7 +386,7 @@ class EmojiPickerMenu extends Component { )); // Remove sticky header indices. There are no headers while searching and we don't want to make emojis sticky - this.setState({filteredEmojis: newFilteredEmojiList, headerIndices: [], highlightedIndex: 0}); + this.setState({filteredEmojis: newFilteredEmojiList, headerIndices: [], highlightedIndex: -1}); this.setFirstNonHeaderIndex(newFilteredEmojiList); } From cde253d13db88c771a025b6f77e7d7a489cc7741 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 9 Dec 2022 17:01:20 -0700 Subject: [PATCH 08/49] Add comment explaining -1 index --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 38e699a4bd2d..3818c78dc25e 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -386,6 +386,7 @@ class EmojiPickerMenu extends Component { )); // Remove sticky header indices. There are no headers while searching and we don't want to make emojis sticky + // Always set the highlighted index to -1 so that no emojis are highlighted until the keyboard is used this.setState({filteredEmojis: newFilteredEmojiList, headerIndices: [], highlightedIndex: -1}); this.setFirstNonHeaderIndex(newFilteredEmojiList); } From b4dc62445a28f5fdce61e60dea1e6a5076df8b9f Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 12 Dec 2022 14:16:47 -0700 Subject: [PATCH 09/49] Also replace the existing message so that we are comparing the same thing --- src/libs/actions/Report.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 90dc443cb4f8..de6837b3429a 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -905,6 +905,7 @@ function editReportComment(reportID, originalReportAction, textForNewComment) { // Do not autolink if someone explicitly tries to remove a link from message. // https://github.com/Expensify/App/issues/9090 const htmlForNewComment = parser.replace(textForNewComment, {filterRules: _.filter(_.pluck(parser.rules, 'name'), name => name !== 'autolink')}); + const originalMessageHTML = parser.replace(originalReportAction.message[0].html, {filterRules: _.filter(_.pluck(parser.rules, 'name'), name => name !== 'autolink')}); // Delete the comment if it's empty if (_.isEmpty(htmlForNewComment)) { @@ -913,7 +914,7 @@ function editReportComment(reportID, originalReportAction, textForNewComment) { } // Skip the Edit if message is not changed - if (originalReportAction.message[0].html === htmlForNewComment.trim()) { + if (originalMessageHTML === htmlForNewComment.trim()) { return; } From 0e02e78bbdb10595db9e9ee5ac2726a27f92b433 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 12 Dec 2022 14:19:21 -0700 Subject: [PATCH 10/49] Remove code from wrong PR --- src/libs/actions/Report.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index de6837b3429a..90dc443cb4f8 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -905,7 +905,6 @@ function editReportComment(reportID, originalReportAction, textForNewComment) { // Do not autolink if someone explicitly tries to remove a link from message. // https://github.com/Expensify/App/issues/9090 const htmlForNewComment = parser.replace(textForNewComment, {filterRules: _.filter(_.pluck(parser.rules, 'name'), name => name !== 'autolink')}); - const originalMessageHTML = parser.replace(originalReportAction.message[0].html, {filterRules: _.filter(_.pluck(parser.rules, 'name'), name => name !== 'autolink')}); // Delete the comment if it's empty if (_.isEmpty(htmlForNewComment)) { @@ -914,7 +913,7 @@ function editReportComment(reportID, originalReportAction, textForNewComment) { } // Skip the Edit if message is not changed - if (originalMessageHTML === htmlForNewComment.trim()) { + if (originalReportAction.message[0].html === htmlForNewComment.trim()) { return; } From 2be5d34c4bf512254ef0325faa6f6167bb73ff30 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 09:24:52 -0700 Subject: [PATCH 11/49] rename fetchIOUReportByID to openIOUPreview --- src/components/ReportActionItem/IOUPreview.js | 2 +- src/libs/actions/Report.js | 20 +++---------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index b47ea3b930d1..6a39f4da5425 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -119,7 +119,7 @@ const IOUPreview = (props) => { const reportIsLoading = _.isEmpty(props.iouReport); if (reportIsLoading) { - Report.fetchIOUReportByID(props.iouReportID, props.chatReportID); + Report.openIOUPreview(props.iouReportID, props.chatReportID); } const managerName = lodashGet(props.personalDetails, [managerEmail, 'firstName'], '') diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 082317c9db63..c1237fadd4ca 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -232,23 +232,9 @@ function setLocalIOUReportData(iouReportObject) { * * @param {Number} iouReportID - ID of the report we are fetching * @param {Number} chatReportID - associated chatReportID, set as an iouReport field - * @param {Boolean} [shouldRedirectIfEmpty=false] - Whether to redirect to Active Report Screen if IOUReport is empty - * @returns {Promise} */ -function fetchIOUReportByID(iouReportID, chatReportID, shouldRedirectIfEmpty = false) { - return fetchIOUReport(iouReportID, chatReportID) - .then((iouReportObject) => { - if (!iouReportObject && shouldRedirectIfEmpty) { - Growl.error(Localize.translateLocal('notFound.iouReportNotFound')); - Navigation.navigate(ROUTES.REPORT); - return; - } - if (!iouReportObject) { - return; - } - setLocalIOUReportData(iouReportObject); - return iouReportObject; - }); +function openIOUPreview(iouReportID, chatReportID) { + API.read('OpenIOUPreview', {iouReportID, chatReportID}); } /** @@ -1348,7 +1334,7 @@ Onyx.connect({ }); export { - fetchIOUReportByID, + openIOUPreview, addComment, addAttachment, reconnect, From 3c60858e34f82c0d484a87159c98acb2f230d3df Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 09:25:23 -0700 Subject: [PATCH 12/49] rm setLocalIOUReportData --- src/libs/actions/Report.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index c1237fadd4ca..61756c551118 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -214,19 +214,6 @@ function fetchIOUReport(iouReportID, chatReportID) { }); } -/** - * Given IOU object, save the data to Onyx. - * - * @param {Object} iouReportObject - * @param {Number} iouReportObject.stateNum - * @param {Number} iouReportObject.total - * @param {Number} iouReportObject.reportID - */ -function setLocalIOUReportData(iouReportObject) { - const iouReportKey = `${ONYXKEYS.COLLECTION.REPORT}${iouReportObject.reportID}`; - Onyx.merge(iouReportKey, iouReportObject); -} - /** * Fetch the iouReport and persist the data to Onyx. * From f7bd6142dde53a5556aab232475ecc235614a6ae Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 09:26:51 -0700 Subject: [PATCH 13/49] rm unused imports --- src/libs/actions/Report.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 61756c551118..f16ceae014cf 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -19,8 +19,6 @@ import CONST from '../../CONST'; import Log from '../Log'; import * as LoginUtils from '../LoginUtils'; import * as ReportUtils from '../ReportUtils'; -import Growl from '../Growl'; -import * as Localize from '../Localize'; import DateUtils from '../DateUtils'; import * as ReportActionsUtils from '../ReportActionsUtils'; import * as OptionsListUtils from '../OptionsListUtils'; From dc49401917f16aa7aaabaca19fd1d6e0d83b7e51 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 09:48:01 -0700 Subject: [PATCH 14/49] rm fetchIOUReport --- src/libs/actions/Report.js | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index f16ceae014cf..f7ff951a7931 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -12,7 +12,6 @@ import Navigation from '../Navigation/Navigation'; import * as ActiveClientManager from '../ActiveClientManager'; import Visibility from '../Visibility'; import ROUTES from '../../ROUTES'; -import * as DeprecatedAPI from '../deprecatedAPI'; import * as API from '../API'; import CONFIG from '../../CONFIG'; import CONST from '../../CONST'; @@ -179,39 +178,6 @@ function getSimplifiedIOUReport(reportData, chatReportID) { }; } -/** - * Given IOU and chat report ID fetches most recent IOU data from DeprecatedAPI. - * - * @param {Number} iouReportID - * @param {Number} chatReportID - * @returns {Promise} - */ -function fetchIOUReport(iouReportID, chatReportID) { - return DeprecatedAPI.Get({ - returnValueList: 'reportStuff', - reportIDList: iouReportID, - shouldLoadOptionalKeys: true, - includePinnedReports: true, - }).then((response) => { - if (!response) { - return; - } - if (response.jsonCode !== 200) { - console.error(response.message); - return; - } - const iouReportData = response.reports[iouReportID]; - if (!iouReportData) { - // IOU data for a report will be missing when the IOU report has already been paid. - // This is expected and we return early as no further processing can be done. - return; - } - return getSimplifiedIOUReport(iouReportData, chatReportID); - }).catch((error) => { - Log.hmmm('[Report] Failed to populate IOU Collection:', error.message); - }); -} - /** * Fetch the iouReport and persist the data to Onyx. * From 78ebc797f44681454f40eb7ea0288d2c4352a9b1 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 11:52:36 -0700 Subject: [PATCH 15/49] convert ioupreview to class component --- src/components/ReportActionItem/IOUPreview.js | 219 +++++++++--------- 1 file changed, 111 insertions(+), 108 deletions(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 6a39f4da5425..eb281c98957a 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -101,121 +101,124 @@ const defaultProps = { isHovered: false, }; -const IOUPreview = (props) => { - // Usually the parent determines whether the IOU Preview is displayed. But as the iouReport total cannot be known - // until it is stored locally, we need to make this check within the Component after retrieving it. This allows us - // to handle the loading UI from within this Component instead of needing to declare it within each parent, which - // would duplicate and complicate the logic - if (props.iouReport.total === 0) { - return null; +class IOUPreview extends React.Component { + componentDidMount() { + if (!_.isEmpty(this.props.iouReport)) { + return; + } + Report.openIOUPreview(this.props.iouReportID, this.props.chatReportID); } - const sessionEmail = lodashGet(props.session, 'email', null); - const managerEmail = props.iouReport.managerEmail || ''; - const ownerEmail = props.iouReport.ownerEmail || ''; - - // Pay button should only be visible to the manager of the report. - const isCurrentUserManager = managerEmail === sessionEmail; - const reportIsLoading = _.isEmpty(props.iouReport); - - if (reportIsLoading) { - Report.openIOUPreview(props.iouReportID, props.chatReportID); - } - - const managerName = lodashGet(props.personalDetails, [managerEmail, 'firstName'], '') - || Str.removeSMSDomain(managerEmail); - const ownerName = lodashGet(props.personalDetails, [ownerEmail, 'firstName'], '') || Str.removeSMSDomain(ownerEmail); - const managerAvatar = lodashGet(props.personalDetails, [managerEmail, 'avatar'], ''); - const ownerAvatar = lodashGet(props.personalDetails, [ownerEmail, 'avatar'], ''); - const cachedTotal = props.iouReport.total && props.iouReport.currency - ? props.numberFormat( - Math.abs(props.iouReport.total) / 100, - {style: 'currency', currency: props.iouReport.currency}, - ) : ''; - const avatarTooltip = [Str.removeSMSDomain(managerEmail), Str.removeSMSDomain(ownerEmail)]; - return ( - - - {reportIsLoading - ? - : ( - { - PaymentMethods.clearWalletTermsError(); - Report.clearIOUError(props.chatReportID); - }} - errorRowStyles={[styles.mbn1]} - > - - - - - {cachedTotal} - - {!props.iouReport.hasOutstandingIOU && ( - - - - )} - - - + render() { + // Usually the parent determines whether the IOU Preview is displayed. But as the iouReport total cannot be known + // until it is stored locally, we need to make this check within the Component after retrieving it. This allows us + // to handle the loading UI from within this Component instead of needing to declare it within each parent, which + // would duplicate and complicate the logic + if (this.props.iouReport.total === 0) { + return null; + } + + const sessionEmail = lodashGet(this.props.session, 'email', null); + const managerEmail = this.props.iouReport.managerEmail || ''; + const ownerEmail = this.props.iouReport.ownerEmail || ''; + + // Pay button should only be visible to the manager of the report. + const isCurrentUserManager = managerEmail === sessionEmail; + const managerName = lodashGet(this.props.personalDetails, [managerEmail, 'firstName'], '') + || Str.removeSMSDomain(managerEmail); + const ownerName = lodashGet(this.props.personalDetails, [ownerEmail, 'firstName'], '') || Str.removeSMSDomain(ownerEmail); + const managerAvatar = lodashGet(this.props.personalDetails, [managerEmail, 'avatar'], ''); + const ownerAvatar = lodashGet(this.props.personalDetails, [ownerEmail, 'avatar'], ''); + const cachedTotal = this.props.iouReport.total && this.props.iouReport.currency + ? this.props.numberFormat( + Math.abs(this.props.iouReport.total) / 100, + {style: 'currency', currency: this.props.iouReport.currency}, + ) : ''; + const avatarTooltip = [Str.removeSMSDomain(managerEmail), Str.removeSMSDomain(ownerEmail)]; + + return ( + + + {_.isEmpty(this.props.iouReport) + ? + : ( + { + PaymentMethods.clearWalletTermsError(); + Report.clearIOUError(this.props.chatReportID); + }} + errorRowStyles={[styles.mbn1]} + > + + + + + {cachedTotal} + + {!this.props.iouReport.hasOutstandingIOU && ( + + + + )} + + + + - - {isCurrentUserManager - ? ( - - {props.iouReport.hasOutstandingIOU - ? props.translate('iou.youowe', {owner: ownerName}) - : props.translate('iou.youpaid', {owner: ownerName})} - - ) - : ( - - {props.iouReport.hasOutstandingIOU - ? props.translate('iou.owesyou', {manager: managerName}) - : props.translate('iou.paidyou', {manager: managerName})} - - )} - {(isCurrentUserManager - && !props.shouldHidePayButton - && props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && ( - - + {this.props.iouReport.hasOutstandingIOU + ? this.props.translate('iou.youowe', {owner: ownerName}) + : this.props.translate('iou.youpaid', {owner: ownerName})} + + ) + : ( + + {this.props.iouReport.hasOutstandingIOU + ? this.props.translate('iou.owesyou', {manager: managerName}) + : this.props.translate('iou.paidyou', {manager: managerName})} + + )} + {(isCurrentUserManager + && !this.props.shouldHidePayButton + && this.props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && ( + - {props.translate('iou.pay')} - - - ))} - - - )} - - - ); -}; + + {this.props.translate('iou.pay')} + + + ))} + + + )} + + + ); + } +} IOUPreview.propTypes = propTypes; IOUPreview.defaultProps = defaultProps; -IOUPreview.displayName = 'IOUPreview'; export default compose( withLocalize, From a945e87a0609a2cd47edc1188c8b536ea9dfff63 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 11:58:19 -0700 Subject: [PATCH 16/49] rm export of getSimplifiedIOUReport --- src/libs/actions/Report.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index f7ff951a7931..b6bf3a998ee8 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1299,7 +1299,6 @@ export { editReportComment, saveReportActionDraft, deleteReportComment, - getSimplifiedIOUReport, syncChatAndIOUReports, navigateToConciergeChat, setReportWithDraft, From 595e5d444093ea67640cc8516676d0c3ec88cc07 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 13 Dec 2022 14:23:13 -0700 Subject: [PATCH 17/49] Revert to starting index at 0 to avoid breaking functionality --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 3818c78dc25e..2d97a24439fa 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -386,8 +386,7 @@ class EmojiPickerMenu extends Component { )); // Remove sticky header indices. There are no headers while searching and we don't want to make emojis sticky - // Always set the highlighted index to -1 so that no emojis are highlighted until the keyboard is used - this.setState({filteredEmojis: newFilteredEmojiList, headerIndices: [], highlightedIndex: -1}); + this.setState({filteredEmojis: newFilteredEmojiList, headerIndices: [], highlightedIndex: 0}); this.setFirstNonHeaderIndex(newFilteredEmojiList); } From 934749e30c5529b3bd738cb254d224c6c57c1bba Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 18:09:43 -0700 Subject: [PATCH 18/49] rm openIOUPreview --- src/libs/actions/Report.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index b6bf3a998ee8..8f44accc1019 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -178,16 +178,6 @@ function getSimplifiedIOUReport(reportData, chatReportID) { }; } -/** - * Fetch the iouReport and persist the data to Onyx. - * - * @param {Number} iouReportID - ID of the report we are fetching - * @param {Number} chatReportID - associated chatReportID, set as an iouReport field - */ -function openIOUPreview(iouReportID, chatReportID) { - API.read('OpenIOUPreview', {iouReportID, chatReportID}); -} - /** * Get the private pusher channel name for a Report. * @@ -1285,7 +1275,6 @@ Onyx.connect({ }); export { - openIOUPreview, addComment, addAttachment, reconnect, From a26350150b573bbb21ef5a59f812f1da1dc3f31b Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 18:10:20 -0700 Subject: [PATCH 19/49] revert class component --- src/components/ReportActionItem/IOUPreview.js | 219 +++++++++--------- 1 file changed, 108 insertions(+), 111 deletions(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index eb281c98957a..b47ea3b930d1 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -101,124 +101,121 @@ const defaultProps = { isHovered: false, }; -class IOUPreview extends React.Component { - componentDidMount() { - if (!_.isEmpty(this.props.iouReport)) { - return; - } - Report.openIOUPreview(this.props.iouReportID, this.props.chatReportID); +const IOUPreview = (props) => { + // Usually the parent determines whether the IOU Preview is displayed. But as the iouReport total cannot be known + // until it is stored locally, we need to make this check within the Component after retrieving it. This allows us + // to handle the loading UI from within this Component instead of needing to declare it within each parent, which + // would duplicate and complicate the logic + if (props.iouReport.total === 0) { + return null; } - render() { - // Usually the parent determines whether the IOU Preview is displayed. But as the iouReport total cannot be known - // until it is stored locally, we need to make this check within the Component after retrieving it. This allows us - // to handle the loading UI from within this Component instead of needing to declare it within each parent, which - // would duplicate and complicate the logic - if (this.props.iouReport.total === 0) { - return null; - } - - const sessionEmail = lodashGet(this.props.session, 'email', null); - const managerEmail = this.props.iouReport.managerEmail || ''; - const ownerEmail = this.props.iouReport.ownerEmail || ''; - - // Pay button should only be visible to the manager of the report. - const isCurrentUserManager = managerEmail === sessionEmail; - const managerName = lodashGet(this.props.personalDetails, [managerEmail, 'firstName'], '') - || Str.removeSMSDomain(managerEmail); - const ownerName = lodashGet(this.props.personalDetails, [ownerEmail, 'firstName'], '') || Str.removeSMSDomain(ownerEmail); - const managerAvatar = lodashGet(this.props.personalDetails, [managerEmail, 'avatar'], ''); - const ownerAvatar = lodashGet(this.props.personalDetails, [ownerEmail, 'avatar'], ''); - const cachedTotal = this.props.iouReport.total && this.props.iouReport.currency - ? this.props.numberFormat( - Math.abs(this.props.iouReport.total) / 100, - {style: 'currency', currency: this.props.iouReport.currency}, - ) : ''; - const avatarTooltip = [Str.removeSMSDomain(managerEmail), Str.removeSMSDomain(ownerEmail)]; - - return ( - - - {_.isEmpty(this.props.iouReport) - ? - : ( - { - PaymentMethods.clearWalletTermsError(); - Report.clearIOUError(this.props.chatReportID); - }} - errorRowStyles={[styles.mbn1]} - > - - - - - {cachedTotal} - - {!this.props.iouReport.hasOutstandingIOU && ( - - - - )} - - - - - - {isCurrentUserManager - ? ( - - {this.props.iouReport.hasOutstandingIOU - ? this.props.translate('iou.youowe', {owner: ownerName}) - : this.props.translate('iou.youpaid', {owner: ownerName})} - - ) - : ( - - {this.props.iouReport.hasOutstandingIOU - ? this.props.translate('iou.owesyou', {manager: managerName}) - : this.props.translate('iou.paidyou', {manager: managerName})} - + const sessionEmail = lodashGet(props.session, 'email', null); + const managerEmail = props.iouReport.managerEmail || ''; + const ownerEmail = props.iouReport.ownerEmail || ''; + + // Pay button should only be visible to the manager of the report. + const isCurrentUserManager = managerEmail === sessionEmail; + const reportIsLoading = _.isEmpty(props.iouReport); + + if (reportIsLoading) { + Report.fetchIOUReportByID(props.iouReportID, props.chatReportID); + } + + const managerName = lodashGet(props.personalDetails, [managerEmail, 'firstName'], '') + || Str.removeSMSDomain(managerEmail); + const ownerName = lodashGet(props.personalDetails, [ownerEmail, 'firstName'], '') || Str.removeSMSDomain(ownerEmail); + const managerAvatar = lodashGet(props.personalDetails, [managerEmail, 'avatar'], ''); + const ownerAvatar = lodashGet(props.personalDetails, [ownerEmail, 'avatar'], ''); + const cachedTotal = props.iouReport.total && props.iouReport.currency + ? props.numberFormat( + Math.abs(props.iouReport.total) / 100, + {style: 'currency', currency: props.iouReport.currency}, + ) : ''; + const avatarTooltip = [Str.removeSMSDomain(managerEmail), Str.removeSMSDomain(ownerEmail)]; + return ( + + + {reportIsLoading + ? + : ( + { + PaymentMethods.clearWalletTermsError(); + Report.clearIOUError(props.chatReportID); + }} + errorRowStyles={[styles.mbn1]} + > + + + + + {cachedTotal} + + {!props.iouReport.hasOutstandingIOU && ( + + + )} - {(isCurrentUserManager - && !this.props.shouldHidePayButton - && this.props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && ( - - - {this.props.translate('iou.pay')} - - - ))} + + + + - - )} - - - ); - } -} + {isCurrentUserManager + ? ( + + {props.iouReport.hasOutstandingIOU + ? props.translate('iou.youowe', {owner: ownerName}) + : props.translate('iou.youpaid', {owner: ownerName})} + + ) + : ( + + {props.iouReport.hasOutstandingIOU + ? props.translate('iou.owesyou', {manager: managerName}) + : props.translate('iou.paidyou', {manager: managerName})} + + )} + {(isCurrentUserManager + && !props.shouldHidePayButton + && props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && ( + + + {props.translate('iou.pay')} + + + ))} + + + )} + + + ); +}; IOUPreview.propTypes = propTypes; IOUPreview.defaultProps = defaultProps; +IOUPreview.displayName = 'IOUPreview'; export default compose( withLocalize, From 8081c509ebffffe7deda83fb16da15309adeef22 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 18:11:48 -0700 Subject: [PATCH 20/49] rm iouReportID prop --- src/components/ReportActionItem/IOUAction.js | 1 - src/components/ReportActionItem/IOUPreview.js | 8 -------- src/pages/iou/IOUDetailsModal.js | 1 - 3 files changed, 10 deletions(-) diff --git a/src/components/ReportActionItem/IOUAction.js b/src/components/ReportActionItem/IOUAction.js index affa1035eb64..214bfd946377 100644 --- a/src/components/ReportActionItem/IOUAction.js +++ b/src/components/ReportActionItem/IOUAction.js @@ -62,7 +62,6 @@ const IOUAction = (props) => { {shouldShowIOUPreview && ( { // Pay button should only be visible to the manager of the report. const isCurrentUserManager = managerEmail === sessionEmail; const reportIsLoading = _.isEmpty(props.iouReport); - - if (reportIsLoading) { - Report.fetchIOUReportByID(props.iouReportID, props.chatReportID); - } - const managerName = lodashGet(props.personalDetails, [managerEmail, 'firstName'], '') || Str.removeSMSDomain(managerEmail); const ownerName = lodashGet(props.personalDetails, [ownerEmail, 'firstName'], '') || Str.removeSMSDomain(ownerEmail); diff --git a/src/pages/iou/IOUDetailsModal.js b/src/pages/iou/IOUDetailsModal.js index 0d45271ab5b1..1022053bc962 100644 --- a/src/pages/iou/IOUDetailsModal.js +++ b/src/pages/iou/IOUDetailsModal.js @@ -149,7 +149,6 @@ class IOUDetailsModal extends Component { Date: Tue, 13 Dec 2022 18:12:34 -0700 Subject: [PATCH 21/49] rm isLoadingReport --- src/components/ReportActionItem/IOUPreview.js | 138 +++++++++--------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 40c94045df9d..6cd0e2b57f71 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -113,7 +113,7 @@ const IOUPreview = (props) => { // Pay button should only be visible to the manager of the report. const isCurrentUserManager = managerEmail === sessionEmail; - const reportIsLoading = _.isEmpty(props.iouReport); + const managerName = lodashGet(props.personalDetails, [managerEmail, 'firstName'], '') || Str.removeSMSDomain(managerEmail); const ownerName = lodashGet(props.personalDetails, [ownerEmail, 'firstName'], '') || Str.removeSMSDomain(ownerEmail); @@ -128,78 +128,74 @@ const IOUPreview = (props) => { return ( - {reportIsLoading - ? - : ( - { - PaymentMethods.clearWalletTermsError(); - Report.clearIOUError(props.chatReportID); - }} - errorRowStyles={[styles.mbn1]} - > - - - - - {cachedTotal} - - {!props.iouReport.hasOutstandingIOU && ( - - - - )} - - - + { + PaymentMethods.clearWalletTermsError(); + Report.clearIOUError(props.chatReportID); + }} + errorRowStyles={[styles.mbn1]} + > + + + + + {cachedTotal} + + {!props.iouReport.hasOutstandingIOU && ( + + - - {isCurrentUserManager - ? ( - - {props.iouReport.hasOutstandingIOU - ? props.translate('iou.youowe', {owner: ownerName}) - : props.translate('iou.youpaid', {owner: ownerName})} - - ) - : ( - - {props.iouReport.hasOutstandingIOU - ? props.translate('iou.owesyou', {manager: managerName}) - : props.translate('iou.paidyou', {manager: managerName})} - - )} - {(isCurrentUserManager - && !props.shouldHidePayButton - && props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && ( - - - {props.translate('iou.pay')} - - - ))} + )} + + + - - )} + + {isCurrentUserManager + ? ( + + {props.iouReport.hasOutstandingIOU + ? props.translate('iou.youowe', {owner: ownerName}) + : props.translate('iou.youpaid', {owner: ownerName})} + + ) + : ( + + {props.iouReport.hasOutstandingIOU + ? props.translate('iou.owesyou', {manager: managerName}) + : props.translate('iou.paidyou', {manager: managerName})} + + )} + {(isCurrentUserManager + && !props.shouldHidePayButton + && props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && ( + + + {props.translate('iou.pay')} + + + ))} + + ); From dca62bd52329de8a26572eb60ca6fbb9ab793f63 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 13 Dec 2022 18:18:47 -0700 Subject: [PATCH 22/49] rm unused import --- src/components/ReportActionItem/IOUPreview.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 6cd0e2b57f71..11ae9eb3bb5b 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -1,7 +1,6 @@ import React from 'react'; import { View, - ActivityIndicator, TouchableOpacity, TouchableWithoutFeedback, } from 'react-native'; From 25660d0af5f9d468684a6f0037ad5de50bd3a7d3 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 14 Dec 2022 13:41:51 -0700 Subject: [PATCH 23/49] revert prop removal and suppress lint error --- src/components/ReportActionItem/IOUAction.js | 1 + src/components/ReportActionItem/IOUPreview.js | 4 ++++ src/pages/iou/IOUDetailsModal.js | 1 + 3 files changed, 6 insertions(+) diff --git a/src/components/ReportActionItem/IOUAction.js b/src/components/ReportActionItem/IOUAction.js index 214bfd946377..affa1035eb64 100644 --- a/src/components/ReportActionItem/IOUAction.js +++ b/src/components/ReportActionItem/IOUAction.js @@ -62,6 +62,7 @@ const IOUAction = (props) => { {shouldShowIOUPreview && ( Date: Thu, 15 Dec 2022 10:27:19 -0700 Subject: [PATCH 24/49] rm unused iou prop --- src/pages/iou/IOUDetailsModal.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/IOUDetailsModal.js b/src/pages/iou/IOUDetailsModal.js index 0d45271ab5b1..8dc72c5aba6b 100644 --- a/src/pages/iou/IOUDetailsModal.js +++ b/src/pages/iou/IOUDetailsModal.js @@ -147,7 +147,6 @@ class IOUDetailsModal extends Component { Date: Thu, 15 Dec 2022 14:59:51 -0700 Subject: [PATCH 25/49] Add specific style for keyboard highlight --- src/styles/styles.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/styles/styles.js b/src/styles/styles.js index baac1d8f3386..a7c407de558d 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -1475,6 +1475,13 @@ const styles = { backgroundColor: themeColors.buttonDefaultBG, }, + emojiItemKeyboardHighlighted: { + transition: '0.2s ease', + borderWidth: 1, + borderColor: themeColors.link, + borderRadius: variables.buttonBorderRadius, + }, + chatItemEmojiButton: { alignSelf: 'flex-end', borderRadius: variables.buttonBorderRadius, From fc1efdc52a3e356cf6392b278c30c9f85efcd391 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 15 Dec 2022 17:27:43 -0700 Subject: [PATCH 26/49] Add new prop for when the user is using keyboard highlighting --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 3 +++ src/components/EmojiPicker/EmojiPickerMenuItem.js | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 2d97a24439fa..b8411c82ffa1 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -101,6 +101,7 @@ class EmojiPickerMenu extends Component { end: 0, }, isFocused: false, + isUsingKeyboardMovement: false, }; } @@ -246,6 +247,7 @@ class EmojiPickerMenu extends Component { return; } this.searchInput.blur(); + this.setState({isUsingKeyboardMovement: true}); // We only want to hightlight the Emoji if none was highlighted already // If we already have a highlighted Emoji, lets just skip the first navigation @@ -449,6 +451,7 @@ class EmojiPickerMenu extends Component { }} emoji={emojiCode} isHighlighted={index === this.state.highlightedIndex} + isUsingKeyboardMovement={this.state.isUsingKeyboardMovement} /> ); } diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem.js b/src/components/EmojiPicker/EmojiPickerMenuItem.js index a0c0ab2f71d6..c25884a35157 100644 --- a/src/components/EmojiPicker/EmojiPickerMenuItem.js +++ b/src/components/EmojiPicker/EmojiPickerMenuItem.js @@ -21,6 +21,9 @@ const propTypes = { /** Whether this menu item is currently highlighted or not */ isHighlighted: PropTypes.bool, + + /** Whether the emoji is highlighted by the keyboard/mouse */ + isUsingKeyboardMovement: PropTypes.bool, }; const EmojiPickerMenuItem = props => ( @@ -32,7 +35,8 @@ const EmojiPickerMenuItem = props => ( pressed, }) => ([ StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)), - props.isHighlighted ? styles.emojiItemHighlighted : {}, + props.isHighlighted && props.isUsingKeyboardMovement ? styles.emojiItemKeyboardHighlighted : {}, + props.isHighlighted && !props.isUsingKeyboardMovement ? styles.emojiItemHighlighted : {}, styles.emojiItem, ])} > @@ -46,6 +50,7 @@ EmojiPickerMenuItem.propTypes = propTypes; EmojiPickerMenuItem.displayName = 'EmojiPickerMenuItem'; EmojiPickerMenuItem.defaultProps = { isHighlighted: false, + isUsingKeyboardMovement: false, onHoverIn: () => {}, onHoverOut: () => {}, }; From 550756f2acab4b5f5872a24354528f6a82acd625 Mon Sep 17 00:00:00 2001 From: Jules Rosser Date: Fri, 16 Dec 2022 16:42:19 +0000 Subject: [PATCH 27/49] introduce Android notification channel --- .../CustomNotificationProvider.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 deeff81bf76d..aa03e26a9931 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 @@ -1,5 +1,7 @@ package com.expensify.chat.customairshipextender; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -8,11 +10,13 @@ import android.graphics.Bitmap.Config; import android.graphics.PorterDuffXfermode; import android.graphics.PorterDuff.Mode; +import android.os.Build; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.WindowManager; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.core.app.Person; @@ -48,6 +52,9 @@ public class CustomNotificationProvider extends ReactNotificationProvider { // Logging private static final String TAG = "NotificationProvider"; + // Define notification channel + public static final String CHANNEL_MESSAGES_ID = "CHANNEL_MESSAGES"; + public static final String CHANNEL_MESSAGES_NAME = "Message Notifications"; // Conversation JSON keys private static final String PAYLOAD_KEY = "payload"; private static final String TYPE_KEY = "type"; @@ -58,6 +65,9 @@ public class CustomNotificationProvider extends ReactNotificationProvider { public CustomNotificationProvider(@NonNull Context context, @NonNull AirshipConfigOptions configOptions) { super(context, configOptions); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createAndRegisterNotificationChannel(context); + } } @NonNull @@ -82,6 +92,14 @@ protected NotificationCompat.Builder onExtendBuilder(@NonNull Context context, @ return builder; } + @RequiresApi(api = Build.VERSION_CODES.O) + private void createAndRegisterNotificationChannel(@NonNull Context context) { + NotificationChannel channel = new NotificationChannel(CHANNEL_MESSAGES_ID, CHANNEL_MESSAGES_NAME, NotificationManager.IMPORTANCE_HIGH); + + NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(channel); + } + /** * Creates a canvas to draw a circle and then draws the bitmap avatar within that circle * to clip off the area of the bitmap outside the circular path and returns a circular From 58932f65da3be6948825df4cb5e487f220f1f566 Mon Sep 17 00:00:00 2001 From: Jules Rosser Date: Fri, 16 Dec 2022 16:43:12 +0000 Subject: [PATCH 28/49] increase Android notification priority, show above other apps --- .../CustomNotificationProvider.java | 9 +++++++++ 1 file changed, 9 insertions(+) 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 aa03e26a9931..3dc4e63814d6 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 @@ -1,5 +1,7 @@ package com.expensify.chat.customairshipextender; +import static androidx.core.app.NotificationCompat.PRIORITY_MAX; + import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; @@ -76,6 +78,13 @@ protected NotificationCompat.Builder onExtendBuilder(@NonNull Context context, @ super.onExtendBuilder(context, builder, arguments); PushMessage message = arguments.getMessage(); + // Configure the notification channel or priority to ensure it shows in foreground + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder.setChannelId(CHANNEL_MESSAGES_ID); + } else { + builder.setPriority(PRIORITY_MAX); + } + if (message.containsKey(PAYLOAD_KEY)) { try { JsonMap payload = JsonValue.parseString(message.getExtra(PAYLOAD_KEY)).optMap(); From fb01fc4e71b0876d50368b42b21d85e9942b2d01 Mon Sep 17 00:00:00 2001 From: Jules Rosser Date: Fri, 16 Dec 2022 16:43:37 +0000 Subject: [PATCH 29/49] introduce Android notification channel grouping --- .../customairshipextender/CustomNotificationProvider.java | 7 +++++++ 1 file changed, 7 insertions(+) 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 3dc4e63814d6..7c1f4a245cd2 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 @@ -3,6 +3,7 @@ import static androidx.core.app.NotificationCompat.PRIORITY_MAX; import android.app.NotificationChannel; +import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.content.Context; import android.graphics.Bitmap; @@ -57,6 +58,9 @@ public class CustomNotificationProvider extends ReactNotificationProvider { // Define notification channel public static final String CHANNEL_MESSAGES_ID = "CHANNEL_MESSAGES"; public static final String CHANNEL_MESSAGES_NAME = "Message Notifications"; + public static final String CHANNEL_GROUP_ID = "CHANNEL_GROUP_CHATS"; + public static final String CHANNEL_GROUP_NAME = "Chats"; + // Conversation JSON keys private static final String PAYLOAD_KEY = "payload"; private static final String TYPE_KEY = "type"; @@ -103,9 +107,12 @@ protected NotificationCompat.Builder onExtendBuilder(@NonNull Context context, @ @RequiresApi(api = Build.VERSION_CODES.O) private void createAndRegisterNotificationChannel(@NonNull Context context) { + NotificationChannelGroup channelGroup = new NotificationChannelGroup(CHANNEL_GROUP_ID, CHANNEL_GROUP_NAME); NotificationChannel channel = new NotificationChannel(CHANNEL_MESSAGES_ID, CHANNEL_MESSAGES_NAME, NotificationManager.IMPORTANCE_HIGH); + channel.setGroup(CHANNEL_GROUP_ID); NotificationManager notificationManager = context.getSystemService(NotificationManager.class); + notificationManager.createNotificationChannelGroup(channelGroup); notificationManager.createNotificationChannel(channel); } From a2f795c9a489de69f6d19407aa0be9a737173a4f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 16 Dec 2022 13:17:52 -0700 Subject: [PATCH 30/49] disable checkbox and change cursor --- src/components/CheckboxWithTooltip/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CheckboxWithTooltip/index.js b/src/components/CheckboxWithTooltip/index.js index 83756feb0bc3..e6cba3ebaae8 100644 --- a/src/components/CheckboxWithTooltip/index.js +++ b/src/components/CheckboxWithTooltip/index.js @@ -22,7 +22,7 @@ const CheckboxWithTooltip = (props) => { ); return ( From b354a4757f7ba93c38d1d98cd9005d9c77bb72c2 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 16 Dec 2022 13:58:33 -0700 Subject: [PATCH 31/49] fix link style --- src/pages/signin/ResendValidationForm.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/signin/ResendValidationForm.js b/src/pages/signin/ResendValidationForm.js index 8854905a47e8..0d5368ae190b 100755 --- a/src/pages/signin/ResendValidationForm.js +++ b/src/pages/signin/ResendValidationForm.js @@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import Str from 'expensify-common/lib/str'; import styles from '../../styles/styles'; +import themeColors from '../../styles/themes/default'; import Button from '../../components/Button'; import Text from '../../components/Text'; import * as Session from '../../libs/actions/Session'; @@ -79,8 +80,11 @@ const ResendValidationForm = (props) => { )} - redirectToSignIn()}> - + redirectToSignIn()} + underlayColor={themeColors.componentBG} + > + {props.translate('common.back')} From b2f768e65b88c17a6277f1538392874acf383d26 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 16 Dec 2022 14:24:57 -0700 Subject: [PATCH 32/49] disable checkbox on resize --- .../CheckboxWithTooltipForMobileWebAndNative.js | 1 + src/components/CheckboxWithTooltip/index.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js b/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js index ac58d030e962..43d3c062608b 100644 --- a/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js +++ b/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js @@ -38,6 +38,7 @@ class CheckboxWithTooltipForMobileWebAndNative extends React.Component { ); diff --git a/src/components/CheckboxWithTooltip/index.js b/src/components/CheckboxWithTooltip/index.js index e6cba3ebaae8..ced15a589acb 100644 --- a/src/components/CheckboxWithTooltip/index.js +++ b/src/components/CheckboxWithTooltip/index.js @@ -15,6 +15,7 @@ const CheckboxWithTooltip = (props) => { onPress={props.onPress} text={props.text} toggleTooltip={props.toggleTooltip} + disabled={props.disabled} /> ); } From 99d68ddc4b770ba53433736e5acc245e8257d934 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 16 Dec 2022 14:59:29 -0700 Subject: [PATCH 33/49] rm invalid underlayColor prop --- src/pages/home/report/ReportActionCompose.js | 4 ---- src/pages/signin/ChangeExpensifyLoginLink.js | 2 -- src/pages/signin/PasswordForm.js | 1 - src/pages/signin/ResendValidationForm.js | 2 -- 4 files changed, 9 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 7811d1c25ee1..ff7bb85ced53 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -571,7 +571,6 @@ class ReportActionCompose extends React.Component { // Keep focus on the composer when Collapse button is clicked. onMouseDown={e => e.preventDefault()} style={styles.composerSizeButton} - underlayColor={themeColors.componentBG} disabled={isBlockedFromConcierge} > @@ -590,7 +589,6 @@ class ReportActionCompose extends React.Component { // Keep focus on the composer when Expand button is clicked. onMouseDown={e => e.preventDefault()} style={styles.composerSizeButton} - underlayColor={themeColors.componentBG} disabled={isBlockedFromConcierge} > @@ -608,7 +606,6 @@ class ReportActionCompose extends React.Component { this.setMenuVisibility(true); }} style={styles.chatItemAttachButton} - underlayColor={themeColors.componentBG} disabled={isBlockedFromConcierge} > @@ -699,7 +696,6 @@ class ReportActionCompose extends React.Component { (this.state.isCommentEmpty || hasExceededMaxCommentLength) ? undefined : styles.buttonSuccess, ]} onPress={this.submitForm} - underlayColor={themeColors.componentBG} // Keep focus on the composer when Send message is clicked. // eslint-disable-next-line react/jsx-props-no-multi-spaces diff --git a/src/pages/signin/ChangeExpensifyLoginLink.js b/src/pages/signin/ChangeExpensifyLoginLink.js index 45528e6594e1..8289a754deaf 100755 --- a/src/pages/signin/ChangeExpensifyLoginLink.js +++ b/src/pages/signin/ChangeExpensifyLoginLink.js @@ -5,7 +5,6 @@ import PropTypes from 'prop-types'; import Str from 'expensify-common/lib/str'; import Text from '../../components/Text'; import styles from '../../styles/styles'; -import themeColors from '../../styles/themes/default'; import ONYXKEYS from '../../ONYXKEYS'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import compose from '../../libs/compose'; @@ -42,7 +41,6 @@ const ChangeExpensifyLoginLink = props => ( {props.translate('common.goBack')} diff --git a/src/pages/signin/PasswordForm.js b/src/pages/signin/PasswordForm.js index f2e2c3558481..0ae644469d6c 100755 --- a/src/pages/signin/PasswordForm.js +++ b/src/pages/signin/PasswordForm.js @@ -162,7 +162,6 @@ class PasswordForm extends React.Component { {this.props.translate('passwordForm.forgot')} diff --git a/src/pages/signin/ResendValidationForm.js b/src/pages/signin/ResendValidationForm.js index 0d5368ae190b..b29d04dca10b 100755 --- a/src/pages/signin/ResendValidationForm.js +++ b/src/pages/signin/ResendValidationForm.js @@ -5,7 +5,6 @@ import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import Str from 'expensify-common/lib/str'; import styles from '../../styles/styles'; -import themeColors from '../../styles/themes/default'; import Button from '../../components/Button'; import Text from '../../components/Text'; import * as Session from '../../libs/actions/Session'; @@ -82,7 +81,6 @@ const ResendValidationForm = (props) => { redirectToSignIn()} - underlayColor={themeColors.componentBG} > {props.translate('common.back')} From 6812a44319d907248fd6cbf38786db52591b15e3 Mon Sep 17 00:00:00 2001 From: staszekscp Date: Fri, 16 Dec 2022 22:59:39 +0100 Subject: [PATCH 34/49] fix QR code for web --- .github/workflows/testBuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 98b75f7da3de..edadad1fdca4 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -267,6 +267,6 @@ jobs: | ![Android](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${{fromJson(steps.set_var.outputs.android_paths).html_path}}) | ![iOS](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${{fromJson(steps.set_var.outputs.ios_paths).html_path}}) | | desktop :computer: | web :spider_web: | | https://ad-hoc-expensify-cash.s3.amazonaws.com/desktop/$PULL_REQUEST_NUMBER/NewExpensify.dmg | https://$PULL_REQUEST_NUMBER.pr-testing.expensify.com | - | ![desktop](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://ad-hoc-expensify-cash.s3.amazonaws.com/desktop/$PULL_REQUEST_NUMBER/NewExpensify.dmg) | ![web](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://$(PULL_REQUEST_NUMBER).pr-testing.expensify.com) |" + | ![desktop](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://ad-hoc-expensify-cash.s3.amazonaws.com/desktop/$PULL_REQUEST_NUMBER/NewExpensify.dmg) | ![web](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://$PULL_REQUEST_NUMBER.pr-testing.expensify.com) |" env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} From add1203e81368be1c7ffd2287dc1a1024c03793f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 16 Dec 2022 15:05:17 -0700 Subject: [PATCH 35/49] undo change to onPress --- src/pages/signin/ResendValidationForm.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/signin/ResendValidationForm.js b/src/pages/signin/ResendValidationForm.js index b29d04dca10b..7753faa65294 100755 --- a/src/pages/signin/ResendValidationForm.js +++ b/src/pages/signin/ResendValidationForm.js @@ -79,9 +79,7 @@ const ResendValidationForm = (props) => { )} - redirectToSignIn()} - > + redirectToSignIn()}> {props.translate('common.back')} From 11e5cd26339ef3ecf8cba9ce6569dcf858e76ada Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 16 Dec 2022 15:25:20 -0700 Subject: [PATCH 36/49] When we hover, turn the normal background back on --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index b8411c82ffa1..1090e0d305e0 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -442,7 +442,7 @@ class EmojiPickerMenu extends Component { return ( this.addToFrequentAndSelectEmoji(emoji, item)} - onHoverIn={() => this.setState({highlightedIndex: index})} + onHoverIn={() => this.setState({highlightedIndex: index, isUsingKeyboardMovement: false})} onHoverOut={() => { if (this.state.arePointerEventsDisabled) { return; From 024d684c4af5bc3fd1b123b9cbdf8bb73cbf8a03 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 16 Dec 2022 15:25:59 -0700 Subject: [PATCH 37/49] Any time the search bar is focused, reset the highlighted emoji and turn off keyboard movement styles --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 1090e0d305e0..90daba2950ba 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -475,7 +475,7 @@ class EmojiPickerMenu extends Component { autoFocus selectTextOnFocus={this.state.selectTextOnFocus} onSelectionChange={this.onSelectionChange} - onFocus={() => this.setState({isFocused: true})} + onFocus={() => this.setState({isFocused: true, highlightedIndex: -1, isUsingKeyboardMovement: false})} onBlur={() => this.setState({isFocused: false})} /> From 42ace8603beb73dff09bf637a7abd1483bf0b92f Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 16 Dec 2022 15:35:24 -0700 Subject: [PATCH 38/49] Update propsAreEqual to also change when the keyboard movement prop is updated --- src/components/EmojiPicker/EmojiPickerMenuItem.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem.js b/src/components/EmojiPicker/EmojiPickerMenuItem.js index c25884a35157..86e9a1cf2436 100644 --- a/src/components/EmojiPicker/EmojiPickerMenuItem.js +++ b/src/components/EmojiPicker/EmojiPickerMenuItem.js @@ -59,6 +59,8 @@ EmojiPickerMenuItem.defaultProps = { // by only re-rendering at most two EmojiPickerMenuItems that are highlighted/un-highlighted per user action. export default React.memo( EmojiPickerMenuItem, - (prevProps, nextProps) => prevProps.isHighlighted === nextProps.isHighlighted - && prevProps.emoji === nextProps.emoji, + (prevProps, nextProps) => + prevProps.isHighlighted === nextProps.isHighlighted + && prevProps.emoji === nextProps.emoji + && prevProps.isUsingKeyboardMovement === nextProps.isUsingKeyboardMovement, ); From 0c058e5560579c668bc830c2f24028c8090c99a3 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 16 Dec 2022 15:42:43 -0700 Subject: [PATCH 39/49] Always set keyboardMovement to true when moving --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 90daba2950ba..439fb11c56c6 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -317,7 +317,7 @@ class EmojiPickerMenu extends Component { // Actually highlight the new emoji and scroll to it if the index was changed if (newIndex !== this.state.highlightedIndex) { - this.setState({highlightedIndex: newIndex}); + this.setState({highlightedIndex: newIndex, isUsingKeyboardMovement: true}); this.scrollToHighlightedIndex(); } } From 37a154b2666711d4d1fd64d2bdf96d59fea923b8 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 16 Dec 2022 15:48:05 -0700 Subject: [PATCH 40/49] Add comments to areas where it may be confusing --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 439fb11c56c6..ab68b51802c1 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -246,6 +246,8 @@ class EmojiPickerMenu extends Component { ) { return; } + + // Blur the input and change the highlight type to keyboard this.searchInput.blur(); this.setState({isUsingKeyboardMovement: true}); @@ -315,7 +317,7 @@ class EmojiPickerMenu extends Component { break; } - // Actually highlight the new emoji and scroll to it if the index was changed + // Actually highlight the new emoji, apply keyboard movement styles, and scroll to it if the index was changed if (newIndex !== this.state.highlightedIndex) { this.setState({highlightedIndex: newIndex, isUsingKeyboardMovement: true}); this.scrollToHighlightedIndex(); From 7f5a88ecb2e107d37d103744f84b69458e37273c Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 16 Dec 2022 15:57:37 -0700 Subject: [PATCH 41/49] Remove line break for linter --- src/components/EmojiPicker/EmojiPickerMenuItem.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem.js b/src/components/EmojiPicker/EmojiPickerMenuItem.js index 86e9a1cf2436..60be79adb9d5 100644 --- a/src/components/EmojiPicker/EmojiPickerMenuItem.js +++ b/src/components/EmojiPicker/EmojiPickerMenuItem.js @@ -59,8 +59,7 @@ EmojiPickerMenuItem.defaultProps = { // by only re-rendering at most two EmojiPickerMenuItems that are highlighted/un-highlighted per user action. export default React.memo( EmojiPickerMenuItem, - (prevProps, nextProps) => - prevProps.isHighlighted === nextProps.isHighlighted + (prevProps, nextProps) => prevProps.isHighlighted === nextProps.isHighlighted && prevProps.emoji === nextProps.emoji && prevProps.isUsingKeyboardMovement === nextProps.isUsingKeyboardMovement, ); From 2ab2bcab2dca071c29194c63f78dc687ce73754f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Mon, 19 Dec 2022 11:20:01 -0700 Subject: [PATCH 42/49] add proptype --- .../CheckboxWithTooltip/checkboxWithTooltipPropTypes.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js b/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js index e0aa67e85b26..f764e216156b 100644 --- a/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js +++ b/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js @@ -22,6 +22,9 @@ const propTypes = { /** Container styles */ style: stylePropTypes, + /** Wheter the checkbox is disabled */ + disabled: PropTypes.bool, + /** Props inherited from withWindowDimensions */ ...windowDimensionsPropTypes, }; From 23a4b71eeebd8ec2bda17776b9151b0db38cd876 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Tue, 20 Dec 2022 00:54:21 +0000 Subject: [PATCH 43/49] Update version to 1.2.41-4 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index fb08766d230f..3682bff35fd3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001024103 - versionName "1.2.41-3" + versionCode 1001024104 + versionName "1.2.41-4" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 5655a13a353c..3a9a1d9887a3 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.41.3 + 1.2.41.4 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index e82772c4259b..b67e49afb237 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.2.41.3 + 1.2.41.4 diff --git a/package-lock.json b/package-lock.json index ac7cc5424abd..4c9d7ca917b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.41-3", + "version": "1.2.41-4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.41-3", + "version": "1.2.41-4", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 918cf4ef3dc4..3f2eb5677417 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.41-3", + "version": "1.2.41-4", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From d6293e4dd8c5f1b58c808587a0cb7ab5365aa5fe Mon Sep 17 00:00:00 2001 From: OSBotify Date: Tue, 20 Dec 2022 05:40:56 +0000 Subject: [PATCH 44/49] Update version to 1.2.42-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 3682bff35fd3..bd02f2bad317 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001024104 - versionName "1.2.41-4" + versionCode 1001024200 + versionName "1.2.42-0" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 3a9a1d9887a3..ef97d47567bd 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.41 + 1.2.42 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.41.4 + 1.2.42.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index b67e49afb237..578c452cf5c6 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.2.41 + 1.2.42 CFBundleSignature ???? CFBundleVersion - 1.2.41.4 + 1.2.42.0 diff --git a/package-lock.json b/package-lock.json index 4c9d7ca917b3..be3191859194 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.41-4", + "version": "1.2.42-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.41-4", + "version": "1.2.42-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 3f2eb5677417..71087807bff1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.41-4", + "version": "1.2.42-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 5cc7a511a8859179cc8af0447ded71bdf00f7755 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Tue, 20 Dec 2022 13:18:26 +0000 Subject: [PATCH 45/49] Update version to 1.2.42-1 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index bd02f2bad317..36db063b9177 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001024200 - versionName "1.2.42-0" + versionCode 1001024201 + versionName "1.2.42-1" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index ef97d47567bd..0f8cf931636f 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.42.0 + 1.2.42.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 578c452cf5c6..0ab913d00326 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.2.42.0 + 1.2.42.1 diff --git a/package-lock.json b/package-lock.json index be3191859194..8a64675399b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.42-0", + "version": "1.2.42-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.42-0", + "version": "1.2.42-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 71087807bff1..e40ecdc2286e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.42-0", + "version": "1.2.42-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From ed2bedbdd872a9c8402263a7c9e2e630c6d6b495 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 20 Dec 2022 09:50:16 -0700 Subject: [PATCH 46/49] update location usage key --- ios/NewExpensify/Info.plist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 0f8cf931636f..156814e54037 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.42 + 1.2.41 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.42.1 + 1.2.41.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes @@ -65,8 +65,8 @@ NSCameraUsageDescription Your camera is used to create chat attachments, documents, and facial capture. - NSLocationWhenInUseUsageDescription - Your location is used to determine your default currency. + NSLocationAlwaysAndWhenInUseUsageDescription + Your location is used to determine your default currency and timezone. NSMicrophoneUsageDescription Required for video capture NSPhotoLibraryAddUsageDescription From 0fd6dc6fe95f0e434f102a3b4227ecae5368c24d Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 20 Dec 2022 10:05:54 -0700 Subject: [PATCH 47/49] fix bundle version --- ios/NewExpensify/Info.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 156814e54037..2088673e7654 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.41 + 1.2.42 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.41.2 + 1.2.42.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes From d6b2e3e0615734cf7367826471fc4b2dcfa753eb Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Tue, 20 Dec 2022 14:45:16 -0800 Subject: [PATCH 48/49] Troubleshooting seciton --- docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/README.md b/docs/README.md index 0ff0d480ee41..bcaed298f593 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,6 +41,12 @@ ln -sf universal-darwin22 universal-darwin21 - _Note: If you see an error like `Unable to load the EventMachine C Extension...`, try running `gem uninstall eventmachine && bundle install`. If that doesn't work just removing the `--livereload` flag should work._ 1. Modify a `.html` or `.md` file and save your changes, and the browser should quickly auto-refresh. +## Troubleshooting + +### Android Chrome emulator +To visit the site on the Android emulator, go to `10.0.2.2:4000`. + + # How the project is structured The [docs](https://github.com/Expensify/App/tree/main/docs) folder will contain the following main folders: From c874a71d8f65cea8d0284915fe52b1f52983f128 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Tue, 20 Dec 2022 14:46:28 -0800 Subject: [PATCH 49/49] added error condition --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/README.md b/docs/README.md index bcaed298f593..9193439c4b59 100644 --- a/docs/README.md +++ b/docs/README.md @@ -46,6 +46,8 @@ ln -sf universal-darwin22 universal-darwin21 ### Android Chrome emulator To visit the site on the Android emulator, go to `10.0.2.2:4000`. +If you're getting an error page that says "Refused to connect", try running `adb reverse tcp:4000 tcp:4000` with your emulator open. + # How the project is structured