461 lines
18 KiB
JavaScript
461 lines
18 KiB
JavaScript
import * as React from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
TouchableOpacity,
|
|
Alert,
|
|
Image,
|
|
Modal,
|
|
ScrollView,
|
|
BackHandler
|
|
} from 'react-native';
|
|
import { returnIcon } from '../../utils/card';
|
|
import { saveUserInfo } from "../../redux/actions/AppUserInfoActions";
|
|
import { Input } from 'react-native-elements';
|
|
import { connect } from "react-redux";
|
|
import { openModal } from '../../redux/actions/AlertActions';
|
|
import { AdjustableText } from '../../components/text';
|
|
import Assets from '../../components/assets.manager'
|
|
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 Elements from '../../components/elements.js';
|
|
import REQUEST from '../../components/api';
|
|
import DB from '../../components/storage/';
|
|
import CustomIcon from '../../components/icons.js';
|
|
|
|
class TopUp extends React.Component {
|
|
|
|
constructor(props) {
|
|
super(props)
|
|
this.current = ""
|
|
}
|
|
|
|
state = {
|
|
connected: true,
|
|
loading: false,
|
|
popup: false,
|
|
Task: "",
|
|
DisplayAmount: "",
|
|
amount: 0,
|
|
focused: false,
|
|
checkoutResult: "",
|
|
userProfile: null,
|
|
session: null,
|
|
topupCount: 0,
|
|
merchant: {},
|
|
selectedCreditCard: null,
|
|
activeIndex: 0,
|
|
isKeyboardActive: false,
|
|
transactionType: null,
|
|
completeModal: false,
|
|
rate: 0,
|
|
radius: 0
|
|
}
|
|
|
|
componentDidMount() {
|
|
NetInfo.netstatus(isConnected => {
|
|
if(isConnected) {
|
|
this.init()
|
|
} else {
|
|
this.setState({ connected: false })
|
|
Elements.nointernet2(this.props)
|
|
}
|
|
})
|
|
}
|
|
|
|
init = async () => {
|
|
let user = await DB.profile()
|
|
const session = await DB.session();
|
|
|
|
this.setState({ loading: true })
|
|
await this.getRadiusAndPercentTage();
|
|
await this.getSelectedCard();
|
|
|
|
this.setState({ connected: true, userProfile: user, session: session })
|
|
if(user.data.civilstatus_code == "0" || user.data.gender_code == "0") {
|
|
this.setState({ loading: false })
|
|
return Alert.alert("Information", '\n' + "Update your Profile first to use this feature.", [
|
|
{text: "CANCEL", onPress: () => {
|
|
return this.props.navigation.goBack();
|
|
}},
|
|
{text: "OK", onPress: () => {
|
|
this.props.navigation.navigate("EditProfile", {data: this.state.userProfile.data, onGoBack: () => {
|
|
this.init()
|
|
}});
|
|
}}
|
|
]);
|
|
}
|
|
|
|
}
|
|
|
|
getSelectedCard = async () => {
|
|
const card = await DB.get("topupPaymentCards");
|
|
if(card) {
|
|
return this.setState({ selectedCreditCard: JSON.parse(card) });
|
|
} else {
|
|
return this.getFunding()
|
|
}
|
|
}
|
|
|
|
onBackHandler = (type) => {
|
|
if(type === "disable") return BackHandler.addEventListener("hardwareBackPress", this.onBack);
|
|
else if (type === "enable")return BackHandler.removeEventListener("hardwareBackPress", this.onBack)
|
|
}
|
|
|
|
onBack = () => {
|
|
return true
|
|
}
|
|
|
|
getFunding = 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 && res.data.cards.length > 0) {
|
|
const getDefault = res.data.cards.find(card => card.default);
|
|
await DB.set(
|
|
"topupPaymentCards",
|
|
JSON.stringify(getDefault),
|
|
() => {},
|
|
() => {}
|
|
)
|
|
this.setState({ selectedCreditCard: getDefault })
|
|
}
|
|
|
|
this.setState({ loading: false })
|
|
}, (error) => {
|
|
this.onError(error);
|
|
}, "Funding", "Fetch")
|
|
}
|
|
|
|
getRadiusAndPercentTage = async () => {
|
|
const SESSION = await DB.session()
|
|
REQUEST("getPercentageRadius", "get", {
|
|
'Authorization': SESSION.token,
|
|
}, {}, {}, (res) => {
|
|
if(res.status === 1) {
|
|
const { percentage, radius } = res.data;
|
|
this.setState({ rate: percentage, radius: radius })
|
|
}
|
|
|
|
this.setState({ loading: false })
|
|
}, (err) => {
|
|
this.onError(err);
|
|
}, "Percentage Radius", "Fetch")
|
|
}
|
|
|
|
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)
|
|
let newVal = val.length == 6 ? "PHP " + fv.substr(0, 1) + "," + fv.substr(2, fv.length) : "PHP " + fv;
|
|
return Theme.formatter.CRNCYNOFIXED(newVal)
|
|
}
|
|
|
|
validate = () => {
|
|
NetInfo.netstatus((response) => {
|
|
if(!response) {
|
|
Elements.nointernet2();
|
|
this.onBackHandler("enable");
|
|
}
|
|
else {
|
|
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
|
|
}
|
|
|
|
this.props.openModal({
|
|
open: true,
|
|
title: "Confirm Top-Up",
|
|
body: `Your card number **** **** **** ${this.state.selectedCreditCard?.last4}\nwill be used to pay for ${Theme.formatter.CRNCY(this.state.amount)} points.`,
|
|
yesCB: this.topup,
|
|
theme: this.props.app_theme
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
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)
|
|
, "Topup", "Update")
|
|
}
|
|
|
|
initiateTopup = async () => {
|
|
let mct = this.state.selectedCreditCard;
|
|
|
|
let SESSION = await DB.session();
|
|
REQUEST("payTopUp", 'post', {
|
|
'Authorization': SESSION.token,
|
|
}, {}, {
|
|
amount: this.state.amount,
|
|
token: mct.cardTokenId
|
|
}, (res) => {
|
|
console.log(res)
|
|
if(res.status === 1) {
|
|
this.setState({ loading: false })
|
|
let data = {
|
|
amount: this.state.amount,
|
|
transactionId: res.data.id,
|
|
data: {redirectUrl: res.data.response?.verificationUrl || res.data.verificationUrl, card_number: mct.maskedPan, type: 'create' },
|
|
onBack: (_, msg) => alert(msg),
|
|
successCB: () => this.setState({ completeModal: true })
|
|
}
|
|
this.props.navigation.navigate('CheckOut', data);
|
|
this.onBackHandler("enable");
|
|
}
|
|
}, (err) => this.onError(err)
|
|
, "Topup", "Initiate")
|
|
}
|
|
|
|
topup = async () => {
|
|
this.setState({ loading: true });
|
|
this.onBackHandler("disable");
|
|
let mct = this.state.selectedCreditCard;
|
|
|
|
let SESSION = await DB.session();
|
|
|
|
REQUEST('verifyAmount', 'post', {
|
|
'Authorization': SESSION.token
|
|
}, {}, {amount: this.state.amount}, (res) => {
|
|
console.log(res)
|
|
if(res.status === 1) {
|
|
this.initiateTopup();
|
|
} else if(res.status === 0) {
|
|
this.onBackHandler("enable");
|
|
this.setState({ loading: false });
|
|
|
|
if(res.data && res.data.topup_bal_perday !== "0") {
|
|
return Alert.alert("Information", '\n' + `You only have ${Theme.formatter.CRNCY(res.data.topup_bal_perday)} remaining Top-Up credits today.`, [{text: "OK"}]);
|
|
}
|
|
|
|
return Alert.alert("Information", '\n' + res.message, [{text: "OK", onPress: () => this.props.navigation.goBack()}]);
|
|
}
|
|
}, (err) => {
|
|
this.onBackHandler("enable");
|
|
this.onError(err)
|
|
}, "Amount", "Verify")
|
|
}
|
|
|
|
onError = (err) => {
|
|
this.setState({ loading: false })
|
|
|
|
if(err?.toJSON().message === 'Network Error') {
|
|
Elements.nointernet2()
|
|
} else {
|
|
Alert.alert("Information", `\n${err.message}`);
|
|
}
|
|
}
|
|
|
|
returnCard = () => {
|
|
return (
|
|
this.state.selectedCreditCard ?
|
|
<TouchableOpacity activeOpacity={1} onPress={() => this.props.navigation.navigate("TopupPaymentList", { onSelectedPaymentCard: (selected) => this.setState({ selectedCreditCard: selected })})}>
|
|
<Elements.shadowView style={{backgroundColor: this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.border : Theme.colors.white, paddingHorizontal: 20, paddingVertical: 15, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
|
|
<View style={{flexDirection: 'row', alignItems: 'center'}}>
|
|
<Image source={this.state.selectedCreditCard && returnIcon(this.state.selectedCreditCard.cardType)} style={{height: 40, width: 40, resizeMode: 'contain'}} />
|
|
<View style={{marginLeft: 10}}>
|
|
<Text style={{fontSize: 13, fontWeight: 'bold', color: this.props.app_theme?.theme.colors.text}}>**** **** **** {this.state.selectedCreditCard.last4}</Text>
|
|
<Text style={{fontStyle: 'italic', fontSize: 11, color: '#6887ed'}}>Primary</Text>
|
|
</View>
|
|
</View>
|
|
<View style={{flexDirection: 'row', alignItems: 'center'}}>
|
|
<Text style={{fontSize: 15, color: Theme.colors.soda, marginRight: 15}}>Change</Text>
|
|
<CustomIcon.Entypo name={"chevron-thin-right"} color={this.props.app_theme?.theme.colors.text} size={16} />
|
|
</View>
|
|
</Elements.shadowView>
|
|
</TouchableOpacity>
|
|
:
|
|
<TouchableOpacity activeOpacity={1} onPress={() => this.props.navigation.navigate("TopupPaymentList", { onSelectedPaymentCard: (selected) => this.setState({ selectedCreditCard: selected })})}>
|
|
<Elements.shadowView style={{backgroundColor: this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.border : Theme.colors.white, paddingHorizontal: 20, paddingVertical: 15, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
|
|
<AdjustableText style={{fontSize: 18, color: Theme.colors.soda }}>Select Card</AdjustableText>
|
|
<CustomIcon.Entypo name={"chevron-thin-right"} color={this.props.app_theme?.theme.colors.text} size={16} />
|
|
</Elements.shadowView>
|
|
</TouchableOpacity>
|
|
)
|
|
}
|
|
|
|
completeModal = () => {
|
|
return (
|
|
<Modal
|
|
visible={this.state.completeModal}
|
|
transparent
|
|
>
|
|
<View style={{
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
backgroundColor: '#00000090',
|
|
}}>
|
|
<View style={{
|
|
paddingVertical: 28,
|
|
paddingHorizontal: 23,
|
|
width: Theme.screen.w * .8,
|
|
alignItems: 'center',
|
|
backgroundColor: this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.border : Theme.colors.white,
|
|
borderRadius: 10
|
|
}}>
|
|
<Text style={{color: Theme.colors.primary, fontSize: 15, fontWeight: 'bold'}}>Transaction Completed!</Text>
|
|
<Image style={{height: 60, resizeMode: 'contain', marginTop: 15}} source={Assets.logo.round} />
|
|
<Text style={{marginTop: 10, color: this.props.app_theme?.theme.colors.text, fontWeight: 'bold', marginBottom: 30, fontSize: 15}}>{Theme.formatter.NAME(this.props.userinfo.data)}</Text>
|
|
<Text style={{marginTop: 10, color: this.props.app_theme?.theme.colors.text, fontSize: 15}}>You have received</Text>
|
|
<Text style={{marginTop: 10, color: this.props.app_theme?.theme.colors.text, fontSize: 15, fontWeight: 'bold'}}>{Theme.formatter.CRNCY((this.state.amount + ((this.state.amount / 100) * this.state.rate)))} POINTS</Text>
|
|
<TouchableOpacity onPress={() => {
|
|
this.setState({ completeModal: false });
|
|
this.props.navigation.goBack()
|
|
}} style={{paddingHorizontal: 35, paddingVertical: 4, backgroundColor: Theme.colors.primary, borderRadius: 12, marginTop: 20}}>
|
|
<Text style={{color: Theme.colors.white, fontSize: 15}}>OK</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</Modal>
|
|
)
|
|
}
|
|
|
|
render() {
|
|
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.completeModal()}
|
|
<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: this.props.app_theme?.theme.dark ? "black" : Theme.colors.white }}>
|
|
<View style={{flexDirection: 'row', padding: 15, backgroundColor: Theme.colors.midnight}}>
|
|
<View style={{flex: 1}}>
|
|
<Text style={{fontFamily: 'Arial', fontSize: 16, color: '#fff'}}>Select Top-Up Value Points</Text>
|
|
</View>
|
|
</View>
|
|
<Elements.shadowView style={{backgroundColor: this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.border : Theme.colors.white, marginVertical: 10, marginHorizontal: 15, alignItems: 'center', paddingVertical: 10}}>
|
|
<Text style={{fontSize: 13, color: Theme.colors.soda, fontWeight: 'bold'}}>Get extra {this.state.rate} points for every 100 points top-up!</Text>
|
|
<AdjustableText style={{fontSize: 11, color: Theme.colors.soda}}>You can buy a maximum of 50,000 points per day</AdjustableText>
|
|
</Elements.shadowView>
|
|
<View style={{flexDirection: 'column', padding: 20, paddingTop: 0, 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: 1}}>
|
|
<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: 1}}>
|
|
<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: 1}}>
|
|
<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: 1}}>
|
|
<Text style={{textAlign: 'center', fontFamily: 'Arial', fontSize: 16, color: Theme.colors.primary}}>5000</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={{padding: 15, paddingTop: 0}}>
|
|
<Input
|
|
keyboardType="numeric"
|
|
placeholder="PHP"
|
|
placeholderTextColor={Theme.colors.textPrimary}
|
|
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 }}
|
|
/>
|
|
</View>
|
|
|
|
<View style={{flexDirection: 'row', padding: 15, backgroundColor: Theme.colors.midnight}}>
|
|
<View style={{flex: 1}}>
|
|
<Text style={{fontFamily: 'Arial', fontSize: 16, color: '#fff'}}>Payment Method</Text>
|
|
</View>
|
|
</View>
|
|
|
|
{this.returnCard()}
|
|
|
|
<View style={{marginBottom:60}}></View>
|
|
</View>
|
|
</ScrollView>
|
|
{this.state.topupCount >= 5 ? null :
|
|
<TouchableOpacity
|
|
disabled={this.state.selectedCreditCard ? false : true}
|
|
style={{justifyContent: 'center', marginHorizontal: 15, paddingVertical: 15, borderRadius: 10, backgroundColor: this.state.selectedCreditCard ? Theme.colors.primary : this.props.app_theme?.theme.dark ? this.props.app_theme?.theme.colors.border : Theme.colors.primary + "15", marginBottom: 16}}
|
|
onPress={() => this.validate()}>
|
|
<Text style={{fontSize: 16, fontFamily: 'Arial', textAlign: 'center', color: '#fff'}}>Proceed</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,
|
|
openModal
|
|
}
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(TopUp);
|