#walter_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/1341216678461308930
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
All the examples I can find including this one: https://4242.io/test/elements-recommended/ call confirmPayment within the express checkout element confirm event.
hello! Can you share more on what specifically you're confused about?
If there's no call to confirmPayment within the express checkout confirm event, we're seeing card errors in the payment element once elements.submit() is called
Our goal is to allow users to enter payment details via either the ECE or PE, and on the same page, show a show a cost breakdown.
If there's no call to confirmPayment within the express checkout confirm event, we're seeing card errors in the payment element once elements.submit() is called - what's the specific error message you're seeing?
after entering payment details the users would be able to add promo codes or change their billing address which would change the total cost shown in the price breakdown
The specific error is incomplete_number
Which is sort of true since the payment element is empty, but the user has already provided their payment details via the ECE
We're using a single elements instance currently
can you share the relevant code snippets for how you're implementing things?
sure, hang on
` const options = {
mode: 'subscription',
amount: this.product.price,
currency: 'usd',
setupFutureUsage: 'off_session',
}
// Set up Stripe.js and Elements to use in billing form.
this.elements = this.stripe.elements(options)
// this.mountAddressElement()
this.mountExpressPayElement()
this.mountPaymentElement()`
Mounting the payment element...
`mountPaymentElement() {
const paymentElement = this.elements.create('payment', {
fields: {
billingDetails: 'never',
},
})
paymentElement.on('ready', () => {
if (this.elements.getElement('address')) {
paymentElement.collapse()
}
})
paymentElement.on('loaderror', function (event) {
this.handleError(event.error)
})
paymentElement.on('change', (event) => {
console.log('payment element change event: ', event)
if (event.complete) {
this.paymentCollected = true
this.elements.getElement('expressCheckout').destroy()
// $nextTick is needed to ensure computed properties are updated before calling mountAddressElement
this.$nextTick(async () => {
if (!this.elements.getElement('address')) {
this.mountAddressElement()
} else {
const { error: submitError } = await this.elements.submit()
if (submitError) {
this.handleError(submitError)
return
}
}
this.mountExpressPayElement()
})
}
})
paymentElement.mount('#payment-element')
}`
gimme a while to look into this
` mountExpressPayElement() {
const expressCheckoutOptions = {
buttonType: {
applePay: 'buy',
googlePay: 'plain',
paypal: 'buynow',
klarna: 'pay',
},
paymentMethods: {
applePay: 'always',
googlePay: 'always',
},
}
const expressCheckoutElement = this.elements.create(
'expressCheckout',
expressCheckoutOptions
)
expressCheckoutElement.on('click', (event) => {
...
})
expressCheckoutElement.on('confirm', async (event) => {
this.makingPurchaseRequest = false
this.paymentCollected = true
this.address = event.billingDetails.address
this.elements.getElement('payment').destroy()
// Create a confirmation token for use summarizing the payment details later
const { error, confirmationToken } =
await this.stripe.createConfirmationToken({
elements: this.elements,
params: {
payment_method_data: {
billing_details: {
name: event.billingDetails.name,
address: event.billingDetails.address,
},
},
},
})
this.stripeConfirmationToken = confirmationToken
// $nextTick is needed to ensure computed properties are updated before calling mountAddressElement
this.$nextTick(async () => {
if (!this.elements.getElement('address')) {
this.mountAddressElement(event.billingDetails.name)
} else {
// Trigger form validation and wallet collection
const { error: submitError } = await this.elements.submit()
this.mountPaymentElement()
if (submitError) {
...
}
}
})
if (error) {
...
}
})
expressCheckoutElement.mount('#express-checkout-element')
}`
Currently, in an attempt to solve the issue with form validation errors appearing, we're destroying the payment element within ECE confirm event.
It is later re-mounted and collapse() is called, which hides the errors, but this is seeming like a not great solution that shouldn't be needed.
this is likely going to take me a while to test out, would you prefer to write in via a ticket then I'll get back to you on the ticket instead so you don't have to wait around?
I've had a support ticket open for slightly more than a week now with no help or solution ๐
I don't mind waiting if it means I get answers haha
hmmm, can you share your account id too so that I can find the ticket? You can find your account id by logging in to https://dashboard.stripe.com/settings/account. It'll look like acct_123
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
Is this a public chat?
I'm not sure I should share my account id if so
I'd be happy to forward the email thread with support to you if I had your email
Or if you had a private method I could share my account id that isn't searchable here in discord
it is a public thread, the account id isn't sensitive info, but let me see how to enable DMs so that you can send that info to me
can you try and see if you can send me a DM now?
I tried
okay, i found your support ticket too, I'm going to take over this ticket too
going back to looking into how this should be implemented
I very roughly threw this together, and i didn't run into that error you mentioned
checkout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Accept a payment</title>
<meta name="description" content="A demo of a payment on Stripe" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="checkout.css" />
<script src="https://js.stripe.com/v3/"></script>
<script src="checkout.js" defer></script>
<!-- <script src="checkout-payment-element.js" defer></script> -->
</head>
<body>
<form id="payment-form">
<div id="express-checkout-element">
<!-- Elements will create form elements here -->
</div>
<div id="payment-element">
<!-- Elements will create form elements here -->
</div>
<button id="submit" >Submit</button>
<div id="error-message">
<!-- Display error message to your customers here -->
</div>
</form>
</body>
</html>
checkout.js
const stripe = Stripe("pk_test_...");
const options = {
mode: 'subscription',
amount: 1099,
currency: 'usd',
// Fully customizable with appearance API.
paymentMethodCreation : 'manual',
appearance: {/*...*/},
};
// Set up Stripe.js and Elements to use in checkout form
const elements = stripe.elements(options);
// Create and mount the Express Checkout Element
const expressCheckoutElement = elements.create('expressCheckout');
expressCheckoutElement.mount('#express-checkout-element');
// Create and mount the Payment Element
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
// const form = document.getElementById('express-checkout-element');
// const submitBtn = document.getElementById('submit');
const handleError = (error) => {
const messageContainer = document.querySelector('#error-message');
messageContainer.textContent = error.message;
}
expressCheckoutElement.on('confirm', async (event) => {
const {error: submitError} = await elements.submit();
if (submitError) {
handleError(submitError);
return;
}
stripe
.createConfirmationToken({
elements,
params: {
payment_method_data: {
billing_details: {
name: 'Jenny Rosen',
},
},
},
})
.then(function(result) {
// Handle result.error or result.confirmationToken
console.log(result);
});
});
paymentElement.on('confirm', async (event) => {
const {error: submitError} = await elements.submit();
if (submitError) {
handleError(submitError);
return;
}
stripe
.createConfirmationToken({
elements,
params: {
payment_method_data: {
billing_details: {
name: 'Jenny Rosen',
},
},
},
})
.then(function(result) {
// Handle result.error or result.confirmationToken
console.log(result);
});
});
Hmm, at first glance that looks the same as what I have.
i don't see your payment element mentioned in the code snippet you shared though
I'll dig in tomorrow to figure out what's different it's late here and I need to sign off
Erm it's there in the mountPaymentElement function
alright! Maybe take some time to compare mine against yours, feel free to reach out again on Discord, you'll start a new thread since this one will be closed when you come back after
What are the hours for the discord? 9-5 SGT?