Ott 299 team page (#90)

* fix(ott-287): changed default football to null

* fix(ott-287): minor bug

* fix(ott-287): temp

* feat(ott-287): created infinite scroll

* feat(ott-287): added infinite scroll

* fix(ott-299): changed imports position

* fix(ott-299): comment bug fix

* fix(ott-299): minor bug fix

* fix(ott-299): some minor css bugs

* fix(ott-299): fixed width styles

* fix(ott-299): fixed menu right margin

* fix(ott-299): fixed comments, added team type

* fix(ott-299): conflict resolved

* fix(ott-299): conflict consequences are resolved

* fix(ott-299): some minor bugs fix
keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
Armen 5 years ago committed by GitHub
parent 6460d0cc2e
commit 2534688392
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .gitignore
  2. 2
      src/config/procedures.tsx
  3. 14
      src/features/Header/index.tsx
  4. 19
      src/features/Header/styled.tsx
  5. 44
      src/features/HeaderFilters/components/TournamentFilter/hooks.tsx
  6. 3
      src/features/HeaderFilters/components/TournamentFilter/index.tsx
  7. 2
      src/features/HeaderFilters/components/TournamentList/index.tsx
  8. 57
      src/features/MatchPage/MatchProfileCard/index.tsx
  9. 38
      src/features/MatchPage/MatchProfileCard/styled.tsx
  10. 53
      src/features/MatchPage/hooks.tsx
  11. 20
      src/features/MatchPage/index.tsx
  12. 6
      src/features/MatchPage/styled.tsx
  13. 1
      src/features/Menu/index.tsx
  14. 8
      src/features/OutsideClick/index.tsx
  15. 2
      src/features/ProfileCard/styled.tsx
  16. 2
      src/features/Search/index.tsx
  17. 2
      src/features/Search/styled.tsx
  18. 35
      src/features/TeamPage/hooks.tsx
  19. 15
      src/features/TeamPage/index.tsx
  20. 11
      src/features/TournamentPage/hooks.tsx
  21. 47
      src/requests/getMatchInfo.tsx
  22. 7
      src/requests/getSportTournaments.tsx
  23. 40
      src/requests/getTeamInfo.tsx
  24. 2
      src/requests/index.tsx

1
.gitignore vendored

@ -24,6 +24,5 @@ yarn-error.log*
yarn.lock
package-lock.json
# IntelliJ IDEA products
.idea

@ -2,10 +2,12 @@ export const PROCEDURES = {
auth_user: 'auth_user',
create_user: 'create_user',
get_cities: 'get_cities',
get_match_info: 'get_match_info',
get_matches: 'get_matches',
get_player_info: 'get_player_info',
get_players_teams_tournaments: 'get_players_teams_tournaments',
get_sport_list: 'get_sport_list',
get_team_info: 'get_team_info',
get_tournament_info: 'get_tournament_info',
get_tournament_list: 'get_tournament_list',
get_user_favorites: 'get_user_favorites',

@ -18,6 +18,8 @@ import {
FilterWrapper,
HomeButtonLink,
SearchWrapper,
SportFilterWrapper,
MenuWrapper,
} from './styled'
export const Header = () => {
@ -25,11 +27,13 @@ export const Header = () => {
const isMatch = useRouteMatch(`/:sportName${PAGES.match}/:pageId`)?.isExact
return (
<Wrapper>
<Menu />
{!isOnHome && <HomeButtonLink to={PAGES.home} />}
<MenuWrapper>
<Menu />
{!isOnHome && <HomeButtonLink to={PAGES.home} />}
</MenuWrapper>
{isMatch
? (
<FilterWrapper size='900px'>
<FilterWrapper>
<Search />
</FilterWrapper>
)
@ -48,10 +52,10 @@ export const Header = () => {
</FilterWrapper>
{isOnHome && (
<FilterWrapper size='400px'>
<SportFilterWrapper>
<SportTypeFilter />
<TournamentFilter />
</FilterWrapper>
</SportFilterWrapper>
)}
</Fragment>
)}

@ -12,21 +12,32 @@ export const HomeButtonLink = styled(Link)`
cursor:pointer;
}
`
export const Wrapper = styled.header`
display: flex;
padding-top: 16px;
margin-bottom: 30px;
`
export const FilterWrapper = styled.div<{ size?: string }>`
width: ${({ size }) => size || '288px'};
export const FilterWrapper = styled.div`
width: 288px;
height: 48px;
margin-right: 16px;
display: flex;
`
export const SearchWrapper = styled(FilterWrapper)`
width: ${({ size }) => size || '288px'};
width: 288px;
height: 48px;
margin-right: 16px;
margin-left: 57px;
display: flex;
`
export const SportFilterWrapper = styled(FilterWrapper)`
width: 400px;
`
export const MenuWrapper = styled.div`
display: flex;
margin-right: 57px;
`

@ -1,10 +1,9 @@
import type { BaseSyntheticEvent } from 'react'
import { useEffect, useState } from 'react'
import find from 'lodash/find'
import type { Tournaments } from 'requests'
import { getSportTournaments } from 'requests'
import { useToggle } from 'hooks'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
@ -12,21 +11,13 @@ import { useLexicsStore } from 'features/LexicsStore'
import { normalizeTournaments } from './helpers'
const useTournamentsList = () => {
const { selectedSportTypeId } = useHeaderFiltersStore()
export const useTournamentFilter = () => {
const [list, setList] = useState<Tournaments>([])
useEffect(() => {
setList([])
getSportTournaments(selectedSportTypeId).then(setList)
}, [selectedSportTypeId])
return list
}
export const useTournamentFilter = () => {
const { suffix } = useLexicsStore()
const {
selectedSportTypeId,
selectedTournamentId,
setSelectedTournamentId,
} = useHeaderFiltersStore()
@ -35,8 +26,30 @@ export const useTournamentFilter = () => {
isOpen,
open,
} = useToggle()
const tournamentList = useTournamentsList()
const tournaments = normalizeTournaments(tournamentList, suffix)
useEffect(() => {
setList([])
getSportTournaments(selectedSportTypeId).then(setList)
}, [selectedSportTypeId])
const [offset, setOffset] = useState(0)
const [requestSent, setRequestSent] = useState(false)
const handleScroll = (e: BaseSyntheticEvent) => {
const scrollPositionBottom = e.target.scrollHeight - e.target.scrollTop
- e.target.clientHeight - 400 <= 0
if (scrollPositionBottom && !requestSent) {
setRequestSent(true)
setOffset(offset + 1)
getSportTournaments(selectedSportTypeId).then((res) => {
setList([...list, ...res])
setRequestSent(false)
})
}
}
const tournaments = normalizeTournaments(list, suffix)
const selectedTournament = find(
tournaments,
(tournament) => tournament.id === selectedTournamentId,
@ -49,6 +62,7 @@ export const useTournamentFilter = () => {
return {
close,
handleScroll,
isOpen,
onTournamentSelect,
open,

@ -16,6 +16,7 @@ import {
export const TournamentFilter = () => {
const {
close,
handleScroll,
isOpen,
onTournamentSelect,
open,
@ -42,7 +43,7 @@ export const TournamentFilter = () => {
{
isOpen && (
<OutsideClick onClick={close}>
<ListWrapper id='tournamentsList'>
<ListWrapper id='tournamentsList' onScroll={handleScroll}>
<TournamentList
tournaments={tournaments}
onSelect={onTournamentSelect}

@ -48,7 +48,7 @@ export const TournamentList = ({ onSelect, tournaments }: TournamentListProps) =
sportLexic,
}) => (
<ListItem
key={id}
key={`${id}_${name}`}
onClick={() => onSelect(id)}
role='option'
>

@ -0,0 +1,57 @@
import React, { Fragment } from 'react'
import isEmpty from 'lodash/isEmpty'
import { getSportColor } from 'helpers/getSportColor'
import { SportName } from 'features/Common/SportName'
import { useSportNameParam } from 'hooks/useSportNameParam'
import { useMatchPage } from '../hooks'
import {
Wrapper,
Teams,
Score,
Tournament,
Dash,
} from './styled'
export const MatchProfileCard = () => {
const {
matchProfile,
matchProfileNames: {
team1Name,
team2Name,
tournament,
},
} = useMatchPage()
const { sportName, sportType } = useSportNameParam()
const { team1, team2 } = matchProfile || {}
const color = getSportColor(sportType)
return (
<Wrapper>
{!isEmpty(matchProfile)
&& (
<Fragment>
<Teams>
{team1Name} <Dash /> {team2Name}
</Teams>
<Score>
{team1?.score} : {team2?.score}
</Score>
<Tournament>
<SportName
color={color}
t={sportName}
/>{tournament}
</Tournament>
</Fragment>
)}
</Wrapper>
)
}

@ -0,0 +1,38 @@
import styled from 'styled-components/macro'
export const Wrapper = styled.div`
display: flex;
font-weight: bold;
font-size: 36px;
line-height: 24px;
color: white;
min-height: 28px;
`
export const Teams = styled.div`
display: flex;
`
export const Dash = styled.span`
position: relative;
width: 40px;
border-bottom: 3px solid white;
margin: 0 15px;
height: fit-content;
align-self: center;
`
export const Score = styled.div`
display: flex;
margin-left: 48px;
`
export const Tournament = styled.div`
display: flex;
font-weight: 500;
font-size: 12px;
line-height: 16px;
align-self: flex-end;
margin-left: 48px;
color: #666666;
`

@ -0,0 +1,53 @@
import { useEffect, useState } from 'react'
import type { MatchInfo } from 'requests'
import { getMatchInfo } from 'requests'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { useLexicsStore } from 'features/LexicsStore'
import { useSportNameParam, usePageId } from 'hooks'
type Name = 'name_rus' | 'name_eng'
export const useMatchPage = () => {
const [matchProfile, setMatchProfile] = useState<MatchInfo>(null)
const { sportType } = useSportNameParam()
const pageId = usePageId()
const { suffix } = useLexicsStore()
const {
setSelectedSportTypeId,
setSelectedTournamentId,
} = useHeaderFiltersStore()
const matchProfileNames = {
team1Name: matchProfile?.team1[`name_${suffix}` as Name],
team2Name: matchProfile?.team2[`name_${suffix}` as Name],
tournament: matchProfile?.tournament[`name_${suffix}` as Name],
}
useEffect(() => {
setSelectedSportTypeId(sportType)
setSelectedTournamentId(pageId)
getMatchInfo(sportType, pageId)
.then(setMatchProfile)
return () => {
setSelectedSportTypeId(null)
setSelectedTournamentId(null)
}
},
[
sportType,
pageId,
setSelectedSportTypeId,
setSelectedTournamentId,
])
return {
matchProfile,
matchProfileNames,
}
}

@ -1,11 +1,17 @@
import React from 'react'
import styled from 'styled-components'
const TempPageTitle = styled.span`
padding: 20px;
font-size: 20px;
color: white;
`
import { UserFavoritesStore } from 'features/UserFavorites/store'
import { MatchProfileCard } from './MatchProfileCard'
import {
MainWrapper,
} from './styled'
export const MatchPage = () => (
<TempPageTitle>MATCH PAGE!</TempPageTitle>
<UserFavoritesStore>
<MainWrapper>
<MatchProfileCard />
</MainWrapper>
</UserFavoritesStore>
)

@ -0,0 +1,6 @@
import styled from 'styled-components/macro'
export const MainWrapper = styled.div`
margin-left: 18px;
margin-top: 63px;
`

@ -2,6 +2,7 @@ import React from 'react'
import { PAGES } from 'config'
import { useToggle } from 'hooks'
import { useAuthStore } from 'features/AuthStore'
import { T9n } from 'features/T9n'
import { OutsideClick } from 'features/OutsideClick'

@ -8,24 +8,20 @@ import { useOutsideClickEffect } from './hooks'
type Props = {
/** элемент, которому необходим функционал `OutsideClick` */
children: ReactNode,
fullSize?: boolean,
/** функция-коллбек, отрабатывающая по клику вне области элемента */
onClick: () => void,
}
const OutsideClickWrapper = styled.div<{fullSize?:boolean}>`
width: ${({ fullSize }) => (fullSize ? '100%' : 'auto')}
`
const OutsideClickWrapper = styled.div``
export const OutsideClick = ({
children,
fullSize,
onClick,
}: Props) => {
const wrapperRef = useOutsideClickEffect({ onClick })
return (
<OutsideClickWrapper ref={wrapperRef} fullSize={fullSize}>
<OutsideClickWrapper ref={wrapperRef}>
{children}
</OutsideClickWrapper>
)

@ -22,7 +22,7 @@ export const Logo = styled.img<{ profileType: number }>`
height: 88px;
margin-right: 15px;
border-radius: ${({ profileType }) => (
profileType === ProfileTypes.TOURNAMENTS ? '0' : '50%'
profileType === ProfileTypes.PLAYERS ? '50%' : '0'
)};
`

@ -29,7 +29,7 @@ export const Search = () => {
} = useSearch()
return (
<OutsideClick onClick={close} fullSize>
<OutsideClick onClick={close}>
<Wrapper>
<Form role='search' onSubmit={onSubmit}>
<Input

@ -8,11 +8,11 @@ import {
} from 'features/Common/Input/styled'
export const Wrapper = styled.div`
width: 100%;
position: relative;
`
export const Form = styled.form`
width: 288px;
${InputWrapper} {
margin: 0;
padding-bottom: 13px;

@ -1,29 +1,56 @@
import { useEffect } from 'react'
import { useEffect, useState } from 'react'
import type { TeamInfo } from 'requests'
import { getTeamInfo } from 'requests'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { useLexicsStore } from 'features/LexicsStore'
import { useSportNameParam, usePageId } from 'hooks'
type Name = 'name_rus' | 'name_eng'
export const useTeamPage = () => {
const [teamProfile, setTeamProfile] = useState<TeamInfo>(null)
const { sportType } = useSportNameParam()
const teamId = usePageId()
const { suffix } = useLexicsStore()
const {
setSelectedSportTypeId,
setTeamId,
} = useHeaderFiltersStore()
const {
[`name_${suffix}` as Name]: name = '',
} = teamProfile || {}
const {
[`name_${suffix}` as Name]: country = '',
} = teamProfile?.country || {}
useEffect(() => {
setSelectedSportTypeId(sportType)
setTeamId(teamId)
getTeamInfo(sportType, teamId)
.then(setTeamProfile)
return () => {
setSelectedSportTypeId(null)
setTeamId(null)
}
}, [
setSelectedSportTypeId,
setTeamId,
},
[
sportType,
teamId,
setSelectedSportTypeId,
setTeamId,
])
return {
infoItems: [country],
name,
sportType,
}
}

@ -1,19 +1,30 @@
import React from 'react'
import { ProfileTypes } from 'config'
import { UserFavorites } from 'features/UserFavorites'
import { Matches } from 'features/Matches'
import { ProfileCard } from 'features/ProfileCard'
import { UserFavoritesStore } from 'features/UserFavorites/store'
import { Matches } from 'features/Matches'
import { useTeamPage } from './hooks'
import { Content } from './styled'
export const TeamPage = () => {
useTeamPage()
const {
infoItems,
name,
} = useTeamPage()
return (
<UserFavoritesStore>
<UserFavorites />
<Content>
<ProfileCard
profileType={ProfileTypes.TEAMS}
name={name}
infoItems={infoItems}
/>
<Matches />
</Content>
</UserFavoritesStore>

@ -31,19 +31,22 @@ export const useTournamentPage = () => {
} = tournamentProfile?.country || {}
useEffect(() => {
getTournamentInfo(sportType, pageId)
.then(setTournamentProfile)
setSelectedSportTypeId(sportType)
setSelectedTournamentId(pageId)
getTournamentInfo(sportType, pageId)
.then(setTournamentProfile)
return () => {
setSelectedSportTypeId(null)
setSelectedTournamentId(null)
}
}, [pageId,
},
[
sportType,
pageId,
setSelectedSportTypeId,
setSelectedTournamentId,
sportType,
])
return {

@ -0,0 +1,47 @@
import {
DATA_URL,
PROCEDURES,
} from 'config'
import { callApi, getResponseData } from 'helpers'
import { MatchStatuses } from 'features/HeaderFilters'
const proc = PROCEDURES.get_match_info
type Team = {
id: number,
name_eng: string,
name_rus: string,
score: number,
}
export type MatchInfo = {
date: Date,
stream_status: MatchStatuses,
team1: Team,
team2: Team,
tournament: {
id: number,
name_eng: string,
name_rus: string,
},
} | null
export const getMatchInfo = (sportId: number, matchId: number)
: Promise<MatchInfo> => {
const config = {
body: {
params: {
_p_match_id: matchId,
_p_sport: sportId,
},
proc,
},
}
return callApi({
config,
url: DATA_URL,
}).then(getResponseData(proc))
}

@ -27,10 +27,15 @@ export type Tournament = {
export type Tournaments = Array<Tournament>
export const getSportTournaments = (sportId: number | null): Promise<Tournaments> => {
export const getSportTournaments = (
sportId?: number | null,
offset: number = 0,
): Promise<Tournaments> => {
const config = {
body: {
params: {
_p_limit: 20,
_p_offset: offset,
_p_sport: sportId,
},
proc,

@ -0,0 +1,40 @@
import {
DATA_URL,
PROCEDURES,
} from 'config'
import { callApi, getResponseData } from 'helpers'
const proc = PROCEDURES.get_team_info
export type TeamInfo = {
country: {
id: number,
name_eng: string,
name_rus: string,
},
id: number,
is_favorite: boolean,
name_eng: string,
name_rus: string,
short_name_eng: string,
short_name_rus: string,
} | null
export const getTeamInfo = (sportId: number, teamId: number)
: Promise<TeamInfo> => {
const config = {
body: {
params: {
_p_sport: sportId,
_p_team_id: teamId,
},
proc,
},
}
return callApi({
config,
url: DATA_URL,
}).then(getResponseData(proc))
}

@ -10,3 +10,5 @@ export * from './getUserSportFavs'
export * from './modifyUserSportFavs'
export * from './getSportTournaments'
export * from './getTournamentInfo'
export * from './getTeamInfo'
export * from './getMatchInfo'

Loading…
Cancel
Save