chore(update): update deps #156

Merged
andrey.dekterev merged 1 commits from update-deps into develop 3 years ago
  1. 10
      .eslintrc
  2. 50486
      package-lock.json
  3. 12
      package.json
  4. 2
      src/config/clients/facr.tsx
  5. 2
      src/config/clients/tunisia.tsx
  6. 12
      src/features/AudioTracks/index.tsx
  7. 14
      src/features/AuthServiceApp/hooks/useParamsUrl.tsx
  8. 12
      src/features/BuyMatchPopup/components/SelectSubscription/index.tsx
  9. 4
      src/features/BuyMatchPopup/store/hooks/useSubscriptions.tsx
  10. 8
      src/features/CompanyInfo/index.tsx
  11. 3
      src/features/HeaderMobile/styled.tsx
  12. 6
      src/features/MatchPage/components/MatchDescription/index.tsx
  13. 9
      src/features/MatchPage/store/hooks/index.tsx
  14. 6
      src/features/MatchPage/store/hooks/useFitersPopup.tsx
  15. 2
      src/features/MatchPage/store/hooks/useStatsTab.tsx
  16. 16
      src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx
  17. 24
      src/features/MatchSidePlaylists/components/PlayersTable/index.tsx
  18. 49
      src/features/ProfileHeader/index.tsx
  19. 3
      src/features/ProfileHeader/styled.tsx
  20. 54
      src/features/SportsFilter/components/SelectSportPopup/index.tsx
  21. 3
      src/features/SportsFilter/components/SelectSportPopup/styled.tsx
  22. 18
      src/features/TeamPage/hooks.tsx
  23. 26
      src/features/TournamentPage/hooks.tsx
  24. 3
      src/features/UserAccount/components/PagePersonalInfo/hooks/index.tsx
  25. 3
      src/helpers/bodyScrollLock/index.tsx
  26. 3
      src/pages/HighlightsPage/components/FormHighlights/hooks.tsx
  27. 3
      src/requests/getSelectedSubscriptions.tsx
  28. 6
      src/requests/getTeamPlayers.tsx

@ -80,8 +80,16 @@
], ],
"typescript-sort-keys/interface": 1, "typescript-sort-keys/interface": 1,
"typescript-sort-keys/string-enum": 1, "typescript-sort-keys/string-enum": 1,
"react/function-component-definition": [
2,
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
},
],
"react/jsx-no-useless-fragment": [2, { "allowExpressions": true }],
"camelcase": "off", "camelcase": "off",
"default-param-last": 0,
"import/no-unresolved": "off", "import/no-unresolved": "off",
"import/prefer-default-export": "off", "import/prefer-default-export": "off",
"indent": "off", "indent": "off",

