Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/custom theme #134

Merged
merged 25 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
be63fa6
feat(theme): add property customTheme, Theme interface
absolemDev Nov 15, 2023
9374544
feat(form): add disabled property
absolemDev Nov 15, 2023
6921103
feat(input, button): customization components, add interfaces
absolemDev Nov 16, 2023
96cd845
fix(theme-provider): add conditional render
absolemDev Nov 16, 2023
e005061
feat: test
Nelfimov Nov 17, 2023
2ec40ad
chore: deps
Nelfimov Nov 17, 2023
5398e3a
feat: add customElement property, interfaces, conditional render cust…
absolemDev Nov 20, 2023
9f9f1d8
fix: install dependencies
absolemDev Nov 20, 2023
c3e7e80
fix: imports, interfaces
absolemDev Nov 20, 2023
c9b1626
feat: add wrappers for custom elemrnts
absolemDev Nov 22, 2023
bf5c3ac
fix: interfaces
absolemDev Nov 22, 2023
2b0cd55
feat: add form provider, form context, hook useForm
absolemDev Nov 23, 2023
611572e
fix: interfaces
absolemDev Nov 23, 2023
2762700
fix(input-wrapper): transform children arguments to object
absolemDev Nov 23, 2023
e122833
feat: add disabled prop, arguments for cildren button wrapper, edit i…
absolemDev Nov 24, 2023
9ac4775
fix(form-provider): export const
absolemDev Nov 24, 2023
84addff
feat(enums): add ButtonType enum
absolemDev Nov 24, 2023
f8d6d3c
feat: add use-custom-element hook, extend form context, edit interfaces
absolemDev Nov 27, 2023
bf5b803
fix: useMemo props for custom-elements hook, use Condition in wrapper…
absolemDev Nov 28, 2023
78bbb3d
fix: add fields hook, button hook, utils
absolemDev Nov 28, 2023
4272da8
docs: add README.md
absolemDev Nov 28, 2023
cfc8b6b
docs: edit README.md
absolemDev Nov 29, 2023
759c5c0
fix: get-name-fields util
absolemDev Nov 29, 2023
6b3cc3d
docs: edit package name
absolemDev Nov 29, 2023
2da55e8
fix: yarn check
absolemDev Nov 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 89 additions & 2 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions .run/test-unit.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="test-unit" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="yarn test unit" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/zsh" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="true" />
<option name="EXECUTE_SCRIPT_FILE" value="false" />
<envs />
<method v="2" />
</configuration>
</component>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
61 changes: 61 additions & 0 deletions packages/payment-widget/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# @atls/react-payment-widget
TorinAsakura marked this conversation as resolved.
Show resolved Hide resolved

