unioil-loyalty-rn-app/app/screens/topup/topuppaymentmethod.js

424 lines
18 KiB
JavaScript

import * as React from 'react';
import * as UTILS from './utils';
import { connect } from "react-redux";
import {
TouchableOpacity,
View,
Text,
Image,
Switch,
StyleSheet,
Modal,
Alert,
TextInput,
Keyboard
} from 'react-native';
import { returnIcon } from '../../utils/card';
import { ENV } from '../../components/environment';
import REQUEST from '../../components/api';
import moment from 'moment';
import cardValidator from 'card-validator';
import CustomHeader from '../../components/header.js';
import Theme from '../../components/theme.style.js';
import DB from '../../components/storage/';
import Elements from '../../components/elements.js';
import Assets from '../../components/assets.manager.js';
import Tokenization from '../../components/paymaya/tokenization';
import CustomSafeArea from '../../components/safeArea.component';
class TopupPaymentMethod extends React.Component {
constructor(props) {
super(props)
}
state = {
cardNumber: null,
cardExpiry: null,
cardCVV: null,
customerName: `${this.props.userinfo.data.firstname} ${this.props.userinfo.data.lastname}`,
focus_number: false,
focus_holder: false,
focus_expiry: false,
focus_cvv: false,
enableDefaultCard: false,
showModal: false,
pubkey: null,
verificationUrl: null,
cardDetails: null,
loading: false
}
addCard = async () => {
this.setState({ loading: true })
const USER_PROFILE = await DB.profile();
const SESSION = await DB.session();
let splitedExpiry = this.state.cardExpiry.split("/");
const newCardNumber = this.state.cardNumber.replace(/ /g, "").toString();
const dataToSend = {
number: newCardNumber,
expmonth: splitedExpiry[0],
expyear: moment().year().toString().slice(0, -2) + splitedExpiry[1],
cvv: this.state.cardCVV,
is_default: this.state.enableDefaultCard,
}
console.log(dataToSend)
await REQUEST("paymaya_tokens", "get", {'Authorization': SESSION.token}, {noID: false, value: USER_PROFILE.data.card_number}, {}, async (res) => {
console.log(this.props.route?.params.merchant.customer_id);
if(res.status === 1 && res.data) {
// const checker = res.data?.cards?.find(card => newCardNumber.includes(card.first6) && newCardNumber.includes(card.last4));
// if(!checker) {
if(this.props.route?.params.merchant.customer_id) dataToSend.customer_id = this.props.route?.params.merchant.customer_id;
await REQUEST("paymaya_tokens", "post", {'Authorization': SESSION.token}, {}, dataToSend, (result) => {
console.log(dataToSend);
if(result.status === 1 && result.data) {
this.props.navigation.navigate('CheckOut', {
data: {redirectUrl: result.data.verificationUrl, card_number: result.data.card_number, type: 'add'},
onBack: () => {
this.props.route?.params.onAddNewCard(result.data);
this.props.navigation.goBack();
}
});
} else {
console.log(result)
this.setState({ loading: false })
}
}, (err) => {}, "Card", "Add")
// }
// else {
// Alert.alert("Warning", '\n' + "Card number already exist.")
// this.setState({ loading: false })
// }
} else {
await REQUEST("paymaya_tokens", "post", {'Authorization': SESSION.token}, {}, dataToSend, (result) => {
console.log(dataToSend);
if(result.status === 1 && result.data) {
this.props.navigation.navigate('CheckOut', {
data: {redirectUrl: result.data.verificationUrl, card_number: result.data.card_number, type: 'add'},
onBack: () => {
this.props.route?.params.onAddNewCard(result.data);
this.props.navigation.goBack();
}
});
} else {
console.log(result)
// Alert.alert("Warning", '\n' + "Card number already exist.")
this.setState({ loading: false })
}
}, (err) => {}, "Card", "Add")
}
this.setState({ loading: false })
}, (error) => {
console.log(error)
this.setState({ loading: false })
this.onError(error);
}, "Funding", "Fetch")
}
onError = (err) => {
if(err.toJSON().message !== 'Network Error') {
Alert.alert("Information", `\n${err.message}`);
} else {
Elements.nointernet2()
}
this.setState({ loading: false })
}
_handlingCardNumber = (number) => {
var value = number.replace(/\s+/g, '').replace(/[^0-9]/gi, '')
var matches = value.match(/\d{4,16}/g);
var match = matches && matches[0] || ''
var parts = []
for (let i = 0, len=match.length; i<len; i+=4) {
parts.push(match.substring(i, i+4))
}
var cardnumber = parts.length ? parts.join(' ') : number
this.setState({ cardNumber: cardnumber, cardDetails: cardValidator.number(cardnumber) });
}
_handlingCustomerName = (name) => {
this.setState({ customerName: name })
}
_handlingCardExpiry = (number) => {
if (number.indexOf('.') >= 0 || number.length > 5) return
if (number.length === 2 && this.state.cardExpiry.length === 1) number += '/'
this.setState({ cardExpiry: number });
}
_handlingCVV = (number) => {
if (number.indexOf('.') >= 0 || number.length > 3) return
this.setState({ cardCVV: number });
}
submitNewAddedCard = () => {
if(this.state.cardNumber == null || this.state.cardExpiry == null || this.state.cardCVV == null) {
this.setState({ showModal: true })
return
}
let numberYear = moment(Theme.platform === "android" ? Date() : new Date()).format('YYYY').slice(0, 2) //get initial 2 digits of year
let cardnumber = this.state.cardNumber.replace(/\s/g, "")
let cardExpiry = `${this.state.cardExpiry.split("/")[0]}${numberYear}${this.state.cardExpiry.split("/")[1]}`
let cardCvv = this.state.cardCVV
if(!cardValidator.number(cardnumber)?.card?.type || cardnumber.length < 16) {
Alert.alert("Information", '\n' + `Invalid card number. Please use different card type.`)
return
}
if(!cardValidator.expirationDate(cardExpiry).isValid) {
Alert.alert("Information", '\n' + "Invalid expiration date. Please check and try again.")
return
}
if(!cardValidator.cvv(cardCvv).isValid) {
Alert.alert("Information", '\n' + "Invalid cvv number. Please check and try again")
return
}
this.setState({ loading: true });
this.addCard();
}
notEmpty = () => {
const { cardNumber, cardExpiry, cardCVV, customerName } = this.state;
if(cardNumber && cardExpiry && cardCVV && customerName) {
return true;
}
return false
}
onBackConfirmation = () => {
Alert.alert(
'',
'Are you sure you want to cancel adding card?',
[
{
text: 'Cancel',
style: 'cancel',
},
{
text: 'OK',
onPress: () => this.props.navigation.goBack(),
},
],
{cancelable: true},
);
}
onSubmitEditing = () => {
Keyboard.dismiss();
if(this.notEmpty()) return this.submitNewAddedCard();
}
renderErrorModal = () => {
return (
<Modal
animationType="none"
transparent={true}
visible={this.state.showModal}>
<TouchableOpacity activeOpacity={1} onPress={() => {}} style={styles.centeredView}>
<View style={[styles.modalView, { backgroundColor: this.props.app_theme?.theme.colors.border }]}>
<>
<Image source={Assets.icons.points_balance} style={{ width: 85, height: 85, resizeMode: 'contain' }} />
<Text style={{ fontSize: 18, color: this.props.app_theme?.theme.colors.text, marginVertical: 30 }}>{'Please Fill in the required fields'}</Text>
<TouchableOpacity onPress={() => this.setState({ showModal: false })} style={{ width: 80, height: 30, backgroundColor: Theme.colors.primary, alignItems: 'center', justifyContent: 'center', borderRadius: 5 }}>
<Text style={{ fontSize: 18, color: Theme.colors.white, textAlign: 'center' }}>Ok</Text>
</TouchableOpacity>
</>
</View>
</TouchableOpacity>
</Modal>
)
}
renderCardForm = () => {
return (
<View style={{paddingHorizontal: 20, paddingTop: 40}}>
<Text style={{alignSelf: 'center', fontSize: 20, color: Theme.colors.primary, marginBottom: 20}}>Enroll Your Payment Card</Text>
<Text style={{fontSize: 12, color: this.state.focus_number ? Theme.colors.primary : Theme.colors.searchGray, marginLeft: 15, marginBottom: 5}}>Card Number</Text>
<View style={[styles.cardContainer, this.state.focus_number && {borderBottomColor: Theme.colors.primary}]}>
<TextInput
keyboardType="numeric"
returnKeyType={'done'}
onSubmitEditing={Keyboard.dismiss}
placeholder="Card Number"
placeholderTextColor={Theme.colors.gray}
value={this.state.cardNumber}
onFocus={() => this.setState({ focus_number: true })}
onBlur={() => this.setState({ focus_number: false })}
onChangeText={(value) => this._handlingCardNumber(value)}
style={{ flex: 1, color: this.props.app_theme?.theme.colors.text }}
/>
<Image source={returnIcon(this.state.cardDetails?.card?.niceType)} style={{ width: 30, height: 30, resizeMode: 'contain' }} />
</View>
<Text style={{fontSize: 12, color: this.state.focus_holder ? Theme.colors.primary : Theme.colors.searchGray, marginLeft: 15, marginTop: 10, marginBottom: 5}}>Name on Card</Text>
<View style={[styles.cardContainer, this.state.focus_holder && {borderBottomColor: Theme.colors.primary}]}>
<TextInput
returnKeyType={'done'}
placeholder="Customer Name"
placeholderTextColor={Theme.colors.gray}
onSubmitEditing={Keyboard.dismiss}
value={this.state.customerName}
onFocus={() => this.setState({ focus_holder: true })}
onBlur={() => this.setState({ focus_holder: false })}
onChangeText={(value) => this._handlingCustomerName(value)}
style={{ flex: 1, color: this.props.app_theme?.theme.colors.text }}
/>
</View>
<View style={{flexDirection: 'row' }}>
<View style={[styles.expirationCvvContainer, this.state.focus_expiry && {borderBottomColor: Theme.colors.primary}, { flex: 1, marginLeft: 16, marginRight: 5 }]}>
<TextInput
keyboardType="numeric"
returnKeyType={'done'}
placeholder="Expiration(MM/YY)"
onSubmitEditing={Keyboard.dismiss}
placeholderTextColor={Theme.colors.gray}
value={this.state.cardExpiry}
onFocus={() => this.setState({ focus_expiry: true })}
onBlur={() => this.setState({ focus_expiry: false })}
onChangeText={(value) => this._handlingCardExpiry(value)}
style={{ flex: 1, color: this.props.app_theme?.theme.colors.text, marginRight: 3 }}
/>
</View>
<View style={[styles.expirationCvvContainer, this.state.focus_cvv && {borderBottomColor: Theme.colors.primary}, { flex: 0.55, marginRight: 16, marginLeft: 5 }]}>
<TextInput
keyboardType="numeric"
returnKeyType={'done'}
placeholder="CVV"
onSubmitEditing={this.onSubmitEditing}
placeholderTextColor={Theme.colors.gray}
value={this.state.cardCVV}
onFocus={() => this.setState({ focus_cvv: true })}
onBlur={() => this.setState({ focus_cvv: false })}
onChangeText={(value) => this._handlingCVV(value)}
style={{ flex: 1, color: this.props.app_theme?.theme.colors.text, marginLeft: 3 }}
/>
</View>
</View>
</View>
)
}
renderSwitch = () => {
return (
<View style={{flexDirection: 'row', paddingHorizontal: 35, marginTop: 20, alignItems: 'center', justifyContent: 'space-between'}}>
<Text style={{color: Theme.colors.gray}}>Set as primary card</Text>
<Switch
style={{ transform: [{scale: .8}]}}
value={this.state.enableDefaultCard}
trackColor={{true: Theme.colors.primary + 35, false: "gray"}}
thumbColor={this.state.enableDefaultCard ? Theme.colors.primary : "gray"}
onChange={() => this.setState({ enableDefaultCard: !this.state.enableDefaultCard })}
/>
</View>
)
}
render() {
return (
<CustomSafeArea>
<CustomHeader
title={"Add Card"}
onBackPress={() => this.onBackConfirmation()}
back={true}
menu={false}
navigation={this.props.navigation}
/>
<Elements.loaderView
title="Validating"
message="Please wait..."
isDarkMode={this.props.app_theme?.theme.dark}
backgroundColor={this.props.app_theme?.theme.colors.border}
color={this.props.app_theme?.theme.colors.text}
visible={this.state.loading} />
{this.renderErrorModal()}
{this.renderCardForm()}
{this.renderSwitch()}
<View style={{ flex: 1 }} />
<View>
<Text style={{ fontSize: 12, fontWeight: 'bold', textAlign: 'center', fontStyle: 'italic', color: this.props.app_theme?.theme.colors.text }}>Your card will be charged to ensure that it's valid.</Text>
<Text style={{ fontSize: 12, fontWeight: 'bold', textAlign: 'center', fontStyle: 'italic', color: this.props.app_theme?.theme.colors.text, marginBottom: 10 }}>Charged amount will be automatically refunded.</Text>
<View style={{ marginBottom: 5 }} />
<TouchableOpacity disabled={!this.notEmpty()} onPress={() => this.submitNewAddedCard()}
style={{ height: 50, marginBottom: 16, backgroundColor: this.notEmpty() ? Theme.colors.primary : this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.border : Theme.colors.primary + "15", justifyContent: 'center', alignItems: 'center', borderRadius: 5, marginHorizontal: 35 }}>
<Text style={{ fontSize: 18, color: Theme.colors.white, textAlign: 'center', fontWeight: 'bold' }}>Save</Text>
</TouchableOpacity>
</View>
</CustomSafeArea>
)
}
}
const mapStateToProps = (state) => {
return {
app_theme: state.appThemeReducer.theme,
userinfo: state.appUserInfoReducer.userinfo
}
}
export default connect(mapStateToProps, null)(TopupPaymentMethod)
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
backgroundColor: '#00000090',
},
modalView: {
margin: 25,
backgroundColor: "white",
borderRadius: 15,
padding: 20,
alignItems: "center",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5
},
cardContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: Theme.colors.gray,
height: 40,
borderRadius: 5,
marginBottom: 10,
marginHorizontal: 16
},
expirationCvvContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: Theme.colors.gray,
height: 40,
borderRadius: 5,
marginVertical: 10
}
})