feat(ott-144): added user fav sport items (#51)

keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
ElAnonimo 5 years ago committed by GitHub
parent e29b1b3889
commit 455157c361
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. BIN
      public/images/sportFavStar.png
  2. BIN
      public/images/xIcon.png
  3. 2
      src/config/procedures.tsx
  4. 42
      src/config/routes.tsx
  5. 40
      src/features/HomePage/index.tsx
  6. 2
      src/features/MainWrapper/index.tsx
  7. 27
      src/features/UserSportFav/TooltipBlock/hooks/index.tsx
  8. 48
      src/features/UserSportFav/TooltipBlock/index.tsx
  9. 47
      src/features/UserSportFav/TooltipBlock/styled.tsx
  10. 132
      src/features/UserSportFav/hooks/index.tsx
  11. 68
      src/features/UserSportFav/index.tsx
  12. 80
      src/features/UserSportFav/styled.tsx
  13. 27
      src/helpers/handleImg/index.tsx
  14. 2
      src/helpers/index.tsx
  15. 53
      src/requests/getUserSportFavs.tsx
  16. 2
      src/requests/index.tsx
  17. 37
      src/requests/modifyUserSportFavs.tsx

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

@ -4,7 +4,9 @@ export const PROCEDURES = {
get_cities: 'get_cities',
get_matches: 'get_matches',
get_players_teams_tournaments: 'get_players_teams_tournaments',
get_user_favorites: 'get_user_favorites',
logout_user: 'logout_user',
lst_c_country: 'lst_c_country',
param_lexical: 'param_lexical',
save_user_favorite: 'save_user_favorite',
}

@ -19,4 +19,44 @@ export const LOGOS_FALLBACKS = {
teams: 'https://hockey.instatscout.com/images/team-no-photo.png',
tournaments: 'https://hockey.instatscout.com/images/tournaments/180/no-photo.png',
},
}
} as const
export const LOGOS_URLS = {
basketball: {
players: 'https://basketball.instatscout.com/images/players/180',
teams: 'https://basketball.instatscout.com/images/teams/180',
tournaments: 'https://basketball.instatscout.com/images/tournaments/180',
},
football: {
players: 'https://instatscout.com/images/players/180',
teams: 'https://instatscout.com/images/teams/180',
tournaments: 'https://instatscout.com/images/tournaments/180',
},
hockey: {
players: 'https://hockey.instatscout.com/images/players/180',
teams: 'https://hockey.instatscout.com/images/teams/180',
tournaments: 'https://hockey.instatscout.com/images/tournaments/180',
},
} as const
export const FAV_SPORT_URLS = {
basketball: {
players: '/basketball/players',
teams: '/basketball/teams',
tournaments: '/basketball/tournaments',
},
football: {
players: '/football/players',
teams: '/football/teams',
tournaments: '/football/tournaments',
},
hockey: {
players: '/hockey/players',
teams: '/hockey/teams',
tournaments: '/hockey/tournaments',
},
} as const

@ -1,4 +1,4 @@
import React from 'react'
import React, { Fragment } from 'react'
import { Header } from 'features/Header'
import { MainWrapper } from 'features/MainWrapper'
@ -7,30 +7,34 @@ import { DateFilter } from 'features/DateFilter'
import { MatchStatusFilter } from 'features/MatchStatusFilter'
import { SportTypeFilter } from 'features/SportTypeFilter'
import { TournamentFilter } from 'features/TournamentFilter'
import { UserSportFav } from 'features/UserSportFav'
import {
FilterWrapper,
} from './styled'
export const HomePage = () => (
<MainWrapper>
<Header>
<FilterWrapper>
<Search />
</FilterWrapper>
<Fragment>
<MainWrapper>
<UserSportFav />
<Header>
<FilterWrapper>
<Search />
</FilterWrapper>
<FilterWrapper>
<DateFilter />
</FilterWrapper>
<FilterWrapper>
<DateFilter />
</FilterWrapper>
<FilterWrapper>
<MatchStatusFilter />
</FilterWrapper>
<FilterWrapper>
<MatchStatusFilter />
</FilterWrapper>
<FilterWrapper>
<SportTypeFilter />
<TournamentFilter />
</FilterWrapper>
</Header>
</MainWrapper>
<FilterWrapper>
<SportTypeFilter />
<TournamentFilter />
</FilterWrapper>
</Header>
</MainWrapper>
</Fragment>
)

