Створення користувацького інтерфейсу кредитної картки з Adyen і React + TypeScript

Вступ

Adyen — це популярне платіжне рішення, яке надає можливості для безпечної обробки платежів. Хоча Adyen пропонує готові компоненти, іноді нам потрібен більший контроль над інтерфейсом користувача (UI), при цьому зберігаючи стандарти безпеки. У цій статті ми дізнаємося, як реалізувати кастомізований інтерфейс для введення кредитної картки, використовуючи захищені поля Adyen з React-хуками та TypeScript.

Необхідні вимоги

Перед тим як почати, переконайтесь, що у вас є:

  • Налаштований проект на React + TypeScript (ми будемо використовувати Vite)
  • Облікові дані клієнта Adyen
  • Node.js версії 18.17.0 або новішої
  • Базові знання React-хуків та TypeScript

Налаштування проекту

Спочатку створіть новий проект Vite з React та TypeScript:

npm create vite@latest adyen-integration -- --template react-ts  
cd adyen-integration  
npm install

Потім встановіть необхідні пакети:

npm install @adyen/adyen-web

Реалізація

1. Ініціалізація конфігурації Adyen

Спочатку створимо кастомний хук для ініціалізації Adyen. Цей хук буде обробляти базову конфігурацію та створювати екземпляр checkout.

// src/hooks/useInitializeAdyen.ts  
import { useState, useEffect } from "react";  
import { AdyenCheckout, AdyenConfiguration } from "@adyen/adyen-web";  
import "@adyen/adyen-web/styles/adyen.css";
interface AdyenConfiguration {  
 locale: string;  
 countryCode: string;  
 environment: "test" | "live" | "live-us" | "live-au" | "live-apse" | "live-in";  
 clientKey: string;  
 analytics: {  
 enabled: boolean;  
 };  
} 

export default function useInitializeAdyen() {  
 const [checkout, setCheckout] = useState(null); 
 useEffect(() => {  
   const initializeCheckout = async () => {  
     const configuration: AdyenConfiguration = {  
       locale: "en-US",  
       countryCode: "US",  
       environment: "test",  
       clientKey: "YOUR_CLIENT_KEY",  
       analytics: {  
         enabled: false,  
       },  
     };  
     try {  
       const checkoutInstance = await AdyenCheckout(configuration);  
       setCheckout(checkoutInstance);  
     } catch (error) {  
       console.error("Error initializing Adyen:", error);  
     }  
   };  
   initializeCheckout();  
 }, []);  
 return { checkout };  
}

## Створення хука для Adyen Checkout

Далі ми створимо хук, щоб обробляти компонент кредитної картки з обробкою помилок:

// src/hooks/useAdyenCheckout.ts
import { useEffect, useReducer, useRef } from "react";
import useInitializeAdyen from "./useInitializeAdyen";
import { CustomCard, CustomCardConfiguration } from "@adyen/adyen-web";
```

const initialState = {  
 cardNumberError: "",  
 dateError: "",  
 cvcError: "",  
}; 

function reducer(  
 state: typeof initialState,  
 action: { type: string; payload: string }  
) {  
 switch (action.type) {  
 case "SET_CARD_NUMBER_ERROR":  
 return { ...state, cardNumberError: action.payload };  
 case "SET_DATE_ERROR":  
 return { ...state, dateError: action.payload };  
 case "SET_CVC_ERROR":  
 return { ...state, cvcError: action.payload };  
 default:  
 return state;  
 }  
} 

export default function useAdyenCheckout() {  
 const { checkout } = useInitializeAdyen();  
 const cardRef = useRef(null);  
 const [errorState, dispatch] = useReducer(reducer, initialState); 

 useEffect(() => {  
 if (checkout) {  
   const configuration: CustomCardConfiguration = {  
     type: "card",  
     brands: ["visa", "mc"],  
     onError: (error) => {  
       console.error("Error:", error);  
     },  
     onChange: (state) => {  
       // Обробка помилок номера картки  
       if (state.errors?.encryptedCardNumber) {  
         dispatch({  
           type: "SET_CARD_NUMBER_ERROR",  
           payload: state.errors.encryptedCardNumber.errorMessage,  
         });  
       } else {  
         dispatch({ type: "SET_CARD_NUMBER_ERROR", payload: "" });  
       } 
       // Обробка помилок дати  
       if (state.errors?.encryptedExpiryDate) {  
         dispatch({  
           type: "SET_DATE_ERROR",  
           payload: "Будь ласка, введіть правильну дату",  
         });  
       } else {  
         dispatch({ type: "SET_DATE_ERROR", payload: "" });  
       } 
       // Обробка помилок CVC  
       if (state.errors?.encryptedSecurityCode) {  
         dispatch({  
           type: "SET_CVC_ERROR",  
           payload: "Будь ласка, введіть правильний CVC",  
         });  
       } else {  
         dispatch({ type: "SET_CVC_ERROR", payload: "" });  
       } 
       if (state.isValid) {  
         console.log("Картка є валідною:", state.data);  
       }  
     },  
     onBrand: (brand: { brand: string }) => {  
       console.log('Бренд картки:', brand);  
     },  
     styles: {  
       base: {  
         color: "#000",  
         fontSize: "14px",  
         fontFamily: "Arial, sans-serif",  
       },  
     },  
     placeholders: {  
       encryptedCardNumber: 'Номер картки',  
       encryptedExpiryMonth: 'MM',  
       encryptedExpiryYear: 'YY',  
       encryptedSecurityCode: 'CVC'  
     }  
   };  
   const card = new CustomCard(checkout, configuration).mount(  
     "#card-container"  
   );  
   cardRef.current = card;  
 }  
 return () => {  
   if (cardRef.current) {  
     cardRef.current.unmount();  
   }  
 };  
 }, [checkout]); 

 return { card: cardRef.current, errors: errorState };  
}

3. Створення компонента для картки

Тепер створимо React-компонент, який буде рендерити нашу кастомізовану форму для кредитної картки:

// src/components/CreditCardForm.tsx  
import React from 'react';  
import useAdyenCheckout from '../hooks/useAdyenCheckout';  
import './CreditCardForm.css';
const CreditCardForm: React.FC = () => {  
 const { errors } = useAdyenCheckout(); 
 return (  
   <div>  
     Номер картки  
     {errors.cardNumberError && (    
       <div className="error">{errors.cardNumberError}</div>  
     )}    
     Дата закінчення терміну  
     {errors.dateError && (    
       <div className="error">{errors.dateError}</div>  
     )}    
     CVC / CVV    
   </div>  
 );   
}; 

export default CreditCardForm;

## Стилізація

Додайте CSS для форми:

/* src/components/CreditCardForm.css */
.card-form {
max-width: 400px;
padding: 20px;
margin: 0 auto;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
```

