From 183f0ff399aded1569de926f2f5eb8eb29c32857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD=20=D0=9F=D0=B8=D0=BC=D0=B8=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2?= <61900450+ivan-piminov@users.noreply.github.com> Date: Tue, 24 Aug 2021 17:10:10 +0300 Subject: [PATCH] feat(#1330): added arrow loader (#437) * feat(#1330): added arrow loader * refactor(#1330): refactoring * refactor(#1330): rename --- public/images/arrowGroup.svg | 4 ++ .../components/Form/hooks/index.tsx | 11 +++++- .../AddCardForm/components/Form/index.tsx | 10 ++--- src/features/AddCardForm/index.tsx | 11 ++++-- src/features/ArrowLoader/index.tsx | 19 +++++++++ src/features/ArrowLoader/styled.tsx | 39 +++++++++++++++++++ src/features/ArrowLoader/types.tsx | 6 +++ .../SubscriptionSelectionStep/index.tsx | 18 ++++++--- .../BuyMatchPopup/store/hooks/index.tsx | 6 ++- src/features/CardsStore/hooks/index.tsx | 11 ++++-- .../UserAccount/components/BankCard/index.tsx | 12 +++++- .../components/PageBankCards/index.tsx | 2 + src/features/UserAccount/styled.tsx | 6 +++ 13 files changed, 130 insertions(+), 25 deletions(-) create mode 100644 public/images/arrowGroup.svg create mode 100644 src/features/ArrowLoader/index.tsx create mode 100644 src/features/ArrowLoader/styled.tsx create mode 100644 src/features/ArrowLoader/types.tsx diff --git a/public/images/arrowGroup.svg b/public/images/arrowGroup.svg new file mode 100644 index 00000000..59b845d9 --- /dev/null +++ b/public/images/arrowGroup.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/features/AddCardForm/components/Form/hooks/index.tsx b/src/features/AddCardForm/components/Form/hooks/index.tsx index 370ff9eb..a427617d 100644 --- a/src/features/AddCardForm/components/Form/hooks/index.tsx +++ b/src/features/AddCardForm/components/Form/hooks/index.tsx @@ -32,6 +32,7 @@ export type Props = { children?: ReactNode, initialformOpen?: boolean, inputsBackground?: string, + loader?: boolean, onAddSuccess?: () => void, } @@ -54,6 +55,7 @@ export const useFormSubmit = ({ onAddSuccess }: Props) => { const [name, setName] = useState('') const [inputStates, setInputStates] = useObjectState(initialState) const [error, setError] = useState('') + const [loader, setLoader] = useState(false) const onNameChange = (e: ChangeEvent) => { const { value } = e.target @@ -104,7 +106,7 @@ export const useFormSubmit = ({ onAddSuccess }: Props) => { const cardNumberElement = elements.getElement(CardNumberElement) if (!cardNumberElement) return - + setLoader(true) const { error: tokenError, token } = await stripe.createToken( cardNumberElement, { name }, @@ -112,8 +114,12 @@ export const useFormSubmit = ({ onAddSuccess }: Props) => { if (tokenError) { setError(tokenError.message || '') + setLoader(false) } else if (token) { - onAddCard(token.id).then(onAddSuccess) + setLoader(true) + onAddCard(token.id) + .then(onAddSuccess) + .then(() => setLoader(false)) } } @@ -125,6 +131,7 @@ export const useFormSubmit = ({ onAddSuccess }: Props) => { error, handleSubmit, isLabelVisible, + loader, name, onInputsBlur, onInputsChange, diff --git a/src/features/AddCardForm/components/Form/index.tsx b/src/features/AddCardForm/components/Form/index.tsx index 424b24f7..57b8e8b8 100644 --- a/src/features/AddCardForm/components/Form/index.tsx +++ b/src/features/AddCardForm/components/Form/index.tsx @@ -8,7 +8,7 @@ import { isMobileDevice } from 'config/userAgent' import { T9n } from 'features/T9n' import { useCardsStore } from 'features/CardsStore' -import { SolidButton } from 'features/UserAccount/styled' +import { ArrowLoader } from 'features/ArrowLoader' import { ElementContainer } from '../ElementContainer' @@ -51,6 +51,7 @@ export const AddCardFormInner = (props: Props) => { error: formError, handleSubmit, isLabelVisible, + loader, name, onInputsBlur, onInputsChange, @@ -121,12 +122,7 @@ export const AddCardFormInner = (props: Props) => { ) } - - {children || ( - - Сохранить - - )} + {loader ? : children} ) diff --git a/src/features/AddCardForm/index.tsx b/src/features/AddCardForm/index.tsx index 68e68d07..965e35e8 100644 --- a/src/features/AddCardForm/index.tsx +++ b/src/features/AddCardForm/index.tsx @@ -3,13 +3,16 @@ import type { MouseEvent } from 'react' import { useToggle } from 'hooks' import { T9n } from 'features/T9n' -import { OutlineButton, Icon } from 'features/UserAccount/styled' +import { + OutlineButton, + Icon, + SolidButton, +} from 'features/UserAccount/styled' import type { Props } from './components/Form/hooks' import { AddCardFormInner } from './components/Form' export const AddCardForm = ({ - children, initialformOpen, inputsBackground, onAddSuccess, @@ -33,7 +36,9 @@ export const AddCardForm = ({ inputsBackground={inputsBackground} onAddSuccess={onSuccess} > - {children} + + Сохранить + ) : ( diff --git a/src/features/ArrowLoader/index.tsx b/src/features/ArrowLoader/index.tsx new file mode 100644 index 00000000..8e432a21 --- /dev/null +++ b/src/features/ArrowLoader/index.tsx @@ -0,0 +1,19 @@ +import { ArrowLoaderProps } from './types' +import { Wrapper, Arrows } from './styled' + +export const ArrowLoader = ({ + backgroundColor, + backgroundSize, + disabled, + width, +}: ArrowLoaderProps) => ( + + + +) + +export const ArrowLoaderUI = { ArrowLoader, Arrows } diff --git a/src/features/ArrowLoader/styled.tsx b/src/features/ArrowLoader/styled.tsx new file mode 100644 index 00000000..9f960bb5 --- /dev/null +++ b/src/features/ArrowLoader/styled.tsx @@ -0,0 +1,39 @@ +import styled from 'styled-components/macro' +import { keyframes } from 'styled-components' + +import { ArrowLoaderProps } from './types' + +const rotate = keyframes` + from { + transform: rotate(360deg); + } + + to { + transform: rotate(0deg); + } +` + +export const Wrapper = styled.button` + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); + border-color: transparent; + width: ${({ width = 'auto' }) => width}; + height: 50px; + background-color: ${({ backgroundColor = '#294fc4' }) => backgroundColor}; + border-radius: 5px; + display: flex; + align-items: center; + justify-content: center; + :disabled { + opacity: 0.5; + } +` + +export const Arrows = styled.div` + width: 36px; + height: 34px; + background-size: ${({ backgroundSize = 'contain' }) => backgroundSize}; + background-image: url(/images/arrowGroup.svg); + background-repeat: no-repeat; + background-position: center; + animation: ${rotate} 1s linear infinite; + ` diff --git a/src/features/ArrowLoader/types.tsx b/src/features/ArrowLoader/types.tsx new file mode 100644 index 00000000..48b657a1 --- /dev/null +++ b/src/features/ArrowLoader/types.tsx @@ -0,0 +1,6 @@ +export type ArrowLoaderProps = { + backgroundColor?: string, + backgroundSize?: string, + disabled?: boolean, + width?:string, +} diff --git a/src/features/BuyMatchPopup/components/SubscriptionSelectionStep/index.tsx b/src/features/BuyMatchPopup/components/SubscriptionSelectionStep/index.tsx index 48496fbf..14a694f4 100644 --- a/src/features/BuyMatchPopup/components/SubscriptionSelectionStep/index.tsx +++ b/src/features/BuyMatchPopup/components/SubscriptionSelectionStep/index.tsx @@ -11,6 +11,7 @@ import { import { T9n } from 'features/T9n' import { Name } from 'features/Name' import { useCardsStore } from 'features/CardsStore' +import { ArrowLoader } from 'features/ArrowLoader' import { useBuyMatchPopupStore } from '../../store' import { SelectedCard } from '../SelectedCard' @@ -32,6 +33,7 @@ export const SubscriptionSelectionStep = () => { const { close, + loader, match, onBuyClick, selectedSubscription, @@ -62,12 +64,16 @@ export const SubscriptionSelectionStep = () => {
- + {loader + ? + : ( + + )}
) diff --git a/src/features/BuyMatchPopup/store/hooks/index.tsx b/src/features/BuyMatchPopup/store/hooks/index.tsx index c2515097..daf08175 100644 --- a/src/features/BuyMatchPopup/store/hooks/index.tsx +++ b/src/features/BuyMatchPopup/store/hooks/index.tsx @@ -42,10 +42,12 @@ export const useBuyMatchPopup = () => { const [steps, setSteps] = useState>([]) const [match, setMatch] = useState(null) const [error, setError] = useState('') + const [loader, setLoader] = useState(false) const goTo = useCallback( (step: Steps, e?: MouseEvent) => setSteps((state) => { e?.stopPropagation() + setLoader(false) return [...state, step] }), [], @@ -134,7 +136,7 @@ export const useBuyMatchPopup = () => { const item = selectedSubscription.originalObject const buy = requests[selectedSubscription.type] - + setLoader(true) buy({ cardId: defaultCard.id, item }).then( onSuccessfulSubscription, onUnsuccessfulSubscription, @@ -142,6 +144,7 @@ export const useBuyMatchPopup = () => { } const onBuyClick = (e?: MouseEvent) => { + e?.stopPropagation() if (defaultCard) { subscribeToMatch() } else { @@ -161,6 +164,7 @@ export const useBuyMatchPopup = () => { error, goBack, goTo, + loader, match, matchSubscriptions, onBuyClick, diff --git a/src/features/CardsStore/hooks/index.tsx b/src/features/CardsStore/hooks/index.tsx index 71495343..55b8bd42 100644 --- a/src/features/CardsStore/hooks/index.tsx +++ b/src/features/CardsStore/hooks/index.tsx @@ -12,13 +12,14 @@ import { addCard } from 'requests/addCard' import { deleteCard } from 'requests/deleteCard' import { setDefaultCard as setDefaultCardRequest } from 'requests/setDefaultCard' -import { useToggle } from 'hooks' +import { useRequest, useToggle } from 'hooks' export const useBankCards = () => { const { isOpen: infoModalOpen, toggle: toggleInfoModal, } = useToggle() + const [error, setError] = useState('') const [cards, setCards] = useState(null) const defaultCard = useMemo( @@ -37,12 +38,13 @@ export const useBankCards = () => { .then(fetchCards) ) - const onDeleteCard = (cardId: string) => { - deleteCard(cardId).then(() => { + const onDeleteCard = async (cardId: string) => { + await deleteCard(cardId).then(() => { fetchCards() toggleInfoModal() }) } + const { isFetching, request: handleCardDelete } = useRequest(onDeleteCard) const onSetDefaultCard = (cardId: string) => { setDefaultCardRequest(cardId).then(fetchCards) @@ -54,8 +56,9 @@ export const useBankCards = () => { error, fetchCards, infoModalOpen, + isFetching, onAddCard, - onDeleteCard, + onDeleteCard: handleCardDelete, onSetDefaultCard, setError, toggleInfoModal, diff --git a/src/features/UserAccount/components/BankCard/index.tsx b/src/features/UserAccount/components/BankCard/index.tsx index 3a58d07c..713c18b9 100644 --- a/src/features/UserAccount/components/BankCard/index.tsx +++ b/src/features/UserAccount/components/BankCard/index.tsx @@ -1,6 +1,7 @@ import type { Card } from 'requests/getCardsList' import { T9n } from 'features/T9n' +import { Arrows } from 'features/ArrowLoader/styled' import { InlineButton } from '../../styled' import { CardNumberWrapper, CustomRadio } from './styled' @@ -8,6 +9,7 @@ import { CardNumberWrapper, CustomRadio } from './styled' type Props = { card: Card, checked?: boolean, + loader?: boolean, onChange: (cardId: string) => void, onDelete: (cardId: string) => void, } @@ -15,6 +17,7 @@ type Props = { export const BankCard = ({ card, checked, + loader, onChange, onDelete, }: Props) => ( @@ -24,8 +27,13 @@ export const BankCard = ({ checked={checked} onChange={() => onChange(card.id)} /> - onDelete(card.id)}> - + onDelete(card.id)} + > + {loader + ? + : } ) diff --git a/src/features/UserAccount/components/PageBankCards/index.tsx b/src/features/UserAccount/components/PageBankCards/index.tsx index 69d19362..e5c00389 100644 --- a/src/features/UserAccount/components/PageBankCards/index.tsx +++ b/src/features/UserAccount/components/PageBankCards/index.tsx @@ -29,6 +29,7 @@ export const PageBankCards = () => { defaultCard, fetchCards, infoModalOpen, + isFetching, onDeleteCard, onSetDefaultCard, toggleInfoModal, @@ -49,6 +50,7 @@ export const PageBankCards = () => { checked={card.id === defaultCard?.id} onChange={onSetDefaultCard} onDelete={onDeleteCard} + loader={isFetching} /> ))} diff --git a/src/features/UserAccount/styled.tsx b/src/features/UserAccount/styled.tsx index cc5ee9d8..1e6adb04 100644 --- a/src/features/UserAccount/styled.tsx +++ b/src/features/UserAccount/styled.tsx @@ -159,6 +159,9 @@ type InlineButtonProps = { } export const InlineButton = styled.button` + display: flex; + justify-content: center; + align-items: center; position: absolute; right: 0; border: none; @@ -173,4 +176,7 @@ export const InlineButton = styled.button` cursor: pointer; transition: transform 0.3s ease-in-out; transform: translateX(calc(100% + 1px)); + :disabled { + opacity: 0.5; + } `