Skip to content

Commit

Permalink
Fiat on Ramp: Payments (#1666)
Browse files Browse the repository at this point in the history
* Add react-native-payments

* Initial apple pay screen

* Add Transak order updates and notifications

* Hide debug view

* Add quick amounts and keypad behavior

* Add 0. case to keypad

* Add some more details about transak

* enable-apple-pay

* Add initial apple pay processing

* Add react-native-payments

* Initial apple pay screen

* Add Transak order updates and notifications

* Hide debug view

* Add quick amounts and keypad behavior

* Add 0. case to keypad

* Add some more details about transak

* Add initial apple pay processing

* Reorganize components and variables

* analytics only on not dev

* startwatcher

* Add Wyre Apple Pay processing

* Move images to images folder

* dev

* Optimize for small devices

* Add Android Purchase Method Screen

* Make Wyre Apple Pay depend on selected network

* Remove react-native-dotenv

* Fix env vars, babel plugin replaces string, is not an object

lol

* Add i18n for fiat orders ui and notifications

* Add missing i18n to apple pay amount screen

* Fix i18n argument for failed fiat order placement

* Add home graphic

* Add Logger to Fiat Orders creation and processing

* Add Aborted apple pay check

* env.

* Add wyre rates to apple pay amount screen

* add react-native-payments from fork

* Add Logger.message

* circleci

* Add AppConstants

* Add requestbin debugging

* Fix apple pay attempt

* Limit card payment to debit cards

* Fix wyre transfer fees and update order always in state

* Format amount in Fiat Order notification

* Deactivate Wyre promotion

* Add alert when trying to buy in incorrect network

* Add some missing translations

* Add buy eth to SendTo balance 0 warning

* Change credit card to debit card and transfer

* Remove home graphic and change display rules

* Fix margins

* Add allowedToBuy function to control by device and network

* Improve paymentMethod Modal for small screens

* Add Analytics

* Add improved Receive Drawer

* Remove logger.messages and add errors to track

* Remove logger.messages and add errors to track

* Move Fiat Orders polling frequency to AppConstants

* Fix duplicated proptypes for transak webview

* Remove .env from .gitignore

* Add marginVertical and documentation to props in Base text component

* Add marginVertical and documentation to props in base Title component

* Use same disabled style for text and logo in apple pay button

* Remove code used for debugging

* Add apple pay UI i18n

* Add propTypes comments to Apple Pay Payment Method screen

* Remove comments from network alert

* Remove Roboto font usage

* Add createdAt property to FiatOrder

* Add cryptoAmount to transakOrderRedirect handler

* Add Fiat Orders List View

* Remove unnecessary fragment

* Add toLocaleString to Order summary

* Prevent duplicate add order

* Fix summary displaying NaN values

* bump CURRENT_PROJECT_VERSION:
:

* Update merchant ids

* Add error logger when apple pay fails

* merchantids

* publish-pre-release-android:

* npx jetify

* Conditionally show account name

Fixes QA Issue #3

* Add ScrollView hack to modal

Solves QA Issue#4

* Fix apple pay keypad for small device

Fixes QA Issue #5

* Fix transak logo for iphone 5

Fixes QA Issue #6

* issue 7

* Improve heading title in iphone5s

* bump 514

* Update countries list

* bump 515

* :protectWalletModalVisible:

* centeredTitle

* more protectWalletModalVisible

* 516

* protectWalletModalVisible

* send android to browser

* circleci

* Revert "circleci"

This reverts commit 89b348a.

* react-native-webview

* Revert "send android to browser"

This reverts commit 6e49761.

* iuse react-native-webview-forked

* 517

* circleci

* 518

* mocks and snaps

Co-authored-by: Esteban Mino <[email protected]>
  • Loading branch information
wachunei and estebanmino authored Aug 18, 2020
1 parent 7b823c0 commit d143039
Show file tree
Hide file tree
Showing 90 changed files with 4,590 additions and 1,449 deletions.
1 change: 1 addition & 0 deletions android/app/src/main/java/io/metamask/MainApplication.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.metamask;

import com.facebook.react.ReactApplication;
import com.reactnativecommunity.webviewforked.RNCWebViewForkedPackage;
import com.cmcewen.blurview.BlurViewPackage;
import android.content.Context;
import com.facebook.react.PackageList;
Expand Down
2 changes: 2 additions & 0 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
rootProject.name = 'MetaMask'
include ':react-native-webview-forked'
project(':react-native-webview-forked').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-forked/android')
include ':@react-native-community_blur'
project(':@react-native-community_blur').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/blur/android')
include ':lottie-react-native'
Expand Down
1 change: 1 addition & 0 deletions app/__mocks__/@exodus/react-native-payments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from '@exodus/react-native-payments/lib/js/__mocks__';
127 changes: 127 additions & 0 deletions app/components/Base/DetailsModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import React from 'react';
import PropTypes from 'prop-types';
import { View, StyleSheet, TouchableOpacity } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { colors, fontStyles } from '../../styles/common';

import Text from './Text';

const styles = StyleSheet.create({
modalContainer: {
width: '100%',
backgroundColor: colors.white,
borderRadius: 10
},
modalView: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center'
},
header: {
borderBottomWidth: StyleSheet.hairlineWidth,
borderColor: colors.grey100,
flexDirection: 'row'
},
title: {
flex: 1,
textAlign: 'center',
fontSize: 18,
marginVertical: 12,
marginHorizontal: 24,
color: colors.fontPrimary,
...fontStyles.bold
},
closeIcon: { paddingTop: 4, position: 'absolute', right: 16 },
body: {
paddingHorizontal: 15
},
section: {
paddingVertical: 16,
flexDirection: 'row'
},
sectionBorderBottom: {
borderBottomColor: colors.grey100,
borderBottomWidth: 1
},
column: {
flex: 1
},
columnEnd: {
alignItems: 'flex-end'
},
sectionTitle: {
...fontStyles.normal,
fontSize: 10,
color: colors.grey500,
marginBottom: 8
}
});
const DetailsModal = ({ children }) => (
<View style={styles.modalView}>
<View style={styles.modalContainer}>{children}</View>
</View>
);

