I'm trying test a payment using stripe for my react native project. But when I press the pay button i get an error stating. since there is not an official doc for stripe for react native, its been challenging
here the error
TypeError: null is not an object (evaluating 'StripeBridge.createPayment')
onPaymentPress
PaymentScreen.js:17:33
what that error mean exactly and how do I remove it?
essentially my goal is for the user to make a one time payment once they enter their details and press the pay button
here is my code
import React, { useState } from 'react'
import { Image, Text, TextInput, TouchableOpacity, View,ImageBackground,NativeModules} from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import styles from './styles';
var StripeBridge = NativeModules.StripeBridge;
export default function PaymentScreen({navigation}) {
const [ccNumber, setCCNumber] = useState('')
const [month, setMonth] = useState('')
const [year, setYear] = useState('')
const [zipCode, setZipCode] = useState('')
const [cvv, setCvv] = useState('')
const onPaymentPress = () => {
fetch('http://localhost:3001/createStripePaymentIntent', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(responseJson => {
console.log(responseJson.setupIntentId);
StripeBridge.createPayment(
responseJson.setupIntentId,
ccNumber,
month,
year,
cvv,
zipCode,
(error, res, payment_method) => {
if (res == 'SUCCESS') {
Alert.alert('Stripe Payment', 'Your Stripe payment succeeded', [
{text: 'OK', onPress: () => console.log('OK Pressed')},
]);
}
},
);
})
.catch(error => {
console.error(error);
});
// setTimeout(navigation.navigate("Products"), 1000)
}
return (
</View>
......
style={styles.button}
onPress={() => onPaymentPress()}>
<Text style={styles.buttonTitle}>Submit Payment</Text>
</TouchableOpacity>
<View style={styles.footerView}>
<Text style={styles.footerText}> Payment secured by Stripe <Text style={styles.footerLink}></Text></Text>
</View>
</KeyboardAwareScrollView>
</View>
</ImageBackground>
)
}
Related
I am developing a mobile application with React Native. With this application, I connect to salesforce and make transactions.
I created Platform Events on Salesforce side and I want React Native Component to subscribe to it.
I can't use lightning/empApi or CometD because I don't code web. According to the document, my only option is Pub/Sub API.
I tried to pull it directly with FETCH but with no result.
import {View, Text} from 'react-native';
import React, { useEffect, useState } from 'react';
import { Force, oauth } from 'react-native-force';
function History() {
const [session, setSession] = useState()
const eventName = "Test_PE__e";
const replayId = -1;
const [subscription, setSubscription] = React.useState();
useEffect(() => {
oauth.getAuthCredentials(
(data) => console.log(data), // already logged in
() => {
oauth.authenticate(
() => setSession(data),
(error) => console.log('Failed to authenticate:' + error)
);
});
},[]);
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text> Subscribed to {eventName} </Text>
</View>
);
async function setPEvents(session) {
const headers = new Headers({
'Authorization': `Bearer ${session.accessToken}`,
'Content-Type': 'application/json'
});
const body = {
"event": `/event/${eventName}`,
"replayId": replayId
};
const url = `${session.instanceUrl}/services/data/v57.0/event/${eventName}/subscriptions`;
const requestOptions = {
method: 'POST',
headers: headers,
body: JSON.stringify(body)
};
const resp = await fetch(url, requestOptions)
.then(async (response) => {
console.log(response);
return await response.json();
})
.catch(error => console.log('Error:', error));
setSubscription(resp);
console.log("FIRATTT");
console.log("Result:",resp);
}
}
export default History;
What can I do to subscribe?
Or how can I use the SalesForce Pub/Sub API in React Native?
i'm trying to navigate from once a user inputs their Credit card details and presses to the pay button, it takes them to another screen within my app. I've set the navigation path to a screen called products. However my payment function takes the payment via Stripe but doesn't navigate to the next screen.what am i doing wrong?
Here is my payment function
import React, { useState } from 'react'
import { Image, Text, TextInput, TouchableOpacity, View,ImageBackground } from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import styles from './styles';
import stripe from 'tipsi-stripe';
import axios from 'axios'
stripe.setOptions({
publishableKey:
'pk_test_XXXXX'
})
export default function PaymentScreen({navigation}) {
const [ccNumber, setCCNumber] = useState('')
const [expDate, setExpDate] = useState('')
const [zipCode, setZipCode] = useState('')
const [cvv, setCvv] = useState('')
const [ loading, setLoading] = useState(false)
const [token, setToken] = useState(null)
const onPaymentPress = async () => {
if ( ccNumber && expDate && zipCode && cvv == null) {
alert("All fields must be completed")
return
};
const token = await stripe.paymentRequestWithCardForm({
smsAutofillDisabled: true,
requiredBillingAddressFields: 'full',
prefilledInformation: {
billingAddress: {
name: 'Gunilla Haugeh',
line1: 'Canary Place',
line2: '3',
city: 'Macon',
state: 'Georgia',
country: 'US',
postalCode: '31217',
email: 'ghaugeh0#printfriendly.com',
},
},
})
axios({
method:'POST',
url: 'https://us-central1-lvc2-73300.cloudfunctions.net/completePaymentWithStripe',
data: {
amount: 50000,
currency:'usd',
token: token
},
})
.then(response => {
console.log(response);
loading:false
})
navigation.navigate('Products',{token})
}
here is my on press function to activate the payment
<TouchableOpacity
style={styles.button}
onPress={() => onPaymentPress()}>
<Text style={styles.buttonTitle}>Submit Payment</Text>
</TouchableOpacity>
also i'm using firebase to store the data
Here is my database firebase backend
const stripe = require('stripe')('sk_test_XXXX)
exports.completePaymentWithStripe = functions.https.onRequest(
(request,response) => {
stripe.charges.create({
amount: request.body.amount,
currency: request.body.currency,
source: request.body.token.tokenId,
})
.then(charge => {
response.send(charge)
return null
})
.catch(error => {
console.log(error)
})
}
)
In my project I have many users and many resources (and many user_resources/the join between users and resources).When I POST to user_resources I see it work on my rails backend (as in I see that instance posted) but in my react native front end I don't see it listed upon update. However, once the app is completely refresh (when I stop and restart the expo server), I finally see those items rendered. ANY IDEAS? I've been working on this forever now to no avail and my project is due tmrw, so any help is appreciated.
screen where I post to user_resources:
import React from 'react';
import { ScrollView,SafeAreaView,StyleSheet, Text, View, FlatList, TouchableOpacity,Button, NativeEventEmitter} from 'react-native';
import {connect} from 'react-redux';
import {fetchResources,searchChanged} from '../actions';
import { addUserResource } from '../actions'
import {SearchBar} from 'react-native-elements';
import { MaterialIcons } from '#expo/vector-icons';
import { MaterialCommunityIcons } from '#expo/vector-icons';
class ResourcesScreen extends React.Component {
state = {
search: ''
}
componentDidMount = () =>{
this.props.fetchResources();
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 0.5,
width: "100%",
backgroundColor: "lightblue",
}}
/>
);
}
handlePress(item) {
debugger
fetch('http://localhost:3000/user_resources', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify({
resource_id: item.id,
user_id: this.props.users.id,
name: item.name,
description:item.description,
link:item.link,
})
})
.then(res => res.json())
.then(data2 => {
console.log(data2)
this.props.addUserResource(data2)
console.log(this.props)
})
}
header = () => {
return <View>
<Text style={styles.header}>Resources</Text>
</View>
}
onSearchChange = text => {
this.setState({search:text})
}
render(){
return(
<SafeAreaView>
<SearchBar placeholderTextColor="white" placeholder="Enter resource name here" onChangeText={this.onSearchChange} value={this.state.search}/>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Add A New Resource',{topicId:this.props.route.params.topicId})} style={styles.buttonitem}>
<Text style={styles.text}>
<MaterialIcons name="add-circle-outline" size={24} color="white"/>Add A New Resource
</Text>
</TouchableOpacity>
<FlatList keyExtractor={(item)=> item.id.toString()} data={this.props.resourceName} ItemSeparatorComponent = { this.FlatListItemSeparator } renderItem={({item}) => {
return <TouchableOpacity style={styles.material2}>
<Text onPress={() => this.props.navigation.navigate('Add A New Resource',{topicId:item.id})} style={styles.listitem}>{item.name}</Text>
<MaterialCommunityIcons name="bookmark-plus" size={50} color="#16a085" backgroundColor='black' onPress={()=>this.handlePress(item)}/>
</TouchableOpacity>
}}
ListHeaderComponent = {this.header}/>
</SafeAreaView>
)
}
}
const mapStateToProps = (state) => {
return {
resourceName: state.resourceReducer.resources,
users: state.userReducer,
search:state.resourceReducer.searchTerm
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchResources: () => dispatch(fetchResources()),
addUserResource,
searchChanged
}
}
export default connect(mapStateToProps,mapDispatchToProps)(ResourcesScreen)
After this I head to the profile page where the user_resources SHOULD be displayed, but aren't
import React from 'react';
import { ScrollView,StyleSheet, Text, View, FlatList, TouchableOpacity} from 'react-native';
import {connect} from 'react-redux';
import {SearchBar} from 'react-native-elements';
import { AntDesign } from '#expo/vector-icons';
class Profile extends React.Component{
handleDelete = (id) => {
debugger
fetch(`http://localhost:3000/user_resources/${id}`, {
method: "DELETE",
headers: {
"Authorization": this.props.users.token
}
})
.then(r => r.json())
.then((delResource) => {
console.log(delResource)
this.props.deleteOneFood(delResource)
console.log('deleted')
this.forceUpdate()
})
}
render(){
return(
<View>
{this.props.users.user_resources.map(singleResource=> {
return <Text key={singleResource.id}>{singleResource.name}</Text>
})}
</View>
)}
}
let deleteOneResource = (id) => {
return {
type: "DELETE_ONE_USER_RESOURCE",
payload: id
}
}
const mapDispatchToProps = {
deleteOneResource
}
const mapStateToProps = (state) => {
return {
users: state.userReducer,
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Profile)
I had a flatlist before but thought that may be causing the issues so rendered it another way, still no luck. I tried forceUpdates as well, still no luck. I'm not sure if the issue is coming from my reducer:
let userInitialState = {
id: 0,
username: "",
name: '',
category: '',
token: "",
user_resources:[],
}
let userReducer = (state = userInitialState, action) => {
switch(action.type){
case "ADD_USERS":
let singleNestedObject = {
...action.users.user,
token: action.users.token
}
return {
...state,
username: action.users.user.username,
token: action.users.token,
id: action.users.user.id,
name: action.users.user.name,
category: action.users.user.category,
user_resources: action.users.user.user_resources
}
case "ADD_ONE_USER_RESOURCE":
let copyOfResources = [...state.user_resources, action.userResources]
return {
...state,
user_resources: copyOfResources
}
default:
return state
}
}
and it's action
export const addUserResource = (resourceInfo) => {
return {
type: "ADD_ONE_USER_RESOURCE",
userResources: resourceInfo
}
}
Please help me find the issue here, I'm losing it.
I am using Expo for developing react-native applications.
I want to make an Infinite list, but every time onEndReached event is fired, FlatList is refreshed automatically scrolls to the top of the page!
import React, { useState, useEffect } from "react";
import { SafeAreaView, Text, FlatList } from "react-native";
export default function App() {
const [config, setConfig] = useState({
result: [],
page: 0
});
async function fetchData() {
const response = await fetch("http://192.168.2.49:3500/q", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({ page: config.page })
});
const data = await response.json();
setConfig({
result: [...config.result, ...data],
page: config.page++
});
}
const onEndReached = async () => {
await setConfig({
page: config.page++
});
fetchData();
};
useEffect(() => {
fetchData();
}, []);
return (
<SafeAreaView>
<Text>Current Page : {config.page}</Text>
<FlatList
data={config.result}
renderItem={o => <Text>X :{o.item.t.c}</Text>}
keyExtractor={item => item._id}
onEndReached={() => onEndReached()}
onEndReachedThreshold={0}
></FlatList>
</SafeAreaView>
);
}
You are calling setConfig twice, before calling fetchData and after a successful API request. Which triggers a rerender.
I refactored your code, try this.
import React, { useState, useEffect, useCallback } from 'react';
import {
SafeAreaView,
Text,
FlatList,
NativeSyntheticEvent,
NativeScrollEvent,
} from 'react-native';
export default function App() {
const [config, setConfig] = useState({
result: [],
page: 0,
});
const [isScrolled, setIsScrolled] = useState(false);
const fetchData = useCallback(() => {
async function runFetch() {
const response = await fetch('http://192.168.2.49:3500/q', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ page: config.page }),
});
const data = await response.json();
setConfig({
result: [...config.result, ...data],
page: config.page++,
});
}
runFetch();
}, [config.page, config.result]);
const onEndReached = useCallback(() => fetchData(), [fetchData]);
const onScroll = useCallback(
e => setIsScrolled(e.nativeEvent.contentOffset.y > 0),
[],
);
useEffect(() => {
fetchData();
}, [fetchData]);
return (
<SafeAreaView>
<Text>Current Page : {config.page}</Text>
<FlatList
data={config.result}
keyExtractor={item => item._id}
onEndReached={onEndReached}
onEndReachedThreshold={0.1}
onScroll={onScroll}
renderItem={o => <Text>X :{o.item.t.c}</Text>}
/>
</SafeAreaView>
);
}
I'm trying to add an email address to a mailchimp list I have.
This is for a react native app and I'm trying to implement the request using fetch.
This is my code within the component:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { connect } from 'react-redux';
import { emailChanged, nameChanged, addToWaitingList } from '../actions';
import { Card, CardSection, Input, Button, Spinner } from '../components/Auth';
class addToWaitingListForm extends Component {
onEmailChange(text) {
this.props.emailChanged(text);
}
onButtonPress() {
const { email } = this.props;
this.props.addToWaitingList({ email });
}
renderButton() {
if (this.props.loading) {
return <Spinner size="large" />;
}
return (
<Button onPress={this.onButtonPress.bind(this)}>
Keep me in the loop!
</Button>
);
}
render() {
return (
<View>
<Card>
<CardSection>
<Input
placeholder="your name"
onChangeText={this.onNameChange.bind(this)}
value={this.props.name}
/>
</CardSection>
<CardSection>
<Input
placeholder="email#uni.ac.uk"
onChangeText={this.onEmailChange.bind(this)}
value={this.props.email}
/>
</CardSection>
<Text style={styles.errorTextStyle}>
{this.props.error}
</Text>
<CardSection style={{ borderBottomWidth: 0 }}>
{this.renderButton()}
</CardSection>
</Card>
</View>
);
}
}
const mapStateToProps = ({ auth }) => {
const { email, name, error, loading } = auth;
return { email, name, error, loading };
};
export default connect(mapStateToProps, {
emailChanged,
addToWaitingList
})(addToWaitingListForm);
Add this is my action code for interacting with the mailchimp api:
import Router from '../../navigation/Router';
import { getNavigationContext } from '../../navigation/NavigationContext';
export const addToWaitingList = ({ email }) => {
const emailListID = 'e100c8fe03';
fetch(`https://us13.api.mailchimp.com/3.0/lists/${emailListID}/members/`, {
method: 'POST',
body: JSON.stringify({
'email_address': email,
'status': 'subscribed',
'merge_fields': {
'FNAME': 'Urist',
'LNAME': 'McVankab'
}
})
})
.then(() => addSubscriberSuccess())
.catch(error => console.log(error));
};
const addSubscriberSuccess = () => {
getNavigationContext().getNavigator('root').immediatelyResetStack([Router.getRoute('auth')]);
};
Right now, the error I'm just getting back is ExceptionsManager.js:62 Cannot read property 'type' of undefined and Error: unsupported BodyInit type
What does this mean and how can I fix this?
You need to do two things.
First off you need to send the basic authentication via fetch so you cant do "user:pass" You have to convert it with btoa('user:pass').
Then you have to send it with mode: 'no-cors'
let authenticationString = btoa('randomstring:ap-keyxxxxxxx-us9');
authenticationString = "Basic " + authenticationString;
fetch('https://us9.api.mailchimp.com/3.0/lists/111111/members', {
mode: 'no-cors',
method: 'POST',
headers: {
'authorization': authenticationString,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email_address: "dude#gmail.com",
status: "subscribed",
})
}).then(function(e){
console.log("fetch finished")
}).catch(function(e){
console.log("fetch error");
})