@ -2,5 +2,5 @@ import styled from 'styled-components/macro'
export const MainWrapper = styled.div`
width: 100%;
padding-left: 80px;
display: flex;
`

@ -0,0 +1,27 @@
import { SPORT_COLORS } from 'config'
export const getSportName = (sport: number, suffix: string): string => {
switch (sport) {
case 1:
return suffix === 'eng' ? 'Football' : 'Футбол'
case 2:
return suffix === 'eng' ? 'Hockey' : 'Хоккей'
case 3:
return suffix === 'eng' ? 'Basketball' : 'Баскетбол'
default:
return ''
}
}
export const getSportColor = (sport: number): string => {
switch (sport) {
case 1:
return SPORT_COLORS.football
case 2:
return SPORT_COLORS.hockey
case 3:
return SPORT_COLORS.basketball
default:
return ''
}
}

@ -0,0 +1,48 @@
import React from 'react'
import {
getSportName,
getSportColor,
} from './hooks'
import {
TooltipBlockWrapper,
TooltipBlockItem,
TooltipBlockItemThinUpperCase,
TooltipBlockItemThin,
} from './styled'
type TTooltipBlock = {
countryName?: string,
date?: string,
playerFirstName?: string,
playerLastName?: string,
playerTeamName?: string,
sport: number,
suffix: string,
teamName?: string,
}
export const TooltipBlock = ({
countryName,
playerFirstName,
playerLastName,
playerTeamName,
sport,
suffix,
teamName,
}: TTooltipBlock) => (
<TooltipBlockWrapper>
<TooltipBlockItem>
{playerFirstName && playerLastName && `${playerFirstName} ${playerLastName}`}
</TooltipBlockItem>
<TooltipBlockItem>
{teamName}
</TooltipBlockItem>
<TooltipBlockItemThin>
<TooltipBlockItemThinUpperCase color={getSportColor(sport)}>
{getSportName(sport, suffix)}
</TooltipBlockItemThinUpperCase>{' '}
{playerTeamName || countryName}
</TooltipBlockItemThin>
</TooltipBlockWrapper>
)

@ -0,0 +1,47 @@
import styled, { css } from 'styled-components/macro'
export const TooltipBlockWrapper = styled.div`
background-color: #fff;
border-radius: 10px;
padding: 12px;
white-space: nowrap;
&::before {
position: absolute;
top: -8px;
content: '';
border-bottom: 8px solid #fff;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
}
`
export type TTooltipProps = {
color?: string,
}
export const TooltipStyles = css<TTooltipProps>`
display: block;
font-family: Montserrat, Tahoma, sans-serif;
font-size: 14px;
line-height: 18px;
color: ${({ color }) => (color ? `${color}` : '#2c2d2e')};
font-weight: 600;
&:hover {
background-color: rgba(255, 255, 255, 0.7);
}
`
export const TooltipBlockItem = styled.span`
${TooltipStyles}
`
export const TooltipBlockItemThin = styled(TooltipBlockItem)`
font-weight: 400;
`
export const TooltipBlockItemThinUpperCase = styled(TooltipBlockItem)`
display: inline;
text-transform: uppercase;
font-weight: 400;
`

