Ott 140 calendar filter (#49)

keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
Mirlan 5 years ago committed by GitHub
parent 6d44eefd1b
commit 2fff5da887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      package.json
  2. 2
      public/index.html
  3. 1
      src/config/procedures.tsx
  4. 25
      src/features/DateFilter/components/DatePicker/hooks.tsx
  5. 79
      src/features/DateFilter/components/DatePicker/index.tsx
  6. 138
      src/features/DateFilter/components/DatePicker/styled.tsx
  7. 27
      src/features/DateFilter/helpers.tsx
  8. 69
      src/features/DateFilter/hooks/index.tsx
  9. 53
      src/features/DateFilter/index.tsx
  10. 144
      src/features/DateFilter/styled.tsx
  11. 2
      src/features/Menu/styled.tsx
  12. 56
      src/requests/getMatches.tsx
  13. 1
      src/requests/index.tsx

@ -14,10 +14,12 @@
},
"dependencies": {
"@reach/combobox": "^0.10.4",
"date-fns": "^2.14.0",
"history": "^4.10.1",
"lodash": "^4.17.15",
"node-sass": "^4.14.1",
"react": "^16.13.1",
"react-datepicker": "^3.1.3",
"react-dom": "^16.13.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
@ -42,6 +44,7 @@
"@types/lodash": "^4.14.154",
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-datepicker": "^3.0.2",
"@types/react-dom": "^16.9.0",
"@types/react-router": "^5.1.7",
"@types/react-router-dom": "^5.1.5",

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;700&display=swap" rel="stylesheet">
<title>Instat TV</title>
</head>
<body>

@ -2,6 +2,7 @@ export const PROCEDURES = {
auth_user: 'auth_user',
create_user: 'create_user',
get_cities: 'get_cities',
get_matches: 'get_matches',
get_players_teams_tournaments: 'get_players_teams_tournaments',
logout_user: 'logout_user',
lst_c_country: 'lst_c_country',

@ -0,0 +1,25 @@
import { useEffect } from 'react'
import ru from 'date-fns/locale/ru'
import en from 'date-fns/locale/en-GB'
import { registerLocale, setDefaultLocale } from 'react-datepicker'
import { useLexicsStore } from 'features/LexicsStore'
/**
* react-datepicker использует date-fns локейлы для локализации
* регистрируем [en, ru] чтобы названия дней недели менялись при смене языка
*/
export const useDatepickerLocales = () => {
const { lang } = useLexicsStore()
useEffect(() => {
registerLocale('ru', ru)
registerLocale('en', en)
}, [])
useEffect(() => {
setDefaultLocale(lang)
}, [lang])
}

@ -0,0 +1,79 @@
import React from 'react'
import type { ReactDatePickerProps } from 'react-datepicker'
import DatePickerComponent from 'react-datepicker'
import 'react-datepicker/dist/react-datepicker.css'
import addMonths from 'date-fns/addMonths'
import { useLexicsStore } from 'features/LexicsStore'
import { getDisplayDate, getMonthName } from 'features/DateFilter/helpers'
import { useDatepickerLocales } from './hooks'
import {
Wrapper,
MonthsWrapper,
CurrentMonth,
MonthButton,
} from './styled'
type Args = (
Parameters<NonNullable<ReactDatePickerProps['renderCustomHeader']>>[0]
& { lang: string }
)
const monthType = 'short'
const renderCustomHeader = ({
date,
decreaseMonth,
increaseMonth,
lang,
}: Args) => {
const prevMonth = getMonthName({
date: addMonths(date, -1),
lang,
monthType,
})
const nextMonth = getMonthName({
date: addMonths(date, 1),
lang,
monthType,
})
const currentDate = getDisplayDate({
date,
lang,
})
return (
<MonthsWrapper>
<MonthButton onClick={decreaseMonth}>{prevMonth}</MonthButton>
<CurrentMonth>{currentDate.month}, {currentDate.year}</CurrentMonth>
<MonthButton onClick={increaseMonth}>{nextMonth}</MonthButton>
</MonthsWrapper>
)
}
type Props = Pick<ReactDatePickerProps, (
| 'onChange'
| 'open'
| 'selected'
)>
export const DatePicker = ({
onChange,
open,
selected,
}: Props) => {
const { lang } = useLexicsStore()
useDatepickerLocales()
return (
<Wrapper>
<DatePickerComponent
open={open}
selected={selected}
onChange={onChange}
renderCustomHeader={(props) => renderCustomHeader({ ...props, lang })}
/>
</Wrapper>
)
}

@ -0,0 +1,138 @@
import styled from 'styled-components/macro'
export const Wrapper = styled.div`
position: absolute;
left: 0;
top: calc(100% + 14px);
.react-datepicker {
margin: 0;
border: none;
width: 288px;
background-color: #666666;
box-shadow: 0px 2px 50px #000000;
border-radius: 2px;
font-family: inherit;
color: #fff;
}
.react-datepicker__header {
border: none;
border-radius: 2;
padding-top: 12px;
background-color: #666666;
}
.react-datepicker__month-container {
width: 100%;
}
.react-datepicker__day-names {
margin-top: 24px;
margin-bottom: 12px;
display: flex;
justify-content: space-around;
}
.react-datepicker__day-name {
margin: 0;
width: 28px;
color: inherit;
font-size: 16px;
line-height: 16px;
text-align: center;
letter-spacing: 0.1px;
}
.react-datepicker__month {
margin: 0;
}
.react-datepicker__week {
margin: 8px 0;
display: flex;
justify-content: space-around;
}
.react-datepicker__day {
margin: 0;
border: none;
outline: none;
width: 28px;
height: 28px;
color: inherit;
opacity: 0.6;
font-weight: normal;
font-size: 12px;
border-radius: 50%;
:hover {
background-color: rgba(255, 255, 255, 0.4);
}
}
.react-datepicker__day--selected {
color: #005EDD;
background-color: #ffffff;
opacity: 1;
}
.react-datepicker__day--keyboard-selected {
color: inherit;
background-color: transparent;
}
.react-datepicker__day--outside-month {
opacity: 0.2
}
.react-datepicker-popper {
transform: translate(0, 0) !important;
}
.react-datepicker-popper[data-placement^="bottom"] {
margin-top: 0px;
}
.react-datepicker__input-container,
.react-datepicker__triangle {
display: none;
}
`
export const MonthsWrapper = styled.div`
width: 100%;
height: 28px;
padding: 0 12px;
display: flex;
align-items: center;
justify-content: space-between;
font-weight: 600;
font-size: 16px;
line-height: 16px;
text-align: center;
letter-spacing: 0.1px;
text-transform: capitalize;
`
export const CurrentMonth = styled.span`
min-width: 100px;
height: 100%;
padding: 0 14px;
display: flex;
align-items: center;
justify-content: center;
background-color: #005EDD;
border-radius: 16px;
`
export const MonthButton = styled.button`
border: none;
outline: none;
padding: 0;
opacity: 0.4;
color: inherit;
background-color: transparent;
text-transform: inherit;
cursor: pointer;
`

@ -0,0 +1,27 @@
type Args = {
date: Date,
lang: string,
monthType?: 'long' | 'short',
}
export const getMonthName = ({
date,
lang,
monthType,
}: Args) => (
date.toLocaleString(lang, { month: monthType })
)
export const getDisplayDate = ({
date,
lang,
monthType = 'long',
}: Args) => ({
day: date.getDate(),
month: getMonthName({
date,
lang,
monthType,
}),
year: date.getFullYear(),
})

@ -0,0 +1,69 @@
import {
useState,
useCallback,
useEffect,
} from 'react'
import debounce from 'lodash/debounce'
import format from 'date-fns/format'
import addDays from 'date-fns/addDays'
import startOfDay from 'date-fns/startOfDay'
import { getMatches } from 'requests'
import { useToggle } from 'hooks'
import { useLexicsStore } from 'features/LexicsStore'
import { getDisplayDate } from '../helpers'
const dateFormat = 'dd/MM/yyyy HH:mm:ss'
export const useDateFilter = () => {
const { lang } = useLexicsStore()
const {
close,
isOpen,
open,
} = useToggle()
const fetchMatches = useCallback(debounce(getMatches, 300), [])
const [currentDate, setCurrentDate] = useState(new Date())
const date = getDisplayDate({
date: currentDate,
lang,
})
const onPreviousClick = () => {
setCurrentDate(addDays(currentDate, -1))
}
const onNextClick = () => {
setCurrentDate(addDays(currentDate, 1))
}
const onDateChange = (newDate: Date | null) => {
if (newDate) {
setCurrentDate(newDate)
close()
}
}
useEffect(() => {
const formattedDate = format(startOfDay(currentDate), dateFormat)
fetchMatches({
date: formattedDate,
sportType: 1,
tournamentId: 8,
})
}, [fetchMatches, currentDate])
return {
close,
currentDate,
date,
isOpen,
onDateChange,
onNextClick,
onPreviousClick,
open,
}
}

@ -1,5 +1,54 @@
import React from 'react'
import { Wrapper } from './styled'
import { OutsideClick } from 'features/OutsideClick'
export const DateFilter = () => <Wrapper />
import { useDateFilter } from './hooks'
import { DatePicker } from './components/DatePicker'
import {
Wrapper,
Button,
ArrowLeft,
ArrowRight,
DateButton,
Day,
MonthYearWrapper,
Month,
Year,
} from './styled'
export const DateFilter = () => {
const {
close,
currentDate,
date,
isOpen,
onDateChange,
onNextClick,
onPreviousClick,
open,
} = useDateFilter()
return (
<Wrapper active={isOpen}>
<Button onClick={onPreviousClick} borderLeftRadius={2}>
<ArrowLeft />
</Button>
<OutsideClick onClick={close}>
<DateButton onClick={open}>
<Day>{date.day}</Day>
<MonthYearWrapper>
<Month>{date.month}</Month>
<Year>{date.year}</Year>
</MonthYearWrapper>
</DateButton>
<DatePicker
open={isOpen}
selected={currentDate}
onChange={onDateChange}
/>
</OutsideClick>
<Button onClick={onNextClick} borderRightRadius={2}>
<ArrowRight />
</Button>
</Wrapper>
)
}

@ -1,3 +1,145 @@
import styled from 'styled-components/macro'
export const Wrapper = styled.div``
type Props = {
active: boolean,
}
export const Wrapper = styled.div<Props>`
position: relative;
height: 100%;
width: 100%;
display: flex;
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
${({ active }) => (active
? `
& ${Button}, ${DateButton} {
color: #fff;
background-color: #666666;
}
`
: ''
)};
`
export const DateButton = styled.button`
border: none;
outline: none;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
text-align: left;
width: 192px;
height: 100%;
border-left: 1px solid #222222;
border-right: 1px solid #222222;
cursor: pointer;
background-color: #3F3F3F;
color: #999999;
:hover {
background-color: #484848;
}
:active {
color: #fff;
background-color: #666666;
}
`
export const Day = styled.span`
font-weight: bold;
font-size: 38px;
letter-spacing: -0.03em;
`
export const Month = styled.span`
font-weight: bold;
font-size: 14px;
`
export const MonthYearWrapper = styled.div`
height: 28px;
margin-left: 4px;
display: flex;
flex-direction: column;
justify-content: space-between;
`
export const Year = styled.span`
font-style: normal;
font-weight: 300;
font-size: 14px;
`
const Arrow = styled.div`
width: 16px;
height: 2px;
margin: auto;
background-color: #222222;
&::before {
content: '';
position: absolute;
width: 10px;
height: 10px;
border-left: 2px solid #222222;
border-bottom: 2px solid #222222;
}
`
export const ArrowLeft = styled(Arrow)`
&:before {
transform: rotate(45deg);
top: 19px;
left: 17px;
}
`
export const ArrowRight = styled(Arrow)`
&:before {
transform: rotate(225deg);
top: 19px;
right: 17px;
}
`
type ButtonProps = {
borderLeftRadius?: number,
borderRightRadius?: number,
}
export const Button = styled.button<ButtonProps>`
position: relative;
outline: none;
border: none;
width: 48px;
height: 100%;
cursor: pointer;
background-color: #3F3F3F;
${({ borderLeftRadius }) => (
borderLeftRadius
? `
border-top-left-radius: ${borderLeftRadius}px;
border-bottom-left-radius: ${borderLeftRadius}px;
`
: ''
)}
${({ borderRightRadius }) => (
borderRightRadius
? `
border-top-right-radius: ${borderRightRadius}px;
border-bottom-right-radius: ${borderRightRadius}px;
`
: ''
)}
:hover {
background-color: #484848;
}
:active {
background-color: #666666;
}
`

@ -7,7 +7,7 @@ export const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 304px;
width: 320px;
height: 48px;
`
export const ToggleButton = styled.button`

@ -0,0 +1,56 @@
import { DATA_URL, PROCEDURES } from 'config'
import { callApi, getResponseData } from 'helpers'
const proc = PROCEDURES.get_matches
export type Item = {
id: number,
matches: Array<Match>,
name_eng: string,
name_rus: string,
sport: number,
}
export type Match = {
date: string,
id: number,
round_id: number,
stream_status: number,
team1: Team,
team2: Team,
}
export type Team = {
id: number,
name_eng: string,
name_rus: string,
score: number,
}
type Args = {
date: string,
sportType: number,
tournamentId: number,
}
export const getMatches = ({
date,
sportType,
tournamentId,
}: Args): Promise<Array<Item>> => {
const config = {
body: {
params: {
_p_date: date,
_p_sport: sportType,
_p_tournament_id: tournamentId,
},
proc,
},
}
return callApi({
config,
url: DATA_URL,
}).then(getResponseData(proc))
}

@ -5,3 +5,4 @@ export * from './getCountries'
export * from './getCountryCities'
export * from './getLexics'
export * from './getSearchItems'
export * from './getMatches'

Loading…
Cancel
Save