[//]: # 'VERSIONS'

## [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=%40atls-ui-parts%2Fbutton&message=0.0.12&labelColor=097CEB&color=0B6DCC">](https://www.npmjs.com/package/@atls-ui-parts/button/v/0.0.12) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=%40atls-ui-parts%2Fcondition&message=0.0.4&labelColor=097CEB&color=0B6DCC">](https://www.npmjs.com/package/@atls-ui-parts/condition/v/0.0.4) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=%40atls-ui-parts%2Fhidden-input&message=0.0.6&labelColor=097CEB&color=0B6DCC">](https://www.npmjs.com/package/@atls-ui-parts/hidden-input/v/0.0.6) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=%40atls-ui-parts%2Finput&message=0.0.13&labelColor=097CEB&color=0B6DCC">](https://www.npmjs.com/package/@atls-ui-parts/input/v/0.0.13) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=%40atls-ui-parts%2Flayout&message=0.0.7&labelColor=097CEB&color=0B6DCC">](https://www.npmjs.com/package/@atls-ui-parts/layout/v/0.0.7) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=%40atls-ui-parts%2Ftext&message=0.0.11&labelColor=097CEB&color=0B6DCC">](https://www.npmjs.com/package/@atls-ui-parts/layout/v/0.0.7) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=react-intl&message=6.4.4&labelColor=ECEEF5&color=D7DCEB">](https://www.npmjs.com/package/react-intl/v/6.4.4) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=react-laag&message=2.0.5&labelColor=ECEEF5&color=D7DCEB">](https://www.npmjs.com/package/react-laag) [<img src="https://img.shields.io/static/v1?style=for-the-badge&label=styled-tools&message=1.7.2&labelColor=ECEEF5&color=D7DCEB">](https://www.npmjs.com/package/styled-tools)

**@atls/react-payment-widget** предназначен для интеграции в проекты формы, позволяющей проводить оплаты с помощью терминала "Тинькофф Касса". Реализован при помощи `styled-components` и `@emotion`.

## Использование со стандартной темой

Для корректной работы **@atls/react-payment-widget** достаточно для компонента `Widget` назначить атрибуту `settings` объект с ключом `storeID`:

```tsx
import { Widget } from '@atls/react-payment-widget'
export const Form = () => <Widget settings={{ storeId: 'STORE_ID' }} />
```

Основные атрибуты для компонента `Widget`:

- **`settings`** - обязательный атрибут, принимает объект с настройками для терминала.
- **`amount`** - опциональный атрибут, принимает сумму платежа.Без заданного значения `Widget` генерирует обязательное поле для ввода суммы.
- **`additionalFields`** - опциональный атрибут для добавления дополнительных полей, принимает массив объектов с обязательным ключом `name`.
- **`receipt`** - опциональный атрибут, принимает объект с настройками для генерации чека.
- **`styles`** - опциональный атрибут, принимает объект с настройками для генерации чека.
- **`disabled`** - опциональный атрибут для управлением активным состоянием кнопки, принимает булево значение.

## Использование с кастомной темой

**@atls/react-payment-widget** предусматривает возможность использования стилизованных полей ввода и кнопки из Вашего проекта. Для этого предоставляются компоненты обёртки `InputWrapper` и `ButtonWrapper`.

`InputWrapper` принимает обязательный атрибут `name`.

```tsx
import { AdditionalFieldsType } from '@atls/react-payment-widget'
import { ButtonWrapper } from '@atls/react-payment-widget'
import { InputWrapper } from '@atls/react-payment-widget'
import { Widget } from '@atls/react-payment-widget'
export const Form = () => (
<Widget amount={5000} settings={{ storeId: '1698844342541DEMO' }}>
<InputWrapper name={AdditionalFieldsType.Email}>{(props) => <Input {...props} />}</InputWrapper>
<ButtonWrapper>{(props) => <Button {...props}>Оплатить</Button>}</ButtonWrapper>
</Widget>
)
```

> [!WARNING]
> Не используйте атрибут `additionalFields` совместно с `InputWrapper`, это приведет к исключению.
>
> Так же, при использовании `InputWrapper` Виджет не генерирует дополнительные поля.

## Экспортируемые компоненты

[**Widget**]() - главный компонент Виджета.

[**InputWrapper**]() - компонент обёртка для полей ввода.

[**ButtonWrapper**]() - компонент обёртка для кнопки.

[**AdditionalFieldsType**]() - интерфейс дополнительных полей.

[**RequiredFieldsType**]() - интерфейс обязательных полей.
4 changes: 4 additions & 0 deletions packages/payment-widget/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,16 @@
"styled-tools": "1.7.2"
},
"devDependencies": {
"@emotion/jest": "11.9.4",
"@emotion/react": "11.9.3",
"@emotion/styled": "11.9.3",
"@testing-library/react": "14.1.0",
"@types/react": "18.2.20",
"@types/react-dom": "18",
"@types/styled-system": "5.1.16",
"csstype": "3.1.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"styled-system": "5.1.5"
},
"peerDependencies": {
Expand Down
4 changes: 4 additions & 0 deletions packages/payment-widget/src/enums/button.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* eslint-disable no-shadow */
export enum ButtonType {
Submit = 'submit',
}
2 changes: 2 additions & 0 deletions packages/payment-widget/src/enums/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from './payment-method.enum'
export * from './payment-object.enum'
export * from './tax.enum'
export * from './taxation.enum'
export * from './button.enum'
export * from './wrapper.enum'
5 changes: 5 additions & 0 deletions packages/payment-widget/src/enums/wrapper.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* eslint-disable no-shadow */
export enum NameWrapperComponent {
InputWrapper = 'InputWrapper',
ButtonWrapper = 'ButtonWrapper',
}
2 changes: 2 additions & 0 deletions packages/payment-widget/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export * from './use-init.hook'
export { useValidate } from './use-validate.hook'
export { useFieldsState } from './use-fields-state.hook'
export { useFieldsRenderer } from './use-fields-render.hook'
export { useCustomFields } from './use-custom-fields.hook'
export { useCustomButton } from './use-custom-button.hook'
7 changes: 7 additions & 0 deletions packages/payment-widget/src/hooks/use-custom-button.hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ReactNode } from 'react'

import { NameWrapperComponent } from '../enums'
import { isCustomElement } from '../utils'

export const useCustomButton = (nodeArray: ReactNode[]): ReactNode =>
nodeArray.find((node) => isCustomElement(NameWrapperComponent.ButtonWrapper, node))
60 changes: 60 additions & 0 deletions packages/payment-widget/src/hooks/use-custom-fields.hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ReactNode } from 'react'
import { isValidElement } from 'react'

import { AdditionalFieldsType } from '../enums'
import { NameWrapperComponent } from '../enums'
import { RequiredFieldsType } from '../enums'
import { CustomFields } from '../interfaces'
import { CustomFieldsProps } from '../interfaces'
import { isCustomElement } from '../utils'

export const useCustomFields = ({
existAmount,
existReceipt,
existAdditionalFields,
nodeArray,
}: CustomFieldsProps): CustomFields => {
const isAdditionalField = (node: ReactNode): boolean =>
isValidElement(node) ? Object.values(AdditionalFieldsType).includes(node.props.name) : false
const isRequiredField = (node: ReactNode): boolean =>
isValidElement(node) ? node.props.name === RequiredFieldsType.Amount && !existAmount : false

const customFields = nodeArray.filter(
(node) =>
isCustomElement(NameWrapperComponent.InputWrapper, node) &&
(isAdditionalField(node) || isRequiredField(node))
)

const isGenerateReceiptField = existReceipt && !customFields.length

const isGenerateRequiredField = !existAmount && existAdditionalFields

const existCustomAmountField = customFields.some(
(field) => isValidElement(field) && field.props.name === RequiredFieldsType.Amount
)
const existCustomReceiptField = customFields.some(
(field) =>
isValidElement(field) &&
(field.props.name === AdditionalFieldsType.Email ||
field.props.name === AdditionalFieldsType.Phone)
)

if (existAdditionalFields && customFields.length)
throw new Error('Don`t use additionalFields property with InputWrapper component')

if (customFields.length && !existAmount && !existCustomAmountField)
throw new Error(
'If you use InputWrapper component and don`t set amount property, you mast use InputWrapper componnet with property name equal RequiredFieldsType.Amount'
)

if (customFields.length && existReceipt && !existCustomReceiptField)
throw new Error(
'If you set receipt property whith InputWrapper component, you mast use InputWrapper componnet with property name equal AdditionalFieldsType.Phone or AdditionalFieldsType.Email'
)

return {
customFields,
isGenerateReceiptField,
isGenerateRequiredField,
}
}
Loading
Loading