diff --git a/packages/mobile/.env b/packages/mobile/.env index 20f99890196..f3ce19e1ed2 100644 --- a/packages/mobile/.env +++ b/packages/mobile/.env @@ -1,6 +1,6 @@ ENVIRONMENT=local DEFAULT_TESTNET=alfajoresstaging -# If ZERO_SYNC_ENABLED_INITIALLY, local geth will not run initially. +# If ZERO_SYNC_ENABLED_INITIALLY, local geth will not run initially. # If toggled on, it will use DEFAULT_SYNC_MODE. See src/geth/consts.ts for more info ZERO_SYNC_ENABLED_INITIALLY=false DEFAULT_SYNC_MODE=5 @@ -10,4 +10,4 @@ SHOW_TESTNET_BANNER=true SHOW_GET_INVITE_LINK=false DEV_SETTINGS_ACTIVE_INITIALLY=true # Enable for true hot reloading while dev-ing UI -DEV_RESTORE_NAV_STATE_ON_RELOAD=false \ No newline at end of file +DEV_RESTORE_NAV_STATE_ON_RELOAD=false diff --git a/packages/mobile/locales/en-US/global.json b/packages/mobile/locales/en-US/global.json index f49b975177d..2cc16aa1b4e 100644 --- a/packages/mobile/locales/en-US/global.json +++ b/packages/mobile/locales/en-US/global.json @@ -63,6 +63,7 @@ "decline": "Decline", "to": "To", "for": "For", + "reclaim": "Reclaim", "celoGold": "Celo Gold", "celoDollars": "{{CeloDollars}}", "oops": "Oops!", @@ -102,5 +103,8 @@ "localCurrencyTitle": "Select Currency", "or": "or", "accepted": "Accepted", - "processing": "Processing" + "processing": "Processing", + "moreWithCount": "+{{count }} more", + "unknown": "Unknown", + "emptyList": "Empty list" } diff --git a/packages/mobile/locales/en-US/inviteFlow11.json b/packages/mobile/locales/en-US/inviteFlow11.json index dfe8725351e..47f0f97393f 100644 --- a/packages/mobile/locales/en-US/inviteFlow11.json +++ b/packages/mobile/locales/en-US/inviteFlow11.json @@ -25,5 +25,8 @@ "inviteAnyone": "Invite Anyone in your address book to send and receive value", "inviteComplete": "Invite Complete", "inviteReceived": "Invite Received", - "pedningInvitations": "Pending Invitations" + "escrowPaymentNotificationTitle": "Invited ({{amount}}) {{mobile}}", + "escrowPaymentNotificationLine": "<0>{{recipientPhone}} for <1>{{amount}}", + "escrowPaymentNotificationLine_missingRecipientPhone": "<0>Unknown for <1>{{amount}}", + "defaultComment": "Invitation sent" } diff --git a/packages/mobile/locales/en-US/paymentRequestFlow.json b/packages/mobile/locales/en-US/paymentRequestFlow.json index 1d86f8de0c5..55d175c34ea 100644 --- a/packages/mobile/locales/en-US/paymentRequestFlow.json +++ b/packages/mobile/locales/en-US/paymentRequestFlow.json @@ -1,10 +1,12 @@ { "requests": "Requests", "empty": "You have no Payment Requests", - "incomingPaymentRequests": "Requests Waiting for You", - "outgoingPaymentRequests": "Payments You’ve Requested", "celoDollarBalance": "{{CeloDollar}} Balance", "requestDeclined": "Request Declined", "requestPaid": "Request Paid", - "paymentRequestUpdateFailed": "Cannot update payment request" + "paymentRequestUpdateFailed": "Cannot update payment request", + "incomingPaymentRequestNotificationTitle": "{{name}} requested {{amount}}", + "outgoingPaymentRequestNotificationTitle": "Requested {{amount}} from {{name}}", + "defaultComment": "Payment Requested", + "paymentRequestNotificationLine": "<0>{{displayName}} for <1>{{amount}}" } diff --git a/packages/mobile/locales/en-US/sendFlow7.json b/packages/mobile/locales/en-US/sendFlow7.json index 1a5502ff911..e1db576fb9d 100644 --- a/packages/mobile/locales/en-US/sendFlow7.json +++ b/packages/mobile/locales/en-US/sendFlow7.json @@ -14,7 +14,6 @@ "sendTo": "Send to", "amount": "Amount", "celoDollarsAvailable": "{{CeloDollars}} Available", - "for": "For", "groceriesRent": "Groceries, rent, etc. (Optional)", "fee": "Fee", "securityFee": "Security Fee", diff --git a/packages/mobile/locales/en-US/walletFlow5.json b/packages/mobile/locales/en-US/walletFlow5.json index 107d76fbe4b..f9665a58aa2 100644 --- a/packages/mobile/locales/en-US/walletFlow5.json +++ b/packages/mobile/locales/en-US/walletFlow5.json @@ -1,9 +1,7 @@ { "getStarted": "Get Started", - "incomingPaymentRequest": "Request Waiting for You", - "incomingPaymentRequestWithCount_plural": "{{count}} Requests Waiting on You", - "outgoingPaymentRequest": "Payment You’ve Requested", - "outgoingPaymentRequestWithCount_plural": "{{count}} Payments You’ve Requested", + "incomingPaymentRequests": "Requests from Others", + "outgoingPaymentRequests": "Payments You’ve Requested", "SMSError": "Error sending SMS", "notifications": "Notifications", "getBackupKey": "Get Backup Key", @@ -54,11 +52,7 @@ "maybeLater": "Maybe Later", "balanceNeedUpdating": "Balance needs updating", "refreshBalances": "Refresh Balances", - "reclaimPayment": "Reclaim Payment", - "sendMessage": "Send Message", - "escrowedPaymentReminderListItemTitle": "Remind {{mobile}} to Accept Payment", - "escrowedPaymentReminder": "Remind the recipient to Accept Payment", - "escrowedPaymentReminderWithCount_plural": "Remind {{count}} recipients to Accept Payment", + "escrowedPaymentReminder": "Pending Invitations", "escrowedPaymentReminderSms": "A friendly reminder that you haven't yet redeemed your Celo Dollars!", "testnetAlert": { diff --git a/packages/mobile/locales/es-419/global.json b/packages/mobile/locales/es-419/global.json index fdbed9dd927..e04d22b9661 100755 --- a/packages/mobile/locales/es-419/global.json +++ b/packages/mobile/locales/es-419/global.json @@ -63,6 +63,7 @@ "decline": "Disminución", "to": "Para", "for": "Por", + "reclaim": "Reclaim", "celoGold": "Celo Oro", "celoDollars": "{{CeloDollars}}", "oops": "¡Uy!", @@ -103,5 +104,8 @@ "localCurrencyTitle": "Seleccione el tipo de moneda", "or": "o", "accepted": "Aceptado", - "processing": "Procesando" + "processing": "Procesando", + "moreWithCount": "~~+{{count }} more", + "unknown": "~~Unknown", + "emptyList": "~~Empty list" } diff --git a/packages/mobile/locales/es-419/inviteFlow11.json b/packages/mobile/locales/es-419/inviteFlow11.json index 20a7df9ecc0..935be142290 100755 --- a/packages/mobile/locales/es-419/inviteFlow11.json +++ b/packages/mobile/locales/es-419/inviteFlow11.json @@ -25,5 +25,8 @@ "inviteAnyone": "Invite a cualquiera en tu lista de contactos para enviar y recibir valor", "inviteComplete": "Invitación completa", "inviteReceived": "Invitación recibida", - "pedningInvitations": "Invitaciones pendientes" + "escrowPaymentNotificationTitle": "~~Invited ({{amount}}) {{mobile}}", + "escrowPaymentNotificationLine": "~~<0>{{recipientPhone}} for <1>{{amount}}", + "escrowPaymentNotificationLine_missingRecipientPhone": "~~<0>Unknown for <1>{{amount}}", + "defaultComment": "~~Invitation sent" } diff --git a/packages/mobile/locales/es-419/paymentRequestFlow.json b/packages/mobile/locales/es-419/paymentRequestFlow.json index 5507196aa76..60692110920 100644 --- a/packages/mobile/locales/es-419/paymentRequestFlow.json +++ b/packages/mobile/locales/es-419/paymentRequestFlow.json @@ -1,10 +1,12 @@ { "requests": "Solicitudes", "empty": "No tienes solicitudes de pago", - "incomingPaymentRequests": "Pedidos esperandote", - "outgoingPaymentRequests": "Pagos que tu has pedido", "celoDollarBalance": "Saldo de {{CeloDollar}}", "requestDeclined": "Solicitud rechazada", "requestPaid": "Solicitud Pagada", - "paymentRequestUpdateFailed": "No se pudo actualizar el pedido de pago" + "paymentRequestUpdateFailed": "No se pudo actualizar el pedido de pago", + "incomingPaymentRequestNotificationTitle": "~~{{name}} requested {{amount}}", + "outgoingPaymentRequestNotificationTitle": "~~Requested {{amount}} from {{name}}", + "defaultComment": "~~Payment Requested", + "paymentRequestNotificationLine": "~~<0>{{displayName}} for <1>{{amount}}" } diff --git a/packages/mobile/locales/es-419/sendFlow7.json b/packages/mobile/locales/es-419/sendFlow7.json index e91aceb532d..a21064e1583 100755 --- a/packages/mobile/locales/es-419/sendFlow7.json +++ b/packages/mobile/locales/es-419/sendFlow7.json @@ -14,7 +14,6 @@ "sendTo": "Enviar a", "amount": "Monto", "celoDollarsAvailable": "{{CeloDollars}} disponibles", - "for": "Por", "groceriesRent": "Supermercado, alquiler, etc. (Opcional)", "fee": "Comisión", "securityFee": "Comisión de seguridad", diff --git a/packages/mobile/locales/es-419/walletFlow5.json b/packages/mobile/locales/es-419/walletFlow5.json index 1f105fe06ab..eaf9daa9f7f 100755 --- a/packages/mobile/locales/es-419/walletFlow5.json +++ b/packages/mobile/locales/es-419/walletFlow5.json @@ -1,9 +1,7 @@ { "getStarted": "Primeros pasos", - "incomingPaymentRequest": "Pedido esperandote", - "incomingPaymentRequestWithCount_plural": "{{count}} Pedidos esperandote", - "outgoingPaymentRequest": "Pago que tu has pedido", - "outgoingPaymentRequestWithCount_plural": "{{count}} Pagos que tu has pedido", + "incomingPaymentRequests": "~~Requests from Others", + "outgoingPaymentRequests": "~~Payments You’ve Requested", "SMSError": "Error al enviar SMS", "notifications": "Notificaciones", "getBackupKey": "Obtener clave de respaldo", @@ -55,11 +53,7 @@ "maybeLater": "quizas mas tarde", "balanceNeedUpdating": "Saldo necesita actualizarse", "refreshBalances": "Actualizar saldos", - "reclaimPayment": "Reclamar el Pago", - "sendMessage": "Enviar Mensaje", - "escrowedPaymentReminderListItemTitle": "Recuérdele a {{mobile #}} que acepte el pago", "escrowedPaymentReminder": "Reacuerda al receptor aceptar el pago", - "escrowedPaymentReminderWithCount_plural": "Recordar {{count}} receptores to aceptar el pago", "escrowedPaymentReminderSms": "¡Un recordatorio amistoso de que aún no ha canjeado sus dólares de celo!", "testnetAlert": { diff --git a/packages/mobile/src/app/ErrorBoundary.tsx b/packages/mobile/src/app/ErrorBoundary.tsx index c49650966a1..8344b9f57ac 100644 --- a/packages/mobile/src/app/ErrorBoundary.tsx +++ b/packages/mobile/src/app/ErrorBoundary.tsx @@ -5,6 +5,7 @@ import { withNamespaces, WithNamespaces } from 'react-i18next' import CeloAnalytics from 'src/analytics/CeloAnalytics' import { DefaultEventNames } from 'src/analytics/constants' import ErrorScreen from 'src/app/ErrorScreen' +import { Namespaces } from 'src/i18n' interface State { childError: Error | null @@ -37,4 +38,4 @@ class ErrorBoundary extends React.Component { } } -export default withNamespaces('global')(ErrorBoundary) +export default withNamespaces(Namespaces.global)(ErrorBoundary) diff --git a/packages/mobile/src/app/ErrorScreen.tsx b/packages/mobile/src/app/ErrorScreen.tsx index 967c3e57c2d..2362a44b945 100644 --- a/packages/mobile/src/app/ErrorScreen.tsx +++ b/packages/mobile/src/app/ErrorScreen.tsx @@ -4,6 +4,7 @@ import * as React from 'react' import { withNamespaces, WithNamespaces } from 'react-i18next' import { Text, View } from 'react-native' import { NavigationParams, NavigationScreenProp } from 'react-navigation' +import { Namespaces } from 'src/i18n' import { deleteChainDataAndRestartApp, RESTART_APP_I18N_KEY } from 'src/utils/AppRestart' interface OwnProps { @@ -44,4 +45,4 @@ class ErrorScreen extends React.Component { } } -export default withNamespaces('global')(ErrorScreen) +export default withNamespaces(Namespaces.global)(ErrorScreen) diff --git a/packages/mobile/src/app/UpgradeScreen.tsx b/packages/mobile/src/app/UpgradeScreen.tsx index 63110ffe47f..82ebddb9521 100644 --- a/packages/mobile/src/app/UpgradeScreen.tsx +++ b/packages/mobile/src/app/UpgradeScreen.tsx @@ -2,6 +2,7 @@ import FullscreenCTA from '@celo/react-components/components/FullscreenCTA' import * as React from 'react' import { withNamespaces, WithNamespaces } from 'react-i18next' import { NavigationParams, NavigationScreenProp } from 'react-navigation' +import { Namespaces } from 'src/i18n' import { navigateToWalletPlayStorePage } from 'src/utils/linking' interface OwnProps { @@ -27,4 +28,4 @@ class UpgradeScreen extends React.Component { } } -export default withNamespaces('global')(UpgradeScreen) +export default withNamespaces(Namespaces.global)(UpgradeScreen) diff --git a/packages/mobile/src/escrow/EscrowedPaymentLineItem.tsx b/packages/mobile/src/escrow/EscrowedPaymentLineItem.tsx index 9cfc7b250be..2a6763e4e63 100644 --- a/packages/mobile/src/escrow/EscrowedPaymentLineItem.tsx +++ b/packages/mobile/src/escrow/EscrowedPaymentLineItem.tsx @@ -1,24 +1,34 @@ import fontStyles from '@celo/react-components/styles/fonts' import * as React from 'react' +import { Trans, withNamespaces, WithNamespaces } from 'react-i18next' import { StyleSheet, Text } from 'react-native' import { EscrowedPayment } from 'src/escrow/actions' +import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' +import { Namespaces } from 'src/i18n' import { divideByWei, getCentAwareMoneyDisplay } from 'src/utils/formatting' interface Props { payment: EscrowedPayment } -export default function EscrowedPaymentLineItem(props: Props) { - const { amount, message, recipientPhone } = props.payment +function EscrowedPaymentLineItem(props: Props & WithNamespaces) { + const { amount, recipientPhone } = props.payment return ( - - {recipientPhone} - {message} - - - {' '} - ${getCentAwareMoneyDisplay(divideByWei(amount.toString()))} - + + {{ recipientPhone }} for + {{ amount }} + ) } @@ -27,4 +37,11 @@ const styles = StyleSheet.create({ oneLine: { flexDirection: 'row', }, + phone: fontStyles.subSmall, + amount: { + ...fontStyles.subSmall, + ...fontStyles.semiBold, + }, }) + +export default withNamespaces(Namespaces.inviteFlow11)(EscrowedPaymentLineItem) diff --git a/packages/mobile/src/escrow/EscrowedPaymentListItem.test.tsx b/packages/mobile/src/escrow/EscrowedPaymentListItem.test.tsx index d90dc2022f9..b51b84b7d54 100644 --- a/packages/mobile/src/escrow/EscrowedPaymentListItem.test.tsx +++ b/packages/mobile/src/escrow/EscrowedPaymentListItem.test.tsx @@ -3,6 +3,7 @@ import 'react-native' import { Provider } from 'react-redux' import * as renderer from 'react-test-renderer' import EscrowedPaymentListItem from 'src/escrow/EscrowedPaymentListItem' + import { createMockStore } from 'test/utils' import { mockEscrowedPayment } from 'test/values' diff --git a/packages/mobile/src/escrow/EscrowedPaymentListItem.tsx b/packages/mobile/src/escrow/EscrowedPaymentListItem.tsx index 99958028bce..3595231f66c 100644 --- a/packages/mobile/src/escrow/EscrowedPaymentListItem.tsx +++ b/packages/mobile/src/escrow/EscrowedPaymentListItem.tsx @@ -1,18 +1,20 @@ import BaseNotification from '@celo/react-components/components/BaseNotification' +import fontStyles from '@celo/react-components/styles/fonts' import * as React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { Image, Platform, StyleSheet, View } from 'react-native' +import { Image, Platform, StyleSheet, Text, View } from 'react-native' import SendIntentAndroid from 'react-native-send-intent' import CeloAnalytics from 'src/analytics/CeloAnalytics' import { CustomEventNames } from 'src/analytics/constants' import { componentWithAnalytics } from 'src/analytics/wrapper' import { ErrorMessages } from 'src/app/ErrorMessages' import { EscrowedPayment } from 'src/escrow/actions' +import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' import { Namespaces } from 'src/i18n' import { inviteFriendsIcon } from 'src/images/Images' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' -import NotificationAmount from 'src/paymentRequest/NotificationAmount' +import { divideByWei, getCentAwareMoneyDisplay } from 'src/utils/formatting' import { navigateToURI } from 'src/utils/linking' import Logger from 'src/utils/Logger' @@ -25,14 +27,14 @@ type Props = OwnProps & WithNamespaces const TAG = 'EscrowedPaymentListItem' export class EscrowedPaymentListItem extends React.PureComponent { - onSendMessage = () => { + onRemind = () => { const { payment, t } = this.props const recipientPhoneNumber = payment.recipientPhone CeloAnalytics.track(CustomEventNames.clicked_escrowed_payment_send_message) // TODO: open up whatsapp/text message slider with pre populated message try { if (Platform.OS === 'android') { - SendIntentAndroid.sendSms(recipientPhoneNumber, t('escrowedPaymentReminderSms')) + SendIntentAndroid.sendSms(recipientPhoneNumber, t('walletFlow5:escrowedPaymentReminderSms')) } else { // TODO look into using MFMessageComposeViewController to prefill the body for iOS navigateToURI(`sms:${recipientPhoneNumber}`) @@ -51,44 +53,50 @@ export class EscrowedPaymentListItem extends React.PureComponent { } getCTA = () => { const { t } = this.props - return [ - { - text: t('sendMessage'), - onPress: this.onSendMessage, - }, - { - text: t('reclaimPayment'), - onPress: this.onReclaimPayment, - }, - ] + const ctas = [] + if (this.getDisplayName()) { + ctas.push({ + text: t('global:remind'), + onPress: this.onRemind, + }) + } + ctas.push({ + text: t('global:reclaim'), + onPress: this.onReclaimPayment, + }) + return ctas } - getTitle() { - const { t, payment } = this.props - const displayName = payment.recipientContact - ? payment.recipientContact.displayName - : payment.recipientPhone - return t('escrowedPaymentReminderListItemTitle', { mobile: displayName }) + getDisplayName() { + const { payment } = this.props + return payment.recipientContact ? payment.recipientContact.displayName : payment.recipientPhone } render() { - const { payment } = this.props - + const { t, payment } = this.props return ( - } - ctas={this.getCTA()} - roundedBorders={false} - callout={} - > - - + + } + ctas={this.getCTA()} + > + {payment.message || t('defaultComment')} + + ) } } const styles = StyleSheet.create({ + container: { + marginBottom: 16, + }, body: { marginTop: 5, flexDirection: 'row', @@ -103,5 +111,5 @@ const styles = StyleSheet.create({ }) export default componentWithAnalytics( - withNamespaces(Namespaces.walletFlow5)(EscrowedPaymentListItem) + withNamespaces(Namespaces.inviteFlow11)(EscrowedPaymentListItem) ) diff --git a/packages/mobile/src/escrow/EscrowedPaymentListScreen.test.tsx b/packages/mobile/src/escrow/EscrowedPaymentListScreen.test.tsx index 3aa4ceb77de..41bd814d619 100644 --- a/packages/mobile/src/escrow/EscrowedPaymentListScreen.test.tsx +++ b/packages/mobile/src/escrow/EscrowedPaymentListScreen.test.tsx @@ -1,3 +1,4 @@ +import BigNumber from 'bignumber.js' import * as React from 'react' import 'react-native' import { Provider } from 'react-redux' @@ -5,10 +6,18 @@ import * as renderer from 'react-test-renderer' import { escrowPaymentDouble } from 'src/escrow/__mocks__' import { EscrowedPayment } from 'src/escrow/actions' import EscrowedPaymentListScreen from 'src/escrow/EscrowedPaymentListScreen' -import { createMockStore } from 'test/utils' +import { createMockNavigationProp, createMockStore } from 'test/utils' +import { mockAccount, mockRecipient } from 'test/values' const payments = [escrowPaymentDouble({}), escrowPaymentDouble({}), escrowPaymentDouble({})] +const navigation = createMockNavigationProp({ + recipient: mockRecipient, + recipientAddress: mockAccount, + amount: new BigNumber(10), + reason: 'My Reason', +}) + function testStore(sentEscrowedPayments: EscrowedPayment[]) { return createMockStore({ stableToken: { balance: '120' }, @@ -22,7 +31,7 @@ describe('EscrowedPaymentListScreen', () => { const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() @@ -33,7 +42,7 @@ describe('EscrowedPaymentListScreen', () => { const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() diff --git a/packages/mobile/src/escrow/EscrowedPaymentListScreen.tsx b/packages/mobile/src/escrow/EscrowedPaymentListScreen.tsx index 292a6d84cfa..429216982e4 100644 --- a/packages/mobile/src/escrow/EscrowedPaymentListScreen.tsx +++ b/packages/mobile/src/escrow/EscrowedPaymentListScreen.tsx @@ -1,11 +1,7 @@ -import SectionHeader from '@celo/react-components/components/SectionHead' -import colors from '@celo/react-components/styles/colors' -import { componentStyles } from '@celo/react-components/styles/styles' -import variables from '@celo/react-components/styles/variables' import * as React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { ScrollView, StyleSheet, View } from 'react-native' -import SafeAreaView from 'react-native-safe-area-view' +import { View } from 'react-native' +import { NavigationInjectedProps } from 'react-navigation' import { connect } from 'react-redux' import { EscrowedPayment } from 'src/escrow/actions' import EscrowedPaymentListItem from 'src/escrow/EscrowedPaymentListItem' @@ -14,15 +10,14 @@ import { updatePaymentRequestStatus } from 'src/firebase/actions' import i18n, { Namespaces } from 'src/i18n' import { fetchPhoneAddresses } from 'src/identity/actions' import { e164NumberToAddressSelector, E164NumberToAddressType } from 'src/identity/reducer' -import { headerWithBackButton } from 'src/navigator/Headers' -import PaymentRequestBalance from 'src/paymentRequest/PaymentRequestBalance' -import PaymentRequestListEmpty from 'src/paymentRequest/PaymentRequestListEmpty' +import { + NotificationList, + titleWithBalanceNavigationOptions, + useBalanceInNavigationParam, +} from 'src/notifications/NotificationList' import { NumberToRecipient } from 'src/recipients/recipient' import { recipientCacheSelector } from 'src/recipients/reducer' import { RootState } from 'src/redux/reducers' -import DisconnectBanner from 'src/shared/DisconnectBanner' - -const { contentPadding } = variables interface StateProps { dollarBalance: string | null @@ -43,57 +38,31 @@ const mapStateToProps = (state: RootState): StateProps => ({ recipientCache: recipientCacheSelector(state), }) -type Props = WithNamespaces & StateProps & DispatchProps - -export class EscrowedPaymentListScreen extends React.Component { - static navigationOptions = () => ({ - ...headerWithBackButton, - headerTitle: i18n.t('inviteFlow11:pedningInvitations'), - }) +type Props = NavigationInjectedProps & WithNamespaces & StateProps & DispatchProps - renderRequest = (payment: EscrowedPayment, key: number, allPayments: EscrowedPayment[]) => { - return ( - - - {key < allPayments.length - 1 && } - - ) - } +export const listItemRenderer = (payment: EscrowedPayment, key: number | undefined = undefined) => { + return ( + + + + ) +} - render() { - return ( - - - - - {this.props.sentEscrowedPayments.length > 0 ? ( - - - {this.props.sentEscrowedPayments.map(this.renderRequest)} - - - ) : ( - - )} - - ) - } +const EscrowedPaymentListScreen = (props: Props) => { + const { dollarBalance, navigation } = props + useBalanceInNavigationParam(dollarBalance, navigation) + return ( + + ) } -const styles = StyleSheet.create({ - container: { - backgroundColor: colors.background, - flex: 1, - }, - separator: { - borderBottomColor: colors.darkLightest, - borderBottomWidth: 1, - marginLeft: 50, - }, - scrollArea: { - margin: contentPadding, - }, -}) +EscrowedPaymentListScreen.navigationOptions = titleWithBalanceNavigationOptions( + i18n.t('walletFlow5:escrowedPaymentReminder') +) export default connect( mapStateToProps, diff --git a/packages/mobile/src/notifications/EscrowedPaymentReminderSummaryNotification.test.tsx b/packages/mobile/src/escrow/EscrowedPaymentReminderSummaryNotification.test.tsx similarity index 91% rename from packages/mobile/src/notifications/EscrowedPaymentReminderSummaryNotification.test.tsx rename to packages/mobile/src/escrow/EscrowedPaymentReminderSummaryNotification.test.tsx index 916f47a6034..114d21192d7 100644 --- a/packages/mobile/src/notifications/EscrowedPaymentReminderSummaryNotification.test.tsx +++ b/packages/mobile/src/escrow/EscrowedPaymentReminderSummaryNotification.test.tsx @@ -3,7 +3,7 @@ import 'react-native' import { Provider } from 'react-redux' import * as renderer from 'react-test-renderer' import { escrowPaymentDouble } from 'src/escrow/__mocks__' -import EscrowedPaymentReminderSummaryNotification from 'src/notifications/EscrowedPaymentReminderSummaryNotification' +import EscrowedPaymentReminderSummaryNotification from 'src/escrow/EscrowedPaymentReminderSummaryNotification' import { createMockStore } from 'test/utils' const fakePayments = [escrowPaymentDouble({}), escrowPaymentDouble({})] diff --git a/packages/mobile/src/notifications/EscrowedPaymentReminderSummaryNotification.tsx b/packages/mobile/src/escrow/EscrowedPaymentReminderSummaryNotification.tsx similarity index 53% rename from packages/mobile/src/notifications/EscrowedPaymentReminderSummaryNotification.tsx rename to packages/mobile/src/escrow/EscrowedPaymentReminderSummaryNotification.tsx index dec063d8bb9..9c929d851f8 100644 --- a/packages/mobile/src/notifications/EscrowedPaymentReminderSummaryNotification.tsx +++ b/packages/mobile/src/escrow/EscrowedPaymentReminderSummaryNotification.tsx @@ -1,16 +1,17 @@ -import BaseNotification from '@celo/react-components/components/BaseNotification' import variables from '@celo/react-components/styles/variables' import * as React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { Image, StyleSheet, View } from 'react-native' +import { Image, StyleSheet } from 'react-native' import CeloAnalytics from 'src/analytics/CeloAnalytics' import { CustomEventNames } from 'src/analytics/constants' import { EscrowedPayment } from 'src/escrow/actions' import EscrowedPaymentLineItem from 'src/escrow/EscrowedPaymentLineItem' +import { listItemRenderer } from 'src/escrow/EscrowedPaymentListScreen' import { Namespaces } from 'src/i18n' import { inviteFriendsIcon } from 'src/images/Images' import { navigate } from 'src/navigator/NavigationService' import { Stacks } from 'src/navigator/Screens' +import SummaryNotification from 'src/notifications/SummaryNotification' interface OwnProps { payments: EscrowedPayment[] @@ -18,47 +19,28 @@ interface OwnProps { type Props = OwnProps & WithNamespaces -const PREVIEW_SIZE = 2 - export class EscrowedPaymentReminderSummaryNotification extends React.Component { - getTotal() { - return this.props.payments.length + onReview = () => { + CeloAnalytics.track(CustomEventNames.escrowed_payment_review) + navigate(Stacks.EscrowStack) } - getTitle() { - const { t } = this.props - return this.getTotal() > 1 - ? t('escrowedPaymentReminderWithCount_plural', { count: this.getTotal() }) - : t('escrowedPaymentReminder') - } - getCTA = () => { - return [ - { - text: this.props.t('review'), - onPress: () => { - CeloAnalytics.track(CustomEventNames.escrowed_payment_review) - navigate(Stacks.EscrowStack) - }, - }, - ] + itemRenderer = (item: EscrowedPayment) => { + return } + render() { - const { payments } = this.props - return ( - + items={payments} + title={t('escrowedPaymentReminder')} icon={} - ctas={this.getCTA()} - roundedBorders={true} - > - - - {payments.slice(0, PREVIEW_SIZE).map((payment, key) => { - return - })} - - - + onReview={this.onReview} + itemRenderer={this.itemRenderer} + /> ) } } diff --git a/packages/mobile/src/escrow/ReclaimPaymentConfirmationCard.tsx b/packages/mobile/src/escrow/ReclaimPaymentConfirmationCard.tsx index 9032fe5851e..9572ef396c2 100644 --- a/packages/mobile/src/escrow/ReclaimPaymentConfirmationCard.tsx +++ b/packages/mobile/src/escrow/ReclaimPaymentConfirmationCard.tsx @@ -74,10 +74,12 @@ class ReclaimPaymentConfirmationCard extends React.PureComponent { {recipientContact.displayName} )} - + {recipientPhone && ( + + )} +491522345678 - - - test message + for - - $ - 7 + 11870000 `; diff --git a/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListItem.test.tsx.snap b/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListItem.test.tsx.snap index ae3662c57c3..238259880f4 100644 --- a/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListItem.test.tsx.snap +++ b/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListItem.test.tsx.snap @@ -3,188 +3,183 @@ exports[`EscrowedPaymentReminderNotification renders correctly 1`] = ` - - + - - - - escrowedPaymentReminderListItemTitle - - - + + + + escrowPaymentNotificationTitle + - - - sendMessage - - + defaultComment + - + + global:remind + + + - reclaimPayment - + + global:reclaim + + - - - - $0 - - - `; diff --git a/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListScreen.test.tsx.snap b/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListScreen.test.tsx.snap index 889835478c9..c9b36d47934 100644 --- a/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListScreen.test.tsx.snap +++ b/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentListScreen.test.tsx.snap @@ -9,91 +9,6 @@ exports[`EscrowedPaymentListScreen renders correctly with no payments 1`] = ` } } > - - - - - celoDollarBalance - - - $120 - - - - - - payments - - - empty + global:emptyList `; @@ -124,91 +39,6 @@ exports[`EscrowedPaymentListScreen renders correctly with payments 1`] = ` } } > - - - - - celoDollarBalance - - - $120 - - - - - - payments - - - empty + global:emptyList `; diff --git a/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentReminderSummaryNotification.test.tsx.snap b/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentReminderSummaryNotification.test.tsx.snap new file mode 100644 index 00000000000..bdd961b5ad7 --- /dev/null +++ b/packages/mobile/src/escrow/__snapshots__/EscrowedPaymentReminderSummaryNotification.test.tsx.snap @@ -0,0 +1,617 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EscrowedPaymentReminderSummaryNotification renders correctly 1`] = ` + + + + + + + + escrowedPaymentReminder + + + + + + + +491522345678 + for + + + 11870000 + + + + + +491522345678 + for + + + 11870000 + + + + + + + + walletFlow5:review + + + + + + + +`; + +exports[`EscrowedPaymentReminderSummaryNotification when more 1 requests renders just it alone 1`] = ` + + + + + + + + + + escrowPaymentNotificationTitle + + + + test message + + + + + global:remind + + + + + global:reclaim + + + + + + + + + +`; + +exports[`EscrowedPaymentReminderSummaryNotification when more than 2 requests renders just two 1`] = ` + + + + + + + + escrowedPaymentReminder + + + + + + + +491522345678 + for + + + 11870000 + + + + + +491522345678 + for + + + 11870000 + + + + + + + + walletFlow5:review + + + + + + + +`; diff --git a/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationCard.test.tsx.snap b/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationCard.test.tsx.snap index e3d542a6b57..9279431ea62 100644 --- a/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationCard.test.tsx.snap +++ b/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationCard.test.tsx.snap @@ -192,7 +192,6 @@ exports[`ReclaimPaymentConfirmationCard renders correctly for send payment confi "alignItems": "stretch", "justifyContent": "center", "marginBottom": 10, - "marginTop": 10, } } > diff --git a/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationScreen.test.tsx.snap b/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationScreen.test.tsx.snap index 7a196fd37ac..53ee77b7b9f 100644 --- a/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationScreen.test.tsx.snap +++ b/packages/mobile/src/escrow/__snapshots__/ReclaimPaymentConfirmationScreen.test.tsx.snap @@ -262,7 +262,6 @@ exports[`ReclaimPaymentConfirmationScreen renders correctly 1`] = ` "alignItems": "stretch", "justifyContent": "center", "marginBottom": 10, - "marginTop": 10, } } > @@ -907,7 +906,6 @@ exports[`ReclaimPaymentConfirmationScreen renders correctly when fee calculation "alignItems": "stretch", "justifyContent": "center", "marginBottom": 10, - "marginTop": 10, } } > @@ -1552,7 +1550,6 @@ exports[`ReclaimPaymentConfirmationScreen renders correctly when fee calculation "alignItems": "stretch", "justifyContent": "center", "marginBottom": 10, - "marginTop": 10, } } > diff --git a/packages/mobile/src/escrow/saga.ts b/packages/mobile/src/escrow/saga.ts index d49452a4723..92861b08953 100644 --- a/packages/mobile/src/escrow/saga.ts +++ b/packages/mobile/src/escrow/saga.ts @@ -243,7 +243,6 @@ function* doFetchSentPayments() { const sentPaymentsRaw = yield all( sentPaymentIDs.map((paymentID) => call(getEscrowedPayment, escrow, paymentID)) ) - const tempAddresstoRecipientPhoneNumber: Invitees = yield select(inviteesSelector) const sentPayments: EscrowedPayment[] = [] for (let i = 0; i < sentPaymentsRaw.length; i++) { diff --git a/packages/mobile/src/home/NotificationBox.test.tsx b/packages/mobile/src/home/NotificationBox.test.tsx index 840fb21a937..12a749e14b4 100644 --- a/packages/mobile/src/home/NotificationBox.test.tsx +++ b/packages/mobile/src/home/NotificationBox.test.tsx @@ -83,7 +83,23 @@ describe('NotificationBox', () => { expect(getByText('inviteFlow11:inviteFriendsToCelo')).toBeTruthy() }) - it('renders payment requests when they exist', () => { + it('renders incoming payment request when they exist', () => { + const store = createMockStore({ + ...storeDataNotificationsDisabled, + account: { + ...storeDataNotificationsDisabled.account, + incomingPaymentRequests: [mockPaymentRequests[0]], + }, + }) + const { getByText } = render( + + + + ) + expect(getByText('incomingPaymentRequestNotificationTitle')).toBeTruthy() + }) + + it('renders incoming payment requests when they exist', () => { const store = createMockStore({ ...storeDataNotificationsDisabled, account: { @@ -96,7 +112,39 @@ describe('NotificationBox', () => { ) - expect(getByText('incomingPaymentRequest')).toBeTruthy() + expect(getByText('incomingPaymentRequests')).toBeTruthy() + }) + + it('renders outgoing payment requests when they exist', () => { + const store = createMockStore({ + ...storeDataNotificationsDisabled, + account: { + ...storeDataNotificationsDisabled.account, + outgoingPaymentRequests: mockPaymentRequests, + }, + }) + const { getByText } = render( + + + + ) + expect(getByText('outgoingPaymentRequests')).toBeTruthy() + }) + + it('renders outgoing payment request when they exist', () => { + const store = createMockStore({ + ...storeDataNotificationsDisabled, + account: { + ...storeDataNotificationsDisabled.account, + outgoingPaymentRequests: [mockPaymentRequests[0]], + }, + }) + const { getByText } = render( + + + + ) + expect(getByText('outgoingPaymentRequestNotificationTitle')).toBeTruthy() }) it('renders verification reminder when not verified', () => { diff --git a/packages/mobile/src/home/NotificationBox.tsx b/packages/mobile/src/home/NotificationBox.tsx index 4943b5ab75b..774563b9d95 100644 --- a/packages/mobile/src/home/NotificationBox.tsx +++ b/packages/mobile/src/home/NotificationBox.tsx @@ -12,6 +12,7 @@ import { CustomEventNames } from 'src/analytics/constants' import { componentWithAnalytics } from 'src/analytics/wrapper' import { PROMOTE_REWARDS_APP } from 'src/config' import { EscrowedPayment } from 'src/escrow/actions' +import EscrowedPaymentReminderSummaryNotification from 'src/escrow/EscrowedPaymentReminderSummaryNotification' import { getReclaimableEscrowPayments } from 'src/escrow/saga' import { setEducationCompleted as setGoldEducationCompleted } from 'src/goldToken/actions' import i18n, { Namespaces } from 'src/i18n' @@ -24,10 +25,9 @@ import { } from 'src/images/Images' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' -import EscrowedPaymentReminderSummaryNotification from 'src/notifications/EscrowedPaymentReminderSummaryNotification' -import IncomingPaymentRequestSummaryNotification from 'src/notifications/IncomingPaymentRequestSummaryNotification' -import OutgoingPaymentRequestSummaryNotification from 'src/notifications/OutgoingPaymentRequestSummaryNotification' import SimpleNotification from 'src/notifications/SimpleNotification' +import IncomingPaymentRequestSummaryNotification from 'src/paymentRequest/IncomingPaymentRequestSummaryNotification' +import OutgoingPaymentRequestSummaryNotification from 'src/paymentRequest/OutgoingPaymentRequestSummaryNotification' import { RootState } from 'src/redux/reducers' import { isBackupTooLate } from 'src/redux/selectors' import { navigateToVerifierApp } from 'src/utils/linking' diff --git a/packages/mobile/src/home/__snapshots__/NotificationBox.test.tsx.snap b/packages/mobile/src/home/__snapshots__/NotificationBox.test.tsx.snap index 6de974ee123..cfbf818ddb3 100644 --- a/packages/mobile/src/home/__snapshots__/NotificationBox.test.tsx.snap +++ b/packages/mobile/src/home/__snapshots__/NotificationBox.test.tsx.snap @@ -24,73 +24,79 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` } } > - + - - - - + + + - incomingPaymentRequest - - + + incomingPaymentRequests + @@ -118,6 +124,19 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` } } > + + +14155550000 + for + + 12.34 + + + + +14155550000 - - - Rent request for June, it is already late!!! + for - $12.34 + 12.34 @@ -158,7 +201,7 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` style={ Object { "flexDirection": "row", - "marginTop": 15, + "marginTop": 5, } } > @@ -195,7 +238,7 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` ] } > - review + walletFlow5:review @@ -212,73 +255,79 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` } } > - + - - - - + + + - backupKeyFlow6:yourBackupKey - - + + backupKeyFlow6:yourBackupKey + @@ -306,7 +355,7 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` style={ Object { "flexDirection": "row", - "marginTop": 15, + "marginTop": 5, } } > @@ -360,73 +409,79 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` } } > - + - - - - + + + - nuxVerification2:notification.title - - + + nuxVerification2:notification.title + @@ -454,7 +509,7 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` style={ Object { "flexDirection": "row", - "marginTop": 15, + "marginTop": 5, } } > @@ -544,73 +599,79 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` } } > - + - - - - + + + - global:celoGold - - + + global:celoGold + @@ -638,7 +699,7 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` style={ Object { "flexDirection": "row", - "marginTop": 15, + "marginTop": 5, } } > @@ -728,73 +789,79 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` } } > - + - - - - + + + - inviteFlow11:inviteFriendsToCelo - - + + inviteFlow11:inviteFriendsToCelo + @@ -822,7 +889,7 @@ exports[`NotificationBox renders correctly for with all notifications 1`] = ` style={ Object { "flexDirection": "row", - "marginTop": 15, + "marginTop": 5, } } > diff --git a/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap b/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap index f527ca797e0..61e335996f5 100644 --- a/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap +++ b/packages/mobile/src/home/__snapshots__/WalletHome.test.tsx.snap @@ -295,7 +295,7 @@ exports[`Testnet banner Renders when connected with backup complete 1`] = ` style={ Object { "color": "#2E3338", - "fontFamily": "Hind-Medium", + "fontFamily": "Hind-Bold", "fontSize": 14, "opacity": 0, } @@ -1660,7 +1660,7 @@ exports[`Testnet banner Shows testnet banner for 5 seconds 1`] = ` style={ Object { "color": "#2E3338", - "fontFamily": "Hind-Medium", + "fontFamily": "Hind-Bold", "fontSize": 14, "opacity": 0, } diff --git a/packages/mobile/src/icons/PaymentsIcon.tsx b/packages/mobile/src/icons/PaymentsIcon.tsx index d18699d8f7b..275680ebf58 100644 --- a/packages/mobile/src/icons/PaymentsIcon.tsx +++ b/packages/mobile/src/icons/PaymentsIcon.tsx @@ -10,8 +10,8 @@ interface Props { export default class PaymentsIcon extends React.PureComponent { static defaultProps = { - width: 28, - height: 28, + width: 34, + height: 34, color: colors.dark, } diff --git a/packages/mobile/src/navigator/Navigator.tsx b/packages/mobile/src/navigator/Navigator.tsx index 18cf8d530e9..77d446d8720 100644 --- a/packages/mobile/src/navigator/Navigator.tsx +++ b/packages/mobile/src/navigator/Navigator.tsx @@ -278,6 +278,12 @@ const AppStack = createStackNavigator( // Note, WalletHome isn't in this stack because it's part of the tab navigator [Screens.TabNavigator]: { screen: TabNavigator }, [Stacks.SendStack]: { screen: SendStack }, + // Adding this screen, so it possbile to go back to Home screen from it + [Screens.SendConfirmation]: { screen: SendConfirmation }, + // Adding this screen, so it possbile to go back to Home screen from it + [Screens.ReclaimPaymentConfirmationScreen]: { + screen: ReclaimPaymentConfirmationScreen, + }, [Stacks.QRSendStack]: { screen: QRSendStack }, [Stacks.ExchangeStack]: { screen: ExchangeStack }, [Stacks.IncomingRequestStack]: { screen: IncomingRequestStack }, diff --git a/packages/mobile/src/navigator/TabNavigator.tsx b/packages/mobile/src/navigator/TabNavigator.tsx index a7b5fdd3790..e879fc568ad 100644 --- a/packages/mobile/src/navigator/TabNavigator.tsx +++ b/packages/mobile/src/navigator/TabNavigator.tsx @@ -163,7 +163,7 @@ const styles = StyleSheet.create({ marginLeft: 3, }, alignPaymentIcon: { - marginBottom: 15, + marginBottom: 8, }, }) diff --git a/packages/mobile/src/notifications/IncomingPaymentRequestSummaryNotification.tsx b/packages/mobile/src/notifications/IncomingPaymentRequestSummaryNotification.tsx index 3c354797246..d73183456e0 100644 --- a/packages/mobile/src/notifications/IncomingPaymentRequestSummaryNotification.tsx +++ b/packages/mobile/src/notifications/IncomingPaymentRequestSummaryNotification.tsx @@ -95,7 +95,6 @@ export class IncomingPaymentRequestSummaryNotification extends React.Component

} ctas={this.getCTA()} - roundedBorders={true} > @@ -104,7 +103,6 @@ export class IncomingPaymentRequestSummaryNotification extends React.Component

