From 3e941ffa9b5affc42a787a1f543984c236ed68b9 Mon Sep 17 00:00:00 2001 From: mateusbra Date: Fri, 30 Jul 2021 23:11:33 -0300 Subject: [PATCH 1/4] expensify-common hash update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd8d39e531d2e..1baf224cb5e9a 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "electron-log": "^4.3.5", "electron-serve": "^1.0.0", "electron-updater": "^4.3.4", - "expensify-common": "git://github.com/Expensify/expensify-common.git#e83c6998dac6837098745139cb2bdd4e18bf7134", + "expensify-common": "git://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", "expo-haptics": "^10.0.0", "file-loader": "^6.0.0", "html-entities": "^1.3.1", From 7efd1cd6ed194506d22edb9b6eeea3959931bf04 Mon Sep 17 00:00:00 2001 From: mateusbra Date: Mon, 2 Aug 2021 13:42:19 -0300 Subject: [PATCH 2/4] Updating expensify-common hash --- package-lock.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7015b7eef3943..f24b47dd40521 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23075,8 +23075,8 @@ } }, "expensify-common": { - "version": "git://github.com/Expensify/expensify-common.git#e83c6998dac6837098745139cb2bdd4e18bf7134", - "from": "git://github.com/Expensify/expensify-common.git#e83c6998dac6837098745139cb2bdd4e18bf7134", + "version": "git://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", + "from": "git://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", "requires": { "classnames": "2.3.1", "clipboard": "2.0.4", @@ -36094,14 +36094,14 @@ "from": "git+https://github.com/Expensify/react-native-onyx.git#d73900b7cb7bf82bed77cb6b6baabf8fe2eb3a0e", "requires": { "ascii-table": "0.0.9", - "expensify-common": "git+https://github.com/Expensify/expensify-common.git#2e5cff552cf132da90a3fb9756e6b4fb6ae7b40c", + "expensify-common": "git+https://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", "lodash": "4.17.21", "underscore": "^1.13.1" }, "dependencies": { "expensify-common": { - "version": "git+https://github.com/Expensify/expensify-common.git#2e5cff552cf132da90a3fb9756e6b4fb6ae7b40c", - "from": "git+https://github.com/Expensify/expensify-common.git#2e5cff552cf132da90a3fb9756e6b4fb6ae7b40c", + "version": "git+https://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", + "from": "git+https://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", "requires": { "classnames": "2.2.5", "clipboard": "2.0.4", From 0d8da7fd386e84ba1bb5541e3690ee343f01ffc4 Mon Sep 17 00:00:00 2001 From: Matheus Braz Date: Mon, 2 Aug 2021 20:35:24 -0300 Subject: [PATCH 3/4] Updating hash in expensify-common --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2cbdf68a245e6..21428f084452e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23075,8 +23075,8 @@ } }, "expensify-common": { - "version": "git://github.com/Expensify/expensify-common.git#89becf7fa3106d4dd26c81a56d29b8f4b5d7ee87", - "from": "git://github.com/Expensify/expensify-common.git#89becf7fa3106d4dd26c81a56d29b8f4b5d7ee87", + "version": "git://github.com/Expensify/expensify-common.git#4016a786d66ff38ed76a191edef31ebd737a0190", + "from": "git://github.com/Expensify/expensify-common.git#4016a786d66ff38ed76a191edef31ebd737a0190", "requires": { "classnames": "2.3.1", "clipboard": "2.0.4", @@ -36094,14 +36094,14 @@ "from": "git+https://github.com/Expensify/react-native-onyx.git#d73900b7cb7bf82bed77cb6b6baabf8fe2eb3a0e", "requires": { "ascii-table": "0.0.9", - "expensify-common": "git+https://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", + "expensify-common": "git+https://github.com/Expensify/expensify-common.git#4016a786d66ff38ed76a191edef31ebd737a0190", "lodash": "4.17.21", "underscore": "^1.13.1" }, "dependencies": { "expensify-common": { - "version": "git+https://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", - "from": "git+https://github.com/Expensify/expensify-common.git#326206dee3f758da09ebc3bc184cfb66366ecec5", + "version": "git+https://github.com/Expensify/expensify-common.git#4016a786d66ff38ed76a191edef31ebd737a0190", + "from": "git+https://github.com/Expensify/expensify-common.git#4016a786d66ff38ed76a191edef31ebd737a0190", "requires": { "classnames": "2.2.5", "clipboard": "2.0.4", diff --git a/package.json b/package.json index d0fda054005b7..01b8b5c3d41f3 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "electron-log": "^4.3.5", "electron-serve": "^1.0.0", "electron-updater": "^4.3.4", - "expensify-common": "git://github.com/Expensify/expensify-common.git#89becf7fa3106d4dd26c81a56d29b8f4b5d7ee87", + "expensify-common": "git://github.com/Expensify/expensify-common.git#4016a786d66ff38ed76a191edef31ebd737a0190", "expo-haptics": "^10.0.0", "file-loader": "^6.0.0", "html-entities": "^1.3.1", From 8d8ce8dd141a943c9733ff9a9ea00db257e2ddb5 Mon Sep 17 00:00:00 2001 From: Matheus Braz Date: Mon, 2 Aug 2021 20:48:38 -0300 Subject: [PATCH 4/4] Revert "Merge branch 'main' into updated-expensify-common-hash" This reverts commit b451f3c6a316e0299bb66173e15918f49cb7b671, reversing changes made to e511b1f70082ad965b5dc85117d18f4dce54287d. --- .github/workflows/createNewVersion.yml | 2 +- .github/workflows/e2e.yml | 4 +- .github/workflows/finishReleaseCycle.yml | 2 +- .github/workflows/lockDeploys.yml | 2 +- .github/workflows/platformDeploy.yml | 6 +- .github/workflows/warnCPLabel.yml | 4 +- android/app/build.gradle | 4 +- desktop/main.js | 8 +- ios/ExpensifyCash/Info.plist | 2 +- ios/ExpensifyCashTests/Info.plist | 2 +- ios/Podfile.lock | 6 +- src/CONFIG.js | 2 +- src/CONST.js | 1 + src/ROUTES.js | 2 + .../AttachmentPicker/index.native.js | 1 + src/components/AvatarWithImagePicker.js | 10 +- src/components/OptionsSelector.js | 4 + src/languages/en.js | 17 +- src/languages/es.js | 27 +-- .../Navigation/AppNavigator/AuthScreens.js | 11 +- .../AppNavigator/ModalStackNavigators.js | 7 + src/libs/Navigation/linkingConfig.js | 6 + .../LocalNotification/BrowserNotifications.js | 2 +- src/libs/actions/BankAccounts.js | 10 +- src/libs/actions/Policy.js | 42 +++-- src/pages/ReimbursementAccount/EnableStep.js | 56 +++++++ .../ReimbursementAccountPage.js | 6 + src/pages/home/report/ParticipantLocalTime.js | 9 +- src/pages/settings/InitialPage.js | 22 ++- src/pages/workspace/WorkspaceCardPage.js | 8 +- src/pages/workspace/WorkspaceEditorPage.js | 156 ++++++++++++++++++ src/pages/workspace/WorkspaceSidebar.js | 67 ++++---- src/styles/roundToNearestMultipleOfFour.js | 2 +- src/styles/styles.js | 12 +- 34 files changed, 407 insertions(+), 115 deletions(-) create mode 100644 src/pages/ReimbursementAccount/EnableStep.js create mode 100644 src/pages/workspace/WorkspaceEditorPage.js diff --git a/.github/workflows/createNewVersion.yml b/.github/workflows/createNewVersion.yml index 9fb1f7100aa5c..4252e6c6dcb42 100644 --- a/.github/workflows/createNewVersion.yml +++ b/.github/workflows/createNewVersion.yml @@ -10,7 +10,7 @@ on: jobs: createNewVersion: if: github.actor == 'OSBotify' - runs-on: macos-latest + runs-on: macos-11 steps: # Version: 2.3.4 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index a1cce6113adbb..30ea5497df76e 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -6,12 +6,12 @@ on: branches-ignore: [staging, production] env: - DEVELOPER_DIR: /Applications/Xcode_12.3.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_12.5.app/Contents/Developer jobs: test: if: github.actor != 'OSBotify' - runs-on: macos-latest + runs-on: macos-11 steps: - uses: actions/checkout@v2 - uses: actions/setup-ruby@v1 diff --git a/.github/workflows/finishReleaseCycle.yml b/.github/workflows/finishReleaseCycle.yml index c6fdeabaf53eb..7d1aaace2ab42 100644 --- a/.github/workflows/finishReleaseCycle.yml +++ b/.github/workflows/finishReleaseCycle.yml @@ -53,7 +53,7 @@ jobs: # Deploy deferred PRs to staging and create a new StagingDeployCash for the next release cycle. createNewStagingDeployCash: - runs-on: macos-latest + runs-on: macos-11 needs: checkDeployBlockers if: ${{ needs.checkDeployBlockers.outputs.hasDeployBlockers == 'false' }} steps: diff --git a/.github/workflows/lockDeploys.yml b/.github/workflows/lockDeploys.yml index 49d58b33f7787..9123870b449eb 100644 --- a/.github/workflows/lockDeploys.yml +++ b/.github/workflows/lockDeploys.yml @@ -7,7 +7,7 @@ on: jobs: lockStagingDeploys: if: ${{ github.event.label.name == '🔐 LockCashDeploys 🔐' && contains(github.event.issue.labels.*.name, 'StagingDeployCash') && github.actor != 'OSBotify' }} - runs-on: macos-latest + runs-on: macos-11 steps: # Version: 2.3.4 - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index 4d0760f2c5bd2..3c85ac4a1d019 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -10,7 +10,7 @@ on: env: SHOULD_DEPLOY_PRODUCTION: ${{ github.event_name == 'release' }} - DEVELOPER_DIR: /Applications/Xcode_12.3.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_12.5.app/Contents/Developer jobs: android: @@ -79,7 +79,7 @@ jobs: desktop: name: Build and deploy Desktop if: github.actor == 'OSBotify' - runs-on: macos-latest + runs-on: macos-11 steps: - uses: actions/checkout@v2 @@ -134,7 +134,7 @@ jobs: iOS: name: Build and deploy iOS if: github.actor == 'OSBotify' - runs-on: macos-latest + runs-on: macos-11 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/warnCPLabel.yml b/.github/workflows/warnCPLabel.yml index bc6073029eab0..25434a5d88b7a 100644 --- a/.github/workflows/warnCPLabel.yml +++ b/.github/workflows/warnCPLabel.yml @@ -1,7 +1,7 @@ name: Explain Cherry-Pick label via OSBotify comment on: - pull_request: + pull_request_target: types: - labeled @@ -14,7 +14,7 @@ jobs: - name: Comment on PR to explain the CP Staging label uses: actions-ecosystem/action-create-comment@cd098164398331c50e7dfdd0dfa1b564a1873fac with: - github_token: ${{ secrets.OS_BOTIFY_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} body: | :warning: :warning: **Heads up! This pull request has the `CP Staging` label.** :warning: :warning: Merging it will cause it to be immediately deployed to staging, _even if the [open `StagingDeployCash` deploy checklist](https://github.com/Expensify/Expensify.cash/issues?q=is%3Aopen+is%3Aissue+label%3AStagingDeployCash) is locked._ diff --git a/android/app/build.gradle b/android/app/build.gradle index 250ee25973a4b..3d9b9bebd5b96 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -150,8 +150,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001008200 - versionName "1.0.82-0" + versionCode 1001008202 + versionName "1.0.82-2" } splits { abi { diff --git a/desktop/main.js b/desktop/main.js index 4f8892472fe09..2f84fa5d24f3c 100644 --- a/desktop/main.js +++ b/desktop/main.js @@ -86,7 +86,7 @@ const quitAndInstallWithUpdate = () => { // Defines the system-level menu item for manually triggering an update after const updateAppMenuItem = new MenuItem({ - label: 'Update Expensify.cash', + label: 'Update New Expensify', enabled: false, click: quitAndInstallWithUpdate, }); @@ -120,7 +120,7 @@ const mainWindow = (() => { // Prod and staging set the icon in the electron-builder config, so only update it here for dev if (isDev) { app.dock.setIcon(`${__dirname}/icon-dev.png`); - app.setName('Expensify.cash'); + app.setName('New Expensify'); } return app.whenReady() @@ -137,7 +137,7 @@ const mainWindow = (() => { // Prod and staging overwrite the app name in the electron-builder config, so only update it here for dev if (isDev) { - browserWindow.setTitle('Expensify.cash'); + browserWindow.setTitle('New Expensify'); } // List the Expensify Chat instance under the Window menu, even when it's hidden @@ -172,7 +172,7 @@ const mainWindow = (() => { const windowMenu = systemMenu.items.find(item => item.role === 'windowmenu'); windowMenu.submenu.append(new MenuItem({type: 'separator'})); windowMenu.submenu.append(new MenuItem({ - label: 'Expensify.cash', + label: 'New Expensify', accelerator: 'CmdOrCtrl+1', click: () => browserWindow.show(), })); diff --git a/ios/ExpensifyCash/Info.plist b/ios/ExpensifyCash/Info.plist index c43f775c510c8..c92231397a19b 100644 --- a/ios/ExpensifyCash/Info.plist +++ b/ios/ExpensifyCash/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.0.82.0 + 1.0.82.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/ExpensifyCashTests/Info.plist b/ios/ExpensifyCashTests/Info.plist index b121d99320e1f..777d404b19b97 100644 --- a/ios/ExpensifyCashTests/Info.plist +++ b/ios/ExpensifyCashTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.0.82.0 + 1.0.82.2 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 26a81647d8aff..266fa84eaa6ad 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -564,7 +564,7 @@ PODS: - UMCore - UMConstantsInterface (6.1.0): - UMCore - - UMCore (7.1.0) + - UMCore (7.1.1) - UMFaceDetectorInterface (6.1.0) - UMFileSystemInterface (6.1.0) - UMFontInterface (6.1.0) @@ -957,7 +957,7 @@ SPEC CHECKSUMS: UMBarCodeScannerInterface: 96a01d81ff0c7febbfefc2d7396db9e7462d8c68 UMCameraInterface: 8ad433fdadca22703ebeb614d42b814092d38d69 UMConstantsInterface: 55c79ca258a3ede70480fed85e3843899cd47ea3 - UMCore: 0da048c9753abcea0042258e6ad0fed77811f7e1 + UMCore: 063edcab3a9de0c44301fe77af147aa1a654b40f UMFaceDetectorInterface: 4db950a25e785796a237bcebb8fff05078c4fb61 UMFileSystemInterface: 4a92ee36e6c2757833031718f8496690fa931280 UMFontInterface: 81a951117d03f57aa636fba3992adefd0191f200 @@ -972,4 +972,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 2092930e33e7aa4d68cdf783d6174465bd3ce380 -COCOAPODS: 1.10.1 +COCOAPODS: 1.10.2 diff --git a/src/CONFIG.js b/src/CONFIG.js index b7e4f52d1b692..cb979552c0f5e 100644 --- a/src/CONFIG.js +++ b/src/CONFIG.js @@ -55,7 +55,7 @@ export default { APP_KEY: lodashGet(Config, 'PUSHER_APP_KEY', '268df511a204fbb60884'), CLUSTER: 'mt1', }, - SITE_TITLE: 'Expensify.cash', + SITE_TITLE: 'New Expensify', FAVICON: { DEFAULT: '/favicon.png', UNREAD: '/favicon-unread.png', diff --git a/src/CONST.js b/src/CONST.js index 1856c35f03a17..1365c3a35004e 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -69,6 +69,7 @@ const CONST = { VERIFICATION_MAX_ATTEMPTS: 7, STATE: { VERIFYING: 'VERIFYING', + PENDING: 'PENDING', }, }, INCORPORATION_TYPES: { diff --git a/src/ROUTES.js b/src/ROUTES.js index ab583dd6935f4..31c3badc0a5b9 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -80,6 +80,8 @@ export default { getWorkspaceInviteRoute: policyID => `workspace/${policyID}/invite`, WORKSPACE_INVITE: 'workspace/:policyID/invite', REQUEST_CALL: 'request-call', + getWorkspaceEditorRoute: policyID => `workspace/${policyID}/edit`, + WORKSPACE_EDITOR: 'workspace/:policyID/edit', VALIDATE_CODE_URL: (accountID, validateCode, exitTo = '') => { const exitToURL = exitTo ? `?exitTo=${exitTo}` : ''; return `v/${accountID}/${validateCode}${exitToURL}`; diff --git a/src/components/AttachmentPicker/index.native.js b/src/components/AttachmentPicker/index.native.js index beca94c97e50f..db2efe74e535e 100644 --- a/src/components/AttachmentPicker/index.native.js +++ b/src/components/AttachmentPicker/index.native.js @@ -50,6 +50,7 @@ function getDataForUpload(fileData) { name: fileData.fileName || fileData.name || 'chat_attachment', type: fileData.type, uri: fileData.uri, + size: fileData.size, }; } diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 219203bb57f87..27f969259bd24 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -12,6 +12,7 @@ import styles from '../styles/styles'; import themeColors from '../styles/themes/default'; import AttachmentPicker from './AttachmentPicker'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; +import variables from '../styles/variables'; const propTypes = { /** Avatar URL to display */ @@ -114,10 +115,15 @@ class AvatarWithImagePicker extends React.Component { {({openPicker}) => ( <> this.setState({isMenuVisible: true})} > - + `You have been invited to the ${workspaceName} Workspace! Download the Expensify mobile App to start tracking your expenses.`, }, + editor: { + title: 'Edit Workspace', + nameInputLabel: 'Name', + nameInputHelpText: 'This is the name you will see on your Workspace.', + save: 'Save', + genericFailureMessage: 'An error occurred updating the workspace, please try again.', + avatarUploadFailureMessage: 'An error occurred uploading the avatar, please try again.', + }, }, requestCallPage: { requestACall: 'Request a Call', diff --git a/src/languages/es.js b/src/languages/es.js index c8b487901248a..f4d3b8eff7c68 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -68,7 +68,7 @@ export default { }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', - expensifyDoesntHaveAccessToCamera: 'Expensify.cash no tiene acceso a tu cámara, por favor activa el permiso y vuelve a intentarlo.', + expensifyDoesntHaveAccessToCamera: 'Esta aplicación no tiene acceso a tu cámara, por favor activa el permiso y vuelve a intentarlo.', attachmentError: 'Error al adjuntar archivo', errorWhileSelectingAttachment: 'Ha ocurrido un error al seleccionar un adjunto, por favor inténtalo de nuevo', errorWhileSelectingCorruptedImage: 'Ha ocurrido un error al seleccionar un adjunto corrupto, por favor intentalo con otro archivo', @@ -84,7 +84,7 @@ export default { }, baseUpdateAppModal: { updateApp: 'Actualizar App', - updatePrompt: 'Existe una nueva versión de Expensify.cash.\nActualiza ahora or reinicia la aplicación más tarde para recibir la última versión.', + updatePrompt: 'Existe una nueva versión de esta aplicación.\nActualiza ahora or reinicia la aplicación más tarde para recibir la última versión.', }, iOUConfirmationList: { whoPaid: '¿QUIÉN PAGO?', @@ -105,7 +105,7 @@ export default { hello: 'Hola', phoneCountryCode: '34', welcomeText: { - phrase1: 'Con Expensify.cash, chat y pagos son lo mismo.', + phrase1: 'Con el Nuevo Expensify, chat y pagos son lo mismo.', phrase2: 'El dinero habla. Y ahora que chat y pagos están en un mismo lugar, es también fácil.', phrase3: 'Tus pagos llegan tan rápido como tus mensajes.', }, @@ -237,7 +237,7 @@ export default { }, passwordPage: { changePassword: 'Cambiar Contraseña', - changingYourPasswordPrompt: 'El cambio de contraseña va a afectar tanto a la cuenta de Expensify.com\ncomo la de Expensify.cash.', + changingYourPasswordPrompt: 'El cambio de contraseña va a afectar tanto a la cuenta de Expensify.com\ncomo la de Nuevo Expensify.', currentPassword: 'Contraseña Actual', newPassword: 'Nueva contraseña', newPasswordPrompt: 'La nueva contraseña tiene que ser diferente de la antigua, tener al menos 8 letras,\n1 letra mayúscula, 1 letra minúscula y 1 número.', @@ -274,8 +274,7 @@ export default { }, }, signInPage: { - expensifyDotCash: 'Expensify.cash', - expensifyIsOpenSource: 'Expensify.cash es open source', + expensifyDotCash: 'Nuevo Expensify', theCode: 'el código', openJobs: 'trabajos disponibles', heroHeading: 'Dividir cuentas\ny chatear con amigos.', @@ -288,13 +287,13 @@ export default { }, }, termsOfUse: { - phrase1: 'Al usar Expensify.cash, estás aceptando los', + phrase1: 'Al iniciar sesión, estás accediendo a los', phrase2: 'términos de servicio', phrase3: 'y', phrase4: 'política de privacidad', - phrase5: 'El envío de dinero es brindado por Expensify Payments LLC (NMLS ID:2017010) de conformidad con sus', - phrase6: 'licencias', - phrase7: 'licenses', + phrase5: 'El envío de dinero es brindado por Expensify Payments LLC (NMLS', + phrase6: 'ID:2017010) de conformidad con sus', + phrase7: 'licencias', }, passwordForm: { pleaseFillOutAllFields: 'Por favor completa todos los campos', @@ -584,6 +583,14 @@ export default { genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..', welcomeNote: ({workspaceName}) => `¡Has sido invitado a la ${workspaceName} Espacio de trabajo! Descargue la aplicación móvil Expensify para comenzar a rastrear sus gastos.`, }, + editor: { + title: 'Editar espacio de trabajo', + nameInputLabel: 'Nombre', + nameInputHelpText: 'Este es el nombre que verás en tu espacio de trabajo.', + save: 'Guardar', + genericFailureMessage: 'Se produjo un error al guardar el espacio de trabajo. Por favor, inténtalo de nuevo.', + avatarUploadFailureMessage: 'No se pudo subir el avatar. Por favor, inténtalo de nuevo.', + }, }, requestCallPage: { requestACall: 'Llámame por teléfono', diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 028ff82ea4438..dbbe137bafeeb 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -58,6 +58,7 @@ import { WorkspaceInviteModalStackNavigator, RequestCallModalStackNavigator, ReportDetailsModalStackNavigator, + WorkspaceEditorNavigator, } from './ModalStackNavigators'; import SCREENS from '../../../SCREENS'; import Timers from '../../Timers'; @@ -268,7 +269,7 @@ class AuthScreens extends React.Component { name={SCREENS.HOME} options={{ headerShown: false, - title: 'Expensify.cash', + title: 'New Expensify', // prevent unnecessary scrolling cardStyle: { @@ -281,7 +282,7 @@ class AuthScreens extends React.Component { name="ValidateLogin" options={{ headerShown: false, - title: 'Expensify.cash', + title: 'New Expensify', }} component={ValidateLoginPage} /> @@ -408,6 +409,12 @@ class AuthScreens extends React.Component { component={IOUSendModalStackNavigator} listeners={modalScreenListeners} /> + ); } diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 326dc6ed11ad0..786228868dc19 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -28,6 +28,7 @@ import ReimbursementAccountPage from '../../../pages/ReimbursementAccount/Reimbu import NewWorkspacePage from '../../../pages/workspace/NewWorkspacePage'; import RequestCallPage from '../../../pages/RequestCallPage'; import ReportDetailsPage from '../../../pages/ReportDetailsPage'; +import WorkspaceEditorPage from '../../../pages/workspace/WorkspaceEditorPage'; const defaultSubRouteOptions = { cardStyle: styles.navigationScreenCardStyle, @@ -197,6 +198,11 @@ const RequestCallModalStackNavigator = createModalStackNavigator([{ name: 'RequestCall_Root', }]); +const WorkspaceEditorNavigator = createModalStackNavigator([{ + Component: WorkspaceEditorPage, + name: 'WorkspaceEditor_Root', +}]); + export { IOUBillStackNavigator, IOURequestModalStackNavigator, @@ -215,4 +221,5 @@ export { NewWorkspaceStackNavigator, WorkspaceInviteModalStackNavigator, RequestCallModalStackNavigator, + WorkspaceEditorNavigator, }; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index cf3c57b07ac6b..48ace4ba68ae2 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -157,6 +157,12 @@ export default { }, }, + WorkspaceEditor: { + screens: { + WorkspaceEditor_Root: ROUTES.WORKSPACE_EDITOR, + }, + }, + RequestCall: { screens: { RequestCall_Root: ROUTES.REQUEST_CALL, diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js index f5e128d3eec1c..b122c16f03acf 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -126,7 +126,7 @@ export default { pushUpdateAvailableNotification() { push({ title: 'Update available', - body: 'A new version of Expensify.cash is available!', + body: 'A new version of this app is available!', delay: 0, onClick: () => { Onyx.merge(ONYXKEYS.UPDATE_AVAILABLE, true); diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 168bac43e8877..23ea4e36a16aa 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -9,7 +9,6 @@ import * as API from '../API'; import BankAccount from '../models/BankAccount'; import promiseAllSettled from '../promiseAllSettled'; import Growl from '../Growl'; -import Navigation from '../Navigation/Navigation'; import {translateLocal} from '../translate'; /** @@ -450,7 +449,7 @@ function fetchFreePlanVerifiedBankAccount(stepToOpen) { ? CONST.BANK_ACCOUNT.STEP.VALIDATION : CONST.BANK_ACCOUNT.STEP.COMPANY; achData.bankAccountInReview = hasTriedToUpgrade; } else { - // In Expensify.cash we do not show a specific view for the EnableStep since we + // We do not show a specific view for the EnableStep since we // will enable the Expensify card automatically. However, we will still handle // that step and show the Validate view. currentStep = CONST.BANK_ACCOUNT.STEP.ENABLE; @@ -552,8 +551,11 @@ function validateBankAccount(bankAccountID, validateCode) { .then((response) => { if (response.jsonCode === 200) { Growl.show('Bank Account successfully validated!', CONST.GROWL.SUCCESS, 3000); - Navigation.dismissModal(); - Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: false, error: ''}); + API.User_IsUsingExpensifyCard() + .then(({isUsingExpensifyCard}) => { + Onyx.merge(ONYXKEYS.USER, {isUsingExpensifyCard}); + Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: false, error: ''}); + }); return; } diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 4965508c8b166..251b2470b3698 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -207,35 +207,41 @@ function create(name) { } /** - * Sets avatar or removes it if called with no avatarURL - * - * @param {String} policyID - * @param {String} [avatarURL] + * @param {Object} file + * @returns {Promise} */ -function setAvatarURL(policyID, avatarURL = '') { - API.UpdatePolicy({policyID, value: JSON.stringify({avatarURL}), lastModified: null}) - .then((policyResponse) => { - if (policyResponse.jsonCode !== 200) { +function uploadAvatar(file) { + return API.User_UploadAvatar({file}) + .then((response) => { + if (response.jsonCode !== 200) { + // Show the user feedback + const errorMessage = translateLocal('workspace.editor.avatarUploadFailureMessage'); + Growl.error(errorMessage, 5000); return; } - Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {avatarURL}); + return response.s3url; }); } /** + * Sets the name of the policy + * * @param {String} policyID - * @param {Object} file + * @param {Object} values */ -function updateAvatar(policyID, file) { - API.User_UploadAvatar({file}) - .then((response) => { - if (response.jsonCode !== 200) { +function update(policyID, values) { + API.UpdatePolicy({policyID, value: JSON.stringify(values), lastModified: null}) + .then((policyResponse) => { + if (policyResponse.jsonCode !== 200) { + // Show the user feedback + const errorMessage = translateLocal('workspace.editor.genericFailureMessage'); + Growl.error(errorMessage, 5000); return; } - // Once we get the s3url back, update the policy with the new avatar URL - setAvatarURL(policyID, response.s3url); + Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, values); + Navigation.dismissModal(); }); } @@ -245,6 +251,6 @@ export { removeMembers, invite, create, - updateAvatar, - setAvatarURL, + uploadAvatar, + update, }; diff --git a/src/pages/ReimbursementAccount/EnableStep.js b/src/pages/ReimbursementAccount/EnableStep.js new file mode 100644 index 0000000000000..45c991561b78e --- /dev/null +++ b/src/pages/ReimbursementAccount/EnableStep.js @@ -0,0 +1,56 @@ +import React from 'react'; +import {Image, View} from 'react-native'; +import styles from '../../styles/styles'; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import {navigateToConciergeChat} from '../../libs/actions/Report'; +import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; +import Navigation from '../../libs/Navigation/Navigation'; +import Text from '../../components/Text'; +import CONST from '../../CONST'; +import TextLink from '../../components/TextLink'; +import compose from '../../libs/compose'; + +const propTypes = { + ...withLocalizePropTypes, +}; + +const EnableStep = ({translate}) => { + const verifyingUrl = `${CONST.CLOUDFRONT_URL}/images/icons/emptystates/emptystate_reviewing.gif`; + return ( + + + + + + {translate('validationStep.reviewingInfo')} + { + // There are two modals that must be dismissed before we can reveal the Concierge + // chat underneath these screens + Navigation.dismissModal(); + Navigation.dismissModal(); + navigateToConciergeChat(); + }} + > + {translate('common.here')} + + {translate('validationStep.forNextSteps')} + + + + ); +}; + +EnableStep.propTypes = propTypes; +EnableStep.displayName = 'EnableStep'; + +export default compose( + withLocalize, +)(EnableStep); diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index ce76ff22233c7..05c93882eb350 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -24,6 +24,7 @@ import CompanyStep from './CompanyStep'; import RequestorStep from './RequestorStep'; import ValidationStep from './ValidationStep'; import BeneficialOwnersStep from './BeneficialOwnersStep'; +import EnableStep from './EnableStep'; import ROUTES from '../../ROUTES'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; @@ -232,6 +233,11 @@ class ReimbursementAccountPage extends React.Component { error={error} /> )} + {currentStep === CONST.BANK_ACCOUNT.STEP.ENABLE && ( + + )} ); diff --git a/src/pages/home/report/ParticipantLocalTime.js b/src/pages/home/report/ParticipantLocalTime.js index 010edcf25ce26..9e6b14eda91eb 100644 --- a/src/pages/home/report/ParticipantLocalTime.js +++ b/src/pages/home/report/ParticipantLocalTime.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {PureComponent} from 'react'; import { View, } from 'react-native'; @@ -18,7 +18,7 @@ const propTypes = { ...withLocalizePropTypes, }; -class ParticipantLocalTime extends React.Component { +class ParticipantLocalTime extends PureComponent { constructor(props) { super(props); this.getParticipantLocalTime = this.getParticipantLocalTime.bind(this); @@ -35,13 +35,8 @@ class ParticipantLocalTime extends React.Component { }, 1000)); } - shouldComponentUpdate(nextProps, nextState) { - return nextState.localTime !== this.state.localTime; - } - componentWillUnmount() { clearInterval(this.timer); - clearInterval(this.readyTimer); } getParticipantLocalTime() { diff --git a/src/pages/settings/InitialPage.js b/src/pages/settings/InitialPage.js index 064691876484a..9305ba6a6e63b 100755 --- a/src/pages/settings/InitialPage.js +++ b/src/pages/settings/InitialPage.js @@ -1,5 +1,5 @@ import React from 'react'; -import {View, ScrollView} from 'react-native'; +import {View, ScrollView, Pressable} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; @@ -153,6 +153,9 @@ const InitialSettingsPage = ({ .value(); menuItems.push(...defaultMenuItems); + + const openProfileSettings = () => Navigation.navigate(ROUTES.SETTINGS_PROFILE); + return ( - + - - - {myPersonalDetails.displayName - ? myPersonalDetails.displayName - : Str.removeSMSDomain(session.email)} - + + + + + {myPersonalDetails.displayName + ? myPersonalDetails.displayName + : Str.removeSMSDomain(session.email)} + + {myPersonalDetails.displayName && ( { - const isVerifying = lodashGet(reimbursementAccount, 'achData.state', '') === CONST.BANK_ACCOUNT.STATE.VERIFYING; + const isVerifying = lodashGet(reimbursementAccount, 'achData.state', '') === BankAccount.STATE.VERIFYING; + const isPending = lodashGet(reimbursementAccount, 'achData.state', '') === BankAccount.STATE.PENDING; + const isNotAutoProvisioned = !user.isUsingExpensifyCard + && lodashGet(reimbursementAccount, 'achData.state', '') === BankAccount.STATE.OPEN; let buttonText; if (user.isFromPublicDomain) { buttonText = translate('workspace.card.addEmail'); } else if (user.isUsingExpensifyCard) { buttonText = translate('workspace.card.manageCards'); - } else if (isVerifying) { + } else if (isVerifying || isPending || isNotAutoProvisioned) { buttonText = translate('workspace.card.finishSetup'); } else { buttonText = translate('workspace.card.getStarted'); diff --git a/src/pages/workspace/WorkspaceEditorPage.js b/src/pages/workspace/WorkspaceEditorPage.js new file mode 100644 index 0000000000000..7486a7ddf2993 --- /dev/null +++ b/src/pages/workspace/WorkspaceEditorPage.js @@ -0,0 +1,156 @@ +import React from 'react'; +import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; +import lodashGet from 'lodash/get'; +import _ from 'underscore'; +import ONYXKEYS from '../../ONYXKEYS'; +import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; +import ScreenWrapper from '../../components/ScreenWrapper'; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import Navigation from '../../libs/Navigation/Navigation'; +import Permissions from '../../libs/Permissions'; +import styles from '../../styles/styles'; +import TextInputWithLabel from '../../components/TextInputWithLabel'; +import Button from '../../components/Button'; +import Text from '../../components/Text'; +import compose from '../../libs/compose'; +import { + uploadAvatar, update, +} from '../../libs/actions/Policy'; +import Icon from '../../components/Icon'; +import {Workspace} from '../../components/Icon/Expensicons'; +import AvatarWithImagePicker from '../../components/AvatarWithImagePicker'; +import defaultTheme from '../../styles/themes/default'; + +const propTypes = { + /** List of betas */ + betas: PropTypes.arrayOf(PropTypes.string), + + ...withLocalizePropTypes, +}; +const defaultProps = { + betas: [], +}; + +class WorkspaceEditorPage extends React.Component { + constructor(props) { + super(props); + + this.state = { + name: props.policy.name, + avatarURL: props.policy.avatarURL, + previewAvatarURL: props.policy.avatarURL, + }; + + this.submit = this.submit.bind(this); + this.onImageSelected = this.onImageSelected.bind(this); + this.onImageRemoved = this.onImageRemoved.bind(this); + this.uploadAvatarPromise = Promise.resolve(); + } + + onImageSelected(image) { + this.setState({previewAvatarURL: image.uri}); + + // Store the upload avatar promise so we can wait for it to finish before updating the policy + this.uploadAvatarPromise = uploadAvatar(image).then(url => new Promise((resolve) => { + this.setState({avatarURL: url}, resolve); + })); + } + + onImageRemoved() { + this.setState({previewAvatarURL: '', avatarURL: ''}); + } + + submit() { + // Wait for the upload avatar promise to finish before updating the policy + this.uploadAvatarPromise.then(() => { + const name = this.state.name.trim(); + const avatarURL = this.state.avatarURL; + const policyID = this.props.policy.id; + + update(policyID, {name, avatarURL}); + }); + } + + render() { + const {policy} = this.props; + + if (!Permissions.canUseFreePlan(this.props.betas)) { + console.debug('Not showing workspace editor page because user is not on free plan beta'); + return ; + } + + if (_.isEmpty(policy)) { + return null; + } + + return ( + + + + + + ( + + )} + style={[styles.mb3]} + anchorPosition={{top: 172, right: 18}} + isUsingDefaultAvatar={!this.state.previewAvatarURL} + onImageSelected={this.onImageSelected} + onImageRemoved={this.onImageRemoved} + /> + + this.setState({name})} + onSubmitEditting={this.submit} + /> + + {this.props.translate('workspace.editor.nameInputHelpText')} + + + +