diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx index 059418c6..10eeccb5 100644 --- a/src/config/lexics/indexLexics.tsx +++ b/src/config/lexics/indexLexics.tsx @@ -21,13 +21,19 @@ const matchPopupLexics = { } const buyMatchPopupLexics = { + buy_for: 14095, buy_subscription: 13565, change_card: 13564, choose_subscription: 13563, + error_not_enough_balance: 14098, for_month: 13561, for_year: 13562, + payment: 14096, + payment_confirmation: 14094, per_month: 13573, per_year: 13574, + subscription_done: 2668, + success_subscription: 14097, } export const indexLexics = { diff --git a/src/features/BuyMatchPopup/components/ConfirmationStep/index.tsx b/src/features/BuyMatchPopup/components/ConfirmationStep/index.tsx new file mode 100644 index 00000000..a5a3af39 --- /dev/null +++ b/src/features/BuyMatchPopup/components/ConfirmationStep/index.tsx @@ -0,0 +1,48 @@ +import { currencySymbols } from 'config' + +import { T9n } from 'features/T9n' +import { + CloseButton, + Header, + HeaderActions, + HeaderTitle, +} from 'features/PopupComponents' + +import { useBuyMatchPopupStore } from '../../store' +import { SubscriptionsList } from '../SubscriptionsList' +import { + Wrapper, + Footer, + Button, + Body, +} from '../../styled' + +export const ConfirmationStep = () => { + const { + close, + selectedSubscriptions, + subscribeToMatches, + totalPrice, + } = useBuyMatchPopupStore() + + return ( + +
+ + + + + + +
+ + + + +
+ ) +} diff --git a/src/features/BuyMatchPopup/components/ErrorStep/index.tsx b/src/features/BuyMatchPopup/components/ErrorStep/index.tsx new file mode 100644 index 00000000..f759c7ff --- /dev/null +++ b/src/features/BuyMatchPopup/components/ErrorStep/index.tsx @@ -0,0 +1,34 @@ +import { T9n } from 'features/T9n' +import { + Header, + HeaderTitle, + HeaderActions, + CloseButton, +} from 'features/PopupComponents' + +import { useBuyMatchPopupStore } from '../../store' +import { + Wrapper, + Body, + ResultText, +} from '../../styled' + +export const ErrorStep = () => { + const { close } = useBuyMatchPopupStore() + + return ( + +
+ + + + + + +
+ + + +
+ ) +} diff --git a/src/features/BuyMatchPopup/components/MatchSubscriptions/index.tsx b/src/features/BuyMatchPopup/components/SubscriptionSelectionStep/index.tsx similarity index 59% rename from src/features/BuyMatchPopup/components/MatchSubscriptions/index.tsx rename to src/features/BuyMatchPopup/components/SubscriptionSelectionStep/index.tsx index b8481bd6..efe5a69a 100644 --- a/src/features/BuyMatchPopup/components/MatchSubscriptions/index.tsx +++ b/src/features/BuyMatchPopup/components/SubscriptionSelectionStep/index.tsx @@ -1,11 +1,6 @@ -import styled from 'styled-components/macro' - -import isEmpty from 'lodash/isEmpty' - import { MDASH } from 'config' import { T9n } from 'features/T9n' -import { useBuyMatchPopupStore } from 'features/BuyMatchPopup' import { CloseButton, Header, @@ -15,27 +10,21 @@ import { import { Name } from 'features/Name' import { Steps } from 'features/BuyMatchPopup/types' +import { useBuyMatchPopupStore } from '../../store' import { SelectedCard } from '../SelectedCard' import { Subscriptions } from '../Subscriptions' -import { Button } from '../../styled' - -const Wrapper = styled.div` - width: 870px; - height: 695px; -` - -const Center = styled.div` - width: 100%; - display: flex; - justify-content: center; -` +import { + Wrapper, + Body, + Footer, + Button, +} from '../../styled' -export const MatchSubscriptionsStep = () => { +export const SubscriptionSelectionStep = () => { const { close, goTo, match, - selectedSubscriptions, } = useBuyMatchPopupStore() if (!match) return null @@ -52,16 +41,17 @@ export const MatchSubscriptionsStep = () => { - - -
+ + + + +
-
+ ) } diff --git a/src/features/BuyMatchPopup/components/Subscriptions/index.tsx b/src/features/BuyMatchPopup/components/Subscriptions/index.tsx index e050f5a0..5e37630e 100644 --- a/src/features/BuyMatchPopup/components/Subscriptions/index.tsx +++ b/src/features/BuyMatchPopup/components/Subscriptions/index.tsx @@ -1,9 +1,9 @@ import styled from 'styled-components/macro' import { T9n } from 'features/T9n' -import { useBuyMatchPopupStore } from 'features/BuyMatchPopup' import { PaymentPeriodTabs } from 'features/PaymentPeriodTabs' +import { useBuyMatchPopupStore } from '../../store' import { SubscriptionsList } from '../SubscriptionsList' const Wrapper = styled.div` @@ -22,7 +22,13 @@ const Title = styled.span` ` export const Subscriptions = () => { - const { onPeriodSelect, selectedPeriod } = useBuyMatchPopupStore() + const { + onPeriodSelect, + onSubscriptionSelect, + selectedPeriod, + selectedSubscriptions, + subscriptions, + } = useBuyMatchPopupStore() return ( { <T9n t='choose_subscription' /> - + ) } diff --git a/src/features/BuyMatchPopup/components/SubscriptionsList/index.tsx b/src/features/BuyMatchPopup/components/SubscriptionsList/index.tsx index 6b10e1e3..d365772d 100644 --- a/src/features/BuyMatchPopup/components/SubscriptionsList/index.tsx +++ b/src/features/BuyMatchPopup/components/SubscriptionsList/index.tsx @@ -1,7 +1,7 @@ import map from 'lodash/map' import includes from 'lodash/includes' -import { useBuyMatchPopupStore } from 'features/BuyMatchPopup/store' +import type { MatchSubscriptions, MatchSubscription } from 'requests' import { List, @@ -12,41 +12,39 @@ import { Price, } from './styled' -export const SubscriptionsList = () => { - const { - onSubscriptionSelect, - selectedSubscriptions, - subscriptions, - } = useBuyMatchPopupStore() +type Props = { + height?: number, + onSelect?: (subscription: MatchSubscription) => void, + selectedSubscriptions?: MatchSubscriptions, + subscriptions: MatchSubscriptions, +} - return ( - - { - map(subscriptions, ({ - description, - header, - price, - subscription_id, - type, - }) => ( - onSubscriptionSelect(subscription_id)} - active={includes(selectedSubscriptions, subscription_id)} - > - -
- {header} -
- - {description} - -
+export const SubscriptionsList = ({ + height, + onSelect, + selectedSubscriptions, + subscriptions, +}: Props) => ( + + { + map(subscriptions, (subscription) => ( + onSelect?.(subscription)} + active={includes(selectedSubscriptions, subscription)} + > + +
+ {subscription.header} +
+ + {subscription.description} + +
- -
- )) - } -
- ) -} + +
+ )) + } +
+) diff --git a/src/features/BuyMatchPopup/components/SubscriptionsList/styled.tsx b/src/features/BuyMatchPopup/components/SubscriptionsList/styled.tsx index a4268558..1545f3b6 100644 --- a/src/features/BuyMatchPopup/components/SubscriptionsList/styled.tsx +++ b/src/features/BuyMatchPopup/components/SubscriptionsList/styled.tsx @@ -4,8 +4,14 @@ import { popupScrollbarStyles } from 'features/PopupComponents' import { Price as BasePrice } from 'features/Price' import { PriceAmount, PriceDetails } from 'features/Price/styled' -export const List = styled.ul` - height: 364px; +type ListProps = { + height?: number, + marginTop?: number, +} + +export const List = styled.ul` + max-height: 364px; + height: ${({ height }) => (height ? `${height}px` : 'auto')}; display: flex; flex-direction: column; overflow-y: auto; diff --git a/src/features/BuyMatchPopup/components/SuccessStep/index.tsx b/src/features/BuyMatchPopup/components/SuccessStep/index.tsx new file mode 100644 index 00000000..b7616219 --- /dev/null +++ b/src/features/BuyMatchPopup/components/SuccessStep/index.tsx @@ -0,0 +1,36 @@ +import { T9n } from 'features/T9n' +import { + Header, + HeaderTitle, +} from 'features/PopupComponents' + +import { useBuyMatchPopupStore } from '../../store' +import { + Wrapper, + Body, + Footer, + Button, + ResultText, +} from '../../styled' + +export const SuccessStep = () => { + const { close } = useBuyMatchPopupStore() + + return ( + +
+ + + +
+ + + +
+ +
+
+ ) +} diff --git a/src/features/BuyMatchPopup/index.tsx b/src/features/BuyMatchPopup/index.tsx index ce76de14..db0cff87 100644 --- a/src/features/BuyMatchPopup/index.tsx +++ b/src/features/BuyMatchPopup/index.tsx @@ -1,6 +1,8 @@ -import { useBuyMatchPopupStore } from 'features/BuyMatchPopup' - -import { MatchSubscriptionsStep } from './components/MatchSubscriptions' +import { useBuyMatchPopupStore } from './store' +import { SubscriptionSelectionStep } from './components/SubscriptionSelectionStep' +import { ConfirmationStep } from './components/ConfirmationStep' +import { SuccessStep } from './components/SuccessStep' +import { ErrorStep } from './components/ErrorStep' import { Modal } from './styled' import { Steps } from './types' @@ -9,11 +11,11 @@ export * from './store' const Empty = () => null const components = { - [Steps.Subscriptions]: MatchSubscriptionsStep, + [Steps.Subscriptions]: SubscriptionSelectionStep, [Steps.CardSelection]: Empty, - [Steps.Confirmation]: Empty, - [Steps.Success]: Empty, - [Steps.Error]: Empty, + [Steps.Confirmation]: ConfirmationStep, + [Steps.Success]: SuccessStep, + [Steps.Error]: ErrorStep, } export const BuyMatchPopup = () => { diff --git a/src/features/BuyMatchPopup/store/hooks/index.tsx b/src/features/BuyMatchPopup/store/hooks/index.tsx index abb70811..977e65f6 100644 --- a/src/features/BuyMatchPopup/store/hooks/index.tsx +++ b/src/features/BuyMatchPopup/store/hooks/index.tsx @@ -1,5 +1,9 @@ import type { MouseEvent } from 'react' -import { useCallback, useState } from 'react' +import { + useCallback, + useState, + useEffect, +} from 'react' import last from 'lodash/last' @@ -17,18 +21,10 @@ type MatchData = Pick { const [steps, setSteps] = useState>([]) const [match, setMatch] = useState(null) - const { - onPeriodSelect, - onSubscriptionSelect, - resetSubscriptions, - selectedPeriod, - selectedSubscriptions, - subscriptions, - } = useSubscriptions() const goTo = useCallback( - (e: MouseEvent, step: Steps) => setSteps((state) => { - e.stopPropagation() + (step: Steps, e?: MouseEvent) => setSteps((state) => { + e?.stopPropagation() return [...state, step] }), [], @@ -47,9 +43,25 @@ export const useBuyMatchPopup = () => { const closePopup = () => { setMatch(null) setSteps([]) - resetSubscriptions() } + const { + fetchSubscriptions, + onPeriodSelect, + onSubscriptionSelect, + selectedPeriod, + selectedSubscriptions, + subscribeToMatches, + subscriptions, + totalPrice, + } = useSubscriptions(goTo) + + useEffect(() => { + if (match) { + fetchSubscriptions() + } + }, [match, fetchSubscriptions]) + return { close: closePopup, currentStep: last(steps), @@ -59,9 +71,10 @@ export const useBuyMatchPopup = () => { onPeriodSelect, onSubscriptionSelect, open: openPopup, - resetSubscriptions, selectedPeriod, selectedSubscriptions, + subscribeToMatches, subscriptions, + totalPrice, } } diff --git a/src/features/BuyMatchPopup/store/hooks/useSubscriptions.tsx b/src/features/BuyMatchPopup/store/hooks/useSubscriptions.tsx index b0fa8e95..1b127ac0 100644 --- a/src/features/BuyMatchPopup/store/hooks/useSubscriptions.tsx +++ b/src/features/BuyMatchPopup/store/hooks/useSubscriptions.tsx @@ -1,22 +1,30 @@ +import type { MouseEvent } from 'react' import { useMemo, useState, - useEffect, useCallback, } from 'react' +import sumBy from 'lodash/sumBy' import filter from 'lodash/filter' +import without from 'lodash/without' import includes from 'lodash/includes' -import type { MatchSubscriptions } from 'requests' -import { SubscriptionType, getMatchSubscriptions } from 'requests' +import type { MatchSubscriptions, MatchSubscription } from 'requests' +import { + SubscriptionType, + getMatchSubscriptions, + buyMatchSubscriptions, +} from 'requests' + +import { Steps } from 'features/BuyMatchPopup/types' -export const useSubscriptions = () => { +export const useSubscriptions = (goTo: (step: Steps) => void) => { const [selectedPeriod, setSelectedPeriod] = useState(SubscriptionType.Month) const [subscriptionsList, setSubscriptionsList] = useState([]) - const [selectedSubscriptions, setSelectedSubscriptions] = useState>([]) + const [selectedSubscriptions, setSelectedSubscriptions] = useState([]) - useEffect(() => { + const fetchSubscriptions = useCallback(() => { getMatchSubscriptions().then(setSubscriptionsList) }, []) @@ -25,16 +33,16 @@ export const useSubscriptions = () => { [selectedPeriod, subscriptionsList], ) - const onSubscriptionSelect = (id: number) => { - if (includes(selectedSubscriptions, id)) { - const newSubscriptions = filter( - selectedSubscriptions, - (subscriptionId) => subscriptionId !== id, - ) - setSelectedSubscriptions(newSubscriptions) - } else { - setSelectedSubscriptions([...selectedSubscriptions, id]) - } + const totalPrice = useMemo( + () => sumBy(selectedSubscriptions, (subscription) => subscription.price), + [selectedSubscriptions], + ) + + const onSubscriptionSelect = (selected: MatchSubscription) => { + const newSubscriptions = includes(selectedSubscriptions, selected) + ? without(selectedSubscriptions, selected) + : [...selectedSubscriptions, selected] + setSelectedSubscriptions(newSubscriptions) } const resetSubscriptions = useCallback(() => { @@ -42,12 +50,22 @@ export const useSubscriptions = () => { setSelectedSubscriptions([]) }, []) + const subscribeToMatches = (e: MouseEvent) => { + e.stopPropagation() + buyMatchSubscriptions() + .then(() => goTo(Steps.Success)) + .catch(() => goTo(Steps.Error)) + } + return { + fetchSubscriptions, onPeriodSelect: setSelectedPeriod, onSubscriptionSelect, resetSubscriptions, selectedPeriod, selectedSubscriptions, + subscribeToMatches, subscriptions, + totalPrice, } } diff --git a/src/features/BuyMatchPopup/styled.tsx b/src/features/BuyMatchPopup/styled.tsx index c584600a..19416e6b 100644 --- a/src/features/BuyMatchPopup/styled.tsx +++ b/src/features/BuyMatchPopup/styled.tsx @@ -5,13 +5,14 @@ import { devices } from 'config' import { Modal as BaseModal } from 'features/Modal' import { ModalWindow } from 'features/Modal/styled' import { ButtonSolid } from 'features/Common' +import { T9n } from 'features/T9n' export const Modal = styled(BaseModal)` background-color: rgba(0, 0, 0, 0.7); ${ModalWindow} { min-width: 517px; - min-height: 310px; + min-height: auto; padding: 20px 0; background-color: #3F3F3F; border-radius: 5px; @@ -37,3 +38,43 @@ export const Button = styled(ButtonSolid)` opacity: 0.5; } ` + +type WrapperProps = { + width?: number, +} + +export const Wrapper = styled.div` + width: ${({ width }) => (width ? `${width}px` : '870px')}; +` + +type BodyProps = { + marginBottom?: number, + marginTop?: number, +} + +export const Body = styled.div` + margin-top: ${({ marginTop }) => (marginTop ? `${marginTop}px` : '')}; + margin-bottom: ${({ marginBottom }) => (marginBottom ? `${marginBottom}px` : '')}; +` + +type FooterProps = { + marginTop?: number, +} + +export const Footer = styled.div` + width: 100%; + display: flex; + justify-content: center; + + margin-top: ${({ marginTop }) => (marginTop ? `${marginTop}px` : '')}; + margin-bottom: 15px; +` + +export const ResultText = styled(T9n)` + width: 100%; + display: inline-block; + text-align: center; + font-weight: normal; + font-size: 20px; + line-height: 27px; +` diff --git a/src/features/PaymentPeriodTabs/index.tsx b/src/features/PaymentPeriodTabs/index.tsx index c80a4342..0fc42c0d 100644 --- a/src/features/PaymentPeriodTabs/index.tsx +++ b/src/features/PaymentPeriodTabs/index.tsx @@ -14,9 +14,7 @@ type ItemProps = { active?: boolean, } -export const Item = styled.li.attrs(() => ({ - tabIndex: 0, -}))` +export const Item = styled.li` width: 50%; font-size: 20px; line-height: 42px; diff --git a/src/requests/buyMatchSubscriptions.tsx b/src/requests/buyMatchSubscriptions.tsx new file mode 100644 index 00000000..bea8e952 --- /dev/null +++ b/src/requests/buyMatchSubscriptions.tsx @@ -0,0 +1,18 @@ +import { API_ROOT } from 'config' +import { callApi } from 'helpers' + +export const buyMatchSubscriptions = () => { + const config = { + body: { + _p_c_subscription_plan: 1, + _p_is_scheduled: 0, + }, + } + + callApi({ + config, + url: `${API_ROOT}/account/purchase`, + }) + + return Promise.resolve() +} diff --git a/src/requests/getMatchSubscriptions.tsx b/src/requests/getMatchSubscriptions.tsx index 024495dc..86ae5ad4 100644 --- a/src/requests/getMatchSubscriptions.tsx +++ b/src/requests/getMatchSubscriptions.tsx @@ -6,7 +6,7 @@ export enum SubscriptionType { Year = 'year', } -type MatchSubscription = { +export type MatchSubscription = { description: string, header: string, price: number, diff --git a/src/requests/index.tsx b/src/requests/index.tsx index c4c397b0..19bbc9a3 100644 --- a/src/requests/index.tsx +++ b/src/requests/index.tsx @@ -25,3 +25,4 @@ export * from './getSportActions' export * from './getMatchPlaylists' export * from './getPlayerPlaylists' export * from './getMatchSubscriptions' +export * from './buyMatchSubscriptions'