diff --git a/packages/mobile/src/notifications/NotificationList.test.tsx b/packages/mobile/src/notifications/NotificationList.test.tsx new file mode 100644 index 00000000000..1ff90c52c26 --- /dev/null +++ b/packages/mobile/src/notifications/NotificationList.test.tsx @@ -0,0 +1,25 @@ +import * as React from 'react' +import { Text } from 'react-native' +import { Provider } from 'react-redux' +import * as renderer from 'react-test-renderer' +import { NotificationList } from 'src/notifications/NotificationList' +import { createMockStore } from 'test/utils' + +const props = () => ({ + dollarBalance: '123', + items: ['a'], + listItemRenderer: (item: string, key: number) => { + return {`test-${item}`} + }, +}) + +describe(NotificationList, () => { + it('renders correctly', () => { + const tree = renderer.create( + + {...props()} /> + + ) + expect(tree).toMatchSnapshot() + }) +}) diff --git a/packages/mobile/src/notifications/NotificationList.tsx b/packages/mobile/src/notifications/NotificationList.tsx new file mode 100644 index 00000000000..e25f0eff4c7 --- /dev/null +++ b/packages/mobile/src/notifications/NotificationList.tsx @@ -0,0 +1,99 @@ +import colors from '@celo/react-components/styles/colors' +import fontStyles from '@celo/react-components/styles/fonts' +import variables from '@celo/react-components/styles/variables' +import React, { useEffect } from 'react' +import { ScrollView, StyleSheet, Text, View } from 'react-native' +import SafeAreaView from 'react-native-safe-area-view' +import { + NavigationParams, + NavigationProp, + NavigationScreenProp, + NavigationState, +} from 'react-navigation' +import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' +import i18n from 'src/i18n' +import { headerWithBackButton } from 'src/navigator/Headers' +import DisconnectBanner from 'src/shared/DisconnectBanner' +import { getCentAwareMoneyDisplay } from 'src/utils/formatting' + +const { contentPadding } = variables + +interface OwnProps { + dollarBalance: string | null + listItemRenderer: (item: T, key: number) => JSX.Element + items: T[] +} + +type Props = OwnProps + +export function NotificationList(props: Props) { + return ( + + + {props.items.length > 0 ? ( + + {props.items.map(props.listItemRenderer)} + + ) : ( + {i18n.t('global:emptyList')} + )} + + ) +} + +export function titleWithBalanceNavigationOptions(title: string) { + return ({ navigation }: { navigation: NavigationProp }) => ({ + ...headerWithBackButton, + headerTitle: ( + + {title && {title}} + + {(navigation.state.params && + navigation.state.params.dollarBalance && + CURRENCIES[CURRENCY_ENUM.DOLLAR].symbol + + i18n.t('sendFlow7:celoDollarsAvailable', { + CeloDollars: getCentAwareMoneyDisplay(navigation.state.params.dollarBalance || 0), + })) || + i18n.t('global:loading')} + + + ), + }) +} + +const styles = StyleSheet.create({ + container: { + backgroundColor: colors.background, + flex: 1, + }, + scrollArea: { + margin: contentPadding, + }, + balanceText: { + ...fontStyles.bodySmall, + color: colors.inactiveDark, + }, + empty: { + textAlign: 'center', + marginTop: 30, + }, + header: { + alignItems: 'center', + flex: 1, + }, +}) + +// Should be used together with titleWithBalanceNavigationOptions. +// Call this hook inside a Screen and assign +// Screen.navigationOptions = titleWithBalanceNavigationOptions(title) +export function useBalanceInNavigationParam( + dollarBalance: string | null, + navigation: NavigationScreenProp +) { + useEffect( + () => { + navigation.setParams({ dollarBalance }) + }, + [dollarBalance] + ) +} diff --git a/packages/mobile/src/notifications/OutgoingPaymentRequestSummaryNotification.tsx b/packages/mobile/src/notifications/OutgoingPaymentRequestSummaryNotification.tsx index f1ab00394b6..23f555ae5bc 100644 --- a/packages/mobile/src/notifications/OutgoingPaymentRequestSummaryNotification.tsx +++ b/packages/mobile/src/notifications/OutgoingPaymentRequestSummaryNotification.tsx @@ -95,7 +95,6 @@ export class OutgoingPaymentRequestSummaryNotification extends React.Component

} ctas={this.getCTA()} - roundedBorders={true} > @@ -104,7 +103,6 @@ export class OutgoingPaymentRequestSummaryNotification extends React.Component

