HA
Hamza Ali

Styled Card - Copy this React, Mui Component to your project

Import React, { useState, useEffect } from "react"; import { useStripe, useElements, CardElement, PaymentRequestButtonElement, } from "@stripe/react stripe js"; const PaymentForm = () => { const stripe = useStripe(); const elements = useElements(); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const [paymentRequest, setPaymentRequest] = useState(null); const [canMakePayment, setCanMakePayment] = useState(false); const [plan, setPlan] = useState("monthly"); // Default plan is "monthly" useEffect(() => { if (!stripe || !elements) return; const pr = stripe.paymentRequest({ country: "US", currency: "usd", total: { label: "Total", amount: plan === "monthly" ? 1000 : 10000, }, requestPayerName: true, requestPayerEmail: true, }); pr.canMakePayment().then((result) => { setCanMakePayment(!!result); }); pr.on("paymentmethod", async (ev) => { try { const payload = { free_trial_user: false, payment_method_id: ev.paymentMethod.id, plan: plan, userId: "67e1477c277416456876bcd4", }; const response = await fetch(`${pimport.meta.env.VITE_APP_BACKEND_BASEURL}/payment/create subscription`, { method: "POST", headers: { "Content Type": "application/json", }, body: JSON.stringify(payload), }); const data = await response.json(); if (!response.ok) throw new Error(data.message || "Subscription failed"); ev.complete("success"); setSuccess(true); } catch (err) { ev.complete("fail"); setError(err.message); } }); setPaymentRequest(pr); }, [stripe, elements, plan]); const fetchWithTimeout = (url, options = {}, timeout = 20000) => { const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Request timed out')), timeout) ); return Promise.race([fetch(url, options), timeoutPromise]); }; const handleSubmit = async (event) => { event.preventDefault(); setLoading(true); if (!stripe || !elements) { setError("Stripe has not loaded yet."); setLoading(false); return; } try { const cardElement = elements.getElement(CardElement); // Create Payment Method const { paymentMethod, error } = await stripe.createPaymentMethod({ type: "card", card: cardElement, }); if (error) { setError(error.message); setLoading(false); return; } const payload = { free_trial_user: false, payment_method_id: paymentMethod.id, plan: plan, userId: "67e1477c277416456876bcd4", }; // Call Subscription API with timeout logic const response = await fetchWithTimeout( `${import.meta.env.VITE_APP_BACKEND_BASEURL}/payment/create subscription`, { method: "POST", headers: { "Content Type": "application/json", }, body: JSON.stringify(payload), }, 20000 // Timeout after 20 seconds ); const data = await response.json(); if (!response.ok) throw new Error(data.message || "Subscription failed"); setSuccess(true); // Assuming success state is used to show confirmation } catch (err) { setError(err.message); // Display error message if request fails or times out } finally { setLoading(false); // Always stop the loading spinner } }; const styles = { form: { maxWidth: "400px", margin: "0 auto", padding: "20px", backgroundColor: "#fff", borderRadius: "8px", boxShadow: "0 4px 8px rgba(0,0,0,0.1)", textAlign: "center", }, header: { marginBottom: "20px", fontSize: "24px", color: "#333", fontWeight: "bold", }, toggleContainer: { display: "flex", justifyContent: "center", alignItems: "center", gap: "10px", marginBottom: "20px", }, toggleSwitch: { cursor: "pointer", padding: "8px 15px", borderRadius: "20px", backgroundColor: plan === "monthly" ? "#5469d4" : "#28a745", color: "#fff", fontWeight: "bold", border: "none", }, button: { backgroundColor: "#5469d4", color: "#fff", border: "none", padding: "12px 0", fontSize: "16px", width: "100%", borderRadius: "4px", cursor: "pointer", marginTop: "20px", }, cardElement: { marginTop: "20px", border: "1px solid #ccc", borderRadius: "4px", padding: "10px", fontSize: "16px", width: "100%", }, error: { color: "red", marginTop: "10px", }, success: { color: "green", marginTop: "10px", }, }; return ( <div style={styles.form}> <h3 style={styles.header}>Checkout</h3> {/* Toggle Monthly/Yearly Subscription */} <div style={styles.toggleContainer}> <span>Monthly</span> <button style={styles.toggleSwitch} onClick={() => setPlan(plan === "monthly" ? "yearly" : "monthly")} > {plan === "monthly" ? "Switch to Yearly" : "Switch to Monthly"} </button> <span>Yearly</span> </div> {/* Payment Request Button for Apple Pay & Google Pay */} {canMakePayment && paymentRequest && ( <PaymentRequestButtonElement options={{ paymentRequest: paymentRequest, style: { paymentRequestButton: { type: "default", theme: "light", height: "40px", width: "100%", }, }, }} /> )} {/* Card Payment Form */} <form onSubmit={handleSubmit} style={{ marginTop: "20px" }}> <CardElement options={{ style: styles.cardElement }} /> <button type="submit" disabled={!stripe || loading} style={styles.button} > {loading ? "Processing..." : `Pay with Card (${plan})`} </button> </form> {error && <p style={styles.error}>{error}</p>} {success && <p style={styles.success}>Payment Successful!</p>} </div> ); }; export default PaymentForm; in show also add subscription fee 10$/month and in case of year 100$/year

Prompt
Component Preview

About

StyledCard - A payment form for subscriptions with monthly ($10) and yearly ($100) plans, built with React and MUI. Get free template!

Share

Last updated 1 month ago