diff --git a/packages/payment-widget/package.json b/packages/payment-widget/package.json new file mode 100644 index 0000000..1285631 --- /dev/null +++ b/packages/payment-widget/package.json @@ -0,0 +1,3 @@ +{ + "name": "payment-widget" +} diff --git a/packages/payment-widget/src/index.ts b/packages/payment-widget/src/index.ts new file mode 100644 index 0000000..8decf7e --- /dev/null +++ b/packages/payment-widget/src/index.ts @@ -0,0 +1,2 @@ +export * from './payment-widget.component' +export {AdditionalFieldsNames} from './payment-fields.interfaces' \ No newline at end of file diff --git a/packages/payment-widget/src/payment-fields.component.tsx b/packages/payment-widget/src/payment-fields.component.tsx new file mode 100644 index 0000000..c6f4d80 --- /dev/null +++ b/packages/payment-widget/src/payment-fields.component.tsx @@ -0,0 +1,30 @@ +import {usePayment} from './payment-widget.hook' +import { + AdditionalFieldsProps, + FieldsProps, + RequiredFieldsNames, + RequiredFieldsProps +} from './payment-fields.interfaces' + +const requiredFields: RequiredFieldsProps[] = [ + { + name: RequiredFieldsNames.Amount, + placeholder: 'Сумма заказа', + required: true, + } +] + +export const PaymentFields = ({ additionalFields }: { additionalFields?: AdditionalFieldsProps[] }) => { + const allFields: FieldsProps[] = additionalFields ? + [...requiredFields, ...additionalFields] + : + requiredFields + const {fields, pay} = usePayment(allFields); + + return ( + <> + {fields} + + + ) +} \ No newline at end of file diff --git a/packages/payment-widget/src/payment-fields.interfaces.ts b/packages/payment-widget/src/payment-fields.interfaces.ts new file mode 100644 index 0000000..4292d6c --- /dev/null +++ b/packages/payment-widget/src/payment-fields.interfaces.ts @@ -0,0 +1,28 @@ +export enum RequiredFieldsNames { + Amount = 'amount', +} + +export enum AdditionalFieldsNames { + Name = 'name', + Email = 'email', + Phone = 'phone', + Description = 'description', + Order = 'order', +} + +export type fieldsNames = RequiredFieldsNames | AdditionalFieldsNames + +export interface FieldsProps { + name: fieldsNames + placeholder: string + required?: boolean + type?: string +} + +export interface AdditionalFieldsProps extends FieldsProps { + name: AdditionalFieldsNames +} + +export interface RequiredFieldsProps extends FieldsProps { + name: RequiredFieldsNames +} \ No newline at end of file diff --git a/packages/payment-widget/src/payment-settings.component.tsx b/packages/payment-widget/src/payment-settings.component.tsx new file mode 100644 index 0000000..fdbf556 --- /dev/null +++ b/packages/payment-widget/src/payment-settings.component.tsx @@ -0,0 +1,20 @@ +import {FC} from 'react' +import {PaymentSettingsProps} from './payment-settings.interfaces' + +export const PaymentSettings: FC = (props) => { + const { + storeId, + language = 'ru', + isNewWindow = false, + generateReceipt = false, + } = props + + return ( + <> + + + + { generateReceipt && } + + ) +} \ No newline at end of file diff --git a/packages/payment-widget/src/payment-settings.interfaces.ts b/packages/payment-widget/src/payment-settings.interfaces.ts new file mode 100644 index 0000000..416b8f4 --- /dev/null +++ b/packages/payment-widget/src/payment-settings.interfaces.ts @@ -0,0 +1,12 @@ +interface autoPaymentConfig { + reccurentPayment: boolean + customerKey: string +} + +export interface PaymentSettingsProps { + storeId: string + language?: string + isNewWindow?: boolean + autopayment?: autoPaymentConfig + generateReceipt?: boolean +} \ No newline at end of file diff --git a/packages/payment-widget/src/payment-widget.component.tsx b/packages/payment-widget/src/payment-widget.component.tsx new file mode 100644 index 0000000..51c89e8 --- /dev/null +++ b/packages/payment-widget/src/payment-widget.component.tsx @@ -0,0 +1,12 @@ +import {PaymentWidgetProps} from './payment-widget.interfaces' +import {PaymentSettings} from './payment-settings.component' +import {PaymentFields} from './payment-fields.component' + +export const PaymentWidget = ({settings, additionalFields}: PaymentWidgetProps) => { + return ( +
+ + + + ) +} \ No newline at end of file diff --git a/packages/payment-widget/src/payment-widget.hook.tsx b/packages/payment-widget/src/payment-widget.hook.tsx new file mode 100644 index 0000000..96becef --- /dev/null +++ b/packages/payment-widget/src/payment-widget.hook.tsx @@ -0,0 +1,63 @@ +import {useState, useRef, useEffect} from 'react' +import {fieldsNames, FieldsProps} from './payment-fields.interfaces' + + +const TINKOFF_SCRIPT_URL = 'https://securepay.tinkoff.ru/html/payForm/js/tinkoff_v2.js' + +export const usePayment = (fields: FieldsProps[]) => { + const initialFormState: Record = fields.reduce((acc, field) => { + return { ...acc, [field.name]: '' } + }, {} as Record) + + const [formFields, setFormFields] = + useState>(initialFormState) + const payRef = useRef(null) + + + useEffect(() => { + const script = document.createElement('script') + script.src = TINKOFF_SCRIPT_URL + script.async = true + document.body.appendChild(script) + + script.onload = () => { + payRef.current = (window as any).pay as Function; + } + + script.onerror = () => { + console.error('Failed to load Tinkoff Cashier script.') + } + + return () => { + document.body.removeChild(script) + } + }, []) + + const pay = () => { + try{ + if(payRef.current) { + payRef.current(formFields) + } + }catch (e) { + console.error(e) + } + } + + const handleChange = (name: string, value: string) => { + setFormFields(prevFields => ({ ...prevFields, [name]: value })) + } + + const inputElements = fields.map((field, index) => { + return handleChange(e.target.name, e.target.value)} + /> + }) + + return { fields: inputElements, pay } +} \ No newline at end of file diff --git a/packages/payment-widget/src/payment-widget.interfaces.ts b/packages/payment-widget/src/payment-widget.interfaces.ts new file mode 100644 index 0000000..82c3254 --- /dev/null +++ b/packages/payment-widget/src/payment-widget.interfaces.ts @@ -0,0 +1,7 @@ +import {PaymentSettingsProps} from './payment-settings.interfaces' +import {AdditionalFieldsProps} from './payment-fields.interfaces' + +export interface PaymentWidgetProps { + settings: PaymentSettingsProps + additionalFields?: AdditionalFieldsProps[] +} \ No newline at end of file