@ -0,0 +1,132 @@
import {
useEffect,
useState,
useMemo,
} from 'react'
import map from 'lodash/map'
import {
LOGOS_URLS,
FAV_SPORT_URLS,
} from 'config'
import {
SPORT_TYPES,
DATA_TYPES,
} from 'helpers'
import {
modifyUserSportFavs,
ModifyUserSportFavsArgs,
getUserSportFavs,
UserSportFavItem,
} from 'requests'
import { useLexicsStore } from 'features/LexicsStore'
type TNames = 'name_eng' | 'name_rus'
type TShortNames = 'short_name_eng' | 'short_name_rus'
type TFirstNames = 'firstname_eng' | 'firstname_rus'
type TLastNames = 'lastname_eng' | 'firstname_rus'
type TNickNames = 'nickname_eng' | 'nickname_rus'
export type TMemoizedUserSportFavItem = {
countryName?: string,
firstname?: string,
id: number,
lastname?: string,
name?: string,
nickname?: string,
shortName?: string,
sport: number,
teamName?: string,
type: number,
}
type TMakeUrlArgs = {
id: number,
sport: number,
type: number,
}
export const useUserSportFavs = () => {
const { suffix } = useLexicsStore()
const [userSportFavItems, setUserSportFavItems] = useState<Array<UserSportFavItem>>([])
const nameField = `name_${suffix}` as TNames
const shortNameField = `short_name_${suffix}` as TShortNames
const firtsNameField = `firstname_${suffix}` as TFirstNames
const lastNameField = `lastname_${suffix}` as TLastNames
const nickNameField = `nickname_${suffix}` as TNickNames
useEffect(() => {
getUserSportFavs().then(setUserSportFavItems)
}, [])
const addRemoveSportFav = ({
action,
id,
sport,
type,
}: ModifyUserSportFavsArgs) => {
// при добавлении дубликата userSportFavItem back возвращает {}
modifyUserSportFavs({
action,
id,
sport,
type,
}).then((userSportFavs) => Array.isArray(userSportFavs) && setUserSportFavItems(userSportFavs))
}
const memoizedUserSportFavItems = useMemo(() => map(userSportFavItems, (item) => ({
countryName: item.info.country?.[nameField],
firstname: item.info[firtsNameField],
id: item.id,
lastname: item.info[lastNameField],
name: item.info[nameField],
nickname: item.info[nickNameField],
shortName: item.info[shortNameField],
sport: item.sport,
teamName: item.info.team?.[nameField],
type: item.type,
})),
[
firtsNameField,
lastNameField,
userSportFavItems,
nameField,
nickNameField,
shortNameField,
])
return {
addRemoveSportFav,
userSportFavItems: memoizedUserSportFavItems,
}
}
export const makePicUrl = (arg: TMakeUrlArgs) => (
// @ts-expect-error
`${LOGOS_URLS[SPORT_TYPES[arg.sport]][DATA_TYPES[arg.type]]}/${arg.id}.png`
)
export const makeProfileUrl = (arg: TMakeUrlArgs) => (
// @ts-expect-error
`${FAV_SPORT_URLS[SPORT_TYPES[arg.sport]][DATA_TYPES[arg.type]]}/${arg.id}`
)
export const userSportFavs = (
userSportFavItems: Array<TMemoizedUserSportFavItem>,
) => userSportFavItems?.length > 0 && map(
userSportFavItems, (fav) => ({
...fav,
pic_url: makePicUrl({
id: fav.id,
sport: fav.sport,
type: fav.type,
}),
profile_url: makeProfileUrl({
id: fav.id,
sport: fav.sport,
type: fav.type,
}),
}),
)

@ -0,0 +1,68 @@
import React from 'react'
import map from 'lodash/map'
import { useLexicsStore } from 'features/LexicsStore'
import { handleImageError } from 'helpers'
import {
useUserSportFavs,
userSportFavs,
} from './hooks'
import { TooltipBlock } from './TooltipBlock'
import {
StyledLink,
UserSportFavItemLogoWrapper,
UserSportFavXWrapper,
UserSportFavImgWrapper,
UserSportFavStar,
UserSportFavLogoWrapper,
UserSportFavWrapper,
} from './styled'
export const UserSportFav = () => {
const { addRemoveSportFav, userSportFavItems } = useUserSportFavs()
const { suffix } = useLexicsStore()
const userSportFavList = userSportFavs(userSportFavItems)
return (
<UserSportFavWrapper>
<UserSportFavLogoWrapper height={12} width={52} />
<UserSportFavStar />
{userSportFavList && map(userSportFavList, (item) => (
<UserSportFavItemLogoWrapper key={`${item.type}_${item.sport}_${item.id}`}>
<UserSportFavXWrapper
onClick={() => addRemoveSportFav({
action: 2,
id: item.id,
sport: item.sport,
type: item.type,
})}
/>
<TooltipBlock
countryName={item.countryName}
teamName={item.name}
playerTeamName={item.teamName}
playerFirstName={item.firstname}
playerLastName={item.lastname}
sport={item.sport}
suffix={suffix}
/>
<StyledLink to={item.profile_url} target='_blank'>
<UserSportFavImgWrapper
src={item.pic_url}
alt={item.name}
onError={(e) => handleImageError({
e,
sport: item.sport,
type: item.type,
})}
/>
</StyledLink>
</UserSportFavItemLogoWrapper>
))}
</UserSportFavWrapper>
)
}

