#cristoffer_unexpected

1 messages ¡ Page 1 of 1 (latest)

crimson lintelBOT
#

👋 Welcome to your new thread!

⏲️ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

⏱️ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

🔗 This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1243559195714781195

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

pine pumice
#

My component looks like this

#

My Payment components (in docs App)

const Payment = ({ orderDetails, products }: PaymentProps) => {
  const [loading, setLoading] = useState(true);

  const [stripePromise, setStripePromise] =
    useState<Promise<Stripe | null> | null>(null);
  const [clientSecret, setClientSecret] = useState("");

  // Effect to fetch publishable stripe key
  useEffect(() => {
    axios.get("/api/payment/config").then((res) => {
      if (res.status === 200) {
        setStripePromise(loadStripe(res.data.publishableKey));
      }
    });
  }, []);

  // Effect to check if order data collected from user is correct. Server side do the verifications.
  useEffect(() => {
    axios
      .post("/api/payment/create-payment-intent", { ...orderDetails, products })
      .then((res) => {
        if (res.status === 200) {
          const clientSecret = res.data.clientSecret;
          setClientSecret(clientSecret);
        }
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => setLoading(false));
  }, []);

  const appearance: Appearance = {
    theme: "stripe",
  };

  const options: StripeElementsOptions = {
    clientSecret,
    appearance,
  };

  return (
    <div className="payment">
      {loading || !clientSecret || !stripePromise ? (
        <Spinner />
      ) : (
        <Elements options={options} stripe={stripePromise}>
          <CheckoutForm />
        </Elements>
      )}
    </div>
  );
};
#

My CheckoutForm component

const CheckoutForm = () => {
  const stripe = useStripe();
  const elements = useElements();

  const [message, setMessage] = useState<string | undefined>();
  const [isProcessing, setIsProcessing] = useState(false);

  const handleSubmit: FormEventHandler<HTMLFormElement> = async (e) => {
    e.preventDefault();

    if (!stripe || !elements) {
      return;
    }

    setIsProcessing(true);

    const { error } = await stripe.confirmPayment({
      elements,
      confirmParams: {
        return_url: `${window.location.origin}/completion`,
      },
    });

    if (error.type === "card_error" || error.type === "validation_error") {
      setMessage(error.message);
    } else {
      setMessage("unexpected-error");
    }
    setIsProcessing(false);
  };

  const paymentElementOptions: StripePaymentElementOptions = {
    layout: "tabs",
  };

  return (
    <form id="payment-form" onSubmit={handleSubmit}>
      <PaymentElement id="payment-element" options={paymentElementOptions} />
      <button disabled={isProcessing || !stripe || !elements} id="submit">
        <span id="button-text">
          {isProcessing ? (
            <div className="spinner" id="spinner"></div>
          ) : (
            "Pay now"
          )}
        </span>
      </button>
      {message && <div id="payment-message">{message}</div>}
    </form>
  );
};
#

And on my server-side payment controller and his endpoints

const OrderService = require("../services/modelServices/OrderService");
const orderService = new OrderService();

const { Stripe } = require("stripe");
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

const createPaymentIntent = async (req, res) => {
  const order = req.body;
  const userId = res.locals?.user?.id;
  try {
    const verification = await orderService.verifyClientOrder(order, userId);
    if (!verification.success) {
      return res.status(400).json({ success: false, message: verification.message });
    }

    const paymentIntent = await stripe.paymentIntents.create({
      currency: "pln",
      amount: order.priceForAll,
      automatic_payment_methods: { enabled: true },
    });
    return res.status(200).json({ success: true, message: verification.message, clientSecret: paymentIntent.client_secret });
  } catch (err) {
    console.log(err);
    return res.status(400).json({ success: false, message: "unexpected-error" });
  }
};

const getConfig = async (req, res) => {
  return res.status(200).json({ publishableKey: process.env.STRIPE_PUBLISHABLE_KEY });
};

module.exports = { createPaymentIntent, getConfig };
sudden pasture
#

Can you share the payment intent id?

pine pumice
#

Yeah, its : pi_3PJySNRrtsKOar1b1xvPZMw9

#

I'm on test mode working on local server without https. I don't know if it changes something. Also it's my very first experience with Stripe so propably it's something obvious i should have configured before

sudden pasture
#

In the response for the payment intent creation request here: https://dashboard.stripe.com/test/logs/req_i33EiWdrHoqBce you can see:

    "card",
  ],```
That indicates card is the only PM available even though you enabled automatic payment method. So, you'll need to enable more payment methods if you want them to show up: https://dashboard.stripe.com/test/settings/payment_methods
pine pumice
#

Yeah but this page shows me that cards, apple pay, Link, Blik, BanContact, etc are also active

sudden pasture
#

In live mode?

pine pumice
#

Nevermind i have just switched P24 and refreshed my page and it works now

#

Does offered payment methods depends on client localisation? For example if customer from Australia will see methods which are popular there?

sudden pasture
#

Yep it depends on currency, location of the customer, and location of your account

pine pumice
#

Oke, that's what important for me cause customer sells items to different countries

#

Can i show somehow on this component amount that have to be paid?

sudden pasture
#

No you'll need to render it yourself somewhere on the page

pine pumice
#

Okey, thank you for help :))

sudden pasture
#

No problem

pine pumice
#

I have another question if you are still there. How Stripe Elements are translated, do i have to provide translations to them or they are translated based on localisation or something else? Is there some prop which can change language of text's in component?