From 023cfdfe48a97f199292d32a4a93f9615c5ad312 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Fri, 15 Sep 2023 06:10:12 +0100 Subject: [PATCH 01/43] migrate withViewportOffsetTop.js class to function component --- src/components/withViewportOffsetTop.js | 58 ++++++++++--------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/src/components/withViewportOffsetTop.js b/src/components/withViewportOffsetTop.js index 113c72ed1e1a..722347a6b307 100644 --- a/src/components/withViewportOffsetTop.js +++ b/src/components/withViewportOffsetTop.js @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; +import React, {useEffect, forwardRef, useState, useCallback} from 'react'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import getComponentDisplayName from '../libs/getComponentDisplayName'; @@ -13,43 +13,33 @@ const viewportOffsetTopPropTypes = { }; export default function (WrappedComponent) { - class WithViewportOffsetTop extends Component { - constructor(props) { - super(props); - - this.updateDimensions = this.updateDimensions.bind(this); - - this.state = { - viewportOffsetTop: 0, - }; - } - - componentDidMount() { - this.removeViewportResizeListener = addViewportResizeListener(this.updateDimensions); - } - - componentWillUnmount() { - this.removeViewportResizeListener(); - } + function WithViewportOffsetTop(props) { + const [viewportOffsetTop, setViewportOffsetTop] = useState(0); /** * @param {SyntheticEvent} e */ - updateDimensions(e) { - const viewportOffsetTop = lodashGet(e, 'target.offsetTop', 0); - this.setState({viewportOffsetTop}); - } + const updateDimensions = useCallback((e) => { + const viewPortOffsetTop = lodashGet(e, 'target.offsetTop', 0); + setViewportOffsetTop(viewPortOffsetTop); + }, []); + + useEffect(() => { + const removeViewportResizeListener = addViewportResizeListener(updateDimensions); - render() { - return ( - - ); - } + return () => { + removeViewportResizeListener(); + }; + }, [updateDimensions]); + + return ( + + ); } WithViewportOffsetTop.displayName = `WithViewportOffsetTop(${getComponentDisplayName(WrappedComponent)})`; @@ -59,7 +49,7 @@ export default function (WrappedComponent) { WithViewportOffsetTop.defaultProps = { forwardedRef: undefined, }; - return React.forwardRef((props, ref) => ( + return forwardRef((props, ref) => ( Date: Fri, 15 Sep 2023 09:31:06 +0100 Subject: [PATCH 02/43] move updateDimensions to useEffect --- src/components/withViewportOffsetTop.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/withViewportOffsetTop.js b/src/components/withViewportOffsetTop.js index 722347a6b307..5dc795ad2750 100644 --- a/src/components/withViewportOffsetTop.js +++ b/src/components/withViewportOffsetTop.js @@ -1,4 +1,4 @@ -import React, {useEffect, forwardRef, useState, useCallback} from 'react'; +import React, {useEffect, forwardRef, useState} from 'react'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import getComponentDisplayName from '../libs/getComponentDisplayName'; @@ -16,21 +16,21 @@ export default function (WrappedComponent) { function WithViewportOffsetTop(props) { const [viewportOffsetTop, setViewportOffsetTop] = useState(0); - /** - * @param {SyntheticEvent} e - */ - const updateDimensions = useCallback((e) => { - const viewPortOffsetTop = lodashGet(e, 'target.offsetTop', 0); - setViewportOffsetTop(viewPortOffsetTop); - }, []); - useEffect(() => { + /** + * @param {SyntheticEvent} e + */ + const updateDimensions = (e) => { + const targetOffsetTop = lodashGet(e, 'target.offsetTop', 0); + setViewportOffsetTop(targetOffsetTop); + }; + const removeViewportResizeListener = addViewportResizeListener(updateDimensions); return () => { removeViewportResizeListener(); }; - }, [updateDimensions]); + }, []); return ( Date: Fri, 15 Sep 2023 10:12:09 +0100 Subject: [PATCH 03/43] fix lint issue --- src/components/withViewportOffsetTop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/withViewportOffsetTop.js b/src/components/withViewportOffsetTop.js index 5dc795ad2750..ccf928b3bd13 100644 --- a/src/components/withViewportOffsetTop.js +++ b/src/components/withViewportOffsetTop.js @@ -24,7 +24,7 @@ export default function (WrappedComponent) { const targetOffsetTop = lodashGet(e, 'target.offsetTop', 0); setViewportOffsetTop(targetOffsetTop); }; - + const removeViewportResizeListener = addViewportResizeListener(updateDimensions); return () => { From b0afc326530380553cabc23e98ebb7cccfddcf47 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sun, 8 Oct 2023 19:35:21 +0530 Subject: [PATCH 04/43] made setupNewDotWebForEmulators script --- package.json | 3 +- scripts/select-device.sh | 87 +++++++++++++++++ scripts/setup-newdot-web-emulators.sh | 130 ++++++++++++++++++++++++++ scripts/shellUtils.sh | 29 +++++- 4 files changed, 243 insertions(+), 6 deletions(-) create mode 100755 scripts/select-device.sh create mode 100755 scripts/setup-newdot-web-emulators.sh diff --git a/package.json b/package.json index 9a3b9ed3af86..26937ea33741 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "private": true, "scripts": { "configure-mapbox": "scripts/setup-mapbox-sdk-walkthrough.sh", + "setupNewDotWebForEmulators": "scripts/setup-newdot-web-emulators.sh", "postinstall": "scripts/postInstall.sh", "clean": "npx react-native clean-project-auto", "android": "scripts/set-pusher-suffix.sh && npx react-native run-android --variant=developmentDebug --appId=com.expensify.chat.dev", @@ -114,8 +115,8 @@ "react-collapse": "^5.1.0", "react-content-loader": "^6.1.0", "react-dom": "18.1.0", - "react-map-gl": "^7.1.3", "react-error-boundary": "^4.0.11", + "react-map-gl": "^7.1.3", "react-native": "0.72.4", "react-native-android-location-enabler": "^1.2.2", "react-native-blob-util": "^0.17.3", diff --git a/scripts/select-device.sh b/scripts/select-device.sh new file mode 100755 index 000000000000..47e7cfca227c --- /dev/null +++ b/scripts/select-device.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# Use functions and varaibles from the utils script +source scripts/shellUtils.sh + +select_device_ios() +{ + IFS="$@" arr=$(xcrun xctrace list devices | grep -E "iPhone|iPad") + + # Create arrays to store device names and identifiers + device_names=() + device_identifiers=() + + # Parse the device list and populate the arrays + while IFS= read -r line; do + if [[ $line =~ ^(.*)\ \((.*)\)\ \((.*)\)$ ]]; then + device="${BASH_REMATCH[1]}" + version="${BASH_REMATCH[2]}" + identifier="${BASH_REMATCH[3]}" + device_identifiers+=("$identifier") + device_names+=("$device Version: $version") + else + info "Input does not match the expected pattern." + echo $line + fi + done <<< $arr + if [ ${#device_names[@]} -eq 0 ]; then + error "No devices detected, please create one." + exit 1 + fi + if [ ${#device_names[@]} -eq 1 ]; then + device_identifier="${device_identifiers[0]}" + success "Single device detected, launching ${device_names[0]}" + open -a Simulator --args -CurrentDeviceUDID $device_identifier + return + fi + info "Multiple devices detected, please select one from the list." + PS3='Please enter your choice: ' + select device_name in "${device_names[@]}"; do + if [ -n "$device_name" ]; then + selected_index=$((REPLY - 1)) + device_name_for_display="${device_names[$selected_index]}" + device_identifier="${device_identifiers[$selected_index]}" + break + else + echo "Invalid selection. Please choose a device." + fi + done + success "Launching $device_name_for_display" + open -a Simulator --args -CurrentDeviceUDID $device_identifier +} + +select_device_android() +{ + IFS="$@" arr=$(emulator -list-avds) + + # Create arrays to store device names + device_names=() + + # Parse the device list and populate the arrays + while IFS= read -r line; do + device_names+=("$line") + done <<< $arr + if [ ${#device_names[@]} -eq 0 ]; then + error "No devices detected, please create one." + exit 1 + fi + if [ ${#device_names[@]} -eq 1 ]; then + device_identifier="${device_names[0]}" + success "Single device detected, launching $device_identifier" + emulator -avd $device_names -writable-system > /dev/null 2>&1 & + return + fi + info "Multiple devices detected, please select one from the list." + PS3='Please enter your choice: ' + select device_name in "${device_names[@]}"; do + if [ -n "$device_name" ]; then + selected_index=$((REPLY - 1)) + device_identifier="${device_names[$selected_index]}" + break + else + echo "Invalid selection. Please choose a device." + fi + done + success "Launching $device_identifier" + emulator -avd $device_identifier -writable-system > /dev/null 2>&1 & +} \ No newline at end of file diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh new file mode 100755 index 000000000000..14d99e550d05 --- /dev/null +++ b/scripts/setup-newdot-web-emulators.sh @@ -0,0 +1,130 @@ +#!/bin/bash + +# NewDot Web Configuration Script for iOS and Android Emulators +# ============================================================= +# +# Purpose: +# -------- +# This script configures Configure iOS simulators and Android emulators to connect to +# new.expensify.com.dev over https for local development. +# +# Background: +# ----------- +# We plan to change the URL to serve the App on the development environment from +# localhost:8082 to new.expensify.com.dev. This can be accomplished by adding a new entry +# to the laptop's hosts file along with changes made in the PR. +# However, we're not sure how we can access the App on Safari or Chrome on iOS or Android +# simulators. +# +# How this script helps: +# ---------------------- +# This script streamlines the process of adding the certificates to both android and +# ios platforms. +# +# Usage: +# ------ +# To run this script, pass the platform on which you want to run as a command-line +# argument which can be the following: +# 1. ios +# 2. android +# 3. all (default) +# ./setup-newdot-web-emulators.sh platform + +# Use functions and varaibles from the utils script +source scripts/shellUtils.sh + +# Use functions to select and open the emulator for iOS and Android +source scripts/select-device.sh + +if [ $# -eq 0 ]; then + platform="all" +else + platform=$1 +fi + +setup_ios() +{ + select_device_ios + sleep 5 + info "Installing certificates on iOS simulator" + xcrun simctl keychain booted add-cert ./config/webpack/certificate.pem +} + +restart_adb_server() { + info "Restarting adb ..." + adb kill-server + sleep 2 + adb start-server + sleep 2 + info "Restarting adb done" +} + +ensure_device_available() { + # Must turn off exit on error temporarily + set +e + adb devices | grep -q offline + if [ $? -eq 0 ]; then + restart_adb_server + adb devices | grep -q offline + if [ $? -eq 0 ]; then + error "Device remains 'offline'. Please investigate!" + exit 1 + fi + fi + set -e +} + +setup_android_path_1() +{ + adb root || { + error "Failed to restart adb as root" + info "You may want to check https://stackoverflow.com/a/45668555" + exit 1 + } + sleep 2 + adb remount + adb push /etc/hosts /system/etc/hosts +} + +setup_android_path_2() +{ + adb root || { + error "Failed to restart adb as root" + info "You may want to check https://stackoverflow.com/a/45668555" + exit 1 + } + sleep 2 + adb disable-verity + adb reboot + sleep 30 + ensure_device_available + adb root + sleep 2 + adb remount + adb push /etc/hosts /system/etc/hosts +} + +setup_android() +{ + select_device_android + sleep 5 + info "Installing certificates on Android emulator" + setup_android_path_1 || { + info "Looks like the system partition is read-only" + info "Trying another method to install the certificates" + setup_android_path_2 + } +} + +if [ "$platform" = "ios" ] || [ "$platform" = "all" ]; then + setup_ios || { + error "Failed to setup iOS simulator" + exit 1 + } +fi + +if [ "$platform" = "android" ] || [ "$platform" = "all" ]; then + setup_android +fi + +success "Done!" \ No newline at end of file diff --git a/scripts/shellUtils.sh b/scripts/shellUtils.sh index 4c9e2febc34d..848e6d238254 100644 --- a/scripts/shellUtils.sh +++ b/scripts/shellUtils.sh @@ -1,10 +1,29 @@ #!/bin/bash -declare -r GREEN=$'\e[1;32m' -declare -r RED=$'\e[1;31m' -declare -r BLUE=$'\e[1;34m' -declare -r TITLE=$'\e[1;4;34m' -declare -r RESET=$'\e[0m' +# Check if GREEN has already been defined +if [ -z "${GREEN+x}" ]; then + declare -r GREEN=$'\e[1;32m' +fi + +# Check if RED has already been defined +if [ -z "${RED+x}" ]; then + declare -r RED=$'\e[1;31m' +fi + +# Check if BLUE has already been defined +if [ -z "${BLUE+x}" ]; then + declare -r BLUE=$'\e[1;34m' +fi + +# Check if TITLE has already been defined +if [ -z "${TITLE+x}" ]; then + declare -r TITLE=$'\e[1;4;34m' +fi + +# Check if RESET has already been defined +if [ -z "${RESET+x}" ]; then + declare -r RESET=$'\e[0m' +fi function success { echo "🎉 $GREEN$1$RESET" From b02536a2f2f19349275b80e730e1d57e9a69f7e0 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sun, 8 Oct 2023 20:18:13 +0530 Subject: [PATCH 05/43] fix lint --- scripts/select-device.sh | 16 +++++++++------- scripts/setup-newdot-web-emulators.sh | 6 ++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/select-device.sh b/scripts/select-device.sh index 47e7cfca227c..3c318ede36b6 100755 --- a/scripts/select-device.sh +++ b/scripts/select-device.sh @@ -5,6 +5,7 @@ source scripts/shellUtils.sh select_device_ios() { + # shellcheck disable=SC2124 IFS="$@" arr=$(xcrun xctrace list devices | grep -E "iPhone|iPad") # Create arrays to store device names and identifiers @@ -21,9 +22,9 @@ select_device_ios() device_names+=("$device Version: $version") else info "Input does not match the expected pattern." - echo $line + echo "$line" fi - done <<< $arr + done <<< "$arr" if [ ${#device_names[@]} -eq 0 ]; then error "No devices detected, please create one." exit 1 @@ -31,7 +32,7 @@ select_device_ios() if [ ${#device_names[@]} -eq 1 ]; then device_identifier="${device_identifiers[0]}" success "Single device detected, launching ${device_names[0]}" - open -a Simulator --args -CurrentDeviceUDID $device_identifier + open -a Simulator --args -CurrentDeviceUDID "$device_identifier" return fi info "Multiple devices detected, please select one from the list." @@ -47,11 +48,12 @@ select_device_ios() fi done success "Launching $device_name_for_display" - open -a Simulator --args -CurrentDeviceUDID $device_identifier + open -a Simulator --args -CurrentDeviceUDID "$device_identifier" } select_device_android() { + # shellcheck disable=SC2124 IFS="$@" arr=$(emulator -list-avds) # Create arrays to store device names @@ -60,7 +62,7 @@ select_device_android() # Parse the device list and populate the arrays while IFS= read -r line; do device_names+=("$line") - done <<< $arr + done <<< "$arr" if [ ${#device_names[@]} -eq 0 ]; then error "No devices detected, please create one." exit 1 @@ -68,7 +70,7 @@ select_device_android() if [ ${#device_names[@]} -eq 1 ]; then device_identifier="${device_names[0]}" success "Single device detected, launching $device_identifier" - emulator -avd $device_names -writable-system > /dev/null 2>&1 & + emulator -avd "$device_identifier" -writable-system > /dev/null 2>&1 & return fi info "Multiple devices detected, please select one from the list." @@ -83,5 +85,5 @@ select_device_android() fi done success "Launching $device_identifier" - emulator -avd $device_identifier -writable-system > /dev/null 2>&1 & + emulator -avd "$device_identifier" -writable-system > /dev/null 2>&1 & } \ No newline at end of file diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh index 14d99e550d05..558d5ae99900 100755 --- a/scripts/setup-newdot-web-emulators.sh +++ b/scripts/setup-newdot-web-emulators.sh @@ -62,11 +62,9 @@ restart_adb_server() { ensure_device_available() { # Must turn off exit on error temporarily set +e - adb devices | grep -q offline - if [ $? -eq 0 ]; then + if adb devices | grep -q offline; then restart_adb_server - adb devices | grep -q offline - if [ $? -eq 0 ]; then + if adb devices | grep -q offline; then error "Device remains 'offline'. Please investigate!" exit 1 fi From 7c7c6cfb095f39aa4ac04ba95e58fef5b30ebe82 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 9 Oct 2023 11:40:53 +0530 Subject: [PATCH 06/43] fix flow --- scripts/select-device.sh | 10 ++++++++++ scripts/setup-newdot-web-emulators.sh | 3 +++ 2 files changed, 13 insertions(+) diff --git a/scripts/select-device.sh b/scripts/select-device.sh index 3c318ede36b6..f1ad18bf8d96 100755 --- a/scripts/select-device.sh +++ b/scripts/select-device.sh @@ -51,6 +51,11 @@ select_device_ios() open -a Simulator --args -CurrentDeviceUDID "$device_identifier" } +kill_all_emulators_ios() { + # kill all the emulators + killall Simulator +} + select_device_android() { # shellcheck disable=SC2124 @@ -86,4 +91,9 @@ select_device_android() done success "Launching $device_identifier" emulator -avd "$device_identifier" -writable-system > /dev/null 2>&1 & +} + +kill_all_emulators_android() { + # kill all the emulators + adb devices | grep emulator | cut -f1 | while read -r line; do adb -s "$line" emu kill; done } \ No newline at end of file diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh index 558d5ae99900..29c52f7a57e7 100755 --- a/scripts/setup-newdot-web-emulators.sh +++ b/scripts/setup-newdot-web-emulators.sh @@ -48,6 +48,7 @@ setup_ios() sleep 5 info "Installing certificates on iOS simulator" xcrun simctl keychain booted add-cert ./config/webpack/certificate.pem + kill_all_emulators_ios } restart_adb_server() { @@ -82,6 +83,7 @@ setup_android_path_1() sleep 2 adb remount adb push /etc/hosts /system/etc/hosts + kill_all_emulators_android } setup_android_path_2() @@ -100,6 +102,7 @@ setup_android_path_2() sleep 2 adb remount adb push /etc/hosts /system/etc/hosts + kill_all_emulators_android } setup_android() From 6ddc935535d11267e49ae340d7d35d1b9ef1bb02 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 9 Oct 2023 17:25:20 +0700 Subject: [PATCH 07/43] Add pin icon in the IOU report page of request amount --- src/components/MoneyRequestHeader.js | 52 +++++++++++++++++++--------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 493184c159e0..c6176bcb2c9e 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -21,6 +21,9 @@ import * as TransactionUtils from '../libs/TransactionUtils'; import reportActionPropTypes from '../pages/home/report/reportActionPropTypes'; import transactionPropTypes from './transactionPropTypes'; import useWindowDimensions from '../hooks/useWindowDimensions'; +import themeColors from '../styles/themes/default'; +import * as Report from '../libs/actions/Report'; +import * as Session from '../libs/actions/Session'; const propTypes = { /** The report currently being looked at */ @@ -79,6 +82,38 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, }, [parentReportAction, setIsDeleteModalVisible]); const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); + const threeDotsMenuItems = [ + ...(TransactionUtils.hasReceipt(transaction) + ? [] + : [ + { + icon: Expensicons.Receipt, + text: translate('receipt.addReceipt'), + onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), + }, + ]), + { + icon: Expensicons.Trashcan, + text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), + onSelected: () => setIsDeleteModalVisible(true), + }, + ]; + + if (!report.isPinned) { + threeDotsMenuItems.unshift({ + icon: Expensicons.Pin, + iconFill: themeColors.icon, + text: translate('common.pin'), + onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), + }); + } else { + threeDotsMenuItems.unshift({ + icon: Expensicons.Pin, + iconFill: themeColors.icon, + text: translate('common.unPin'), + onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), + }); + } return ( <> @@ -87,22 +122,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, shouldShowAvatarWithDisplay shouldShowPinButton={false} shouldShowThreeDotsButton={isActionOwner && !isSettled && !isApproved} - threeDotsMenuItems={[ - ...(TransactionUtils.hasReceipt(transaction) - ? [] - : [ - { - icon: Expensicons.Receipt, - text: translate('receipt.addReceipt'), - onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), - }, - ]), - { - icon: Expensicons.Trashcan, - text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), - onSelected: () => setIsDeleteModalVisible(true), - }, - ]} + threeDotsMenuItems={threeDotsMenuItems} threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)} report={{ ...report, From fc5cecb16c8767c6e8a0e018fae3cf36be71237b Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 9 Oct 2023 19:04:55 +0530 Subject: [PATCH 08/43] fix somethings --- scripts/select-device.sh | 16 ++++++++++++++-- scripts/setup-mapbox-sdk-walkthrough.sh | 2 +- scripts/setup-mapbox-sdk.sh | 2 +- scripts/setup-newdot-web-emulators.sh | 9 ++++++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/scripts/select-device.sh b/scripts/select-device.sh index f1ad18bf8d96..d83709d927ab 100755 --- a/scripts/select-device.sh +++ b/scripts/select-device.sh @@ -1,6 +1,18 @@ #!/bin/bash -# Use functions and varaibles from the utils script +# Utility script for iOS and Android Emulators +# ============================================ +# +# Purpose: +# -------- +# This script helps to start and kill iOS simulators and Android emulators instances. +# +# How this script helps: +# ---------------------- +# This script streamlines the process of starting and killing on both android and ios +# platforms. + +# Use functions and variables from the utils script source scripts/shellUtils.sh select_device_ios() @@ -96,4 +108,4 @@ select_device_android() kill_all_emulators_android() { # kill all the emulators adb devices | grep emulator | cut -f1 | while read -r line; do adb -s "$line" emu kill; done -} \ No newline at end of file +} diff --git a/scripts/setup-mapbox-sdk-walkthrough.sh b/scripts/setup-mapbox-sdk-walkthrough.sh index 20b79641fc42..46b970f2d462 100755 --- a/scripts/setup-mapbox-sdk-walkthrough.sh +++ b/scripts/setup-mapbox-sdk-walkthrough.sh @@ -21,7 +21,7 @@ # To configure Mapbox, invoke this script by running the following command from the project's root directory: # npm run configure-mapbox -# Use functions and varaibles from the utils script +# Use functions and variables from the utils script source scripts/shellUtils.sh # Intro message diff --git a/scripts/setup-mapbox-sdk.sh b/scripts/setup-mapbox-sdk.sh index 06fd75fba299..fa37cc2fbbad 100755 --- a/scripts/setup-mapbox-sdk.sh +++ b/scripts/setup-mapbox-sdk.sh @@ -36,7 +36,7 @@ # To run this script, pass the secret Mapbox access token as a command-line argument: # ./scriptname.sh YOUR_MAPBOX_ACCESS_TOKEN -# Use functions and varaibles from the utils script +# Use functions and variables from the utils script source scripts/shellUtils.sh NETRC_PATH="$HOME/.netrc" diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh index 29c52f7a57e7..1d886796c64d 100755 --- a/scripts/setup-newdot-web-emulators.sh +++ b/scripts/setup-newdot-web-emulators.sh @@ -30,7 +30,7 @@ # 3. all (default) # ./setup-newdot-web-emulators.sh platform -# Use functions and varaibles from the utils script +# Use functions and variables from the utils script source scripts/shellUtils.sh # Use functions to select and open the emulator for iOS and Android @@ -125,7 +125,10 @@ if [ "$platform" = "ios" ] || [ "$platform" = "all" ]; then fi if [ "$platform" = "android" ] || [ "$platform" = "all" ]; then - setup_android + setup_android || { + error "Failed to setup Android emulator" + exit 1 + } fi -success "Done!" \ No newline at end of file +success "Done!" From 0069124124a79f2ec5b072be2ec3000b4d90187d Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 9 Oct 2023 21:24:35 +0530 Subject: [PATCH 09/43] fix timing --- scripts/setup-newdot-web-emulators.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh index 1d886796c64d..1cea4aaeab25 100755 --- a/scripts/setup-newdot-web-emulators.sh +++ b/scripts/setup-newdot-web-emulators.sh @@ -83,7 +83,7 @@ setup_android_path_1() sleep 2 adb remount adb push /etc/hosts /system/etc/hosts - kill_all_emulators_android + # kill_all_emulators_android } setup_android_path_2() @@ -102,13 +102,14 @@ setup_android_path_2() sleep 2 adb remount adb push /etc/hosts /system/etc/hosts - kill_all_emulators_android + # kill_all_emulators_android } setup_android() { select_device_android - sleep 5 + sleep 30 + ensure_device_available info "Installing certificates on Android emulator" setup_android_path_1 || { info "Looks like the system partition is read-only" From b2b99233a6a0e0509da0a03086872e5d2486d95a Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Mon, 9 Oct 2023 13:08:12 -0500 Subject: [PATCH 10/43] fix: default merchant for money request with receipt --- src/libs/TransactionUtils.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index beb1f9c323d6..5fae27ae4c73 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -58,16 +58,13 @@ function buildOptimisticTransaction( commentJSON.originalTransactionID = originalTransactionID; } - // For the SmartScan to run successfully, we need to pass the merchant field empty to the API - const defaultMerchant = !receipt || Object.keys(receipt).length === 0 ? CONST.TRANSACTION.DEFAULT_MERCHANT : ''; - return { transactionID, amount, currency, reportID, comment: commentJSON, - merchant: merchant || defaultMerchant, + merchant: merchant || CONST.TRANSACTION.DEFAULT_MERCHANT, created: created || DateUtils.getDBTime(), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, receipt, From f78a4806720d2f306bc07d46a5b9961828c1e589 Mon Sep 17 00:00:00 2001 From: Roji Philip Date: Tue, 10 Oct 2023 00:55:06 +0530 Subject: [PATCH 11/43] ignore concierge report id during deep link launch --- src/libs/actions/Report.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index ab2ac7fb0ca2..c115df445c41 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1388,9 +1388,11 @@ function updateWriteCapabilityAndNavigate(report, newValue) { /** * Navigates to the 1:1 report with Concierge + * + * @param {Boolean} ignoreConciergeReportID */ -function navigateToConciergeChat() { - if (!conciergeChatReportID) { +function navigateToConciergeChat(ignoreConciergeReportID = false) { + if (!conciergeChatReportID || ignoreConciergeReportID) { // In order to avoid creating concierge repeatedly, // we need to ensure that the server data has been successfully pulled Welcome.serverDataIsReadyPromise().then(() => { @@ -1884,7 +1886,7 @@ function openReportFromDeepLink(url, isAuthenticated) { InteractionManager.runAfterInteractions(() => { Session.waitForUserSignIn().then(() => { if (route === ROUTES.CONCIERGE) { - navigateToConciergeChat(); + navigateToConciergeChat(true); return; } Navigation.navigate(route, CONST.NAVIGATION.TYPE.PUSH); From 179812cc7df7426a4dcfd5d743e08d8552217582 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Tue, 10 Oct 2023 00:50:06 +0100 Subject: [PATCH 12/43] display tooltip over links --- .../Hoverable/hoverablePropTypes.js | 8 +- src/components/Hoverable/index.js | 15 +- src/components/Tooltip/index.js | 254 ++++++++++++++++-- 3 files changed, 246 insertions(+), 31 deletions(-) diff --git a/src/components/Hoverable/hoverablePropTypes.js b/src/components/Hoverable/hoverablePropTypes.js index d483a06d6aaf..f0c52a4d1646 100644 --- a/src/components/Hoverable/hoverablePropTypes.js +++ b/src/components/Hoverable/hoverablePropTypes.js @@ -13,6 +13,12 @@ const propTypes = { /** Function that executes when the mouse leaves the children. */ onHoverOut: PropTypes.func, + /** Direct pass-through of React's onMouseEnter event. */ + onMouseEnter: PropTypes.func, + + /** Direct pass-through of React's onMouseLeave event. */ + onMouseLeave: PropTypes.func, + /** Decides whether to handle the scroll behaviour to show hover once the scroll ends */ shouldHandleScroll: PropTypes.bool, }; @@ -24,4 +30,4 @@ const defaultProps = { shouldHandleScroll: false, }; -export {propTypes, defaultProps}; +export {propTypes, defaultProps}; \ No newline at end of file diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index 38ea64952a2c..2401315800d8 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -46,6 +46,7 @@ class Hoverable extends Component { * If the user has started scrolling and the isHoveredRef is true, then we should set the hover state to false. * This is to hide the existing hover and reaction bar. */ + this.isHoveredRef = false; this.setState({isHovered: false}, this.props.onHoverOut); } this.isScrollingRef = scrolling; @@ -90,9 +91,7 @@ class Hoverable extends Component { /** * If the isScrollingRef is true, then the user is scrolling and we should not update the hover state. */ - if (this.isScrollingRef && this.props.shouldHandleScroll && !this.state.isHovered) { - return; - } + if (this.isScrollingRef && this.props.shouldHandleScroll && !this.state.isHovered) return; if (isHovered !== this.state.isHovered) { this.setState({isHovered}, isHovered ? this.props.onHoverIn : this.props.onHoverOut); @@ -155,6 +154,10 @@ class Hoverable extends Component { } }, onMouseEnter: (el) => { + if (_.isFunction(this.props.onMouseEnter)) { + this.props.onMouseEnter(el); + } + this.setIsHovered(true); if (_.isFunction(child.props.onMouseEnter)) { @@ -162,6 +165,10 @@ class Hoverable extends Component { } }, onMouseLeave: (el) => { + if (_.isFunction(this.props.onMouseLeave)) { + this.props.onMouseLeave(el); + } + this.setIsHovered(false); if (_.isFunction(child.props.onMouseLeave)) { @@ -186,4 +193,4 @@ class Hoverable extends Component { Hoverable.propTypes = propTypes; Hoverable.defaultProps = defaultProps; -export default Hoverable; +export default Hoverable; \ No newline at end of file diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js index 2e6789ec73f6..0083a52d6ba7 100644 --- a/src/components/Tooltip/index.js +++ b/src/components/Tooltip/index.js @@ -1,37 +1,239 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {propTypes as tooltipPropTypes, defaultProps as tooltipDefaultProps} from './tooltipPropTypes'; -import BaseTooltip from './BaseTooltip'; +import _ from 'underscore'; +import React, {memo, useCallback, useEffect, useRef, useState} from 'react'; +import {Animated} from 'react-native'; +import {BoundsObserver} from '@react-ng/bounds-observer'; +import TooltipRenderedOnPageBody from './TooltipRenderedOnPageBody'; +import Hoverable from '../Hoverable'; +import * as tooltipPropTypes from './tooltipPropTypes'; +import TooltipSense from './TooltipSense'; +import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; +import usePrevious from '../../hooks/usePrevious'; +import useLocalize from '../../hooks/useLocalize'; +import useWindowDimensions from '../../hooks/useWindowDimensions'; -const propTypes = { - ...tooltipPropTypes, +const hasHoverSupport = DeviceCapabilities.hasHoverSupport(); - /** Whether the actual Tooltip should be rendered. If false, it's just going to return the children */ - shouldRender: PropTypes.bool, -}; +/** + * Choose the correct bounding box from the given list. + * This is a helper function for chooseBoundingBox below. + * + * @param {Element} bbs The bounding boxes of DOM element being hovered over. + * @param {number} clientX The X position from the MouseEvent. + * @param {number} clientY The Y position from the MouseEvent. + * @param {number} slop An allowed slop factor when searching for the bounding + * box. If the user is moving the mouse quickly we can end up getting a + * hover event with the position outside any of our bounding boxes. We retry + * with a small slop factor in that case, so if we have a bounding box close + * enough then we go with that. + * @return {DOMRect | null} The chosen bounding box. null if we failed to find + * a matching one, which can happen if the user is moving the mouse quickly + * and the onHoverOver event actually fires outside the element bounding box. + */ +function chooseBoundingBoxWithSlop(bbs, clientX, clientY, slop) { + for (let i = 0; i < bbs.length; i++) { + const bb = bbs[i]; + if (bb.x - slop <= clientX && bb.x + bb.width + slop >= clientX && bb.y - slop <= clientY && bb.y + bb.height + slop >= clientY) { + return bb; + } + } + return null; +} + +/** + * Choose the correct bounding box for the tooltip to be positioned against. + * This handles the case where the target is wrapped across two lines, and + * so we need to find the correct part (the one that the user is hovering + * over) and show the tooltip there. + * + * @param {Element} target The DOM element being hovered over. + * @param {number} clientX The X position from the MouseEvent. + * @param {number} clientY The Y position from the MouseEvent. + * @return {DOMRect} The chosen bounding box. + */ +function chooseBoundingBox(target, clientX, clientY) { + const bbs = target.getClientRects(); + if (bbs.length === 1) { + return bbs[0]; + } + let bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 0); + if (bb) { + return bb; + } + // Retry with a slop factor, in case the user is moving the mouse quickly. + bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 5); + if (bb) { + return bb; + } + // Fall back to the full bounding box if we failed to find a matching one. + // This could only happen if the user is moving the mouse very quickly + // and they got it outside our slop above. + return target.getBoundingClientRect(); +} + +/** + * A component used to wrap an element intended for displaying a tooltip. The term "tooltip's target" refers to the + * wrapped element, which, upon hover, triggers the tooltip to be shown. + * @param {propTypes} props + * @returns {ReactNodeLike} + */ +function Tooltip(props) { + const {children, numberOfLines, maxWidth, text, renderTooltipContent, renderTooltipContentKey} = props; + + const {preferredLocale} = useLocalize(); + const {windowWidth} = useWindowDimensions(); + + // Is tooltip already rendered on the page's body? happens once. + const [isRendered, setIsRendered] = useState(false); + // Is the tooltip currently visible? + const [isVisible, setIsVisible] = useState(false); + // The distance between the left side of the wrapper view and the left side of the window + const [xOffset, setXOffset] = useState(0); + // The distance between the top of the wrapper view and the top of the window + const [yOffset, setYOffset] = useState(0); + // The width and height of the wrapper view + const [wrapperWidth, setWrapperWidth] = useState(0); + const [wrapperHeight, setWrapperHeight] = useState(0); + + // Whether the tooltip is first tooltip to activate the TooltipSense + const isTooltipSenseInitiator = useRef(false); + const animation = useRef(new Animated.Value(0)); + const isAnimationCanceled = useRef(false); + const prevText = usePrevious(text); + + const target = useRef(null); + const initialMousePosition = useRef({x: 0, y: 0}); -const defaultProps = { - ...tooltipDefaultProps, - shouldRender: true, -}; + const updateTargetAndMousePosition = useCallback((e) => { + target.current = e.target; + initialMousePosition.current = {x: e.clientX, y: e.clientY}; + }, []); -function Tooltip({shouldRender, children, ...props}) { - if (!shouldRender) { + /** + * Display the tooltip in an animation. + */ + const showTooltip = useCallback(() => { + if (!isRendered) { + setIsRendered(true); + } + + setIsVisible(true); + + animation.current.stopAnimation(); + + // When TooltipSense is active, immediately show the tooltip + if (TooltipSense.isActive()) { + animation.current.setValue(1); + } else { + isTooltipSenseInitiator.current = true; + Animated.timing(animation.current, { + toValue: 1, + duration: 140, + delay: 500, + useNativeDriver: false, + }).start(({finished}) => { + isAnimationCanceled.current = !finished; + }); + } + TooltipSense.activate(); + }, [isRendered]); + + // eslint-disable-next-line rulesdir/prefer-early-return + useEffect(() => { + // if the tooltip text changed before the initial animation was finished, then the tooltip won't be shown + // we need to show the tooltip again + if (isVisible && isAnimationCanceled.current && text && prevText !== text) { + isAnimationCanceled.current = false; + showTooltip(); + } + }, [isVisible, text, prevText, showTooltip]); + + /** + * Update the tooltip bounding rectangle + * + * @param {Object} bounds - updated bounds + */ + const updateBounds = (bounds) => { + if (bounds.width === 0) { + setIsRendered(false); + } + // Choose a bounding box for the tooltip to target. + // In the case when the target is a link that has wrapped onto + // multiple lines, we want to show the tooltip over the part + // of the link that the user is hovering over. + const betterBounds = chooseBoundingBox(target.current, initialMousePosition.current.x, initialMousePosition.current.y); + setWrapperWidth(betterBounds.width); + setWrapperHeight(betterBounds.height); + setXOffset(betterBounds.x); + setYOffset(betterBounds.y); + }; + + /** + * Hide the tooltip in an animation. + */ + const hideTooltip = () => { + animation.current.stopAnimation(); + + if (TooltipSense.isActive() && !isTooltipSenseInitiator.current) { + animation.current.setValue(0); + } else { + // Hide the first tooltip which initiated the TooltipSense with animation + isTooltipSenseInitiator.current = false; + Animated.timing(animation.current, { + toValue: 0, + duration: 140, + useNativeDriver: false, + }).start(); + } + + TooltipSense.deactivate(); + + setIsVisible(false); + }; + + // Skip the tooltip and return the children if the text is empty, + // we don't have a render function or the device does not support hovering + if ((_.isEmpty(text) && renderTooltipContent == null) || !hasHoverSupport) { return children; } return ( - - {children} - + <> + {isRendered && ( + + )} + + + {children} + + + ); } -Tooltip.displayName = 'Tooltip'; -Tooltip.propTypes = propTypes; -Tooltip.defaultProps = defaultProps; - -export default Tooltip; +Tooltip.propTypes = tooltipPropTypes.propTypes; +Tooltip.defaultProps = tooltipPropTypes.defaultProps; +export default memo(Tooltip); \ No newline at end of file From f724dac52d830b2875fd2d7ac54f8d968ab45582 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Tue, 10 Oct 2023 01:12:58 +0100 Subject: [PATCH 13/43] fix lint --- src/components/Hoverable/hoverablePropTypes.js | 2 +- src/components/Hoverable/index.js | 6 ++++-- src/components/Tooltip/index.js | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/Hoverable/hoverablePropTypes.js b/src/components/Hoverable/hoverablePropTypes.js index f0c52a4d1646..a3aeaa597d7a 100644 --- a/src/components/Hoverable/hoverablePropTypes.js +++ b/src/components/Hoverable/hoverablePropTypes.js @@ -30,4 +30,4 @@ const defaultProps = { shouldHandleScroll: false, }; -export {propTypes, defaultProps}; \ No newline at end of file +export {propTypes, defaultProps}; diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index 2401315800d8..9d7330da3684 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -91,7 +91,9 @@ class Hoverable extends Component { /** * If the isScrollingRef is true, then the user is scrolling and we should not update the hover state. */ - if (this.isScrollingRef && this.props.shouldHandleScroll && !this.state.isHovered) return; + if (this.isScrollingRef && this.props.shouldHandleScroll && !this.state.isHovered) { + return; + } if (isHovered !== this.state.isHovered) { this.setState({isHovered}, isHovered ? this.props.onHoverIn : this.props.onHoverOut); @@ -193,4 +195,4 @@ class Hoverable extends Component { Hoverable.propTypes = propTypes; Hoverable.defaultProps = defaultProps; -export default Hoverable; \ No newline at end of file +export default Hoverable; diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js index 0083a52d6ba7..7137b4c6a065 100644 --- a/src/components/Tooltip/index.js +++ b/src/components/Tooltip/index.js @@ -236,4 +236,4 @@ function Tooltip(props) { Tooltip.propTypes = tooltipPropTypes.propTypes; Tooltip.defaultProps = tooltipPropTypes.defaultProps; -export default memo(Tooltip); \ No newline at end of file +export default memo(Tooltip); From 51deb9de8a4b6e05720ded0b18e430860c389c6f Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 10 Oct 2023 20:13:47 +0530 Subject: [PATCH 14/43] fix ios flow --- scripts/setup-newdot-web-emulators.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh index 1cea4aaeab25..85f3a2686cc7 100755 --- a/scripts/setup-newdot-web-emulators.sh +++ b/scripts/setup-newdot-web-emulators.sh @@ -45,9 +45,9 @@ fi setup_ios() { select_device_ios - sleep 5 + sleep 30 info "Installing certificates on iOS simulator" - xcrun simctl keychain booted add-cert ./config/webpack/certificate.pem + xcrun simctl keychain booted add-root-cert "$(mkcert -CAROOT)/rootCA.pem" kill_all_emulators_ios } From dd19591ca476cf4d05f19f700d346f4890dd41ab Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 11 Oct 2023 14:38:54 +0700 Subject: [PATCH 15/43] add threedot button on receiver IOU request --- src/components/MoneyRequestHeader.js | 55 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 262abe6a213e..1b3dcd73f311 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -83,22 +83,33 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, }, [parentReportAction, setIsDeleteModalVisible]); const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); - const threeDotsMenuItems = [ - ...(TransactionUtils.hasReceipt(transaction) - ? [] - : [ - { - icon: Expensicons.Receipt, - text: translate('receipt.addReceipt'), - onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), - }, - ]), - { - icon: Expensicons.Trashcan, - text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), - onSelected: () => setIsDeleteModalVisible(true), - }, - ]; + const canModifyRequest = isActionOwner && !isSettled && !isApproved; + + useEffect(() => { + if (canModifyRequest) { + return; + } + + setIsDeleteModalVisible(false); + }, [canModifyRequest]); + const threeDotsMenuItems = canModifyRequest + ? [ + ...(TransactionUtils.hasReceipt(transaction) + ? [] + : [ + { + icon: Expensicons.Receipt, + text: translate('receipt.addReceipt'), + onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), + }, + ]), + { + icon: Expensicons.Trashcan, + text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), + onSelected: () => setIsDeleteModalVisible(true), + }, + ] + : []; if (!report.isPinned) { threeDotsMenuItems.unshift({ @@ -116,23 +127,13 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, }); } - const canModifyRequest = isActionOwner && !isSettled && !isApproved; - - useEffect(() => { - if (canModifyRequest) { - return; - } - - setIsDeleteModalVisible(false); - }, [canModifyRequest]); - return ( <> Date: Wed, 11 Oct 2023 15:19:17 +0700 Subject: [PATCH 16/43] make logic more simple --- src/components/MoneyRequestHeader.js | 43 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 1b3dcd73f311..052d65e8bed2 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -92,34 +92,16 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, setIsDeleteModalVisible(false); }, [canModifyRequest]); - const threeDotsMenuItems = canModifyRequest - ? [ - ...(TransactionUtils.hasReceipt(transaction) - ? [] - : [ - { - icon: Expensicons.Receipt, - text: translate('receipt.addReceipt'), - onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), - }, - ]), - { - icon: Expensicons.Trashcan, - text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), - onSelected: () => setIsDeleteModalVisible(true), - }, - ] - : []; - + const threeDotsMenuItems = []; if (!report.isPinned) { - threeDotsMenuItems.unshift({ + threeDotsMenuItems.push({ icon: Expensicons.Pin, iconFill: themeColors.icon, text: translate('common.pin'), onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), }); } else { - threeDotsMenuItems.unshift({ + threeDotsMenuItems.push({ icon: Expensicons.Pin, iconFill: themeColors.icon, text: translate('common.unPin'), @@ -127,6 +109,25 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, }); } + if (canModifyRequest) { + threeDotsMenuItems.push([ + ...(TransactionUtils.hasReceipt(transaction) + ? [] + : [ + { + icon: Expensicons.Receipt, + text: translate('receipt.addReceipt'), + onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), + }, + ]), + { + icon: Expensicons.Trashcan, + text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), + onSelected: () => setIsDeleteModalVisible(true), + }, + ]); + } + return ( <> From 5d121bb839f7f78cb236f401f162b13cd2e8ba99 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 11 Oct 2023 15:26:04 +0700 Subject: [PATCH 17/43] make logic more simple --- src/components/MoneyRequestHeader.js | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 052d65e8bed2..0e7ad6b6c6be 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -110,22 +110,18 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, } if (canModifyRequest) { - threeDotsMenuItems.push([ - ...(TransactionUtils.hasReceipt(transaction) - ? [] - : [ - { - icon: Expensicons.Receipt, - text: translate('receipt.addReceipt'), - onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), - }, - ]), - { - icon: Expensicons.Trashcan, - text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), - onSelected: () => setIsDeleteModalVisible(true), - }, - ]); + if (!TransactionUtils.hasReceipt(transaction)) { + threeDotsMenuItems.push({ + icon: Expensicons.Receipt, + text: translate('receipt.addReceipt'), + onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)), + }); + } + threeDotsMenuItems.push({ + icon: Expensicons.Trashcan, + text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}), + onSelected: () => setIsDeleteModalVisible(true), + }); } return ( From be5988658c958b9989174fc4065959669cc86a93 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Wed, 11 Oct 2023 09:40:49 +0100 Subject: [PATCH 18/43] move bounding box logic to base tooltip --- src/components/Hoverable/index.js | 5 - src/components/Tooltip/BaseTooltip.js | 83 ++++++++- src/components/Tooltip/index.js | 254 +++----------------------- 3 files changed, 105 insertions(+), 237 deletions(-) diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index 9d7330da3684..281c1e7860f7 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -42,11 +42,6 @@ class Hoverable extends Component { if (!scrolling && this.isHoveredRef) { this.setState({isHovered: this.isHoveredRef}, this.props.onHoverIn); } else if (scrolling && this.isHoveredRef) { - /** - * If the user has started scrolling and the isHoveredRef is true, then we should set the hover state to false. - * This is to hide the existing hover and reaction bar. - */ - this.isHoveredRef = false; this.setState({isHovered: false}, this.props.onHoverOut); } this.isScrollingRef = scrolling; diff --git a/src/components/Tooltip/BaseTooltip.js b/src/components/Tooltip/BaseTooltip.js index f60982f52dd4..8478cd333691 100644 --- a/src/components/Tooltip/BaseTooltip.js +++ b/src/components/Tooltip/BaseTooltip.js @@ -19,6 +19,65 @@ const hasHoverSupport = DeviceCapabilities.hasHoverSupport(); * @param {propTypes} props * @returns {ReactNodeLike} */ + +/** + * Choose the correct bounding box from the given list. + * This is a helper function for chooseBoundingBox below. + * + * @param {Element} bbs The bounding boxes of DOM element being hovered over. + * @param {number} clientX The X position from the MouseEvent. + * @param {number} clientY The Y position from the MouseEvent. + * @param {number} slop An allowed slop factor when searching for the bounding + * box. If the user is moving the mouse quickly we can end up getting a + * hover event with the position outside any of our bounding boxes. We retry + * with a small slop factor in that case, so if we have a bounding box close + * enough then we go with that. + * @return {DOMRect | null} The chosen bounding box. null if we failed to find + * a matching one, which can happen if the user is moving the mouse quickly + * and the onHoverOver event actually fires outside the element bounding box. + */ +function chooseBoundingBoxWithSlop(bbs, clientX, clientY, slop) { + for (let i = 0; i < bbs.length; i++) { + const bb = bbs[i]; + if (bb.x - slop <= clientX && bb.x + bb.width + slop >= clientX && bb.y - slop <= clientY && bb.y + bb.height + slop >= clientY) { + return bb; + } + } + return null; +} + +/** + * Choose the correct bounding box for the tooltip to be positioned against. + * This handles the case where the target is wrapped across two lines, and + * so we need to find the correct part (the one that the user is hovering + * over) and show the tooltip there. + * + * @param {Element} target The DOM element being hovered over. + * @param {number} clientX The X position from the MouseEvent. + * @param {number} clientY The Y position from the MouseEvent. + * @return {DOMRect} The chosen bounding box. + */ + +function chooseBoundingBox(target, clientX, clientY) { + const bbs = target.getClientRects(); + if (bbs.length === 1) { + return bbs[0]; + } + let bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 0); + if (bb) { + return bb; + } + // Retry with a slop factor, in case the user is moving the mouse quickly. + bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 5); + if (bb) { + return bb; + } + // Fall back to the full bounding box if we failed to find a matching one. + // This could only happen if the user is moving the mouse very quickly + // and they got it outside our slop above. + return target.getBoundingClientRect(); +} + function Tooltip(props) { const {children, numberOfLines, maxWidth, text, renderTooltipContent, renderTooltipContentKey} = props; @@ -43,6 +102,14 @@ function Tooltip(props) { const isAnimationCanceled = useRef(false); const prevText = usePrevious(text); + const target = useRef(null); + const initialMousePosition = useRef({x: 0, y: 0}); + + const updateTargetAndMousePosition = useCallback((e) => { + target.current = e.target; + initialMousePosition.current = {x: e.clientX, y: e.clientY}; + }, []); + /** * Display the tooltip in an animation. */ @@ -91,10 +158,15 @@ function Tooltip(props) { if (bounds.width === 0) { setIsRendered(false); } - setWrapperWidth(bounds.width); - setWrapperHeight(bounds.height); - setXOffset(bounds.x); - setYOffset(bounds.y); + // Choose a bounding box for the tooltip to target. + // In the case when the target is a link that has wrapped onto + // multiple lines, we want to show the tooltip over the part + // of the link that the user is hovering over. + const betterBounds = chooseBoundingBox(target.current, initialMousePosition.current.x, initialMousePosition.current.y); + setWrapperWidth(betterBounds.width); + setWrapperHeight(betterBounds.height); + setXOffset(betterBounds.x); + setYOffset(betterBounds.y); }; /** @@ -152,6 +224,7 @@ function Tooltip(props) { onBoundsChange={updateBounds} > = clientX && bb.y - slop <= clientY && bb.y + bb.height + slop >= clientY) { - return bb; - } - } - return null; -} - -/** - * Choose the correct bounding box for the tooltip to be positioned against. - * This handles the case where the target is wrapped across two lines, and - * so we need to find the correct part (the one that the user is hovering - * over) and show the tooltip there. - * - * @param {Element} target The DOM element being hovered over. - * @param {number} clientX The X position from the MouseEvent. - * @param {number} clientY The Y position from the MouseEvent. - * @return {DOMRect} The chosen bounding box. - */ -function chooseBoundingBox(target, clientX, clientY) { - const bbs = target.getClientRects(); - if (bbs.length === 1) { - return bbs[0]; - } - let bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 0); - if (bb) { - return bb; - } - // Retry with a slop factor, in case the user is moving the mouse quickly. - bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 5); - if (bb) { - return bb; - } - // Fall back to the full bounding box if we failed to find a matching one. - // This could only happen if the user is moving the mouse very quickly - // and they got it outside our slop above. - return target.getBoundingClientRect(); -} - -/** - * A component used to wrap an element intended for displaying a tooltip. The term "tooltip's target" refers to the - * wrapped element, which, upon hover, triggers the tooltip to be shown. - * @param {propTypes} props - * @returns {ReactNodeLike} - */ -function Tooltip(props) { - const {children, numberOfLines, maxWidth, text, renderTooltipContent, renderTooltipContentKey} = props; - - const {preferredLocale} = useLocalize(); - const {windowWidth} = useWindowDimensions(); - - // Is tooltip already rendered on the page's body? happens once. - const [isRendered, setIsRendered] = useState(false); - // Is the tooltip currently visible? - const [isVisible, setIsVisible] = useState(false); - // The distance between the left side of the wrapper view and the left side of the window - const [xOffset, setXOffset] = useState(0); - // The distance between the top of the wrapper view and the top of the window - const [yOffset, setYOffset] = useState(0); - // The width and height of the wrapper view - const [wrapperWidth, setWrapperWidth] = useState(0); - const [wrapperHeight, setWrapperHeight] = useState(0); - - // Whether the tooltip is first tooltip to activate the TooltipSense - const isTooltipSenseInitiator = useRef(false); - const animation = useRef(new Animated.Value(0)); - const isAnimationCanceled = useRef(false); - const prevText = usePrevious(text); - - const target = useRef(null); - const initialMousePosition = useRef({x: 0, y: 0}); + /** Whether the actual Tooltip should be rendered. If false, it's just going to return the children */ + shouldRender: PropTypes.bool, +}; - const updateTargetAndMousePosition = useCallback((e) => { - target.current = e.target; - initialMousePosition.current = {x: e.clientX, y: e.clientY}; - }, []); +const defaultProps = { + ...tooltipDefaultProps, + shouldRender: true, +}; - /** - * Display the tooltip in an animation. - */ - const showTooltip = useCallback(() => { - if (!isRendered) { - setIsRendered(true); - } - - setIsVisible(true); - - animation.current.stopAnimation(); - - // When TooltipSense is active, immediately show the tooltip - if (TooltipSense.isActive()) { - animation.current.setValue(1); - } else { - isTooltipSenseInitiator.current = true; - Animated.timing(animation.current, { - toValue: 1, - duration: 140, - delay: 500, - useNativeDriver: false, - }).start(({finished}) => { - isAnimationCanceled.current = !finished; - }); - } - TooltipSense.activate(); - }, [isRendered]); - - // eslint-disable-next-line rulesdir/prefer-early-return - useEffect(() => { - // if the tooltip text changed before the initial animation was finished, then the tooltip won't be shown - // we need to show the tooltip again - if (isVisible && isAnimationCanceled.current && text && prevText !== text) { - isAnimationCanceled.current = false; - showTooltip(); - } - }, [isVisible, text, prevText, showTooltip]); - - /** - * Update the tooltip bounding rectangle - * - * @param {Object} bounds - updated bounds - */ - const updateBounds = (bounds) => { - if (bounds.width === 0) { - setIsRendered(false); - } - // Choose a bounding box for the tooltip to target. - // In the case when the target is a link that has wrapped onto - // multiple lines, we want to show the tooltip over the part - // of the link that the user is hovering over. - const betterBounds = chooseBoundingBox(target.current, initialMousePosition.current.x, initialMousePosition.current.y); - setWrapperWidth(betterBounds.width); - setWrapperHeight(betterBounds.height); - setXOffset(betterBounds.x); - setYOffset(betterBounds.y); - }; - - /** - * Hide the tooltip in an animation. - */ - const hideTooltip = () => { - animation.current.stopAnimation(); - - if (TooltipSense.isActive() && !isTooltipSenseInitiator.current) { - animation.current.setValue(0); - } else { - // Hide the first tooltip which initiated the TooltipSense with animation - isTooltipSenseInitiator.current = false; - Animated.timing(animation.current, { - toValue: 0, - duration: 140, - useNativeDriver: false, - }).start(); - } - - TooltipSense.deactivate(); - - setIsVisible(false); - }; - - // Skip the tooltip and return the children if the text is empty, - // we don't have a render function or the device does not support hovering - if ((_.isEmpty(text) && renderTooltipContent == null) || !hasHoverSupport) { +function Tooltip({shouldRender, children, ...props}) { + if (!shouldRender) { return children; } return ( - <> - {isRendered && ( - - )} - - - {children} - - - + + {children} + ); } -Tooltip.propTypes = tooltipPropTypes.propTypes; -Tooltip.defaultProps = tooltipPropTypes.defaultProps; -export default memo(Tooltip); +Tooltip.displayName = 'Tooltip'; +Tooltip.propTypes = propTypes; +Tooltip.defaultProps = defaultProps; + +export default Tooltip; From 0ad6afdbf3e2e3b60fa7136404e899913e44e60a Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Wed, 11 Oct 2023 09:45:34 +0100 Subject: [PATCH 19/43] destructure from props --- src/components/Tooltip/BaseTooltip.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Tooltip/BaseTooltip.js b/src/components/Tooltip/BaseTooltip.js index 8478cd333691..27a57dfb467e 100644 --- a/src/components/Tooltip/BaseTooltip.js +++ b/src/components/Tooltip/BaseTooltip.js @@ -79,7 +79,7 @@ function chooseBoundingBox(target, clientX, clientY) { } function Tooltip(props) { - const {children, numberOfLines, maxWidth, text, renderTooltipContent, renderTooltipContentKey} = props; + const {children, numberOfLines, maxWidth, text, renderTooltipContent, renderTooltipContentKey, shouldHandleScroll} = props; const {preferredLocale} = useLocalize(); const {windowWidth} = useWindowDimensions(); @@ -227,7 +227,7 @@ function Tooltip(props) { onMouseEnter={updateTargetAndMousePosition} onHoverIn={showTooltip} onHoverOut={hideTooltip} - shouldHandleScroll={props.shouldHandleScroll} + shouldHandleScroll={shouldHandleScroll} > {children} From eb8530a728cb34459cc03839f21e4bb26cb7b219 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Wed, 11 Oct 2023 10:43:37 +0100 Subject: [PATCH 20/43] merge and improve functions with a tolerance of 5 --- src/components/Tooltip/BaseTooltip.js | 57 ++++++++------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/src/components/Tooltip/BaseTooltip.js b/src/components/Tooltip/BaseTooltip.js index 27a57dfb467e..b8bca189c534 100644 --- a/src/components/Tooltip/BaseTooltip.js +++ b/src/components/Tooltip/BaseTooltip.js @@ -20,32 +20,6 @@ const hasHoverSupport = DeviceCapabilities.hasHoverSupport(); * @returns {ReactNodeLike} */ -/** - * Choose the correct bounding box from the given list. - * This is a helper function for chooseBoundingBox below. - * - * @param {Element} bbs The bounding boxes of DOM element being hovered over. - * @param {number} clientX The X position from the MouseEvent. - * @param {number} clientY The Y position from the MouseEvent. - * @param {number} slop An allowed slop factor when searching for the bounding - * box. If the user is moving the mouse quickly we can end up getting a - * hover event with the position outside any of our bounding boxes. We retry - * with a small slop factor in that case, so if we have a bounding box close - * enough then we go with that. - * @return {DOMRect | null} The chosen bounding box. null if we failed to find - * a matching one, which can happen if the user is moving the mouse quickly - * and the onHoverOver event actually fires outside the element bounding box. - */ -function chooseBoundingBoxWithSlop(bbs, clientX, clientY, slop) { - for (let i = 0; i < bbs.length; i++) { - const bb = bbs[i]; - if (bb.x - slop <= clientX && bb.x + bb.width + slop >= clientX && bb.y - slop <= clientY && bb.y + bb.height + slop >= clientY) { - return bb; - } - } - return null; -} - /** * Choose the correct bounding box for the tooltip to be positioned against. * This handles the case where the target is wrapped across two lines, and @@ -59,23 +33,24 @@ function chooseBoundingBoxWithSlop(bbs, clientX, clientY, slop) { */ function chooseBoundingBox(target, clientX, clientY) { + const slop = 5; const bbs = target.getClientRects(); - if (bbs.length === 1) { - return bbs[0]; - } - let bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 0); - if (bb) { - return bb; - } - // Retry with a slop factor, in case the user is moving the mouse quickly. - bb = chooseBoundingBoxWithSlop(bbs, clientX, clientY, 5); - if (bb) { - return bb; + const clientXMin = clientX - slop; + const clientXMax = clientX + slop; + const clientYMin = clientY - slop; + const clientYMax = clientY + slop; + + for (let i = 0; i < bbs.length; i++) { + const bb = bbs[i]; + if (clientXMin <= bb.right && clientXMax >= bb.left && clientYMin <= bb.bottom && clientYMax >= bb.top) { + return bb; + } } - // Fall back to the full bounding box if we failed to find a matching one. - // This could only happen if the user is moving the mouse very quickly - // and they got it outside our slop above. - return target.getBoundingClientRect(); + + // If no matching bounding box is found, fall back to the first one. + // This could only happen if the user is moving the mouse very quickly + // and they got it outside our slop above. + return bbs[0]; } function Tooltip(props) { From 1b90bb2f4c2abc717d2f735c500357f8778756c1 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Wed, 11 Oct 2023 10:55:06 +0100 Subject: [PATCH 21/43] fix lint --- src/components/Tooltip/BaseTooltip.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Tooltip/BaseTooltip.js b/src/components/Tooltip/BaseTooltip.js index b8bca189c534..bcbb14686a2e 100644 --- a/src/components/Tooltip/BaseTooltip.js +++ b/src/components/Tooltip/BaseTooltip.js @@ -46,10 +46,10 @@ function chooseBoundingBox(target, clientX, clientY) { return bb; } } - + // If no matching bounding box is found, fall back to the first one. - // This could only happen if the user is moving the mouse very quickly - // and they got it outside our slop above. + // This could only happen if the user is moving the mouse very quickly + // and they got it outside our slop above. return bbs[0]; } From 99947cfe9014dd45dbb6e2eec76a77c901ce59bc Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 11 Oct 2023 22:15:22 +0700 Subject: [PATCH 22/43] create new utils function --- src/components/MoneyRequestHeader.js | 22 ++-------------------- src/libs/HeaderUtils.js | 28 ++++++++++++++++++++++++++++ src/pages/home/HeaderView.js | 18 ++---------------- 3 files changed, 32 insertions(+), 36 deletions(-) create mode 100644 src/libs/HeaderUtils.js diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 0e7ad6b6c6be..49870038cbca 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -19,12 +19,10 @@ import ConfirmModal from './ConfirmModal'; import useLocalize from '../hooks/useLocalize'; import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar'; import * as TransactionUtils from '../libs/TransactionUtils'; +import * as HeaderUtils from '../libs/HeaderUtils'; import reportActionPropTypes from '../pages/home/report/reportActionPropTypes'; import transactionPropTypes from './transactionPropTypes'; import useWindowDimensions from '../hooks/useWindowDimensions'; -import themeColors from '../styles/themes/default'; -import * as Report from '../libs/actions/Report'; -import * as Session from '../libs/actions/Session'; const propTypes = { /** The report currently being looked at */ @@ -92,23 +90,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, setIsDeleteModalVisible(false); }, [canModifyRequest]); - const threeDotsMenuItems = []; - if (!report.isPinned) { - threeDotsMenuItems.push({ - icon: Expensicons.Pin, - iconFill: themeColors.icon, - text: translate('common.pin'), - onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), - }); - } else { - threeDotsMenuItems.push({ - icon: Expensicons.Pin, - iconFill: themeColors.icon, - text: translate('common.unPin'), - onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), - }); - } - + const threeDotsMenuItems = [HeaderUtils.getPinFunctionality()]; if (canModifyRequest) { if (!TransactionUtils.hasReceipt(transaction)) { threeDotsMenuItems.push({ diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.js new file mode 100644 index 000000000000..b51fb4a9486d --- /dev/null +++ b/src/libs/HeaderUtils.js @@ -0,0 +1,28 @@ +import * as Localize from './Localize'; +import themeColors from '../styles/themes/default'; +import * as Session from './actions/Session'; +import * as Report from './actions/Report'; +import * as Expensicons from '../components/Icon/Expensicons'; + +/** + * @param {Object} report + * @returns {Object} + */ +function getPinFunctionality(report) { + if (!report.isPinned) { + return { + icon: Expensicons.Pin, + iconFill: themeColors.icon, + text: Localize.translateLocal('common.pin'), + onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), + }; + } + return { + icon: Expensicons.Pin, + iconFill: themeColors.icon, + text: Localize.translateLocal('common.unPin'), + onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(report.reportID, report.isPinned)), + }; +} + +export default getPinFunctionality; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 4e48a965b095..1f00743e8d67 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -23,11 +23,11 @@ import participantPropTypes from '../../components/participantPropTypes'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions'; import * as OptionsListUtils from '../../libs/OptionsListUtils'; +import * as HeaderUtils from '../../libs/HeaderUtils'; import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; import * as ReportUtils from '../../libs/ReportUtils'; import * as Link from '../../libs/actions/Link'; import * as Report from '../../libs/actions/Report'; -import * as Session from '../../libs/actions/Session'; import * as Task from '../../libs/actions/Task'; import compose from '../../libs/compose'; import styles from '../../styles/styles'; @@ -135,21 +135,7 @@ function HeaderView(props) { } } - if (!props.report.isPinned) { - threeDotMenuItems.push({ - icon: Expensicons.Pin, - iconFill: themeColors.icon, - text: props.translate('common.pin'), - onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(props.report.reportID, props.report.isPinned)), - }); - } else { - threeDotMenuItems.push({ - icon: Expensicons.Pin, - iconFill: themeColors.icon, - text: props.translate('common.unPin'), - onSelected: Session.checkIfActionIsAllowed(() => Report.togglePinnedState(props.report.reportID, props.report.isPinned)), - }); - } + threeDotMenuItems.push(HeaderUtils.getPinFunctionality()); if (isConcierge && props.guideCalendarLink) { threeDotMenuItems.push({ From d4511cd561c0ca3ee98a6a3bc7c91e76fe1994e0 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 11 Oct 2023 22:22:54 +0700 Subject: [PATCH 23/43] fix lint --- src/libs/HeaderUtils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.js index b51fb4a9486d..4b3361e9d033 100644 --- a/src/libs/HeaderUtils.js +++ b/src/libs/HeaderUtils.js @@ -25,4 +25,7 @@ function getPinFunctionality(report) { }; } -export default getPinFunctionality; +export { + // eslint-disable-next-line import/prefer-default-export + getPinFunctionality +} From 73bab1d44622ac8f09d0b27625e2c2f2db3cfd75 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 11 Oct 2023 22:24:12 +0700 Subject: [PATCH 24/43] fix lint --- src/components/MoneyRequestHeader.js | 2 +- src/pages/home/HeaderView.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 49870038cbca..647ad7d362e7 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -90,7 +90,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, setIsDeleteModalVisible(false); }, [canModifyRequest]); - const threeDotsMenuItems = [HeaderUtils.getPinFunctionality()]; + const threeDotsMenuItems = [HeaderUtils.getPinFunctionality(report)]; if (canModifyRequest) { if (!TransactionUtils.hasReceipt(transaction)) { threeDotsMenuItems.push({ diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 1f00743e8d67..c8dc6b8bde54 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -135,7 +135,7 @@ function HeaderView(props) { } } - threeDotMenuItems.push(HeaderUtils.getPinFunctionality()); + threeDotMenuItems.push(HeaderUtils.getPinFunctionality(props.report)); if (isConcierge && props.guideCalendarLink) { threeDotMenuItems.push({ From 3af8079865c7f949698259fa569d13cc1ee8ab87 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 11 Oct 2023 22:33:57 +0700 Subject: [PATCH 25/43] fix lint --- src/libs/HeaderUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.js index 4b3361e9d033..915a713bbe2c 100644 --- a/src/libs/HeaderUtils.js +++ b/src/libs/HeaderUtils.js @@ -27,5 +27,5 @@ function getPinFunctionality(report) { export { // eslint-disable-next-line import/prefer-default-export - getPinFunctionality -} + getPinFunctionality, +}; From 8e6c289f59c4a70b52cd2b38279c653c39c521ed Mon Sep 17 00:00:00 2001 From: Roji Philip Date: Wed, 11 Oct 2023 21:14:58 +0530 Subject: [PATCH 26/43] added comments --- src/libs/actions/Report.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index c115df445c41..1ab0685580f0 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1389,9 +1389,13 @@ function updateWriteCapabilityAndNavigate(report, newValue) { /** * Navigates to the 1:1 report with Concierge * - * @param {Boolean} ignoreConciergeReportID + * @param {Boolean} ignoreConciergeReportID - Flag to ignore conciergeChatReportID during navigation. The default behavior is to not ignore. */ function navigateToConciergeChat(ignoreConciergeReportID = false) { + // If conciergeChatReportID contains a concierge report ID, we navigate to the concierge chat using the stored report ID. + // Otherwise, we would find the concierge chat and navigate to it. + // Now, when user performs sign-out and a sign-in again, conciergeChatReportID may contain a stale value. + // In order to prevent navigation to a stale value, we use ignoreConciergeReportID to forcefully find and navigate to concierge chat. if (!conciergeChatReportID || ignoreConciergeReportID) { // In order to avoid creating concierge repeatedly, // we need to ensure that the server data has been successfully pulled From 1f91fe9986a5ef8cd7c6ba3164174d23fb731037 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 11 Oct 2023 22:50:54 +0700 Subject: [PATCH 27/43] change name function --- src/components/MoneyRequestHeader.js | 2 +- src/libs/HeaderUtils.js | 4 ++-- src/pages/home/HeaderView.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 647ad7d362e7..caa6d0a6d57e 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -90,7 +90,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, setIsDeleteModalVisible(false); }, [canModifyRequest]); - const threeDotsMenuItems = [HeaderUtils.getPinFunctionality(report)]; + const threeDotsMenuItems = [HeaderUtils.getPinOptions(report)]; if (canModifyRequest) { if (!TransactionUtils.hasReceipt(transaction)) { threeDotsMenuItems.push({ diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.js index 915a713bbe2c..4d5f7d78f754 100644 --- a/src/libs/HeaderUtils.js +++ b/src/libs/HeaderUtils.js @@ -8,7 +8,7 @@ import * as Expensicons from '../components/Icon/Expensicons'; * @param {Object} report * @returns {Object} */ -function getPinFunctionality(report) { +function getPinOptions(report) { if (!report.isPinned) { return { icon: Expensicons.Pin, @@ -27,5 +27,5 @@ function getPinFunctionality(report) { export { // eslint-disable-next-line import/prefer-default-export - getPinFunctionality, + getPinOptions, }; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index c8dc6b8bde54..9f32ba25341a 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -135,7 +135,7 @@ function HeaderView(props) { } } - threeDotMenuItems.push(HeaderUtils.getPinFunctionality(props.report)); + threeDotMenuItems.push(HeaderUtils.getPinOptions(props.report)); if (isConcierge && props.guideCalendarLink) { threeDotMenuItems.push({ From 4600363e9789dfa21cae79fa45a2861a397f1454 Mon Sep 17 00:00:00 2001 From: Rodrigo Lino da Costa Date: Wed, 11 Oct 2023 17:00:03 -0300 Subject: [PATCH 28/43] Changed inconmark color for adhoc build loading screen --- assets/images/new-expensify-adhoc.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/images/new-expensify-adhoc.svg b/assets/images/new-expensify-adhoc.svg index 26f18c8cc088..d3a926a097ec 100644 --- a/assets/images/new-expensify-adhoc.svg +++ b/assets/images/new-expensify-adhoc.svg @@ -1,6 +1,6 @@ From d6f8379d107409f3a25c5d02a4d23f3a83e58637 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Wed, 11 Oct 2023 23:52:58 +0100 Subject: [PATCH 29/43] revert comment and use function destructure --- src/components/Hoverable/index.js | 4 ++++ src/components/Tooltip/BaseTooltip.js | 9 ++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js index 281c1e7860f7..5cba52db5a7b 100644 --- a/src/components/Hoverable/index.js +++ b/src/components/Hoverable/index.js @@ -42,6 +42,10 @@ class Hoverable extends Component { if (!scrolling && this.isHoveredRef) { this.setState({isHovered: this.isHoveredRef}, this.props.onHoverIn); } else if (scrolling && this.isHoveredRef) { + /** + * If the user has started scrolling and the isHoveredRef is true, then we should set the hover state to false. + * This is to hide the existing hover and reaction bar. + */ this.setState({isHovered: false}, this.props.onHoverOut); } this.isScrollingRef = scrolling; diff --git a/src/components/Tooltip/BaseTooltip.js b/src/components/Tooltip/BaseTooltip.js index bcbb14686a2e..f8d1cf87fc42 100644 --- a/src/components/Tooltip/BaseTooltip.js +++ b/src/components/Tooltip/BaseTooltip.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import React, {memo, useCallback, useEffect, useRef, useState} from 'react'; import {Animated} from 'react-native'; import {BoundsObserver} from '@react-ng/bounds-observer'; +import Str from 'expensify-common/lib/str'; import TooltipRenderedOnPageBody from './TooltipRenderedOnPageBody'; import Hoverable from '../Hoverable'; import * as tooltipPropTypes from './tooltipPropTypes'; @@ -53,9 +54,7 @@ function chooseBoundingBox(target, clientX, clientY) { return bbs[0]; } -function Tooltip(props) { - const {children, numberOfLines, maxWidth, text, renderTooltipContent, renderTooltipContentKey, shouldHandleScroll} = props; - +function Tooltip({children, numberOfLines, maxWidth, text, renderTooltipContent, renderTooltipContentKey, shouldHandleScroll, shiftHorizontal, shiftVertical}) { const {preferredLocale} = useLocalize(); const {windowWidth} = useWindowDimensions(); @@ -183,8 +182,8 @@ function Tooltip(props) { yOffset={yOffset} targetWidth={wrapperWidth} targetHeight={wrapperHeight} - shiftHorizontal={_.result(props, 'shiftHorizontal')} - shiftVertical={_.result(props, 'shiftVertical')} + shiftHorizontal={Str.result(shiftHorizontal)} + shiftVertical={Str.result(shiftVertical)} text={text} maxWidth={maxWidth} numberOfLines={numberOfLines} From 88893c5ac5a568c65ffe74dac45311e0e24aae3c Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Thu, 12 Oct 2023 07:33:23 +0530 Subject: [PATCH 30/43] update notification count --- .../UnreadIndicatorUpdater/updateUnread/index.website.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js index 244eaf805d10..d624c02f525f 100644 --- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js +++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js @@ -3,6 +3,7 @@ */ import CONFIG from '../../../CONFIG'; +let _totalCount = 0; /** * Set the page title on web * @@ -10,7 +11,7 @@ import CONFIG from '../../../CONFIG'; */ function updateUnread(totalCount) { const hasUnread = totalCount !== 0; - + _totalCount = totalCount; // This setTimeout is required because due to how react rendering messes with the DOM, the document title can't be modified synchronously, and we must wait until all JS is done // running before setting the title. setTimeout(() => { @@ -22,4 +23,8 @@ function updateUnread(totalCount) { }, 0); } +window.addEventListener('popstate', (event) => { + updateUnread(_totalCount) + }) + export default updateUnread; From 04c4827d6ad93c427947c4bb197f2a1aa2250320 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Thu, 12 Oct 2023 07:41:18 +0530 Subject: [PATCH 31/43] update lint --- .../updateUnread/index.website.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js index d624c02f525f..aeb590420c1f 100644 --- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js +++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js @@ -3,7 +3,7 @@ */ import CONFIG from '../../../CONFIG'; -let _totalCount = 0; +let unReadTotalCount = 0; /** * Set the page title on web * @@ -11,7 +11,7 @@ let _totalCount = 0; */ function updateUnread(totalCount) { const hasUnread = totalCount !== 0; - _totalCount = totalCount; + unReadTotalCount = totalCount; // This setTimeout is required because due to how react rendering messes with the DOM, the document title can't be modified synchronously, and we must wait until all JS is done // running before setting the title. setTimeout(() => { @@ -23,8 +23,8 @@ function updateUnread(totalCount) { }, 0); } -window.addEventListener('popstate', (event) => { - updateUnread(_totalCount) - }) +window.addEventListener('popstate', () => { + updateUnread(unReadTotalCount); +}); export default updateUnread; From 75854f578f1765b0499e7e3aa4a86763825a8724 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 12 Oct 2023 07:57:35 +0530 Subject: [PATCH 32/43] adding android script --- package.json | 1 + scripts/select-device.sh | 22 ++++++++++++++++++++++ scripts/setup-newdot-web-emulators.sh | 22 ---------------------- scripts/start-android.sh | 11 +++++++++++ 4 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 scripts/start-android.sh diff --git a/package.json b/package.json index 26937ea33741..3edc5c7e8321 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "configure-mapbox": "scripts/setup-mapbox-sdk-walkthrough.sh", "setupNewDotWebForEmulators": "scripts/setup-newdot-web-emulators.sh", + "startAndroidEmulator": "scripts/start-android.sh", "postinstall": "scripts/postInstall.sh", "clean": "npx react-native clean-project-auto", "android": "scripts/set-pusher-suffix.sh && npx react-native run-android --variant=developmentDebug --appId=com.expensify.chat.dev", diff --git a/scripts/select-device.sh b/scripts/select-device.sh index d83709d927ab..a53a6034d3da 100755 --- a/scripts/select-device.sh +++ b/scripts/select-device.sh @@ -68,6 +68,28 @@ kill_all_emulators_ios() { killall Simulator } +restart_adb_server() { + info "Restarting adb ..." + adb kill-server + sleep 2 + adb start-server + sleep 2 + info "Restarting adb done" +} + +ensure_device_available() { + # Must turn off exit on error temporarily + set +e + if adb devices | grep -q offline; then + restart_adb_server + if adb devices | grep -q offline; then + error "Device remains 'offline'. Please investigate!" + exit 1 + fi + fi + set -e +} + select_device_android() { # shellcheck disable=SC2124 diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh index 85f3a2686cc7..88598dd2e692 100755 --- a/scripts/setup-newdot-web-emulators.sh +++ b/scripts/setup-newdot-web-emulators.sh @@ -51,28 +51,6 @@ setup_ios() kill_all_emulators_ios } -restart_adb_server() { - info "Restarting adb ..." - adb kill-server - sleep 2 - adb start-server - sleep 2 - info "Restarting adb done" -} - -ensure_device_available() { - # Must turn off exit on error temporarily - set +e - if adb devices | grep -q offline; then - restart_adb_server - if adb devices | grep -q offline; then - error "Device remains 'offline'. Please investigate!" - exit 1 - fi - fi - set -e -} - setup_android_path_1() { adb root || { diff --git a/scripts/start-android.sh b/scripts/start-android.sh new file mode 100644 index 000000000000..b9a4e08a07a2 --- /dev/null +++ b/scripts/start-android.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Script for starting android emulator correctly + +# Use functions to select and open the emulator for iOS and Android +source scripts/select-device.sh + +select_device_android +sleep 30 +ensure_device_available +adb reverse tcp:8082 tcp:8082 \ No newline at end of file From b2d504ef33ce13a4130c854874551ac54bdf9488 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 12 Oct 2023 08:00:14 +0530 Subject: [PATCH 33/43] fix android script --- scripts/setup-newdot-web-emulators.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/setup-newdot-web-emulators.sh b/scripts/setup-newdot-web-emulators.sh index 88598dd2e692..a0ed1422d2a9 100755 --- a/scripts/setup-newdot-web-emulators.sh +++ b/scripts/setup-newdot-web-emulators.sh @@ -61,7 +61,7 @@ setup_android_path_1() sleep 2 adb remount adb push /etc/hosts /system/etc/hosts - # kill_all_emulators_android + kill_all_emulators_android } setup_android_path_2() @@ -80,7 +80,7 @@ setup_android_path_2() sleep 2 adb remount adb push /etc/hosts /system/etc/hosts - # kill_all_emulators_android + kill_all_emulators_android } setup_android() From 6a04e5990888a319868380262a0f0389e32ca95f Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Wed, 11 Oct 2023 23:04:58 -0400 Subject: [PATCH 34/43] revert to previous token for issues temporarily --- .github/workflows/finishReleaseCycle.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/finishReleaseCycle.yml b/.github/workflows/finishReleaseCycle.yml index f8b68786aaab..12afae0dc5e3 100644 --- a/.github/workflows/finishReleaseCycle.yml +++ b/.github/workflows/finishReleaseCycle.yml @@ -40,7 +40,7 @@ jobs: if: ${{ !fromJSON(steps.isDeployer.outputs.IS_DEPLOYER) }} uses: Expensify/App/.github/actions/javascript/reopenIssueWithComment@main with: - GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} COMMENT: | Sorry, only members of @Expensify/Mobile-Deployers can close deploy checklists. @@ -51,14 +51,14 @@ jobs: id: checkDeployBlockers uses: Expensify/App/.github/actions/javascript/checkDeployBlockers@main with: - GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} - name: Reopen and comment on issue (has blockers) if: ${{ fromJSON(steps.isDeployer.outputs.IS_DEPLOYER) && fromJSON(steps.checkDeployBlockers.outputs.HAS_DEPLOY_BLOCKERS || 'false') }} uses: Expensify/App/.github/actions/javascript/reopenIssueWithComment@main with: - GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} COMMENT: | This issue either has unchecked items or has not yet been marked with the `:shipit:` emoji of approval. From b77907f39001566f6cc2d04f945a37f6b50c0ff5 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Wed, 11 Oct 2023 23:22:36 -0400 Subject: [PATCH 35/43] Update finishReleaseCycle.yml --- .github/workflows/finishReleaseCycle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/finishReleaseCycle.yml b/.github/workflows/finishReleaseCycle.yml index 12afae0dc5e3..4fe6249edacc 100644 --- a/.github/workflows/finishReleaseCycle.yml +++ b/.github/workflows/finishReleaseCycle.yml @@ -34,7 +34,7 @@ jobs: echo "IS_DEPLOYER=false" >> "$GITHUB_OUTPUT" fi env: - GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - name: Reopen and comment on issue (not a team member) if: ${{ !fromJSON(steps.isDeployer.outputs.IS_DEPLOYER) }} From e1d0896a44bc04e6ae2999d4ce6a42ceb4876737 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 12 Oct 2023 03:33:03 +0000 Subject: [PATCH 36/43] Update version to 1.3.82-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 8e5044fb9527..fde410c9e9c5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001038110 - versionName "1.3.81-10" + versionCode 1001038200 + versionName "1.3.82-0" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index cb04e9c1ef90..311c4c447e0c 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.81 + 1.3.82 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.81.10 + 1.3.82.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index e597c10142d8..b284f7db8675 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.81 + 1.3.82 CFBundleSignature ???? CFBundleVersion - 1.3.81.10 + 1.3.82.0 diff --git a/package-lock.json b/package-lock.json index e61b21504b7b..827460d2f154 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.81-10", + "version": "1.3.82-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.81-10", + "version": "1.3.82-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 57060257f0e9..ff5ee4d52d71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.81-10", + "version": "1.3.82-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 e88773b043736eb6100b7a775c6574fe6cd08458 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Wed, 11 Oct 2023 23:40:14 -0400 Subject: [PATCH 37/43] fix production checkout --- .github/workflows/deploy.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9e0f633ae34e..ea4e8746e7fa 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -32,6 +32,12 @@ jobs: runs-on: ubuntu-latest if: github.ref == 'refs/heads/production' steps: + - uses: actions/checkout@v3 + name: Checkout + with: + ref: production + token: ${{ secrets.OS_BOTIFY_TOKEN }} + - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab id: setupGitForOSBotify with: @@ -39,13 +45,6 @@ jobs: OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }} - - uses: actions/checkout@v3 - - name: Checkout - uses: actions/checkout@v3 - with: - ref: production - token: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} - - name: Get current app version run: echo "PRODUCTION_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" From 44e65c4cddcb3784fd418c1e1909a9f58ec32ce2 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Wed, 11 Oct 2023 23:40:39 -0400 Subject: [PATCH 38/43] fix staging checkout --- .github/workflows/deploy.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ea4e8746e7fa..78040f237689 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,6 +9,12 @@ jobs: runs-on: ubuntu-latest if: github.ref == 'refs/heads/staging' steps: + - name: Checkout staging branch + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + with: + ref: staging + token: ${{ secrets.OS_BOTIFY_TOKEN }} + - uses: Expensify/App/.github/actions/composite/setupGitForOSBotifyApp@8c19d6da4a3d7ce3b15c9cd89a802187d208ecab id: setupGitForOSBotify with: @@ -16,12 +22,6 @@ jobs: OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }} - - name: Checkout staging branch - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 - with: - ref: staging - token: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} - - name: Tag version run: git tag "$(npm run print-version --silent)" From 8a96c9a1e750650a011e8792132904ce05f5709a Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 12 Oct 2023 03:57:05 +0000 Subject: [PATCH 39/43] Update version to 1.3.82-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 fde410c9e9c5..1ed86bacbf41 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001038200 - versionName "1.3.82-0" + versionCode 1001038201 + versionName "1.3.82-1" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 311c4c447e0c..6effc9b319d1 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.82.0 + 1.3.82.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index b284f7db8675..f1459843995a 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.82.0 + 1.3.82.1 diff --git a/package-lock.json b/package-lock.json index 827460d2f154..f19124ac3fd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.82-0", + "version": "1.3.82-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.82-0", + "version": "1.3.82-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ff5ee4d52d71..fc12307d0329 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.82-0", + "version": "1.3.82-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 518161c27fedff21294dfe147ee33ccf21636717 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 12 Oct 2023 03:57:38 +0000 Subject: [PATCH 40/43] Update version to 1.3.83-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 1ed86bacbf41..bdaa4c343a93 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001038201 - versionName "1.3.82-1" + versionCode 1001038300 + versionName "1.3.83-0" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 6effc9b319d1..5e2654a14fe4 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.82 + 1.3.83 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.82.1 + 1.3.83.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index f1459843995a..b0a458e62633 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.82 + 1.3.83 CFBundleSignature ???? CFBundleVersion - 1.3.82.1 + 1.3.83.0 diff --git a/package-lock.json b/package-lock.json index f19124ac3fd9..790af13e8c2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.82-1", + "version": "1.3.83-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.82-1", + "version": "1.3.83-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index fc12307d0329..87af349130df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.82-1", + "version": "1.3.83-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 54109b61b87e4f0090eae8fb7cd9a3e1d4efd45c Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 12 Oct 2023 04:50:26 +0000 Subject: [PATCH 41/43] Update version to 1.3.83-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 bdaa4c343a93..27bceccc6d32 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001038300 - versionName "1.3.83-0" + versionCode 1001038301 + versionName "1.3.83-1" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 5e2654a14fe4..fd6ad177d56b 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.83.0 + 1.3.83.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index b0a458e62633..af1ff6f92259 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.83.0 + 1.3.83.1 diff --git a/package-lock.json b/package-lock.json index 790af13e8c2c..13ae50b2d537 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.83-0", + "version": "1.3.83-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.83-0", + "version": "1.3.83-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 87af349130df..3256b8f65199 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.83-0", + "version": "1.3.83-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 a2a7c08447b7fde7367a6ebf905d79167c2a0dd4 Mon Sep 17 00:00:00 2001 From: Dylan Date: Thu, 12 Oct 2023 17:28:27 +0700 Subject: [PATCH 42/43] change name function --- src/components/MoneyRequestHeader.js | 2 +- src/libs/HeaderUtils.js | 6 +++--- src/pages/home/HeaderView.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index caa6d0a6d57e..0f2d19d424b6 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -90,7 +90,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, setIsDeleteModalVisible(false); }, [canModifyRequest]); - const threeDotsMenuItems = [HeaderUtils.getPinOptions(report)]; + const threeDotsMenuItems = [HeaderUtils.getPinMenuItem(report)]; if (canModifyRequest) { if (!TransactionUtils.hasReceipt(transaction)) { threeDotsMenuItems.push({ diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.js index 4d5f7d78f754..ccc7bac3f571 100644 --- a/src/libs/HeaderUtils.js +++ b/src/libs/HeaderUtils.js @@ -6,9 +6,9 @@ import * as Expensicons from '../components/Icon/Expensicons'; /** * @param {Object} report - * @returns {Object} + * @returns {Object} pin/unpin object */ -function getPinOptions(report) { +function getPinMenuItem(report) { if (!report.isPinned) { return { icon: Expensicons.Pin, @@ -27,5 +27,5 @@ function getPinOptions(report) { export { // eslint-disable-next-line import/prefer-default-export - getPinOptions, + getPinMenuItem, }; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 9f32ba25341a..fc913fb201e0 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -135,7 +135,7 @@ function HeaderView(props) { } } - threeDotMenuItems.push(HeaderUtils.getPinOptions(props.report)); + threeDotMenuItems.push(HeaderUtils.getPinMenuItem(props.report)); if (isConcierge && props.guideCalendarLink) { threeDotMenuItems.push({ From 2344675d2c6722c54efc1f3d476a5c06b5f7daf1 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Thu, 12 Oct 2023 18:23:58 +0530 Subject: [PATCH 43/43] update property name --- .../UnreadIndicatorUpdater/updateUnread/index.website.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js index aeb590420c1f..4c829239ef14 100644 --- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js +++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js @@ -3,7 +3,7 @@ */ import CONFIG from '../../../CONFIG'; -let unReadTotalCount = 0; +let unreadTotalCount = 0; /** * Set the page title on web * @@ -11,7 +11,7 @@ let unReadTotalCount = 0; */ function updateUnread(totalCount) { const hasUnread = totalCount !== 0; - unReadTotalCount = totalCount; + unreadTotalCount = totalCount; // This setTimeout is required because due to how react rendering messes with the DOM, the document title can't be modified synchronously, and we must wait until all JS is done // running before setting the title. setTimeout(() => { @@ -24,7 +24,7 @@ function updateUnread(totalCount) { } window.addEventListener('popstate', () => { - updateUnread(unReadTotalCount); + updateUnread(unreadTotalCount); }); export default updateUnread;