Stripe 45 min
parent
742024ab35
commit
3565652962
2
.env
2
.env
|
@ -2,3 +2,5 @@ EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_bWVhc3VyZWQtcGFudGhlci04Mi5jbGVyay5hY2
|
||||||
DATABASE_URL=postgresql://jsm_uber_owner:npg_wsprVk4dJ8XW@ep-rapid-field-a1prd9ss-pooler.ap-southeast-1.aws.neon.tech/jsm_uber?sslmode=require
|
DATABASE_URL=postgresql://jsm_uber_owner:npg_wsprVk4dJ8XW@ep-rapid-field-a1prd9ss-pooler.ap-southeast-1.aws.neon.tech/jsm_uber?sslmode=require
|
||||||
EXPO_PUBLIC_GEOAPIFY_API_KEY=0e7ccfac62054b0f846032bff6bae5c9
|
EXPO_PUBLIC_GEOAPIFY_API_KEY=0e7ccfac62054b0f846032bff6bae5c9
|
||||||
EXPO_PUBLIC_GOOGLE_API_KEY=AIzaSyD10tc4ec2FFVXQcWDXCT2CeBy-jwbRZB8
|
EXPO_PUBLIC_GOOGLE_API_KEY=AIzaSyD10tc4ec2FFVXQcWDXCT2CeBy-jwbRZB8
|
||||||
|
EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51RBCg0EEiRKTsjR3t4krSuirMpl6cf28QcyIpMlWD6eIZoU9qBCGBhoSwr9zlRLEQsoUwCusZupgnOMmOAyYG19U00S86heUPX
|
||||||
|
STRIPE_SECRET_KEY=sk_test_51RBCg0EEiRKTsjR3wFKcVMiOhedbosVqKnl5fCYhTDsQkXZVx7UJqUiXRu6b9ghbP6yrqMnom1GePKtUAgVl9twg00dJzPIgBz
|
|
@ -5,21 +5,26 @@ import RideLayout from "@/components/RideLayout";
|
||||||
import {icons} from "@/constants";
|
import {icons} from "@/constants";
|
||||||
import {formatTime} from "@/lib/utils";
|
import {formatTime} from "@/lib/utils";
|
||||||
import {useDriverStore, useLocationStore} from "@/store";
|
import {useDriverStore, useLocationStore} from "@/store";
|
||||||
|
import Payment from "@/components/Payment";
|
||||||
|
import { StripeProvider } from '@stripe/stripe-react-native';
|
||||||
|
|
||||||
const BookRide = () => {
|
const BookRide = () => {
|
||||||
const {user} = useUser();
|
const {user} = useUser();
|
||||||
const {userAddress, destinationAddress} = useLocationStore();
|
const {userAddress, destinationAddress} = useLocationStore();
|
||||||
const {drivers, selectedDriver} = useDriverStore();
|
const {drivers, selectedDriver} = useDriverStore();
|
||||||
console.log(drivers);
|
|
||||||
console.log(selectedDriver);
|
|
||||||
const driverDetails = drivers?.filter(
|
const driverDetails = drivers?.filter(
|
||||||
(driver) => +driver.id === selectedDriver,
|
(driver) => +driver.id === selectedDriver,
|
||||||
)[0];
|
)[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<StripeProvider
|
||||||
|
publishableKey={process.env.EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY!}
|
||||||
|
merchantIdentifier="merchant.identifier" // required for Apple Pay
|
||||||
|
urlScheme="your-url-scheme" // required for 3D Secure and bank redirects
|
||||||
|
>
|
||||||
<RideLayout title="Book Ride">
|
<RideLayout title="Book Ride">
|
||||||
<>
|
<>
|
||||||
<Text style={tw`text-xl font-JakartaSemiBold mb-3`}>
|
<Text style={tw`text-xl font-JakartaSemiBold mb-3`} >
|
||||||
Ride Information
|
Ride Information
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
@ -87,8 +92,16 @@ const BookRide = () => {
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
<Payment
|
||||||
|
fullName={user?.fullName!}
|
||||||
|
email={user?.emailAddresses[0].emailAddress!}
|
||||||
|
amount={driverDetails?.price!}
|
||||||
|
driverId={driverDetails?.id!}
|
||||||
|
rideTime={driverDetails?.time!}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
</RideLayout>
|
</RideLayout>
|
||||||
|
</StripeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import {Stripe} from "stripe";
|
||||||
|
|
||||||
|
const stripe = new Stripe(process.env.STRIPE_SERCET_KEY!);
|
||||||
|
export async function POST(request:Request) {
|
||||||
|
const body = await request.json();
|
||||||
|
const { name, email, amount} = body;
|
||||||
|
if(!name || !email || !amount){
|
||||||
|
return new Response (JSON.stringify({error:"please enter a valid email Address",status:400}))
|
||||||
|
}
|
||||||
|
let customer;
|
||||||
|
const existingCustomer = await stripe.customers.list({email});
|
||||||
|
if(existingCustomer.data.length > 0){
|
||||||
|
customer = existingCustomer.data[0];
|
||||||
|
}else{
|
||||||
|
const newCustomer = await stripe.customers.create({
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
});
|
||||||
|
customer = newCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ephemeralKey = await stripe.ephemeralKeys.create(
|
||||||
|
{customer: customer.id},
|
||||||
|
{apiVersion: '2025-03-31.basil'}
|
||||||
|
);
|
||||||
|
const paymentIntent = await stripe.paymentIntents.create({
|
||||||
|
amount: parseInt(amount) * 100,
|
||||||
|
currency: 'usd',
|
||||||
|
customer: customer.id,
|
||||||
|
automatic_payment_methods: {
|
||||||
|
enabled: true,
|
||||||
|
allow_redirects:"never",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(JSON.stringify({
|
||||||
|
paymentIntent: paymentIntent.client_secret,
|
||||||
|
ephemeralKey: ephemeralKey.secret,
|
||||||
|
customer: customer.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
import {Stripe} from "stripe";
|
||||||
|
|
||||||
|
const stripe = new Stripe(process.env.STRIPE_SERCET_KEY!);
|
||||||
|
export async function POST(request:Request) {
|
||||||
|
try {
|
||||||
|
const body = await request.json();
|
||||||
|
const { payment_method_id,payment_intent_id,customer_id} = body;
|
||||||
|
if(!payment_method_id || !payment_intent_id || !customer_id) {
|
||||||
|
return new Response (
|
||||||
|
JSON.stringify({
|
||||||
|
error:"Missing required payment infomation",
|
||||||
|
status:400
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const paymentMethod = await stripe.paymentMethods.attach(payment_method_id,{customer:customer_id});
|
||||||
|
const result = await stripe.paymentIntents.confirm(payment_intent_id,{payment_method:paymentMethod.id,});
|
||||||
|
return new Response (
|
||||||
|
JSON.stringify({
|
||||||
|
success:true,
|
||||||
|
message:"Payment confirmed successfully",result:result,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
error:error,
|
||||||
|
status:500,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { data } from "@/constants";
|
||||||
|
import { neon } from "@neondatabase/serverless";
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
const sql = neon(`${process.env.DATABASE_URL}`);
|
||||||
|
const response = await sql`SELECT * FROM drivers`;
|
||||||
|
return Response.json({data:response})
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return Response.json({error:error});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import {neon} from "@neondatabase/serverless";
|
||||||
|
|
||||||
|
export async function GET(request: Request, {id}: { id: string }) {
|
||||||
|
if (!id)
|
||||||
|
return Response.json({error: "Missing required fields"}, {status: 400});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const sql = neon(`${process.env.DATABASE_URL}`);
|
||||||
|
const response = await sql`
|
||||||
|
SELECT
|
||||||
|
rides.ride_id,
|
||||||
|
rides.origin_address,
|
||||||
|
rides.destination_address,
|
||||||
|
rides.origin_latitude,
|
||||||
|
rides.origin_longitude,
|
||||||
|
rides.destination_latitude,
|
||||||
|
rides.destination_longitude,
|
||||||
|
rides.ride_time,
|
||||||
|
rides.fare_price,
|
||||||
|
rides.payment_status,
|
||||||
|
rides.created_at,
|
||||||
|
'driver', json_build_object(
|
||||||
|
'driver_id', drivers.id,
|
||||||
|
'first_name', drivers.first_name,
|
||||||
|
'last_name', drivers.last_name,
|
||||||
|
'profile_image_url', drivers.profile_image_url,
|
||||||
|
'car_image_url', drivers.car_image_url,
|
||||||
|
'car_seats', drivers.car_seats,
|
||||||
|
'rating', drivers.rating
|
||||||
|
) AS driver
|
||||||
|
FROM
|
||||||
|
rides
|
||||||
|
INNER JOIN
|
||||||
|
drivers ON rides.driver_id = drivers.id
|
||||||
|
WHERE
|
||||||
|
rides.user_id = ${id}
|
||||||
|
ORDER BY
|
||||||
|
rides.created_at DESC;
|
||||||
|
`;
|
||||||
|
|
||||||
|
return Response.json({data: response});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching recent rides:", error);
|
||||||
|
return Response.json({error: "Internal Server Error"}, {status: 500});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
import {neon} from "@neondatabase/serverless";
|
||||||
|
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
try {
|
||||||
|
const body = await request.json();
|
||||||
|
const {
|
||||||
|
origin_address,
|
||||||
|
destination_address,
|
||||||
|
origin_latitude,
|
||||||
|
origin_longitude,
|
||||||
|
destination_latitude,
|
||||||
|
destination_longitude,
|
||||||
|
ride_time,
|
||||||
|
fare_price,
|
||||||
|
payment_status,
|
||||||
|
driver_id,
|
||||||
|
user_id,
|
||||||
|
} = body;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!origin_address ||
|
||||||
|
!destination_address ||
|
||||||
|
!origin_latitude ||
|
||||||
|
!origin_longitude ||
|
||||||
|
!destination_latitude ||
|
||||||
|
!destination_longitude ||
|
||||||
|
!ride_time ||
|
||||||
|
!fare_price ||
|
||||||
|
!payment_status ||
|
||||||
|
!driver_id ||
|
||||||
|
!user_id
|
||||||
|
) {
|
||||||
|
return Response.json(
|
||||||
|
{error: "Missing required fields"},
|
||||||
|
{status: 400},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sql = neon(`${process.env.DATABASE_URL}`);
|
||||||
|
|
||||||
|
const response = await sql`
|
||||||
|
INSERT INTO rides (
|
||||||
|
origin_address,
|
||||||
|
destination_address,
|
||||||
|
origin_latitude,
|
||||||
|
origin_longitude,
|
||||||
|
destination_latitude,
|
||||||
|
destination_longitude,
|
||||||
|
ride_time,
|
||||||
|
fare_price,
|
||||||
|
payment_status,
|
||||||
|
driver_id,
|
||||||
|
user_id
|
||||||
|
) VALUES (
|
||||||
|
${origin_address},
|
||||||
|
${destination_address},
|
||||||
|
${origin_latitude},
|
||||||
|
${origin_longitude},
|
||||||
|
${destination_latitude},
|
||||||
|
${destination_longitude},
|
||||||
|
${ride_time},
|
||||||
|
${fare_price},
|
||||||
|
${payment_status},
|
||||||
|
${driver_id},
|
||||||
|
${user_id}
|
||||||
|
)
|
||||||
|
RETURNING *;
|
||||||
|
`;
|
||||||
|
|
||||||
|
return Response.json({data: response[0]}, {status: 201});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error inserting data into recent_rides:", error);
|
||||||
|
return Response.json({error: "Internal Server Error"}, {status: 500});
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ const DriverCard = ({item, selected, setSelected}: DriverCardProps) => {
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text style={tw`text-sm font-JakartaRegular text-general-800`}>
|
<Text style={tw`text-sm font-JakartaRegular text-general-800`}>
|
||||||
{formatTime(item.time!)}
|
{formatTime(parseInt(`${item.time}`) || 5)}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text style={tw`text-sm font-JakartaRegular text-general-800 mx-1`}>
|
<Text style={tw`text-sm font-JakartaRegular text-general-800 mx-1`}>
|
||||||
|
|
|
@ -1,65 +1,49 @@
|
||||||
import { useDriverStore, useLocationStore } from "@/store";
|
import { useDriverStore, useLocationStore } from "@/store";
|
||||||
import { View, Text } from "react-native";
|
import { calculateDriverTimes, calculateRegion, generateMarkersFromData } from "@/lib/map";
|
||||||
import { calculateRegion, generateMarkersFromData } from "@/lib/map";
|
|
||||||
import MapView, { Marker, PROVIDER_DEFAULT } from "react-native-maps";
|
import MapView, { Marker, PROVIDER_DEFAULT } from "react-native-maps";
|
||||||
import tw from "twrnc";
|
import tw from "twrnc";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { MarkerData } from "@/types/type";
|
import { Driver, MarkerData } from "@/types/type";
|
||||||
import { icons } from "@/constants";
|
import { icons } from "@/constants";
|
||||||
const drivers = [
|
import { useFetch } from "@/lib/fetch";
|
||||||
{
|
import { ActivityIndicator, Text, View } from "react-native";
|
||||||
"id": "1",
|
|
||||||
"first_name": "James",
|
|
||||||
"last_name": "Wilson",
|
|
||||||
"profile_image_url": "https://ucarecdn.com/dae59f69-2c1f-48c3-a883-017bcf0f9950/-/preview/1000x666/",
|
|
||||||
"car_image_url": "https://ucarecdn.com/a2dc52b2-8bf7-4e49-9a36-3ffb5229ed02/-/preview/465x466/",
|
|
||||||
"car_seats": 4,
|
|
||||||
"rating": "4.80"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2",
|
|
||||||
"first_name": "David",
|
|
||||||
"last_name": "Brown",
|
|
||||||
"profile_image_url": "https://ucarecdn.com/6ea6d83d-ef1a-483f-9106-837a3a5b3f67/-/preview/1000x666/",
|
|
||||||
"car_image_url": "https://ucarecdn.com/a3872f80-c094-409c-82f8-c9ff38429327/-/preview/930x932/",
|
|
||||||
"car_seats": 5,
|
|
||||||
"rating": "4.60"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "3",
|
|
||||||
"first_name": "Michael",
|
|
||||||
"last_name": "Johnson",
|
|
||||||
"profile_image_url": "https://ucarecdn.com/0330d85c-232e-4c30-bd04-e5e4d0e3d688/-/preview/826x822/",
|
|
||||||
"car_image_url": "https://ucarecdn.com/289764fb-55b6-4427-b1d1-f655987b4a14/-/preview/930x932/",
|
|
||||||
"car_seats": 4,
|
|
||||||
"rating": "4.70"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "4",
|
|
||||||
"first_name": "Robert",
|
|
||||||
"last_name": "Green",
|
|
||||||
"profile_image_url": "https://ucarecdn.com/fdfc54df-9d24-40f7-b7d3-6f391561c0db/-/preview/626x417/",
|
|
||||||
"car_image_url": "https://ucarecdn.com/b6fb3b55-7676-4ff3-8484-fb115e268d32/-/preview/930x932/",
|
|
||||||
"car_seats": 4,
|
|
||||||
"rating": "4.90"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const Map = () => {
|
const Map = () => {
|
||||||
|
const { data: drivers, loading, error } = useFetch<Driver[]>("/(api)/driver");
|
||||||
const { userLongitude, userLatitude, destinationLatitude, destinationLongitude } = useLocationStore();
|
const { userLongitude, userLatitude, destinationLatitude, destinationLongitude } = useLocationStore();
|
||||||
const { selectedDriver, setDrivers } = useDriverStore();
|
const { selectedDriver, setDrivers } = useDriverStore();
|
||||||
const [markers, setMarkers] = useState<MarkerData[]>();
|
const [markers, setMarkers] = useState<MarkerData[]>([]);
|
||||||
const region = calculateRegion({
|
const region = calculateRegion({
|
||||||
userLongitude, userLatitude, destinationLatitude, destinationLongitude,
|
userLongitude, userLatitude, destinationLatitude, destinationLongitude,
|
||||||
});
|
});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// TODO:Remove
|
|
||||||
setDrivers(drivers);
|
|
||||||
if (Array.isArray(drivers)) {
|
if (Array.isArray(drivers)) {
|
||||||
if (!userLatitude || !userLongitude) return;
|
if (!userLatitude || !userLongitude) return;
|
||||||
const newMarkers = generateMarkersFromData({ data : drivers, userLatitude, userLongitude, });
|
const newMarkers = generateMarkersFromData({ data: drivers, userLatitude, userLongitude, });
|
||||||
setMarkers(newMarkers)
|
setMarkers(newMarkers);
|
||||||
|
}
|
||||||
|
}, [drivers]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (markers.length > 0 && destinationLatitude && destinationLongitude) {
|
||||||
|
calculateDriverTimes({ markers, userLongitude, userLatitude, destinationLatitude, destinationLongitude }).then((drivers) => {
|
||||||
|
setDrivers(drivers as MarkerData[]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [markers, destinationLatitude, destinationLongitude]);
|
||||||
|
if (loading || !userLatitude || !userLongitude) {
|
||||||
|
return (
|
||||||
|
<View style={tw`flex justify-between items-center w-full`}>
|
||||||
|
<ActivityIndicator size="small" color="#000" />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<View style={tw`flex justify-between items-center w-full`}>
|
||||||
|
<Text>Error:{error}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [drivers])
|
|
||||||
return (
|
return (
|
||||||
<MapView provider={PROVIDER_DEFAULT} style={tw`w-full h-full rounded-2xl `} tintColor="black" mapType="standard" showsPointsOfInterest={false} initialRegion={region} showsUserLocation={true} userInterfaceStyle="light" >
|
<MapView provider={PROVIDER_DEFAULT} style={tw`w-full h-full rounded-2xl `} tintColor="black" mapType="standard" showsPointsOfInterest={false} initialRegion={region} showsUserLocation={true} userInterfaceStyle="light" >
|
||||||
{markers?.map((marker) => (
|
{markers?.map((marker) => (
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { Alert, Text, View } from "react-native";
|
||||||
|
import CustomButton from "./CustomButton";
|
||||||
|
import tw from "twrnc";
|
||||||
|
import { PaymentMethod, PaymentSheetError, useStripe } from "@stripe/stripe-react-native";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { fetchAPI } from "@/lib/fetch";
|
||||||
|
import { PaymentProps } from "@/types/type";
|
||||||
|
const Payment = ({fullName,email,amount,driverId,rideTime}:PaymentProps) => {
|
||||||
|
const [success, setSuccess] = useState(false);
|
||||||
|
const { initPaymentSheet, presentPaymentSheet } = useStripe();
|
||||||
|
const confirmHandler = async (paymentMethod,_, intentCreationCallback) => {
|
||||||
|
const {paymentIntent,customer} = await fetchAPI("/(api)/(stripe)/create",{
|
||||||
|
method:"POST",
|
||||||
|
headers:{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body:JSON.stringify({
|
||||||
|
name:fullName || email.split("@")[0],
|
||||||
|
email: email,
|
||||||
|
amount: amount,
|
||||||
|
paymentMethodId : paymentMethod.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if(paymentIntent.client_sercet){
|
||||||
|
const {result} = await fetchAPI ("/(api)/(stripe)/pay",{
|
||||||
|
method:"POST",
|
||||||
|
headers:{
|
||||||
|
"Content-Type":"application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
payment_method_id:paymentMethod.id,
|
||||||
|
payment_intent_id:paymentIntent.id,
|
||||||
|
customer_id:customer,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
if (result.client_sercet) {
|
||||||
|
//ride/create
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { clientSercet, error } = await response.json();
|
||||||
|
if(clientSercet){
|
||||||
|
intentCreationCallback({clientSercet})
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
intentCreationCallback({error})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const initializePaymentSheet = async () => {
|
||||||
|
const { error } = await initPaymentSheet({
|
||||||
|
merchantDisplayName: "Example,Inc.",
|
||||||
|
intentConfiguration: {
|
||||||
|
mode: {
|
||||||
|
amount: 1099,
|
||||||
|
currencyCode: "USD",
|
||||||
|
},
|
||||||
|
confirmHandler: confirmHandler
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (error) {
|
||||||
|
//handle error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const openPaymentSheet = async () => {
|
||||||
|
await initializePaymentSheet();
|
||||||
|
|
||||||
|
const { error } = await presentPaymentSheet();
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
Alert.alert(`Error code: ${error.code}`, error.message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setSuccess(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CustomButton title="Confirm Ride" style={tw`my-10`} onPress={openPaymentSheet} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
export default Payment;
|
|
@ -15,6 +15,7 @@
|
||||||
"@neondatabase/serverless": "^0.10.4",
|
"@neondatabase/serverless": "^0.10.4",
|
||||||
"@react-navigation/bottom-tabs": "^7.2.0",
|
"@react-navigation/bottom-tabs": "^7.2.0",
|
||||||
"@react-navigation/native": "^7.0.14",
|
"@react-navigation/native": "^7.0.14",
|
||||||
|
"@stripe/stripe-react-native": "0.38.6",
|
||||||
"expo": "52.0.42",
|
"expo": "52.0.42",
|
||||||
"expo-blur": "~14.0.3",
|
"expo-blur": "~14.0.3",
|
||||||
"expo-constants": "~17.0.8",
|
"expo-constants": "~17.0.8",
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
"react-native-swiper": "^1.6.0",
|
"react-native-swiper": "^1.6.0",
|
||||||
"react-native-web": "~0.19.13",
|
"react-native-web": "~0.19.13",
|
||||||
"react-native-webview": "13.12.5",
|
"react-native-webview": "13.12.5",
|
||||||
|
"stripe": "^18.0.0",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"twrnc": "^4.6.1",
|
"twrnc": "^4.6.1",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
|
@ -4976,6 +4978,22 @@
|
||||||
"node": ">=12.16"
|
"node": ">=12.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@stripe/stripe-react-native": {
|
||||||
|
"version": "0.38.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@stripe/stripe-react-native/-/stripe-react-native-0.38.6.tgz",
|
||||||
|
"integrity": "sha512-U6yELoRr4h4x+p9an0MiDXZBbm/FYNayPXJP0PtsR3iFVAGpGQm6DzM+cye2PVlhbDK8htBA5ReZ1YEFxT/hJA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": ">=46.0.9",
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"expo": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@swc/helpers": {
|
"node_modules/@swc/helpers": {
|
||||||
"version": "0.5.15",
|
"version": "0.5.15",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||||
|
@ -6981,7 +6999,6 @@
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||||
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.2",
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
@ -14160,7 +14177,6 @@
|
||||||
"version": "1.13.4",
|
"version": "1.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
@ -16984,7 +17000,6 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
@ -17004,7 +17019,6 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
@ -17021,7 +17035,6 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bound": "^1.0.2",
|
"call-bound": "^1.0.2",
|
||||||
|
@ -17040,7 +17053,6 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bound": "^1.0.2",
|
"call-bound": "^1.0.2",
|
||||||
|
@ -17602,6 +17614,34 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stripe": {
|
||||||
|
"version": "18.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stripe/-/stripe-18.0.0.tgz",
|
||||||
|
"integrity": "sha512-3Fs33IzKUby//9kCkCa1uRpinAoTvj6rJgQ2jrBEysoxEvfsclvXdna1amyEYbA2EKkjynuB4+L/kleCCaWTpA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": ">=8.1.0",
|
||||||
|
"qs": "^6.11.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/stripe/node_modules/qs": {
|
||||||
|
"version": "6.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||||
|
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"side-channel": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/structured-headers": {
|
"node_modules/structured-headers": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz",
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"@neondatabase/serverless": "^0.10.4",
|
"@neondatabase/serverless": "^0.10.4",
|
||||||
"@react-navigation/bottom-tabs": "^7.2.0",
|
"@react-navigation/bottom-tabs": "^7.2.0",
|
||||||
"@react-navigation/native": "^7.0.14",
|
"@react-navigation/native": "^7.0.14",
|
||||||
|
"@stripe/stripe-react-native": "0.38.6",
|
||||||
"expo": "52.0.42",
|
"expo": "52.0.42",
|
||||||
"expo-blur": "~14.0.3",
|
"expo-blur": "~14.0.3",
|
||||||
"expo-constants": "~17.0.8",
|
"expo-constants": "~17.0.8",
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
"react-native-swiper": "^1.6.0",
|
"react-native-swiper": "^1.6.0",
|
||||||
"react-native-web": "~0.19.13",
|
"react-native-web": "~0.19.13",
|
||||||
"react-native-webview": "13.12.5",
|
"react-native-webview": "13.12.5",
|
||||||
|
"stripe": "^18.0.0",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"twrnc": "^4.6.1",
|
"twrnc": "^4.6.1",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
|
|
Loading…
Reference in New Issue