const DetailsModalHeader = ({ style, ...props }) => <View style={[styles.header, style]} {...props} />;
const DetailsModalTitle = ({ style, ...props }) => <Text style={[styles.title, style]} {...props} />;
const DetailsModalCloseIcon = ({ style, ...props }) => (
<TouchableOpacity style={[styles.closeIcon, style]} {...props}>
<Ionicons name={'ios-close'} size={38} />
</TouchableOpacity>
);
const DetailsModalBody = ({ style, ...props }) => <View style={[styles.body, style]} {...props} />;
const DetailsModalSection = ({ style, borderBottom, ...props }) => (
<View style={[styles.section, borderBottom && styles.sectionBorderBottom]} {...props} />
);
const DetailsModalSectionTitle = ({ style, ...props }) => <Text style={[styles.sectionTitle, style]} {...props} />;
const DetailsModalColumn = ({ style, end, ...props }) => (
<View style={[styles.column, end && styles.columnEnd, style]} {...props} />
);

DetailsModal.Header = DetailsModalHeader;
DetailsModal.Title = DetailsModalTitle;
DetailsModal.CloseIcon = DetailsModalCloseIcon;
DetailsModal.Body = DetailsModalBody;
DetailsModal.Section = DetailsModalSection;
DetailsModal.SectionTitle = DetailsModalSectionTitle;
DetailsModal.Column = DetailsModalColumn;

/**
* Any other external style defined in props will be applied
*/
const stylePropType = PropTypes.oneOfType([PropTypes.object, PropTypes.array]);

DetailsModal.propTypes = {
children: PropTypes.node
};

DetailsModalHeader.propTypes = {
style: stylePropType
};
DetailsModalTitle.propTypes = {
style: stylePropType
};
DetailsModalCloseIcon.propTypes = {
style: stylePropType
};
DetailsModalBody.propTypes = {
style: stylePropType
};
DetailsModalSection.propTypes = {
style: stylePropType,
/**
* Adds a border to the bottom of the section
*/
borderBottom: PropTypes.bool
};
DetailsModalSectionTitle.propTypes = {
style: stylePropType
};
DetailsModalColumn.propTypes = {
style: stylePropType,
/**
* Aligns column content to flex-end
*/
end: PropTypes.bool
};
export default DetailsModal;
112 changes: 112 additions & 0 deletions app/components/Base/ListItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, View } from 'react-native';
import Device from '../../util/Device';
import { colors, fontStyles } from '../../styles/common';
import Text from './Text';

const styles = StyleSheet.create({
wrapper: {
padding: 15,
minHeight: Device.isIos() ? 95 : 100
},
date: {
color: colors.fontSecondary,
fontSize: 12,
marginBottom: 10,
...fontStyles.normal
},
content: {
flexDirection: 'row'
},
actions: {
flexDirection: 'row',
paddingTop: 10,
paddingLeft: 40
},
icon: {
flexDirection: 'row',
alignItems: 'center'
},
body: {
flex: 1,
marginLeft: 15
},
amounts: {
flex: 0.6,
alignItems: 'flex-end'
},
title: {
fontSize: 15,
color: colors.fontPrimary
},
amount: {
fontSize: 15,
color: colors.fontPrimary
},
fiatAmount: {
fontSize: 12,
color: colors.fontSecondary,
textTransform: 'uppercase'
}
});

