feat(ott-191): player page header (#76)

keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
Ruslan Khayrullin 5 years ago committed by GitHub
parent 3e90223c5d
commit 22d93b845c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      src/config/lexics/homeLexics.tsx
  2. 3
      src/config/lexics/indexLexics.tsx
  3. 10
      src/config/lexics/playerLexics.tsx
  4. 1
      src/config/procedures.tsx
  5. 70
      src/features/App/AuthenticatedApp.tsx
  6. 24
      src/features/Common/StarIcon/index.tsx
  7. 1
      src/features/Common/index.tsx
  8. 58
      src/features/HomePage/index.tsx
  9. 44
      src/features/PlayerPage/hooks.tsx
  10. 45
      src/features/PlayerPage/index.tsx
  11. 57
      src/features/ProfileCard/hooks.tsx
  12. 63
      src/features/ProfileCard/index.tsx
  13. 75
      src/features/ProfileCard/styled.tsx
  14. 8
      src/features/ProfileCard/types.tsx
  15. 19
      src/features/Search/hooks/useNormalizedItems.tsx
  16. 4
      src/features/UserFavorites/index.tsx
  17. 27
      src/features/UserFavorites/store/index.tsx
  18. 2
      src/helpers/getProfileUrl/index.tsx
  19. 2
      src/hooks/index.tsx
  20. 16
      src/hooks/useSportNameParam.tsx
  21. 48
      src/requests/getPlayerInfo.tsx

@ -0,0 +1,7 @@
import { indexLexics } from './indexLexics'
export const homeLexics = {
...indexLexics,
video_from_my_subscriptions: 13023,
}

@ -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,

@ -0,0 +1,10 @@
import { indexLexics } from './indexLexics'
export const playerLexics = {
...indexLexics,
add_to_favorites: 1701,
added_to_favorites: 13048,
cm: 817,
kg: 652,
}

@ -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',

@ -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 (
<ScoreStore>
<ToggleScore />
<LanguageSelect />
<Switch>
<Route exact path={PAGES.home}>
<HomePage />
</Route>
<Route path={`${PAGES.tournament}/:pageId`}>
<TournamentPage />
</Route>
<Route path={`${PAGES.team}/:pageId`}>
<TeamPage />
</Route>
<Route path={`${PAGES.player}/:pageId`}>
<PlayerPage />
</Route>
<Route path={`${PAGES.match}/:pageId`}>
<MatchPage />
</Route>
<Route path={PAGES.useraccount}>
<UserAccount />
</Route>
<Redirect to={PAGES.home} />
</Switch>
</ScoreStore>
)
}
export const AuthenticatedApp = () => (
<ScoreStore>
<ToggleScore />
<LanguageSelect />
<Switch>
<Route exact path={PAGES.home}>
<HomePage />
</Route>
<Route path={`/:sportName${PAGES.tournament}/:pageId`}>
<TournamentPage />
</Route>
<Route path={`/:sportName${PAGES.team}/:pageId`}>
<TeamPage />
</Route>
<Route path={`/:sportName${PAGES.player}/:pageId`}>
<PlayerPage />
</Route>
<Route path={`/:sportName${PAGES.match}/:pageId`}>
<MatchPage />
</Route>
<Route path={PAGES.useraccount}>
<UserAccount />
</Route>
<Redirect to={PAGES.home} />
</Switch>
</ScoreStore>
)

@ -0,0 +1,24 @@
import React from 'react'
type StarProps = {
fill: string,
}
export const StarIcon = ({ fill }: StarProps) => (
<svg width='20' height='19' viewBox='0 0 20 19' xmlns='http://www.w3.org/2000/svg'>
<g filter='url(#filter0_d)'>
<path d='M10 0L12.5814 5.44704L18.5595 6.21885L14.1767 10.3571L15.2901 16.2812L10 13.3917L4.70993 16.2812L5.82325 10.3571L1.44049 6.21885L7.41863 5.44704L10 0Z' fill={fill} />
</g>
<defs>
<filter id='filter0_d' x='0.44043' y='0' width='19.119' height='18.2812' filterUnits='userSpaceOnUse' colorInterpolationFilters='sRGB'>
<feFlood floodOpacity='0' result='BackgroundImageFix' />
<feColorMatrix in='SourceAlpha' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0' />
<feOffset dy='1' />
<feGaussianBlur stdDeviation='0.5' />
<feColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0' />
<feBlend mode='normal' in2='BackgroundImageFix' result='effect1_dropShadow' />
<feBlend mode='normal' in='SourceGraphic' in2='effect1_dropShadow' result='shape' />
</filter>
</defs>
</svg>
)

