TD-697: Bump typescript, prettier, eslint (#228)

This commit is contained in:
Ildar Galeev 2023-08-16 18:48:04 +03:00 committed by GitHub
parent 0317ed841b
commit f06f7f9461
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
278 changed files with 4882 additions and 5047 deletions

55
.eslintrc.js Normal file
View File

@ -0,0 +1,55 @@
module.exports = {
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:@typescript-eslint/recommended',
'prettier',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'import', 'react'],
root: true,
rules: {
'import/order': [
'error',
{
alphabetize: {
caseInsensitive: true,
order: 'asc',
},
groups: [['builtin', 'external'], 'internal', ['parent', 'sibling', 'index'], 'object'],
'newlines-between': 'always',
pathGroups: [
{
group: 'internal',
pattern: 'checkout/**',
},
],
pathGroupsExcludedImportTypes: ['builtin'],
},
],
'react/jsx-filename-extension': ['error', { extensions: ['.tsx', '.ts'] }],
'react/jsx-max-depth': ['error', { max: 3 }],
'react/jsx-sort-props': [
'error',
{
callbacksLast: true,
ignoreCase: false,
locale: 'auto',
multiline: 'last',
noSortAlphabetically: false,
reservedFirst: true,
shorthandFirst: true,
},
],
'react/require-default-props': [0],
'@typescript-eslint/no-explicit-any': 'off',
'no-case-declarations': 'off',
},
settings: {
react: {
version: 'detect',
},
},
};

View File

@ -3,7 +3,7 @@ name: Vality basic linters
on:
pull_request:
branches:
- "*"
- '*'
jobs:
lint:

View File

