diff --git a/app/frontend/src/javascript/api/api-client.ts b/app/frontend/src/javascript/api/api-client.ts index d7766794f..ad4aa60f2 100644 --- a/app/frontend/src/javascript/api/api-client.ts +++ b/app/frontend/src/javascript/api/api-client.ts @@ -7,6 +7,39 @@ const client: AxiosInstance = axios.create({ 'X-CSRF-Token': token?.content || 'no-csrf-token' } } -}) +}); + +client.interceptors.response.use(function (response) { + // Any status code that lie within the range of 2xx cause this function to trigger + return response; +}, function (error) { + // Any status codes that falls outside the range of 2xx cause this function to trigger + const message = error.response?.data || error.message || error; + return Promise.reject(extractHumanReadableMessage(message)); +}); + +function extractHumanReadableMessage(error: any): string { + if (typeof error === 'string') return error; + + let message = ''; + if (error instanceof Object) { + // iterate through all the keys to build the message + for (const key in error) { + if (Object.prototype.hasOwnProperty.call(error, key)) { + message += `${key} : `; + if (error[key] instanceof Array) { + // standard rails messages are stored as {field: [error1, error2]} + // we rebuild them as "field: error1, error2" + message += error[key].join(', '); + } else { + message += error[key]; + } + } + } + return message; + } + + return JSON.stringify(error); +} export default client; diff --git a/app/frontend/src/javascript/components/stripe-form.tsx b/app/frontend/src/javascript/components/stripe-form.tsx index be6325aa2..a96af73a3 100644 --- a/app/frontend/src/javascript/components/stripe-form.tsx +++ b/app/frontend/src/javascript/components/stripe-form.tsx @@ -45,25 +45,31 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, onE }); if (error) { + // stripe error onError(error.message); } else { - if (!paymentSchedule) { - // process the normal payment pipeline, including SCA validation - const res = await PaymentAPI.confirm(paymentMethod.id, cartItems); - await handleServerConfirmation(res); - } else { - // we start by associating the payment method with the user - const { client_secret } = await PaymentAPI.setupIntent(customer.id); - const { setupIntent, error } = await stripe.confirmCardSetup(client_secret, { - payment_method: paymentMethod.id - }) - if (error) { - onError(error.message); + try { + if (!paymentSchedule) { + // process the normal payment pipeline, including SCA validation + const res = await PaymentAPI.confirm(paymentMethod.id, cartItems); + await handleServerConfirmation(res); } else { - // then we confirm the payment schedule - const res = await PaymentAPI.confirmPaymentSchedule(setupIntent.id, cartItems); - onSuccess(res); + // we start by associating the payment method with the user + const { client_secret } = await PaymentAPI.setupIntent(customer.id); + const { setupIntent, error } = await stripe.confirmCardSetup(client_secret, { + payment_method: paymentMethod.id + }) + if (error) { + onError(error.message); + } else { + // then we confirm the payment schedule + const res = await PaymentAPI.confirmPaymentSchedule(setupIntent.id, cartItems); + onSuccess(res); + } } + } catch (err) { + // catch api errors + onError(err); } } } diff --git a/app/frontend/src/stylesheets/modules/payment-schedule-summary.scss b/app/frontend/src/stylesheets/modules/payment-schedule-summary.scss index 93aaa2f8f..ea08d7a0c 100644 --- a/app/frontend/src/stylesheets/modules/payment-schedule-summary.scss +++ b/app/frontend/src/stylesheets/modules/payment-schedule-summary.scss @@ -11,14 +11,12 @@ position: relative; margin-bottom: 0.75em; .schedule-item-info { - display: block; + display: inline; border-bottom: 1px solid #ddd; - margin-right: 2em; } .schedule-item-price { - position: absolute; - top: 0; - right: 2em; + display: inline; + border-bottom: 1px solid #ddd; } .schedule-item-date { display: block; diff --git a/app/frontend/src/stylesheets/modules/stripe-modal.scss b/app/frontend/src/stylesheets/modules/stripe-modal.scss index 3765227b3..4f39805bd 100644 --- a/app/frontend/src/stylesheets/modules/stripe-modal.scss +++ b/app/frontend/src/stylesheets/modules/stripe-modal.scss @@ -10,7 +10,6 @@ padding: 15px; .stripe-errors { - height: 20px; padding: 4px 0; color: #9e2146; margin-bottom: 1.2em;