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

486 lines
19 KiB
JavaScript

import * as React from 'react';
import {
View,
Text,
TouchableOpacity,
Alert,
Platform,
Image
} from 'react-native';
import {
Image as NBImage,
Button,
ScrollView
} from 'native-base';
import {
TotalAmount,
Buyer,
Item,
Ref,
CheckOut
} from '../../components/paymaya/checkout';
import { saveUserInfo } from "../../redux/actions/AppUserInfoActions";
import { Input } from 'react-native-elements';
import { connect } from "react-redux";
import Icon from '../../components/icons.js';
import CustomSafeArea from '../../components/safeArea.component.js';
import NetInfo from '../../components/netstatus';
import CustomHeader from '../../components/header.js';
import Theme from '../../components/theme.style.js';
import Assets from '../../components/assets.manager.js';
import Elements from '../../components/elements.js';
import REQUEST from '../../components/api';
import DB from '../../components/storage/';
import TokenizationForm from './form';
import Tokenization from '../../components/paymaya/tokenization'
import moment from 'moment';
// const PAYMENT_ENV = "SANDBOX"
// const PAYMENT_ENV = "PRODUCTION"
class TopUp extends React.Component {
constructor(props) {
super(props)
this.current = ""
}
state = {
connected: false,
isCardFormVisible: false,
loading: false,
popup: false,
Task: "",
DisplayAmount: "",
amount: 0,
focused: false,
checkoutResult: "",
userProfile: null,
session: null,
topupCount: 0,
merchant: {},
creditcards: [],
activeIndex: 0,
isKeyboardActive: false,
tokenizationFormCount: 0,
transactionType: null
}
componentDidMount() {
NetInfo.netstatus(isConnected => {
if(isConnected) {
this.init()
} else {
Elements.nointernet2(this.props)
}
})
}
componentWillUnmount() {
}
init = async () => {
let user = await DB.profile()
const session = await DB.session()
this.setState({ connected: true, loading: true, userProfile: user, session: session })
if(user.data.civilstatus_code == "0" || user.data.gender_code == "0") {
Alert.alert("Information", "Update your Profile first to use this feature.", [{text: "OK", onPress: () => this.props.navigation.goBack()}])
return
}
this.countTransactions()
this.getMerchant()
}
countTransactions = async () => {
const SESSION = await DB.session()
await REQUEST("transactions", "get", {
Authorization: SESSION.token,
card_number: SESSION.user.card_number
}, {}, {}, (res) => {
console.log(res)
let count = 0
if(res.data.length > 0){
for(var x=0;x<res.data.length;x++){
let today = moment()
let dt = moment(res.data[x].date.split(",")[0])
let diff = dt.diff(today, 'days')
if(diff == 0) count++
}
}
this.setState({ topupCount: count, loading: false })
if(count >= 5){
this.setState({ loading: false })
Platform.OS == 'ios' ? setTimeout(() => {
Alert.alert("Top Up", "\nYou have reached your maximum top up for this day.")
}, 700)
:
Alert.alert("Top Up", "\nYou have reached your maximum top up for this day.")
}
}, (error) => {
this.setState({ loading: false })
console.log(error)
})
}
handleDelete = (id, token, uuid) => {
Alert.alert(
"Delete Payment Card",
"Are you sure you want to delete this card?",
[
{
text: "NO",
style: "cancel"
},
{
text: "YES",
onPress: () => {
this.setState({ loading: true })
Tokenization.initRemove(id, token, uuid).then((res) => {
this.setState({ loading: false })
if(res.result == 'OK'){
setTimeout(() => {
Alert.alert("Deleted Successfully", "\nYour credit card has successfully deleted.", [{text: "OK", onPress: async () => {
this.init()
let creditcards = this.state.creditcards.filter(function(item){
return item.uuid != uuid
}).map(function(item){
return item
})
this.setState({ creditcards: creditcards })
}}])
}, 300)
}
})
}
},
]
)
}
getMerchant = async () => {
const USER_PROFILE = await DB.profile()
const SESSION = await DB.session()
await REQUEST("paymaya_tokens", "get", {'Authorization': SESSION.token}, {noID: true, value: USER_PROFILE.data.card_number}, {}, async (res) => {
if(res.data && res.data.cards){
this.setState({ merchant: res.data, activeIndex: 0 })
for(var x=0;x<res.data.cards.length;x++){
if(res.data.cards[x].default) this.setState({ activeIndex: x })
}
console.log(res.data.cards, res)
this.setState({ creditcards: res.data.cards, loading: false })
} else {
this.setState({ merchant: {}, creditcards: [], loading: false })
}
}, (error) => {
this.setState({ loading: false })
console.log(error)
})
}
moneyFormat = (price, sign = 'PHP ') => {
const pieces = parseFloat(price).toFixed(2).split('')
let ii = pieces.length - 3
while ((ii-=3) > 0) {
pieces.splice(ii, 0, ',')
}
return sign + pieces.join('')
}
setamount = (value) => {
this.setState({ DisplayAmount: this.moneyFormat(value).toString(), amount: value })
}
onAmountChange = (value) => {
if(value != this.current){
let parsed = parseFloat(this.clean(value))
if(parsed > 1000000) return false
let formatted = this.formatCurrency(parsed)
this.current = formatted
this.setState({ DisplayAmount: formatted, amount: parseFloat(parsed/100) })
}
}
clean = (str) => {
return str.replace("PHP ", "").replace(".", "").replace(",", "").toString()
}
formatCurrency = (val) => {
let fv = isNaN(val) ? (0).toFixed(2) : parseFloat(val / 100).toFixed(2)
return val.length == 6 ? "PHP " + fv.substr(0, 1) + "," + fv.substr(2, fv.length) : "PHP " + fv
}
validate = () => {
if(this.state.amount < 100 || this.state.amount > 10000){
Alert.alert("Invalid top up amount", "\nPlease enter value between 100 - 10,000 pesos only.\n")
return false
}
return true
}
onReload = (res, msg) => {
console.log("onBack", res, msg)
}
updateTopup = (transactionId, amount, onSuccess, onError) => {
REQUEST('topup_transaction_entry', 'post', {
Authorization: this.state.session.token
}, {}, {
amount: amount,
paymaya_tranx_id: transactionId
}, (res) => onSuccess(res), (error) => onError(error))
}
initCheckout = async () => {
if(!this.validate()) return false
if(this.state.creditcards.length > 0){
let mct = this.state.creditcards[this.state.activeIndex]
Alert.alert("Confirm Top Up", "\nYour card number will be used to pay for "+parseFloat(this.state.amount).toFixed(2)+" points.", [
{text: "NO",style: "cancel"},
{text: "YES",
onPress: async () => {
let payout = await Tokenization.initNewPayout(mct.cardTokenId, this.state.amount);
if(payout.status == "success") {
this.setState({ loading: true })
this.updateTopup(payout.id, this.state.amount, onSuccess => {
this.setState({ loading: false })
let data = {
amount: this.state.amount,
transactionId: payout.id,
data: {redirectUrl: payout.verificationUrl, card_number: mct.maskedPan, type: 'create' },
onBack: (res, msg) => alert(msg)
}
this.props.navigation.navigate('CheckOut', data)
}, onError => {
setTimeout(() => {
Alert.alert("Top Up", `\n${onError.error}`)
}, 700)
})
} else if(payout.status == "failed"){
this.setState({ loading: false })
if(payout.parameters.length > 0) {
setTimeout(() => {
Alert.alert("Top Up", `\n${payout.parameters[0]?.description}`)
}, 700)
} else {
Platform.OS == 'ios' ? setTimeout(() => {
Alert.alert("Top Up", "\nFailed to add new card.")
}, 300) : Alert.alert("Top Up", "\nFailed to add new card.")
}
}
}
}
])
} else {
this.setState({ isCardFormVisible: true })
}
}
initAddCard = async () => {
this.setState({ isCardFormVisible: true, tokenizationFormCount: this.state.tokenizationFormCount + 1, transactionType: "add" })
}
getDisplayCard = (type) => {
if(!type) return
else if(type == "visa") return Assets.icons.stpvisa
else if(type == "master-card") return Assets.icons.stpmastercard
else if(type == "jcb") return Assets.icons.stpjcb
else return Assets.icons.stpunknown
}
renderCardform = () => {
return (
<TokenizationForm
key={this.state.tokenizationFormCount}
type={this.state.transactionType == "add" ? "add" : "create"}
cardlist={this.state.creditcards}
customerId={this.state.merchant && this.state.creditcards.length > 0 ? this.state.merchant.customer_id : ''}
amount={this.state.amount}
onDone={() => {
this.init()
console.log("onDone")
}}
onBack={(res, msg) => {
this.onReload(res, msg)
}}
onGoBack={() => {
this.setState({ isCardFormVisible: false })
console.log("onGoBack")
}}
onSuccess={data => {
console.log("onSucces", data)
this.props.navigation.navigate('CheckOut', data)
}}
/>
)
}
render() {
console.log("The Credit Cards: " + JSON.stringify(this.state.creditcards));
if(!this.state.connected){
return (
<CustomSafeArea style={{flex: 1}}>
<View style={{flex: 1}}>
<CustomHeader title="Top Up Points" menu={false} navigation={this.props.navigation} />
<Elements.nointernet
message="No internet found. Please check your internet connection."
buttonText="Try Again"
onPress={() => this.init()}
/>
</View>
</CustomSafeArea>
)
}
return (
<CustomSafeArea>
{this.state.isCardFormVisible && this.renderCardform()}
<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} />
<CustomHeader title="Top Up Points" menu={false} navigation={this.props.navigation} />
<ScrollView>
<View style={{ flex: 1, backgroundColor: Theme.colors.white }}>
<View style={{flexDirection: 'row', padding: 15, backgroundColor: Theme.colors.textPrimary}}>
<View style={{flex: 1}}>
<Text style={{fontFamily: 'Arial', fontSize: 16, color: '#fff'}}>Select Top Up Value Points</Text>
</View>
</View>
<View style={{flexDirection: 'column', padding: 20, paddingTop: 10, paddingBottom: 5, alignItems: 'center'}}>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={() => this.setamount(100)} style={{flex: 1, margin: 10, padding: 10, borderRadius: 10, borderColor: Theme.colors.primary, borderWidth: 2}}>
<Text style={{textAlign: 'center', fontFamily: 'Arial', fontSize: 16, color: Theme.colors.primary}}>100</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setamount(500)} style={{flex: 1, margin: 10, padding: 10, borderRadius: 10, borderColor: Theme.colors.primary, borderWidth: 2}}>
<Text style={{textAlign: 'center', fontFamily: 'Arial', fontSize: 16, color: Theme.colors.primary}}>500</Text>
</TouchableOpacity>
</View>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={() => this.setamount(1000)} style={{flex: 1, margin: 10, padding: 10, borderRadius: 10, borderColor: Theme.colors.primary, borderWidth: 2}}>
<Text style={{textAlign: 'center', fontFamily: 'Arial', fontSize: 16, color: Theme.colors.primary}}>1000</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setamount(5000)} style={{flex: 1, margin: 10, padding: 10, borderRadius: 10, borderColor: Theme.colors.primary, borderWidth: 2}}>
<Text style={{textAlign: 'center', fontFamily: 'Arial', fontSize: 16, color: Theme.colors.primary}}>5000</Text>
</TouchableOpacity>
</View>
</View>
<View style={{padding: 15, paddingTop: 0}}>
<Text style={{padding: 5, paddingLeft:12, fontSize: 14, color: this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.text : Theme.colors.darkGray}}>
Or Enter Desired Value (maximum of 10,000 points)
</Text>
<Input
keyboardType="numeric"
placeholder="PHP"
value={this.state.DisplayAmount}
onFocus={() => this.setState({ focused: true })}
onChangeText={(value) => this.onAmountChange(value)}
containerStyle={{padding: 0}}
inputContainerStyle={{padding: 0, borderBottomWidth: this.state.focused ? 1.75 : 1, borderColor: this.state.focused ? Theme.colors.accent : "gray" }}
inputStyle={{padding: 0, fontFamily: 'Arial', fontSize: 16, color: this.props.app_theme?.theme.colors.text }}
/>
<Text style={{fontStyle: 'italic', fontSize: 15, paddingLeft: 12, marginTop: 20, fontFamily: 'Arial', color: this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.text : Theme.colors.darkGray}}>Note: Top Up to a maximum of five(5) times per day.</Text>
</View>
<View style={{flexDirection: 'row', padding: 15, backgroundColor: Theme.colors.textPrimary}}>
<View style={{flex: 1}}>
<Text style={{fontFamily: 'Arial', fontSize: 16, color: '#fff'}}>Payment Method</Text>
</View>
</View>
{
this.state.creditcards.length > 0 &&
<View style={{flexDirection: 'row', alignItems: 'center', paddingHorizontal: 15, borderBottomWidth: 0.5, borderColor: 'lightgray'}}>
<NBImage source={this.getDisplayCard(this.state.creditcards[this.state.activeIndex]?.cardType)} style={{width: 60, resizeMode: 'contain'}} />
<View style={{marginLeft: 10}}>
<Text style={{ color: this.props.app_theme?.theme.colors.text }}>{this.state.creditcards[this.state.activeIndex]?.cardType.toString().toUpperCase()} {this.state.creditcards[this.state.activeIndex]?.maskedPan}</Text>
<Text style={{ color: this.props.app_theme?.theme.colors.text }} note numberOfLines={1}>**** **** **** {this.state.creditcards[this.state.activeIndex]?.maskedPan}</Text>
</View>
</View>
}
{
this.state.creditcards && this.state.creditcards.length === 0 &&
<View style={{flexDirection: 'row', alignItems: 'center', paddingHorizontal: 15, borderBottomWidth: 0.5, borderColor: 'lightgray'}}>
<NBImage source={Assets.icons.stpunknown} style={{width: 60, resizeMode: 'contain'}} />
<View style={{marginLeft: 10}}>
<Text style={{ color: this.props.app_theme?.theme.colors.text }} note numberOfLines={1}>0000 0000 0000 0000</Text>
</View>
</View>
}
{
this.state.creditcards.length <= 5 && (
<TouchableOpacity onPress={() => this.initAddCard()} style={{flexDirection: 'row', alignItems: 'center', padding: 15, borderBottomWidth: 0.5, borderColor: 'lightgray'}}>
<Image source={Assets.icons.topup} style={{width: 25, height: 25, tintColor: this.props.app_theme?.theme.colors.text}} />
<Text style={{fontFamily: 'Arial', fontSize: 16, marginLeft: 10, color: this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.text : Theme.colors.textPrimary}}>
Add New Card
</Text>
</TouchableOpacity>
)
}
{
this.state.creditcards.length > 0 && this.state.creditcards.map((card, index) => {
return (
<View style={{flexDirection: 'row', alignItems: 'center', paddingHorizontal: 15, marginBottom: 5}}>
<TouchableOpacity
activeOpacity={.8}
onPress={() => {
Alert.alert("Select Card", "**** **** **** " + card?.maskedPan + " is selected.", [{text: "OK"}])
this.setState({ activeIndex: index });
}}
style={{flexDirection: 'row', flex: 1, alignItems: 'center'}}>
<NBImage source={this.getDisplayCard(card?.cardType)} style={{width: 80, resizeMode: 'contain'}} />
<View style={{marginLeft: 10 }}>
<Text style={{ color: this.props.app_theme?.theme.colors.text }}>{card?.cardType.toString().toUpperCase()}</Text>
<Text style={{ color: this.props.app_theme?.theme.colors.text }} note numberOfLines={1}>**** **** **** {card?.maskedPan}</Text>
</View>
</TouchableOpacity>
<Button
style={{padding: 0, backgroundColor: 'transparent', marginRight: 10}}
onPress={() => this.handleDelete(card.customer_id, card.paymentTokenId, card.uuid)}>
<Icon.Ionicons name='trash' size={25} color={Theme.colors.primary}/>
</Button>
</View>
)
})
}
<View style={{marginBottom:60}}></View>
</View>
</ScrollView>
{this.state.topupCount >= 5 ? null :
<TouchableOpacity
disabled={this.state.creditcards.length > 0 ? false : true}
style={{justifyContent: 'center', marginHorizontal: 15, paddingVertical: 15, borderRadius: 10, backgroundColor: this.state.creditcards.length > 0 ? Theme.colors.primary : this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.border : Theme.colors.primary + "15", marginBottom: 16}}
onPress={() => this.initCheckout()}>
<Text style={{fontSize: 16, fontFamily: 'Arial', textAlign: 'center', color: '#fff'}}>Next</Text>
</TouchableOpacity>
}
<Elements.popup visible={this.state.popup} message={`Transaction ${this.state.Task != "" ? this.state.Task : null}.`} />
</CustomSafeArea>
)
}
}
const mapStateToProps = (state) => {
return {
userinfo: state.appUserInfoReducer.userinfo,
app_theme: state.appThemeReducer.theme
}
}
const mapDispatchToProps = {
saveUserInfo
}
export default connect(mapStateToProps, mapDispatchToProps)(TopUp);