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

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);