.form-group {  
 margin-bottom: 16px;  
} 

label {  
 display: block;  
 margin-bottom: 8px;  
 color: #333;  
 font-weight: 500;  
}

.form-row {  
 display: flex;  
 gap: 16px;  
} 

.card-field,  
.date-fields,  
.cvv-field {  
 height: 40px;  
 padding: 8px;  
 border: 1px solid #ccc;  
 border-radius: 4px;  
 background: #fff;  
}

.date-fields {  
 display: flex;  
 gap: 8px;  
} 

.card-field:focus-within,  
.date-fields:focus-within,  
.cvv-field:focus-within {  
 border-color: #0066cc;  
 box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.2);  
}

.error-message {  
 color: #d10244;  
 font-size: 12px;  
 margin-top: 4px;  
}

/* Стилі для iframe Adyen */  
iframe {  
 border: none;  
 margin: 0;  
 padding: 0;  
 width: 100%;  
 height: 100%;  
}

5. Оновлення компонента App

Нарешті, оновіть ваш компонент App, щоб використовувати форму кредитної картки:

// src/App.tsx  
import CreditCardForm from './components/CreditCardForm'  
import './App.css'
function App() {  
 return (  
   <div>  
     Інтеграція платежів Adyen  
   </div>  
 );   
} 

export default App;

Додайте базову стилізацію для додатку:

/* src/App.css */  
.app {  
  max-width: 800px;  
  margin: 0 auto;  
  padding: 40px 20px;  
}
h1 {  
  text-align: center;  
  color: #333;  
  margin-bottom: 40px;  
}

Ключові особливості

1. Типова безпека:
- Повна підтримка TypeScript з правильними інтерфейсами
- Сильна перевірка типів для конфігурацій і стану
- Кращий досвід розробки з підказками типів

2. Обробка помилок:
- Деталізовані повідомлення про помилки для кожного поля
- Реальний час перевірки валідності
- Правильне управління станом помилок з використанням useReducer

3. Безпека:
- Дані картки безпосередньо шифруються Adyen
- Жодні чутливі дані не потрапляють на ваші сервери
- Відповідність стандартам PCI забезпечується Adyen

4. Кастомізація:
- Повний контроль над розташуванням інтерфейсу
- Кастомні стилі
- Гнучка обробка помилок і їх відображення

5. Валідність:
- Перевірка валідності номера картки в реальному часі
- Визначення типу картки
- Перевірка терміну дії та CVC

Кращі практики

  1. Завжди обробляйте помилки коректно та показуйте чіткі повідомлення
  2. Тестуйте ретельно як у тестовому, так і в реальному середовищі
  3. Ніколи не зберігайте та не реєструйте дані карток
  4. Завжди використовуйте HTTPS
  5. Оновлюйте Node.js та залежності до останніх версій
  6. Використовуйте TypeScript для кращої типізації
  7. Реалізуйте правильні стани завантаження
  8. Правильно обробляйте демонтаж компонентів

Важливі зауваження

  1. Замініть YOUR_CLIENT_KEY на ваш фактичний клієнтський ключ Adyen
  2. Переконайтеся, що використовуєте Node.js версії 18.17.0 або вищої
  3. В середовищі продукції потрібно використовувати параметр “live”
  4. Рекомендується реалізувати стани завантаження та межі помилок
  5. Додайте правильну обробку помилок для продуктивного використання
  6. Тестуйте з різними типами карток і сценаріями помилок

Ресурси

Перекладено з: Creating Custom Credit Card UI with Adyen and React + TypeScript

Leave a Reply

Your email address will not be published. Required fields are marked *