Компонент Stripe ‹CardElement /› по умолчанию выглядит прилично и действительно прост в использовании, и по умолчанию принимает номер карты, срок действия и CVC в одной области ввода.
Однако некоторые макеты требуют, чтобы вы отделяли ввод CVC и срок действия от номера карты. Я начинаю это руководство с того момента, как уже завершил реализацию ‹CardElement /› (код приведен ниже). Тем не менее, я не вникаю в фактическую настройку чередования, например, установку библиотек чередования для реакции, получение обещания чередования или перенос провайдера ‹Elements /› на модальный компонент оплаты.


Вот код, который я написал для создания этого простого платежного модала:
const stripe = useStripe();
const elements = useElements();
const createSubscription = async () => {
setLoading(true);
try {
// create a payment method
const paymentMethod = await stripe?.createPaymentMethod({
type: "card",
card: elements.getElement(CardElement),
billing_details: {
name: GlobalAppState.getUser().name,
}
});
}
catch (error) {
ZensoryModule.getErrorHandler().handleError(error);
console.log(error);
}
}
<div className="popup-container-payment" ref={modalRef}>
<div className="popup-header">
<img
id="btn-auth-error-popup-close"
src={cross}
className="popup-close-icon"
onClick={(e) => closePopup(e)}
alt="Close popup"
tabIndex="0"
onKeyDown={(e) => _handleKeyDownClose(e)}
/>
</div>
<div className="popup-instruction-payment">
{getText(TextId.subscribePayment)}
</div>
<div className="card-entry">
<CardElement options={cardElementOptions} />
</div>
{loading ? (
<div
style={{
position: "relative",
marginBottom: "40px",
marginTop: "10px",
}}
>
<SpinnerLoader />
</div>
) : (
<button
disabled={!stripe || loading}
id="btn-auth-error-popup-okay"
tabIndex="0"
className="subscribe-button"
onClick={createSubscription}
>
Subscribe
</button>
)}
<div>
<img src={stripePower} alt="Powered by stripe" />
</div>
</div>
Однако внешний вид, которого я хотел добиться, был (это дизайн):

Для этого нам нужно заменить ‹CardElement /› на ‹CardNumberElement /›, ‹CardExpiryElement /› и ‹CardCvcElement /›.
Обновленный код:
const stripe = useStripe();
const elements = useElements();
const createSubscription = async () => {
setLoading(true);
try {
// create a payment method
const paymentMethod = await stripe?.createPaymentMethod({
type: "card",
card: elements.getElement(CardNumberElement), //please note this is changed from the original code
billing_details: {
name: GlobalAppState.getUser().name,
}
});
}
catch (error) {
ZensoryModule.getErrorHandler().handleError(error);
console.log(error);
}
}
<div className="popup-container-payment" ref={modalRef}>
<div className="popup-header">
<img
id="btn-auth-error-popup-close"
src={cross}
className="popup-close-icon"
onClick={(e) => closePopup(e)}
alt="Close popup"
tabIndex="0"
onKeyDown={(e) => _handleKeyDownClose(e)}
/>
</div>
<div className="popup-instruction-payment">
{getText(TextId.subscribePayment)}
</div>
<div className="card-entry">
<CardNumberElement options={cardElementOptions} />
</div>
<div className="expiry-cvc-entry">
<div className="card-entry">
<CardExpiryElement options={cardElementOptions} />
</div>
<div className="card-entry">
<CardCvcElement options={cardElementOptions} />
</div>
</div>
{loading ? (
<div
style={{
position: "relative",
marginBottom: "40px",
marginTop: "10px",
}}
>
<SpinnerLoader />
</div>
) : (
<button
disabled={!stripe || loading}
id="btn-auth-error-popup-okay"
tabIndex="0"
className="subscribe-button"
onClick={createSubscription}
>
Subscribe
</button>
)}
<div>
<img src={stripePower} alt="Powered by stripe" />
</div>
</div>
Достигнутый результат:

Этот макет может быть просто требованием дизайна или выбором UX. На мой взгляд, он выглядит более профессионально, а также хорошо понятен пользователям.