@ -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'

@ -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 = () => (
<HeaderFiltersStore>
<MainWrapper>
<UserFavorites />
<Header>
<FilterWrapper>
<Search />
</FilterWrapper>
export const HomePage = () => {
useLexicsConfig(homeLexics)
<FilterWrapper>
<DateFilter />
</FilterWrapper>
return (
<HeaderFiltersStore>
<MainWrapper>
<UserFavorites />
<Header>
<FilterWrapper>
<Search />
</FilterWrapper>
<FilterWrapper>
<MatchStatusFilter />
</FilterWrapper>
<FilterWrapper>
<DateFilter />
</FilterWrapper>
<FilterWrapper>
<SportTypeFilter />
<TournamentFilter />
</FilterWrapper>
</Header>
<Content>
<Title><T9n t='video_from_my_subscriptions' /></Title>
<Matches />
</Content>
</MainWrapper>
</HeaderFiltersStore>
)
<FilterWrapper>
<MatchStatusFilter />
</FilterWrapper>
<FilterWrapper>
<SportTypeFilter />
<TournamentFilter />
</FilterWrapper>
</Header>
<Content>
<Title><T9n t='video_from_my_subscriptions' /></Title>
<Matches />
</Content>
</MainWrapper>
</HeaderFiltersStore>
)
}

@ -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<PlayerProfile>(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,
}
}

@ -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 = () => (
<TempPageTitle>PLAYER PAGE</TempPageTitle>
)
import { usePlayerPage } from './hooks'
export const PlayerPage = () => {
const {
infoItems,
name,
sportType,
} = usePlayerPage()
useLexicsConfig(playerLexics)
return (
<UserFavoritesStore>
<MainWrapper>
<UserFavorites />
<Header>
<ProfileCard
sportType={sportType}
profileType={ProfileTypes.PLAYERS}
name={name}
infoItems={infoItems}
/>
<Search />
</Header>
</MainWrapper>
</UserFavoritesStore>
)
}

@ -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,
}
}

@ -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 (
<Wrapper>
<Logo
src={logo}
alt={name}
onError={onError}
/>
<Details>
<Name>{name}</Name>
<Bottom>
{isFavorite ? (
<InFavorites as='div'>
<StarIcon fill='#eacb6f' />
<T9n t='added_to_favorites' />
</InFavorites>
) : (
<AddToFavButton onClick={addToFavorites}>
<StarIcon fill='#fff' />
<T9n t='add_to_favorites' />
</AddToFavButton>
)}
<InfoItems>
{map(infoItems, (infoItem) => <InfoItem key={infoItem}>{infoItem}</InfoItem>)}
</InfoItems>
</Bottom>
</Details>
</Wrapper>
)
}

@ -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);
`

@ -0,0 +1,8 @@
import { ProfileTypes, SportTypes } from 'config'
export type ProfileCardProps = {
infoItems: Array<string>,
name: string,
profileType: ProfileTypes,
sportType: SportTypes,
}

@ -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,
}

@ -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 (
<UserSportFavWrapper>

@ -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<typeof useUserFavorites>
const UserFavoritesContext = createContext({} as UserFavoritesStore)
type Props = { children: ReactNode }
export const UserFavoritesStore = ({ children }: Props) => {
const userFavoritesStore = useUserFavorites()
return (
<UserFavoritesContext.Provider value={userFavoritesStore}>
{children}
</UserFavoritesContext.Provider>
)
}
export const useUserFavoritesStore = () => useContext(UserFavoritesContext)

@ -16,5 +16,5 @@ export const getProfileUrl = ({
profileType,
sportType,
}: Args) => (
`${SPORT_NAMES[sportType]}/${PROFILE_NAMES[profileType]}/${id}`
`/${SPORT_NAMES[sportType]}/${PROFILE_NAMES[profileType]}/${id}`
)

@ -1,2 +1,4 @@
export * from './usePageId'
export * from './useToggle'
export * from './useRequest'
export * from './useSportNameParam'

@ -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],
}
}

@ -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<PlayerProfile> => {
const config = {
body: {
params: {
_p_player_id: playerId,
_p_sport: sportType,
},
proc,
},
}
return callApi({
config,
url: DATA_URL,
}).then(getResponseData(proc))
}
Loading…
Cancel
Save