@ -0,0 +1,80 @@
import { Link } from 'react-router-dom'
import styled from 'styled-components/macro'
import { Logo } from 'features/Logo'
import { TooltipBlockWrapper } from './TooltipBlock/styled'
export const StyledLink = styled(Link)``
export const UserSportFavWrapper = styled.div`
width: 80px;
display: flex;
flex: 0 0 auto;
flex-direction:column;
align-items: center;
background: rgba(255, 255, 255, 0.1);
`
export const UserSportFavLogoWrapper = styled(Logo)`
margin-top: 35px;
margin-bottom: 120px;
`
export const UserSportFavXWrapper = styled.span`
display: block;
position: absolute;
top: 0;
right: 0;
background: transparent url('/images/xIcon.png') no-repeat center;
height: 11px;
width: 11px;
border: none;
`
export const UserSportFavItemLogoWrapper = styled.div`
position: relative;
width: 48px;
height: 48px;
border-radius: 50%;
padding: 5px;
background-color: #fff;
margin-bottom: 16px;
${UserSportFavXWrapper} {
display: none;
}
${TooltipBlockWrapper} {
display: none;
position: absolute;
left: 40%;
top: 120%;
z-index: 2;
}
&:hover {
background-color: rgba(255, 255, 255, 0.7);
cursor: pointer;
${UserSportFavXWrapper} {
display: block;
}
${TooltipBlockWrapper} {
display: block;
}
}
`
export const UserSportFavImgWrapper = styled.img`
width: 100%;
`
export const UserSportFavStar = styled.div`
width: 48px;
height: 48px;
border-radius: 50%;
background: #3f3f3f url('/images/sportFavStar.png') no-repeat center;
margin-bottom: 16px;
`

@ -0,0 +1,27 @@
import { BaseSyntheticEvent } from 'react'
import { LOGOS_FALLBACKS } from 'config'
export type imageErrorArgs = {
e: BaseSyntheticEvent,
sport: number,
type: number,
}
export const SPORT_TYPES = {
1: 'football',
2: 'hockey',
3: 'basketball',
} as const
export const DATA_TYPES = {
1: 'tournaments',
2: 'teams',
3: 'players',
} as const
export const handleImageError = (arg: imageErrorArgs): void => {
arg.e.target.onError = ''
// @ts-expect-error
arg.e.target.src = LOGOS_FALLBACKS[SPORT_TYPES[arg.sport]][DATA_TYPES[arg.type]]
}

@ -2,3 +2,5 @@ export * from './callApi'
export * from './callApi/getResponseData'
export * from './token'
export * from './getLogo'
export * from './handleImg'

@ -0,0 +1,53 @@
import { DATA_URL, PROCEDURES } from 'config'
import { callApi, getResponseData } from 'helpers'
const proc = PROCEDURES.get_user_favorites
export type UserSportFavItem = {
id: number,
info: {
country?: {
name_eng: string,
name_rus: string,
},
date?: string,
firstname_eng?: string,
firstname_rus?: string,
lastname_eng?: string,
lastname_rus?: string,
name_eng?: string,
name_rus?: string,
nickname_eng?: string,
nickname_rus?: string,
short_name_eng?: string,
short_name_rus?: string,
team?: {
name_eng: string,
name_rus: string,
},
team1?: {
name_eng: string,
name_rus: string,
},
team2?: {
name_eng: string,
name_rus: string,
},
},
sport: number,
type: number,
}
export const getUserSportFavs = (): Promise<Array<UserSportFavItem>> => {
const config = {
body: {
params: {},
proc,
},
}
return callApi({
config,
url: DATA_URL,
}).then(getResponseData(proc))
}

@ -6,3 +6,5 @@ export * from './getCountryCities'
export * from './getLexics'
export * from './getSearchItems'
export * from './getMatches'
export * from './getUserSportFavs'
export * from './modifyUserSportFavs'

@ -0,0 +1,37 @@
import { DATA_URL, PROCEDURES } from 'config'
import { callApi, getResponseData } from 'helpers'
import { UserSportFavItem } from './getUserSportFavs'
const proc = PROCEDURES.save_user_favorite
export type ModifyUserSportFavsArgs = {
action: number,
id: number,
sport: number,
type: number,
}
// при добавлении дубликата userSportFavItem back возвращает {}
export const modifyUserSportFavs = ({
action,
id,
sport,
type,
}: ModifyUserSportFavsArgs): Promise<Array<UserSportFavItem> | {}> => {
const config = {
body: {
params: {
_p_action: action,
_p_id: id,
_p_sport: sport,
_p_type: type,
},
proc,
},
}
return callApi({
config,
url: DATA_URL,
}).then(getResponseData(proc))
}
Loading…
Cancel
Save