const ListItem = ({ style, ...props }) => <View style={[styles.wrapper, style]} {...props} />;

const ListItemDate = ({ style, ...props }) => <Text style={[styles.date, style]} {...props} />;
const ListItemContent = ({ style, ...props }) => <View style={[styles.content, style]} {...props} />;
const ListItemActions = ({ style, ...props }) => <View style={[styles.actions, style]} {...props} />;
const ListItemIcon = ({ style, ...props }) => <View style={[styles.icon, style]} {...props} />;
const ListItemBody = ({ style, ...props }) => <View style={[styles.body, style]} {...props} />;
const ListItemTitle = ({ style, ...props }) => <Text style={[styles.title, style]} {...props} />;
const ListItemAmounts = ({ style, ...props }) => <View style={[styles.amounts, style]} {...props} />;
const ListItemAmount = ({ style, ...props }) => <Text style={[styles.amount, style]} {...props} />;
const ListItemFiatAmount = ({ style, ...props }) => <Text style={[styles.fiatAmount, style]} {...props} />;

ListItem.Date = ListItemDate;
ListItem.Content = ListItemContent;
ListItem.Actions = ListItemActions;
ListItem.Icon = ListItemIcon;
ListItem.Body = ListItemBody;
ListItem.Title = ListItemTitle;
ListItem.Amounts = ListItemAmounts;
ListItem.Amount = ListItemAmount;
ListItem.FiatAmount = ListItemFiatAmount;

export default ListItem;

/**
* Any other external style defined in props will be applied
*/
const stylePropType = PropTypes.oneOfType([PropTypes.object, PropTypes.array]);

ListItem.propTypes = {
style: stylePropType
};
ListItemDate.propTypes = {
style: stylePropType
};
ListItemContent.propTypes = {
style: stylePropType
};
ListItemActions.propTypes = {
style: stylePropType
};
ListItemIcon.propTypes = {
style: stylePropType
};
ListItemBody.propTypes = {
style: stylePropType
};
ListItemTitle.propTypes = {
style: stylePropType
};
ListItemAmounts.propTypes = {
style: stylePropType
};
ListItemAmount.propTypes = {
style: stylePropType
};
ListItemFiatAmount.propTypes = {
style: stylePropType
};
17 changes: 17 additions & 0 deletions app/components/Base/ModalHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useState } from 'react';

function ModalHandler({ children }) {
const [isVisible, setVisible] = useState(false);

const showModal = () => setVisible(true);
const hideModal = () => setVisible(true);
const toggleModal = () => setVisible(!isVisible);

if (typeof children === 'function') {
return children({ isVisible, toggleModal, showModal, hideModal });
}

return children;
}

export default ModalHandler;
64 changes: 64 additions & 0 deletions app/components/Base/StatusText.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';
import PropTypes from 'prop-types';
import Text from './Text';
import { colors } from '../../styles/common';
import { StyleSheet } from 'react-native';
import { FIAT_ORDER_STATES } from '../../reducers/fiatOrders';
import { strings } from '../../../locales/i18n';

const styles = StyleSheet.create({
status: {
marginTop: 4,
fontSize: 12,
letterSpacing: 0.5
}
});

export const ConfirmedText = props => <Text bold green style={styles.status} {...props} />;
export const PendingText = props => <Text bold style={[styles.status, { color: colors.orange }]} {...props} />;
export const FailedText = props => <Text bold style={[styles.status, { color: colors.red }]} {...props} />;

function StatusText({ status, context, ...props }) {
switch (status) {
case 'Confirmed':
case 'confirmed':
return <ConfirmedText>{strings(`${context}.${status}`)}</ConfirmedText>;
case 'Pending':
case 'pending':
case 'Submitted':
case 'submitted':
return <PendingText>{strings(`${context}.${status}`)}</PendingText>;
case 'Failed':
case 'Cancelled':
case 'failed':
case 'cancelled':
return <FailedText>{strings(`${context}.${status}`)}</FailedText>;

case FIAT_ORDER_STATES.COMPLETED:
return <ConfirmedText>{strings(`${context}.completed`)}</ConfirmedText>;
case FIAT_ORDER_STATES.PENDING:
return <PendingText>{strings(`${context}.pending`)}</PendingText>;
case FIAT_ORDER_STATES.FAILED:
return <FailedText>{strings(`${context}.failed`)}</FailedText>;
case FIAT_ORDER_STATES.CANCELLED:
return <FailedText>{strings(`${context}.cancelled`)}</FailedText>;

default:
return (
<Text bold style={styles.status}>
{status}
</Text>
);
}
}

StatusText.defaultProps = {
context: 'transaction'
};

StatusText.propTypes = {
status: PropTypes.string.isRequired,
context: PropTypes.string
};

export default StatusText;
Loading

0 comments on commit d143039

Please sign in to comment.