@ -15,8 +15,8 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
check:
name: Check
lint-format-check:
name: Lint and prettier check
runs-on: ubuntu-latest
needs: [init]
steps:
@ -26,14 +26,22 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
- name: Init NodeJS
uses: actions/setup-node@v3
- name: Lint
run: npm run lint
- name: Prettier
run: npm run prettier
test:
name: Test
runs-on: ubuntu-latest
needs: [init]
steps:
- name: Cache
uses: actions/cache@v3
id: cache
with:
node-version: '16.13.2'
cache: 'npm'
- name: Check
run: npm run check
- name: Run tests
path: ./*
key: ${{ github.sha }}
- name: Test
run: npm run test
build:
name: Build
@ -46,10 +54,5 @@ jobs:
with:
path: ./*
key: ${{ github.sha }}
- name: Init NodeJS
uses: actions/setup-node@v3
with:
node-version: '16.13.2'
cache: 'npm'
- name: Build
run: npm run build

View File

@ -1,38 +1,7 @@
# Exclude everything by default
/**/*
# Include all folders
!/**/*/
# Includes
!*.js
!*.jsx
!*.ts
!*.tsx
!*.css
!*.scss
!*.html
!*.md
!*.svg
!*.json
!*.prettierrc
!*.babelrc
# Excludes
package-lock.json
package.json
node_modules
dist
# VS Code
.vscode
# IDEA
.idea
# Crowdin formats json in his own way
src/locale/*.json

View File

@ -2,8 +2,6 @@
"printWidth": 120,
"tabWidth": 4,
"singleQuote": true,
"jsxBracketSameLine": true,
"arrowParens": "always",
"overrides": [
{
"files": "*.svg",

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html dir="ltr">
<head>
<meta charset="utf-8" />

View File

@ -3,6 +3,6 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'jest-environment-jsdom',
moduleNameMapper: {
'^checkout/(.*)': '<rootDir>/src/app/$1'
}
'^checkout/(.*)': '<rootDir>/src/app/$1',
},
};

6919
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,15 +6,13 @@
"dev": "vite --c vite.config.app.ts",
"build:app": "vite build --c vite.config.app.ts",
"build:checkout": "vite build --c vite.config.checkout.ts",
"build": "npm run build:checkout && npm run build:app",
"build": "tsc && npm run build:checkout && npm run build:app",
"preview": "npm run build && vite --c vite.config.preview.ts",
"test": "jest",
"test:watch": "jest --watch",
"prettier:fix": "prettier \"**\" --write",
"prettier:check": "prettier \"**\" --list-different",
"lint:fix": "tslint \"src/**/*.@(ts|tsx)\" -e \"**/*.d.ts\"",
"check": "npm run lint:fix; npm run prettier:check",
"fix": "npm run lint:fix; npm run prettier:fix"
"prettier": "prettier * --list-different --ignore-unknown",
"prettier:fix": "prettier * --write --ignore-unknown",
"lint": "eslint -c .eslintrc.js --ext .ts,.tsx ."
},
"license": "Apache-2.0",
"dependencies": {
@ -45,17 +43,18 @@
"@types/react": "18.2.14",
"@types/react-dom": "18.2.6",
"@types/react-test-renderer": "18.0.0",
"@typescript-eslint/eslint-plugin": "6.4.0",
"@vitejs/plugin-react": "4.0.3",
"eslint": "8.47.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-import": "2.28.0",
"eslint-plugin-react": "7.33.1",
"jest": "29.5.0",
"jest-environment-jsdom": "29.5.0",
"prettier": "~1.19.1",
"prettier": "3.0.1",
"react-test-renderer": "18.2.0",
"ts-jest": "29.1.0",
"tslint": "~5.11.0",
"tslint-config-prettier": "~1.18.0",
"tslint-immutable": "~4.5.1",
"tslint-react": "~3.6.0",
"typescript": "4.5.4",
"typescript": "5.1.6",
"vite": "4.4.6",
"vite-plugin-static-copy": "0.17.0",
"vite-plugin-svgr": "3.2.0",

View File

@ -1,16 +1,17 @@
import { InvoiceAndToken, InvoiceParamsWithTemplate } from 'checkout/backend/model';
import { fetchCapi } from '.';
import v from './capi-version';
import { InvoiceAndToken, InvoiceParamsWithTemplate } from 'checkout/backend/model';
export const createInvoiceWithTemplate = (
capiEndpoint: string,
accessToken: string,
invoiceTemplateID: string,
params: InvoiceParamsWithTemplate
params: InvoiceParamsWithTemplate,
): Promise<InvoiceAndToken> =>
fetchCapi({
method: 'POST',
endpoint: `${capiEndpoint}/${v}/processing/invoice-templates/${invoiceTemplateID}/invoices`,
accessToken,
body: params
body: params,
});

View File

@ -1,4 +1,5 @@
import { ClientInfo, PaymentResource, PaymentTool } from 'checkout/backend/model';
import v from './capi-version';
import { fetchCapi } from './fetch-capi';
@ -6,7 +7,7 @@ export const createPaymentResource = (
capiEndpoint: string,
accessToken: string,
paymentTool: PaymentTool,
clientInfo: ClientInfo
clientInfo: ClientInfo,
): Promise<PaymentResource> =>
fetchCapi<PaymentResource>({
endpoint: `${capiEndpoint}/${v}/processing/payment-resources`,
@ -14,6 +15,6 @@ export const createPaymentResource = (
method: 'POST',
body: {
paymentTool,
clientInfo
}
clientInfo,
},
});

View File

@ -1,16 +1,16 @@
import { PaymentParams, Payment } from './model';
import v from './capi-version';
import { fetchCapi } from './fetch-capi';
import { PaymentParams, Payment } from './model';
export const createPayment = (
capiEndpoint: string,
accessToken: string,
invoiceID: string,
paymentParams: PaymentParams
paymentParams: PaymentParams,
): Promise<Payment> =>
fetchCapi({
method: 'POST',
endpoint: `${capiEndpoint}/${v}/processing/invoices/${invoiceID}/payments`,
accessToken,
body: paymentParams
body: paymentParams,
});

View File

@ -3,14 +3,14 @@ import { fetchCapi } from './fetch-capi';
describe('fetch capi', () => {
test('should do GET request', async () => {
const expected = {
someField: 'someValue'
someField: 'someValue',
};
const mockFetch = jest.fn();
mockFetch.mockResolvedValue({
status: 200,
ok: true,
json: async () => expected
json: async () => expected,
});
global.fetch = mockFetch;
@ -25,22 +25,22 @@ describe('fetch capi', () => {
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json;charset=utf-8',
'X-Request-ID': expect.any(String)
'X-Request-ID': expect.any(String),
},
method: 'GET'
method: 'GET',
});
});
test('should do POST request', async () => {
const expected = {
someField: 'someValue'
someField: 'someValue',
};
const mockFetch = jest.fn();
mockFetch.mockResolvedValue({
status: 200,
ok: true,
json: async () => expected
json: async () => expected,
});
global.fetch = mockFetch;
@ -57,9 +57,9 @@ describe('fetch capi', () => {
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json;charset=utf-8',
'X-Request-ID': expect.any(String)
'X-Request-ID': expect.any(String),
},
method
method,
});
});
@ -69,7 +69,7 @@ describe('fetch capi', () => {
mockFetch.mockResolvedValue({
status: 500,
ok: false,
statusText
statusText,
});
global.fetch = mockFetch;
@ -78,14 +78,18 @@ describe('fetch capi', () => {
try {
await fetchCapi({ endpoint, accessToken });
} catch (error) {
expect(error).toStrictEqual({ status: 500, statusText, details: undefined });
expect(error).toStrictEqual({
status: 500,
statusText,
details: undefined,
});
}
});
test('should retry json reject', async () => {
const errorMsg = 'Read json error';
const expected = {
someField: 'someValue'
someField: 'someValue',
};
const mockFetchJson = jest
.fn()
@ -95,7 +99,7 @@ describe('fetch capi', () => {
const mockFetch = jest.fn().mockResolvedValue({
status: 200,
ok: true,
json: mockFetchJson
json: mockFetchJson,
});
global.fetch = mockFetch;
@ -112,7 +116,7 @@ describe('fetch capi', () => {
test('should retry failed fetch requests', async () => {
const expected = {
someField: 'someValue'
someField: 'someValue',
};
const mockFetch = jest
@ -122,7 +126,7 @@ describe('fetch capi', () => {
.mockResolvedValueOnce({
status: 200,
ok: true,
json: async () => expected
json: async () => expected,
});
global.fetch = mockFetch;
@ -140,9 +144,9 @@ describe('fetch capi', () => {
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json;charset=utf-8',
'X-Request-ID': expect.any(String)
'X-Request-ID': expect.any(String),
},
method: 'GET'
method: 'GET',
};
expect(mockFetch).toHaveBeenCalledWith(endpoint, requestInit);
expect(mockFetch).toHaveBeenCalledWith(endpoint, requestInit);

View File

@ -1,5 +1,5 @@
import guid from 'checkout/utils/guid';
import delay from 'checkout/utils/delay';
import guid from 'checkout/utils/guid';
export type FetchCapiParams = {
endpoint: string;
@ -25,7 +25,7 @@ const provideResponse = async (response: Response, retryDelay: number, retryLimi
return Promise.reject({
status: response.status,
statusText: response.statusText || undefined,
details: await getDetails(response)
details: await getDetails(response),
});
} catch (ex) {
if (attempt === retryLimit) {
@ -44,9 +44,9 @@ const doFetch = async (param: FetchCapiParams, retryDelay: number, retryLimit: n
headers: {
'Content-Type': 'application/json;charset=utf-8',
Authorization: param.accessToken ? `Bearer ${param.accessToken}` : undefined,
'X-Request-ID': guid()
'X-Request-ID': guid(),
},
body: param.body ? JSON.stringify(param.body) : undefined
body: param.body ? JSON.stringify(param.body) : undefined,
});
} catch (ex) {
if (attempt === retryLimit) {

View File

@ -1,5 +1,6 @@
import { AppConfig } from './app-config';
import { getNocacheValue } from 'checkout/utils';
import { AppConfig } from './app-config';
import { fetchCapi } from './fetch-capi';
export const getAppConfig = (): Promise<AppConfig> =>

View File

@ -1,4 +1,5 @@
import { getNocacheValue } from 'checkout/utils';
import { fetchCapi } from './fetch-capi';
export interface Env {

View File

@ -1,13 +1,14 @@
import { InvoiceEvent } from 'checkout/backend/model';
import { fetchCapi } from '.';
import v from './capi-version';
import { InvoiceEvent } from 'checkout/backend/model';
export const getInvoiceEvents = (
capiEndpoint: string,
accessToken: string,
invoiceID: string,
limit: number = 50,
eventID?: number
eventID?: number,
): Promise<InvoiceEvent[]> => {
let endpoint = `${capiEndpoint}/${v}/processing/invoices/${invoiceID}/events?limit=${limit}`;
endpoint = eventID ? endpoint + `&eventID=${eventID}` : endpoint;

View File

@ -4,9 +4,9 @@ import v from './capi-version';
export const getInvoicePaymentMethodsByTemplateID = (
capiEndpoint: string,
accessToken: string,
invoiceTemplateID: string
invoiceTemplateID: string,
): Promise<PaymentMethod[]> =>
fetchCapi({
endpoint: `${capiEndpoint}/${v}/processing/invoice-templates/${invoiceTemplateID}/payment-methods`,
accessToken
accessToken,
});

View File

@ -4,9 +4,9 @@ import v from './capi-version';
export const getInvoicePaymentMethods = (
capiEndpoint: string,
accessToken: string,
invoiceID: string
invoiceID: string,
): Promise<PaymentMethod[]> =>
fetchCapi({
endpoint: `${capiEndpoint}/${v}/processing/invoices/${invoiceID}/payment-methods`,
accessToken
accessToken,
});

View File

@ -4,9 +4,9 @@ import v from './capi-version';
export const getInvoiceTemplateByID = (
capiEndpoint: string,
accessToken: string,
invoiceTemplateID: string
invoiceTemplateID: string,
): Promise<InvoiceTemplate> =>
fetchCapi({
endpoint: `${capiEndpoint}/${v}/processing/invoice-templates/${invoiceTemplateID}`,
accessToken
accessToken,
});

View File

@ -4,5 +4,5 @@ import v from './capi-version';
export const getInvoiceByID = (capiEndpoint: string, accessToken: string, invoiceID: string): Promise<Invoice> =>
fetchCapi({
endpoint: `${capiEndpoint}/${v}/processing/invoices/${invoiceID}`,
accessToken
accessToken,
});

View File

@ -1,7 +1,10 @@
import { Locale } from 'checkout/locale';
import { detectLocale } from '../../locale';
import { getNocacheValue } from 'checkout/utils';
import { fetchCapi } from './fetch-capi';
import { detectLocale } from '../../locale';
export const getLocale = (locale: string): Promise<Locale> =>
fetchCapi({ endpoint: `../v1/locale/${detectLocale(locale)}.json?nocache=${getNocacheValue()}` });
fetchCapi({
endpoint: `../v1/locale/${detectLocale(locale)}.json?nocache=${getNocacheValue()}`,
});

View File

@ -4,9 +4,9 @@ import v from './capi-version';
export const getServiceProviderByID = (
capiEndpoint: string,
accessToken: string,
serviceProviderID: string
serviceProviderID: string,
): Promise<ServiceProvider> =>
fetchCapi({
endpoint: `${capiEndpoint}/${v}/processing/service-providers/${serviceProviderID}`,
accessToken
accessToken,
});

View File

@ -1,7 +1,6 @@
import { PaymentMethod } from './payment-method';
import { PaymentSystem } from './payment-system';
import { PaymentMethod, PaymentMethodName } from './payment-method';
export class BankCard extends PaymentMethod {
method: PaymentMethodName.BankCard;
paymentSystems: PaymentSystem[];
}

View File

@ -1,6 +1,5 @@
import { PaymentMethod, PaymentMethodName } from './payment-method';
import { PaymentMethod } from './payment-method';
export class DigitalWallet extends PaymentMethod {
method: PaymentMethodName.DigitalWallet;
providers: string[];
}

View File

@ -4,5 +4,5 @@ export enum InvoiceChangeType {
PaymentInteractionRequested = 'PaymentInteractionRequested',
PaymentInteractionCompleted = 'PaymentInteractionCompleted',
PaymentStarted = 'PaymentStarted',
PaymentStatusChanged = 'PaymentStatusChanged'
PaymentStatusChanged = 'PaymentStatusChanged',
}

View File

@ -1,6 +1,7 @@
import { InvoiceChangeType } from 'checkout/backend/model/event/invoice-change-type';
import { InvoiceChange } from './invoice-change';
import { Invoice } from '../invoice';
import { InvoiceChangeType } from 'checkout/backend/model/event/invoice-change-type';
export class InvoiceCreated extends InvoiceChange {
changeType = InvoiceChangeType.InvoiceCreated;

View File

@ -1,4 +1,5 @@
import { InvoiceChange } from 'checkout/backend/model/event/invoice-change';
import { Event } from './event';
export class InvoiceEvent extends Event<InvoiceChange> {}

View File

@ -6,7 +6,7 @@ export enum InvoiceStatuses {
cancelled = 'cancelled',
fulfilled = 'fulfilled',
unpaid = 'unpaid',
refunded = 'refunded'
refunded = 'refunded',
}
export class InvoiceStatusChanged extends InvoiceChange {

View File

@ -1,6 +1,6 @@
import { InvoiceChange } from './invoice-change';
import { Payment } from '../payment';
import { InvoiceChangeType } from './invoice-change-type';
import { Payment } from '../payment';
export class PaymentStarted extends InvoiceChange {
changeType = InvoiceChangeType.PaymentStarted;

View File

@ -1,6 +1,7 @@
import { PaymentError } from 'checkout/backend';
import { InvoiceChange } from './invoice-change';
import { InvoiceChangeType } from './invoice-change-type';
import { PaymentError } from 'checkout/backend';
export enum PaymentStatuses {
processed = 'processed',
@ -8,7 +9,7 @@ export enum PaymentStatuses {
cancelled = 'cancelled',
pending = 'pending',
captured = 'captured',
refunded = 'refunded'
refunded = 'refunded',
}
export class PaymentStatusChanged extends InvoiceChange {

View File

@ -1,5 +1,5 @@
export enum InteractionType {
Redirect = 'Redirect',
PaymentTerminalReceipt = 'PaymentTerminalReceipt',
QrCodeDisplayRequest = 'QrCodeDisplayRequest'
QrCodeDisplayRequest = 'QrCodeDisplayRequest',
}

View File

@ -1,5 +1,5 @@
import { UserInteraction } from './user-interaction';
import { BrowserRequest } from './browser-request';
import { UserInteraction } from './user-interaction';
export class Redirect extends UserInteraction {
request: BrowserRequest;

View File

@ -1,4 +1,4 @@
export enum RequestType {
BrowserGetRequest = 'BrowserGetRequest',
BrowserPostRequest = 'BrowserPostRequest'
BrowserPostRequest = 'BrowserPostRequest',
}

View File

@ -3,5 +3,5 @@ export enum InvoiceStatus {
paid = 'paid',
cancelled = 'cancelled',
refunded = 'refunded',
fulfilled = 'fulfilled'
fulfilled = 'fulfilled',
}

View File

@ -1,5 +1,5 @@
import { InvoiceTemplate } from './invoice-template';
import { AccessToken } from './access-token';
import { InvoiceTemplate } from './invoice-template';
export class InvoiceTemplateAndToken {
invoiceTemplate: InvoiceTemplate;

View File

@ -1,5 +1,5 @@
export enum CostType {
InvoiceTemplateLineCostFixed = 'InvoiceTemplateLineCostFixed',
InvoiceTemplateLineCostRange = 'InvoiceTemplateLineCostRange',
InvoiceTemplateLineCostUnlim = 'InvoiceTemplateLineCostUnlim'
InvoiceTemplateLineCostUnlim = 'InvoiceTemplateLineCostUnlim',
}

View File

@ -1,8 +1,6 @@
import { InvoiceTemplateLineCost } from './invoice-template-line-cost';
import { CostType } from './cost-type';
export class InvoiceTemplateLineCostFixed extends InvoiceTemplateLineCost {
costType: CostType.InvoiceTemplateLineCostFixed;
amount: number;
currency: string;
}

View File

@ -1,9 +1,7 @@
import { InvoiceTemplateLineCost } from './invoice-template-line-cost';
import { CostAmountRange } from './cost-amount-range';
import { CostType } from './cost-type';
import { InvoiceTemplateLineCost } from './invoice-template-line-cost';
export class InvoiceTemplateLineCostRange extends InvoiceTemplateLineCost {
costType: CostType.InvoiceTemplateLineCostRange;
range: CostAmountRange;
currency: string;
}

View File

@ -1,5 +1,5 @@
import { InvoiceTemplateLineCost } from './invoice-template-line-cost';
import { CostType } from './cost-type';
import { InvoiceTemplateLineCost } from './invoice-template-line-cost';
export class InvoiceTemplateLineCostUnlim extends InvoiceTemplateLineCost {
constType: CostType.InvoiceTemplateLineCostUnlim;

View File

@ -1,9 +1,7 @@
import { InvoiceTemplateDetails } from './invoice-template-details';
import { InvoiceLine } from '../invoice-cart/invoice-line';
import { TemplateType } from './template-type';
export class InvoiceTemplateMultiLine extends InvoiceTemplateDetails {
templateType: TemplateType.InvoiceTemplateMultiLine;
cart: InvoiceLine[];
currency: string;
}

View File

@ -1,10 +1,8 @@
import { InvoiceTemplateDetails } from './invoice-template-details';
import { InvoiceTemplateLineCost } from './invoice-template-line-cost';
import { InvoiceLineTaxMode } from '../invoice-cart/invoice-line-tax-mode';
import { TemplateType } from './template-type';
export class InvoiceTemplateSingleLine extends InvoiceTemplateDetails {
templateType: TemplateType.InvoiceTemplateSingleLine;
product: string;
price: InvoiceTemplateLineCost;
taxMode?: InvoiceLineTaxMode;

View File

@ -1,4 +1,4 @@
export enum TemplateType {
InvoiceTemplateMultiLine = 'InvoiceTemplateMultiLine',
InvoiceTemplateSingleLine = 'InvoiceTemplateSingleLine'
InvoiceTemplateSingleLine = 'InvoiceTemplateSingleLine',
}

View File

@ -1,5 +1,5 @@
import { LifetimeInterval } from './invoice-template-details/lifetime-interval';
import { InvoiceTemplateDetails } from './invoice-template-details/invoice-template-details';
import { LifetimeInterval } from './invoice-template-details/lifetime-interval';
export class InvoiceTemplate {
id: string;

View File

@ -20,7 +20,7 @@ export enum LogicErrorCode {
invalidClaimStatus = 'invalidClaimStatus',
invalidClaimRevision = 'invalidClaimRevision',
limitExceeded = 'limitExceeded',
invalidRequest = 'invalidRequest'
invalidRequest = 'invalidRequest',
}
export class LogicError {

View File

@ -1,4 +1,4 @@
export enum PayerType {
CustomerPayer = 'CustomerPayer',
PaymentResourcePayer = 'PaymentResourcePayer'
PaymentResourcePayer = 'PaymentResourcePayer',
}

View File

@ -1,6 +1,5 @@
import { Payer } from './payer';
import { ContactInfo } from '../contact-info';
import { PayerType } from './payer-type';
import { PaymentToolDetails } from '../payment-tool-details';
export type SessionInfo = {
@ -8,7 +7,6 @@ export type SessionInfo = {
};
export class PaymentResourcePayer extends Payer {
payerType: PayerType.PaymentResourcePayer;
paymentToolToken: string;
paymentSession: string;
contactInfo: ContactInfo;

View File

@ -1,4 +1,4 @@
export enum FlowType {
PaymentFlowInstant = 'PaymentFlowInstant',
PaymentFlowHold = 'PaymentFlowHold'
PaymentFlowHold = 'PaymentFlowHold',
}

View File

@ -1,4 +1,4 @@
export enum HoldExpirationType {
cancel = 'cancel',
capture = 'capture'
capture = 'capture',
}

View File

@ -1,8 +1,6 @@
import { PaymentFlow } from './payment-flow';
import { FlowType } from './flow-type';
import { HoldExpirationType } from './hold-expiration-type';
import { PaymentFlow } from './payment-flow';
export class PaymentFlowHold extends PaymentFlow {
type: FlowType.PaymentFlowHold;
onHoldExpiration: HoldExpirationType;
}

View File

@ -1,6 +1,3 @@
import { PaymentFlow } from './payment-flow';
import { FlowType } from './flow-type';
export class PaymentFlowInstant extends PaymentFlow {
type: FlowType.PaymentFlowInstant;
}
export class PaymentFlowInstant extends PaymentFlow {}

View File

@ -1,7 +1,7 @@
export enum PaymentMethodName {
BankCard = 'BankCard',
PaymentTerminal = 'PaymentTerminal',
DigitalWallet = 'DigitalWallet'
DigitalWallet = 'DigitalWallet',
}
export abstract class PaymentMethod {

View File

@ -1,5 +1,5 @@
import { PaymentFlow } from './payment-flow';
import { Payer } from './payer';
import { PaymentFlow } from './payment-flow';
export class PaymentParams {
flow: PaymentFlow;

View File

@ -4,5 +4,5 @@ export enum PaymentStatus {
captured = 'captured',
cancelled = 'cancelled',
refunded = 'refunded',
failed = 'failed'
failed = 'failed',
}

View File

@ -10,5 +10,5 @@ export enum PaymentSystem {
discover = 'discover',
unionpay = 'unionpay',
jcb = 'jcb',
nspkmir = 'nspkmir'
nspkmir = 'nspkmir',
}

View File

@ -1,6 +1,5 @@
import { PaymentMethod, PaymentMethodName } from './payment-method';
import { PaymentMethod } from './payment-method';
export class PaymentTerminal extends PaymentMethod {
method: PaymentMethodName.PaymentTerminal;
providers: string[];
}

View File

@ -1,5 +1,5 @@
export enum PaymentToolDetailsType {
PaymentToolDetailsBankCard = 'PaymentToolDetailsBankCard',
PaymentToolDetailsPaymentTerminal = 'PaymentToolDetailsPaymentTerminal',
PaymentToolDetailsDigitalWallet = 'PaymentToolDetailsDigitalWallet'
PaymentToolDetailsDigitalWallet = 'PaymentToolDetailsDigitalWallet',
}

View File

@ -1,5 +1,5 @@
export enum PaymentToolType {
CardData = 'CardData',
PaymentTerminalData = 'PaymentTerminalData',
DigitalWalletData = 'DigitalWalletData'
DigitalWalletData = 'DigitalWalletData',
}

View File

@ -1,8 +1,9 @@
import { PaymentFlow } from './payment-flow';
import { Payer } from './payer';
import { PaymentStatus } from './payment-status';
import { PaymentError } from 'checkout/backend';
import { Payer } from './payer';
import { PaymentFlow } from './payment-flow';
import { PaymentStatus } from './payment-status';
export class Payment {
id: string;
invoiceID: string;

View File

@ -4,11 +4,11 @@ import { ShortenedUrl, ShortenedUrlParams } from './model';
export const shortenUrl = (
urlShortenerEndpoint: string,
accessToken: string,
params: ShortenedUrlParams
params: ShortenedUrlParams,
): Promise<ShortenedUrl> =>
fetchCapi({
method: 'POST',
endpoint: `${urlShortenerEndpoint}/v1/shortened-urls`,
accessToken,
body: params
body: params,
});

View File

@ -1,16 +1,16 @@
import * as React from 'react';
import { useEffect, useState } from 'react';
import { ThemeProvider } from 'styled-components';
import { useInitApp, useTheme } from 'checkout/hooks';
import { InitParams } from 'checkout/initialize';
import { Overlay } from './overlay';
import { ModalContainer } from './modal-container';
import { LayoutLoader } from './layout-loader';
import { AppWrapper } from './app-wrapper';
import { GlobalStyle } from './global-style';
import { InitialContext } from './initial-context';
import { useInitApp, useTheme } from 'checkout/hooks';
import { LayoutLoader } from './layout-loader';
import { ModalContainer } from './modal-container';
import { ModalError } from './modal-error';
import { Overlay } from './overlay';
import { ResultContext } from './result-context';
export type AppProps = {

View File

@ -1,4 +1,5 @@
import { createGlobalStyle } from 'styled-components';
import { device } from 'checkout/utils/device';
export const GlobalStyle = createGlobalStyle`

View File

@ -1,4 +1,5 @@
import { createContext } from 'react';
import { InitialData } from 'checkout/hooks';
export const InitialContext = createContext<InitialData>(null);

View File

@ -1,9 +1,9 @@
import * as React from 'react';
import styled, { keyframes } from 'styled-components';
import { Loader } from '../ui/loader';
import { device } from 'checkout/utils/device';
import { Loader } from '../ui/loader';
const growth = keyframes`
from {
transform: scale(0);

View File

@ -1,18 +1,18 @@
import * as React from 'react';
import { useContext, useEffect, useMemo, useState } from 'react';
import { motion } from 'framer-motion';
import { useContext, useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import isNil from 'checkout/utils/is-nil';
import { Modal } from './modal';
import { UserInteractionModal } from './user-interaction-modal';
import { ModalName, ResultFormInfo, ResultType } from 'checkout/hooks';
import { InitialContext } from '../initial-context';
import { PayableInvoiceContext } from './payable-invoice-context';
import { PayableInvoiceData, useInvoiceEvents, useModal } from 'checkout/hooks';
import { InvoiceChangeType } from 'checkout/backend';
import { ModalName, ResultFormInfo, ResultType } from 'checkout/hooks';
import { PayableInvoiceData, useInvoiceEvents, useModal } from 'checkout/hooks';
import isNil from 'checkout/utils/is-nil';
import { Modal } from './modal';
import { ModalContext } from './modal-context';
import { PayableInvoiceContext } from './payable-invoice-context';
import { useInteractionModel } from './use-interaction-model';
import { UserInteractionModal } from './user-interaction-modal';
import { InitialContext } from '../initial-context';
const Container = styled.div`
height: 100%;
@ -24,7 +24,7 @@ export const ModalContainer = () => {
appConfig: { capiEndpoint },
initConfig,
model: { serviceProviders, invoice, invoiceAccessToken },
availablePaymentMethods
availablePaymentMethods,
} = useContext(InitialContext);
const {
modalState,
@ -34,11 +34,11 @@ export const ModalContainer = () => {
prepareToRetry,
forgetPaymentAttempt,
setViewInfoError,
toInteractionState
toInteractionState,
} = useModal({
integrationType: initConfig.integrationType,
availablePaymentMethods,
serviceProviders
serviceProviders,
});
const [payableInvoiceData, setPayableInvoiceData] = useState<PayableInvoiceData>(null);
const { eventsState, startPolling, searchEventsChange } = useInvoiceEvents(capiEndpoint, payableInvoiceData);
@ -50,9 +50,9 @@ export const ModalContainer = () => {
invoice: {
id: invoice.id,
dueDate: invoice.dueDate,
externalID: invoice.externalID
externalID: invoice.externalID,
},
invoiceAccessToken
invoiceAccessToken,
});
}
}, []);
@ -85,8 +85,8 @@ export const ModalContainer = () => {
case InvoiceChangeType.PaymentStatusChanged:
goToFormInfo(
new ResultFormInfo(ResultType.hookProcessed, {
change
})
change,
}),
);
break;
}
@ -100,8 +100,8 @@ export const ModalContainer = () => {
if (eventsState.status === 'FAILURE') {
goToFormInfo(
new ResultFormInfo(ResultType.hookError, {
error: eventsState.error
})
error: eventsState.error,
}),
);
}
}, [payableInvoiceData, eventsState]);
@ -114,7 +114,7 @@ export const ModalContainer = () => {
const activeModalName = useMemo(() => modalState.find((modal) => modal.active).name, [modalState]);
return (
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1 }}>
<motion.div animate={{ opacity: 1 }} initial={{ opacity: 0 }} transition={{ duration: 1 }}>
<Container>
<ModalContext.Provider
value={{
@ -123,8 +123,9 @@ export const ModalContainer = () => {
prepareToPay,
prepareToRetry,
forgetPaymentAttempt,
setViewInfoError
}}>
setViewInfoError,
}}
>
<PayableInvoiceContext.Provider value={{ payableInvoiceData, setPayableInvoiceData }}>
{activeModalName === ModalName.modalForms && <Modal />}
{activeModalName === ModalName.modalInteraction && <UserInteractionModal />}

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import { ReactSVG } from 'react-svg';
import { useContext } from 'react';
import { ReactSVG } from 'react-svg';
import styled from 'styled-components';
import { InitialContext } from '../../initial-context';

View File

@ -1,4 +1,5 @@
import styled from 'styled-components';
import { device } from 'checkout/utils/device';
export const FormBlock = styled.div`

View File

@ -1,26 +1,25 @@
import * as React from 'react';
import { useContext, useEffect } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { FormGroup } from '../form-group';
import { CardHolder, CardNumber, ExpireDate, SecureCode } from './fields';
import { ResultFormInfo, ResultType } from 'checkout/hooks';
import { PayButton } from '../pay-button';
import { Header } from '../header';
import { toAmountConfig, toCardHolderConfig } from '../fields-config';
import { Amount } from '../common-fields';
import { PaymentMethodName, useCreatePayment } from 'checkout/hooks';
import { isEmptyObject } from 'checkout/utils/is-empty-object';
import { CardFormInputs } from './card-form-inputs';
import { CardFormInputs } from './card-form-inputs';
import { CardHolder, CardNumber, ExpireDate, SecureCode } from './fields';
import { InitialContext } from '../../../../initial-context';
import { ModalContext } from '../../../modal-context';
import { Amount } from '../common-fields';
import { toAmountConfig, toCardHolderConfig } from '../fields-config';
import { FormGroup } from '../form-group';
import { Header } from '../header';
import { PayButton } from '../pay-button';
export const CardForm = ({ onMount }: { onMount: () => void }) => {
const {
locale,
initConfig,
model: { invoiceTemplate }
model: { invoiceTemplate },
} = useContext(InitialContext);
const { setViewInfoError, goToFormInfo, prepareToPay } = useContext(ModalContext);
const { createPaymentState, setFormData } = useCreatePayment();
@ -28,7 +27,7 @@ export const CardForm = ({ onMount }: { onMount: () => void }) => {
register,
handleSubmit,
watch,
formState: { errors, dirtyFields, isSubmitted }
formState: { errors, dirtyFields, isSubmitted },
} = useForm<CardFormInputs>({ mode: 'onChange' });
const cardHolder = toCardHolderConfig(initConfig.requireCardHolder);
const amount = toAmountConfig(initConfig, invoiceTemplate);
@ -47,8 +46,8 @@ export const CardForm = ({ onMount }: { onMount: () => void }) => {
if (createPaymentState.status === 'FAILURE') {
goToFormInfo(
new ResultFormInfo(ResultType.hookError, {
error: createPaymentState.error
})
error: createPaymentState.error,
}),
);
}
}, [createPaymentState]);
@ -63,35 +62,35 @@ export const CardForm = ({ onMount }: { onMount: () => void }) => {
<Header title={locale['form.header.pay.card.label']} />
<FormGroup>
<CardNumber
locale={locale}
fieldError={errors.cardNumber}
isDirty={dirtyFields.cardNumber}
locale={locale}
register={register}
watch={watch}
/>
</FormGroup>
<FormGroup $gap={10}>
<ExpireDate
locale={locale}
fieldError={errors.expireDate}
isDirty={dirtyFields.expireDate}
locale={locale}
register={register}
/>
<SecureCode
locale={locale}
cardNumber={watch('cardNumber')}
fieldError={errors.secureCode}
isDirty={dirtyFields.secureCode}
register={register}
locale={locale}
obscureCardCvv={initConfig?.obscureCardCvv}
cardNumber={watch('cardNumber')}
register={register}
/>
</FormGroup>
{cardHolder.visible && (
<FormGroup>
<CardHolder
locale={locale}
fieldError={errors.cardHolder}
isDirty={dirtyFields.cardHolder}
locale={locale}
register={register}
/>
</FormGroup>
@ -100,10 +99,10 @@ export const CardForm = ({ onMount }: { onMount: () => void }) => {
<FormGroup>
<Amount
cost={amount.cost}
locale={locale}
localeCode={initConfig.locale}
fieldError={errors.amount}
isDirty={dirtyFields.amount}
locale={locale}
localeCode={initConfig.locale}
register={register}
/>
</FormGroup>

View File

@ -1,13 +1,13 @@
import * as React from 'react';
import { FieldError, UseFormRegister } from 'react-hook-form';
import { validateCardHolder } from './validate-card-holder';
import { Locale } from 'checkout/locale';
import { formatCardHolder } from './format-card-holder';
import { Input } from 'checkout/components';
import { CardFormInputs } from '../../card-form-inputs';
import { Locale } from 'checkout/locale';
import isNil from 'checkout/utils/is-nil';
import { formatCardHolder } from './format-card-holder';
import { validateCardHolder } from './validate-card-holder';
import { ReactComponent as UserIcon } from '../../../../../../../ui/icon/user.svg';
import { CardFormInputs } from '../../card-form-inputs';
export type CardHolderProps = {
register: UseFormRegister<CardFormInputs>;
@ -20,16 +20,16 @@ export const CardHolder = ({ register, locale, fieldError, isDirty }: CardHolder
<Input
{...register('cardHolder', {
required: true,
validate: (value) => !validateCardHolder(value) || 'Card holder is invalid'
validate: (value) => !validateCardHolder(value) || 'Card holder is invalid',
})}
icon={<UserIcon />}
placeholder={locale['form.input.cardholder.placeholder']}
mark={true}
id="card-holder-input"
onInput={formatCardHolder}
autoComplete="cc-name"
spellCheck={false}
error={!isNil(fieldError)}
dirty={isDirty}
error={!isNil(fieldError)}
icon={<UserIcon />}
id="card-holder-input"
mark={true}
placeholder={locale['form.input.cardholder.placeholder']}
spellCheck={false}
onInput={formatCardHolder}
/>
);

View File

@ -1,6 +1,7 @@
import { safeVal } from 'checkout/utils';
import { FormEvent } from 'react';
import { safeVal } from 'checkout/utils';
export const formatCardHolder = (e: FormEvent<HTMLInputElement>) => {
const target = e.currentTarget;
let value = target.value;

View File

@ -1,15 +1,15 @@
import * as React from 'react';
import { FieldError, UseFormRegister, UseFormWatch } from 'react-hook-form';
import styled from 'styled-components';
import { validateCardNumber } from './validate-card-number';
import { Input } from 'checkout/components';
import { Locale } from 'checkout/locale';
import { formatCardNumber } from './format-card-number';
import isNil from 'checkout/utils/is-nil';
import { CardFormInputs } from '../../card-form-inputs';
import { ReactComponent as CardIcon } from '../../../../../../../ui/icon/card.svg';
import { CardTypeIcon } from 'checkout/components/ui/card-type-icon';
import { Locale } from 'checkout/locale';
import isNil from 'checkout/utils/is-nil';
import { formatCardNumber } from './format-card-number';
import { validateCardNumber } from './validate-card-number';
import { ReactComponent as CardIcon } from '../../../../../../../ui/icon/card.svg';
import { CardFormInputs } from '../../card-form-inputs';
const InputContainer = styled.div`
width: 100%;
@ -35,17 +35,17 @@ export const CardNumber = ({ register, locale, fieldError, isDirty, watch }: Car
<CardNumberInput
{...register('cardNumber', {
required: true,
validate: (value) => !validateCardNumber(value) || 'Card number is invalid'
validate: (value) => !validateCardNumber(value) || 'Card number is invalid',
})}
icon={<CardIcon />}
placeholder={locale['form.input.card.placeholder']}
mark={true}
type="tel"
id="card-number-input"
onInput={formatCardNumber}
autoComplete="cc-number"
error={!isNil(fieldError)}
dirty={isDirty}
error={!isNil(fieldError)}
icon={<CardIcon />}
id="card-number-input"
mark={true}
placeholder={locale['form.input.card.placeholder']}
type="tel"
onInput={formatCardNumber}
/>
<CardTypeIcon cardNumber={watch('cardNumber')} />
</InputContainer>

View File

@ -1,5 +1,6 @@
import { FormEvent } from 'react';
import { number } from 'card-validator';
import { FormEvent } from 'react';
import { replaceFullWidthChars, safeVal } from 'checkout/utils';
function format(num: string): string {

View File

@ -1,13 +1,13 @@
import * as React from 'react';
import { FieldError, UseFormRegister } from 'react-hook-form';
import { validateExpireDate } from './validate-expire-date';
import { Locale } from 'checkout/locale';
import { formatExpiry } from './format-expiry';
import { Input } from 'checkout/components';
import { CardFormInputs } from '../../card-form-inputs';
import { Locale } from 'checkout/locale';
import isNil from 'checkout/utils/is-nil';
import { formatExpiry } from './format-expiry';
import { validateExpireDate } from './validate-expire-date';
import { ReactComponent as CalendarIcon } from '../../../../../../../ui/icon/calendar.svg';
import { CardFormInputs } from '../../card-form-inputs';
export type ExpireDateProps = {
register: UseFormRegister<CardFormInputs>;
@ -20,16 +20,16 @@ export const ExpireDate = ({ register, locale, fieldError, isDirty }: ExpireDate
<Input
{...register('expireDate', {
required: true,
validate: (value) => !validateExpireDate(value) || 'Exp date is invalid'
validate: (value) => !validateExpireDate(value) || 'Exp date is invalid',
})}
icon={<CalendarIcon />}
placeholder={locale['form.input.expiry.placeholder']}
mark={true}
type="tel"
id="expire-date-input"
onInput={formatExpiry}
autoComplete="cc-exp"
error={!isNil(fieldError)}
dirty={isDirty}
error={!isNil(fieldError)}
icon={<CalendarIcon />}
id="expire-date-input"
mark={true}
placeholder={locale['form.input.expiry.placeholder']}
type="tel"
onInput={formatExpiry}
/>
);

View File

@ -1,6 +1,7 @@
import { replaceFullWidthChars, safeVal } from 'checkout/utils';
import { FormEvent } from 'react';
import { replaceFullWidthChars, safeVal } from 'checkout/utils';
function format(expiry: string): string {
const parts = expiry.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/);
if (!parts) {

View File

@ -8,7 +8,7 @@ export function cardExpiryVal(value: string): ExpiryDate {
let prefix;
let year;
let ref;
(ref = value.split(/[\s\/]+/, 2)), (month = ref[0]), (year = ref[1]);
(ref = value.split(/[\s]+/, 2)), (month = ref[0]), (year = ref[1]);
if ((year != null ? year.length : void 0) === 2 && /^\d+$/.test(year)) {
prefix = new Date().getFullYear();
prefix = prefix.toString().slice(0, 2);
@ -18,6 +18,6 @@ export function cardExpiryVal(value: string): ExpiryDate {
year = parseInt(year, 10);
return {
month,
year
year,
};
}

View File

@ -1,4 +1,5 @@
import { number } from 'card-validator';
import { replaceFullWidthChars } from 'checkout/utils';
export function formatCVC(value: string, cardNumber: string): string {

View File

@ -1,15 +1,15 @@
import * as React from 'react';
import { number } from 'card-validator';
import { FieldError, UseFormRegister } from 'react-hook-form';
import { validateSecureCode } from './validate-secure-code';
import { Locale } from 'checkout/locale';
import { formatCVC } from './format-cvc';
import { Input } from 'checkout/components';
import { Locale } from 'checkout/locale';
import { safeVal } from 'checkout/utils';
import { CardFormInputs } from '../../card-form-inputs';
import isNil from 'checkout/utils/is-nil';
import { formatCVC } from './format-cvc';
import { validateSecureCode } from './validate-secure-code';
import { ReactComponent as LockIcon } from '../../../../../../../ui/icon/lock.svg';
import { CardFormInputs } from '../../card-form-inputs';
export interface SecureCodeProps {
register: UseFormRegister<CardFormInputs>;
@ -29,19 +29,19 @@ export const SecureCode = ({ cardNumber, locale, obscureCardCvv, register, field
<Input
{...register('secureCode', {
required: true,
validate: (value) => !validateSecureCode(value, { cardNumber }) || 'Secure code is invalid'
validate: (value) => !validateSecureCode(value, { cardNumber }) || 'Secure code is invalid',
})}
icon={<LockIcon />}
placeholder={getPlaceholder(cardNumber, locale)}
mark={true}
type={obscureCardCvv ? 'password' : 'tel'}
id="secure-code-input"
autoComplete="cc-csc"
error={!isNil(fieldError)}
dirty={isDirty}
error={!isNil(fieldError)}
icon={<LockIcon />}
id="secure-code-input"
mark={true}
placeholder={getPlaceholder(cardNumber, locale)}
type={obscureCardCvv ? 'password' : 'tel'}
onInput={(e) => {
const target = e.currentTarget;
let value = target.value;
const value = target.value;
const formatted = formatCVC(value, cardNumber);
return safeVal(formatted, target);
}}

View File

@ -1,13 +1,13 @@
import * as React from 'react';
import { FieldError, UseFormRegister } from 'react-hook-form';
import { InvoiceTemplateLineCostRange, InvoiceTemplateLineCostUnlim } from 'checkout/backend';
import { Input } from 'checkout/components';
import { Locale } from 'checkout/locale';
import isNil from 'checkout/utils/is-nil';
import { formatAmount } from './format-amount';
import { getPlaceholder } from './get-placeholder';
import { validateAmount } from './validate-amount';
import { Locale } from 'checkout/locale';
import { InvoiceTemplateLineCostRange, InvoiceTemplateLineCostUnlim } from 'checkout/backend';
import { formatAmount } from './format-amount';
import isNil from 'checkout/utils/is-nil';
import { ReactComponent as AmountIcon } from '../../../../../../ui/icon/amount.svg';
export type AmountProps = {
@ -23,15 +23,15 @@ export const Amount = ({ register, locale, fieldError, cost, localeCode, isDirty
<Input
{...register('amount', {
required: true,
validate: (value) => !validateAmount(value, cost) || 'Amount is invalid'
validate: (value) => !validateAmount(value, cost) || 'Amount is invalid',
})}
icon={<AmountIcon />}
placeholder={getPlaceholder(cost, locale['form.input.amount.placeholder'], localeCode)}
mark={true}
type="tel"
id="amount-input"
onInput={formatAmount}
error={!isNil(fieldError)}
dirty={isDirty}
error={!isNil(fieldError)}
icon={<AmountIcon />}
id="amount-input"
mark={true}
placeholder={getPlaceholder(cost, locale['form.input.amount.placeholder'], localeCode)}
type="tel"
onInput={formatAmount}
/>
);

View File

@ -1,6 +1,7 @@
import { replaceFullWidthChars, safeVal } from 'checkout/utils';
import { FormEvent } from 'react';
import { replaceFullWidthChars, safeVal } from 'checkout/utils';
const createNumArr = (num: string): string[] => {
let numTempArr;
if (/^\d+(\.\d+)?$/.test(num)) {

View File

@ -9,13 +9,13 @@ const toRangePlaceholder = (cost: InvoiceTemplateLineCostRange, locale: string):
minorValue: range.lowerBound,
currencyCode: cost.currency,
status: 'final',
locale
locale,
});
const upper = formatAmount({
minorValue: range.upperBound,
currencyCode: cost.currency,
status: 'final',
locale
locale,
});
return `${lower} - ${upper}`;
};
@ -23,7 +23,7 @@ const toRangePlaceholder = (cost: InvoiceTemplateLineCostRange, locale: string):
export const getPlaceholder = (
cost: InvoiceTemplateLineCostRange | InvoiceTemplateLineCostUnlim,
localeString: string,
localeCode: string
localeCode: string,
): string => {
if (!cost) {
return;

View File

@ -1,6 +1,6 @@
import toNumber from 'checkout/utils/to-number';
import isNumber from 'checkout/utils/is-number';
import { CostType, InvoiceTemplateLineCostRange, InvoiceTemplateLineCostUnlim } from 'checkout/backend';
import isNumber from 'checkout/utils/is-number';
import toNumber from 'checkout/utils/to-number';
function validate(amount: number, min?: number, max?: number): boolean {
if (!amount || !isNumber(amount) || amount <= 0) {
@ -14,7 +14,7 @@ function validate(amount: number, min?: number, max?: number): boolean {
export const validateAmount = (
value: string,
cost: InvoiceTemplateLineCostRange | InvoiceTemplateLineCostUnlim
cost: InvoiceTemplateLineCostRange | InvoiceTemplateLineCostUnlim,
): boolean => {
if (value) {
value = value.replace(/\s/g, '').replace(/,/g, '.');

View File

@ -1,8 +1,8 @@
import * as React from 'react';
import { FieldError, FieldErrorsImpl, Merge, UseFormRegister } from 'react-hook-form';
import { formatEmail, validateEmail } from 'checkout/utils';
import { Locale } from 'checkout/locale';
import { Input } from 'checkout/components';
import { Locale } from 'checkout/locale';
import { formatEmail, validateEmail } from 'checkout/utils';
import isNil from 'checkout/utils/is-nil';
export type EmailProps = {
@ -16,15 +16,15 @@ export const Email = ({ register, locale, fieldError, isDirty }: EmailProps) =>
<Input
{...register('email', {
required: true,
validate: (value) => !validateEmail(value) || 'Email is invalid'
validate: (value) => !validateEmail(value) || 'Email is invalid',
})}
placeholder={locale['form.input.email.placeholder']}
mark={true}
type="email"
id="email-input"
onInput={formatEmail}
autoComplete="email"
error={!isNil(fieldError)}
dirty={isDirty}
error={!isNil(fieldError)}
id="email-input"
mark={true}
placeholder={locale['form.input.email.placeholder']}
type="email"
onInput={formatEmail}
/>
);

View File

@ -1,8 +1,7 @@
import * as React from 'react';
import { FieldError, FieldErrorsImpl, Merge, UseFormRegister } from 'react-hook-form';
import { Locale } from 'checkout/locale';
import { Input } from 'checkout/components';
import { Locale } from 'checkout/locale';
import { formatPhoneNumber, validatePhone } from 'checkout/utils';
import isNil from 'checkout/utils/is-nil';
@ -17,16 +16,16 @@ export const Phone = ({ register, locale, fieldError, isDirty }: PhoneProps) =>
<Input
{...register('phoneNumber', {
required: true,
validate: (value) => !validatePhone(value) || 'Phone number is invalid'
validate: (value) => !validatePhone(value) || 'Phone number is invalid',
})}
placeholder={locale['form.input.phone.placeholder']}
mark={true}
type="tel"
id="phone-input"
onInput={formatPhoneNumber}
onFocus={formatPhoneNumber}
autoComplete="tel"
error={!isNil(fieldError)}
dirty={isDirty}
error={!isNil(fieldError)}
id="phone-input"
mark={true}
placeholder={locale['form.input.phone.placeholder']}
type="tel"
onFocus={formatPhoneNumber}
onInput={formatPhoneNumber}
/>
);

View File

@ -2,9 +2,10 @@ import {
InvoiceTemplate,
InvoiceTemplateLineCostRange,
InvoiceTemplateLineCostUnlim,
InvoiceTemplateSingleLine
InvoiceTemplateSingleLine,
} from 'checkout/backend';
import { InitConfig } from 'checkout/config';
import { AmountConfig, EmailConfig, FieldsConfig, PhoneNumberConfig } from './fields-config';
const toSingleLineAmountConfig = (c: InvoiceTemplateSingleLine): AmountConfig => {
@ -47,12 +48,12 @@ export const toEmailConfig = (email: string): EmailConfig => {
};
export const toCardHolderConfig = (requireCardHolder: boolean | null) => ({
visible: requireCardHolder === null ? true : requireCardHolder
visible: requireCardHolder === null ? true : requireCardHolder,
});
export const toFieldsConfig = (c: InitConfig, t: InvoiceTemplate): FieldsConfig => ({
amount: toAmountConfig(c, t),
email: toEmailConfig(c.email),
cardHolder: toCardHolderConfig(c.requireCardHolder),
phoneNumber: toPhoneNumberConfig(c.phoneNumber)
phoneNumber: toPhoneNumberConfig(c.phoneNumber),
});

View File

@ -1,23 +1,22 @@
import * as React from 'react';
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { motion } from 'framer-motion';
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import { CardForm } from './card-form';
import { FormName, ModalForms, ModalName, SlideDirection } from 'checkout/hooks';
import { PaymentMethods } from './payment-methods';
import { FormLoader } from './form-loader';
import { ResultForm } from './result-form';
import { WalletForm } from './wallet-form';
import { findNamed } from 'checkout/utils';
import { device } from 'checkout/utils/device';
import { NoAvailablePaymentMethodForm } from './no-available-payment-method-form';
import { WalletProviders } from './wallet-providers';
import { RedirectForm } from './redirect-form';
import { PaymentTerminalForm } from './payment-terminal-form';
import { QrCodeInteractionForm } from './qr-code-interaction-form';
import { PaymentTerminalSelectorForm } from './payment-terminal-selector-form';
import { CardForm } from './card-form';
import { FormLoader } from './form-loader';
import { NoAvailablePaymentMethodForm } from './no-available-payment-method-form';
import { PaymentMethods } from './payment-methods';
import { PaymentTerminalForm } from './payment-terminal-form';
import { PaymentTerminalSelectorForm } from './payment-terminal-selector-form';
import { QrCodeInteractionForm } from './qr-code-interaction-form';
import { RedirectForm } from './redirect-form';
import { ResultForm } from './result-form';
import { WalletForm } from './wallet-form';
import { WalletProviders } from './wallet-providers';
import { ModalContext } from '../../modal-context';
const Container = styled.div`
@ -87,12 +86,12 @@ export const FormContainer = () => {
const {
formName,
viewInfo: { slideDirection, inProcess }
viewInfo: { slideDirection, inProcess },
} = useMemo(() => {
const found = findNamed(modalState, ModalName.modalForms) as ModalForms;
return {
formName: found.formsInfo.find((item) => item.active)?.name,
viewInfo: found.viewInfo
viewInfo: found.viewInfo,
};
}, [modalState]);
@ -111,11 +110,12 @@ export const FormContainer = () => {
<Container>
<Form height={height}>
<motion.div
ref={contentElement}
key={formName}
initial={{ x: toInitialPos(slideDirection) }}
ref={contentElement}
animate={{ x: 0 }}
transition={{ duration: 0.3 }}>
initial={{ x: toInitialPos(slideDirection) }}
transition={{ duration: 0.3 }}
>
{renderForm(formName, onMount)}
{inProcess && <FormLoader />}
</motion.div>

View File

@ -1,6 +1,9 @@
import styled from 'styled-components';
export const FormGroup = styled.div<{ direction?: 'column' | 'row'; $gap?: number }>`
export const FormGroup = styled.div<{
direction?: 'column' | 'row';
$gap?: number;
}>`
display: flex;
flex-wrap: nowrap;
flex-direction: ${({ direction }) => direction || 'row'};

View File

@ -1,4 +1,3 @@
import * as React from 'react';
import { motion } from 'framer-motion';
import styled from 'styled-components';
@ -7,7 +6,7 @@ import { Loader } from 'checkout/components';
const fadeIn = {
hidden: { opacity: 0 },
show: { opacity: 1, transition: { duration: 0.5 } },
exit: { opacity: 0, transition: { duration: 0.5 } }
exit: { opacity: 0, transition: { duration: 0.5 } },
};
const LoaderWrapper = styled.div`
@ -26,7 +25,7 @@ const LoaderWrapper = styled.div`
`;
export const FormLoader = () => (
<motion.div variants={fadeIn} initial="hidden" animate="show" exit="exit">
<motion.div animate="show" exit="exit" initial="hidden" variants={fadeIn}>
<LoaderWrapper key="form-loader" id="form-loader">
<Loader />
</LoaderWrapper>

View File

@ -2,13 +2,13 @@ import {
KnownProviderCategories,
PaymentMethod,
PaymentMethodName,
PaymentTerminalPaymentMethod
PaymentTerminalPaymentMethod,
} from 'checkout/hooks';
import isNil from 'checkout/utils/is-nil';
export const getAvailableTerminalPaymentMethod = (
availablePaymentMethods: PaymentMethod[],
category: KnownProviderCategories
category: KnownProviderCategories,
): PaymentTerminalPaymentMethod | null => {
if (isNil(category)) {
return null;

View File

@ -1,14 +1,13 @@
import * as React from 'react';
import { useContext } from 'react';
import { findInfoWithPrevious, findNamed } from 'checkout/utils';
import { FormInfo, ModalForms, ModalName, ModalState } from 'checkout/hooks';
import { HeaderWrapper } from '../header-wrapper';
import { Title } from '../title';
import { ChevronButton } from 'checkout/components';
import { FormInfo, ModalForms, ModalName, ModalState } from 'checkout/hooks';
import { Direction } from 'checkout/hooks';
import { findInfoWithPrevious, findNamed } from 'checkout/utils';
import { ModalContext } from '../../../modal-context';
import { HeaderWrapper } from '../header-wrapper';
import { Title } from '../title';
const getDestination = (modals: ModalState[]): FormInfo => {
const modalForms = findNamed(modals, ModalName.modalForms) as ModalForms;
@ -24,9 +23,9 @@ export const Header = ({ title }: { title: string }) => {
<HeaderWrapper>
{destination && (
<ChevronButton
id="desktop-back-btn"
type="left"
onClick={() => goToFormInfo(destination, Direction.back)}
id="desktop-back-btn"
/>
)}
<Title>{title}</Title>

View File

@ -1,10 +1,8 @@
import * as React from 'react';
import { useContext, useEffect } from 'react';
import styled from 'styled-components';
import { Text } from '../text';
import { InitialContext } from '../../../../initial-context';
import { Text } from '../text';
const Container = styled.div`
padding: 80px 0;

View File

@ -1,11 +1,10 @@
import * as React from 'react';
import { useContext } from 'react';
import styled from 'styled-components';
import { formatAmount } from 'checkout/utils';
import { Button } from 'checkout/components';
import { Locale } from 'checkout/locale';
import { AmountInfo } from 'checkout/hooks';
import { Locale } from 'checkout/locale';
import { formatAmount } from 'checkout/utils';
import { InitialContext } from '../../../../initial-context';
@ -23,7 +22,7 @@ export const PayButton = () => {
const { locale, amountInfo } = useContext(InitialContext);
const label = toLabel(locale, amountInfo);
return (
<PayButtonWrapper type="submit" color="primary" id="pay-btn">
<PayButtonWrapper color="primary" id="pay-btn" type="submit">
{label}
</PayButtonWrapper>
);

View File

@ -1,10 +1,9 @@
import * as React from 'react';
import { useContext } from 'react';
import { CardFormInfo, FormName } from 'checkout/hooks';
import { Method } from './method';
import { PaymentMethodIcon, PaymentMethodTitle } from 'checkout/components/ui';
import { CardFormInfo, FormName } from 'checkout/hooks';
import { Method } from './method';
import { InitialContext } from '../../../../../initial-context';
import { ModalContext } from '../../../../modal-context';
@ -17,7 +16,7 @@ export const BankCard = () => {
};
return (
<Method onClick={onClick} id="bank-card-payment-method">
<Method id="bank-card-payment-method" onClick={onClick}>
<PaymentMethodIcon name="bank-card" />
<PaymentMethodTitle>{locale['form.payment.method.name.card.label']}</PaymentMethodTitle>
</Method>

View File

@ -1,9 +1,9 @@
import * as React from 'react';
import styled from 'styled-components';
import { Methods } from './methods';
import { PaymentMethod } from 'checkout/hooks';
import { Methods } from './methods';
const List = styled.ul`
margin: 0;
padding: 0;

View File

@ -1,16 +1,15 @@
import * as React from 'react';
import { assertUnreachable } from 'checkout/utils';
import { Wallets } from './wallets';
import { BankCard } from './bank-card';
import { WalletProviderPaymentMethodItem } from '../../wallet-provider-payment-method-item';
import { PaymentTerminalMethodItems } from './payment-terminal-method-items';
import {
DigitalWalletPaymentMethod,
PaymentMethod,
PaymentMethodName,
PaymentTerminalPaymentMethod
PaymentTerminalPaymentMethod,
} from 'checkout/hooks';
import { assertUnreachable } from 'checkout/utils';
import { BankCard } from './bank-card';
import { PaymentTerminalMethodItems } from './payment-terminal-method-items';
import { Wallets } from './wallets';
import { WalletProviderPaymentMethodItem } from '../../wallet-provider-payment-method-item';
const Method = ({ method }: { method: PaymentMethod }) => {
switch (method.name) {

View File

@ -1,10 +1,13 @@
import * as React from 'react';
import { KnownProviderCategories } from 'checkout/hooks';
export const CategoryContent: React.FC<{ category: KnownProviderCategories }> = ({ category }) => {
export const CategoryContent: React.FC<{
category: KnownProviderCategories;
}> = ({ category }) => {
switch (category) {
case 'netbanking':
return <img src="/assets/inb-logo.jpg" height="68px" width="106px"></img>;
return <img height="68px" src="/assets/inb-logo.jpg" width="106px"></img>;
}
return <div>{category}</div>;
};

View File

@ -1,15 +1,16 @@
import * as React from 'react';
import { MetadataContent } from './metadata-content';
import { CategoryContent } from './category-content';
import { PaymentTerminalPaymentMethod } from 'checkout/hooks';
export const Content: React.FC<{ method: PaymentTerminalPaymentMethod; localeCode: string }> = ({
method,
localeCode
}) => {
import { CategoryContent } from './category-content';
import { MetadataContent } from './metadata-content';
export const Content: React.FC<{
method: PaymentTerminalPaymentMethod;
localeCode: string;
}> = ({ method, localeCode }) => {
if (method.serviceProviders.length === 1) {
return <MetadataContent serviceProvider={method.serviceProviders[0]} localeCode={localeCode} />;
return <MetadataContent localeCode={localeCode} serviceProvider={method.serviceProviders[0]} />;
}
if (method.serviceProviders.length > 1) {
return <CategoryContent category={method.category} />;

View File

@ -3,14 +3,14 @@ import * as React from 'react';
import { ServiceProvider } from 'checkout/backend';
import { getMetadata, MetadataLogo, MetadataTitle } from 'checkout/components';
export const MetadataContent: React.FC<{ serviceProvider: ServiceProvider; localeCode: string }> = ({
serviceProvider,
localeCode
}) => {
export const MetadataContent: React.FC<{
serviceProvider: ServiceProvider;
localeCode: string;
}> = ({ serviceProvider, localeCode }) => {
const { logo, title } = getMetadata(serviceProvider);
return (
<>
{title && <MetadataTitle metadata={title} localeCode={localeCode} />}
{title && <MetadataTitle localeCode={localeCode} metadata={title} />}
{logo && <MetadataLogo metadata={logo} />}
</>
);

View File

@ -1,19 +1,18 @@
import * as React from 'react';
import { useContext, useEffect } from 'react';
import isNil from 'checkout/utils/is-nil';
import { PaymentMethodName, ServiceProvider, ServiceProviderContactInfo } from 'checkout/backend';
import { getMetadata, PaymentMethodItemContainer } from 'checkout/components/ui';
import {
FormName,
PaymentTerminalFormInfo,
PaymentTerminalSelectorFormInfo,
ResultFormInfo,
ResultType
ResultType,
} from 'checkout/hooks';
import { getMetadata, PaymentMethodItemContainer } from 'checkout/components/ui';
import { PaymentMethodName, ServiceProvider, ServiceProviderContactInfo } from 'checkout/backend';
import { Content } from './content';
import { PaymentTerminalPaymentMethod, useCreatePayment, PaymentTerminalFormValues } from 'checkout/hooks';
import isNil from 'checkout/utils/is-nil';
import { Content } from './content';
import { InitialContext } from '../../../../../../initial-context';
import { ModalContext } from '../../../../../modal-context';
@ -30,7 +29,7 @@ const isRequiredPhoneNumber = (contactInfo: ServiceProviderContactInfo, phoneNum
const isRequiredPaymentTerminalForm = (
serviceProvider: ServiceProvider,
emailPrefilled: boolean,
phoneNumberPrefilled: boolean
phoneNumberPrefilled: boolean,
): boolean => {
const { form, contactInfo } = getMetadata(serviceProvider);
return (
@ -59,8 +58,8 @@ export const PaymentTerminalMethodItem = ({ method }: PaymentTerminalMethodItemP
setFormData({
method: PaymentMethodName.PaymentTerminal,
values: {
provider: serviceProvider.id
} as PaymentTerminalFormValues
provider: serviceProvider.id,
} as PaymentTerminalFormValues,
});
}
}
@ -78,7 +77,7 @@ export const PaymentTerminalMethodItem = ({ method }: PaymentTerminalMethodItemP
return (
<PaymentMethodItemContainer id={`${Math.floor(Math.random() * 100)}-payment-method-item`} onClick={onClick}>
<Content method={method} localeCode={initConfig.locale} />
<Content localeCode={initConfig.locale} method={method} />
</PaymentMethodItemContainer>
);
};

View File

@ -1,7 +1,6 @@
import * as React from 'react';
import { KnownProviderCategories, PaymentTerminalPaymentMethod } from 'checkout/hooks';
import { assertUnreachable } from 'checkout/utils';
import { PaymentTerminalMethodItem } from './payment-terminal-method-item';
export interface PaymentTerminalMethodItemsProps {

View File

@ -1,11 +1,10 @@
import * as React from 'react';
import { useContext } from 'react';
import { PaymentMethodIcon, PaymentMethodTitle } from 'checkout/components/ui';
import { FormName, WalletProvidersFormInfo } from 'checkout/hooks';
import { Method } from './method';
import { Text } from './text';
import { PaymentMethodIcon, PaymentMethodTitle } from 'checkout/components/ui';
import { InitialContext } from '../../../../../initial-context';
import { ModalContext } from '../../../../modal-context';
@ -18,7 +17,7 @@ export const Wallets = () => {
};
return (
<Method onClick={onClick} id="wallets-payment-method">
<Method id="wallets-payment-method" onClick={onClick}>
<PaymentMethodIcon name="wallets" />
<Text>
<PaymentMethodTitle>{locale['form.payment.method.name.wallet.label']}</PaymentMethodTitle>

Some files were not shown because too many files have changed in this diff Show More