Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions packages/join-flow/src/pages/payment-details.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,38 @@ import { PaymentMethodDDSchema, FormSchema, validate } from "../schema";

import { get as getEnv, getStr as getEnvStr, getPaymentProviders, resolveStripePaymentMethodTypes, PaymentMethod, PaymentProvider } from "../env";
import { loadStripe } from "@stripe/stripe-js";
import type { StripeError } from "@stripe/stripe-js";
import { usePostResource } from "../services/rest-resource.service";
import { SAVED_STATE_KEY } from "../services/router.service";

const STRIPE_CODE_MESSAGES: Partial<Record<string, string>> = {
payment_intent_authentication_failure:
"We were unable to authenticate your payment. Please try a different payment method.",
payment_intent_timeout: "Payment timed out. Please try again.",
};

const TECHNICAL_ERROR_TYPES = new Set([
"api_error",
"invalid_request_error",
"authentication_error",
"rate_limit_error",
"idempotency_error",
"stripe_invalid_response_error",
]);

const GENERIC_PAYMENT_ERROR =
"An error occurred processing your payment. Please try again.";

function formatStripeError(error: StripeError): string {
if (error.code && STRIPE_CODE_MESSAGES[error.code]) {
return STRIPE_CODE_MESSAGES[error.code]!;
}
if (!TECHNICAL_ERROR_TYPES.has(error.type)) {
return error.message ?? GENERIC_PAYMENT_ERROR;
}
return GENERIC_PAYMENT_ERROR;
}

export const PaymentDetailsPage: StagerComponent<FormSchema> = ({
data,
setData,
Expand Down Expand Up @@ -400,14 +429,19 @@ const StripeForm = ({
});

if (error) {
const message = JSON.stringify(error)
handleError({ message });
Sentry.captureMessage("Stripe confirmPayment error", {
level: "error",
extra: { stripeError: error },
});
Comment on lines +432 to +435
setLoading(false);
setErrorMessage(formatStripeError(error));
return;
}
} catch (e: any) {
console.error("Create payment error", e);
handleError({ message: e?.message || JSON.stringify(e) || "Unknown error" });
Sentry.captureException(e)
Sentry.captureException(e);
setLoading(false);
setErrorMessage(GENERIC_PAYMENT_ERROR);
}
Comment on lines 440 to 445
};

Expand Down Expand Up @@ -441,7 +475,7 @@ const StripeForm = ({
setData({ ...data, paymentMethod: stripePaymentMethod === "bacs_debit" ? "directDebit" : "creditCard" });
}}/>
<ContinueButton disabled={loading} text={loading ? "Loading..." : ""} />
{errorMessage && <div>{errorMessage}</div>}
{errorMessage && <div className="invalid-feedback d-block mt-3">{errorMessage}</div>}
</div>
</form>
);
Expand Down
6 changes: 5 additions & 1 deletion packages/join-flow/src/services/rest-resource.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ export const usePostResource = <Params, Result = {}>(resource: string) => {
});

if (!res.ok) {
throw Error(await res.text());
const body = await res.text();
const err = new Error(body) as Error & { status: number; resource: string };
err.status = res.status;
err.resource = resource;
Comment on lines +22 to +24
throw err;
}

return res.json();
Expand Down
Loading