├── assets ├── icon.png ├── favicon.png ├── splash.png └── adaptive-icon.png ├── babel.config.js ├── README.md ├── .gitignore ├── .expo-shared └── assets.json ├── server ├── package.json └── index.js ├── App.js ├── package.json ├── app.json └── src └── StripeApp.js /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathvarun/Expo-Stripe-Tutorial/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathvarun/Expo-Stripe-Tutorial/HEAD/assets/favicon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathvarun/Expo-Stripe-Tutorial/HEAD/assets/splash.png -------------------------------------------------------------------------------- /assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathvarun/Expo-Stripe-Tutorial/HEAD/assets/adaptive-icon.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Expo-Stripe-Tutorial 2 | Project Files for Expo Stripe Tutorial 3 | 4 | - [Expo Stripe | Card Payments ](https://youtu.be/DZlAET7Tgx4) 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | npm-debug.* 4 | *.jks 5 | *.p8 6 | *.p12 7 | *.key 8 | *.mobileprovision 9 | *.orig.* 10 | web-build/ 11 | 12 | # macOS 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /.expo-shared/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, 3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true 4 | } 5 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "type": "module", 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "express": "^4.17.1", 15 | "nodemon": "^2.0.7" 16 | }, 17 | "dependencies": { 18 | "stripe": "^8.154.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import { StatusBar } from "expo-status-bar"; 2 | import React from "react"; 3 | import { StyleSheet, Text, View } from "react-native"; 4 | import StripeApp from "./src/StripeApp"; 5 | import { StripeProvider } from "@stripe/stripe-react-native"; 6 | export default function App() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | 14 | const styles = StyleSheet.create({ 15 | container: { 16 | flex: 1, 17 | backgroundColor: "#fff", 18 | alignItems: "center", 19 | justifyContent: "center", 20 | }, 21 | }); 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "web": "expo start --web", 8 | "eject": "expo eject" 9 | }, 10 | "dependencies": { 11 | "@stripe/stripe-react-native": "0.1.1", 12 | "expo": "~41.0.1", 13 | "expo-status-bar": "~1.0.4", 14 | "react": "16.13.1", 15 | "react-dom": "16.13.1", 16 | "react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz", 17 | "react-native-web": "~0.13.12" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.9.0" 21 | }, 22 | "private": true 23 | } 24 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "expo-stripe-youtube", 4 | "slug": "expo-stripe-youtube", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "splash": { 9 | "image": "./assets/splash.png", 10 | "resizeMode": "contain", 11 | "backgroundColor": "#ffffff" 12 | }, 13 | "updates": { 14 | "fallbackToCacheTimeout": 0 15 | }, 16 | "assetBundlePatterns": [ 17 | "**/*" 18 | ], 19 | "ios": { 20 | "supportsTablet": true 21 | }, 22 | "android": { 23 | "adaptiveIcon": { 24 | "foregroundImage": "./assets/adaptive-icon.png", 25 | "backgroundColor": "#FFFFFF" 26 | } 27 | }, 28 | "web": { 29 | "favicon": "./assets/favicon.png" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | 3 | const app = express(); 4 | const port = 3000; //add your port here 5 | const PUBLISHABLE_KEY = "ADD_PUBLISHABLE KEY HERE"; 6 | const SECRET_KEY = "ADD_SECRETE KEY HERE"; 7 | import Stripe from "stripe"; 8 | 9 | //Confirm the API version from your stripe dashboard 10 | const stripe = Stripe(SECRET_KEY, { apiVersion: "2020-08-27" }); 11 | 12 | app.listen(port, () => { 13 | console.log(`Example app listening at http://localhost:${port}`); 14 | }); 15 | 16 | app.post("/create-payment-intent", async (req, res) => { 17 | try { 18 | const paymentIntent = await stripe.paymentIntents.create({ 19 | amount: 1099, //lowest denomination of particular currency 20 | currency: "usd", 21 | payment_method_types: ["card"], //by default 22 | }); 23 | 24 | const clientSecret = paymentIntent.client_secret; 25 | 26 | res.json({ 27 | clientSecret: clientSecret, 28 | }); 29 | } catch (e) { 30 | console.log(e.message); 31 | res.json({ error: e.message }); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /src/StripeApp.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { View, Text, StyleSheet, TextInput, Button, Alert } from "react-native"; 3 | import { CardField, useConfirmPayment } from "@stripe/stripe-react-native"; 4 | 5 | //ADD localhost address of your server 6 | const API_URL = "http://localhost:3000"; 7 | 8 | const StripeApp = props => { 9 | const [email, setEmail] = useState(); 10 | const [cardDetails, setCardDetails] = useState(); 11 | const { confirmPayment, loading } = useConfirmPayment(); 12 | 13 | const fetchPaymentIntentClientSecret = async () => { 14 | const response = await fetch(`${API_URL}/create-payment-intent`, { 15 | method: "POST", 16 | headers: { 17 | "Content-Type": "application/json", 18 | }, 19 | }); 20 | const { clientSecret, error } = await response.json(); 21 | return { clientSecret, error }; 22 | }; 23 | 24 | const handlePayPress = async () => { 25 | //1.Gather the customer's billing information (e.g., email) 26 | if (!cardDetails?.complete || !email) { 27 | Alert.alert("Please enter Complete card details and Email"); 28 | return; 29 | } 30 | const billingDetails = { 31 | email: email, 32 | }; 33 | //2.Fetch the intent client secret from the backend 34 | try { 35 | const { clientSecret, error } = await fetchPaymentIntentClientSecret(); 36 | //2. confirm the payment 37 | if (error) { 38 | console.log("Unable to process payment"); 39 | } else { 40 | const { paymentIntent, error } = await confirmPayment(clientSecret, { 41 | type: "Card", 42 | billingDetails: billingDetails, 43 | }); 44 | if (error) { 45 | alert(`Payment Confirmation Error ${error.message}`); 46 | } else if (paymentIntent) { 47 | alert("Payment Successful"); 48 | console.log("Payment successful ", paymentIntent); 49 | } 50 | } 51 | } catch (e) { 52 | console.log(e); 53 | } 54 | //3.Confirm the payment with the card details 55 | }; 56 | 57 | return ( 58 | 59 | setEmail(value.nativeEvent.text)} 64 | style={styles.input} 65 | /> 66 | { 74 | setCardDetails(cardDetails); 75 | }} 76 | /> 77 |