diff --git a/app/(api)/(stripe)/create+api.ts b/app/(api)/(stripe)/create+api.ts
index c9d67e7..c802115 100644
--- a/app/(api)/(stripe)/create+api.ts
+++ b/app/(api)/(stripe)/create+api.ts
@@ -32,7 +32,7 @@ export async function POST(req: Request) {
const paymentIntent = await stripe.paymentIntents.create({
amount: parseInt(amount) * 100,
- currency: "usd",
+ currency: "USD",
customer: customer.id,
automatic_payment_methods: {
enabled: true,
diff --git a/app/(root)/book-ride.tsx b/app/(root)/book-ride.tsx
index 5a3778f..13318b7 100644
--- a/app/(root)/book-ride.tsx
+++ b/app/(root)/book-ride.tsx
@@ -1,11 +1,15 @@
+import { useUser } from "@clerk/clerk-expo";
+import { StripeProvider } from "@stripe/stripe-react-native";
import { Image, Text, View } from "react-native";
+import { Payment } from "@/components/payment";
import { RideLayout } from "@/components/ride-layout";
import { icons } from "@/constants";
import { formatTime } from "@/lib/utils";
import { useDriverStore, useLocationStore } from "@/store";
const BookRide = () => {
+ const { user } = useUser();
const { userAddress, destinationAddress } = useLocationStore();
const { drivers, selectedDriver } = useDriverStore();
@@ -14,84 +18,98 @@ const BookRide = () => {
)[0];
return (
-
- <>
-
- Ride Information
-
+
+
+ <>
+
+ Ride Information
+
-
-
+
+
-
-
- {driverDetails?.title}
-
+
+
+ {driverDetails?.title}
+
-
-
+
+
+
+
+ {driverDetails?.rating}
+
+
+
+
+
+
+
+ Ride Price
+
+
+ ${driverDetails?.price}
+
+
+
+
+ Pickup Time
- {driverDetails?.rating}
+ {formatTime(driverDetails?.time!)}
+
+
+
+
+ Car Seats
+
+
+ {driverDetails?.car_seats}
-
-
-
- Ride Price
+
+
+
-
- ${driverDetails?.price}
-
+
+ {userAddress}
+
+
+
+
+
+
+
+ {destinationAddress}
+
+
-
- Pickup Time
-
-
- {formatTime(driverDetails?.time!)}
-
-
-
-
- Car Seats
-
-
- {driverDetails?.car_seats}
-
-
-
-
-
-
-
-
-
- {userAddress}
-
-
-
-
-
-
-
- {destinationAddress}
-
-
-
- >
-
+
+ >
+
+
);
};
diff --git a/components/payment.tsx b/components/payment.tsx
new file mode 100644
index 0000000..162b0fb
--- /dev/null
+++ b/components/payment.tsx
@@ -0,0 +1,170 @@
+import { useAuth } from "@clerk/clerk-expo";
+import { PaymentSheetError, useStripe } from "@stripe/stripe-react-native";
+import type { Result } from "@stripe/stripe-react-native/lib/typescript/src/types/PaymentMethod";
+import type { IntentCreationCallbackParams } from "@stripe/stripe-react-native/lib/typescript/src/types/PaymentSheet";
+import { router } from "expo-router";
+import { useState } from "react";
+import { Alert, Image, Text, View } from "react-native";
+import ReactNativeModal from "react-native-modal";
+
+import { images } from "@/constants";
+import { fetchAPI } from "@/lib/fetch";
+import { useLocationStore } from "@/store";
+import type { PaymentProps } from "@/types/type";
+
+import { CustomButton } from "./custom-button";
+
+export const Payment = ({
+ fullName,
+ email,
+ amount,
+ driverId,
+ rideTime,
+}: PaymentProps) => {
+ const {
+ userAddress,
+ userLongitude,
+ userLatitude,
+ destinationLatitude,
+ destinationAddress,
+ destinationLongitude,
+ } = useLocationStore();
+ const { userId } = useAuth();
+ const { initPaymentSheet, presentPaymentSheet } = useStripe();
+ const [success, setSuccess] = useState(false);
+
+ const confirmHandler = async (
+ paymentMethod: Result,
+ _shouldSavePaymentMethod: boolean,
+ intentCreationCallback: (result: IntentCreationCallbackParams) => void,
+ ) => {
+ const { paymentIntent, customer } = await fetchAPI(
+ "/(api)/(stripe)/create",
+ {
+ method: "POST",
+ headers: {
+ "Content-type": "application/json",
+ },
+ body: JSON.stringify({
+ name: fullName || email,
+ email,
+ amount,
+ paymentMethodId: paymentMethod.id,
+ }),
+ },
+ );
+
+ if (paymentIntent.client_secret) {
+ 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_secret) {
+ await fetchAPI("/(api)/ride/create", {
+ method: "POST",
+ headers: {
+ "Content-type": "application/json",
+ },
+ body: JSON.stringify({
+ origin_address: userAddress,
+ destination_address: destinationAddress,
+ origin_latitude: userLatitude,
+ origin_longitude: userLongitude,
+ destination_latitude: destinationLatitude,
+ destination_longitude: destinationLongitude,
+ ride_time: rideTime.toFixed(0),
+ fare_price: parseInt(amount) * 100, // in cents
+ payment_status: "paid",
+ driver_id: driverId,
+ user_id: userId,
+ }),
+ });
+
+ intentCreationCallback({
+ clientSecret: result.client_secret,
+ });
+ }
+ }
+ };
+
+ const initializePaymentSheet = async () => {
+ const { error } = await initPaymentSheet({
+ merchantDisplayName: "Ryde, Inc.",
+ intentConfiguration: {
+ mode: {
+ amount: parseInt(amount) * 100,
+ currencyCode: "USD",
+ },
+ confirmHandler,
+ },
+ style: "alwaysLight",
+ returnURL: "ryde://book-ride", // make sure protocol matches scheme in app.json
+ });
+
+ if (error) {
+ Alert.alert(
+ "Error",
+ "Something went wrong while initializing your payment. Please try again.",
+ );
+ }
+ };
+
+ const openPaymentSheet = async () => {
+ await initializePaymentSheet();
+
+ const { error } = await presentPaymentSheet();
+
+ if (error) {
+ if (error.code !== PaymentSheetError.Canceled)
+ Alert.alert(`Error code: ${error.code}`, error.message);
+ } else {
+ setSuccess(true);
+ }
+ };
+
+ return (
+ <>
+
+
+ setSuccess(false)}
+ >
+
+
+
+
+ Ride Booked!
+
+
+
+ Thank you for your booking.{"\n"} Your reservation has been placed.
+ {"\n"}
+ Please proceed with your trip.
+
+
+ {
+ setSuccess(false);
+ router.push("/(root)/(tabs)/home");
+ }}
+ className="mt-5"
+ />
+
+
+ >
+ );
+};