diff --git a/package-lock.json b/package-lock.json index d9035f4b..8a86c532 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "react-scripts": "^4.0.3", "react-window": "^1.8.6", "react-youtube": "^7.14.0", + "recoil": "^0.7.4", "screenfull": "^5.0.2", "styled-components": "^5.3.3", "workbox-core": "^5.1.4", @@ -17283,6 +17284,11 @@ "uuid": "bin/uuid" } }, + "node_modules/hamt_plus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", + "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -26950,6 +26956,25 @@ "node": ">=8.10.0" } }, + "node_modules/recoil": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.4.tgz", + "integrity": "sha512-sCXvQGMfSprkNU4ZRkJV4B0qFQSURJMgsICqY1952WRlg66NMwYqi6n67vhnhn0qw4zHU1gHXJuMvRDaiRNFZw==", + "dependencies": { + "hamt_plus": "1.0.2" + }, + "peerDependencies": { + "react": ">=16.13.1" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/recompose": { "version": "0.27.1", "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.27.1.tgz", @@ -46540,6 +46565,11 @@ } } }, + "hamt_plus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz", + "integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==" + }, "handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -53976,6 +54006,14 @@ "picomatch": "^2.2.1" } }, + "recoil": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.4.tgz", + "integrity": "sha512-sCXvQGMfSprkNU4ZRkJV4B0qFQSURJMgsICqY1952WRlg66NMwYqi6n67vhnhn0qw4zHU1gHXJuMvRDaiRNFZw==", + "requires": { + "hamt_plus": "1.0.2" + } + }, "recompose": { "version": "0.27.1", "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.27.1.tgz", diff --git a/package.json b/package.json index 39597514..25c39475 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "react-scripts": "^4.0.3", "react-window": "^1.8.6", "react-youtube": "^7.14.0", + "recoil": "^0.7.4", "screenfull": "^5.0.2", "styled-components": "^5.3.3", "workbox-core": "^5.1.4", diff --git a/public/sounds/background_track.mp3 b/public/sounds/background_track.mp3 new file mode 100644 index 00000000..906873b1 Binary files /dev/null and b/public/sounds/background_track.mp3 differ diff --git a/src/config/lexics/highlightsPageLexic.tsx b/src/config/lexics/highlightsPageLexic.tsx index ffad6d06..1c484081 100644 --- a/src/config/lexics/highlightsPageLexic.tsx +++ b/src/config/lexics/highlightsPageLexic.tsx @@ -6,6 +6,7 @@ export const highlightsPageLexic = { highlight_will_be_generated: 18364, matches_highlight: 419, maximal_duration: 18358, + order_and_buy: 18361, player_highlight: 630, price: 18356, purchase_auto_generated: 18363, diff --git a/src/config/procedures.tsx b/src/config/procedures.tsx index 1af4aa1e..b006839c 100644 --- a/src/config/procedures.tsx +++ b/src/config/procedures.tsx @@ -9,8 +9,10 @@ export const PROCEDURES = { get_player_info: 'get_player_info', get_player_matches: 'get_player_matches', get_sport_list: 'get_sport_list', + get_sport_teams: 'get_sport_teams', get_team_info: 'get_team_info', get_team_matches: 'get_team_matches', + get_team_players: 'get_team_players', get_teams: 'get_teams', get_tournament_info: 'get_tournament_info', get_tournament_list: 'get_tournament_list', diff --git a/src/features/AddCardForm/components/Form/hooks/index.tsx b/src/features/AddCardForm/components/Form/hooks/index.tsx index fec42dde..faa23af8 100644 --- a/src/features/AddCardForm/components/Form/hooks/index.tsx +++ b/src/features/AddCardForm/components/Form/hooks/index.tsx @@ -16,6 +16,8 @@ import { useElements, } from '@stripe/react-stripe-js' +import { useRecoilValue } from 'recoil' + import toUpper from 'lodash/toUpper' import { useObjectState } from 'hooks' @@ -23,6 +25,10 @@ import { useObjectState } from 'hooks' import { useCardsStore } from 'features/CardsStore' import { useLexicsStore } from 'features/LexicsStore' +import { dataForPayHighlights } from 'pages/HighlightsPage/storeHighlightsAtoms' + +import { onePayment } from 'requests/onePayment' + import { SelectedCountry, useCountries } from './useCountries' import { isValidAddress, @@ -67,13 +73,21 @@ export const useFormSubmit = ({ onAddSuccess }: Props) => { const stripe = useStripe() const elements = useElements() const { translate } = useLexicsStore() - const { onAddCard, setError: setCardError } = useCardsStore() + const { + onAddCard, + defaultCard, + isHighlightsPage, + setError: setCardError, + } = useCardsStore() const [name, setName] = useState('') const [city, setCity] = useState('') const [address, setAddress] = useState('') const [inputStates, setInputStates] = useObjectState(initialState) const [errorMessage, setErrorMessage] = useState('') const [loader, setLoader] = useState(false) + const dataFormHighlights = useRecoilValue(dataForPayHighlights) + +console.log('inputStates', inputStates) const { countries, @@ -163,6 +177,17 @@ export const useFormSubmit = ({ onAddSuccess }: Props) => { return } + const allInputEmpty = Object.values(inputStates).every((inputValue) => inputValue.empty) + + if (isHighlightsPage && defaultCard && allInputEmpty) { + setErrorMessage('') + onePayment({ + cardId: defaultCard?.id, + item: { ...dataFormHighlights }, + }) + return + } + const fieldError = validateFields({ address, city, diff --git a/src/features/App/AuthenticatedApp.tsx b/src/features/App/AuthenticatedApp.tsx index e796b68d..ccdeaf56 100644 --- a/src/features/App/AuthenticatedApp.tsx +++ b/src/features/App/AuthenticatedApp.tsx @@ -6,6 +6,8 @@ import { Switch, } from 'react-router-dom' +import { RecoilRoot } from 'recoil' + import { indexLexics } from 'config/lexics/indexLexics' import { isProduction } from 'config/env' import { PAGES } from 'config/pages' @@ -75,7 +77,9 @@ export const AuthenticatedApp = () => { - + + + diff --git a/src/features/BuyMatchPopup/index.tsx b/src/features/BuyMatchPopup/index.tsx index 0b9244cd..b0d339d7 100644 --- a/src/features/BuyMatchPopup/index.tsx +++ b/src/features/BuyMatchPopup/index.tsx @@ -32,7 +32,7 @@ export const BuyMatchPopup = () => { return ( diff --git a/src/features/CardsStore/hooks/index.tsx b/src/features/CardsStore/hooks/index.tsx index c82a02bb..70673f78 100644 --- a/src/features/CardsStore/hooks/index.tsx +++ b/src/features/CardsStore/hooks/index.tsx @@ -2,6 +2,7 @@ import { useCallback, useState, useMemo, + useEffect, } from 'react' import find from 'lodash/find' @@ -13,6 +14,7 @@ import { deleteCard } from 'requests/deleteCard' import { setDefaultCard as setDefaultCardRequest } from 'requests/setDefaultCard' import { useRequest, useToggle } from 'hooks' +import { PAGES } from 'config' export const useBankCards = () => { const { @@ -20,6 +22,7 @@ export const useBankCards = () => { toggle: toggleInfoModal, } = useToggle() + const [isHighlightsPage, setIsHighlightsPage] = useState(false) const [error, setError] = useState('') const [cards, setCards] = useState(null) const defaultCard = useMemo( @@ -45,6 +48,14 @@ export const useBankCards = () => { setDefaultCardRequest(cardId).then(fetchCards) } + useEffect(() => { + if (window.location.pathname === PAGES.highlights) { + setIsHighlightsPage(true) + } else { + setIsHighlightsPage(false) + } + }, []) + return { cards, defaultCard, @@ -52,6 +63,7 @@ export const useBankCards = () => { fetchCards, infoModalOpen, isFetching, + isHighlightsPage, onAddCard, onDeleteCard: handleCardDelete, onSetDefaultCard, diff --git a/src/features/Combobox/index.tsx b/src/features/Combobox/index.tsx index da29ce96..39c08961 100644 --- a/src/features/Combobox/index.tsx +++ b/src/features/Combobox/index.tsx @@ -6,7 +6,9 @@ import map from 'lodash/map' import { useLexicsStore } from 'features/LexicsStore' import { PAGES } from 'config' + import { T9n } from 'features/T9n' +import { Icon } from 'features/Icon' import { OutsideClick } from 'features/OutsideClick' import { Column, @@ -15,6 +17,7 @@ import { InputStyled, Label, LabelTitle, + LabelAfter, } from 'features/Common/Input/styled' import { Props, Option } from './types' @@ -22,6 +25,7 @@ import { useCombobox } from './hooks' import { PopOver, ListOption, + WrapperIcon, } from './styled' import { Arrow } from './components/Arrow' @@ -31,7 +35,9 @@ export const Combobox = (props: Props) => { className, disabled, error, + iconName, label, + labelAfter, labelLexic, labelWidth, maxLength, @@ -87,11 +93,15 @@ export const Combobox = (props: Props) => { placeholder={translate(labelLexic || '')} isUserAccountPage={isUserAccountPage} /> + {labelAfter && query && {labelAfter}} - + {iconName ? ( + + + + ) : ( + + )} {isOpen && !isEmpty(options) && ( diff --git a/src/features/Combobox/styled.tsx b/src/features/Combobox/styled.tsx index caabaa03..087eebf5 100644 --- a/src/features/Combobox/styled.tsx +++ b/src/features/Combobox/styled.tsx @@ -49,3 +49,12 @@ export const ListOption = styled.li.attrs(() => ({ color: #fff; } ` +export const WrapperIcon = styled.div` + position: absolute; + right: 22px; + top: 50%; + width: 15px; + height: 15px; + transform: translateY(-50%); + +` diff --git a/src/features/Combobox/types.tsx b/src/features/Combobox/types.tsx index 96c90f6f..c2953ad7 100644 --- a/src/features/Combobox/types.tsx +++ b/src/features/Combobox/types.tsx @@ -1,6 +1,7 @@ import type { InputHTMLAttributes, ChangeEvent, + ReactNode, } from 'react' import type { CustomStyles } from 'features/Common' @@ -19,7 +20,9 @@ export type Props = Pick, ( className?: string, customListStyles?: CustomStyles, error?: string | null, + iconName?: string, label?: string, + labelAfter?: string | ReactNode, labelLexic?: string, labelWidth?: number, maxLength?: number, diff --git a/src/features/Common/Input/index.tsx b/src/features/Common/Input/index.tsx index 443367bb..0d5d07d4 100644 --- a/src/features/Common/Input/index.tsx +++ b/src/features/Common/Input/index.tsx @@ -41,6 +41,7 @@ type Props = { type?: string, value?: string, withError?: boolean, + wrapperHeight?: number, } & WrapperProps export const Input = ({ diff --git a/src/features/Common/Input/styled.tsx b/src/features/Common/Input/styled.tsx index 23b529db..8af4268c 100644 --- a/src/features/Common/Input/styled.tsx +++ b/src/features/Common/Input/styled.tsx @@ -69,6 +69,7 @@ export const LabelTitle = styled.p` ` type InputProps = { + disabled?: boolean, inputWidth?: number, isUserAccountPage?: boolean, } @@ -115,6 +116,7 @@ const inputStyles = css` export const InputStyled = styled.input` ${inputStyles} + opacity: ${({ disabled }) => (disabled ? 0.5 : 1)}; ::placeholder { opacity: 0; } diff --git a/src/features/FormStore/hooks/useFormState.tsx b/src/features/FormStore/hooks/useFormState.tsx index e8511dc1..da293280 100644 --- a/src/features/FormStore/hooks/useFormState.tsx +++ b/src/features/FormStore/hooks/useFormState.tsx @@ -14,6 +14,7 @@ export type FormState = {[formId: string]: FieldState} export const useFormState = (initialState: FormState = {}) => { const [formState, setFormState] = useState(initialState) + const readFormValue = useCallback( (fieldName: string) => formState[fieldName]?.value ?? '', [formState], diff --git a/src/features/ProfileCard/index.tsx b/src/features/ProfileCard/index.tsx index e519df6e..fbd9617a 100644 --- a/src/features/ProfileCard/index.tsx +++ b/src/features/ProfileCard/index.tsx @@ -76,7 +76,15 @@ export const ProfileCard = ({ profile }: ProfileType) => { - setPlayerHighlight(profile)}> + setPlayerHighlight({ + profile: { + ...profile, + id: profileId, + }, + sportType, + })} + > diff --git a/src/features/UserAccount/components/ChangeCardPopup/index.tsx b/src/features/UserAccount/components/ChangeCardPopup/index.tsx index 79a45ce5..564ae87b 100644 --- a/src/features/UserAccount/components/ChangeCardPopup/index.tsx +++ b/src/features/UserAccount/components/ChangeCardPopup/index.tsx @@ -6,13 +6,17 @@ import { CardStep } from 'features/BuyMatchPopup/components/CardStep' import { Modal } from './styled' type Props = { + btnName?: string, changeCardPopupOpen: boolean, setChangeCardPopupOpen: (open: boolean) => void, + title?: string, } export const ChangeCardPopup = ({ + btnName, changeCardPopupOpen, setChangeCardPopupOpen, + title, }: Props) => { const { fetchCards } = useCardsStore() @@ -28,8 +32,8 @@ export const ChangeCardPopup = ({ withCloseButton > ) diff --git a/src/features/UserAccount/styled.tsx b/src/features/UserAccount/styled.tsx index 73a64ff5..552c0bbb 100644 --- a/src/features/UserAccount/styled.tsx +++ b/src/features/UserAccount/styled.tsx @@ -260,7 +260,7 @@ export const InlineButton = styled.button` ` export const ScButtonGetHighlight = styled(ButtonOutline)` - max-width: 130px; + max-width: 200px; max-height: 50px; margin: 15px 0; border: 1px solid #FFFFFF; diff --git a/src/features/UserFavorites/hooks/index.tsx b/src/features/UserFavorites/hooks/index.tsx index fe99a0ee..b997b87e 100644 --- a/src/features/UserFavorites/hooks/index.tsx +++ b/src/features/UserFavorites/hooks/index.tsx @@ -10,11 +10,15 @@ import { modifyUserFavorites, getUserFavorites } from 'requests' import { useToggle } from 'hooks/useToggle' import { ProfileTypes } from 'config' -type ProfileType = ObjectWithName & { - additionalInfo: ObjectWithName & { +type ProfileType = { + profile: ObjectWithName & { + additionalInfo: ObjectWithName & { + id: number, + tournamentId?: number, + }, id: number, - tournamentId?: number, }, + sportType: number, } type Args = Parameters[0] diff --git a/src/libs/index.ts b/src/libs/index.ts index e96e828f..4bfcf4f7 100644 --- a/src/libs/index.ts +++ b/src/libs/index.ts @@ -8,6 +8,7 @@ export { Hockey } from './objects/Hockey' export { Handball } from './objects/Handball' export { Volleyball } from './objects/Volleyball' export { Search } from './objects/Search' +export { Sound } from './objects/Sound' export { Star } from './objects/Star' export { Dollar } from './objects/Dollar' export { Close } from './objects/Close' diff --git a/src/libs/objects/Sound.tsx b/src/libs/objects/Sound.tsx new file mode 100644 index 00000000..6fe1928d --- /dev/null +++ b/src/libs/objects/Sound.tsx @@ -0,0 +1,17 @@ +export const Sound = () => ( + + + +) diff --git a/src/pages/HighlightsPage/components/FormHighlights/hooks.tsx b/src/pages/HighlightsPage/components/FormHighlights/hooks.tsx index 7e5d5206..5f93492d 100644 --- a/src/pages/HighlightsPage/components/FormHighlights/hooks.tsx +++ b/src/pages/HighlightsPage/components/FormHighlights/hooks.tsx @@ -1,18 +1,293 @@ -import { useEffect, useState } from 'react' +import { + ChangeEvent, + FormEvent, + useEffect, + useRef, + useState, + useMemo, +} from 'react' + +import debounce from 'lodash/debounce' + +import { useRecoilState } from 'recoil' + +import { useUserFavoritesStore } from 'features/UserFavorites/store' + import { getSportList } from 'requests/getSportList' +import { + getSportTeams, + Team, + SportTeamsType, +} from 'requests/getSportTeams' +import { getPlayerMatches } from 'requests/getMatches/getPlayerMatches' +import { getTeamPlayers, Player } from 'requests/getTeamPlayers' + +import { playerMatchesState, dataForPayHighlights } from '../../storeHighlightsAtoms' + +export type SportType = { + id: number, + lexic: string, + name: string, + name_eng: string, + name_rus?: string, +} + +type SportTypeName = SportType& { + name: string, +} + +type PlayerType = Player & { + name: string, +} + +type TeamType = Team & { + name: string, +} + +type FormType = { + duration: string, + playerValue: string, + players: Array, + selectedPlayer: PlayerType | null, + selectedSound: any, + selectedTeam: Team | null, + sport: SportTypeName, + stats: { + id: number, + name: string, + }, + teamValue: string, +} + +const sounds = [ + { + id: 0, + name: 'No', + }, + { + id: 1, + name: 'Sound 1', + }, + { + id: 2, + name: 'Sound 2', + }, + { + id: 3, + name: 'Sound 3', + }, +] + +const summaryStats = [ + { + id: 0, + name: 'No', + }, + { + id: 1, + name: 'Yes', + }, +] export const useHighlightsForm = () => { - const [sports, setSports] = useState() - const players: any = [] + const { playerHighlight } = useUserFavoritesStore() + + const [sports, setSports] = useState>([]) + const [teams, setTeams] = useState>([]) + const [playersData, setPlayersData] = useState>([]) + const [players, setPlayers] = useState>([]) + const [formState, setFormState] = useState({} as FormType) + const [playerMatches, setPlayerMatches] = useRecoilState(playerMatchesState) + const [dataHighlights, setDatahighlights] = useRecoilState(dataForPayHighlights) + + const formRef = useRef(null) + + const onSportSelect = (selectedSport: SportTypeName | null) => { + if (selectedSport) { + setFormState((state) => ({ + ...state, + playerValue: '', + selectedPlayer: null, + selectedTeam: null, + sport: selectedSport, + teamValue: '', + })) + setTeams([]) + setPlayers([]) + } + } + + const onTeamSelect = (selectedTeam: TeamType | null) => { + if (selectedTeam) { + setFormState((state) => ({ + ...state, + selectedTeam, + })) + } + } + + const onPlayerSelect = (selectedPlayer: PlayerType | null) => { + if (!selectedPlayer) return + setFormState((state) => ({ + ...state, + selectedPlayer, + })) + } + + const onSoundSelect = (selectedSound: any) => { + if (!selectedSound) return + setFormState((state) => ({ + ...state, + selectedSound, + })) + } + + const onStatsSelect = (stats: any) => { + if (!stats) return + setFormState((state) => ({ + ...state, + stats, + })) + } + + const onChangeMaxDuration = (e: ChangeEvent) => { + if ((Number(e.target.value) > 0 && Number(e.target.value) <= 100) || e.target.value === '') { + setFormState((state) => ({ + ...state, + duration: e.target.value, + })) + } + } + + const onChangeSummary = (e: ChangeEvent) => { + const regex = /[0-5]/.test(e.target.value) + if ((regex && e.target.value.length <= 1) || e.target.value === '') { + setFormState((state) => ({ + ...state, + summaryDuration: e.target.value, + })) + } + } + + const onChangeTeam = (e: ChangeEvent) => { + setFormState((state: FormType) => ({ + ...state, + selectedTeam: null, + teamValue: e?.target?.value, + })) + } + + const onChangePlayer = (e: ChangeEvent) => { + setFormState((state: FormType) => ({ + ...state, + playerValue: e?.target?.value, + selectedPlayer: null, + })) + setPlayers( + playersData?.filter( + (player: PlayerType) => player + && player.name + ?.toLowerCase() + .indexOf(e?.target?.value.toLowerCase()) >= 0, + ), + ) + } + + const handleSubmit = (e: FormEvent) => { + e.preventDefault() + } - console.log('sports', sports) useEffect(() => { - getSportList().then(setSports) - // getTeams().then(teams) + getSportList().then((state: any) => setSports( + state?.map((sport: SportType) => ({ + ...sport, + name: sport?.name_eng, + })), + )) }, []) + + useEffect(() => { + if (playerHighlight?.sportType) { + setFormState((prevState: any) => ({ + ...prevState, + sport: sports?.find((sportType) => sportType.id === playerHighlight.sportType), + teams: teams?.find(({ id }) => id === playerHighlight.profile.additionalInfo.id), + })) + } + }, [sports, playerHighlight, teams]) + + const fetchTeams = useMemo( + () => debounce(() => getSportTeams(formState?.sport?.id, -1, formState.teamValue).then( + ({ data }: SportTeamsType) => setTeams( + data?.map((team: Team) => ({ + ...team, + name: team.name_eng, + })), + ), + ), 300), + [formState.teamValue], + ) + + useEffect(() => { + if (formState?.teamValue?.length >= 3 && formState?.sport) { + fetchTeams() + } + }, [formState.teamValue, formState?.sport, playerHighlight]) + + useEffect(() => { + if (formState?.selectedPlayer?.id) { + setDatahighlights({ + duration: Number(formState?.duration), + lang: 'en', + matches: playerMatches?.map((match) => match.id), + player_id: formState?.selectedPlayer?.id, + sport_id: formState?.sport.id, + stats: Boolean(formState?.stats?.id), + }) + } + }, [formState, playerMatches]) + + useEffect(() => { + formState?.selectedTeam + && getTeamPlayers(formState?.sport?.id, formState?.selectedTeam?.id) + .then((state: any) => setPlayersData(state?.map((player: PlayerType) => ({ + ...player, + name: `${player?.firstname_eng} ${player?.lastname_eng}`, + })))) + }, [formState?.selectedTeam, playerHighlight]) + + useEffect(() => { + if (!formState?.selectedPlayer) return + + formState?.selectedPlayer + && getPlayerMatches({ + limit: 1000, + offset: 0, + playerId: formState?.selectedPlayer?.id, + sportType: formState?.sport?.id, + }) + .then(({ broadcast }) => setPlayerMatches( + broadcast.map((match: any) => ({ ...match, isChecked: false })), + )) + }, [formState?.selectedPlayer, formState?.selectedTeam]) + return { + formRef, + formState, + handleSubmit, + onChangeMaxDuration, + onChangePlayer, + onChangeTeam, + onPlayerSelect, + onSoundSelect, + onSportSelect, + onStatsSelect, + onTeamSelect, + playerMatches, players, + sounds, sports, - // teams, + summaryStats, + teams, } } diff --git a/src/pages/HighlightsPage/components/FormHighlights/index.tsx b/src/pages/HighlightsPage/components/FormHighlights/index.tsx index 406e349f..631246a2 100644 --- a/src/pages/HighlightsPage/components/FormHighlights/index.tsx +++ b/src/pages/HighlightsPage/components/FormHighlights/index.tsx @@ -1,9 +1,11 @@ import { Combobox } from 'features/Combobox' import { Input } from 'features/Common' import { T9n } from 'features/T9n' -import { useUserFavoritesStore } from 'features/UserFavorites/store' +import { Icon } from 'features/Icon' -import { useHighlightsForm } from './hooks' +import { + useHighlightsForm, +} from './hooks' import { ScWrapper, @@ -18,8 +20,33 @@ const labelWidth = 180 const wrapperHeight = 50 export const FormHighlights = () => { - const { sports } = useHighlightsForm() - const { playerHighlight } = useUserFavoritesStore() + const { + formRef, + formState: { + duration, + playerValue, + selectedPlayer, + selectedSound, + selectedTeam, + sport, + stats, + teamValue, + }, + handleSubmit, + onChangeMaxDuration, + onChangePlayer, + onChangeTeam, + onPlayerSelect, + onSoundSelect, + onSportSelect, + onStatsSelect, + onTeamSelect, + players, + sounds, + sports, + summaryStats, + teams, + } = useHighlightsForm() return ( @@ -35,74 +62,88 @@ export const FormHighlights = () => { /> - + console.log(123)} + value={sport?.name_eng || ''} + onSelect={onSportSelect} options={sports} maxLength={500} withError={false} wrapperHeight={wrapperHeight} /> - console.log('lkdsmfkl')} - iconName='Search' + value={selectedTeam?.name_eng || teamValue || ''} + onSelect={onTeamSelect} + onChange={onChangeTeam} + options={teams} maxLength={500} withError={false} wrapperHeight={wrapperHeight} + iconName='Search' + className='FormHighlights__select__teams' /> - console.log('lkdsmfkl')} - iconName='Search' + value={selectedPlayer?.name || playerValue || ''} + onSelect={onPlayerSelect} + onChange={onChangePlayer} + options={players} maxLength={500} withError={false} wrapperHeight={wrapperHeight} + iconName='Search' + className='FormHighlights__select__players' /> console.log('lkdsmfkl')} + onChange={onChangeMaxDuration} maxLength={500} withError={false} wrapperHeight={wrapperHeight} - // pattern={'1'} labelAfter='min' + className='FormHighlights__input__duration' /> console.log(123)} - options={[]} + value={selectedSound?.name || ''} + onSelect={onSoundSelect} + options={sounds} maxLength={500} withError={false} wrapperHeight={wrapperHeight} + labelAfter={} + className='FormHighlights__input__sound' /> console.log(123)} - options={[]} + value={stats?.name || ''} + onSelect={onStatsSelect} + options={summaryStats} maxLength={500} withError={false} wrapperHeight={wrapperHeight} diff --git a/src/pages/HighlightsPage/components/FormHighlights/styled.tsx b/src/pages/HighlightsPage/components/FormHighlights/styled.tsx index 66a3e0db..f919e127 100644 --- a/src/pages/HighlightsPage/components/FormHighlights/styled.tsx +++ b/src/pages/HighlightsPage/components/FormHighlights/styled.tsx @@ -7,7 +7,7 @@ export const ScWrapper = styled.div` display: flex; flex-direction: column; color: #FFFFFF; - padding: 0 40px; + padding: 0 80px 0 40px; ` export const ScInfoBlock = styled.div` display: flex; @@ -44,4 +44,23 @@ export const ScForm = styled.form` ? css` ` : ''}; + + .FormHighlights__input__duration { + & input { + max-width: 40px; + } + } + + .FormHighlights__input__sound { + & input { + max-width: 100px; + } + } + + .FormHighlights__select__teams, + .FormHighlights__select__players { + & ul { + max-height: 200px; + } + } ` diff --git a/src/pages/HighlightsPage/components/MatchesHighlights/hooks.tsx b/src/pages/HighlightsPage/components/MatchesHighlights/hooks.tsx new file mode 100644 index 00000000..7bf3cb90 --- /dev/null +++ b/src/pages/HighlightsPage/components/MatchesHighlights/hooks.tsx @@ -0,0 +1,21 @@ +import { ChangeEvent } from 'react' + +import { useRecoilState } from 'recoil' + +import { playerMatchesState } from '../../storeHighlightsAtoms' + +export const useHighlighMatches = () => { + const [playerMatches, setPlayerMatches] = useRecoilState(playerMatchesState) + + const onChangeSelectedMatches = ({ target }: ChangeEvent) => setPlayerMatches( + (prev) => prev.map( + (match) => (Number(match.id) === Number(target.id) + ? { ...match, isChecked: !match.isChecked } : match), + ), + ) + + return { + onChangeSelectedMatches, + playerMatches, + } +} diff --git a/src/pages/HighlightsPage/components/MatchesHighlights/index.tsx b/src/pages/HighlightsPage/components/MatchesHighlights/index.tsx new file mode 100644 index 00000000..aef37351 --- /dev/null +++ b/src/pages/HighlightsPage/components/MatchesHighlights/index.tsx @@ -0,0 +1,80 @@ +import { T9n } from 'features/T9n' +import { Checkbox } from 'features/Common/Checkbox' +import { ArrowLoader } from 'features/ArrowLoader' +import { SportIcon } from 'features/SportIcon' + +import { useHighlighMatches } from './hooks' + +import { + ScTitle, + ScMatchesWrapper, + ScMatchesList, + ScLabel, + ScDate, + ScTournament, + ScTournamentName, + ScCountryFlag, + ScFakeDate, + ScFakeTournamentName, + ScFakeTournament, + ScFakeCheckbox, + ScFakeWrapper, + ScLoaderWrapper, +} from './styled' + +export const MatchesHighlights = ({ matches }: any) => { + const { onChangeSelectedMatches, playerMatches } = useHighlighMatches() + + return ( + + + + + + {playerMatches.length ? (playerMatches?.map(({ + country_id, + date, + id, + isChecked, + sport, + team1, + team2, + tournament, + }: any) => ( + + + {date} +   + {team1.name_eng} - {team2.name_eng} + + + + {tournament.name_eng} + + + )} + /> + ))) : (Array.from(Array(12)).map(() => ( + + + + + + + + )))} + {/* + + */} + + + ) +} diff --git a/src/pages/HighlightsPage/components/MatchesHighlights/styled.tsx b/src/pages/HighlightsPage/components/MatchesHighlights/styled.tsx new file mode 100644 index 00000000..2e6bfaad --- /dev/null +++ b/src/pages/HighlightsPage/components/MatchesHighlights/styled.tsx @@ -0,0 +1,108 @@ +import styled, { css } from 'styled-components/macro' +import { isMobileDevice } from 'config/userAgent' + +import { customScrollbar } from 'features/Common' + +export const ScMatchesWrapper = styled.div` + display: flex; + flex-direction: column; + color: white; + min-width: 360px; +` + +export const ScTitle = styled.span` + font-weight: 700; + font-size: 34px; + line-height: 40px; + margin-bottom: 75px; +` + +export const ScMatchesList = styled.div` + max-height: 500px; + overflow-y: auto; + position: relative; + + ${customScrollbar} +` + +export const ScLabel = styled.div` + font-weight: 600; + font-size: 14px; + line-height: 20px; + margin-bottom: 16px; +` + +export const ScDate = styled.span` + font-weight: 400; +` + +export const ScTournament = styled.div` + color: rgba(255, 255, 255, 0.7); + font-size: 10px; + font-weight: 400; + display: flex; + align-items: center; + height: 16px; +` + +export const ScTournamentName = styled.span` + margin-left: 5px; +` + +export const ScCountryFlag = styled.img` + width: 0.71rem; + height: 0.75rem; + margin-left: 0.567rem; + object-fit: contain; + object-position: bottom; + ${isMobileDevice + ? css` + width: 12px; + height: 8px; + margin-left: 3.5px; + ` + : ''}; +` + +export const ScFakeDate = styled.div` + background: #4E4E4E; + border-radius: 4px; + width: 218px; + height: 10px; + margin-bottom: 7px; +` + +export const ScFakeTournamentName = styled.div` + background: rgba(78, 78, 78, 0.6); + border-radius: 4px; + width: 92px; + height: 10px; +` + +export const ScFakeTournament = styled.div` + display: flex; + flex-direction: column; +` + +export const ScFakeCheckbox = styled.div` + width: 20px; + height: 20px; + + background: #4E4E4E; + border-radius: 4px; + margin-right: 20px; +` + +export const ScFakeWrapper = styled.div` + display: flex; + flex-direction: row; + align-items: center; + margin-bottom: 14px; +` + +export const ScLoaderWrapper = styled.div` + position: absolute; + left: 30%; + top: 50%; + z-index: 1; +` diff --git a/src/pages/HighlightsPage/components/PriceInfo/index.tsx b/src/pages/HighlightsPage/components/PriceInfo/index.tsx index c0f52823..ce87a13d 100644 --- a/src/pages/HighlightsPage/components/PriceInfo/index.tsx +++ b/src/pages/HighlightsPage/components/PriceInfo/index.tsx @@ -1,5 +1,3 @@ -import { ReactNode } from 'react' - import { T9n } from 'features/T9n' import { @@ -11,19 +9,16 @@ import { } from './styled' type PriceInfoType = { - currency?: number, - price?: number, + price: number, } -export const PriceInfo = ({ currency, price }: PriceInfoType) => ( +export const PriceInfo = ({ price }: PriceInfoType) => ( - - {currency || '$'} - + $ {price} diff --git a/src/pages/HighlightsPage/components/PriceInfo/styled.tsx b/src/pages/HighlightsPage/components/PriceInfo/styled.tsx index cd657591..9aa77c08 100644 --- a/src/pages/HighlightsPage/components/PriceInfo/styled.tsx +++ b/src/pages/HighlightsPage/components/PriceInfo/styled.tsx @@ -1,7 +1,6 @@ import styled, { css } from 'styled-components/macro' export const ScPriceInfo = styled.div` - width: 188px; height: 186px; border: 1px solid #FFFFFF; border-radius: 34px; diff --git a/src/pages/HighlightsPage/index.tsx b/src/pages/HighlightsPage/index.tsx index f62785ef..00210f7e 100644 --- a/src/pages/HighlightsPage/index.tsx +++ b/src/pages/HighlightsPage/index.tsx @@ -1,27 +1,67 @@ +import { Link } from 'react-router-dom' + +import { PAGES } from 'config' + +import { useRecoilValue, useRecoilState } from 'recoil' + +import { T9n } from 'features/T9n' +import { CompanyInfo } from 'features/CompanyInfo' +import { ChangeCardPopup } from 'features/UserAccount/components/ChangeCardPopup' +import { MultiSourcePlayer } from 'features/MultiSourcePlayer' + import { PriceInfo } from './components/PriceInfo' import { FormHighlights } from './components/FormHighlights' +import { MatchesHighlights } from './components/MatchesHighlights' + +import { + playerMatchesState, + openPopupChangeCard, +} from './storeHighlightsAtoms' import { ScHeader, ScHeaderLogo, ScWrapper, ScWrapperContent, + ScButton, + ScButtonWrap, } from './styled' const HighlightsPage = () => { - console.log(123) + const playerMatches = useRecoilValue(playerMatchesState) + const [isOpenPopupChangeCard, setIsOpenPopupChangeCard] = useRecoilState(openPopupChangeCard) + const countIsCheckedMatches = playerMatches?.filter( + ({ isChecked }: any) => isChecked, + ).length + + console.log(playerMatches) return ( - + + + - + + + setIsOpenPopupChangeCard(true)}> + + + + + + - ) +) } export default HighlightsPage diff --git a/src/pages/HighlightsPage/storeHighlightsAtoms.tsx b/src/pages/HighlightsPage/storeHighlightsAtoms.tsx new file mode 100644 index 00000000..238bfba7 --- /dev/null +++ b/src/pages/HighlightsPage/storeHighlightsAtoms.tsx @@ -0,0 +1,30 @@ +import { atom } from 'recoil' + +import type { Match } from 'requests' + +export type PlayerMatchesType = Array + +type DataForm = { + duration: number, + lang: string, + matches: Array, + player_id: number, + sport_id: number, + stats: boolean, +} + +export const playerMatchesState = atom({ + default: [] as PlayerMatchesType, + key: 'playerMatchesState', +}) + +export const openPopupChangeCard = atom({ + default: false, + key: 'openPopupChangeCard', +}) + +export const dataForPayHighlights = atom({ + default: {} as DataForm, + key: 'dataForPayHighlights', +}) diff --git a/src/pages/HighlightsPage/styled.tsx b/src/pages/HighlightsPage/styled.tsx index 50e04538..826d85b9 100644 --- a/src/pages/HighlightsPage/styled.tsx +++ b/src/pages/HighlightsPage/styled.tsx @@ -1,6 +1,7 @@ import styled, { css } from 'styled-components/macro' import { Logo } from 'features/Logo' +import { ButtonSolid } from 'features/Common/Button' export const ScHeader = styled.div` width: 100%; @@ -14,7 +15,7 @@ export const ScHeaderLogo = styled(Logo)` export const ScWrapper = styled.div` width: 100%; - height: 100%; + max-height: 100vh; display: flex; flex-direction: column; @@ -23,5 +24,20 @@ export const ScWrapper = styled.div` export const ScWrapperContent = styled.div` display: flex; flex-direction: row; - padding: 100px 170px 0px 170px; + padding: 100px 170px 82px 170px; +` + +export const ScButton = styled(ButtonSolid)` + width: 270px; + height: 50px; + background: #294FC4; + border-radius: 5px; + + opacity: ${({ disabled }) => (disabled ? 0.5 : 1)} +` + +export const ScButtonWrap = styled.div` + display: flex; + justify-content: center; + margin-bottom: 100px; ` diff --git a/src/requests/getSportTeams.tsx b/src/requests/getSportTeams.tsx new file mode 100644 index 00000000..f559cea1 --- /dev/null +++ b/src/requests/getSportTeams.tsx @@ -0,0 +1,52 @@ +import { + DATA_URL, + PROCEDURES, +} from 'config' +import { callApi } from 'helpers' + +const proc = PROCEDURES.get_sport_teams + +export type Team = { + c_country?: number, + c_gender?: number, + c_sport?: number, + c_team_type?: number, + country_en?: string, + country_iso?: string, + country_ru?: string, + dl?: boolean, + id: number, + name_eng: string, + name_national: string, + name_rus: string, + short_name_eng?: string, + short_name_rus?: string, + ts: string, +} + +export type SportTeamsType = { + data: Array, + more: boolean, +} +export const getSportTeams = ( + sport_id: number, + _p_limit: number, + _p_name: string, +) +: Promise => { + const config = { + body: { + params: { + _p_limit, + _p_name, + sport_id, + }, + proc, + }, + } + + return callApi({ + config, + url: DATA_URL, + }) +} diff --git a/src/requests/getTeamPlayers.tsx b/src/requests/getTeamPlayers.tsx new file mode 100644 index 00000000..910d004b --- /dev/null +++ b/src/requests/getTeamPlayers.tsx @@ -0,0 +1,41 @@ +import { + DATA_URL, + PROCEDURES, +} from 'config' +import { callApi } from 'helpers' + +const proc = PROCEDURES.get_team_players + +export type Player = { + birthday: string | null, + c_gender: number, + firstname_eng: string, + firstname_rus: string, + height: string | number, + id: number, + lastname_eng: string, + lastname_rus: string, + nickname_eng: string | number| null, + nickname_rus: string | number | null, + sport_id: number, + weight: string | number | null, +} + +export const getTeamPlayers = (_p_sport_id: number, + _p_team_id: number) +: Promise> => { + const config = { + body: { + params: { + _p_sport_id, + _p_team_id, + }, + proc, + }, + } + + return callApi({ + config, + url: DATA_URL, + }) +} diff --git a/src/requests/onePayment.tsx b/src/requests/onePayment.tsx new file mode 100644 index 00000000..1f5e1685 --- /dev/null +++ b/src/requests/onePayment.tsx @@ -0,0 +1,30 @@ +import { API_ROOT } from 'config' +import { callApi } from 'helpers' + +export type Props = { + cardId: string, + item: { + duration: number, + lang: string, + matches: Array, + player_id: number, + sport_id: number, + stats: boolean, + }, +} + +export const onePayment = async ({ cardId, item }: Props) => { + const config = { + body: { + action: 'one_payment', + card_id: cardId, + item, + service: 'stripe_ott', + }, + } + + return callApi({ + config, + url: `${API_ROOT}/account/payments`, + }) +}