50486
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -27,6 +27,7 @@
"@stripe/stripe-js": "^1.13.2", "@stripe/stripe-js": "^1.13.2",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"date-fns": "^2.14.0", "date-fns": "^2.14.0",
"eslint-plugin-typescript-sort-keys": "^2.3.0",
"history": "^4.10.1", "history": "^4.10.1",
"hls.js": "^1.1.1", "hls.js": "^1.1.1",
"lodash": "^4.17.15", "lodash": "^4.17.15",
@ -53,10 +54,10 @@
"@storybook/addon-actions": "^6.3.12", "@storybook/addon-actions": "^6.3.12",
"@storybook/addon-docs": "^6.3.12", "@storybook/addon-docs": "^6.3.12",
"@storybook/addon-links": "^5.3.19", "@storybook/addon-links": "^5.3.19",
"@storybook/addons": "^5.3.19", "@storybook/addons": "^7.0.2",
"@storybook/preset-create-react-app": "^3.0.0", "@storybook/preset-create-react-app": "^3.0.0",
"@storybook/preset-typescript": "^3.0.0", "@storybook/preset-typescript": "^3.0.0",
"@storybook/react": "^6.3.12", "@storybook/react": "^7.0.2",
"@testing-library/jest-dom": "^5.15.0", "@testing-library/jest-dom": "^5.15.0",
"@testing-library/react": "^12.1.2", "@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",
@ -73,8 +74,8 @@
"@types/react-window": "^1.8.5", "@types/react-window": "^1.8.5",
"@types/styled-components": "^5.1.15", "@types/styled-components": "^5.1.15",
"commitizen": "^4.2.4", "commitizen": "^4.2.4",
"eslint": "^7.0.1", "eslint": "^8.38.0",
"eslint-config-airbnb": "18.2.1", "eslint-config-airbnb": "^19.0.4",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-jsx-a11y": "^6.4.1",
@ -82,13 +83,12 @@
"eslint-plugin-react": "^7.21.5", "eslint-plugin-react": "^7.21.5",
"eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-sort-destructure-keys": "^1.3.5", "eslint-plugin-sort-destructure-keys": "^1.3.5",
"eslint-plugin-typescript-sort-keys": "^1.5.0",
"fork-ts-checker-webpack-plugin": "^7.2.13", "fork-ts-checker-webpack-plugin": "^7.2.13",
"gzipper": "^3.7.0", "gzipper": "^3.7.0",
"husky": "^4.2.5", "husky": "^4.2.5",
"lint-staged": "^10.2.7", "lint-staged": "^10.2.7",
"miragejs": "^0.1.45", "miragejs": "^0.1.45",
"storybook-addon-styled-component-theme": "^1.3.0", "storybook-addon-styled-component-theme": "^2.0.0",
"stylelint": "^13.13.1", "stylelint": "^13.13.1",
"stylelint-config-recommended": "^5.0.0", "stylelint-config-recommended": "^5.0.0",
"stylelint-config-styled-components": "^0.1.1", "stylelint-config-styled-components": "^0.1.1",

