diff --git a/src/config/lexics/homeLexics.tsx b/src/config/lexics/homeLexics.tsx
new file mode 100644
index 00000000..0b408a0c
--- /dev/null
+++ b/src/config/lexics/homeLexics.tsx
@@ -0,0 +1,7 @@
+import { indexLexics } from './indexLexics'
+
+export const homeLexics = {
+ ...indexLexics,
+
+ video_from_my_subscriptions: 13023,
+}
diff --git a/src/config/lexics/authenticated.tsx b/src/config/lexics/indexLexics.tsx
similarity index 89%
rename from src/config/lexics/authenticated.tsx
rename to src/config/lexics/indexLexics.tsx
index db3fd103..3bbbe6e5 100644
--- a/src/config/lexics/authenticated.tsx
+++ b/src/config/lexics/indexLexics.tsx
@@ -1,6 +1,6 @@
import { proceduresLexics } from './procedures'
-export const authenticatedLexics = {
+export const indexLexics = {
basketball: 6960,
football: 6958,
full_game: 13028,
@@ -24,7 +24,6 @@ export const authenticatedLexics = {
team: 658,
tournament: 1009,
user_account: 12928,
- video_from_my_subscriptions: 13023,
watch_from_beginning: 13021,
watch_from_last_pause: 13022,
watch_now: 13020,
diff --git a/src/config/lexics/playerLexics.tsx b/src/config/lexics/playerLexics.tsx
new file mode 100644
index 00000000..eded7648
--- /dev/null
+++ b/src/config/lexics/playerLexics.tsx
@@ -0,0 +1,10 @@
+import { indexLexics } from './indexLexics'
+
+export const playerLexics = {
+ ...indexLexics,
+
+ add_to_favorites: 1701,
+ added_to_favorites: 13048,
+ cm: 817,
+ kg: 652,
+}
diff --git a/src/config/procedures.tsx b/src/config/procedures.tsx
index b81749b8..d213e4be 100644
--- a/src/config/procedures.tsx
+++ b/src/config/procedures.tsx
@@ -3,6 +3,7 @@ export const PROCEDURES = {
create_user: 'create_user',
get_cities: 'get_cities',
get_matches: 'get_matches_tmp',
+ get_player_info: 'get_player_info',
get_players_teams_tournaments: 'get_players_teams_tournaments',
get_sport_list: 'get_sport_list',
get_tournament_list: 'get_tournament_list',
diff --git a/src/features/App/AuthenticatedApp.tsx b/src/features/App/AuthenticatedApp.tsx
index e21520c1..f447453c 100644
--- a/src/features/App/AuthenticatedApp.tsx
+++ b/src/features/App/AuthenticatedApp.tsx
@@ -7,8 +7,6 @@ import {
import { PAGES } from 'config'
-import { authenticatedLexics } from 'config/lexics/authenticated'
-import { useLexicsConfig } from 'features/LexicsStore'
import { HomePage } from 'features/HomePage'
import { TeamPage } from 'features/TeamPage'
import { MatchPage } from 'features/MatchPage'
@@ -18,39 +16,35 @@ import { LanguageSelect } from 'features/LanguageSelect'
import { UserAccount } from 'features/UserAccount'
import { ScoreStore, ToggleScore } from 'features/ToggleScore'
-export const AuthenticatedApp = () => {
- useLexicsConfig(authenticatedLexics)
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
+export const AuthenticatedApp = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+)
diff --git a/src/features/Common/StarIcon/index.tsx b/src/features/Common/StarIcon/index.tsx
new file mode 100644
index 00000000..cdd535d6
--- /dev/null
+++ b/src/features/Common/StarIcon/index.tsx
@@ -0,0 +1,24 @@
+import React from 'react'
+
+type StarProps = {
+ fill: string,
+}
+
+export const StarIcon = ({ fill }: StarProps) => (
+
+)
diff --git a/src/features/Common/index.tsx b/src/features/Common/index.tsx
index 8f8984b6..b54bed51 100644
--- a/src/features/Common/index.tsx
+++ b/src/features/Common/index.tsx
@@ -5,5 +5,6 @@ export * from './Checkbox'
export * from './Arrows'
export * from './CloseButton'
export * from './SportName'
+export * from './StarIcon'
export * from './customScrollbar'
export * from './customStyles'
diff --git a/src/features/HomePage/index.tsx b/src/features/HomePage/index.tsx
index 93a16533..0c8833f6 100644
--- a/src/features/HomePage/index.tsx
+++ b/src/features/HomePage/index.tsx
@@ -1,5 +1,7 @@
import React from 'react'
+import { homeLexics } from 'config/lexics/homeLexics'
+import { useLexicsConfig } from 'features/LexicsStore'
import { Header } from 'features/Header'
import { MainWrapper } from 'features/MainWrapper'
import { Search } from 'features/Search'
@@ -20,32 +22,36 @@ import {
Content,
} from './styled'
-export const HomePage = () => (
-
-
-
-
-
-
-
+export const HomePage = () => {
+ useLexicsConfig(homeLexics)
-
-
-
+ return (
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/features/PlayerPage/hooks.tsx b/src/features/PlayerPage/hooks.tsx
new file mode 100644
index 00000000..5ec36ee5
--- /dev/null
+++ b/src/features/PlayerPage/hooks.tsx
@@ -0,0 +1,44 @@
+import { useEffect, useState } from 'react'
+
+import type { PlayerProfile } from 'requests/getPlayerInfo'
+import { getPlayerInfo } from 'requests/getPlayerInfo'
+import { useSportNameParam, usePageId } from 'hooks'
+import { useLexicsStore } from 'features/LexicsStore'
+
+type Firstname = 'firstname_eng' | 'firstname_rus'
+type Lastname = 'lastname_eng' | 'lastname_rus'
+type Name = 'name_eng' | 'name_rus'
+
+export const usePlayerPage = () => {
+ const [playerProfile, setPlayerProfile] = useState(null)
+ const { sportType } = useSportNameParam()
+ const pageId = usePageId()
+ const { suffix, translate } = useLexicsStore()
+
+ const {
+ club_team,
+ height,
+ weight,
+ [`firstname_${suffix}` as Firstname]: firstName = '',
+ [`lastname_${suffix}` as Lastname]: lastName = '',
+ } = playerProfile || {}
+
+ const fullName = `${firstName} ${lastName}`
+ const teamName = club_team?.[`name_${suffix}` as Name] || ''
+
+ const infoItems = [
+ `${height ? `${height} ${translate('cm')}` : ''}${
+ weight ? `, ${weight} ${translate('kg')}` : ''}`,
+ teamName,
+ ]
+
+ useEffect(() => {
+ getPlayerInfo(pageId, sportType).then(setPlayerProfile)
+ }, [pageId, sportType])
+
+ return {
+ infoItems,
+ name: fullName,
+ sportType,
+ }
+}
diff --git a/src/features/PlayerPage/index.tsx b/src/features/PlayerPage/index.tsx
index aa4f9d17..8ad18e08 100644
--- a/src/features/PlayerPage/index.tsx
+++ b/src/features/PlayerPage/index.tsx
@@ -1,12 +1,39 @@
import React from 'react'
-import styled from 'styled-components'
-const TempPageTitle = styled.span`
- padding: 20px;
- font-size: 20px;
- color: white;
-`
+import { ProfileTypes } from 'config'
+import { playerLexics } from 'config/lexics/playerLexics'
+import { useLexicsConfig } from 'features/LexicsStore'
+import { Header } from 'features/Header'
+import { MainWrapper } from 'features/MainWrapper'
+import { Search } from 'features/Search'
+import { UserFavorites } from 'features/UserFavorites'
+import { ProfileCard } from 'features/ProfileCard'
+import { UserFavoritesStore } from 'features/UserFavorites/store'
-export const PlayerPage = () => (
- PLAYER PAGE
-)
+import { usePlayerPage } from './hooks'
+
+export const PlayerPage = () => {
+ const {
+ infoItems,
+ name,
+ sportType,
+ } = usePlayerPage()
+ useLexicsConfig(playerLexics)
+
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/src/features/ProfileCard/hooks.tsx b/src/features/ProfileCard/hooks.tsx
new file mode 100644
index 00000000..1d3b0ae2
--- /dev/null
+++ b/src/features/ProfileCard/hooks.tsx
@@ -0,0 +1,57 @@
+import type { BaseSyntheticEvent } from 'react'
+import { useCallback } from 'react'
+
+import findIndex from 'lodash/findIndex'
+
+import { handleImageError, getProfileLogo } from 'helpers'
+import { useUserFavoritesStore } from 'features/UserFavorites/store'
+import { usePageId } from 'hooks'
+
+import type { ProfileCardProps } from './types'
+
+export const useProfileCard = ({
+ profileType,
+ sportType,
+}: ProfileCardProps) => {
+ const { addRemoveFavorite, userFavorites } = useUserFavoritesStore()
+ const profileId = usePageId()
+
+ const isFavorite = findIndex(userFavorites, {
+ id: profileId,
+ sport: sportType,
+ type: profileType,
+ }) !== -1
+
+ const logo = getProfileLogo({
+ id: profileId,
+ profileType,
+ sportType,
+ })
+
+ const addToFavorites = useCallback(() => {
+ addRemoveFavorite({
+ action: 1,
+ id: profileId,
+ sport: sportType,
+ type: profileType,
+ })
+ }, [
+ addRemoveFavorite,
+ profileId,
+ profileType,
+ sportType,
+ ])
+
+ const onError = useCallback((e: BaseSyntheticEvent) => handleImageError({
+ e,
+ sport: sportType,
+ type: profileType,
+ }), [profileType, sportType])
+
+ return {
+ addToFavorites,
+ isFavorite,
+ logo,
+ onError,
+ }
+}
diff --git a/src/features/ProfileCard/index.tsx b/src/features/ProfileCard/index.tsx
new file mode 100644
index 00000000..4a645656
--- /dev/null
+++ b/src/features/ProfileCard/index.tsx
@@ -0,0 +1,63 @@
+import React from 'react'
+
+import map from 'lodash/map'
+
+import { T9n } from 'features/T9n'
+import { StarIcon } from 'features/Common'
+
+import type { ProfileCardProps } from './types'
+import {
+ Wrapper,
+ Details,
+ AddToFavButton,
+ Logo,
+ InfoItem,
+ InfoItems,
+ Name,
+ Bottom,
+ InFavorites,
+} from './styled'
+import { useProfileCard } from './hooks'
+
+export const ProfileCard = (props: ProfileCardProps) => {
+ const {
+ infoItems,
+ name,
+ } = props
+
+ const {
+ addToFavorites,
+ isFavorite,
+ logo,
+ onError,
+ } = useProfileCard(props)
+
+ return (
+
+
+
+ {name}
+
+ {isFavorite ? (
+
+
+
+
+ ) : (
+
+
+
+
+ )}
+
+ {map(infoItems, (infoItem) => {infoItem})}
+
+
+
+
+ )
+}
diff --git a/src/features/ProfileCard/styled.tsx b/src/features/ProfileCard/styled.tsx
new file mode 100644
index 00000000..a5ca4e98
--- /dev/null
+++ b/src/features/ProfileCard/styled.tsx
@@ -0,0 +1,75 @@
+import styled from 'styled-components/macro'
+
+export const Wrapper = styled.div`
+ display: flex;
+ max-width: 815px;
+ margin-right: 100px;
+`
+
+export const Name = styled.h1`
+ margin-bottom: 10px;
+ line-height: 40px;
+ font-size: 36px;
+ font-weight: bold;
+ letter-spacing: 0.02em;
+ color: #fff;
+`
+
+export const Logo = styled.img`
+ width: 88px;
+ height: 88px;
+ margin-right: 15px;
+ border-radius: 50%;
+ background-color: #000;
+`
+
+export const Details = styled.div``
+
+export const Bottom = styled.div`
+ display: flex;
+`
+
+export const AddToFavButton = styled.button`
+ display: flex;
+ align-items: center;
+ height: 32px;
+ padding: 0 16px;
+ border-radius: 2px;
+ font-size: 14px;
+ color: #fff;
+ background:
+ linear-gradient(
+ 180deg, rgba(255, 255, 255, 0) 0%,
+ rgba(255, 255, 255, 0.1) 0.01%,
+ rgba(0, 0, 0, 0.1) 99.99%
+ ),
+ #0033CC;
+ box-shadow: 0px 1px 0px rgba(0, 4, 41, 0.3);
+ border-style: none;
+ outline: none;
+ cursor: pointer;
+
+ svg {
+ margin-right: 10px;
+ width: 18px;
+ height: 18px;
+ }
+`
+
+export const InFavorites = styled(AddToFavButton)`
+ color: #EACB6F;
+ border: 1px solid currentColor;
+ background-color: transparent;
+ cursor: default;
+`
+
+export const InfoItems = styled.div`
+ margin-left: 20px;
+`
+
+export const InfoItem = styled.div`
+ line-height: 18px;
+ font-size: 16px;
+ letter-spacing: 0.02em;
+ color: rgba(255, 255, 255, 0.5);
+`
diff --git a/src/features/ProfileCard/types.tsx b/src/features/ProfileCard/types.tsx
new file mode 100644
index 00000000..c2f8786c
--- /dev/null
+++ b/src/features/ProfileCard/types.tsx
@@ -0,0 +1,8 @@
+import { ProfileTypes, SportTypes } from 'config'
+
+export type ProfileCardProps = {
+ infoItems: Array,
+ name: string,
+ profileType: ProfileTypes,
+ sportType: SportTypes,
+}
diff --git a/src/features/Search/hooks/useNormalizedItems.tsx b/src/features/Search/hooks/useNormalizedItems.tsx
index 32a296ff..78bcac4c 100644
--- a/src/features/Search/hooks/useNormalizedItems.tsx
+++ b/src/features/Search/hooks/useNormalizedItems.tsx
@@ -7,6 +7,7 @@ import {
getSportColor,
getSportLexic,
getProfileFallbackLogo,
+ getProfileUrl,
} from 'helpers'
import { useLexicsStore } from 'features/LexicsStore'
@@ -45,7 +46,11 @@ export const useNormalizedItems = (searchItems: SearchItems) => {
id,
logo,
name: `${firstName} ${lastName}`,
- profileUrl: `/players/${id}`,
+ profileUrl: getProfileUrl({
+ id,
+ profileType: ProfileTypes.PLAYERS,
+ sportType,
+ }),
sportLexic,
teamOrCountry: teamName,
}
@@ -76,7 +81,11 @@ export const useNormalizedItems = (searchItems: SearchItems) => {
id,
logo,
name,
- profileUrl: `/teams/${id}`,
+ profileUrl: getProfileUrl({
+ id,
+ profileType: ProfileTypes.TEAMS,
+ sportType,
+ }),
sportLexic,
teamOrCountry: country,
}
@@ -107,7 +116,11 @@ export const useNormalizedItems = (searchItems: SearchItems) => {
id,
logo,
name,
- profileUrl: `/tournaments/${id}`,
+ profileUrl: getProfileUrl({
+ id,
+ profileType: ProfileTypes.TOURNAMENTS,
+ sportType,
+ }),
sportLexic,
teamOrCountry: country,
}
diff --git a/src/features/UserFavorites/index.tsx b/src/features/UserFavorites/index.tsx
index 3a27eacc..68a9ab89 100644
--- a/src/features/UserFavorites/index.tsx
+++ b/src/features/UserFavorites/index.tsx
@@ -4,7 +4,7 @@ import map from 'lodash/map'
import { handleImageError } from 'helpers'
-import { useUserFavorites } from './hooks'
+import { useUserFavoritesStore } from './store'
import { TooltipBlock } from './TooltipBlock'
import {
StyledLink,
@@ -17,7 +17,7 @@ import {
} from './styled'
export const UserFavorites = () => {
- const { addRemoveFavorite, userFavorites } = useUserFavorites()
+ const { addRemoveFavorite, userFavorites } = useUserFavoritesStore()
return (
diff --git a/src/features/UserFavorites/store/index.tsx b/src/features/UserFavorites/store/index.tsx
new file mode 100644
index 00000000..28c2a70c
--- /dev/null
+++ b/src/features/UserFavorites/store/index.tsx
@@ -0,0 +1,27 @@
+import type { ReactNode } from 'react'
+import React, {
+ useContext,
+ createContext,
+} from 'react'
+
+import { useUserFavorites } from '../hooks'
+
+export * from '../hooks'
+
+type UserFavoritesStore = ReturnType
+
+const UserFavoritesContext = createContext({} as UserFavoritesStore)
+
+type Props = { children: ReactNode }
+
+export const UserFavoritesStore = ({ children }: Props) => {
+ const userFavoritesStore = useUserFavorites()
+
+ return (
+
+ {children}
+
+ )
+}
+
+export const useUserFavoritesStore = () => useContext(UserFavoritesContext)
diff --git a/src/helpers/getProfileUrl/index.tsx b/src/helpers/getProfileUrl/index.tsx
index 3f8e282b..7b1a2209 100644
--- a/src/helpers/getProfileUrl/index.tsx
+++ b/src/helpers/getProfileUrl/index.tsx
@@ -16,5 +16,5 @@ export const getProfileUrl = ({
profileType,
sportType,
}: Args) => (
- `${SPORT_NAMES[sportType]}/${PROFILE_NAMES[profileType]}/${id}`
+ `/${SPORT_NAMES[sportType]}/${PROFILE_NAMES[profileType]}/${id}`
)
diff --git a/src/hooks/index.tsx b/src/hooks/index.tsx
index 44597d75..95d70492 100644
--- a/src/hooks/index.tsx
+++ b/src/hooks/index.tsx
@@ -1,2 +1,4 @@
export * from './usePageId'
export * from './useToggle'
+export * from './useRequest'
+export * from './useSportNameParam'
diff --git a/src/hooks/useSportNameParam.tsx b/src/hooks/useSportNameParam.tsx
new file mode 100644
index 00000000..f13f35fe
--- /dev/null
+++ b/src/hooks/useSportNameParam.tsx
@@ -0,0 +1,16 @@
+import { useParams } from 'react-router'
+
+import toUpper from 'lodash/toUpper'
+
+import { SportTypes } from 'config'
+
+type SportName = 'FOOTBALL' | 'HOCKEY' | 'BASKETBALL'
+
+export const useSportNameParam = () => {
+ const { sportName } = useParams<{ sportName: string }>()
+
+ return {
+ sportName,
+ sportType: SportTypes[toUpper(sportName) as SportName],
+ }
+}
diff --git a/src/requests/getPlayerInfo.tsx b/src/requests/getPlayerInfo.tsx
new file mode 100644
index 00000000..1a72c3ce
--- /dev/null
+++ b/src/requests/getPlayerInfo.tsx
@@ -0,0 +1,48 @@
+import {
+ DATA_URL,
+ PROCEDURES,
+ SportTypes,
+} from 'config'
+import { callApi, getResponseData } from 'helpers'
+
+const proc = PROCEDURES.get_player_info
+
+export type PlayerProfile = {
+ c_gender: 1 | 2 | null,
+ club_team: {
+ id: number,
+ name_eng: string,
+ name_rus: string,
+ } | null,
+ firstname_eng: string,
+ firstname_rus: string,
+ height: number | null,
+ id: number,
+ is_favorite: boolean,
+ is_gk: boolean | null,
+ lastname_eng: string,
+ lastname_rus: string,
+ nickname_eng: string | null,
+ nickname_rus: string | null,
+ weight: number | null,
+} | null
+
+export const getPlayerInfo = (
+ playerId: number,
+ sportType: SportTypes,
+): Promise => {
+ const config = {
+ body: {
+ params: {
+ _p_player_id: playerId,
+ _p_sport: sportType,
+ },
+ proc,
+ },
+ }
+
+ return callApi({
+ config,
+ url: DATA_URL,
+ }).then(getResponseData(proc))
+}