From 20fc0411107776a32efb3d3ac28592960c82afdf Mon Sep 17 00:00:00 2001 From: Ildar Galeev Date: Fri, 19 Jul 2024 16:57:56 +0700 Subject: [PATCH] Payment method selector refactoring (#320) --- src/common/components/MetadataLogoBox.tsx | 21 ---------- src/common/components/Pane/Pane.tsx | 24 +++++++++++ src/common/components/Pane/PaneLogo.tsx | 5 +++ src/common/components/Pane/PaneLogoBox.tsx | 12 ++++++ .../components/Pane/PaneMetadataLogo.tsx | 10 +++++ src/common/components/Pane/PaneText.tsx | 18 ++++++++ src/common/components/Pane/index.ts | 7 ++++ src/common/components/index.ts | 4 +- .../PaymentFormView/CardForm/CardForm.tsx | 2 +- .../MetadataForm/MetadataForm.tsx | 10 ++--- .../BankCardPane.tsx | 29 +++++-------- .../PaymentMethodSelectorView.tsx | 38 ++++++++--------- .../PaymentTerminalPane.tsx | 41 ++++++++----------- .../TerminalSelectorPane.tsx | 31 +++++--------- .../ServiceProviderPane.tsx | 40 ------------------ .../TerminalSelectorView.tsx | 29 +++++++++---- src/components/ViewContainer/types.ts | 1 + src/components/ViewContainer/useViewModel.ts | 2 + 18 files changed, 165 insertions(+), 159 deletions(-) delete mode 100644 src/common/components/MetadataLogoBox.tsx create mode 100644 src/common/components/Pane/Pane.tsx create mode 100644 src/common/components/Pane/PaneLogo.tsx create mode 100644 src/common/components/Pane/PaneLogoBox.tsx create mode 100644 src/common/components/Pane/PaneMetadataLogo.tsx create mode 100644 src/common/components/Pane/PaneText.tsx create mode 100644 src/common/components/Pane/index.ts delete mode 100644 src/components/ViewContainer/TerminalSelectorView/ServiceProviderPane.tsx diff --git a/src/common/components/MetadataLogoBox.tsx b/src/common/components/MetadataLogoBox.tsx deleted file mode 100644 index 7ca139b1..00000000 --- a/src/common/components/MetadataLogoBox.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Center, Image, Square, useColorModeValue } from '@chakra-ui/react'; -import { HiOutlineCash } from 'react-icons/hi'; - -import { ServiceProviderIconMetadata } from 'checkout/backend/payments/serviceProviderMetadata'; -import { isNil } from 'checkout/utils'; - -export type MetadataLogoBoxProps = { - logo?: ServiceProviderIconMetadata; - height: number; -}; - -export function MetadataLogoBox({ logo, height }: MetadataLogoBoxProps) { - const bgColor = useColorModeValue('white', 'gray.100'); - - return ( -
- {!isNil(logo) && } - {isNil(logo) && } -
- ); -} diff --git a/src/common/components/Pane/Pane.tsx b/src/common/components/Pane/Pane.tsx new file mode 100644 index 00000000..a2d01dee --- /dev/null +++ b/src/common/components/Pane/Pane.tsx @@ -0,0 +1,24 @@ +import { StackProps, useColorModeValue, VStack } from '@chakra-ui/react'; + +export type PaneProps = StackProps; + +export function Pane(props: PaneProps) { + const { children, ...rest } = props; + const hoverBorderColor = useColorModeValue('gray.300', 'whiteAlpha.400'); + + return ( + + {children} + + ); +} diff --git a/src/common/components/Pane/PaneLogo.tsx b/src/common/components/Pane/PaneLogo.tsx new file mode 100644 index 00000000..f0d2e58b --- /dev/null +++ b/src/common/components/Pane/PaneLogo.tsx @@ -0,0 +1,5 @@ +import { Square, SquareProps } from '@chakra-ui/react'; + +export function PaneLogo(props: SquareProps) { + return ; +} diff --git a/src/common/components/Pane/PaneLogoBox.tsx b/src/common/components/Pane/PaneLogoBox.tsx new file mode 100644 index 00000000..08ebdaca --- /dev/null +++ b/src/common/components/Pane/PaneLogoBox.tsx @@ -0,0 +1,12 @@ +import { Center, CenterProps, useColorModeValue } from '@chakra-ui/react'; + +export function PaneLogoBox(props: CenterProps) { + const { children, ...rest } = props; + const bgColor = useColorModeValue('white', 'gray.100'); + + return ( +
+ {children} +
+ ); +} diff --git a/src/common/components/Pane/PaneMetadataLogo.tsx b/src/common/components/Pane/PaneMetadataLogo.tsx new file mode 100644 index 00000000..6691d687 --- /dev/null +++ b/src/common/components/Pane/PaneMetadataLogo.tsx @@ -0,0 +1,10 @@ +import { ImageProps, Image } from '@chakra-ui/react'; + +import { ServiceProviderIconMetadata } from 'checkout/backend/payments/serviceProviderMetadata'; + +export type PaneMetadataLogoProps = { logo: ServiceProviderIconMetadata } & ImageProps; + +export function PaneMetadataLogo(props: PaneMetadataLogoProps) { + const { logo, ...rest } = props; + return ; +} diff --git a/src/common/components/Pane/PaneText.tsx b/src/common/components/Pane/PaneText.tsx new file mode 100644 index 00000000..58ffbdbc --- /dev/null +++ b/src/common/components/Pane/PaneText.tsx @@ -0,0 +1,18 @@ +import { Text, TextProps } from '@chakra-ui/react'; + +export function PaneText(props: TextProps) { + const { children, ...rest } = props; + return ( + + {children} + + ); +} diff --git a/src/common/components/Pane/index.ts b/src/common/components/Pane/index.ts new file mode 100644 index 00000000..35e75f2c --- /dev/null +++ b/src/common/components/Pane/index.ts @@ -0,0 +1,7 @@ +export { Pane } from './Pane'; +export { PaneText } from './PaneText'; +export { PaneLogoBox } from './PaneLogoBox'; +export { PaneLogo } from './PaneLogo'; +export { PaneMetadataLogo } from './PaneMetadataLogo'; + +export type { PaneMetadataLogoProps } from './PaneMetadataLogo'; diff --git a/src/common/components/index.ts b/src/common/components/index.ts index b519ca8f..473bf906 100644 --- a/src/common/components/index.ts +++ b/src/common/components/index.ts @@ -1,4 +1,6 @@ export { ErrorAlert } from './ErrorAlert'; export { BackwardBox } from './BackwardBox'; export { GlobalSpinner } from './GlobalSpinner'; -export { MetadataLogoBox } from './MetadataLogoBox'; +export { Pane, PaneLogo, PaneLogoBox, PaneText, PaneMetadataLogo } from './Pane'; + +export type { PaneMetadataLogoProps } from './Pane'; diff --git a/src/components/ViewContainer/PaymentFormView/CardForm/CardForm.tsx b/src/components/ViewContainer/PaymentFormView/CardForm/CardForm.tsx index 97426657..995ca33b 100644 --- a/src/components/ViewContainer/PaymentFormView/CardForm/CardForm.tsx +++ b/src/components/ViewContainer/PaymentFormView/CardForm/CardForm.tsx @@ -52,7 +52,7 @@ export function CardForm() { return (
- + {hasBackward && } {l['form.header.pay.card.label']} diff --git a/src/components/ViewContainer/PaymentFormView/MetadataForm/MetadataForm.tsx b/src/components/ViewContainer/PaymentFormView/MetadataForm/MetadataForm.tsx index d2d905ba..aa212d50 100644 --- a/src/components/ViewContainer/PaymentFormView/MetadataForm/MetadataForm.tsx +++ b/src/components/ViewContainer/PaymentFormView/MetadataForm/MetadataForm.tsx @@ -1,8 +1,8 @@ -import { Button, Center, LightMode, Spacer, VStack } from '@chakra-ui/react'; +import { Button, LightMode, Spacer, VStack } from '@chakra-ui/react'; import { useContext } from 'react'; import { FieldError, SubmitHandler, useForm } from 'react-hook-form'; -import { BackwardBox, MetadataLogoBox } from 'checkout/components'; +import { BackwardBox, PaneLogoBox, PaneMetadataLogo } from 'checkout/components'; import { LocaleContext, PaymentContext, PaymentModelContext, ViewModelContext } from 'checkout/contexts'; import { toDefaultFormValuesMetadata } from 'checkout/paymentCondition'; import { TerminalValues } from 'checkout/paymentMgmt'; @@ -61,9 +61,9 @@ export function MetadataForm({ provider }: MetadataFormProps) { {hasBackward ? : } {!isNil(logo) && ( -
- -
+ + + )} {!isNil(form) && form diff --git a/src/components/ViewContainer/PaymentMethodSelectorView/BankCardPane.tsx b/src/components/ViewContainer/PaymentMethodSelectorView/BankCardPane.tsx index a220f32d..a0f9ef86 100644 --- a/src/components/ViewContainer/PaymentMethodSelectorView/BankCardPane.tsx +++ b/src/components/ViewContainer/PaymentMethodSelectorView/BankCardPane.tsx @@ -1,29 +1,22 @@ import { useContext } from 'react'; +import { HiCreditCard } from 'react-icons/hi'; -import { LocaleContext, ViewModelContext } from '../../../common/contexts'; -import { Method, PaymentMethodIcon, PaymentMethodTitle } from '../../legacy'; +import { Pane, PaneLogo, PaneLogoBox, PaneText } from 'checkout/components'; +import { LocaleContext } from 'checkout/contexts'; export type BankCardPaneProps = { - destinationViewId: string; + onClick: () => void; }; -export function BankCardPane({ destinationViewId }: BankCardPaneProps) { +export function BankCardPane({ onClick }: BankCardPaneProps) { const { l } = useContext(LocaleContext); - const { - viewModel: { views }, - forward, - } = useContext(ViewModelContext); - - const destination = views.get(destinationViewId); - - if (destination.name !== 'PaymentFormView') { - throw new Error(`Wrong View. Expected: PaymentFormView, actual: ${destination.name}`); - } return ( - forward(destinationViewId)}> - - {l['form.payment.method.name.card.label']} - + + + + + {l['form.payment.method.name.card.label']} + ); } diff --git a/src/components/ViewContainer/PaymentMethodSelectorView/PaymentMethodSelectorView.tsx b/src/components/ViewContainer/PaymentMethodSelectorView/PaymentMethodSelectorView.tsx index 24bf6274..3ff8cb07 100644 --- a/src/components/ViewContainer/PaymentMethodSelectorView/PaymentMethodSelectorView.tsx +++ b/src/components/ViewContainer/PaymentMethodSelectorView/PaymentMethodSelectorView.tsx @@ -1,21 +1,17 @@ +import { VStack, Text, SimpleGrid } from '@chakra-ui/react'; import { useContext } from 'react'; -import styled from 'styled-components'; + +import { LocaleContext, ViewModelContext } from 'checkout/contexts'; import { BankCardPane } from './BankCardPane'; import { PaymentTerminalPane } from './PaymentTerminalPane'; import { TerminalSelectorPane } from './TerminalSelectorPane'; -import { LocaleContext, ViewModelContext } from '../../../common/contexts'; -import { HeaderWrapper, Title } from '../../../components/legacy'; - -const PanesWrapper = styled.div` - display: flex; - flex-direction: column; -`; export function PaymentMethodSelectorView() { const { l } = useContext(LocaleContext); const { viewModel: { views, activeViewId }, + forward, } = useContext(ViewModelContext); const view = views.get(activeViewId); @@ -24,22 +20,26 @@ export function PaymentMethodSelectorView() { } return ( - <> - - {l['form.header.payment.methods.label']} - - - {view.items.map(({ name, viewId }, key) => { + + + {l['form.header.payment.methods.label']} + + + {view.items.map(({ name, viewId, provider, category }, key) => { switch (name) { case 'BankCard': - return ; + return forward(viewId)} />; case 'PaymentTerminal': - return ; + return ( + forward(viewId)} /> + ); case 'TerminalSelector': - return ; + return ( + forward(viewId)} /> + ); } })} - - + +
); } diff --git a/src/components/ViewContainer/PaymentMethodSelectorView/PaymentTerminalPane.tsx b/src/components/ViewContainer/PaymentMethodSelectorView/PaymentTerminalPane.tsx index 9688e753..b6cfb6de 100644 --- a/src/components/ViewContainer/PaymentMethodSelectorView/PaymentTerminalPane.tsx +++ b/src/components/ViewContainer/PaymentMethodSelectorView/PaymentTerminalPane.tsx @@ -1,38 +1,29 @@ -import { Text } from '@chakra-ui/react'; import { useContext } from 'react'; +import { HiCash } from 'react-icons/hi'; -import { PaymentModelContext, ViewModelContext } from '../../../common/contexts'; -import { isNil } from '../../../common/utils'; -import { findMetadata } from '../../../common/utils/findMetadata'; -import { MetadataLogo, PaymentMethodItemContainer } from '../../legacy'; +import { Pane, PaneLogoBox, PaneLogo, PaneText, PaneMetadataLogo } from 'checkout/components'; +import { PaymentModelContext } from 'checkout/contexts'; +import { isNil } from 'checkout/utils'; +import { findMetadata } from 'checkout/utils/findMetadata'; export type PaymentTerminalPaneProps = { - destinationViewId: string; + provider: string; + onClick: () => void; }; -export function PaymentTerminalPane({ destinationViewId }: PaymentTerminalPaneProps) { +export function PaymentTerminalPane({ onClick, provider }: PaymentTerminalPaneProps) { const { paymentModel: { serviceProviders }, } = useContext(PaymentModelContext); - const { - forward, - viewModel: { views }, - } = useContext(ViewModelContext); - const destination = views.get(destinationViewId); - - if (destination.name !== 'PaymentFormView') { - throw new Error(`Wrong View. Expected: PaymentFormView, actual: ${destination.name}`); - } - - const { logo } = findMetadata(serviceProviders, destination.provider); + const { logo } = findMetadata(serviceProviders, provider); + const serviceProvider = serviceProviders.find(({ id }) => id === provider); return ( - forward(destinationViewId)} - > - {!isNil(logo) && } - {isNil(logo) && {destination.provider}} - + + + {isNil(logo) && } {!isNil(logo) && } + + {serviceProvider?.brandName} + ); } diff --git a/src/components/ViewContainer/PaymentMethodSelectorView/TerminalSelectorPane.tsx b/src/components/ViewContainer/PaymentMethodSelectorView/TerminalSelectorPane.tsx index 27452809..1f73fe4c 100644 --- a/src/components/ViewContainer/PaymentMethodSelectorView/TerminalSelectorPane.tsx +++ b/src/components/ViewContainer/PaymentMethodSelectorView/TerminalSelectorPane.tsx @@ -1,28 +1,19 @@ -import { useContext } from 'react'; +import { HiCash } from 'react-icons/hi'; -import { ViewModelContext } from '../../../common/contexts'; -import { Method, PaymentMethodIcon, PaymentMethodTitle } from '../../legacy'; +import { Pane, PaneLogoBox, PaneLogo, PaneText } from 'checkout/components'; export type TerminalSelectorPaneProps = { - destinationViewId: string; + category: string; + onClick: () => void; }; -export function TerminalSelectorPane({ destinationViewId }: TerminalSelectorPaneProps) { - const { - forward, - viewModel: { views }, - } = useContext(ViewModelContext); - - const destination = views.get(destinationViewId); - - if (destination.name !== 'TerminalSelectorView') { - throw new Error(`Wrong View. Expected: TerminalSelectorView, actual: ${destination.name}`); - } - +export function TerminalSelectorPane({ onClick, category }: TerminalSelectorPaneProps) { return ( - forward(destinationViewId)}> - - {destination.category} - + + + + + {category} + ); } diff --git a/src/components/ViewContainer/TerminalSelectorView/ServiceProviderPane.tsx b/src/components/ViewContainer/TerminalSelectorView/ServiceProviderPane.tsx deleted file mode 100644 index 5f67cf36..00000000 --- a/src/components/ViewContainer/TerminalSelectorView/ServiceProviderPane.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { VStack, Text, useColorModeValue } from '@chakra-ui/react'; - -import { ServiceProviderIconMetadata } from 'checkout/backend/payments/serviceProviderMetadata'; -import { MetadataLogoBox } from 'checkout/components'; - -type ServiceProviderPaneProps = { - logo?: ServiceProviderIconMetadata; - text: string; - onClick: () => void; -}; - -export function ServiceProviderPane({ text, logo, onClick }: ServiceProviderPaneProps) { - const hoverBorderColor = useColorModeValue('gray.300', 'whiteAlpha.400'); - - return ( - - - - {text} - - - ); -} diff --git a/src/components/ViewContainer/TerminalSelectorView/TerminalSelectorView.tsx b/src/components/ViewContainer/TerminalSelectorView/TerminalSelectorView.tsx index ccf39fc3..7b66c313 100644 --- a/src/components/ViewContainer/TerminalSelectorView/TerminalSelectorView.tsx +++ b/src/components/ViewContainer/TerminalSelectorView/TerminalSelectorView.tsx @@ -1,25 +1,26 @@ -import { VStack, SimpleGrid, Input } from '@chakra-ui/react'; +import { VStack, SimpleGrid, Input, Flex, Text } from '@chakra-ui/react'; import { useContext, useMemo } from 'react'; +import { HiCash } from 'react-icons/hi'; -import { BackwardBox } from 'checkout/components'; +import { BackwardBox, Pane, PaneLogo, PaneLogoBox, PaneMetadataLogo, PaneText } from 'checkout/components'; import { LocaleContext, PaymentModelContext, ViewModelContext } from 'checkout/contexts'; +import { isNil } from 'checkout/utils'; import { PageNavigation } from './PageNavigation'; -import { ServiceProviderPane } from './ServiceProviderPane'; import { useGridPages } from './useGrigPages'; const ITEMS_ON_PAGE = 6; export function TerminalSelectorView() { const { l } = useContext(LocaleContext); - const { - paymentModel: { serviceProviders }, - } = useContext(PaymentModelContext); const { viewModel: { views, activeViewId, hasBackward }, backward, forward, } = useContext(ViewModelContext); + const { + paymentModel: { serviceProviders }, + } = useContext(PaymentModelContext); const view = views.get(activeViewId); if (view.name !== 'TerminalSelectorView') { @@ -39,12 +40,22 @@ export function TerminalSelectorView() { }; return ( - - {hasBackward && } + + + {hasBackward && } + + {l['form.header.payment.methods.label']} + + {isSearchAvailable && } {pageItems.map(({ logo, brandName, viewId }, i) => ( - forward(viewId)} /> + forward(viewId)}> + + {isNil(logo) && } {!isNil(logo) && } + + {brandName} + ))} {totalPages > 1 && ( diff --git a/src/components/ViewContainer/types.ts b/src/components/ViewContainer/types.ts index ef3d8025..c70f58c0 100644 --- a/src/components/ViewContainer/types.ts +++ b/src/components/ViewContainer/types.ts @@ -31,6 +31,7 @@ export type TerminalSelectorView = { export type PaymentMethodSelectorItem = { name: PaymentMethodName | 'TerminalSelector'; viewId: string; + category?: string; provider?: string; }; diff --git a/src/components/ViewContainer/useViewModel.ts b/src/components/ViewContainer/useViewModel.ts index d5637785..ef48be0d 100644 --- a/src/components/ViewContainer/useViewModel.ts +++ b/src/components/ViewContainer/useViewModel.ts @@ -126,6 +126,7 @@ const toViews = (paymentMethods: PaymentMethod[]): [Map, string] = const singleProviderSelectorItem: PaymentMethodSelectorItem = { name: methodName, viewId: singleProviderTerminalId, + category, provider: providers[0], }; return [ @@ -150,6 +151,7 @@ const toViews = (paymentMethods: PaymentMethod[]): [Map, string] = }; const terminalSelectorItem: PaymentMethodSelectorItem = { name: 'TerminalSelector', + category, viewId: terminalSelectorId, }; return [