diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js index a0f2f1d9880e..a52464078689 100644 --- a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js +++ b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js @@ -236,7 +236,11 @@ function getMergeLogsAsJSON(fromRef, toRef) { sanitizedOutput = sanitizedOutput.replace(/(\r\n|\n|\r)/gm, ''); // Then format as JSON and convert to a proper JS object - const json = `[${sanitizedOutput}]`.replace('},]', '}]'); + const json = `[${sanitizedOutput}]`.replace('},]', '}]') + + // Escape backslashes in commit messages that end with a backslash + .replace('\\"}', '\\\\"}'); + return JSON.parse(json); }); } diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index b62a9df9ba18..c35d0970967c 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -169,7 +169,11 @@ function getMergeLogsAsJSON(fromRef, toRef) { sanitizedOutput = sanitizedOutput.replace(/(\r\n|\n|\r)/gm, ''); // Then format as JSON and convert to a proper JS object - const json = `[${sanitizedOutput}]`.replace('},]', '}]'); + const json = `[${sanitizedOutput}]`.replace('},]', '}]') + + // Escape backslashes in commit messages that end with a backslash + .replace('\\"}', '\\\\"}'); + return JSON.parse(json); }); } diff --git a/.github/libs/GitUtils.js b/.github/libs/GitUtils.js index 327ef6b2b5e4..6b4a6ff327f4 100644 --- a/.github/libs/GitUtils.js +++ b/.github/libs/GitUtils.js @@ -42,7 +42,11 @@ function getMergeLogsAsJSON(fromRef, toRef) { sanitizedOutput = sanitizedOutput.replace(/(\r\n|\n|\r)/gm, ''); // Then format as JSON and convert to a proper JS object - const json = `[${sanitizedOutput}]`.replace('},]', '}]'); + const json = `[${sanitizedOutput}]`.replace('},]', '}]') + + // Escape backslashes in commit messages that end with a backslash + .replace('\\"}', '\\\\"}'); + return JSON.parse(json); }); } diff --git a/.github/scripts/buildActions.sh b/.github/scripts/buildActions.sh index d0c1db7ede69..d0581572a143 100755 --- a/.github/scripts/buildActions.sh +++ b/.github/scripts/buildActions.sh @@ -42,7 +42,7 @@ for ((i=0; i < ${#GITHUB_ACTIONS[@]}; i++)); do # Build the action in the background ncc build "$ACTION" -o "$ACTION_DIR" & - ASYNC_BUILDS[$i]=$! + ASYNC_BUILDS[i]=$! done for ((i=0; i < ${#GITHUB_ACTIONS[@]}; i++)); do @@ -50,7 +50,7 @@ for ((i=0; i < ${#GITHUB_ACTIONS[@]}; i++)); do ACTION_DIR=$(dirname "$ACTION") # Wait for the background build to finish - wait ${ASYNC_BUILDS[$i]} + wait "${ASYNC_BUILDS[$i]}" # Prepend the warning note to the top of the compiled file OUTPUT_FILE="$ACTION_DIR/index.js" diff --git a/.github/scripts/validateActionsAndWorkflows.sh b/.github/scripts/validateActionsAndWorkflows.sh index b4474560c0c9..3785f7da3352 100755 --- a/.github/scripts/validateActionsAndWorkflows.sh +++ b/.github/scripts/validateActionsAndWorkflows.sh @@ -36,7 +36,7 @@ info 'Validating actions and workflows against their JSON schemas...' for ((i=0; i < ${#ACTIONS[@]}; i++)); do ACTION=${ACTIONS[$i]} ajv -s ./tempSchemas/github-action.json -d "$ACTION" --strict=false & - ASYNC_PROCESSES[$i]=$! + ASYNC_PROCESSES[i]=$! done for ((i=0; i < ${#WORKFLOWS[@]}; i++)); do @@ -48,12 +48,12 @@ for ((i=0; i < ${#WORKFLOWS[@]}; i++)); do fi ajv -s ./tempSchemas/github-workflow.json -d "$WORKFLOW" --strict=false & - ASYNC_PROCESSES[${#ACTIONS[@]} + $i]=$! + ASYNC_PROCESSES[${#ACTIONS[@]} + i]=$! done # Wait for the background builds to finish for PID in "${ASYNC_PROCESSES[@]}"; do - wait $PID + wait "$PID" RESULT=$? if [[ $RESULT != 0 ]]; then EXIT_CODE=$RESULT diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index e2af94a00472..a39663797baf 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -2,6 +2,10 @@ name: Build and deploy apps for testing on: workflow_dispatch: + inputs: + PULL_REQUEST_NUMBER: + description: Pull Request number for correct placement of apps + required: true pull_request_target: types: [opened, synchronize] branches: ['*ci-test/**'] @@ -22,16 +26,38 @@ jobs: username: ${{ github.actor }} team: mobile-deployers + getBranchRef: + runs-on: ubuntu-latest + needs: validateActor + if: ${{ fromJSON(needs.validateActor.outputs.IS_TEAM_MEMBER) }} + outputs: + REF: ${{steps.getHeadRef.outputs.REF}} + steps: + - name: Checkout + if: ${{ github.event_name == 'workflow_dispatch' }} + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - name: Check if pull request number is correct + if: ${{ github.event_name == 'workflow_dispatch' }} + id: getHeadRef + run: | + set -e + gh pr checkout ${{ github.event.inputs.PULL_REQUEST_NUMBER }} + echo "REF=$(git rev-parse --abbrev-ref HEAD)" >> "$GITHUB_OUTPUT" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + android: name: Build and deploy Android for testing - needs: validateActor + needs: [validateActor, getBranchRef] if: ${{ fromJSON(needs.validateActor.outputs.IS_TEAM_MEMBER) }} runs-on: ubuntu-latest + env: + PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} steps: # This action checks-out the repository, so the workflow can access it. - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.head_ref || needs.getBranchRef.outputs.REF }} - uses: Expensify/App/.github/actions/composite/setupNode@main @@ -64,7 +90,6 @@ jobs: S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} S3_BUCKET: ad-hoc-expensify-cash S3_REGION: us-east-1 - PULL_REQUEST_NUMBER: ${{ github.event.number }} - uses: actions/upload-artifact@v3 with: @@ -73,14 +98,16 @@ jobs: iOS: name: Build and deploy iOS for testing - needs: validateActor + needs: [validateActor, getBranchRef] if: ${{ fromJSON(needs.validateActor.outputs.IS_TEAM_MEMBER) }} + env: + PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} runs-on: macos-12 steps: # This action checks-out the repository, so the workflow can access it. - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.head_ref || needs.getBranchRef.outputs.REF }} - uses: Expensify/App/.github/actions/composite/setupNode@main @@ -119,7 +146,6 @@ jobs: S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} S3_BUCKET: ad-hoc-expensify-cash S3_REGION: us-east-1 - PULL_REQUEST_NUMBER: ${{ github.event.number }} - uses: actions/upload-artifact@v3 with: @@ -128,13 +154,16 @@ jobs: desktop: name: Build and deploy Desktop for testing - needs: validateActor + needs: [validateActor, getBranchRef] if: ${{ fromJSON(needs.validateActor.outputs.IS_TEAM_MEMBER) }} + env: + PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} runs-on: macos-12 steps: # This action checks-out the repository, so the workflow can access it. - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 with: + ref: ${{ github.head_ref || needs.getBranchRef.outputs.REF }} fetch-depth: 0 - uses: Expensify/App/.github/actions/composite/setupNode@main @@ -159,17 +188,18 @@ jobs: APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - PULL_REQUEST_NUMBER: ${{ github.event.number }} postGithubComment: runs-on: ubuntu-latest name: Post a GitHub comment with app download links for testing - needs: [android, ios, desktop] + needs: [getBranchRef, android, ios, desktop] + env: + PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} steps: - name: Checkout uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 with: - ref: ${{ github.event.pull_request.head.ref }} + ref: ${{ github.head_ref || needs.getBranchRef.outputs.REF }} - uses: actions/download-artifact@v3 @@ -186,6 +216,15 @@ jobs: content_ios="${content_ios//$'\n'/'%0A'}" content_ios="${content_ios//$'\r'/'%0D'}" echo "ios_paths=$content_ios" >> "$GITHUB_OUTPUT" + + # This step removes previous comments with links connected to the PR + - name: maintain-comment + uses: actions-cool/maintain-one-comment@de04bd2a3750d86b324829a3ff34d47e48e16f4b + with: + token: ${{ secrets.OS_BOTIFY_TOKEN }} + body-include: 'Use the links below to test this build in android and iOS. Happy testing!' + number: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }} + delete: true - name: Publish links to apps for download run: | @@ -193,7 +232,7 @@ jobs: ":test_tube::test_tube: Use the links below to test this build in android and iOS. Happy testing! :test_tube::test_tube: | android :robot: | iOS :apple: | desktop :computer: | | ------------- | ------------- | ------------- | - | ${{fromJson(steps.set_var.outputs.android_paths).html_path}} | ${{fromJson(steps.set_var.outputs.ios_paths).html_path}} | https://ad-hoc-expensify-cash.us-east-1.amazonaws.com/desktop/${{github.event.number}}/NewExpensify.dmg | - | ![Android](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${{fromJson(steps.set_var.outputs.android_paths).html_path}}) | ![iOS](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${{fromJson(steps.set_var.outputs.ios_paths).html_path}}) | ![desktop](https://ad-hoc-expensify-cash.us-east-1.amazonaws.com/desktop/${{github.event.number}}/NewExpensify.dmg) |" + | ${{fromJson(steps.set_var.outputs.android_paths).html_path}} | ${{fromJson(steps.set_var.outputs.ios_paths).html_path}} | https://ad-hoc-expensify-cash.us-east-1.amazonaws.com/desktop/$PULL_REQUEST_NUMBER/NewExpensify.dmg | + | ![Android](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${{fromJson(steps.set_var.outputs.android_paths).html_path}}) | ![iOS](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${{fromJson(steps.set_var.outputs.ios_paths).html_path}}) | ![desktop](https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://ad-hoc-expensify-cash.us-east-1.amazonaws.com/desktop/$PULL_REQUEST_NUMBER/NewExpensify.dmg) |" env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} diff --git a/android/app/build.gradle b/android/app/build.gradle index f0b68a3e6348..109290f4cf22 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001023800 - versionName "1.2.38-0" + versionCode 1001023900 + versionName "1.2.39-0" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/contributingGuides/CONTRIBUTING.md b/contributingGuides/CONTRIBUTING.md index ea4504d07f6a..3e580738abac 100644 --- a/contributingGuides/CONTRIBUTING.md +++ b/contributingGuides/CONTRIBUTING.md @@ -68,7 +68,7 @@ This is the most common scenario for contributors. The Expensify team posts new #### Proposing a job that Expensify hasn't posted It’s possible that you found a new bug or new feature that we haven’t posted as a job to the [GitHub repository](https://github.com/Expensify/App/issues?q=is%3Aissue). This is an opportunity to propose a job, and (optionally) a solution for that job. If it's a valid job proposal that we choose to implement by deploying it to production — either internally or via an external contributor — then we will compensate you $250 for identifying and proposing the bug or feature. If the bug or feature is fixed by a PR that is not associated with your proposal, then you will not be eligible for the corresponding compensation unless you can find the PR that fixed it and prove your proposal came first. - Note: If you get assigned the job you proposed **and** you complete the job, this $250 for identifying the improvement is *in addition to* the reward you will be paid for completing the job. -- Note about proposed bugs or features: Expensify has the right not to pay the $250 reward if the suggested bug or feature is already planned. Currently, Expensify plans to implement all features of the old Expensify app in New Expensify. +- Note about proposed bugs or features: Expensify has the right not to pay the $250 reward if the suggested bug has already been reported or the feature request is already planned. Following, if more than one contributor proposes the same bug, the contributor who posted it first is the one who is eligible for the bonus. - Note: whilst you may optionally propose a solution for that job on Slack, solutions are ultimately reviewed in GitHub. The onus is on you to propose the solution on GitHub, and/or ensure the issue creator will include a link to your proposal. Please follow these steps to propose a job: diff --git a/fastlane/Fastfile b/fastlane/Fastfile index c479a8d5e8c2..e60b41583cb8 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -162,7 +162,7 @@ platform :ios do region: ENV['S3_REGION'], ipa: lane_context[SharedValues::IPA_OUTPUT_PATH], - app_directory: "android/#{ENV['PULL_REQUEST_NUMBER']}", + app_directory: "ios/#{ENV['PULL_REQUEST_NUMBER']}", ) sh("echo '{\"ipa_path\": \"#{lane_context[SharedValues::S3_IPA_OUTPUT_PATH]}\",\"html_path\": \"#{lane_context[SharedValues::S3_HTML_OUTPUT_PATH]}\"}' > ../ios_paths.json") diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 3a5d89e05004..0bda69a4cc53 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.38 + 1.2.39 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.38.0 + 1.2.39.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 52e471af78b7..7e65fb22e7ec 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.2.38 + 1.2.39 CFBundleSignature ???? CFBundleVersion - 1.2.38.0 + 1.2.39.0 diff --git a/package-lock.json b/package-lock.json index f0f878afd2f4..b2895c9a15f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.38-0", + "version": "1.2.39-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.38-0", + "version": "1.2.39-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index d95af9e60f70..c4293d02bee0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.38-0", + "version": "1.2.39-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.", diff --git a/src/components/Form.js b/src/components/Form.js index 72ee4afc6b00..a6320fe04b74 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -79,7 +79,6 @@ class Form extends React.Component { this.inputRefs = {}; this.touchedInputs = {}; - this.childPosition = {}; this.setTouchedInput = this.setTouchedInput.bind(this); this.validate = this.validate.bind(this); @@ -109,21 +108,6 @@ class Form extends React.Component { return _.first(_.keys(hasStateErrors ? this.state.erorrs : this.props.formState.errorFields)); } - setPosition(element, position) { - // Some elements might not have props defined, e.g. Text - if (!element.props) { - return; - } - - if (!element.props.inputID && element.props.children) { - _.forEach(element.props.children, (child) => { - this.setPosition(child, position); - }); - } else { - this.childPosition[element.props.inputID] = position; - } - } - submit() { // Return early if the form is already submitting to avoid duplicate submission if (this.props.formState.isLoading) { @@ -268,16 +252,7 @@ class Form extends React.Component { ref={el => this.form = el} > - {_.map(this.childrenWrapperWithProps(this.props.children), child => ( - { - this.setPosition(child, event.nativeEvent.layout.y); - }} - > - {child} - - ))} + {this.childrenWrapperWithProps(this.props.children)} {this.props.isSubmitButtonVisible && ( _.keys(errors).includes(key)); const focusInput = this.inputRefs[focusKey]; - this.form.scrollTo({y: this.childPosition[focusKey], animated: false}); if (focusInput.focus && typeof focusInput.focus === 'function') { focusInput.focus(); } + + // We substract 10 to scroll slightly above the input + if (focusInput.measureLayout && typeof focusInput.measureLayout === 'function') { + focusInput.measureLayout(this.form, (x, y) => this.form.scrollTo({y: y - 10, animated: false})); + } }} - containerStyles={[styles.mh0, styles.mt5]} + containerStyles={[styles.mh0, styles.mt5, styles.flex1]} enabledWhenOffline={this.props.enabledWhenOffline} isDangerousAction={this.props.isDangerousAction} /> diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js index 91b1867a6f91..323df19c7720 100644 --- a/src/components/Modal/BaseModal.js +++ b/src/components/Modal/BaseModal.js @@ -9,6 +9,7 @@ import themeColors from '../../styles/themes/default'; import {propTypes as modalPropTypes, defaultProps as modalDefaultProps} from './modalPropTypes'; import * as Modal from '../../libs/actions/Modal'; import getModalStyles from '../../styles/getModalStyles'; +import variables from '../../styles/variables'; const propTypes = { ...modalPropTypes, @@ -100,8 +101,8 @@ class BaseModal extends PureComponent { onSwipeComplete={this.props.onClose} swipeDirection={swipeDirection} isVisible={this.props.isVisible} - backdropColor={themeColors.modalBackdrop} - backdropOpacity={hideBackdrop ? 0 : 0.5} + backdropColor={themeColors.overlay} + backdropOpacity={hideBackdrop ? 0 : variables.overlayOpacity} backdropTransitionOutTiming={0} hasBackdrop={this.props.fullscreen} coverScreen={this.props.fullscreen} diff --git a/src/components/MultipleAvatars.js b/src/components/MultipleAvatars.js index 70e917bde33c..2f8f86e6f337 100644 --- a/src/components/MultipleAvatars.js +++ b/src/components/MultipleAvatars.js @@ -9,6 +9,7 @@ import Text from './Text'; import themeColors from '../styles/themes/default'; import * as StyleUtils from '../styles/StyleUtils'; import CONST from '../CONST'; +import variables from '../styles/variables'; const propTypes = { /** Array of avatar URLs or icons */ @@ -99,6 +100,9 @@ const MultipleAvatars = (props) => { styles.alignItemsCenter, styles.justifyContentCenter, StyleUtils.getHorizontalStackedAvatarBorderStyle(props.isHovered, props.isPressed), + + // Set overlay background color with RGBA value so that the text will not inherit opacity + StyleUtils.getBackgroundColorWithOpacityStyle(themeColors.overlay, variables.overlayOpacity), styles.horizontalStackedAvatar4Overlay, ]} > diff --git a/src/components/OfflineWithFeedback.js b/src/components/OfflineWithFeedback.js index c02441f61ecd..44415ad60f19 100644 --- a/src/components/OfflineWithFeedback.js +++ b/src/components/OfflineWithFeedback.js @@ -103,7 +103,7 @@ const OfflineWithFeedback = (props) => { )} {(props.shouldShowErrorMessages && hasErrors) && ( - + { : styles.sidebarLinkText; const textUnreadStyle = (props.boldStyle) ? [textStyle, styles.sidebarLinkTextBold] : [textStyle]; - const displayNameStyle = [styles.optionDisplayName, ...textUnreadStyle, props.style]; - const alternateTextStyle = [textStyle, styles.optionAlternateText, styles.textLabelSupporting, props.style]; + const displayNameStyle = StyleUtils.combineStyles(styles.optionDisplayName, textUnreadStyle, props.style); + const alternateTextStyle = StyleUtils.combineStyles(textStyle, styles.optionAlternateText, styles.textLabelSupporting, props.style); const contentContainerStyles = [styles.flex1]; const sidebarInnerRowStyle = StyleSheet.flatten([ styles.chatLinkRowPressable, diff --git a/src/components/RoomHeaderAvatars.js b/src/components/RoomHeaderAvatars.js index 4b96b45af8cc..e3c96ccc6d80 100644 --- a/src/components/RoomHeaderAvatars.js +++ b/src/components/RoomHeaderAvatars.js @@ -73,7 +73,7 @@ const RoomHeaderAvatars = (props) => { diff --git a/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js b/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js index 433620deecb9..1ec48a356328 100644 --- a/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js +++ b/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js @@ -1,6 +1,7 @@ import {Animated} from 'react-native'; import variables from '../../../styles/variables'; import getCardStyles from '../../../styles/cardStyles'; +import themeColors from '../../../styles/themes/default'; export default ( isSmallScreenWidth, @@ -34,9 +35,10 @@ export default ( }, cardStyle, overlayStyle: { + backgroundColor: themeColors.overlay, opacity: progress.interpolate({ inputRange: [0, 1], - outputRange: [0, 0.3], + outputRange: [0, variables.overlayOpacity], extrapolate: 'clamp', }), }, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 58c23bb46d66..def6e0861156 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -436,7 +436,7 @@ function getDefaultAvatar(login = '') { * @returns {Array<*>} */ function getIcons(report, personalDetails, policies, defaultIcon = null) { - if (!report) { + if (_.isEmpty(report)) { return [defaultIcon || getDefaultAvatar()]; } if (isArchivedRoom(report)) { @@ -894,7 +894,7 @@ function buildOptimisticChatReport( lastMessageHtml: '', lastMessageText: null, lastReadSequenceNumber: 0, - lastActionCreated: '', + lastActionCreated: DateUtils.getDBTime(), lastReadTimestamp: 0, maxSequenceNumber: 0, notificationPreference, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 3eb215e1303e..c6c5f9f8c23e 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -67,7 +67,7 @@ function requestMoney(report, amount, currency, recipientEmail, participant, com isNewChat = true; } let iouReport; - if (chatReport.iouReportID) { + if (chatReport.hasOutstandingIOU && chatReport.iouReportID) { iouReport = IOUUtils.updateIOUOwnerAndTotal( iouReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`], recipientEmail, diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index b6f6dd5c348f..7a59a0d3f853 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -684,14 +684,14 @@ function openPaymentDetailsPage(chatReportID, iouReportID) { * Marks the new report actions as read * * @param {String} reportID - * @param {String} created + * @param {String} createdDate */ -function readNewestAction(reportID, created) { +function readNewestAction(reportID, createdDate) { const sequenceNumber = getMaxSequenceNumber(reportID); API.write('ReadNewestAction', { reportID, - created: DateUtils.getDBTime(created), + createdDate, sequenceNumber, }, { @@ -710,17 +710,17 @@ function readNewestAction(reportID, created) { * Sets the last read comment on a report * * @param {String} reportID - * @param {String} created + * @param {String} createdDate * @param {Number} sequenceNumber */ -function markCommentAsUnread(reportID, created, sequenceNumber) { +function markCommentAsUnread(reportID, createdDate, sequenceNumber) { const newLastReadSequenceNumber = sequenceNumber - 1; API.write('MarkAsUnread', { reportID, // We subtract 1 millisecond so that the lastRead is updated to just before this reportAction's created date - created: DateUtils.getDBTime(new Date(created) - 1), + createdDate: DateUtils.getDBTime(moment.utc(createdDate).valueOf() - 1), sequenceNumber, }, { diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index 12a09d5e189a..f0a23f515921 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -224,6 +224,7 @@ const chatReportSelector = (report) => { stateNum: report.stateNum, chatType: report.chatType, policyID: report.policyID, + reportName: report.reportName, }); }; diff --git a/src/pages/signin/LoginForm.js b/src/pages/signin/LoginForm.js index e9813c3bfb1f..e64705de8239 100755 --- a/src/pages/signin/LoginForm.js +++ b/src/pages/signin/LoginForm.js @@ -111,6 +111,11 @@ class LoginForm extends React.Component { if (this.props.account.errors) { Session.clearAccountMessages(); } + + // Clear the "Account successfully closed" message when the user starts typing + if (this.props.closeAccount.success) { + CloseAccount.setDefaultData(); + } } /** diff --git a/src/styles/styles.js b/src/styles/styles.js index dc168715ef60..748ab024bdc4 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -1734,7 +1734,6 @@ const styles = { width: 28, borderWidth: 2, borderStyle: 'solid', - backgroundColor: themeColors.opaqueAvatar, borderRadius: 24, zIndex: 6, }, @@ -1972,14 +1971,14 @@ const styles = { marginLeft: -16, }, - screenBlur: { + roomHeaderAvatarOverlay: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, - backgroundColor: themeColors.inverse, - opacity: 0.5, + backgroundColor: themeColors.overlay, + opacity: variables.overlayOpacity, }, avatarInnerTextChat: { @@ -2169,6 +2168,7 @@ const styles = { fontWeight: fontWeightBold, fontSize: variables.iouAmountTextSize, color: themeColors.heading, + lineHeight: variables.inputHeight, }, iouAmountTextInput: addOutlineWidth({ @@ -2524,13 +2524,13 @@ const styles = { }, cardOverlay: { - backgroundColor: themeColors.modalBackdrop, + backgroundColor: themeColors.overlay, position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', - opacity: 0.5, + opacity: variables.overlayOpacity, }, communicationsLinkIcon: { diff --git a/src/styles/themes/default.js b/src/styles/themes/default.js index 4a4825b2aa9f..f569ae0912bd 100644 --- a/src/styles/themes/default.js +++ b/src/styles/themes/default.js @@ -31,6 +31,7 @@ const darkTheme = { transparent: colors.transparent, // Additional keys + overlay: colors.greenHighlightBackground, inverse: colors.white, shadow: colors.black, componentBG: colors.greenAppBackground, @@ -46,8 +47,7 @@ const darkTheme = { textMutedReversed: colors.greenIcons, textError: colors.red, offline: colors.greenIcons, - opaqueAvatar: 'rgba(198, 201, 202, 0.64)', - modalBackdrop: colors.greenIcons, + modalBackdrop: colors.greenHighlightBackground, modalBackground: colors.greenAppBackground, cardBG: colors.greenHighlightBackground, cardBorder: colors.greenHighlightBackground, @@ -88,8 +88,6 @@ const oldTheme = { textMutedReversed: colors.gray3, buttonDefaultBG: colors.gray2, offline: colors.gray3, - sidebarButtonBG: 'rgba(198, 201, 202, 0.25)', - opaqueAvatar: 'rgba(011, 027, 052, 0.64)', modalBackdrop: colors.gray3, modalBackground: colors.gray2, buttonDisabledBG: colors.gray2, @@ -105,6 +103,7 @@ const oldTheme = { cardBG: colors.gray1, cardBorder: colors.gray1, checkBox: colors.blue, + overlay: colors.gray1, // Merging new Keys for Dark Mode merge. Delete after new branding is implemented. highlightBG: colors.gray1, diff --git a/src/styles/variables.js b/src/styles/variables.js index 663729823701..86f0141b5076 100644 --- a/src/styles/variables.js +++ b/src/styles/variables.js @@ -70,6 +70,7 @@ export default { optionRowHeight: 64, optionRowHeightCompact: 52, optionsListSectionHeaderHeight: getValueUsingPixelRatio(54, 60), + overlayOpacity: 0.6, lineHeightSmall: getValueUsingPixelRatio(14, 16), lineHeightNormal: getValueUsingPixelRatio(16, 21), lineHeightLarge: getValueUsingPixelRatio(18, 24),