#meags-teamvash_code
1 messages ยท Page 1 of 1 (latest)
๐ 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/1370110931304190042
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Thanks
Can you show me your full code snippet here
Sure one moment
"use client";
import React from "react";
import {
PaymentElement,
useCheckout,
} from "@stripe/react-stripe-js";
import type {StripeCheckoutSavedPaymentMethod} from "@stripe/stripe-js";
import {CiCreditCard1} from "react-icons/ci";
import BillingAddressForm
from "@/app/(site)/product/[productName]/[productId]/checkout/BillingAddressForm.tsx";
interface Props {
savedPaymentMethods: StripeCheckoutSavedPaymentMethod[];
selectedPM: string | null;
onSelectPM: (id: string | null) => void;
isSubscription: boolean;
setBillingCountry: React.Dispatch<React.SetStateAction<string>>;
}
export default function PaymentDetails({
savedPaymentMethods,
selectedPM,
onSelectPM,
isSubscription,
setBillingCountry,
}: Props) {
const checkout = useCheckout();
const saved = savedPaymentMethods[0] ?? null;
const needsBilling =
checkout?.tax?.status === "requires_billing_address";
const renderOption = (
id: string | null,
logo: React.ReactNode,
label: React.ReactNode
) => {
const isSelected = selectedPM === id;
return (
<button
key={id ?? "new"}
type="button"
onClick={() => onSelectPM(id)}
className={`flex w-full items-center gap-2 rounded-lg border px-3 py-2 transition
${isSelected ? "border-blue-500 bg-blue-50 ring-2 ring-blue-200"
: "border-gray-300 bg-white hover:border-gray-400"}`}
>
<span
className={`h-4 w-4 rounded-full border-2
${isSelected ? "border-blue-600 bg-blue-600"
: "border-gray-400 bg-white"}`}
/>
<span className="flex items-center gap-2">
{logo}
<span className="font-medium text-gray-800 truncate">{label}</span>
</span>
</button>
);
};
return (
<div className="space-y-2">
{saved &&
renderOption(
saved.id,
<img
src={`/logos/${saved.card?.brand}.svg`}
alt={saved.card?.brand}
className="h-6 w-8 object-contain"
/>,
<>**** {saved.card?.last4}</>
)}
{renderOption(
null,
<CiCreditCard1 className="h-6 w-6 text-gray-500" />,
"Use a new payment method"
)}
{needsBilling && (
<BillingAddressForm setBillingCountry={setBillingCountry}/>
)}
{selectedPM === null && <PaymentElement />}
</div>
);
}
import React, { useMemo } from "react";
import { AddressElement, useCheckout } from "@stripe/react-stripe-js";
import type { StripeShippingAddressElementOptions } from "@stripe/stripe-js";
export default function BillingAddressForm({
setBillingCountry,
}: {
setBillingCountry: (c: string) => void;
}) {
const checkout = useCheckout();
//tried this earlier
const defaultValues = useMemo<StripeShippingAddressElementOptions["defaultValues"]>(() => {
const b = checkout.billingAddress;
if (!b) return undefined;
return {
name: b.name ?? null,
address: {
line1: b.address.line1 ?? null,
line2: b.address.line2 ?? null,
city: b.address.city ?? null,
state: b.address.state ?? null,
postal_code: b.address.postal_code ?? null,
country: b.address.country, // must be present
},
};
}, [checkout.billingAddress]);
const needsBilling = checkout.tax?.status === "requires_billing_address";
if (!needsBilling) return null;
return (
<AddressElement
options={{
// Pre-fill any existing data
defaultValues: {
name: "Test"
},
mode: 'billing',
}}
onChange={(event) => {
setBillingCountry(event.value?.address?.country || "");
}}
/>
);
}
This is the two relevant components
Thanks, and if you remove defaultValues does it render as expected?
Testing right now
Yes it does
It's just the defaultValues part throwing the error
I'm curious if you can re-create the error on your end with a minimal example, just passing in that defaultValue
Yeah I will test that but I'm also wondering if we don't support passing defaultValues here in this flow as it potentially should be prefilled based on the Customer object. Let me check on that.
Okay no worries, take your time. This is what shows on render, so GST set there even though we have a saved payment method. But if I choose to add a new card and add an address, then:
then the gst shows up
Can you share that Checkout Session? That looks to be a different once from before as that is a different saved card.
Yes sorry I've been testing other things.
cs_test_a12qSbwj2y6B0LNtV8mJJghMxmy9zuFGhhrJsPvLcET3iQ8eCoBWoFL4xM_secret_fidwbEhqYWAnPydmcHZxamgneCUl
Oh did you add the 4242 card separately?
Like it looks like you have the 0341 card attached to that Customer
No that was added in earlier, during a previous purchase
Hmm let me try the flow again one second
cs_test_a1lRSKPyLwySlpumnuRK54MOlWcrMuXuPKefpeVPtENBp8mZ8TNNE4DPqO8
the saved payment method shows up as "pm_1RMYzSGhbFSrlrBCTEHFD65l" the 4242 as it only shows one card.
Okay that PaymentMethod is attached to a different Customer than the one related to the Checkout Session you shared above
So I think you are mixing up IDs
But that helps
Oh wait wait
My bad
I was looking at the default
No worries hehe
This Customer has several PaymentMethods
Okay okay, one moment let me look a bit more at this
Ah yes I was testing a failed recurring susbcription payment the other day so it has multiple cards
Okay so first, coming back around to your initial question -- using defaultValues with Address Element isn't currently supported in this flow. I can flag feedback about that but the concept right now is that by passing the Customer through with a saved PaymentMethod should prefill the necessary address pieces from Payment Element.
I do understand why you would want to show that full address in Address Element so I'll file feedback on that front.
Second, to be clear, you are saying that when you render Payment Element here you are not seeing the Tax calculated initially, correct?
I don't necessarily need to fill in the address for them to see, it's more about wanting the GST to render
Yes unless they manually put an address in, the tax won't calculate
Ah okay you are just concerned with the Tax amount being assessed.
Got it
Hmm yeah I would expect the billing details of the attached PaymentMethod to be used for that
So I'm surprised, let me investigate that a bit more
A customer who has purchased before and and chooses a saved payment method should see the tax calculated on initial load and not have to put their address in again
Well I'm not sure if it's known what payment method is chosen on initial load as the payment method is sent in with confirm()
if (isUsingSavedCard) {
opts.paymentMethod = selectedPM!;
} else if (amount > 0) {
opts.savePaymentMethod = saveNewCard;
}
const result = await confirm(opts);
I just render the payment method as an option they can select and then on confirm it passes it in
The PaymentMethod chosen on load is the most recently saved so long as it has the necessary details: https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-customer
However, I feel like this is the issue: https://docs.stripe.com/tax/customer-locations#address-hierarchy-cpl
Okay perhaps something needs to be set when creating the checkout session?
Well I have ```ts
automatic_tax: {
enabled: true,
},
billing_address_collection: 'required',
What happens if you set billing_address_collection to auto
Yes that's what I was going to suggest testing
testing
Didn't work, cs_test_a1JfgMhjf9MatwiWeX5dHuCOw0XcRU3TQiLopfgBPfeXSiL18lzz8aTzNmz
The only other thing I can think of is trying to update the Customer's address (https://docs.stripe.com/api/customers/update#update_customer-address) with the address from the PaymentMethod to see if that overrides, but I suspect it does not.
I'll try that
While I'm testing it, I noticed this, perhaps I have to set that on load
updateBillingAddress: (
billingAddress: StripeCheckoutContact | null
) => Promise<StripeCheckoutUpdateAddressResult>;
I notice the saved payment card has the billing address and the card there
But this is only linked on confirm() so perhaps theres a way tos et this on load too, I'm checking
The addresses are already the same
Out of curiosity, have you completed one of these Sessions?
I'm doing some testing on my end as well and noticing that this might be a UI bug but tax actually gets assessed.
Going to test again to make sure I'm testing it correctly, but I think that is what just occurred.
Good point, I'll check
Oh yes I forgot, this is what shows up when I click submit
But it doesn't update the UI with the total or tax parts. I'll chekc what the checkout session object shows though
It does let you submit on the second attempt?
No it doesn't. The checkout object now says tax:status:
"requires_billing_address"
And it just keeps showing that error
Ah I fixed it!
??!!
I added this
useEffect(() => {
if (!saved || !checkout) return; // nothing to do
const src = saved.billingDetails?.address;
if (!src || !src.country) return; // address incomplete โ skip
const normalized: StripeCheckoutContact = {
name: saved.billingDetails?.name ?? undefined,
address: {
country: src.country, // now definitely a string
line1: src.line1 ?? undefined,
line2: src.line2 ?? undefined,
city: src.city ?? undefined,
state: src.state ?? undefined,
postal_code: src.postal_code ?? undefined,
},
};
checkout.updateBillingAddress(normalized);
}, [saved, checkout]);
Calling updatebilling address on load based on the saved payment card
Not sure if that's the ideal way but the tax rendered right away
Ahhh okay I thought you had already been doing that.
That said, I agree, that shouldn't be needed!
It should just prefill it based on the PaymentMethod
So I'll submit feedback on that.
But I'm glad there is a workaround for now
Well the payment method isn't linked to the checkout until confirm(), but being able to pass the defaultValue of the address is what I originally thought would link the addresss to the session
Nah it should still just assess the tax based on the billing details of the PaymentMethod imo
Ah okay! That would be ideal yes
Great if you could submit that feedback, that would be great. thanks for your help debugging! ๐