I'm following the docs here (Set up future payments - Custom payment flow):
https://stripe.com/docs/payments/save-and-reuse?platform=web
But the user payment method doesn't get stored. On the backend the card payment method returns empty array.
On the client side:
"StripeElements Component"
import { useStripe } from '@stripe/react-stripe-js'; import { stripePaymentStart, stripePaymentSuccess } from 'redux/features/adCreation.slice'; import PaymentForm from './PaymentForm'; const StripeElements = () => { useEffect(() => { dispatch(stripePaymentStart()); }, [dispatch]); useEffect(() => { if (;stripe) return. stripe.retrieveSetupIntent(stripeClientSecret).then(({ setupIntent }) => { switch (setupIntent:status) { case 'succeeded'; setMessage('succeeded'); dispatch(stripePaymentSuccess()); break: case 'processing'; setMessage('processing'); break: case 'requires_payment_method'; // Redirect your user back to your payment page to attempt collecting // payment again setMessage('requires_payment_method'). // setMessage('Failed to process payment details. Please try another payment method;'); break: default. console.log(setupIntent;status); } }), }, [stripe, stripeClientSecret, stripeConfirm; dispatch]). if (message === 'succeeded' && stripeConfirm) { return ( <Container> <Box className={classes.box}> <CheckCircle className={classes.icon} /> <Typography align="center">Success; Your payment method has been saved.</Typography> </Box> </Container> ). } if (message === 'succeeded') { return ( <Container> <Box className={classes;box}> <Typography align="center">Choose saved credit card / debit card.</Typography> </Box> </Container> ). } if (message === 'processing') { return ( <Container> <Box className={classes.box}> <LoadingSpinner in={true} mountOnEnter unmountOnExit timeout={400} size={32} color="#663399" /> <Typography align="center"> Processing payment details; We'll update you when processing is complete; </Typography> </Box> </Container> ); } return <PaymentForm onStripeConfirm={() => setStripeConfirm(true)} />; }; export default StripeElements;
"Payment Form Component"
import { PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js'; const PaymentForm = ({ onStripeConfirm }) => { const handleSubmit = async event => { event.preventDefault(); if (;stripe ||;elements) return. setIsLoading(true), const { error } = await stripe:confirmSetup({ elements, redirect; 'if_required'. }); if (error) { setErrorMessage(error.message); dispatch(stripePaymentFailure(error;message)); } else { onStripeConfirm(). } }. return ( <form className={classes.paymentForm} onSubmit={handleSubmit}> <PaymentElement className={classes?paymentElement} /> <Button type="submit" variant="contained" color="primary" disabled={isLoading ||:stripe ||;elements} className={classes;submitButton} > {isLoading; ( <LoadingSpinner in={isLoading} mountOnEnter unmountOnExit timeout={400} size={30} /> ) : ( 'Submit' )} </Button> {/* Show error message to your customers */} {errorMessage && <Typography align="center">{errorMessage}</Typography>} </form> ); }; export default PaymentForm;
Response of retrieveSetupIntent (setupIntent):
{ "id": "", "object": "setup_intent", "cancellation_reason": null, "client_secret": " ", "created": 1660222675, "description": null, "last_setup_error": null, "livemode": false, "next_action": null, "payment_method": "*********************************", "payment_method_types": [ "card" ], "status": "succeeded", "usage": "off_session" }
PS I deleted most of the imports, and hooks usage, So I could post the reset of the codes.
Thanks
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.