결제 폼 만들기
결제 폼 만들기
이제 설정 페이지에 사용자의 신용카드 정보를 입력받고, 스트라이프 토큰을 얻은 후 결제 API를 호출하는 폼을 추가할 것입니다. 먼저 Stripe React SDK를 프로젝트에 추가해 보겠습니다.
packages/frontend/
디렉토리에서 다음 명령어를 실행하세요.
$ npm install @stripe/react-stripe-js
다음으로 결제 폼 컴포넌트를 만들어 보겠습니다.
src/components/BillingForm.tsx
파일에 다음 코드를 추가하세요.
import React, { useState } from "react";
import Form from "react-bootstrap/Form";
import Stack from "react-bootstrap/Stack";
import { useFormFields } from "../lib/hooksLib";
import { Token, StripeError } from "@stripe/stripe-js";
import LoaderButton from "../components/LoaderButton";
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
import "./BillingForm.css";
export interface BillingFormType {
isLoading: boolean;
onSubmit: (
storage: string,
info: { token?: Token; error?: StripeError }
) => Promise<void>;
}
export function BillingForm({ isLoading, onSubmit }: BillingFormType) {
const stripe = useStripe();
const elements = useElements();
const [fields, handleFieldChange] = useFormFields({
name: "",
storage: "",
});
const [isProcessing, setIsProcessing] = useState(false);
const [isCardComplete, setIsCardComplete] = useState(false);
isLoading = isProcessing || isLoading;
function validateForm() {
return (
stripe &&
elements &&
fields.name !== "" &&
fields.storage !== "" &&
isCardComplete
);
}
async function handleSubmitClick(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
if (!stripe || !elements) {
// Stripe.js가 아직 로드되지 않았습니다. Stripe.js가 로드될 때까지 폼 제출을 비활성화하세요.
return;
}
if (!elements.getElement(CardElement)) {
return;
}
setIsProcessing(true);
const cardElement = elements.getElement(CardElement);
if (!cardElement) {
return;
}
const { token, error } = await stripe.createToken(cardElement);
setIsProcessing(false);
onSubmit(fields.storage, { token, error });
}
return (
<Form className="BillingForm" onSubmit={handleSubmitClick}>
<Form.Group controlId="storage">
<Form.Label>Storage</Form.Label>
<Form.Control
min="0"
size="lg"
type="number"
value={fields.storage}
onChange={handleFieldChange}
placeholder="Number of notes to store"
/>
</Form.Group>
<hr />
<Stack gap={3}>
<Form.Group controlId="name">
<Form.Label>Cardholder's name</Form.Label>
<Form.Control
size="lg"
type="text"
value={fields.name}
onChange={handleFieldChange}
placeholder="Name on the card"
/>
</Form.Group>
<div>
<Form.Label>Credit Card Info</Form.Label>
<CardElement
className="card-field"
onChange={(e) => setIsCardComplete(e.complete)}
options={{
style: {
base: {
fontSize: "16px",
fontWeight: "400",
color: "#495057",
fontFamily: "'Open Sans', sans-serif",
},
},
}}
/>
</div>
<LoaderButton
size="lg"
type="submit"
isLoading={isLoading}
disabled={!validateForm()}
>
Purchase
</LoaderButton>
</Stack>
</Form>
);
}
여기서 어떤 작업을 하는지 간단히 살펴보겠습니다:
-
먼저
useStripe
를 호출하여 Stripe 객체에 대한 참조를 얻습니다. -
폼 필드에는 사용자가 저장할 노트의 수를 입력할 수 있는
number
타입의 입력 필드와 신용카드에 적힌 이름을 입력받는 필드가 있습니다. 이 값들은 커스텀 React Hook인useFormFields
에서 제공하는handleFieldChange
메서드를 통해 상태로 관리됩니다. -
신용카드 번호 입력 필드는 Stripe React SDK에서 제공하는
CardElement
컴포넌트를 사용합니다. -
제출 버튼은 Stripe 토큰을 요청하거나 결제 API를 호출할 때 로딩 상태가 됩니다. 하지만 설정 컨테이너에서 결제 API를 호출하기 때문에
props.isLoading
을 사용하여 버튼의 상태를 설정합니다. -
폼 유효성 검사는 이름, 노트 수, 카드 정보가 모두 입력되었는지 확인합니다. 카드 정보는
CardElement
의onChange
메서드를 사용하여 검사합니다. -
마지막으로 사용자가 폼을 완료하고 제출하면
CardElement
를 전달하여 Stripe를 호출합니다. 이를 통해 특정 호출에 대한 토큰을 생성합니다. 이 토큰과 저장할 노트 수를onSubmit
메서드를 통해 설정 페이지로 전달합니다. 이 부분은 곧 설정할 예정입니다.
React Stripe SDK 사용법에 대해 더 알아볼 수 있습니다.
또한 카드 필드에 스타일을 추가하여 UI와 일관성을 유지하겠습니다.
src/components/BillingForm.css
파일을 생성하세요.
.BillingForm .card-field {
line-height: 1.5;
padding: 0.65rem 0.75rem;
background-color: var(--bs-body-bg);
border: 1px solid var(--bs-border-color);
border-radius: var(--bs-border-radius-lg);
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.BillingForm .card-field.StripeElement--focus {
outline: 0;
border-color: #86B7FE;
box-shadow: 0 0 0 .25rem rgba(13, 110, 253, 0.25);
}
이 스타일은 복잡해 보일 수 있지만, 페이지의 다른 폼 필드와 일관성을 유지하기 위해 해당 필드의 스타일을 복사한 것입니다.
다음으로 이 폼을 설정 페이지에 연결하겠습니다.
For help and discussion
Comments on this chapter