From a980def40b4e08d3e16a1fb7c1902dd1cd87d1eb Mon Sep 17 00:00:00 2001 From: "alberto@expensify.com" Date: Tue, 1 Jun 2021 17:40:24 +0200 Subject: [PATCH 01/20] Make IOU badges clickable --- src/components/IOUBadge.js | 46 +++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/components/IOUBadge.js b/src/components/IOUBadge.js index ffbed144e9be..1f82a04964b5 100644 --- a/src/components/IOUBadge.js +++ b/src/components/IOUBadge.js @@ -5,10 +5,18 @@ import {withOnyx} from 'react-native-onyx'; import Num from 'expensify-common/lib/Num'; import ONYXKEYS from '../ONYXKEYS'; import styles from '../styles/styles'; +import Navigation from '../libs/Navigation/Navigation'; +import ROUTES from '../ROUTES'; const propTypes = { /** IOU Report data object */ iouReport: PropTypes.shape({ + /** The report ID of the IOU */ + reportID: PropTypes.number, + + /** The report ID of the chat associated with theIOU */ + chatReportID: PropTypes.number, + /** The total amount in cents */ total: PropTypes.number, @@ -24,27 +32,35 @@ const propTypes = { const defaultProps = { iouReport: { + reportID: 0, + chatReportID: 0, total: 0, ownerEmail: null, }, }; -const IOUBadge = props => ( - - { + const launchIOUDetailsModal = () => { + Navigation.navigate(ROUTES.getIouDetailsRoute(props.iouReport.chatReportID, props.iouReport.reportID)); + }; + return ( + - {`$${Num.number_format(props.iouReport.total / 100, 2)}`} - - -); + + {`$${Num.number_format(props.iouReport.total / 100, 2)}`} + + + ); +}; IOUBadge.displayName = 'IOUBadge'; IOUBadge.propTypes = propTypes; From 792ee88ef5fa6507854c9421f4a1722fa9598034 Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Thu, 3 Jun 2021 17:28:30 -0600 Subject: [PATCH 02/20] Add Spanish locales --- src/languages/es.js | 276 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/src/languages/es.js b/src/languages/es.js index 201a74f4f84a..b0751ae6f279 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1,3 +1,279 @@ +/* eslint-disable max-len */ export default { + common: { + cancel: 'Cancelar', + upload: 'Subir', + yes: 'Si', + no: 'No', + attachment: 'Adjunto', + to: 'A', + optional: 'Opcional', + new: 'NUEVO', + search: 'Buscar', + next: 'Siguiente', + add: 'Agregar', + resend: 'Reenviar', + save: 'Guardar', + password: 'Contraseña', + profile: 'Perfil', + payments: 'Pagos', + preferences: 'Preferencias', + view: 'Ver', + not: 'No', + signIn: 'Conectarse', + continue: 'Continuar', + phoneNumber: 'Numero de teléfono', + email: 'Email', + and: 'y', + details: 'Detalles', + delete: 'Eliminar', + contacts: 'Contactos', + recents: 'Recientes', + }, + 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.', + attachmentError: 'Error en el adjunto', + errorWhileSelectingAttachment: 'Ha ocurrido un error al seleccionar un adjunto, por favor inténtalo de nuevo', + errorWhileSelectingCorruptedImage: 'Ha occurrido un error al seleccionar un adjunto corrupto, por favor intenta otro archivo', + errorDuringAttachmentSelection: 'Error durante la selección del adjunto', + takePhoto: 'Sacar Foto', + chooseFromGallery: 'Elegir de la galería', + chooseDocument: 'Elegir Documento', + }, + textInputFocusable: { + noExtentionFoundForMimeType: 'No se encontró una extension para este tipo', + problemGettingImageYouPasted: 'Ha ocurrido un problema obteniendo la imágen que has pegado', + }, + baseUpdateAppModal: { + updateApp: 'Actualizar App', + updatePrompt: 'Esta disponible una nueva version de Expensify.cash.\nActualiza ahora or reinicia la aplicación luego para recibir la última version.', + }, + iOUConfirmationList: { + whoPaid: 'QUIÉN PAGO?', + whoWasThere: 'QUIÉN ESTABA?', + whatsItFor: 'PARA QUÉ ES?', + }, + iOUCurrencySelection: { + selectCurrency: 'Selecciona una moneda', + allCurrencies: 'TODAS LAS MONEDAS', + }, + optionsSelector: { + nameEmailOrPhoneNumber: 'Nombre, email o número de teléfono', + }, + videoChatButtonAndMenu: { + zoom: 'Zoom', + googleMeet: 'Google Meet', + }, hello: 'Hola', + phoneCountryCode: '34', + welcomeText: { + phrase1: 'Con Expensify.cash, 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.', + }, + reportActionCompose: { + uploadAttachment: 'Subir Adjunto', + addAttachment: 'Agregar Adjunto', + writeSomething: 'Escribe algo...', + youAppearToBeOffline: 'Parece que estás desconectado.', + }, + reportActionContextMenu: { + copyToClipboard: 'Copiar al Porta Papeles', + copied: 'Copiado!', + copyLink: 'Copiar Enlace', + markAsUnread: 'Marcar como no leído', + editComment: 'Editar Commentario', + deleteComment: 'Eliminar comentario', + deleteConfirmation: 'Estás seguro de que quieres eliminar este comentario?', + }, + reportActionsView: { + beFirstPersonToComment: 'Se el primero en comentar', + }, + reportTypingIndicator: { + isTyping: 'está escribiendo...', + areTyping: 'están escribiendo...', + multipleUsers: 'Varios usuarios', + }, + sidebarScreen: { + newChat: 'Nuevo Chat', + newGroup: 'Nuevo Grupo', + headerChat: 'Chats', + buttonSearch: 'Buscar', + buttonMySettings: 'Mi configuración', + fabNewChat: 'Nuevo Chat', + }, + iou: { + amount: 'Importe', + participants: 'Participantes', + confirm: 'Confirmar', + splitBill: 'Dividir Factura', + requestMoney: 'Pedir Dinero', + pay: 'Pagar', + viewDetails: 'Ver detalles', + settleElsewhere: 'Voy a pagar por otro medio', + decline: 'Rechazar', + settlePaypalMe: 'Pagar con PayPal.me', + settleVenmo: 'Pagar con Venmo', + request: ({amount}) => `Request ${amount}`, + owes: ({manager, owner}) => `${manager} debe a ${owner}`, + paid: ({owner, manager}) => `${manager} pagó a ${owner}`, + split: ({amount}) => `Dividir ${amount}`, + choosePaymentMethod: 'Elige el método de pago:', + }, + loginField: { + addYourPhoneToSettleViaVenmo: 'Agrega tu número de teléfono para pagar usando Venmo.', + numberHasNotBeenValidated: 'El número no está validado todavía. Haz click en el botón para reenviar el enlace de validación via SMS.', + useYourPhoneToSettleViaVenmo: 'Usa tu número de teléfono para pagar usando Venmo.', + emailHasNotBeenValidated: 'El email no está validado todavía. Haz click en el botón para reenviar el enlace de validación via email.', + }, + profilePage: { + uploadPhoto: 'Subir Foto', + removePhoto: 'Eliminar Foto', + profile: 'Perfil', + editPhoto: 'Editar Foto', + tellUsAboutYourself: 'Cuéntanos algo sobre tí, nos encantaría llegar a conocerte!', + firstName: 'Nombre', + john: 'Juan', + lastName: 'Apellido', + doe: 'Nadie', + preferredPronouns: 'Pronombres preferidos', + selectYourPronouns: 'Selecciona tus pronombres', + selfSelectYourPronoun: 'Auto-selecciona tu pronombre', + emailAddress: 'Dirección de Email', + setMyTimezoneAutomatically: 'Configura my huso horario automáticamente', + timezone: 'Huso horario', + growlMessageOnSave: 'Tu perfil se ha guardado correctamente', + }, + addSecondaryLoginPage: { + addPhoneNumber: 'Agregar Número de Teléfono', + addEmailAddress: 'Agregar dirección de Email', + enterPreferredPhoneNumberToSendValidationLink: 'Escribe tu número de teléfono y contraseña para recibir el enlace de validación.', + enterPreferredEmailToSendValidationLink: 'Escribe tu email y contraseña para recibir el enlace de validación.', + sendValidation: 'Enviar validación', + }, + initialSettingsPage: { + settings: 'Configuración', + about: 'Acerca de', + aboutPage: { + description: 'Expensify.cash está desarrollado por una comunidad de desarrolladores open source de todo el mundo. Ven a ayudarnos a construir la próxima generación de Expensify.', + appDownloadLinks: 'Enlaces para descargar la App', + viewTheCode: 'Ver codigo', + viewOpenJobs: 'Ver trabajos disponibles', + reportABug: 'Reporta un bug', + }, + appDownloadLinks: { + android: { + label: 'Android', + }, + ios: { + label: 'iOS', + }, + desktop: { + label: 'Desktop', + }, + }, + signOut: 'Desconectar', + versionLetter: 'v', + changePassword: 'Cambiar Contraseña', + readTheTermsAndPrivacyPolicy: { + phrase1: 'Leer los', + phrase2: 'términos de servicio', + phrase3: 'y', + phrase4: 'política de privacidad', + }, + }, + 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.', + 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 numero.', + confirmNewPassword: 'Confirma la Nueva Contraseña', + }, + paymentsPage: { + enterYourUsernameToGetPaidViaPayPal: 'Escribe to nombre de usuario para que te paguen a través de PayPal.', + payPalMe: 'PayPal.me/', + yourPayPalUsername: 'Tu usuario de PayPal', + addPayPalAccount: 'Agregar Cuenta de Paypal', + }, + preferencesPage: { + mostRecent: 'Mas Recientes', + mostRecentModeDescription: 'Esto va a mostrar por defecto todos los chats, ordenados por mas reciente primeros, con items anclados arriba de todo', + focus: '#focus', + focusModeDescription: '#focus – Esto va a mostrar solo chats no leídos y anclados ordenados alfabéticamente.', + notifications: 'Notificaciones', + receiveRelevantFeatureUpdatesAndExpensifyNews: 'Recibir noticias sobre Expensify y actualizaciones del producto', + priorityMode: 'Modo Prioridad', + }, + signInPage: { + expensifyDotCash: 'Expensify.cash', + expensifyIsOpenSource: 'Expensify.cash es open source', + theCode: 'el código', + openJobs: 'trabajos disponibles', + }, + termsOfUse: { + phrase1: 'Al ingresar, estas aceptando 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', + }, + passwordForm: { + pleaseFillOutAllFields: 'Por favor completa todos los campos', + forgot: 'Te has olvidado?', + twoFactorCode: 'Autenticación de 2 factores', + requiredWhen2FAEnabled: 'Obligatorio cuando A2F esta habilitado', + }, + loginForm: { + pleaseEnterEmailOrPhoneNumber: 'Por favor escribe un email o número de teleéfono', + phoneOrEmail: 'Teleéfono o Email', + enterYourPhoneOrEmail: 'Escribe tu teleéfono o email:', + }, + resendValidationForm: { + linkHasBeenResent: 'El enlace se ha reenviado', + weSentYouMagicSignInLink: 'Te hemos enviado un enlace - simplemente haz click en él para conectarte!', + resendLink: 'Reenviar Enlace', + }, + detailsPage: { + localTime: 'Hora local', + }, + newGroupPage: { + createGroup: 'Crear Grupo', + }, + notFound: { + chatYouLookingForCannotBeFound: 'No se pudo encontrar el chat que estabas buscando.', + getMeOutOfHere: 'Sácame de aquí', + }, + setPasswordPage: { + passwordCannotBeBlank: 'La contraseña no puede estar vacía', + enterPassword: 'Escribe una contraseña', + setPassword: 'Configura tu Contraseña', + }, + addBankAccountPage: { + enterPassword: 'Escribe una contraseña', + addBankAccount: 'Agregar una cuenta de banco', + alreadyAdded: 'Esta cuenta ya ha sido agregada.', + selectAccount: 'Selecciona una cuenta:', + }, + attachmentView: { + unknownFilename: 'Archivo desconocido', + }, + pronouns: { + heHimHis: 'El', + sheHerHers: 'Ella', + theyThemTheirs: 'Ellos', + zeHirHirs: 'Ze/hir', + selfSelect: 'Personalízalo', + callMeByMyName: 'Llámame por mi nombre', + }, + cameraPermissionsNotGranted: 'No has habilitado los permisos para acceder a la cámara', + messages: { + noPhoneNumber: 'Por favor escribe un número de teléfono que incluya el código de país e.g +447814266907', + maxParticipantsReached: 'Has llegado al número máximo de participantes para un grupo.', + }, + session: { + offlineMessage: 'Parece que no estás conectado a internet. Comprueba to conexión e inténtalo de nuevo?', + }, }; From 6e80d88c691a5ec0fab9887c8bf53d478c9876fb Mon Sep 17 00:00:00 2001 From: "alberto@expensify.com" Date: Fri, 4 Jun 2021 12:51:58 +0200 Subject: [PATCH 03/20] fix comment --- src/components/IOUBadge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/IOUBadge.js b/src/components/IOUBadge.js index bbe2ee59d901..1e37bfb7837b 100644 --- a/src/components/IOUBadge.js +++ b/src/components/IOUBadge.js @@ -15,7 +15,7 @@ const propTypes = { /** The report ID of the IOU */ reportID: PropTypes.number, - /** The report ID of the chat associated with theIOU */ + /** The report ID of the chat associated with the IOU */ chatReportID: PropTypes.number, /** The total amount in cents */ From 24c60e765cd9a94603c548aa35dd2d7018596c82 Mon Sep 17 00:00:00 2001 From: "alberto@expensify.com" Date: Fri, 4 Jun 2021 15:16:43 +0200 Subject: [PATCH 04/20] make badge pressable --- src/components/IOUBadge.js | 14 +++++++------- src/styles/colors.js | 1 + src/styles/styles.js | 23 +++++++++++++++++++++++ src/styles/themes/default.js | 2 ++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/components/IOUBadge.js b/src/components/IOUBadge.js index 1e37bfb7837b..09029a6b2a34 100644 --- a/src/components/IOUBadge.js +++ b/src/components/IOUBadge.js @@ -1,9 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {Text, View} from 'react-native'; +import {Text, Pressable} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; -import styles from '../styles/styles'; +import styles, {getBadgeColorStyle} from '../styles/styles'; import Navigation from '../libs/Navigation/Navigation'; import ROUTES from '../ROUTES'; import compose from '../libs/compose'; @@ -47,12 +47,12 @@ const IOUBadge = (props) => { Navigation.navigate(ROUTES.getIouDetailsRoute(props.iouReport.chatReportID, props.iouReport.reportID)); }; return ( - ([ styles.badge, styles.ml2, - props.session.email === props.iouReport.ownerEmail ? styles.badgeSuccess : styles.badgeDanger, - ]} + getBadgeColorStyle(props.session.email === props.iouReport.ownerEmail, pressed), + ])} > { {style: 'currency', currency: props.iouReport.currency}, )} - + ); }; diff --git a/src/styles/colors.js b/src/styles/colors.js index 89c10430fca0..7994b9c27e7c 100644 --- a/src/styles/colors.js +++ b/src/styles/colors.js @@ -10,6 +10,7 @@ export default { green: '#03d47c', greenHover: '#03c775', red: '#fc3826', + redHover: '#e13826', yellow: '#fed607', transparent: 'transparent', }; diff --git a/src/styles/styles.js b/src/styles/styles.js index ee1f2c018e34..e266e5119212 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -264,10 +264,18 @@ const styles = { backgroundColor: themeColors.badgeSuccessBG, }, + badgeSuccessPressed: { + backgroundColor: themeColors.badgeSuccessPressedBG, + }, + badgeDanger: { backgroundColor: themeColors.badgeDangerBG, }, + badgeDangerPressed: { + backgroundColor: themeColors.badgeDangerPressedBG, + }, + badgeText: { color: themeColors.textReversed, fontSize: variables.fontSizeSmall, @@ -1715,6 +1723,20 @@ function getBackgroundColorStyle(backgroundColor) { }; } +/** + * Generate a style for the background color of the IOU badge + * + * @param {Boolean} isOwner + * @param {Boolean} [isPressed] + * @returns {Object} + */ +function getBadgeColorStyle(isOwner, isPressed = false) { + if (isOwner) { + return isPressed ? styles.badgeSuccessPressed : styles.badgeSuccess; + } + return isPressed ? styles.badgeDangerPressed : styles.badgeDanger; +} + /** * Generate a style for the background color of the button, based on its current state. * @@ -1838,6 +1860,7 @@ export { getAutoGrowTextInputStyle, getBackgroundAndBorderStyle, getBackgroundColorStyle, + getBadgeColorStyle, getButtonBackgroundColorStyle, getIconFillColor, getAnimatedFABStyle, diff --git a/src/styles/themes/default.js b/src/styles/themes/default.js index 58a04a03ba13..d0d998629627 100644 --- a/src/styles/themes/default.js +++ b/src/styles/themes/default.js @@ -30,8 +30,10 @@ export default { modalBackdrop: colors.gray3, modalBackground: colors.gray2, badgeDangerBG: colors.red, + badgeDangerPressedBG: colors.redHover, badgeDefaultBG: colors.gray2, badgeSuccessBG: colors.green, + badgeSuccessPressedBG: colors.greenHover, buttonDisabledBG: colors.gray2, buttonHoveredBG: colors.gray1, buttonPressedBG: colors.gray2, From d312ff6655e2873333b2938954fc614d34d7d81e Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Sat, 5 Jun 2021 01:05:08 +0530 Subject: [PATCH 05/20] fix: picker scroll glitch --- src/pages/home/report/EmojiPickerMenu/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/home/report/EmojiPickerMenu/index.js b/src/pages/home/report/EmojiPickerMenu/index.js index 7f043668c129..d7d19762a1b6 100755 --- a/src/pages/home/report/EmojiPickerMenu/index.js +++ b/src/pages/home/report/EmojiPickerMenu/index.js @@ -65,12 +65,12 @@ class EmojiPickerMenu extends Component { this.setupEventHandlers = this.setupEventHandlers.bind(this); this.cleanupEventHandlers = this.cleanupEventHandlers.bind(this); this.renderItem = this.renderItem.bind(this); + this.currentScrollOffset = 0; this.state = { filteredEmojis: this.emojis, headerIndices: this.unfilteredHeaderIndices, highlightedIndex: -1, - currentScrollOffset: 0, arePointerEventsDisabled: false, }; } @@ -210,13 +210,13 @@ class EmojiPickerMenu extends Component { const offsetAtEmojiTop = offsetAtEmojiBottom - CONST.EMOJI_PICKER_ITEM_HEIGHT; // Scroll to fit the entire highlighted emoji into the window if we need to - let targetOffset = this.state.currentScrollOffset; - if (offsetAtEmojiBottom - this.state.currentScrollOffset >= CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT) { + let targetOffset = this.currentScrollOffset; + if (offsetAtEmojiBottom - this.currentScrollOffset >= CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT) { targetOffset = offsetAtEmojiBottom - CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT; - } else if (offsetAtEmojiTop - CONST.EMOJI_PICKER_ITEM_HEIGHT <= this.state.currentScrollOffset) { + } else if (offsetAtEmojiTop - CONST.EMOJI_PICKER_ITEM_HEIGHT <= this.currentScrollOffset) { targetOffset = offsetAtEmojiTop - CONST.EMOJI_PICKER_ITEM_HEIGHT; } - if (targetOffset !== this.state.currentScrollOffset) { + if (targetOffset !== this.currentScrollOffset) { // Disable pointer events so that onHover doesn't get triggered when the items move while we're scrolling if (!this.state.arePointerEventsDisabled) { this.setState({arePointerEventsDisabled: true}); @@ -335,7 +335,7 @@ class EmojiPickerMenu extends Component { style={styles.emojiPickerList} extraData={[this.state.filteredEmojis, this.state.highlightedIndex]} stickyHeaderIndices={this.state.headerIndices} - onScroll={e => this.setState({currentScrollOffset: e.nativeEvent.contentOffset.y})} + onScroll={e => this.currentScrollOffset = e.nativeEvent.contentOffset.y} /> ); From b93be75dc4689c727d8fddbfc6b1b0f07d936e0a Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 7 Jun 2021 12:11:19 +0800 Subject: [PATCH 06/20] Add paypal name save confirmation --- package-lock.json | 3 ++- src/languages/en.js | 1 + src/pages/settings/PaymentsPage.js | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 654b62486c5f..c17cdc4d101d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23126,7 +23126,8 @@ "ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true }, "inline-style-parser": { "version": "0.1.1", diff --git a/src/languages/en.js b/src/languages/en.js index da87f117e21b..acb1a603eb12 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -199,6 +199,7 @@ export default { payPalMe: 'PayPal.me/', yourPayPalUsername: 'Your PayPal username', addPayPalAccount: 'Add PayPal Account', + growlMessageOnSave: 'Your PayPal username was successfully added', }, preferencesPage: { mostRecent: 'Most Recent', diff --git a/src/pages/settings/PaymentsPage.js b/src/pages/settings/PaymentsPage.js index 9a9df206ce2b..f666e60a795e 100755 --- a/src/pages/settings/PaymentsPage.js +++ b/src/pages/settings/PaymentsPage.js @@ -15,6 +15,7 @@ import styles from '../../styles/styles'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import compose from '../../libs/compose'; import Button from '../../components/Button'; +import Growl from '../../libs/Growl'; const propTypes = { /** Username for PayPal.Me */ @@ -54,6 +55,7 @@ class PaymentsPage extends React.Component { */ setPayPalMeUsername() { NameValuePair.set(CONST.NVP.PAYPAL_ME_ADDRESS, this.state.payPalMeUsername, ONYXKEYS.NVP_PAYPAL_ME_ADDRESS); + Growl.show(this.props.translate('paymentsPage.growlMessageOnSave'), CONST.GROWL.SUCCESS, 3000); } render() { @@ -78,10 +80,12 @@ class PaymentsPage extends React.Component { value={this.state.payPalMeUsername} placeholder={this.props.translate('paymentsPage.yourPayPalUsername')} onChangeText={text => this.setState({payPalMeUsername: text})} + editable={!this.props.payPalMeUsername} />