diff --git a/packages/mobile/src/notifications/SimpleNotification.test.tsx b/packages/mobile/src/notifications/SimpleNotification.test.tsx index aae8da07a97..52384815a8d 100644 --- a/packages/mobile/src/notifications/SimpleNotification.test.tsx +++ b/packages/mobile/src/notifications/SimpleNotification.test.tsx @@ -1,11 +1,12 @@ import * as React from 'react' import 'react-native' import * as renderer from 'react-test-renderer' +import { placeholder } from 'src/images/Images' import SimpleNotification from 'src/notifications/SimpleNotification' const props = () => ({ text: 'Gold is where you can choose to store Celo dollars you have', - image: require('src/images/placeholder.png'), + image: placeholder, title: 'Test', ctaList: [{ text: 'it goes boom', onPress: jest.fn() }], }) diff --git a/packages/mobile/src/notifications/SimpleNotification.tsx b/packages/mobile/src/notifications/SimpleNotification.tsx index 200bc12dca9..1cf9e9b64b6 100644 --- a/packages/mobile/src/notifications/SimpleNotification.tsx +++ b/packages/mobile/src/notifications/SimpleNotification.tsx @@ -18,7 +18,6 @@ export function SimpleNotification(props: Props) { title={props.title} icon={} ctas={props.ctaList} - roundedBorders={true} > {props.text} diff --git a/packages/mobile/src/notifications/SummaryNotification.test.tsx b/packages/mobile/src/notifications/SummaryNotification.test.tsx new file mode 100644 index 00000000000..e9e05df4bb2 --- /dev/null +++ b/packages/mobile/src/notifications/SummaryNotification.test.tsx @@ -0,0 +1,23 @@ +import * as React from 'react' +import { Text, View } from 'react-native' +import * as renderer from 'react-test-renderer' +import { placeholder } from 'src/images/Images' +import SummaryNotification from 'src/notifications/SummaryNotification' + +const props = () => ({ + image: placeholder, + icon: , + title: 'Test', + items: ['a'], + itemRenderer: (item: string, key: number) => { + return {`test-${item}`} + }, + onReview: jest.fn(), +}) + +describe(SummaryNotification, () => { + it('renders correctly', () => { + const tree = renderer.create( {...props()} />) + expect(tree).toMatchSnapshot() + }) +}) diff --git a/packages/mobile/src/notifications/SummaryNotification.tsx b/packages/mobile/src/notifications/SummaryNotification.tsx new file mode 100644 index 00000000000..a5befbbcde0 --- /dev/null +++ b/packages/mobile/src/notifications/SummaryNotification.tsx @@ -0,0 +1,69 @@ +import SummaryNotification from '@celo/react-components/components/SummaryNotification' +import fontStyles from '@celo/react-components/styles/fonts' +import * as React from 'react' +import i18n from 'src/i18n' + +import { StyleSheet, Text, View } from 'react-native' + +interface OwnProps { + title: string + icon: JSX.Element + onReview: () => void + itemRenderer: (item: T, key: number) => JSX.Element + items: T[] +} + +type Props = OwnProps + +const PREVIEW_SIZE = 2 + +function getAdditionalItemsCount(items: T[]) { + const total = items.length + if (total - PREVIEW_SIZE > 0) { + return ( + + + {i18n.t('global:moreWithCount', { count: total - PREVIEW_SIZE + 1 })} + + + ) + } +} + +// Payment Request notification for the notification center on home screen +function PaymentsSummaryNotification(props: Props) { + const { items, title, icon, onReview, itemRenderer } = props + + return ( + + + + {items + .slice(0, props.items.length > PREVIEW_SIZE ? PREVIEW_SIZE - 1 : PREVIEW_SIZE) + .map(itemRenderer)} + {getAdditionalItemsCount(items)} + + + + ) +} + +const styles = StyleSheet.create({ + body: { + marginTop: 5, + flexDirection: 'row', + }, + items: { + flex: 1, + }, + moreWithCountText: fontStyles.subSmall, +}) + +export default PaymentsSummaryNotification diff --git a/packages/mobile/src/notifications/__snapshots__/EscrowedPaymentReminderSummaryNotification.test.tsx.snap b/packages/mobile/src/notifications/__snapshots__/EscrowedPaymentReminderSummaryNotification.test.tsx.snap deleted file mode 100644 index 21c1761ff7e..00000000000 --- a/packages/mobile/src/notifications/__snapshots__/EscrowedPaymentReminderSummaryNotification.test.tsx.snap +++ /dev/null @@ -1,643 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`EscrowedPaymentReminderSummaryNotification renders correctly 1`] = ` - - - - - - - escrowedPaymentReminderWithCount_plural - - - - - - - - +491522345678 - - - test message - - - - $ - 7 - - - - - +491522345678 - - - test message - - - - $ - 7 - - - - - - - - review - - - - - - - -`; - -exports[`EscrowedPaymentReminderSummaryNotification when more 1 requests renders just it alone 1`] = ` - - - - - - - escrowedPaymentReminder - - - - - - - - +491522345678 - - - test message - - - - $ - 7 - - - - - - - - review - - - - - - - -`; - -exports[`EscrowedPaymentReminderSummaryNotification when more than 2 requests renders just two 1`] = ` - - - - - - - escrowedPaymentReminderWithCount_plural - - - - - - - - +491522345678 - - - test message - - - - $ - 7 - - - - - +491522345678 - - - test message - - - - $ - 7 - - - - - - - - review - - - - - - - -`; diff --git a/packages/mobile/src/notifications/__snapshots__/IncomingPaymentRequestSummaryNotification.test.tsx.snap b/packages/mobile/src/notifications/__snapshots__/IncomingPaymentRequestSummaryNotification.test.tsx.snap deleted file mode 100644 index e56291ac63e..00000000000 --- a/packages/mobile/src/notifications/__snapshots__/IncomingPaymentRequestSummaryNotification.test.tsx.snap +++ /dev/null @@ -1,677 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`IncomingPaymentRequestSummaryNotification renders correctly 1`] = ` - - - - - - - incomingPaymentRequestWithCount - - - - - - - - +491522345678 - - - Dinner for me and the gals, PIZZAA! - - - $200,000 - - - - - +491522345678 - - - My Birthday Present. :) Am I not the best? Celebration. Bam! - - - $180.89 - - - - - - + - 1 - - - - - - - review - - - - - - - -`; - -exports[`IncomingPaymentRequestSummaryNotification when more 1 requests renders just it alone 1`] = ` - - - - - - - incomingPaymentRequest - - - - - - - - +491522345678 - - - Dinner for me and the gals, PIZZAA! - - - $200,000 - - - - - - - - review - - - - - - - -`; - -exports[`IncomingPaymentRequestSummaryNotification when more than 2 requests renders just two 1`] = ` - - - - - - - incomingPaymentRequestWithCount - - - - - - - - +491522345678 - - - Dinner for me and the gals, PIZZAA! - - - $200,000 - - - - - +491522345678 - - - My Birthday Present. :) Am I not the best? Celebration. Bam! - - - $180.89 - - - - - - + - 1 - - - - - - - review - - - - - - - -`; diff --git a/packages/mobile/src/notifications/__snapshots__/NotificationList.test.tsx.snap b/packages/mobile/src/notifications/__snapshots__/NotificationList.test.tsx.snap new file mode 100644 index 00000000000..9a076d94e37 --- /dev/null +++ b/packages/mobile/src/notifications/__snapshots__/NotificationList.test.tsx.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NotificationList renders correctly 1`] = ` + + + + + + test-a + + + + + +`; diff --git a/packages/mobile/src/notifications/__snapshots__/OutgoingPaymentRequestSummaryNotification.test.tsx.snap b/packages/mobile/src/notifications/__snapshots__/OutgoingPaymentRequestSummaryNotification.test.tsx.snap deleted file mode 100644 index d797a5c3241..00000000000 --- a/packages/mobile/src/notifications/__snapshots__/OutgoingPaymentRequestSummaryNotification.test.tsx.snap +++ /dev/null @@ -1,677 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OutgoingPaymentRequestSummaryNotification renders correctly 1`] = ` - - - - - - - outgoingPaymentRequestWithCount - - - - - - - - +491522345678 - - - Dinner for me and the gals, PIZZAA! - - - $200,000 - - - - - +491522345678 - - - My Birthday Present. :) Am I not the best? Celebration. Bam! - - - $180.89 - - - - - - + - 1 - - - - - - - review - - - - - - - -`; - -exports[`OutgoingPaymentRequestSummaryNotification when more 1 requests renders just it alone 1`] = ` - - - - - - - outgoingPaymentRequest - - - - - - - - +491522345678 - - - Dinner for me and the gals, PIZZAA! - - - $200,000 - - - - - - - - review - - - - - - - -`; - -exports[`OutgoingPaymentRequestSummaryNotification when more than 2 requests renders just two 1`] = ` - - - - - - - outgoingPaymentRequestWithCount - - - - - - - - +491522345678 - - - Dinner for me and the gals, PIZZAA! - - - $200,000 - - - - - +491522345678 - - - My Birthday Present. :) Am I not the best? Celebration. Bam! - - - $180.89 - - - - - - + - 1 - - - - - - - review - - - - - - - -`; diff --git a/packages/mobile/src/notifications/__snapshots__/SimpleNotification.test.tsx.snap b/packages/mobile/src/notifications/__snapshots__/SimpleNotification.test.tsx.snap index 0f04a9f122a..eef2c2f0c62 100644 --- a/packages/mobile/src/notifications/__snapshots__/SimpleNotification.test.tsx.snap +++ b/packages/mobile/src/notifications/__snapshots__/SimpleNotification.test.tsx.snap @@ -1,73 +1,79 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`SimpleNotification renders correctly 1`] = ` - + - - - - + + + - Test - - + + Test + @@ -95,7 +101,7 @@ exports[`SimpleNotification renders correctly 1`] = ` style={ Object { "flexDirection": "row", - "marginTop": 15, + "marginTop": 5, } } > diff --git a/packages/mobile/src/notifications/__snapshots__/SummaryNotification.test.tsx.snap b/packages/mobile/src/notifications/__snapshots__/SummaryNotification.test.tsx.snap new file mode 100644 index 00000000000..458502ecd1b --- /dev/null +++ b/packages/mobile/src/notifications/__snapshots__/SummaryNotification.test.tsx.snap @@ -0,0 +1,136 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PaymentsSummaryNotification renders correctly 1`] = ` + + + + + + + + Test + + + + + + test-a + + + + + + + walletFlow5:review + + + + + + + +`; diff --git a/packages/mobile/src/paymentRequest/IncomingPaymentRequestListItem.tsx b/packages/mobile/src/paymentRequest/IncomingPaymentRequestListItem.tsx index 30200b8132e..d692432e728 100644 --- a/packages/mobile/src/paymentRequest/IncomingPaymentRequestListItem.tsx +++ b/packages/mobile/src/paymentRequest/IncomingPaymentRequestListItem.tsx @@ -1,23 +1,22 @@ import BaseNotification from '@celo/react-components/components/BaseNotification' import ContactCircle from '@celo/react-components/components/ContactCircle' -import colors from '@celo/react-components/styles/colors' import fontStyles from '@celo/react-components/styles/fonts' -import variables from '@celo/react-components/styles/variables' import BigNumber from 'bignumber.js' import * as React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { StyleSheet, Text, TouchableOpacity, View } from 'react-native' +import { Image, StyleSheet, Text, View } from 'react-native' import { PaymentRequestStatus } from 'src/account/types' import CeloAnalytics from 'src/analytics/CeloAnalytics' import { CustomEventNames } from 'src/analytics/constants' import { updatePaymentRequestStatus } from 'src/firebase/actions' +import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' import { Namespaces } from 'src/i18n' +import { unknownUserIcon } from 'src/images/Images' import { navigate } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' -import NotificationAmount from 'src/paymentRequest/NotificationAmount' import { getRecipientThumbnail, Recipient } from 'src/recipients/recipient' import { TransactionTypes } from 'src/transactions/reducer' -import { multiplyByWei } from 'src/utils/formatting' +import { getCentAwareMoneyDisplay } from 'src/utils/formatting' import Logger from 'src/utils/Logger' interface OwnProps { @@ -30,6 +29,8 @@ interface OwnProps { type Props = OwnProps & WithNamespaces +const AVATAR_SIZE = 40 + export class IncomingPaymentRequestListItem extends React.Component { onPay = () => { const { amount, comment: reason, requester: recipient } = this.props @@ -51,7 +52,6 @@ export class IncomingPaymentRequestListItem extends React.Component { this.props.updatePaymentRequestStatus(id.toString(), PaymentRequestStatus.COMPLETED) Logger.showMessage(this.props.t('requestPaid')) CeloAnalytics.track(CustomEventNames.incoming_request_payment_pay) - this.onFinalized() } onPaymentDecline = () => { @@ -59,69 +59,61 @@ export class IncomingPaymentRequestListItem extends React.Component { this.props.updatePaymentRequestStatus(id.toString(), PaymentRequestStatus.DECLINED) Logger.showMessage(this.props.t('requestDeclined')) CeloAnalytics.track(CustomEventNames.incoming_request_payment_decline) - this.onFinalized() - } - - onFinalized = () => { - navigate(Screens.IncomingPaymentRequestListScreen) } getCTA = () => { return [ { - text: this.props.t('pay'), + text: this.props.t('global:pay'), onPress: this.onPay, }, { - text: this.props.t('decline'), + text: this.props.t('global:decline'), onPress: this.onPaymentDecline, }, ] } - isDisplayingNumber = () => { - return this.props.requester.displayId !== this.props.requester.displayName - } - render() { - const { requester } = this.props + const { requester, t } = this.props return ( - + + > + + } - title={requester.displayName} + title={t('incomingPaymentRequestNotificationTitle', { + name: requester.displayName, + amount: + CURRENCIES[CURRENCY_ENUM.DOLLAR].symbol + getCentAwareMoneyDisplay(this.props.amount), + })} ctas={this.getCTA()} - roundedBorders={false} - callout={} + onPress={this.onPay} > - - {this.isDisplayingNumber() && ( - - {this.props.requester.displayId} - - )} - {this.props.comment} - + {this.props.comment || t('defaultComment')} - + ) } } const styles = StyleSheet.create({ - comment: { - paddingTop: variables.contentPadding, + container: { + marginBottom: 16, }, - phoneNumber: { - color: colors.dark, + unknownUser: { + height: AVATAR_SIZE, + width: AVATAR_SIZE, + justifyContent: 'center', + alignItems: 'center', }, }) -export default withNamespaces(Namespaces.global)(IncomingPaymentRequestListItem) +export default withNamespaces(Namespaces.paymentRequestFlow)(IncomingPaymentRequestListItem) diff --git a/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.test.tsx b/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.test.tsx index 28831dff37b..2702ee76761 100644 --- a/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.test.tsx +++ b/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.test.tsx @@ -1,3 +1,4 @@ +import BigNumber from 'bignumber.js' import * as React from 'react' import 'react-native' import { Provider } from 'react-redux' @@ -5,8 +6,8 @@ import * as renderer from 'react-test-renderer' import { PaymentRequest } from 'src/account/types' import { paymentRequestDouble } from 'src/paymentRequest/__mocks__' import IncomingPaymentRequestListScreen from 'src/paymentRequest/IncomingPaymentRequestListScreen' -import { createMockStore } from 'test/utils' -import { mockAccount, mockE164Number } from 'test/values' +import { createMockNavigationProp, createMockStore } from 'test/utils' +import { mockAccount, mockE164Number, mockRecipient } from 'test/values' const requests = [ paymentRequestDouble({ @@ -29,6 +30,13 @@ const requests = [ }), ] +const navigation = createMockNavigationProp({ + recipient: mockRecipient, + recipientAddress: mockAccount, + amount: new BigNumber(10), + reason: 'My Reason', +}) + function testStore(incomingPaymentRequests: PaymentRequest[]) { return createMockStore({ stableToken: { balance: '120' }, @@ -42,7 +50,7 @@ describe('IncomingPaymentRequestListScreen', () => { const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() @@ -53,7 +61,7 @@ describe('IncomingPaymentRequestListScreen', () => { const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() diff --git a/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.tsx b/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.tsx index f607cb1f8fe..168677a1ec5 100644 --- a/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.tsx +++ b/packages/mobile/src/paymentRequest/IncomingPaymentRequestListScreen.tsx @@ -1,10 +1,6 @@ -import colors from '@celo/react-components/styles/colors' -import { componentStyles } from '@celo/react-components/styles/styles' -import variables from '@celo/react-components/styles/variables' -import * as React from 'react' +import React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { ScrollView, StyleSheet, View } from 'react-native' -import SafeAreaView from 'react-native-safe-area-view' +import { NavigationInjectedProps } from 'react-navigation' import { connect } from 'react-redux' import { getIncomingPaymentRequests } from 'src/account/selectors' import { PaymentRequest } from 'src/account/types' @@ -12,17 +8,16 @@ import { updatePaymentRequestStatus } from 'src/firebase/actions' import i18n, { Namespaces } from 'src/i18n' import { fetchPhoneAddresses } from 'src/identity/actions' import { e164NumberToAddressSelector, E164NumberToAddressType } from 'src/identity/reducer' -import { headerWithBackButton } from 'src/navigator/Headers' +import { + NotificationList, + titleWithBalanceNavigationOptions, + useBalanceInNavigationParam, +} from 'src/notifications/NotificationList' import IncomingPaymentRequestListItem from 'src/paymentRequest/IncomingPaymentRequestListItem' -import PaymentRequestBalance from 'src/paymentRequest/PaymentRequestBalance' -import PaymentRequestListEmpty from 'src/paymentRequest/PaymentRequestListEmpty' import { getRecipientFromPaymentRequest } from 'src/paymentRequest/utils' import { NumberToRecipient } from 'src/recipients/recipient' import { recipientCacheSelector } from 'src/recipients/reducer' import { RootState } from 'src/redux/reducers' -import DisconnectBanner from 'src/shared/DisconnectBanner' - -const { contentPadding } = variables interface StateProps { dollarBalance: string | null @@ -43,65 +38,44 @@ const mapStateToProps = (state: RootState): StateProps => ({ recipientCache: recipientCacheSelector(state), }) -type Props = WithNamespaces & StateProps & DispatchProps - -export class IncomingPaymentRequestListScreen extends React.Component { - static navigationOptions = () => ({ - ...headerWithBackButton, - headerTitle: i18n.t('paymentRequestFlow:incomingPaymentRequests'), - }) +type Props = NavigationInjectedProps & WithNamespaces & StateProps & DispatchProps - renderRequest = (request: PaymentRequest, key: number, allRequests: PaymentRequest[]) => { - const { recipientCache } = this.props - const requester = getRecipientFromPaymentRequest(request, recipientCache) +export const listItemRenderer = (params: { + recipientCache: NumberToRecipient + updatePaymentRequestStatus: typeof updatePaymentRequestStatus +}) => (request: PaymentRequest, key: number | undefined = undefined) => { + const requester = getRecipientFromPaymentRequest(request, params.recipientCache) - return ( - - - {key < allRequests.length - 1 && } - - ) - } + return ( + + ) +} - render() { - return ( - - - - {this.props.paymentRequests.length > 0 ? ( - - - {this.props.paymentRequests.map(this.renderRequest)} - - - ) : ( - - )} - - ) - } +const IncomingPaymentRequestListScreen = (props: Props) => { + const { recipientCache, dollarBalance, navigation } = props + useBalanceInNavigationParam(dollarBalance, navigation) + return ( + + ) } -const styles = StyleSheet.create({ - container: { - backgroundColor: colors.background, - flex: 1, - }, - separator: { - borderBottomColor: colors.darkLightest, - borderBottomWidth: 1, - marginLeft: 50, - }, - scrollArea: { - margin: contentPadding, - }, -}) +IncomingPaymentRequestListScreen.navigationOptions = titleWithBalanceNavigationOptions( + i18n.t('walletFlow5:incomingPaymentRequests') +) export default connect( mapStateToProps, diff --git a/packages/mobile/src/notifications/IncomingPaymentRequestSummaryNotification.test.tsx b/packages/mobile/src/paymentRequest/IncomingPaymentRequestSummaryNotification.test.tsx similarity index 95% rename from packages/mobile/src/notifications/IncomingPaymentRequestSummaryNotification.test.tsx rename to packages/mobile/src/paymentRequest/IncomingPaymentRequestSummaryNotification.test.tsx index 95c5891808c..70953924062 100644 --- a/packages/mobile/src/notifications/IncomingPaymentRequestSummaryNotification.test.tsx +++ b/packages/mobile/src/paymentRequest/IncomingPaymentRequestSummaryNotification.test.tsx @@ -4,7 +4,7 @@ import { Provider } from 'react-redux' import * as renderer from 'react-test-renderer' import { PaymentRequestStatus } from 'src/account/types' import { SHORT_CURRENCIES } from 'src/geth/consts' -import IncomingPaymentRequestSummaryNotification from 'src/notifications/IncomingPaymentRequestSummaryNotification' +import IncomingPaymentRequestSummaryNotification from 'src/paymentRequest/IncomingPaymentRequestSummaryNotification' import { createMockStore } from 'test/utils' const requesterE164Number = '+491522345678' diff --git a/packages/mobile/src/paymentRequest/IncomingPaymentRequestSummaryNotification.tsx b/packages/mobile/src/paymentRequest/IncomingPaymentRequestSummaryNotification.tsx new file mode 100644 index 00000000000..0ae36790ecb --- /dev/null +++ b/packages/mobile/src/paymentRequest/IncomingPaymentRequestSummaryNotification.tsx @@ -0,0 +1,104 @@ +import * as React from 'react' +import { WithNamespaces, withNamespaces } from 'react-i18next' +import { Image, StyleSheet } from 'react-native' +import { connect } from 'react-redux' +import { PaymentRequest } from 'src/account/types' +import CeloAnalytics from 'src/analytics/CeloAnalytics' +import { CustomEventNames } from 'src/analytics/constants' +import { updatePaymentRequestStatus } from 'src/firebase/actions' +import { Namespaces } from 'src/i18n' +import { + addressToE164NumberSelector, + AddressToE164NumberType, + e164NumberToAddressSelector, + E164NumberToAddressType, +} from 'src/identity/reducer' +import { sendDollar } from 'src/images/Images' +import { navigate } from 'src/navigator/NavigationService' +import { Stacks } from 'src/navigator/Screens' +import SummaryNotification from 'src/notifications/SummaryNotification' +import { listItemRenderer } from 'src/paymentRequest/IncomingPaymentRequestListScreen' +import PaymentRequestNotificationInner from 'src/paymentRequest/PaymentRequestNotificationInner' +import { NumberToRecipient, phoneNumberToRecipient } from 'src/recipients/recipient' +import { recipientCacheSelector } from 'src/recipients/reducer' +import { RootState } from 'src/redux/reducers' + +interface OwnProps { + requests: PaymentRequest[] +} + +interface DispatchProps { + updatePaymentRequestStatus: typeof updatePaymentRequestStatus +} + +type Props = OwnProps & DispatchProps & WithNamespaces & StateProps + +interface StateProps { + e164PhoneNumberAddressMapping: E164NumberToAddressType + addressToE164Number: AddressToE164NumberType + recipientCache: NumberToRecipient +} + +const mapStateToProps = (state: RootState): StateProps => ({ + e164PhoneNumberAddressMapping: e164NumberToAddressSelector(state), + addressToE164Number: addressToE164NumberSelector(state), + recipientCache: recipientCacheSelector(state), +}) + +// Payment Request notification for the notification center on home screen +export class IncomingPaymentRequestSummaryNotification extends React.Component { + getRequesterRecipient = (requesterE164Number: string) => { + return phoneNumberToRecipient( + requesterE164Number, + this.props.e164PhoneNumberAddressMapping[requesterE164Number], + this.props.recipientCache + ) + } + + onReview = () => { + CeloAnalytics.track(CustomEventNames.incoming_request_payment_review) + navigate(Stacks.IncomingRequestStack) + } + + itemRenderer = (item: PaymentRequest) => { + return ( + + ) + } + + render() { + const { recipientCache, requests, t } = this.props + + return requests.length === 1 ? ( + listItemRenderer({ + updatePaymentRequestStatus: this.props.updatePaymentRequestStatus, + recipientCache, + })(requests[0]) + ) : ( + + items={requests} + title={t('incomingPaymentRequests')} + icon={} + onReview={this.onReview} + itemRenderer={this.itemRenderer} + /> + ) + } +} + +const styles = StyleSheet.create({ + image: { + width: 40, + height: 40, + }, +}) + +export default connect( + mapStateToProps, + { updatePaymentRequestStatus } +)(withNamespaces(Namespaces.walletFlow5)(IncomingPaymentRequestSummaryNotification)) diff --git a/packages/mobile/src/paymentRequest/NotificationAmount.tsx b/packages/mobile/src/paymentRequest/NotificationAmount.tsx deleted file mode 100644 index d9748b8913d..00000000000 --- a/packages/mobile/src/paymentRequest/NotificationAmount.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import colors from '@celo/react-components/styles/colors' -import fontStyles from '@celo/react-components/styles/fonts' -import BigNumber from 'bignumber.js' -import * as React from 'react' -import { StyleSheet, Text, View } from 'react-native' -import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' -import { divideByWei, getCentAwareMoneyDisplay } from 'src/utils/formatting' - -interface Props { - amount: BigNumber.Value -} - -export default class NotificationAmount extends React.PureComponent { - render() { - return ( - - - {CURRENCIES[CURRENCY_ENUM.DOLLAR].symbol + - getCentAwareMoneyDisplay(divideByWei(this.props.amount))} - - - ) - } -} - -const styles = StyleSheet.create({ - amount: { - color: colors.darkSecondary, - }, -}) diff --git a/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListItem.tsx b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListItem.tsx index 1a90b7dec72..eb0c1386099 100644 --- a/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListItem.tsx +++ b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListItem.tsx @@ -2,20 +2,19 @@ import BaseNotification from '@celo/react-components/components/BaseNotification import ContactCircle from '@celo/react-components/components/ContactCircle' import colors from '@celo/react-components/styles/colors' import fontStyles from '@celo/react-components/styles/fonts' -import variables from '@celo/react-components/styles/variables' import * as React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { StyleSheet, Text, View } from 'react-native' +import { Image, StyleSheet, Text, View } from 'react-native' import { PaymentRequestStatus } from 'src/account/types' import CeloAnalytics from 'src/analytics/CeloAnalytics' import { CustomEventNames } from 'src/analytics/constants' import { updatePaymentRequestNotified, updatePaymentRequestStatus } from 'src/firebase/actions' +import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' import { Namespaces } from 'src/i18n' -import { navigate } from 'src/navigator/NavigationService' -import { Screens } from 'src/navigator/Screens' -import NotificationAmount from 'src/paymentRequest/NotificationAmount' +import { unknownUserIcon } from 'src/images/Images' import { getRecipientThumbnail, Recipient } from 'src/recipients/recipient' -import { multiplyByWei } from 'src/utils/formatting' +import { getCentAwareMoneyDisplay } from 'src/utils/formatting' +import Logger from 'src/utils/Logger' interface OwnProps { requester: Recipient @@ -26,14 +25,16 @@ interface OwnProps { updatePaymentRequestNotified: typeof updatePaymentRequestNotified } +const AVATAR_SIZE = 40 + type Props = OwnProps & WithNamespaces export class OutgoingPaymentRequestListItem extends React.Component { onRemind = () => { - const { id } = this.props + const { id, t } = this.props this.props.updatePaymentRequestNotified(id.toString(), false) CeloAnalytics.track(CustomEventNames.outgoing_request_payment_remind) - this.onFinalized() + Logger.showMessage(t('sendFlow7:requestSent')) } onCancel = () => { @@ -42,18 +43,14 @@ export class OutgoingPaymentRequestListItem extends React.Component { CeloAnalytics.track(CustomEventNames.outgoing_request_payment_cancel) } - onFinalized = () => { - navigate(Screens.OutgoingPaymentRequestListScreen) - } - getCTA = () => { return [ { - text: this.props.t('remind'), + text: this.props.t('global:remind'), onPress: this.onRemind, }, { - text: this.props.t('cancel'), + text: this.props.t('global:cancel'), onPress: this.onCancel, }, ] @@ -64,42 +61,47 @@ export class OutgoingPaymentRequestListItem extends React.Component { } render() { - const { requester } = this.props + const { requester, t } = this.props return ( - - } - title={requester.displayName} - ctas={this.getCTA()} - roundedBorders={false} - callout={} - > - - {this.isDisplayingNumber() && ( - - {this.props.requester.displayId} - - )} - {this.props.comment} - - + + + + + } + title={t('outgoingPaymentRequestNotificationTitle', { + name: requester.displayName, + amount: + CURRENCIES[CURRENCY_ENUM.DOLLAR].symbol + getCentAwareMoneyDisplay(this.props.amount), + })} + ctas={this.getCTA()} + > + {this.props.comment || t('defaultComment')} + + ) } } const styles = StyleSheet.create({ - comment: { - paddingTop: variables.contentPadding, - }, phoneNumber: { color: colors.dark, }, + container: { + marginBottom: 16, + }, + unknownUser: { + height: AVATAR_SIZE, + width: AVATAR_SIZE, + justifyContent: 'center', + alignItems: 'center', + }, }) -export default withNamespaces(Namespaces.global)(OutgoingPaymentRequestListItem) +export default withNamespaces(Namespaces.paymentRequestFlow)(OutgoingPaymentRequestListItem) diff --git a/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.test.tsx b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.test.tsx index 3fc89e90531..4816c99a04d 100644 --- a/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.test.tsx +++ b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.test.tsx @@ -1,3 +1,4 @@ +import BigNumber from 'bignumber.js' import * as React from 'react' import 'react-native' import { Provider } from 'react-redux' @@ -5,8 +6,8 @@ import * as renderer from 'react-test-renderer' import { PaymentRequest } from 'src/account/types' import { paymentRequestDouble } from 'src/paymentRequest/__mocks__' import OutgoingPaymentRequestListScreen from 'src/paymentRequest/OutgoingPaymentRequestListScreen' -import { createMockStore } from 'test/utils' -import { mockAccount, mockE164Number } from 'test/values' +import { createMockNavigationProp, createMockStore } from 'test/utils' +import { mockAccount, mockE164Number, mockRecipient } from 'test/values' const requests = [ paymentRequestDouble({ @@ -29,6 +30,13 @@ const requests = [ }), ] +const navigation = createMockNavigationProp({ + recipient: mockRecipient, + recipientAddress: mockAccount, + amount: new BigNumber(10), + reason: 'My Reason', +}) + function testStore(outgoingPaymentRequests: PaymentRequest[]) { return createMockStore({ stableToken: { balance: '120' }, @@ -42,7 +50,7 @@ describe('OutgoingPaymentRequestListScreen', () => { const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() @@ -53,7 +61,7 @@ describe('OutgoingPaymentRequestListScreen', () => { const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() diff --git a/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.tsx b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.tsx index 9a55da1d062..236d8356965 100644 --- a/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.tsx +++ b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestListScreen.tsx @@ -1,10 +1,7 @@ -import colors from '@celo/react-components/styles/colors' -import { componentStyles } from '@celo/react-components/styles/styles' -import variables from '@celo/react-components/styles/variables' -import * as React from 'react' +import React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' -import { ScrollView, StyleSheet, View } from 'react-native' -import SafeAreaView from 'react-native-safe-area-view' +import { View } from 'react-native' +import { NavigationInjectedProps } from 'react-navigation' import { connect } from 'react-redux' import { getOutgoingPaymentRequests } from 'src/account/selectors' import { PaymentRequest } from 'src/account/types' @@ -12,17 +9,16 @@ import { updatePaymentRequestNotified, updatePaymentRequestStatus } from 'src/fi import i18n, { Namespaces } from 'src/i18n' import { fetchPhoneAddresses } from 'src/identity/actions' import { e164NumberToAddressSelector, E164NumberToAddressType } from 'src/identity/reducer' -import { headerWithBackButton } from 'src/navigator/Headers' +import { + NotificationList, + titleWithBalanceNavigationOptions, + useBalanceInNavigationParam, +} from 'src/notifications/NotificationList' import OutgoingPaymentRequestListItem from 'src/paymentRequest/OutgoingPaymentRequestListItem' -import PaymentRequestBalance from 'src/paymentRequest/PaymentRequestBalance' -import PaymentRequestListEmpty from 'src/paymentRequest/PaymentRequestListEmpty' import { getRecipientFromPaymentRequest } from 'src/paymentRequest/utils' import { NumberToRecipient } from 'src/recipients/recipient' import { recipientCacheSelector } from 'src/recipients/reducer' import { RootState } from 'src/redux/reducers' -import DisconnectBanner from 'src/shared/DisconnectBanner' - -const { contentPadding } = variables interface StateProps { dollarBalance: string | null @@ -44,66 +40,43 @@ const mapStateToProps = (state: RootState): StateProps => ({ recipientCache: recipientCacheSelector(state), }) -type Props = WithNamespaces & StateProps & DispatchProps - -export class OutgoingPaymentRequestListScreen extends React.Component { - static navigationOptions = () => ({ - ...headerWithBackButton, - headerTitle: i18n.t('paymentRequestFlow:outgoingPaymentRequests'), - }) - - renderRequest = (request: PaymentRequest, key: number, allRequests: PaymentRequest[]) => { - const { recipientCache } = this.props - const requester = getRecipientFromPaymentRequest(request, recipientCache) +type Props = NavigationInjectedProps & WithNamespaces & StateProps & DispatchProps - return ( - - - {key < allRequests.length - 1 && } - - ) - } +export const listItemRenderer = (params: { + recipientCache: NumberToRecipient + updatePaymentRequestStatus: typeof updatePaymentRequestStatus + updatePaymentRequestNotified: typeof updatePaymentRequestNotified +}) => (request: PaymentRequest, key: number | undefined = undefined) => { + const requester = getRecipientFromPaymentRequest(request, params.recipientCache) + return ( + + + + ) +} - render() { - return ( - - - - {this.props.paymentRequests.length > 0 ? ( - - - {this.props.paymentRequests.map(this.renderRequest)} - - - ) : ( - - )} - - ) - } +const OutgoingPaymentRequestListScreen = (props: Props) => { + const { dollarBalance, navigation } = props + useBalanceInNavigationParam(dollarBalance, navigation) + return ( + + ) } -const styles = StyleSheet.create({ - container: { - backgroundColor: colors.background, - flex: 1, - }, - separator: { - borderBottomColor: colors.darkLightest, - borderBottomWidth: 1, - marginLeft: 50, - }, - scrollArea: { - margin: contentPadding, - }, -}) +OutgoingPaymentRequestListScreen.navigationOptions = titleWithBalanceNavigationOptions( + i18n.t('walletFlow5:outgoingPaymentRequests') +) export default connect( mapStateToProps, diff --git a/packages/mobile/src/notifications/OutgoingPaymentRequestSummaryNotification.test.tsx b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestSummaryNotification.test.tsx similarity index 95% rename from packages/mobile/src/notifications/OutgoingPaymentRequestSummaryNotification.test.tsx rename to packages/mobile/src/paymentRequest/OutgoingPaymentRequestSummaryNotification.test.tsx index 69a70a2d610..86eae3550f6 100644 --- a/packages/mobile/src/notifications/OutgoingPaymentRequestSummaryNotification.test.tsx +++ b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestSummaryNotification.test.tsx @@ -4,7 +4,7 @@ import { Provider } from 'react-redux' import * as renderer from 'react-test-renderer' import { PaymentRequestStatus } from 'src/account/types' import { SHORT_CURRENCIES } from 'src/geth/consts' -import OutgoingPaymentRequestSummaryNotification from 'src/notifications/OutgoingPaymentRequestSummaryNotification' +import OutgoingPaymentRequestSummaryNotification from 'src/paymentRequest/OutgoingPaymentRequestSummaryNotification' import { createMockStore } from 'test/utils' const requesterE164Number = '+491522345678' diff --git a/packages/mobile/src/paymentRequest/OutgoingPaymentRequestSummaryNotification.tsx b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestSummaryNotification.tsx new file mode 100644 index 00000000000..12eef3f50d8 --- /dev/null +++ b/packages/mobile/src/paymentRequest/OutgoingPaymentRequestSummaryNotification.tsx @@ -0,0 +1,108 @@ +import * as React from 'react' +import { WithNamespaces, withNamespaces } from 'react-i18next' +import { Image, StyleSheet } from 'react-native' +import { connect } from 'react-redux' +import { PaymentRequest } from 'src/account/types' +import CeloAnalytics from 'src/analytics/CeloAnalytics' +import { CustomEventNames } from 'src/analytics/constants' +import { updatePaymentRequestNotified, updatePaymentRequestStatus } from 'src/firebase/actions' +import { Namespaces } from 'src/i18n' +import { + addressToE164NumberSelector, + AddressToE164NumberType, + e164NumberToAddressSelector, + E164NumberToAddressType, +} from 'src/identity/reducer' +import { sendDollar } from 'src/images/Images' +import { navigate } from 'src/navigator/NavigationService' +import { Stacks } from 'src/navigator/Screens' +import SummaryNotification from 'src/notifications/SummaryNotification' +import { listItemRenderer } from 'src/paymentRequest/OutgoingPaymentRequestListScreen' +import PaymentRequestNotificationInner from 'src/paymentRequest/PaymentRequestNotificationInner' +import { NumberToRecipient, phoneNumberToRecipient } from 'src/recipients/recipient' +import { recipientCacheSelector } from 'src/recipients/reducer' +import { RootState } from 'src/redux/reducers' + +interface OwnProps { + requests: PaymentRequest[] +} + +interface DispatchProps { + updatePaymentRequestStatus: typeof updatePaymentRequestStatus + updatePaymentRequestNotified: typeof updatePaymentRequestNotified +} + +type Props = OwnProps & DispatchProps & WithNamespaces & StateProps + +interface StateProps { + e164PhoneNumberAddressMapping: E164NumberToAddressType + addressToE164Number: AddressToE164NumberType + recipientCache: NumberToRecipient +} + +const mapStateToProps = (state: RootState): StateProps => ({ + e164PhoneNumberAddressMapping: e164NumberToAddressSelector(state), + addressToE164Number: addressToE164NumberSelector(state), + recipientCache: recipientCacheSelector(state), +}) + +// Payment Request notification for the notification center on home screen +export class OutgoingPaymentRequestSummaryNotification extends React.Component { + onReview = () => { + CeloAnalytics.track(CustomEventNames.outgoing_request_payment_review) + navigate(Stacks.OutgoingRequestStack) + } + + getRequesterRecipient = (requesterE164Number: string) => { + return phoneNumberToRecipient( + requesterE164Number, + this.props.e164PhoneNumberAddressMapping[requesterE164Number], + this.props.recipientCache + ) + } + + itemRenderer = (item: PaymentRequest) => { + return ( + + ) + } + + render() { + const { recipientCache, requests, t } = this.props + return requests.length === 1 ? ( + listItemRenderer({ + updatePaymentRequestStatus: this.props.updatePaymentRequestStatus, + updatePaymentRequestNotified: this.props.updatePaymentRequestNotified, + recipientCache, + })(requests[0]) + ) : ( + + items={requests} + title={t('outgoingPaymentRequests')} + icon={} + onReview={this.onReview} + itemRenderer={this.itemRenderer} + /> + ) + } +} + +const styles = StyleSheet.create({ + image: { + width: 40, + height: 40, + }, +}) + +export default connect( + mapStateToProps, + { + updatePaymentRequestStatus, + updatePaymentRequestNotified, + } +)(withNamespaces(Namespaces.walletFlow5)(OutgoingPaymentRequestSummaryNotification)) diff --git a/packages/mobile/src/paymentRequest/PaymentRequestBalance.tsx b/packages/mobile/src/paymentRequest/PaymentRequestBalance.tsx deleted file mode 100644 index 1ec709a2e06..00000000000 --- a/packages/mobile/src/paymentRequest/PaymentRequestBalance.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import colors from '@celo/react-components/styles/colors' -import fontStyles from '@celo/react-components/styles/fonts' -import variables from '@celo/react-components/styles/variables' -import BigNumber from 'bignumber.js' -import * as React from 'react' -import { WithNamespaces, withNamespaces } from 'react-i18next' -import { StyleSheet, Text, View } from 'react-native' -import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' -import { Namespaces } from 'src/i18n' -import CeloAccountIcon from 'src/icons/CeloAccountIcon' -import { getCentAwareMoneyDisplay } from 'src/utils/formatting' - -const { contentPadding } = variables - -interface Props { - dollarBalance: BigNumber | string | null -} - -class PaymentRequestBalance extends React.PureComponent { - render() { - return ( - - - - {this.props.t('celoDollarBalance')} - - {CURRENCIES[CURRENCY_ENUM.DOLLAR].symbol + - getCentAwareMoneyDisplay(this.props.dollarBalance || 0)} - - - - ) - } -} - -const styles = StyleSheet.create({ - balanceContainer: { - flexDirection: 'row', - alignItems: 'center', - padding: contentPadding, - flex: 0, - }, - balance: { - paddingStart: contentPadding, - flexDirection: 'row', - justifyContent: 'space-between', - flex: 1, - }, - balanceText: { - ...fontStyles.bodySmallSemiBold, - color: colors.celoGreen, - }, -}) -export default withNamespaces(Namespaces.paymentRequestFlow)(PaymentRequestBalance) diff --git a/packages/mobile/src/paymentRequest/PaymentRequestListEmpty.tsx b/packages/mobile/src/paymentRequest/PaymentRequestListEmpty.tsx deleted file mode 100644 index ffcd1e14562..00000000000 --- a/packages/mobile/src/paymentRequest/PaymentRequestListEmpty.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import fontStyles from '@celo/react-components/styles/fonts' -import * as React from 'react' -import { WithNamespaces, withNamespaces } from 'react-i18next' -import { StyleSheet, Text } from 'react-native' -import { Namespaces } from 'src/i18n' - -function PaymentRequestListEmpty(props: WithNamespaces) { - return {props.t('empty')} -} - -const styles = StyleSheet.create({ - empty: { - textAlign: 'center', - marginTop: 30, - }, -}) -export default withNamespaces(Namespaces.paymentRequestFlow)(PaymentRequestListEmpty) diff --git a/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.test.tsx b/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.test.tsx index dc65638cd21..4587cce8d57 100644 --- a/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.test.tsx +++ b/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.test.tsx @@ -8,7 +8,6 @@ it('renders correctly', () => { ) diff --git a/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.tsx b/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.tsx index a209bc9536b..9bffff77ca6 100644 --- a/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.tsx +++ b/packages/mobile/src/paymentRequest/PaymentRequestNotificationInner.tsx @@ -1,27 +1,33 @@ import fontStyles from '@celo/react-components/styles/fonts' import * as React from 'react' +import { Trans, withNamespaces, WithNamespaces } from 'react-i18next' import { StyleSheet, Text } from 'react-native' import { CURRENCIES, CURRENCY_ENUM } from 'src/geth/consts' +import { Namespaces } from 'src/i18n' import { Recipient } from 'src/recipients/recipient' import { getCentAwareMoneyDisplay } from 'src/utils/formatting' interface Props { requesterE164Number: string - comment: string amount: string requesterRecipient: Recipient | null } -export default function PaymentRequestNotificationInner(props: Props) { - const { requesterE164Number, comment: message, amount, requesterRecipient } = props +function PaymentRequestNotificationInner(props: Props & WithNamespaces) { + const { requesterE164Number, amount, requesterRecipient } = props + const displayName = (requesterRecipient && requesterRecipient.displayName) || requesterE164Number return ( - - {(requesterRecipient && requesterRecipient.displayName) || requesterE164Number} - {message} - - - {' ' + CURRENCIES[CURRENCY_ENUM.DOLLAR].symbol + getCentAwareMoneyDisplay(amount)} - + + {{ displayName }} for + {{ amount }} + ) } @@ -31,3 +37,5 @@ const styles = StyleSheet.create({ flexDirection: 'row', }, }) + +export default withNamespaces(Namespaces.paymentRequestFlow)(PaymentRequestNotificationInner) diff --git a/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListItem.test.tsx.snap b/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListItem.test.tsx.snap index f7a8102a3e9..d7bd9e5d8f0 100644 --- a/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListItem.test.tsx.snap +++ b/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListItem.test.tsx.snap @@ -2,54 +2,59 @@ exports[`IncomingPaymentRequestListItem renders correctly 1`] = ` - - 5 - + + - - - - 5126608970 - - + + incomingPaymentRequestNotificationTitle + - - - Hey thanks for the loan, Ill pay you back ASAP. LOVE YOU - - + } + > + Hey thanks for the loan, Ill pay you back ASAP. LOVE YOU + @@ -176,7 +185,7 @@ exports[`IncomingPaymentRequestListItem renders correctly 1`] = ` ] } > - pay + global:pay - decline + global:decline - - - - $24 - - - `; diff --git a/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListScreen.test.tsx.snap b/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListScreen.test.tsx.snap index 679bac25aa9..e4b4832edd9 100644 --- a/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListScreen.test.tsx.snap +++ b/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestListScreen.test.tsx.snap @@ -9,66 +9,6 @@ exports[`IncomingPaymentRequestListScreen renders correctly with no requests 1`] } } > - - - - - celoDollarBalance - - - $120 - - - - empty + global:emptyList `; @@ -99,87 +39,32 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = } } > - - - - - celoDollarBalance - - - $120 - - - - + @@ -210,7 +100,6 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = style={ Object { "alignItems": "center", - "flexDirection": "column", "paddingRight": 16, } } @@ -236,29 +125,28 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = }, Object { "backgroundColor": "#7AD6FE", - "borderRadius": 15, - "height": 30, - "width": 30, + "borderRadius": 20, + "height": 40, + "width": 40, }, ] } > - - + - + /> @@ -273,186 +161,139 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = - +1555-867-5309 + incomingPaymentRequestNotificationTitle - + + + Just the best + - + + > + global:pay + + + - Just the best + global:decline - - - - pay - - - - - decline - - - - - - - $20 - - - - - + @@ -483,7 +329,6 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = style={ Object { "alignItems": "center", - "flexDirection": "column", "paddingRight": 16, } } @@ -509,29 +354,28 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = }, Object { "backgroundColor": "#7AD6FE", - "borderRadius": 15, - "height": 30, - "width": 30, + "borderRadius": 20, + "height": 40, + "width": 40, }, ] } > - - + - + /> @@ -546,186 +390,139 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = - +14155550000 + incomingPaymentRequestNotificationTitle - + + + Just the best for the best. Thanos & Zeus Gods of ultimate Power + - + + > + global:pay + + + - Just the best for the best. Thanos & Zeus Gods of ultimate Power + global:decline - - - - pay - - - - - decline - - - - - - - $102 - - - - - + @@ -756,7 +558,6 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = style={ Object { "alignItems": "center", - "flexDirection": "column", "paddingRight": 16, } } @@ -782,29 +583,28 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = }, Object { "backgroundColor": "#7AD6FE", - "borderRadius": 15, - "height": 30, - "width": 30, + "borderRadius": 20, + "height": 40, + "width": 40, }, ] } > - - + - + /> @@ -819,169 +619,119 @@ exports[`IncomingPaymentRequestListScreen renders correctly with requests 1`] = - +14155550000 + incomingPaymentRequestNotificationTitle - + + + Just the best but less + - + + > + global:pay + + + - Just the best but less + global:decline - - - - pay - - - - - decline - - - - - - - $1 - - - diff --git a/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestSummaryNotification.test.tsx.snap b/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestSummaryNotification.test.tsx.snap new file mode 100644 index 00000000000..1bbe103e03d --- /dev/null +++ b/packages/mobile/src/paymentRequest/__snapshots__/IncomingPaymentRequestSummaryNotification.test.tsx.snap @@ -0,0 +1,631 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`IncomingPaymentRequestSummaryNotification renders correctly 1`] = ` + + + + + + + + incomingPaymentRequests + + + + + + + +491522345678 + for + + + 200000.00 + + + + + global:moreWithCount + + + + + + + + walletFlow5:review + + + + + + + +`; + +exports[`IncomingPaymentRequestSummaryNotification when more 1 requests renders just it alone 1`] = ` + + + + + + + + + + + + + incomingPaymentRequestNotificationTitle + + + + Dinner for me and the gals, PIZZAA! + + + + + global:pay + + + + + global:decline + + + + + + + + +`; + +exports[`IncomingPaymentRequestSummaryNotification when more than 2 requests renders just two 1`] = ` + + + + + + + + incomingPaymentRequests + + + + + + + +491522345678 + for + + + 200000.00 + + + + + global:moreWithCount + + + + + + + + walletFlow5:review + + + + + + + +`; diff --git a/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListItem.test.tsx.snap b/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListItem.test.tsx.snap index 3bae290eae1..98b9287e8a0 100644 --- a/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListItem.test.tsx.snap +++ b/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListItem.test.tsx.snap @@ -3,231 +3,214 @@ exports[`OutgoingPaymentRequestListItem renders correctly 1`] = ` - + - - 5 - - - - - - - 5126608970 - - - - - - Hey thanks for the loan, Ill pay you back ASAP. LOVE YOU - + + + + + + outgoingPaymentRequestNotificationTitle + - - - remind - - + Hey thanks for the loan, Ill pay you back ASAP. LOVE YOU + - - cancel - + + global:remind + + + + + global:cancel + + - - - - $24 - - - `; diff --git a/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListScreen.test.tsx.snap b/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListScreen.test.tsx.snap index 1136356eb0b..28b2a269dc6 100644 --- a/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListScreen.test.tsx.snap +++ b/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestListScreen.test.tsx.snap @@ -9,66 +9,6 @@ exports[`OutgoingPaymentRequestListScreen renders correctly with no requests 1`] } } > - - - - - celoDollarBalance - - - $120 - - - - empty + global:emptyList `; @@ -99,836 +39,655 @@ exports[`OutgoingPaymentRequestListScreen renders correctly with requests 1`] = } } > - - - - - celoDollarBalance - - - $120 - - - - + - - + - - - - - - - +1555-867-5309 - - - - - - + - Just the best - + "alignItems": "center", + "height": 40, + "justifyContent": "center", + "width": 40, + } + } + /> + + + + + outgoingPaymentRequestNotificationTitle + - - - remind - - + Just the best + - + + global:remind + + + - cancel - + + global:cancel + + - - - - $20 - - - - - + - - + - - - - - - - +14155550000 - - - - - - + - Just the best for the best. Thanos & Zeus Gods of ultimate Power - + "alignItems": "center", + "height": 40, + "justifyContent": "center", + "width": 40, + } + } + /> + + + + + outgoingPaymentRequestNotificationTitle + - - - remind - - + Just the best for the best. Thanos & Zeus Gods of ultimate Power + - + + global:remind + + + - cancel - + + global:cancel + + - - - - $102 - - - - - + - - + - - - - - - - +14155550000 - - - - - - + - Just the best but less - + "alignItems": "center", + "height": 40, + "justifyContent": "center", + "width": 40, + } + } + /> + + + + + outgoingPaymentRequestNotificationTitle + - - - remind - - + Just the best but less + - - cancel - + + global:remind + + + + + global:cancel + + - - - - $1 - - - diff --git a/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestSummaryNotification.test.tsx.snap b/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestSummaryNotification.test.tsx.snap new file mode 100644 index 00000000000..c24102a55ec --- /dev/null +++ b/packages/mobile/src/paymentRequest/__snapshots__/OutgoingPaymentRequestSummaryNotification.test.tsx.snap @@ -0,0 +1,616 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OutgoingPaymentRequestSummaryNotification renders correctly 1`] = ` + + + + + + + + outgoingPaymentRequests + + + + + + + +491522345678 + for + + + 200000.00 + + + + + global:moreWithCount + + + + + + + + walletFlow5:review + + + + + + + +`; + +exports[`OutgoingPaymentRequestSummaryNotification when more 1 requests renders just it alone 1`] = ` + + + + + + + + + + + + + + outgoingPaymentRequestNotificationTitle + + + + Dinner for me and the gals, PIZZAA! + + + + + global:remind + + + + + global:cancel + + + + + + + + + +`; + +exports[`OutgoingPaymentRequestSummaryNotification when more than 2 requests renders just two 1`] = ` + + + + + + + + outgoingPaymentRequests + + + + + + + +491522345678 + for + + + 200000.00 + + + + + global:moreWithCount + + + + + + + + walletFlow5:review + + + + + + + +`; diff --git a/packages/mobile/src/paymentRequest/__snapshots__/PaymentRequestNotificationInner.test.tsx.snap b/packages/mobile/src/paymentRequest/__snapshots__/PaymentRequestNotificationInner.test.tsx.snap index 460680a6dab..b12b5f98459 100644 --- a/packages/mobile/src/paymentRequest/__snapshots__/PaymentRequestNotificationInner.test.tsx.snap +++ b/packages/mobile/src/paymentRequest/__snapshots__/PaymentRequestNotificationInner.test.tsx.snap @@ -12,19 +12,16 @@ exports[`renders correctly 1`] = ` > +14155552671 - - - Hey thanks for the loan, Ill pay you back ASAP. LOVE YOU + for - $24 + 24 `; diff --git a/packages/mobile/src/send/Fee.tsx b/packages/mobile/src/send/Fee.tsx index 5d5f2f25216..38df6188d2d 100644 --- a/packages/mobile/src/send/Fee.tsx +++ b/packages/mobile/src/send/Fee.tsx @@ -3,6 +3,7 @@ import BigNumber from 'bignumber.js' import * as React from 'react' import { withNamespaces, WithNamespaces } from 'react-i18next' import { StyleSheet, Text, View } from 'react-native' +import { Namespaces } from 'src/i18n' import { getMoneyDisplayValue } from 'src/utils/formatting' interface Props { @@ -26,4 +27,4 @@ const style = StyleSheet.create({ }, }) -export default withNamespaces('sendFlow7')(Fee) +export default withNamespaces(Namespaces.sendFlow7)(Fee) diff --git a/packages/mobile/src/send/FeeEducation.tsx b/packages/mobile/src/send/FeeEducation.tsx index 83538daf4ea..59db6b581b7 100644 --- a/packages/mobile/src/send/FeeEducation.tsx +++ b/packages/mobile/src/send/FeeEducation.tsx @@ -5,6 +5,7 @@ import * as React from 'react' import { withNamespaces, WithNamespaces } from 'react-i18next' import { Image, StyleSheet, Text, View } from 'react-native' import componentWithAnalytics from 'src/analytics/wrapper' +import { Namespaces } from 'src/i18n' import { sendFee } from 'src/images/Images' import { navigateBack } from 'src/navigator/NavigationService' @@ -55,4 +56,4 @@ const styles = StyleSheet.create({ }, }) -export default componentWithAnalytics(withNamespaces('sendFlow7')(FeeEducation)) +export default componentWithAnalytics(withNamespaces(Namespaces.sendFlow7)(FeeEducation)) diff --git a/packages/mobile/src/send/SendAmount.tsx b/packages/mobile/src/send/SendAmount.tsx index b5ad0af8fae..e4dcca3ad7b 100644 --- a/packages/mobile/src/send/SendAmount.tsx +++ b/packages/mobile/src/send/SendAmount.tsx @@ -404,7 +404,7 @@ export class SendAmount extends React.Component { lng={this.props.lng} /> { if (confirmationInput === '') { throw new Error('Confirmation input missing') } + confirmationInput.amount = new BigNumber(confirmationInput.amount) return confirmationInput } @@ -128,9 +129,8 @@ class SendConfirmation extends React.Component { const { onCancel } = this.getNavParams() if (onCancel) { onCancel() - } else { - navigateBack() } + navigateBack() } renderHeader = () => { diff --git a/packages/mobile/src/send/__snapshots__/SendAmount.test.tsx.snap b/packages/mobile/src/send/__snapshots__/SendAmount.test.tsx.snap index 5083af6303d..1b10e9f3866 100644 --- a/packages/mobile/src/send/__snapshots__/SendAmount.test.tsx.snap +++ b/packages/mobile/src/send/__snapshots__/SendAmount.test.tsx.snap @@ -327,7 +327,7 @@ exports[`SendAmount renders correctly for request payment confirmation 1`] = ` ] } > - for + global:for diff --git a/packages/mobile/src/send/saga.ts b/packages/mobile/src/send/saga.ts index 70ed086f169..a7e600d3f6c 100644 --- a/packages/mobile/src/send/saga.ts +++ b/packages/mobile/src/send/saga.ts @@ -42,7 +42,7 @@ export async function getSendTxGas( const tokenContract = await contractGetter(web3) const txParams = { from: account, feeCurrency: tokenContract._address } const gas = new BigNumber(await tx.estimateGas(txParams)) - Logger.debug(`${TAG}/getSendTxGas`, `Estimated gas of ${gas.toString()}}`) + Logger.debug(`${TAG}/getSendTxGas`, `Estimated gas of ${gas.toString()}`) return gas } diff --git a/packages/mobile/src/set-clock/SetClock.tsx b/packages/mobile/src/set-clock/SetClock.tsx index 4a3bf711852..910df788fa7 100644 --- a/packages/mobile/src/set-clock/SetClock.tsx +++ b/packages/mobile/src/set-clock/SetClock.tsx @@ -5,18 +5,25 @@ import colors from '@celo/react-components/styles/colors' import { fontStyles } from '@celo/react-components/styles/fonts' import * as React from 'react' import { withNamespaces, WithNamespaces } from 'react-i18next' -import { Image, StyleSheet, Text, View } from 'react-native' +import { Image, Platform, StyleSheet, Text, View } from 'react-native' import * as AndroidOpenSettings from 'react-native-android-open-settings' import { componentWithAnalytics } from 'src/analytics/wrapper' import { Namespaces } from 'src/i18n' import clockIcon from 'src/images/clock-icon.png' +import { navigate } from 'src/navigator/NavigationService' +import { Screens } from 'src/navigator/Screens' import { getLocalTimezone, getRemoteTime } from 'src/utils/time' export class SetClock extends React.Component { static navigationOptions = { header: null } goToSettings = () => { - return AndroidOpenSettings.dateSettings() + if (Platform.OS === 'android') { + return AndroidOpenSettings.dateSettings() + } else { + // TODO: Implement Date Setting on iOS + navigate(Screens.WalletHome) + } } render() { diff --git a/packages/mobile/src/transactions/NoActivity.tsx b/packages/mobile/src/transactions/NoActivity.tsx index 77a1be54c1b..c2f86823493 100644 --- a/packages/mobile/src/transactions/NoActivity.tsx +++ b/packages/mobile/src/transactions/NoActivity.tsx @@ -5,6 +5,7 @@ import { ApolloError } from 'apollo-boost' import * as React from 'react' import { withNamespaces, WithNamespaces } from 'react-i18next' import { ActivityIndicator, Image, StyleSheet, Text, View } from 'react-native' +import { Namespaces } from 'src/i18n' import { exchangeIcon, shinyDollar } from 'src/images/Images' import { navigate } from 'src/navigator/NavigationService' import { Stacks } from 'src/navigator/Screens' @@ -94,4 +95,4 @@ const styles = StyleSheet.create({ }, }) -export default withNamespaces('walletFlow5')(NoActivity) +export default withNamespaces(Namespaces.walletFlow5)(NoActivity) diff --git a/packages/mobile/src/transactions/TransferFeedIcon.tsx b/packages/mobile/src/transactions/TransferFeedIcon.tsx index 433b4a6b42c..e9b7a9cd4fe 100644 --- a/packages/mobile/src/transactions/TransferFeedIcon.tsx +++ b/packages/mobile/src/transactions/TransferFeedIcon.tsx @@ -6,7 +6,7 @@ import { coinsIcon, unknownUserIcon } from 'src/images/Images' import { getRecipientThumbnail, Recipient } from 'src/recipients/recipient' import { TransactionTypes } from 'src/transactions/reducer' -const avatarSize = 40 +const AVATAR_SIZE = 40 interface Props { type: TransactionTypes @@ -40,7 +40,7 @@ export default function TransferFeedIcon(props: Props) { return ( {} @@ -52,8 +52,8 @@ export default function TransferFeedIcon(props: Props) { const styles = StyleSheet.create({ image: { - height: avatarSize, - width: avatarSize, + height: AVATAR_SIZE, + width: AVATAR_SIZE, justifyContent: 'center', alignItems: 'center', }, diff --git a/packages/mobile/src/web3/gas.ts b/packages/mobile/src/web3/gas.ts index d0494315078..a14605a4a14 100644 --- a/packages/mobile/src/web3/gas.ts +++ b/packages/mobile/src/web3/gas.ts @@ -11,7 +11,7 @@ let gasPrice: BigNumber | null = null let gasPriceLastUpdated: number | null = null export async function getGasPrice(currency: CURRENCY_ENUM = CURRENCY_ENUM.DOLLAR) { - Logger.debug(`${TAG}}/getGasPrice`, 'Getting gas price') + Logger.debug(`${TAG}/getGasPrice`, 'Getting gas price') try { if ( @@ -24,7 +24,7 @@ export async function getGasPrice(currency: CURRENCY_ENUM = CURRENCY_ENUM.DOLLAR } return gasPrice } catch (error) { - Logger.error(`${TAG}}/getGasPrice`, 'Could not fetch and update gas price.', error) + Logger.error(`${TAG}/getGasPrice`, 'Could not fetch and update gas price.', error) throw new Error('Error fetching gas price') } } diff --git a/packages/mobile/test/values.ts b/packages/mobile/test/values.ts index bf1f742b68d..a25fe41231b 100644 --- a/packages/mobile/test/values.ts +++ b/packages/mobile/test/values.ts @@ -160,4 +160,17 @@ export const mockPaymentRequests: PaymentRequest[] = [ notified: true, type: NotificationTypes.PAYMENT_REQUESTED, }, + { + uid: 'fas12fbs4fa141241', + amount: '12.34', + timestamp: new Date('2019-06-04T16:17:55.239Z'), + requesterAddress: mockAccount2, + requesterE164Number: mockE164Number, + requesteeAddress: mockAccount, + currency: SHORT_CURRENCIES.DOLLAR, + comment: mockComment, + status: PaymentRequestStatus.REQUESTED, + notified: true, + type: NotificationTypes.PAYMENT_REQUESTED, + }, ] diff --git a/packages/react-components/components/BaseListItem.tsx b/packages/react-components/components/BaseListItem.tsx deleted file mode 100644 index 505dcd53f37..00000000000 --- a/packages/react-components/components/BaseListItem.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import fontStyles from '@celo/react-components/styles/fonts' -import { componentStyles } from '@celo/react-components/styles/styles' -import variables from '@celo/react-components/styles/variables' -import * as React from 'react' -import { StyleSheet, Text, View } from 'react-native' - -const { contentPadding } = variables - -interface Props { - icon?: React.ReactNode - title: string - children: React.ReactNode - callout?: React.ReactNode - roundedBorders?: boolean -} - -// just used by notifications for now, useful for out pattern of [icon | title / body | optionalCol] -export default function BaseListItem({ icon, title, children, callout, roundedBorders }: Props) { - return ( - - {icon && {icon}} - - {title} - {children} - - {callout && {callout}} - - ) -} - -const styles = StyleSheet.create({ - container: { - padding: contentPadding, - flexDirection: 'row', - justifyContent: 'space-between', - width: '100%', - }, - iconArea: { - paddingRight: contentPadding, - flexDirection: 'column', - alignItems: 'center', - }, - contentArea: { - justifyContent: 'space-between', - flex: 1, - }, - callout: { - paddingLeft: contentPadding, - }, -}) diff --git a/packages/react-components/components/BaseNotification.tsx b/packages/react-components/components/BaseNotification.tsx index 44312409fac..e158571a6ee 100644 --- a/packages/react-components/components/BaseNotification.tsx +++ b/packages/react-components/components/BaseNotification.tsx @@ -1,15 +1,20 @@ -import BaseListItem from '@celo/react-components/components/BaseListItem' import TextButton from '@celo/react-components/components/TextButton' +import Touchable from '@celo/react-components/components/Touchable' +import colors from '@celo/react-components/styles/colors' +import fontStyles from '@celo/react-components/styles/fonts' +import { elevationShadowStyle } from '@celo/react-components/styles/styles' +import variables from '@celo/react-components/styles/variables' import * as React from 'react' -import { StyleSheet, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' + +const { contentPadding } = variables interface Props { icon?: React.ReactNode title: string children: React.ReactNode - callout?: React.ReactNode ctas: CTA[] - roundedBorders?: boolean + onPress?: () => unknown } export interface CTA { @@ -17,36 +22,59 @@ export interface CTA { text: string } -// For use in Notification Center and Payment Request Screen -export default function BaseNotification(props: Props) { +function Wrapper({ onPress, children }: { children: React.ReactNode; onPress?: () => unknown }) { + return onPress ? {children} : {children} +} + +export default function BaseNotification({ icon, title, children, ctas, onPress }: Props) { return ( - - - {props.children} - - {props.ctas.map((cta, j) => { - return ( - - {cta.text} - - ) - })} + + + {icon && {icon}} + + {title} + + {children} + + {ctas.map((cta, j) => ( + + {cta.text} + + ))} + + - + ) } const styles = StyleSheet.create({ ctas: { flexDirection: 'row', - marginTop: 15, + marginTop: 5, }, action: { paddingEnd: 15, }, body: { - minHeight: 70, + paddingTop: 8, + minHeight: 60, + justifyContent: 'space-between', + }, + container: { + padding: contentPadding, + flexDirection: 'row', + justifyContent: 'space-between', + width: '100%', + backgroundColor: colors.background, + }, + iconArea: { + paddingRight: contentPadding, + alignItems: 'center', + }, + contentArea: { justifyContent: 'space-between', + flex: 1, }, }) diff --git a/packages/react-components/components/SummaryNotification.test.tsx b/packages/react-components/components/SummaryNotification.test.tsx new file mode 100644 index 00000000000..65a3f7acf1f --- /dev/null +++ b/packages/react-components/components/SummaryNotification.test.tsx @@ -0,0 +1,40 @@ +import SummaryNotification from '@celo/react-components/components/SummaryNotification' +import { shallow } from 'enzyme' +import * as React from 'react' +import { Text } from 'react-native' +import * as renderer from 'react-test-renderer' + +const props = (onPress = jest.fn()) => ({ + text: 'Gold is where you can choose to store Celo dollars you have', + image: '', + title: 'Test', + reviewCTA: { text: 'it goes boom', onPress }, +}) + +describe(SummaryNotification, () => { + it('renders correctly', () => { + const tree = renderer.create( + + Test + + ) + expect(tree).toMatchSnapshot() + }) + describe('when ctas are pressed', () => { + it('calls the on press function', () => { + const clickHandler = jest.fn() + + const wrapper = shallow( + + Test + + ) + wrapper + .find('TextButton') + .first() + .simulate('press') + + expect(clickHandler).toHaveBeenCalled() + }) + }) +}) diff --git a/packages/react-components/components/SummaryNotification.tsx b/packages/react-components/components/SummaryNotification.tsx new file mode 100644 index 00000000000..8ac1fa64e0d --- /dev/null +++ b/packages/react-components/components/SummaryNotification.tsx @@ -0,0 +1,81 @@ +import TextButton from '@celo/react-components/components/TextButton' +import colors from '@celo/react-components/styles/colors' +import fontStyles from '@celo/react-components/styles/fonts' +import { elevationShadowStyle } from '@celo/react-components/styles/styles' +import variables from '@celo/react-components/styles/variables' +import * as React from 'react' +import { StyleSheet, Text, TouchableOpacity, View } from 'react-native' + +const { contentPadding } = variables + +interface Props { + icon?: React.ReactNode + title: string + children: React.ReactNode + reviewCTA: CTA + onPress?: () => unknown +} + +export interface CTA { + onPress: () => unknown + text: string +} + +function Wrapper({ onPress, children }: { children: React.ReactNode; onPress?: () => unknown }) { + return onPress ? ( + {children} + ) : ( + {children} + ) +} + +export default function SummaryNotification({ icon, title, children, reviewCTA, onPress }: Props) { + return ( + + + {icon && {icon}} + + {title} + + {children} + + + {reviewCTA.text} + + + + + + + ) +} + +const styles = StyleSheet.create({ + ctas: { + flexDirection: 'row', + marginTop: 5, + }, + action: { + paddingEnd: 15, + }, + body: { + minHeight: 60, + justifyContent: 'space-between', + }, + container: { + padding: contentPadding, + flexDirection: 'row', + justifyContent: 'space-between', + width: '100%', + backgroundColor: colors.background, + }, + iconArea: { + paddingRight: contentPadding, + flexDirection: 'column', + alignItems: 'center', + }, + contentArea: { + justifyContent: 'space-between', + flex: 1, + }, +}) diff --git a/packages/react-components/components/__snapshots__/BaseNotification.test.tsx.snap b/packages/react-components/components/__snapshots__/BaseNotification.test.tsx.snap index d9d0c4ce4d9..06566f1fa26 100644 --- a/packages/react-components/components/__snapshots__/BaseNotification.test.tsx.snap +++ b/packages/react-components/components/__snapshots__/BaseNotification.test.tsx.snap @@ -1,45 +1,56 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`BaseNotification renders correctly 1`] = ` - + - - Test - - + + Test + @@ -50,7 +61,7 @@ exports[`BaseNotification renders correctly 1`] = ` style={ Object { "flexDirection": "row", - "marginTop": 15, + "marginTop": 5, } } > diff --git a/packages/react-components/components/__snapshots__/SummaryNotification.test.tsx.snap b/packages/react-components/components/__snapshots__/SummaryNotification.test.tsx.snap new file mode 100644 index 00000000000..12e835415ed --- /dev/null +++ b/packages/react-components/components/__snapshots__/SummaryNotification.test.tsx.snap @@ -0,0 +1,108 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SummaryNotification renders correctly 1`] = ` + + + + + Test + + + + Test + + + + + it goes boom + + + + + + + +`; diff --git a/packages/react-components/styles/fonts.tsx b/packages/react-components/styles/fonts.tsx index ad603c51f15..7de93d8052c 100644 --- a/packages/react-components/styles/fonts.tsx +++ b/packages/react-components/styles/fonts.tsx @@ -82,6 +82,12 @@ export const fontStyles = StyleSheet.create({ fontFamily: HindSilguri.Regular, color: colors.dark, }, + bodySmallSecondary: { + fontSize: 14, + lineHeight: 18, + fontFamily: HindSilguri.Regular, + color: colors.darkSecondary, + }, bodySmallBold: { fontSize: 14, lineHeight: 18, @@ -158,7 +164,7 @@ export const fontStyles = StyleSheet.create({ }, headerTitle: { fontSize: 14, - fontFamily: HindSilguri.Medium, + fontFamily: HindSilguri.Bold, color: colors.dark, }, headerButton: { diff --git a/packages/react-components/styles/styles.ts b/packages/react-components/styles/styles.ts index 96fae2f4993..869c5d6b737 100644 --- a/packages/react-components/styles/styles.ts +++ b/packages/react-components/styles/styles.ts @@ -4,6 +4,16 @@ import { StyleSheet } from 'react-native' export const TOP_BAR_HEIGHT = 56 +export function elevationShadowStyle(elevation: number) { + return { + elevation, + shadowColor: 'black', + shadowOffset: { width: 0, height: 0.5 * elevation }, + shadowOpacity: 0.3, + shadowRadius: 0.8 * elevation, + } +} + export const componentStyles = StyleSheet.create({ marginTop10: { marginTop: 10,