@ -9,7 +9,7 @@ import {
} from './types' } from './types'
const randomHash = () => ( const randomHash = () => (
(Math.random() ** Math.random()) * 9999999999999999 (Math.random() ** Math.random()) * 100000000000000
) )
const params = { const params = {

@ -7,7 +7,7 @@ import {
} from './types' } from './types'
const randomHash = () => ( const randomHash = () => (
(Math.random() ** Math.random()) * 9999999999999999 (Math.random() ** Math.random()) * 100000000000000
) )
export const tunisia: ClientConfig = { export const tunisia: ClientConfig = {

@ -89,13 +89,11 @@ export const AudioTracks = ({
return ( return (
<Fragment> <Fragment>
{audioTracks?.length > 1 && ( {audioTracks?.length > 1 && (
<Fragment> <SelectedAudioTrack onClick={open}>
<SelectedAudioTrack onClick={open}> {!selectedAudioTrack && audioTracks[0].name}
{!selectedAudioTrack && audioTracks[0].name} {selectedAudioTrack?.name}
{selectedAudioTrack?.name} <IconArrow active={isOpen} />
<IconArrow active={isOpen} /> </SelectedAudioTrack>
</SelectedAudioTrack>
</Fragment>
)} )}
{content} {content}
</Fragment> </Fragment>

@ -22,12 +22,14 @@ export const useParamsUrl = () => {
const urlSearchParams = useMemo(() => new URLSearchParams(location.search), [location.search]) const urlSearchParams = useMemo(() => new URLSearchParams(location.search), [location.search])
// safari начал поддержку Object.fromEntries с версии 12.1 // safari начал поддержку Object.fromEntries с версии 12.1
const params = useMemo(() => ( const params = useMemo(
Array.from(urlSearchParams.entries()).reduce((acc, [key, value]) => ({ () => (
...acc, Array.from(urlSearchParams.entries()).reduce((acc, [key, value]) => ({
[key]: value, ...acc,
}), {})), [key]: value,
[urlSearchParams]) }), {})),
[urlSearchParams],
)
return { return {
client_id, client_id,

@ -45,12 +45,12 @@ export const SelectSubscriptionStep = () => {
selectedSubscription, selectedSubscription,
} = useBuyMatchPopupStore() } = useBuyMatchPopupStore()
const getPackagesCurrency = useCallback( const getPackagesCurrency = useCallback((
(packages: Record<SubscriptionType, Array<MatchPackage>>) => { packages: Record<SubscriptionType, Array<MatchPackage>>,
const packageWithValue = Object.entries(packages).find(([key, value]) => value.length)?.[1][0] ) => {
return packageWithValue ? packageWithValue.currency : 'RUB' const packageWithValue = Object.entries(packages).find(([key, value]) => value.length)?.[1][0]
}, [], return packageWithValue ? packageWithValue.currency : 'RUB'
) }, [])
if (!match || !matchSubscriptions) return null if (!match || !matchSubscriptions) return null

@ -83,9 +83,7 @@ export const useSubscriptions = () => {
}) })
setMatchSubscriptionsList(convertedSubscriptions) setMatchSubscriptionsList(convertedSubscriptions)
fetchLexics(subscriptions.data || []) fetchLexics(subscriptions.data || [])
const firstPackage = find( const firstPackage = find(convertedSubscriptions, (subscription) => !isEmpty(subscription))
convertedSubscriptions, (subscription) => !isEmpty(subscription),
)
setSelectedPeriod(getInitialPeriod(firstPackage)) setSelectedPeriod(getInitialPeriod(firstPackage))
}, [fetchLexics, suffix]) }, [fetchLexics, suffix])

@ -43,11 +43,9 @@ export const CompanyInfo = ({
return '' return ''
case ClientNames.Lff: case ClientNames.Lff:
return ( return (
<Fragment> <CompanyInfoText>
<CompanyInfoText> <T9n t='19590' />
<T9n t='19590' /> </CompanyInfoText>
</CompanyInfoText>
</Fragment>
) )
case ClientNames.Insports: case ClientNames.Insports:
return ( return (

@ -12,7 +12,8 @@ import { customScrollbar } from 'features/Common'
export const DEFAULT_HEADER_COLOR = 'rgba(53, 96, 225, 0.56)' export const DEFAULT_HEADER_COLOR = 'rgba(53, 96, 225, 0.56)'
export const defaultHeaderStyles = ( export const defaultHeaderStyles = (
color: string = DEFAULT_HEADER_COLOR, headerImage: string | undefined | null, color: string = DEFAULT_HEADER_COLOR,
headerImage: string | undefined | null,
) => { ) => {
if (['lff', 'tunisia'].includes(client.name)) { if (['lff', 'tunisia'].includes(client.name)) {
return client.styles.homePageHeader return client.styles.homePageHeader

@ -89,8 +89,10 @@ export const MatchDescription = () => {
const isChangedTimeFormat = includes(['US', 'CA'], user?.profile.country_code) const isChangedTimeFormat = includes(['US', 'CA'], user?.profile.country_code)
const localDate = format(parseDate(date), isMobileDevice ? 'MMM d, y' : 'MMMM d, y') const localDate = format(parseDate(date), isMobileDevice ? 'MMM d, y' : 'MMMM d, y')
const changedTimeFormat = format(parseDate(date), const changedTimeFormat = format(
isChangedTimeFormat ? 'h:mm a' : 'HH:mm') parseDate(date),
isChangedTimeFormat ? 'h:mm a' : 'HH:mm',
)
return ( return (
<Description isHidden={!profileCardShown}> <Description isHidden={!profileCardShown}>

@ -160,20 +160,23 @@ export const useMatchPage = () => {
let getIntervalMatch: ReturnType<typeof setInterval> let getIntervalMatch: ReturnType<typeof setInterval>
if (matchProfile?.live && !matchProfile.youtube_link) { if (matchProfile?.live && !matchProfile.youtube_link) {
getIntervalMatch = setInterval( getIntervalMatch = setInterval(
() => getMatchInfo(sportType, matchId).then(setMatchProfile), 1000 * 60 * 3, () => getMatchInfo(sportType, matchId).then(setMatchProfile),
1000 * 60 * 3,
) )
} }
return () => clearInterval(getIntervalMatch) return () => clearInterval(getIntervalMatch)
}, [ }, [
matchProfile, matchProfile,
sportType, sportType,
matchId]) matchId,
])
useEffect(() => { useEffect(() => {
if (user || !userInfo?.email) return if (user || !userInfo?.email) return
const counter = setInterval( const counter = setInterval(
() => getMatchViewDuration(Number(userInfo?.email)), 1000 * 30, () => getMatchViewDuration(Number(userInfo?.email)),
1000 * 30,
) )
// eslint-disable-next-line // eslint-disable-next-line
return () => clearInterval(counter) return () => clearInterval(counter)

@ -46,10 +46,12 @@ export const useFiltersPopup = ({
const isAllActionsChecked = every(uniqEvents, (el) => (includes(activeEvents, el))) const isAllActionsChecked = every(uniqEvents, (el) => (includes(activeEvents, el)))
const isFirstTeamPlayersChecked = every( const isFirstTeamPlayersChecked = every(
uniqPlayersTeam1, (el) => (includes(activeFirstTeamPlayers, el)), uniqPlayersTeam1,
(el) => (includes(activeFirstTeamPlayers, el)),
) )
const isSecondTeamPlayersChecked = every( const isSecondTeamPlayersChecked = every(
uniqPlayersTeam2, (el) => (includes(activeSecondTeamPlayers, el)), uniqPlayersTeam2,
(el) => (includes(activeSecondTeamPlayers, el)),
) )
const toggle = () => { const toggle = () => {

@ -89,8 +89,8 @@ export const useStatsTab = ({
})) as Array<EventPlaylistOption> })) as Array<EventPlaylistOption>
const playNextEpisode = ({ const playNextEpisode = ({
order,
episodesToPlay = stateEpisodesToPlay, episodesToPlay = stateEpisodesToPlay,
order,
}: PlayNextEpisodeArgs = {}) => { }: PlayNextEpisodeArgs = {}) => {
const currentOrder = order === 0 ? order : plaingOrder const currentOrder = order === 0 ? order : plaingOrder
const isLastEpisode = currentOrder === episodesToPlay.length const isLastEpisode = currentOrder === episodesToPlay.length

@ -46,13 +46,15 @@ const Item = styled.li`
` `
export const MatchPlaylists = forwardRef( export const MatchPlaylists = forwardRef(
({ (
live, {
onSelect, live,
playlists, onSelect,
selectedMathPlaylist, playlists,
}: Props, selectedMathPlaylist,
ref: ForwardedRef<HTMLUListElement>) => ( }: Props,
ref: ForwardedRef<HTMLUListElement>,
) => (
<List ref={ref}> <List ref={ref}>
{ {
map(playlists, (playlist) => ( map(playlists, (playlist) => (

@ -1,5 +1,3 @@
import { Fragment } from 'react'
import { useTour } from '@reactour/tour' import { useTour } from '@reactour/tour'
import map from 'lodash/map' import map from 'lodash/map'
@ -88,18 +86,16 @@ export const PlayersTable = (props: PlayersTableProps) => {
onScroll={handleScroll} onScroll={handleScroll}
> >
{!isExpanded && paramsCount > DISPLAYED_PARAMS_COLUMNS && ( {!isExpanded && paramsCount > DISPLAYED_PARAMS_COLUMNS && (
<Fragment> <ArrowButtonRight
<ArrowButtonRight aria-label='Scroll to right'
aria-label='Scroll to right' onClick={slideRight}
onClick={slideRight} visible={showRightArrow}
visible={showRightArrow} >
> <Arrow direction='right' data-step={Steps.ShowMoreStats} />
<Arrow direction='right' data-step={Steps.ShowMoreStats} /> {Boolean(currentStep === Steps.ShowMoreStats && isOpen) && (
{Boolean(currentStep === Steps.ShowMoreStats && isOpen) && ( <Spotlight />
<Spotlight /> )}
)} </ArrowButtonRight>
</ArrowButtonRight>
</Fragment>
)} )}
<Table <Table
role='marquee' role='marquee'

@ -1,4 +1,3 @@
import { Fragment } from 'react'
import type { ReactNode } from 'react' import type { ReactNode } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
@ -56,34 +55,32 @@ export const ProfileHeader = ({
&& profileType === ProfileTypes.TOURNAMENTS ? `/images/${profileId}` : headerImage && profileType === ProfileTypes.TOURNAMENTS ? `/images/${profileId}` : headerImage
return ( return (
<Fragment> <HeaderStyled
<HeaderStyled headerImage={imageHeader}
headerImage={imageHeader} color={headerColor || color}
color={headerColor || color} height={height}
height={height} >
<Position
top={client.styles.logoTop}
left={client.styles.logoLeft}
> >
<Position <HeaderGroup>
top={client.styles.logoTop} <Link to={PAGES.home}>
left={client.styles.logoLeft} <HeaderLogo />
> </Link>
<HeaderGroup>
<Link to={PAGES.home}>
<HeaderLogo />
</Link>
{client.showSearch && <Search />} {client.showSearch && <Search />}
</HeaderGroup> </HeaderGroup>
</Position> </Position>
{children} {children}
<Position top={isMobileDevice ? client.styles.logoTop : undefined} right={0.71}> <Position top={isMobileDevice ? client.styles.logoTop : undefined} right={0.71}>
<HeaderGroup> <HeaderGroup>
{!isMobileDevice ? <ScoreSwitch /> : null} {!isMobileDevice ? <ScoreSwitch /> : null}
<Menu /> <Menu />
</HeaderGroup> </HeaderGroup>
</Position> </Position>
</HeaderStyled> </HeaderStyled>
</Fragment>
) )
} }

@ -14,7 +14,8 @@ import { isMatchPage } from 'helpers/isMatchPage'
export const DEFAULT_HEADER_COLOR = 'rgba(53, 96, 225, 0.56)' export const DEFAULT_HEADER_COLOR = 'rgba(53, 96, 225, 0.56)'
export const defaultHeaderStyles = ( export const defaultHeaderStyles = (
color: string = DEFAULT_HEADER_COLOR, headerImage: string | undefined | null, color: string = DEFAULT_HEADER_COLOR,
headerImage: string | undefined | null,
) => { ) => {
if ([ClientNames.Lff, ClientNames.Tunisia, ClientNames.Facr].includes(client.name) if ([ClientNames.Lff, ClientNames.Tunisia, ClientNames.Facr].includes(client.name)
&& !isMatchPage()) { && !isMatchPage()) {

@ -33,33 +33,31 @@ export const SelectSportPopup = ({
// TODO: переделать на вариант без указания all_sports // TODO: переделать на вариант без указания all_sports
return ( return (
<> <ScModal
<ScModal isOpen={isOpen}
isOpen={isOpen} withCloseButton={isMobileDevice}
withCloseButton={isMobileDevice} close={onModalClose}
close={onModalClose} closeSize={9}
closeSize={9} >
> <ScHeaderGroup>
<ScHeaderGroup> <ScHeaderTitle>
<ScHeaderTitle> <T9n t='choose_sport' />
<T9n t='choose_sport' /> </ScHeaderTitle>
</ScHeaderTitle> </ScHeaderGroup>
</ScHeaderGroup> <ScBody>
<ScBody> {sportNames?.map((sport: string) => (
{sportNames?.map((sport: string) => ( <ScSport
<ScSport key={sport}
key={sport} onClick={() => onSportClick(sport)}
onClick={() => onSportClick(sport)} className={selectedSport.indexOf(sport) >= 0 ? 'active' : ''}
className={selectedSport.indexOf(sport) >= 0 ? 'active' : ''} active={selectedSport.indexOf(sport) >= 0}
active={selectedSport.indexOf(sport) >= 0} >
> <ScSportName>
<ScSportName> <T9n t={getSport({ sportName: sport })?.lexic ?? 'all_sports'} />
<T9n t={getSport({ sportName: sport })?.lexic ?? 'all_sports'} /> </ScSportName>
</ScSportName> </ScSport>
</ScSport> ))}
))} </ScBody>
</ScBody> </ScModal>
</ScModal>
</>
) )
} }

@ -13,7 +13,8 @@ import { customScrollbar } from 'features/Common'
export const DEFAULT_HEADER_COLOR = 'rgba(53, 96, 225, 0.56)' export const DEFAULT_HEADER_COLOR = 'rgba(53, 96, 225, 0.56)'
export const defaultHeaderStyles = ( export const defaultHeaderStyles = (
color: string = DEFAULT_HEADER_COLOR, headerImage: string | undefined | null, color: string = DEFAULT_HEADER_COLOR,
headerImage: string | undefined | null,
) => { ) => {
if (headerImage && client.name !== 'facr') { if (headerImage && client.name !== 'facr') {
return css`background: url(${headerImage}.png); return css`background: url(${headerImage}.png);

@ -17,14 +17,16 @@ export const useTeamPage = () => {
const { profileId: teamId, sportType } = usePageParams() const { profileId: teamId, sportType } = usePageParams()
const { open: openBuyMatchPopup } = useBuyMatchPopupStore() const { open: openBuyMatchPopup } = useBuyMatchPopupStore()
useEffect(() => { useEffect(
getTeamInfo(sportType, teamId) () => {
.then(setTeamProfile) getTeamInfo(sportType, teamId)
}, .then(setTeamProfile)
[ },
sportType, [
teamId, sportType,
]) teamId,
],
)
useEffect(() => { useEffect(() => {
openSubscribePopup({ openSubscribePopup({

@ -34,18 +34,20 @@ export const useTournamentPage = () => {
const { isFavorite, toggleFavorites } = useProfileCard() const { isFavorite, toggleFavorites } = useProfileCard()
useEffect(() => { useEffect(
if (!isPermittedTournament(tournamentId, sportType)) { () => {
history.push('/') if (!isPermittedTournament(tournamentId, sportType)) {
} history.push('/')
getTournamentInfo(sportType, tournamentId) }
.then(setTournamentProfile) getTournamentInfo(sportType, tournamentId)
}, .then(setTournamentProfile)
[ },
history, [
sportType, history,
tournamentId, sportType,
]) tournamentId,
],
)
useEffect(() => { useEffect(() => {
!isFavorite !isFavorite

@ -77,8 +77,7 @@ export const useUserInfo = () => {
saveUserInfo(data).then(() => { saveUserInfo(data).then(() => {
fetchUserInfo() fetchUserInfo()
const lang_iso = find(languageList, const lang_iso = find(languageList, (language) => language.id === data.language_id)?.iso_639_1
(language) => language.id === data.language_id)?.iso_639_1
if (lang_iso) { if (lang_iso) {
changeLang(lang_iso) changeLang(lang_iso)

@ -212,7 +212,8 @@ export const enableBodyScroll = (targetElement: HTMLElement | Element) => {
// Disable body scroll locking // Disable body scroll locking
export const disableBodyScroll = ( export const disableBodyScroll = (
targetElement: HTMLElement | Element, options?: BodyScrollOptions, targetElement: HTMLElement | Element,
options?: BodyScrollOptions,
) => { ) => {
// targetElement must be provided // targetElement must be provided
if (!targetElement) { if (!targetElement) {

@ -378,7 +378,8 @@ export const useHighlightsForm = () => {
useEffect(() => { useEffect(() => {
formState?.selectedTeam?.id formState?.selectedTeam?.id
&& getTeamPlayers( && getTeamPlayers(
formState?.sport?.id || playerHighlight.sportType, formState?.selectedTeam?.id formState?.sport?.id || playerHighlight.sportType,
formState?.selectedTeam?.id
|| playerHighlight?.profile?.additionalInfo?.id, || playerHighlight?.profile?.additionalInfo?.id,
) )
.then((state) => { .then((state) => {

@ -2,8 +2,7 @@ import { callApi } from 'helpers'
import { Subscriptions } from './getSubscriptions' import { Subscriptions } from './getSubscriptions'
import { API_ROOT } from '../config' import { API_ROOT } from '../config'
export const getSelectedSubscriptions = async ( export const getSelectedSubscriptions = async (): Promise<Subscriptions> => {
): Promise<Subscriptions> => {
const config = { const config = {
method: 'GET', method: 'GET',
} }

@ -21,8 +21,10 @@ export type Player = {
weight: string | number | null, weight: string | number | null,
} }
export const getTeamPlayers = (_p_sport_id: number, export const getTeamPlayers = (
_p_team_id: number) _p_sport_id: number,
_p_team_id: number,
)
: Promise<Array<Player>> => { : Promise<Array<Player>> => {
const config = { const config = {
body: { body: {

Loading…
Cancel
Save