#florin_best-practices
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/1313835078450937938
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- florin_code, 1 day ago, 12 messages
- florin_code, 1 day ago, 35 messages
- florin_code, 2 days ago, 4 messages
- florin_best-practices, 2 days ago, 26 messages
- florin_code, 5 days ago, 17 messages
- florin_unexpected, 5 days ago, 86 messages
Hi
Does stripe provide a dropdown component with the list of countries and these codes?
I'm affraid no, but have you had the chance to check Stripe Address Element ?
@bitter ore https://docs.stripe.com/js/elements_object/create_address_element
I would like to only use the Country dropdown
๐ taking over for my colleague. Let me catch up.
do you need to update the billing or the shipping details?
if you use the https://docs.stripe.com/elements/address-element then you wouldn't need to create your own form
we will collect all the details for you
can I not force all the fields to be required? I see that I can only set the phone field to be required always
yea, I wanted to be required for my app, since I am using a custom checkout
all the fields with a ? following their name are not required
you can do that by doing your own validation
I see that if I only provide a single country in the allowedCOuntries array the dropdown wont show, so I guess the value for it will be that specific country
in that case you can pass it in the defaultValues as well
so it will get pre-populated
hmm yea, my issue is that my app will only ship to the UK, but UK consists of 4 countries, so my users will basically have to specify their Town / City without specifying the exact country
actually, it's fine I only need to specify the UK*
yes that's correct
hmm so I am doing something wrong, I have a component which renders the AddressElement alongside with other logic. I am rendering this component twice each having a type of either shipping or billing.
This is the AddressElement inside <AddressElement
options={{
mode: type,
fields: { phone: 'always' },
...(type === 'shipping' && {
allowedCountries: ['GB'],
defaultValues: {
address: {
country: 'GB',
},
},
}),
validation: {
phone: { required: 'always' },
},
}}
/>
and inside the component I have a test handler in which I am trying to get the values of the element.
const testHandler = async () => {
if (!elements) {
return;
}
console.log('handler');
console.log(await elements.getElement('address', { mode: type }));
const addressElement = elements.getElement('address', { mode: type });
addressElement
?.getValue()
.then(function (result) {
if (result.complete) {
console.log(result.value);
console.log(result.complete);
// Allow user to proceed to the next step
// Optionally, use value to store the address details
} else {
console.log({ result });
}
})
.catch((error) => {
console.log(error);
});
};
My issue is that I can only see the data on the element of type shipping, and not of the type billing
type: 'shipping' | 'billing';
to be clear, you can only have one instance of <AddressElement> per <Elements> component.
when you say "My issue is that I can only see the data on the element of type shipping, and not of the type billing", what specifically are you seeing with getValue?
{
"result": {
"isNewAddress": true,
"complete": false,
"value": {
"name": "dsasadsda",
"phone": "+447400123456",
"address": {
"line1": "dsadad",
"line2": null,
"city": "",
"country": "GB",
"postal_code": "E1 6AN",
"state": ""
}
}
}
}
and what did you expect to see instead?
so basically I have created a custom AddressList component, this component receives a type prop type AddressListProps = {
addresses: ShippingAddressType[] | BillingAddressType[];
formData: ShippingAddressType | BillingAddressType;
onSubmit: () => void;
onChange: (key: keyof BillingAddressType | keyof ShippingAddressType, value: string) => void; // Modified type
onSelect: (address: ShippingAddressType | BillingAddressType) => void;
selectedAddress?: ShippingAddressType | BillingAddressType;
type: 'shipping' | 'billing';
loading: boolean;
};
and based on that type I am creating the <AddressElement
options={{
mode: type,
fields: { phone: 'always' },
...(type === 'shipping' && {
allowedCountries: ['GB'],
defaultValues: {
address: {
country: 'GB',
},
},
}),
validation: {
phone: { required: 'always' },
},
}}
/>
and in the test handler I want to see the form data for each address element const testHandler = async () => {
if (!elements) {
return;
}
console.log('handler');
console.log(await elements.getElement('address', { mode: type }));
const addressElement = elements.getElement('address', { mode: type });
addressElement
?.getValue()
.then(function (result) {
if (result.complete) {
console.log(result.value);
console.log(result.complete);
// Allow user to proceed to the next step
// Optionally, use value to store the address details
} else {
console.log({ result });
}
})
.catch((error) => {
console.log(error);
});
};
I'm with you so far in terms of context, I think, but not following what specific issue you're running into and what result you're getting versus what you expect to get
I can only get the value of the shipping address Element
the billing address element is null
when you say it's null, what specific variable is null that you're expecting not to be? The return value of elements.getElement ? One of the parameters returned from getValue() ? Something else?
the return fo elements.getElement
the first console log is from the billing address element and the second one is from the shipping one
ok. Well remember what I said, you can only have one AddressElement per instance of Elements. Maybe the elements variable is not the right one.
hmm, but doesn't this mean that I have 2 different instances of Elements?
const AddressList = ({
addresses,
formData,
onSubmit,
onChange,
onSelect,
selectedAddress,
type,
loading,
}: AddressListProps) => {
const [showAddressesModal, setShowAddressesModal] = useState(false);
const [showAddAddressForm, setShowAddAddressForm] = useState(false);
const onAddNewAddress = () => {
setShowAddAddressForm(true);
setShowAddressesModal(false);
};
const elements = useElements();
const testHandler = async () => {
if (!elements) {
return;
}
console.log('handler');
console.log(elements.getElement('address', { mode: type }));
const addressElement = elements.getElement('address', { mode: type });
addressElement
?.getValue()
.then(function (result) {
if (result.complete) {
console.log(result.value);
console.log(result.complete);
// Allow user to proceed to the next step
// Optionally, use value to store the address details
} else {
console.log({ result });
}
})
.catch((error) => {
console.log(error);
});
};
as I instantiate it in each AddressList component?
you don't instantiate it, you're getting a reference to it from the useElements hook. That gets the instance from the "StripeProvider" that is higher up in the component tree,
<Elements options=foo>
<ComponentThatUsesAddressElement> // useElements called inside here gets the elements instance with foo options
</Elements>
<Elements options=bar>
<ComponentThatUsesAddressElement> // useElements called inside here gets the elements instance with bar options
</Elements>
so what can I do to have 2 instances of elements here ?
structure it like I have there, with multiple <Elements> components
ok, so I wrapped both of my AddressLists in <Elements stripe={stripePromise}>
but I also have <Elements stripe={stripePromise}> in the root file of my app, is that a problem?
it seems that the address elements are now working
that would probably have been a problem , possibly
so should I do anything with the Elements tag I have wrapped around my root ? I was using it for the CardElement, but now that I added 2 more elements tags around my addresses lists, can anything go bad?
it really depends. Normally I would say you should have the AddressElement and the PaymentElement in the same <Elements> so that the PaymentElement automatically pulls in the address entered and submits it with the payment, but that logic AFAIK doesn't exist for the legacy CardElement. So I suppose it doesn't matter.
I am passing the address when I am using the card element, so I think that shouldn't be an issue ?
const { error: stripePaymentError, paymentIntent } = await stripe.confirmCardPayment(
clientSecret,
{
payment_method: selectedPaymentMethod
? selectedPaymentMethod.id
: {
card: cardElement,
billing_details: {
name: billingDetails.name,
address: {
city: billingDetails.city,
country: billingDetails.country,
line1: billingDetails.address,
postal_code: billingDetails.postalCode,
state: billingDetails.state,
},
phone: billingDetails.phoneNumber,
},
},
}
);
yes if you're just manually pulling the values into your own variables and passing those manually into the API call for confirmCardPayment then it doesn't matter
I don't know what happened, but now it stopped working.
const submitHandler = async () => {
if (!elements) {
return;
}
console.log('here');
const addressElement = elements.getElement('address', { mode: type });
if (!addressElement) {
return;
}
console.log('asdsad');
console.log('1234', await addressElement.getValue());
console.log('here2', addressElement);
const result = await addressElement.getValue();
console.log('here3');
console.log(result);
if (!result?.complete) {
return;
}
console.log('ajunge aici?');
const stripeAddress = result.value;
console.log('abc', stripeAddress);
onSubmit({
address: {
name: stripeAddress.name,
city: stripeAddress.address.city,
country: stripeAddress.address.country,
state: stripeAddress.address.state,
phoneNumber: stripeAddress.phone ?? '',
postalCode: stripeAddress.address.postal_code,
address: stripeAddress.address.line1,
},
});
};
basically when I am calling the .getValue() method everything stops there, and it doesn't seem to throw an error since I wrapped it in a try catch block.
I can see that the element is here
might be easier to open a support case with a minimal reproduction of the problem
how do I do that
ideally put together a simple page on something like Codesandbox or just your own site that reproduces the problem using the multiple <Elements>, and open a support case at https://support.stripe.com/?contact=true sharing a link to that and a description of the problem. Otherwise I can try to help here, it's just getting extremely difficult and abstract without seeing this for myself in my own browser and seeing all the code
hmm, maybe let's try one last time? In my Checkout page I have 2
<Elements stripe={stripePromise}>
<AddressList
addresses={user?.user_shipping_addresses || []}
onSubmit={addShippingAddressMutate}
onSelect={setSelectedShippingAddress}
selectedAddress={selectedShippingAddress}
type="shipping"
loading={addShippingAddressPending}
/>
</Elements>
<Elements stripe={stripePromise}>
<AddressList
addresses={user?.user_billing_addresses || []}
onSubmit={addBillingAddressMutate}
onSelect={setSelectedBillingAddress}
selectedAddress={selectedBillingAddress}
type={'billing'}
loading={addBillingAddressPending}
/>
</Elements>
and inside the AddressList component I have this submitHandler
const submitHandler = async () => {
try {
if (!elements) {
return;
}
console.log('here');
const addressElement = elements.getElement('address', { mode: type });
if (!addressElement) {
return;
}
// this is where everything stops, no error is being thrown, the function just stops
const result = await addressElement.getValue();
console.log('here');
console.log(result);
if (!result?.complete) {
return;
}
const stripeAddress = result.value;
onSubmit({
address: {
name: stripeAddress.name,
city: stripeAddress.address.city,
country: stripeAddress.address.country,
state: stripeAddress.address.state,
phoneNumber: stripeAddress.phone ?? '',
postalCode: stripeAddress.address.postal_code,
address: stripeAddress.address.line1,
},
});
} catch (error) {
console.error(error);
}
};
all I did was to remove some unrelated code, and now the addressElement.getValue stops the execution of the submit handler
it worked before
maybe add the "unrelated code" back and slowly remove parts again until finding where the difference is?
maybe capture an event variable in the submit handler and call event.preventDefault() in submitHandler
I can't think of any specific reason for getValue to "crash", if that is what's happening I'd need to look at an actual reproduction to figure out what's happening
I managed to fix it, it was clearly a mistake on my part, I was hiding the modal by mistake and it would stop the submission. sorry!