From fb76eaa14e6862c710d755d9402ad8a4bc64d835 Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Mon, 21 Nov 2022 18:16:15 +0300 Subject: [PATCH 01/31] build(#187): add india config --- .drone.yml | 147 ++++++++++++++++-- Makefile | 53 +++---- package.json | 1 + run.sh | 9 -- src/config/clients/index.tsx | 3 + src/config/clients/india.tsx | 15 ++ src/config/clients/types.tsx | 2 + src/config/routes.tsx | 6 +- .../AuthServiceApp/config/clients/index.tsx | 2 + .../AuthServiceApp/config/clients/india.tsx | 9 ++ src/features/AuthStore/helpers.tsx | 9 +- src/react-app-env.d.ts | 2 +- 12 files changed, 196 insertions(+), 62 deletions(-) delete mode 100644 run.sh create mode 100644 src/config/clients/india.tsx create mode 100644 src/features/AuthServiceApp/config/clients/india.tsx diff --git a/.drone.yml b/.drone.yml index 6397fe22..c86168c5 100644 --- a/.drone.yml +++ b/.drone.yml @@ -15,9 +15,27 @@ trigger: - refs/heads/master steps: - - name: deploy script + - name: npm-install image: node:16-alpine + environment: + REACT_APP_STRIPE_PK: + from_secret: REACT_APP_STRIPE_PK + commands: + - apk add --no-cache make + - npm install --legacy-peer-deps + + - name: make-prod + image: node:16-alpine + environment: + REACT_APP_STRIPE_PK: + from_secret: REACT_APP_STRIPE_PK + commands: + - make prod + depends_on: + - npm-install + - name: deploy script + image: amazon/aws-cli:latest environment: AWS_ACCESS_KEY_ID: from_secret: AWS_ACCESS_KEY_ID @@ -25,27 +43,126 @@ steps: from_secret: AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION: from_secret: AWS_DEFAULT_REGION - REACT_APP_STRIPE_PK: - from_secret: REACT_APP_STRIPE_PK - SSH_KEY_AUTH: - from_secret: SSH_KEY_AUTH - commands: - - apk add --no-cache aws-cli bash git openssh-client make rsync - - npm install --legacy-peer-deps - - make prod # - aws s3 sync build s3://insports-prod --delete # - aws cloudfront create-invalidation --distribution-id E3KY6BCU3AYHEW --paths "/*" - aws s3 sync build s3://instat-frontend-test-a --delete - aws cloudfront create-invalidation --distribution-id E1WZHVCHZ48SG6 --paths "/*" + depends_on: + - make-prod + + - name: make-auth + image: node:16-alpine + environment: + REACT_APP_STRIPE_PK: + from_secret: REACT_APP_STRIPE_PK + commands: - make auth-production-build + depends_on: + - npm-install + + - name: deploy-S3-auth + image: amazon/aws-cli:latest + environment: + AWS_ACCESS_KEY_ID: + from_secret: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: AWS_SECRET_ACCESS_KEY + AWS_DEFAULT_REGION: + from_secret: AWS_DEFAULT_REGION + commands: + - aws s3 sync build s3://insports-auth --delete + - aws cloudfront create-invalidation --distribution-id EERIKX9X2SRPJ --paths "/*" + depends_on: + - make-auth + + - name: deploy-old-auth-server + image: node:16-alpine + environment: + SSH_KEY_AUTH: + from_secret: SSH_KEY_AUTH + commands: + - apk add --no-cache openssh-client rsync - eval $(ssh-agent -s) - echo -n "$SSH_KEY_AUTH" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh && chmod 700 ~/.ssh - - ssh-keyscan auth.insports.tv >> ~/.ssh/known_hosts - - rsync -v -r -C build_auth/ ubuntu@auth.insports.tv:/home/ubuntu/ott-auth/src/frontend/ - - rsync -v -r -C build_auth/clients/* ubuntu@auth.insports.tv:/home/ubuntu/ott-auth/src/frontend/templates - - ssh ubuntu@auth.insports.tv 'bash -s' < ./run.sh OTT-2535 docker-compose-stage.yaml + depends_on: + - make-auth + + - name: make-india + image: node:16-alpine + environment: + REACT_APP_STRIPE_PK: + from_secret: REACT_APP_STRIPE_PK + commands: + - make india-build + depends_on: + - npm-install + + - name: deploy-india + image: amazon/aws-cli:latest + environment: + AWS_ACCESS_KEY_ID: + from_secret: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: AWS_SECRET_ACCESS_KEY + AWS_DEFAULT_REGION: + from_secret: AWS_DEFAULT_REGION + commands: + - aws s3 sync build_india s3://insports-india --delete + - aws cloudfront create-invalidation --distribution-id E5DKN8IPOMASO --paths "/*" + depends_on: + - make-india + + - name: make-facr + image: node:16-alpine + environment: + REACT_APP_STRIPE_PK: + from_secret: REACT_APP_STRIPE_PK + commands: + - make facr-build + depends_on: + - npm-install + + - name: deploy-facr + image: amazon/aws-cli:latest + environment: + AWS_ACCESS_KEY_ID: + from_secret: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: AWS_SECRET_ACCESS_KEY + AWS_DEFAULT_REGION: + from_secret: AWS_DEFAULT_REGION + commands: + - aws s3 sync build_facr s3://insports-facr-tv --delete + - aws cloudfront create-invalidation --distribution-id E1ZYJS9RAJO89D --paths "/*" + depends_on: + - make-facr + + - name: make-lff + image: node:16-alpine + environment: + REACT_APP_STRIPE_PK: + from_secret: REACT_APP_STRIPE_PK + commands: + - make lff-build + depends_on: + - npm-install + + - name: deploy-lff + image: amazon/aws-cli:latest + environment: + AWS_ACCESS_KEY_ID: + from_secret: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: AWS_SECRET_ACCESS_KEY + AWS_DEFAULT_REGION: + from_secret: AWS_DEFAULT_REGION + commands: + - aws s3 sync build_lff s3://insports-tv-lff-lv --delete + - aws cloudfront create-invalidation --distribution-id E2127IDW4TEH4S --paths "/*" + depends_on: + - make-lff --- kind: pipeline @@ -131,7 +248,6 @@ steps: ## - ssh-keyscan auth.insports.tv >> ~/.ssh/known_hosts ## - rsync -v -r -C build_auth/ ubuntu@auth.insports.tv:/home/ubuntu/ott-auth/src/frontend/ ## - rsync -v -r -C build_auth/clients/* ubuntu@auth.insports.tv:/home/ubuntu/ott-auth/src/frontend/templates -## - ssh ubuntu@auth.insports.tv 'bash -s' < ./run.sh OTT-2535 docker-compose-stage.yaml --- @@ -536,4 +652,5 @@ steps: - ssh-keyscan auth.test.insports.tv >> ~/.ssh/known_hosts - rsync -v -r -C build_auth/ ubuntu@auth.test.insports.tv:/home/ubuntu/ott-auth/src/frontend/ - rsync -v -r -C build_auth/clients/* ubuntu@auth.test.insports.tv:/home/ubuntu/ott-auth/src/frontend/templates - - ssh ubuntu@auth.test.insports.tv 'bash -s' < ./run.sh OTT-2535-test docker-compose-test.yaml + - aws s3 sync build s3://auth-insports-test --delete + - aws cloudfront create-invalidation --distribution-id E10YI3RFOZZDLZ --paths "/*" diff --git a/Makefile b/Makefile index 293df69c..52d17c36 100644 --- a/Makefile +++ b/Makefile @@ -120,14 +120,24 @@ auth-production-build: facr-build: clean REACT_APP_TYPE=ott \ - REACT_APP_ENV=staging \ - REACT_APP_CLIENT=facr \ + REACT_APP_ENV=production \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + BUILD_PATH=build_facr \ + npm run build + +india-build: clean + REACT_APP_TYPE=ott \ + REACT_APP_ENV=production \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + BUILD_PATH=build_india \ npm run build lff-build: clean REACT_APP_TYPE=ott \ - REACT_APP_ENV=staging \ + REACT_APP_ENV=production \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ REACT_APP_CLIENT=lff \ + BUILD_PATH=build_lff \ npm run build .PHONY: build @@ -151,6 +161,13 @@ preprod: clean REACT_APP_STRIPE_PK=pk_live_ANI76cBhSo69DZUxPmyRVIZW \ npm run build +india-prod: clean + REACT_APP_TYPE=ott \ + REACT_APP_ENV=production \ + REACT_APP_CLIENT=india \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + npm run build && cp -r .well-known build + facr-prod: clean REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ @@ -175,36 +192,6 @@ lff-prod: clean deploy-all: prod preprod facr-prod lff-prod -stage: build-stage - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/wwwroot/ - -a-stage: build-a - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/a-wwwroot/ - -b-stage: build-b - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/b-wwwroot/ - -c-stage: build-c - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/c-wwwroot/ - -d-stage: build-d - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/d-wwwroot/ - -e-stage: build-e - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/e-wwwroot/ - -f-stage: build-f - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/f-wwwroot/ - -g-stage: build-g - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/g-wwwroot/ - -h-stage: build-h - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/h-wwwroot/ - -i-stage: build-i - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott-staging@137.74.33.74:/usr/local/www/ott-staging/i-wwwroot/ - test: npm test diff --git a/package.json b/package.json index 2bcac2b3..8c4c954d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "test:auth": "REACT_APP_TYPE=auth-service react-scripts test", "facr": "REACT_APP_CLIENT=facr react-scripts start", "lff": "REACT_APP_CLIENT=lff react-scripts start", + "india": "REACT_APP_CLIENT=india react-scripts start", "insports": "REACT_APP_CLIENT=insports react-scripts start" }, "dependencies": { diff --git a/run.sh b/run.sh deleted file mode 100644 index 6b88230f..00000000 --- a/run.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -branch=$1 -composefile=$2 - -cd /home/ubuntu/ott-auth -docker-compose -f $composefile down -docker-compose -f $composefile up -d -echo "[>] Deployment done." diff --git a/src/config/clients/index.tsx b/src/config/clients/index.tsx index 72ddd498..aef4ea7d 100644 --- a/src/config/clients/index.tsx +++ b/src/config/clients/index.tsx @@ -4,6 +4,7 @@ import { facr } from './facr' import { instat } from './instat' import { lff } from './lff' import { insports } from './insports' +import { india } from './india' export const currentClient = process.env.REACT_APP_CLIENT || 'insports' @@ -11,9 +12,11 @@ export const isLffClient = currentClient === 'lff' export const isInSportsClient = currentClient === 'insports' export const isInstatClient = currentClient === 'instat' export const isFacrClient = currentClient === 'facr' +export const isIndiaClient = currentClient === 'india' const clients = { facr, + india, insports, instat, lff, diff --git a/src/config/clients/india.tsx b/src/config/clients/india.tsx new file mode 100644 index 00000000..461adbac --- /dev/null +++ b/src/config/clients/india.tsx @@ -0,0 +1,15 @@ +import { + ClientConfig, + ClientIds, + ClientNames, +} from './types' + +import { insports } from './insports' + +export const india: ClientConfig = { + ...insports, + auth: { + clientId: ClientIds.India, + }, + name: ClientNames.India, +} diff --git a/src/config/clients/types.tsx b/src/config/clients/types.tsx index 9cdaca4f..7f45e754 100644 --- a/src/config/clients/types.tsx +++ b/src/config/clients/types.tsx @@ -6,6 +6,7 @@ type StyledCss = ReturnType export enum ClientIds { Facr = 'facr-ott-web', + India = 'india-ott-web', Insports = 'insports-ott-web', Instat = 'ott-web', Lff = 'lff-ott-web', @@ -13,6 +14,7 @@ export enum ClientIds { export enum ClientNames { Facr = 'facr', + India = 'india', Insports = 'insports', Instat = 'instat', Lff = 'lff', diff --git a/src/config/routes.tsx b/src/config/routes.tsx index 8a397573..b307e805 100644 --- a/src/config/routes.tsx +++ b/src/config/routes.tsx @@ -5,15 +5,15 @@ import { ENV, isProduction } from './env' export const APIS = { preproduction: { api: 'https://api.insports.tv', - auth: 'https://api.auth.insports.tv', + auth: 'https://auth.insports.tv', }, production: { api: 'https://api.insports.tv', - auth: 'https://api.auth.insports.tv', + auth: 'https://auth.insports.tv', }, staging: { api: 'https://api.test.insports.tv', - auth: 'https://api.auth.test.insports.tv', + auth: 'https://auth.test.insports.tv', }, } diff --git a/src/features/AuthServiceApp/config/clients/index.tsx b/src/features/AuthServiceApp/config/clients/index.tsx index b1401617..040a93d5 100644 --- a/src/features/AuthServiceApp/config/clients/index.tsx +++ b/src/features/AuthServiceApp/config/clients/index.tsx @@ -4,12 +4,14 @@ import { facr } from './facr' import { insports } from './insports' import { instat } from './instat' import { lff } from './lff' +import { india } from './india' const clients = { [ClientIds.Facr]: facr, [ClientIds.Instat]: instat, [ClientIds.Lff]: lff, [ClientIds.Insports]: insports, + [ClientIds.India]: india, } const params = new URLSearchParams(window.location.search) diff --git a/src/features/AuthServiceApp/config/clients/india.tsx b/src/features/AuthServiceApp/config/clients/india.tsx new file mode 100644 index 00000000..e7e1c99e --- /dev/null +++ b/src/features/AuthServiceApp/config/clients/india.tsx @@ -0,0 +1,9 @@ +import { insports as platformInsports } from 'config/clients/insports' + +import type { ClientConfig } from './types' +import { insports } from './insports' + +export const india: ClientConfig = { + ...platformInsports, + ...insports, +} diff --git a/src/features/AuthStore/helpers.tsx b/src/features/AuthStore/helpers.tsx index 7f8662a1..2faf2926 100644 --- a/src/features/AuthStore/helpers.tsx +++ b/src/features/AuthStore/helpers.tsx @@ -23,6 +23,8 @@ export const getClientNameByRedirectUri = () => { switch (client.name) { case ClientNames.Lff: return 'lff.instat' + case ClientNames.India: + return 'india.insports' case ClientNames.Facr: return ClientNames.Facr case ClientNames.Instat: @@ -35,7 +37,12 @@ export const getClientNameByRedirectUri = () => { const redirectUrl = () => { const clientName = getClientNameByRedirectUri() switch (true) { - case (process.env.NODE_ENV === 'development' || client.name === 'lff' || client.name === 'facr'): + case ( + process.env.NODE_ENV === 'development' + || client.name === 'lff' + || client.name === 'facr' + || client.name === 'india' + ): return `${window.origin}/redirect` case (ENV === 'staging' || ENV === 'preproduction'): return `https://${stageENV}.insports.tv/redirect` diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 65952d05..56a364a5 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -3,7 +3,7 @@ declare namespace NodeJS { export interface ProcessEnv { - REACT_APP_CLIENT: 'instat' | 'facr' | 'lff' | 'insports', + REACT_APP_CLIENT: 'instat' | 'facr' | 'lff' | 'insports' | 'india', REACT_APP_ENV: 'production' | 'preproduction' | 'staging', REACT_APP_STAGE: 'staging' | 'test-a' | 'test-b' | 'test-c' | 'test-d' | 'test-e' | 'test-f' | 'test-g' | 'test-h' | 'test-i' | 'test-j' | 'test', REACT_APP_TYPE: 'auth-service' | 'ott', -- 2.30.2 From 1dc9da94fcb1ccb425cbb6908020257d54529a20 Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Tue, 29 Nov 2022 17:16:49 +0300 Subject: [PATCH 02/31] fix(#india): fix build india --- .drone.yml | 11 ++++++++--- .gitignore | 3 +++ Makefile | 50 ++++++++++++++++++++------------------------------ 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/.drone.yml b/.drone.yml index c86168c5..cdd9855e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -30,6 +30,7 @@ steps: REACT_APP_STRIPE_PK: from_secret: REACT_APP_STRIPE_PK commands: + - apk add --no-cache make - make prod depends_on: - npm-install @@ -57,6 +58,7 @@ steps: REACT_APP_STRIPE_PK: from_secret: REACT_APP_STRIPE_PK commands: + - apk add --no-cache make - make auth-production-build depends_on: - npm-install @@ -95,7 +97,8 @@ steps: REACT_APP_STRIPE_PK: from_secret: REACT_APP_STRIPE_PK commands: - - make india-build + - apk add --no-cache make + - make india-prod depends_on: - npm-install @@ -120,7 +123,8 @@ steps: REACT_APP_STRIPE_PK: from_secret: REACT_APP_STRIPE_PK commands: - - make facr-build + - apk add --no-cache make + - make facr-prod depends_on: - npm-install @@ -145,7 +149,8 @@ steps: REACT_APP_STRIPE_PK: from_secret: REACT_APP_STRIPE_PK commands: - - make lff-build + - apk add --no-cache make + - make lff-prod depends_on: - npm-install diff --git a/.gitignore b/.gitignore index 932519ba..f8d1d08e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ # production /build /build_auth +/build_india +/build_facr +/build_lff # misc .DS_Store diff --git a/Makefile b/Makefile index 52d17c36..128c4b80 100644 --- a/Makefile +++ b/Makefile @@ -120,25 +120,21 @@ auth-production-build: facr-build: clean REACT_APP_TYPE=ott \ - REACT_APP_ENV=production \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ - BUILD_PATH=build_facr \ - npm run build + REACT_APP_ENV=staging \ + REACT_APP_CLIENT=facr \ + npm run build india-build: clean REACT_APP_TYPE=ott \ - REACT_APP_ENV=production \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ - BUILD_PATH=build_india \ - npm run build + REACT_APP_ENV=staging \ + REACT_APP_CLIENT=india \ + npm run build lff-build: clean REACT_APP_TYPE=ott \ - REACT_APP_ENV=production \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + REACT_APP_ENV=staging \ REACT_APP_CLIENT=lff \ - BUILD_PATH=build_lff \ - npm run build + npm run build .PHONY: build @@ -149,10 +145,6 @@ prod: clean REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ npm run build && cp -r .well-known build -# rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@de.instat.tv:/usr/local/www/ott/wwwroot/ -# rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@fr.instat.tv:/usr/local/www/ott/wwwroot/ -# rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@137.74.33.74:/usr/local/www/ott/wwwroot/ - preprod: clean REACT_APP_TYPE=ott \ REACT_APP_ENV=preproduction \ @@ -161,34 +153,32 @@ preprod: clean REACT_APP_STRIPE_PK=pk_live_ANI76cBhSo69DZUxPmyRVIZW \ npm run build -india-prod: clean +india-prod: + rm -rf build_india && \ REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ REACT_APP_CLIENT=india \ REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ - npm run build && cp -r .well-known build + BUILD_PATH=build_india \ + npm run build && cp -r .well-known build_india -facr-prod: clean +facr-prod: + rm -rf build_facr && \ REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ REACT_APP_CLIENT=facr \ - npm run build - - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@de.instat.tv:/usr/local/www/ott/facr-wwwroot/ - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@fr.instat.tv:/usr/local/www/ott/facr-wwwroot/ - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@137.74.33.74:/usr/local/www/ott/facr-wwwroot/ + BUILD_PATH=build_facr \ + npm run build && cp -r .well-known build_facr -lff-prod: clean +lff-prod: + rm -rf build_lff && \ REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ REACT_APP_CLIENT=lff \ - npm run build - - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@de.instat.tv:/usr/local/www/ott/lff-wwwroot/ - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@fr.instat.tv:/usr/local/www/ott/lff-wwwroot/ - rsync -zavP --delete-before build/ -e 'ssh -p 666' ott@137.74.33.74:/usr/local/www/ott/lff-wwwroot/ + BUILD_PATH=build_lff \ + npm run build && cp -r .well-known build_lff deploy-all: prod preprod facr-prod lff-prod -- 2.30.2 From 998b7176de8d48d510ba99980a220254ef223735 Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov home Date: Wed, 30 Nov 2022 15:10:44 +0700 Subject: [PATCH 03/31] fix deploy auth test --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index cdd9855e..610a70ee 100644 --- a/.drone.yml +++ b/.drone.yml @@ -657,5 +657,5 @@ steps: - ssh-keyscan auth.test.insports.tv >> ~/.ssh/known_hosts - rsync -v -r -C build_auth/ ubuntu@auth.test.insports.tv:/home/ubuntu/ott-auth/src/frontend/ - rsync -v -r -C build_auth/clients/* ubuntu@auth.test.insports.tv:/home/ubuntu/ott-auth/src/frontend/templates - - aws s3 sync build s3://auth-insports-test --delete + - aws s3 sync build_auth s3://auth-insports-test --delete - aws cloudfront create-invalidation --distribution-id E10YI3RFOZZDLZ --paths "/*" -- 2.30.2 From 2d445cbc0213350a9e9411958c89c04d00d53063 Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Wed, 30 Nov 2022 12:32:50 +0300 Subject: [PATCH 04/31] style(#188): add tunis config to auth --- package.json | 1 + public/images/tunis-logo.svg | 29 ++++++++ public/images/tunis_auth_logo.svg | 36 ++++++++++ src/config/clients/index.tsx | 3 + src/config/clients/tunis.tsx | 57 ++++++++++++++++ src/config/clients/types.tsx | 2 + .../components/ConfirmPopup/styled.tsx | 3 + .../components/RegisterPopup/index.tsx | 8 --- .../components/RegisterPopup/styled.tsx | 23 ++----- .../AuthServiceApp/config/clients/index.tsx | 2 + .../AuthServiceApp/config/clients/tunis.tsx | 67 +++++++++++++++++++ .../AuthServiceApp/config/clients/types.tsx | 1 + src/features/AuthStore/helpers.tsx | 3 + src/features/CompanyInfo/index.tsx | 2 + src/react-app-env.d.ts | 2 +- 15 files changed, 211 insertions(+), 28 deletions(-) create mode 100644 public/images/tunis-logo.svg create mode 100644 public/images/tunis_auth_logo.svg create mode 100644 src/config/clients/tunis.tsx create mode 100644 src/features/AuthServiceApp/config/clients/tunis.tsx diff --git a/package.json b/package.json index 8c4c954d..9eba47e8 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "facr": "REACT_APP_CLIENT=facr react-scripts start", "lff": "REACT_APP_CLIENT=lff react-scripts start", "india": "REACT_APP_CLIENT=india react-scripts start", + "tunis": "REACT_APP_CLIENT=tunis react-scripts start", "insports": "REACT_APP_CLIENT=insports react-scripts start" }, "dependencies": { diff --git a/public/images/tunis-logo.svg b/public/images/tunis-logo.svg new file mode 100644 index 00000000..9f66058e --- /dev/null +++ b/public/images/tunis-logo.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/tunis_auth_logo.svg b/public/images/tunis_auth_logo.svg new file mode 100644 index 00000000..1b26b37c --- /dev/null +++ b/public/images/tunis_auth_logo.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/config/clients/index.tsx b/src/config/clients/index.tsx index aef4ea7d..f6835d60 100644 --- a/src/config/clients/index.tsx +++ b/src/config/clients/index.tsx @@ -5,6 +5,7 @@ import { instat } from './instat' import { lff } from './lff' import { insports } from './insports' import { india } from './india' +import { tunis } from './tunis' export const currentClient = process.env.REACT_APP_CLIENT || 'insports' @@ -13,6 +14,7 @@ export const isInSportsClient = currentClient === 'insports' export const isInstatClient = currentClient === 'instat' export const isFacrClient = currentClient === 'facr' export const isIndiaClient = currentClient === 'india' +export const isTunisClient = currentClient === 'tunis' const clients = { facr, @@ -20,6 +22,7 @@ const clients = { insports, instat, lff, + tunis, } export const client: ClientConfig = clients[currentClient] diff --git a/src/config/clients/tunis.tsx b/src/config/clients/tunis.tsx new file mode 100644 index 00000000..6764be26 --- /dev/null +++ b/src/config/clients/tunis.tsx @@ -0,0 +1,57 @@ +import { css } from 'styled-components/macro' + +import { + ClientConfig, + ClientIds, + ClientNames, +} from './types' + +const randomHash = () => ( + (Math.random() ** Math.random()) * 9999999999999999 +) + +export const tunis: ClientConfig = { + auth: { + clientId: ClientIds.Tunis, + metaDataUrlParams: `?hash=${randomHash()}`, + }, + defaultLanguage: 'fr', + description: 'Live sports streaming platform. All matches playing under the auspices of Czech Republic FA. Access to full matches, various player playlists, and highlights. Free access in the Czech Republic. Available across all devices', + disabledPreferences: false, + name: ClientNames.Tunis, + privacyLink: '/privacy-policy-and-statement', + showSearch: false, + styles: { + background: '', + homePageHeader: css` + background: radial-gradient( + 160.34% 257.27% at -7.45% 162.22%, + #2AB7AA 3.27%, + #02505C 43.69%, #0B2E4D 100%); + `, + logo: 'tunis-logo.svg', + logoHeight: 6.3, + logoLeft: 1.1, + logoTop: 1.74, + logoWidth: 8.25, + matchLogoHeight: 3.4, + matchLogoTopMargin: 0.9, + matchLogoWidth: 4.5, + matchPageMobileHeaderLogo: css` + width: 35px; + height: 25px; + top: 2px; + `, + mobileHeaderLogo: css` + width: 48px; + height: 37px; + `, + userAccountLogo: css` + width: 4.56rem; + height: 3.488rem; + `, + }, + termsLink: '/terms-and-conditions?client_id=facr-ott-web', + title: 'FACR.TV - The home of Czech football streaming', + userAccountLinksDisabled: true, +} diff --git a/src/config/clients/types.tsx b/src/config/clients/types.tsx index 7f45e754..98c61297 100644 --- a/src/config/clients/types.tsx +++ b/src/config/clients/types.tsx @@ -10,6 +10,7 @@ export enum ClientIds { Insports = 'insports-ott-web', Instat = 'ott-web', Lff = 'lff-ott-web', + Tunis = 'tunis-ott-web', } export enum ClientNames { @@ -18,6 +19,7 @@ export enum ClientNames { Insports = 'insports', Instat = 'instat', Lff = 'lff', + Tunis = 'tunis', } export type ClientConfig = { diff --git a/src/features/AuthServiceApp/components/ConfirmPopup/styled.tsx b/src/features/AuthServiceApp/components/ConfirmPopup/styled.tsx index 1123334b..91a89512 100644 --- a/src/features/AuthServiceApp/components/ConfirmPopup/styled.tsx +++ b/src/features/AuthServiceApp/components/ConfirmPopup/styled.tsx @@ -11,6 +11,8 @@ import { HeaderTitle, } from 'features/AuthServiceApp/components/RegisterPopup/styled' +import { client } from '../../config/clients/index' + export const Modal = styled(BaseModal)` ${ModalWindow} { min-height: 220px; @@ -59,6 +61,7 @@ export const ScApplyButton = styled(ApplyButton)` font-size: 14px; ` : ''}; + ${client.styles.popupApplyButton} ` export const ScLink = styled.a` diff --git a/src/features/AuthServiceApp/components/RegisterPopup/index.tsx b/src/features/AuthServiceApp/components/RegisterPopup/index.tsx index 8aef84d2..6d8d78b5 100644 --- a/src/features/AuthServiceApp/components/RegisterPopup/index.tsx +++ b/src/features/AuthServiceApp/components/RegisterPopup/index.tsx @@ -25,11 +25,6 @@ export const RegisterPopup = (props: Props) => { isModalOpen, } = props - // const handleNewConfirmation = () => { - // // TODO дописать логику для отправки доп. письма, может понадобится, когда допишут бэк - // // console.log('send new confirmation') - // } - return ( @@ -53,9 +48,6 @@ export const RegisterPopup = (props: Props) => {
handleModalClose()}>Ok - {/* - - */}
diff --git a/src/features/AuthServiceApp/components/RegisterPopup/styled.tsx b/src/features/AuthServiceApp/components/RegisterPopup/styled.tsx index f8877dd5..a661f487 100644 --- a/src/features/AuthServiceApp/components/RegisterPopup/styled.tsx +++ b/src/features/AuthServiceApp/components/RegisterPopup/styled.tsx @@ -7,7 +7,9 @@ import { ModalWindow } from 'features/Modal/styled' import { Modal as BaseModal } from 'features/Modal' import { Header as BaseHeader } from 'features/PopupComponents' -import { ButtonSolid, ButtonOutline } from 'features/Common' +import { ButtonSolid } from 'features/Common' + +import { client } from '../../config/clients' export const Modal = styled(BaseModal)` background-color: rgba(0, 0, 0, 0.7); @@ -139,26 +141,9 @@ export const ApplyButton = styled(ButtonSolid)` } ` : ''}; + ${client.styles.popupApplyButton} ` -export const SendConfirmationButton = styled(ButtonOutline)` - width: 100%; - height: 50px; - border-radius: 5px; - font-weight: 500; - font-size: 20px; - ${isMobileDevice - ? css` - @media ${devices.mobile}{ - width: 100%; - } - - @media (orientation: landscape){ - width: 290px; - } - ` - : ''}; -` export const Text = styled.span` margin-bottom: 20px; ` diff --git a/src/features/AuthServiceApp/config/clients/index.tsx b/src/features/AuthServiceApp/config/clients/index.tsx index 040a93d5..6de84332 100644 --- a/src/features/AuthServiceApp/config/clients/index.tsx +++ b/src/features/AuthServiceApp/config/clients/index.tsx @@ -5,6 +5,7 @@ import { insports } from './insports' import { instat } from './instat' import { lff } from './lff' import { india } from './india' +import { tunis } from './tunis' const clients = { [ClientIds.Facr]: facr, @@ -12,6 +13,7 @@ const clients = { [ClientIds.Lff]: lff, [ClientIds.Insports]: insports, [ClientIds.India]: india, + [ClientIds.Tunis]: tunis, } const params = new URLSearchParams(window.location.search) diff --git a/src/features/AuthServiceApp/config/clients/tunis.tsx b/src/features/AuthServiceApp/config/clients/tunis.tsx new file mode 100644 index 00000000..b587b6e8 --- /dev/null +++ b/src/features/AuthServiceApp/config/clients/tunis.tsx @@ -0,0 +1,67 @@ +import styled, { css } from 'styled-components/macro' + +import { tunis as platformTunis } from 'config/clients/tunis' + +import { isMobileDevice } from 'config/userAgent' +import type { ClientConfig } from './types' + +const Background = styled.div` + position: relative; + width: 100%; + height: 100vh; + display: flex; + justify-content: center; + background: linear-gradient(0deg, rgba(2, 46, 48, 0.3), + rgba(2, 46, 48, 0.3)), + radial-gradient(152.89% 271.81% at 0% 96.71%, #2AB7AA 3.27%, #02505C 43.69%, #0B2E4D 100%); +` + +export const tunis: ClientConfig = { + ...platformTunis, + background: Background, + styles: { + centerBlock: css` + margin-top: 9.15rem; + ${isMobileDevice ? css` + margin-top: 107px; + @media screen and (orientation: landscape) { + width: 290px; + margin: auto; + } + ` : ''}; + `, + input: css` + background-color: transparent; + :not(:last-of-type) { + border-color: ${({ theme }) => theme.colors.white}; + } + `, + inputGroup: css` + border: 1px solid ${({ theme }) => theme.colors.white}; + `, + loader: css` + color: #0B2E4D; + `, + logo: css` + background-image: url(/images/tunis_auth_logo.svg); + width: 200px; + height: 178px; + margin-bottom: 1.82rem; + + ${isMobileDevice ? css` + margin-bottom: 20px; + width: 130px; + height: 100px; + ` : ''} + `, + popupApplyButton: css` + background-color: #0E8F84; + color: ${({ theme }) => theme.colors.white}; + `, + popupLoader: '#FFFFFF', + submitButton: css` + background-color: ${({ theme }) => theme.colors.white}; + color: #0B2E4D; + `, + }, +} diff --git a/src/features/AuthServiceApp/config/clients/types.tsx b/src/features/AuthServiceApp/config/clients/types.tsx index 5a305af6..0542b57a 100644 --- a/src/features/AuthServiceApp/config/clients/types.tsx +++ b/src/features/AuthServiceApp/config/clients/types.tsx @@ -12,6 +12,7 @@ export type ClientConfig = { background: FC<{ children: ReactNode }>, defaultLanguage: string, description: string, + isHideSelectLanguages?: boolean, name: ClientNames, privacyLink: string, styles: { diff --git a/src/features/AuthStore/helpers.tsx b/src/features/AuthStore/helpers.tsx index 2faf2926..d9d1f050 100644 --- a/src/features/AuthStore/helpers.tsx +++ b/src/features/AuthStore/helpers.tsx @@ -25,6 +25,8 @@ export const getClientNameByRedirectUri = () => { return 'lff.instat' case ClientNames.India: return 'india.insports' + case ClientNames.Tunis: + return ClientNames.Tunis case ClientNames.Facr: return ClientNames.Facr case ClientNames.Instat: @@ -42,6 +44,7 @@ const redirectUrl = () => { || client.name === 'lff' || client.name === 'facr' || client.name === 'india' + || client.name === 'tunis' ): return `${window.origin}/redirect` case (ENV === 'staging' || ENV === 'preproduction'): diff --git a/src/features/CompanyInfo/index.tsx b/src/features/CompanyInfo/index.tsx index 12c5b4a4..1cc5a30d 100644 --- a/src/features/CompanyInfo/index.tsx +++ b/src/features/CompanyInfo/index.tsx @@ -39,6 +39,8 @@ export const CompanyInfo = ({ ) + case ClientNames.Tunis: + return '' case ClientNames.Lff: return ( diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 56a364a5..9740e798 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -3,7 +3,7 @@ declare namespace NodeJS { export interface ProcessEnv { - REACT_APP_CLIENT: 'instat' | 'facr' | 'lff' | 'insports' | 'india', + REACT_APP_CLIENT: 'instat' | 'facr' | 'lff' | 'insports' | 'india' | 'tunis', REACT_APP_ENV: 'production' | 'preproduction' | 'staging', REACT_APP_STAGE: 'staging' | 'test-a' | 'test-b' | 'test-c' | 'test-d' | 'test-e' | 'test-f' | 'test-g' | 'test-h' | 'test-i' | 'test-j' | 'test', REACT_APP_TYPE: 'auth-service' | 'ott', -- 2.30.2 From 66ddaf141e198c6677c22d125dcab9b17b994ce2 Mon Sep 17 00:00:00 2001 From: Rakov Roman Date: Fri, 18 Nov 2022 15:03:13 +0300 Subject: [PATCH 05/31] fix(#3099): save match stats --- src/config/routes.tsx | 7 ++++ .../MultiSourcePlayer/hooks/index.tsx | 36 +++++++++++++++++-- src/features/StreamPlayer/hooks/index.tsx | 32 +++++++++++++++-- src/hooks/index.tsx | 1 + src/requests/index.tsx | 1 + src/requests/saveMatchStats.tsx | 30 ++++++++++++++++ 6 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 src/requests/saveMatchStats.tsx diff --git a/src/config/routes.tsx b/src/config/routes.tsx index b307e805..178b420b 100644 --- a/src/config/routes.tsx +++ b/src/config/routes.tsx @@ -17,8 +17,15 @@ export const APIS = { }, } +const VIEWS_APIS = { + preproduction: 'https://views.insports.tv', + production: 'https://views.insports.tv', + staging: 'https://views.test.insports.tv', +} + const env = isProduction ? ENV : readSelectedApi() ?? ENV +export const VIEWS_API = VIEWS_APIS[env] export const AUTH_SERVICE = APIS[env].auth export const API_ROOT = APIS[env].api export const DATA_URL = `${API_ROOT}/data` diff --git a/src/features/MultiSourcePlayer/hooks/index.tsx b/src/features/MultiSourcePlayer/hooks/index.tsx index 63c0d73a..25a261fb 100644 --- a/src/features/MultiSourcePlayer/hooks/index.tsx +++ b/src/features/MultiSourcePlayer/hooks/index.tsx @@ -14,9 +14,18 @@ import { useVolume } from 'features/VideoPlayer/hooks/useVolume' import { useNoNetworkPopupStore } from 'features/NoNetworkPopup' import { useMatchPageStore } from 'features/MatchPage/store' -import { useEventListener, useObjectState } from 'hooks' +import { + useEventListener, + useInterval, + useObjectState, + usePageParams, +} from 'hooks' -import { MatchInfo } from 'requests' +import { + intervalMs, + MatchInfo, + saveMatchStats, +} from 'requests' import { useProgressChangeHandler } from './useProgressChangeHandler' import { usePlayingHandlers } from './usePlayingHandlers' @@ -63,6 +72,8 @@ export const useMultiSourcePlayer = ({ playNextEpisode, } = useMatchPageStore() + const { profileId, sportType } = usePageParams() + const numberOfChapters = size(chapters) const [ { @@ -267,6 +278,27 @@ export const useMultiSourcePlayer = ({ } }, [ready, videoRef]) + // ведем статистику просмотра матча + const { start: startCollectingStats, stop: stopCollectingStats } = useInterval({ + callback: () => { + saveMatchStats({ + matchId: profileId, + matchSecond: videoRef.current?.currentTime!, + sportType, + }) + }, + intervalDuration: intervalMs, + startImmediate: false, + }) + + useEffect(() => { + if (playing) { + startCollectingStats() + } else { + stopCollectingStats() + } + }, [playing, startCollectingStats, stopCollectingStats]) + return { activeChapterIndex, activePlayer, diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx index 91ef416f..d46820b2 100644 --- a/src/features/StreamPlayer/hooks/index.tsx +++ b/src/features/StreamPlayer/hooks/index.tsx @@ -11,8 +11,12 @@ import isEmpty from 'lodash/isEmpty' import { isIOS } from 'config/userAgent' -import { useObjectState } from 'hooks/useObjectState' -import { useEventListener } from 'hooks/useEventListener' +import { + useObjectState, + useEventListener, + usePageParams, + useInterval, +} from 'hooks' import type { TSetCircleAnimation } from 'features/CircleAnimationBar' import type { Chapters } from 'features/StreamPlayer/types' @@ -21,6 +25,8 @@ import { useNoNetworkPopupStore } from 'features/NoNetworkPopup' import { useLiveMatch } from 'features/MatchPage/components/LiveMatch/hooks' import { useLexicsStore } from 'features/LexicsStore' +import { intervalMs, saveMatchStats } from 'requests' + import { REWIND_SECONDS } from '../config' import { useHlsPlayer } from './useHlsPlayer' import { useFullscreen } from './useFullscreen' @@ -88,6 +94,7 @@ export const useVideoPlayer = ({ selectedPlaylist, } = useLiveMatch() const { lang } = useLexicsStore() + const { profileId, sportType } = usePageParams() const { url } = chapters[0] ?? { url: '' } const numberOfChapters = size(chapters) @@ -427,6 +434,27 @@ export const useVideoPlayer = ({ ? 'La transmisión en vivo no está disponible temporalmente en dispositivos iOS' : 'Live streaming is temporarily unavailable on iOS devices' + // ведем статистику просмотра матча + const { start: startCollectingStats, stop: stopCollectingStats } = useInterval({ + callback: () => { + saveMatchStats({ + matchId: profileId, + matchSecond: videoRef.current?.currentTime!, + sportType, + }) + }, + intervalDuration: intervalMs, + startImmediate: false, + }) + + useEffect(() => { + if (playing) { + startCollectingStats() + } else { + stopCollectingStats() + } + }, [playing, startCollectingStats, stopCollectingStats]) + return { activeChapterIndex, allPlayedProgress: playedProgress + getActiveChapter().startMs, diff --git a/src/hooks/index.tsx b/src/hooks/index.tsx index f318328b..8219ac0e 100644 --- a/src/hooks/index.tsx +++ b/src/hooks/index.tsx @@ -4,3 +4,4 @@ export * from './useStorage' export * from './useInterval' export * from './useEventListener' export * from './useObjectState' +export * from './usePageParams' diff --git a/src/requests/index.tsx b/src/requests/index.tsx index f4f0e777..b8074c36 100644 --- a/src/requests/index.tsx +++ b/src/requests/index.tsx @@ -24,3 +24,4 @@ export * from './getMatchPlaylists' export * from './getPlayerPlaylists' export * from './getSubscriptions' export * from './buySubscription' +export * from './saveMatchStats' diff --git a/src/requests/saveMatchStats.tsx b/src/requests/saveMatchStats.tsx new file mode 100644 index 00000000..2307ecad --- /dev/null +++ b/src/requests/saveMatchStats.tsx @@ -0,0 +1,30 @@ +import { SportTypes, VIEWS_API } from 'config' + +import { callApi } from 'helpers' + +type Props = { + matchId: number, + matchSecond: number, + sportType: SportTypes, +} + +export const intervalMs = 15000 + +export const saveMatchStats = ({ + matchId, + matchSecond, + sportType, +}: Props) => { + const url = `${VIEWS_API}/user/view` + + const config = { + body: { + interval: intervalMs / 1000, + match_id: matchId, + second: matchSecond, + sport_id: sportType, + }, + } + + return callApi({ config, url }) +} -- 2.30.2 From 5f47bbce1bce1811d1709033e765bc4cf36a5478 Mon Sep 17 00:00:00 2001 From: Farber Denis Date: Fri, 18 Nov 2022 12:31:11 +0300 Subject: [PATCH 06/31] fix(#in178): pip fix fix($in178): min fix fix(#in178): attr check add fix(#in178): auto pip conditions fixed fix(#178): auto pip min fix --- src/components/PictureInPicture/PiP.tsx | 18 +++++++++++++++++- src/features/MatchPage/index.tsx | 1 + .../Controls/Components/ControlsWeb/index.tsx | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/PictureInPicture/PiP.tsx b/src/components/PictureInPicture/PiP.tsx index b56290c9..30f8661e 100644 --- a/src/components/PictureInPicture/PiP.tsx +++ b/src/components/PictureInPicture/PiP.tsx @@ -1,6 +1,7 @@ import { memo, RefObject, + useEffect, } from 'react' import styled from 'styled-components/macro' @@ -15,10 +16,11 @@ const PipWrapper = styled.div` ` type PipProps = { + isPlaying: boolean, videoRef: RefObject, } -export const PiP = memo(({ videoRef }: PipProps) => { +export const PiP = memo(({ isPlaying, videoRef }: PipProps) => { const togglePip = async () => { try { if ( @@ -33,6 +35,20 @@ export const PiP = memo(({ videoRef }: PipProps) => { } } + useEffect(() => { + window.addEventListener('visibilitychange', async () => { + if ( + document.hidden === true + && document.pictureInPictureEnabled + && videoRef.current !== document.pictureInPictureElement + && videoRef.current?.hidden === false + && isPlaying + ) { + await videoRef.current?.requestPictureInPicture() + } + }) + }, [videoRef, isPlaying]) + return ( diff --git a/src/features/MatchPage/index.tsx b/src/features/MatchPage/index.tsx index ed4ec6ad..112a6a4d 100644 --- a/src/features/MatchPage/index.tsx +++ b/src/features/MatchPage/index.tsx @@ -82,6 +82,7 @@ const MatchPageComponent = () => { const sportName = history.location.pathname.split('/')[1] history.push(`/${sportName}/tournaments/${profile.tournament.id}`) } + return ( diff --git a/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx b/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx index a98c2f18..5c0f2d7e 100644 --- a/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx +++ b/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx @@ -114,7 +114,7 @@ export const ControlsWeb = (controlsProps: { props: ControlsPropsExtended }) => )} {document.pictureInPictureEnabled && ( - + )} Date: Thu, 24 Nov 2022 11:41:25 +0400 Subject: [PATCH 07/31] feat(in-132): videoplayer bugfix --- src/features/MatchPage/store/hooks/index.tsx | 4 ++-- src/features/StreamPlayer/hooks/index.tsx | 6 +++++- .../StreamPlayer/hooks/useHlsPlayer.tsx | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index 8b472265..58a33ed2 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -57,11 +57,11 @@ export const useMatchPage = () => { let getIntervalMatch: ReturnType if (matchProfile?.live && !matchProfile.youtube_link) { getIntervalMatch = setInterval( - () => getMatchInfo(sportType, matchId).then(setMatchProfile), 1000 * 60 * 3, + () => getMatchInfo(sportType, matchId).then(setMatchProfile), 5000, ) } return () => clearInterval(getIntervalMatch) - }, [matchProfile, sportType, matchId]) + }) const { events, diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx index d46820b2..28573a8b 100644 --- a/src/features/StreamPlayer/hooks/index.tsx +++ b/src/features/StreamPlayer/hooks/index.tsx @@ -98,7 +98,11 @@ export const useVideoPlayer = ({ const { url } = chapters[0] ?? { url: '' } const numberOfChapters = size(chapters) - const { hls, videoRef } = useHlsPlayer(url, resumeFrom) + const { hls, videoRef } = useHlsPlayer({ + isLive, + resumeFrom, + src: url, + }) const [isLiveTime, setIsLiveTime] = useState(false) const [isPausedTime, setIsPausedTime] = useState(false) const [pausedProgress, setPausedProgress] = useState(0) diff --git a/src/features/StreamPlayer/hooks/useHlsPlayer.tsx b/src/features/StreamPlayer/hooks/useHlsPlayer.tsx index 34c995c4..2a04c637 100644 --- a/src/features/StreamPlayer/hooks/useHlsPlayer.tsx +++ b/src/features/StreamPlayer/hooks/useHlsPlayer.tsx @@ -9,7 +9,17 @@ import isNumber from 'lodash/isNumber' import { streamConfig } from '../config' -export const useHlsPlayer = (src: string, resumeFrom?: number) => { +type useHlsPlayerType = { + isLive?: boolean, + resumeFrom?: number, + src: string, +} + +export const useHlsPlayer = ({ + isLive, + resumeFrom, + src, +}: useHlsPlayerType) => { const hls = useMemo(() => { if (!Hls.isSupported()) return null @@ -19,7 +29,11 @@ export const useHlsPlayer = (src: string, resumeFrom?: number) => { } return new Hls(newStreamConfig) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [resumeFrom, src]) + }, [ + resumeFrom, + src, + isLive, + ]) const videoRef = useRef(null) -- 2.30.2 From d1f0a6e4b529e1ac274c05724cf4c98a4513f721 Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov home Date: Mon, 5 Dec 2022 14:59:01 +0700 Subject: [PATCH 08/31] add consistent deploy --- .drone.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 610a70ee..4709673f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -35,7 +35,7 @@ steps: depends_on: - npm-install - - name: deploy script + - name: deploy-prod image: amazon/aws-cli:latest environment: AWS_ACCESS_KEY_ID: @@ -77,6 +77,7 @@ steps: - aws cloudfront create-invalidation --distribution-id EERIKX9X2SRPJ --paths "/*" depends_on: - make-auth + - deploy-prod - name: deploy-old-auth-server image: node:16-alpine @@ -116,6 +117,7 @@ steps: - aws cloudfront create-invalidation --distribution-id E5DKN8IPOMASO --paths "/*" depends_on: - make-india + - deploy-S3-auth - name: make-facr image: node:16-alpine @@ -142,6 +144,7 @@ steps: - aws cloudfront create-invalidation --distribution-id E1ZYJS9RAJO89D --paths "/*" depends_on: - make-facr + - deploy-india - name: make-lff image: node:16-alpine @@ -168,6 +171,7 @@ steps: - aws cloudfront create-invalidation --distribution-id E2127IDW4TEH4S --paths "/*" depends_on: - make-lff + - deploy-facr --- kind: pipeline -- 2.30.2 From 5bffc91ad8feda320be6e20625a4965216263c94 Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Tue, 6 Dec 2022 14:50:23 +0300 Subject: [PATCH 09/31] fix(#206): change link for india - about the project --- src/config/clients/india.tsx | 1 + src/config/clients/types.tsx | 1 + src/features/UserAccount/index.tsx | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/config/clients/india.tsx b/src/config/clients/india.tsx index 461adbac..0eac3a13 100644 --- a/src/config/clients/india.tsx +++ b/src/config/clients/india.tsx @@ -8,6 +8,7 @@ import { insports } from './insports' export const india: ClientConfig = { ...insports, + about_the_project: 'https://prsolution.pro', auth: { clientId: ClientIds.India, }, diff --git a/src/config/clients/types.tsx b/src/config/clients/types.tsx index 98c61297..febb8d15 100644 --- a/src/config/clients/types.tsx +++ b/src/config/clients/types.tsx @@ -23,6 +23,7 @@ export enum ClientNames { } export type ClientConfig = { + about_the_project?: string, auth: { clientId: ClientIds, metaDataUrlParams?: string, diff --git a/src/features/UserAccount/index.tsx b/src/features/UserAccount/index.tsx index a1fd24bd..553a5524 100644 --- a/src/features/UserAccount/index.tsx +++ b/src/features/UserAccount/index.tsx @@ -77,7 +77,7 @@ const UserAccount = () => { {!isLffClient && !isInSportsClient && ( -- 2.30.2 From 4c51ae8ce2733a0608eef228c156dc60288d646d Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov home Date: Mon, 5 Dec 2022 14:54:59 +0700 Subject: [PATCH 10/31] add deploy diwansport.net --- .drone.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.drone.yml b/.drone.yml index 4709673f..db78f563 100644 --- a/.drone.yml +++ b/.drone.yml @@ -173,6 +173,32 @@ steps: - make-lff - deploy-facr + - name: make-diwansport + image: node:16-alpine + environment: + REACT_APP_STRIPE_PK: + from_secret: REACT_APP_STRIPE_PK + commands: + - apk add --no-cache make + - make diwansport-prod + depends_on: + - npm-install + + - name: deploy-lff + image: amazon/aws-cli:latest + environment: + AWS_ACCESS_KEY_ID: + from_secret: AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: AWS_SECRET_ACCESS_KEY + AWS_DEFAULT_REGION: + from_secret: AWS_DEFAULT_REGION + commands: + - aws s3 sync build_insports-diwansport s3://insports-diwansport --delete + - aws cloudfront create-invalidation --distribution-id E3LKAH6TR4O2JL --paths "/*" + depends_on: + - make-diwansport + --- kind: pipeline type: docker -- 2.30.2 From 7d6334839157fe7d6a1b211341134d35a5b458fa Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov home Date: Mon, 5 Dec 2022 15:05:07 +0700 Subject: [PATCH 11/31] add consistent deploy diwansport.net --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index db78f563..66e5e6a6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -198,6 +198,7 @@ steps: - aws cloudfront create-invalidation --distribution-id E3LKAH6TR4O2JL --paths "/*" depends_on: - make-diwansport + - deploy-lff --- kind: pipeline -- 2.30.2 From 8e19b230cc489e73148396fdaebae3168c6d1f29 Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Thu, 8 Dec 2022 11:20:42 +0300 Subject: [PATCH 12/31] fix(#210): add link to smartbanner for ios --- .drone.yml | 2 +- src/components/SmartBanner/index.tsx | 5 ++++- src/config/clients/insports.tsx | 1 + src/config/clients/types.tsx | 1 + src/config/userAgent.tsx | 2 ++ src/features/HeaderMobile/index.tsx | 16 ++++++++++++---- src/features/HomePage/hooks.tsx | 4 +++- src/features/HomePage/index.tsx | 2 ++ src/requests/getUserInfo.tsx | 1 + 9 files changed, 27 insertions(+), 7 deletions(-) diff --git a/.drone.yml b/.drone.yml index 66e5e6a6..4ab93d7c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -184,7 +184,7 @@ steps: depends_on: - npm-install - - name: deploy-lff + - name: deploy-diwansport image: amazon/aws-cli:latest environment: AWS_ACCESS_KEY_ID: diff --git a/src/components/SmartBanner/index.tsx b/src/components/SmartBanner/index.tsx index 97f24a58..817341d4 100644 --- a/src/components/SmartBanner/index.tsx +++ b/src/components/SmartBanner/index.tsx @@ -1,6 +1,7 @@ import { Icon } from 'features/Icon' import { add } from 'date-fns' +import { isIOS } from 'config' import { ScBannerWrap, @@ -38,7 +39,9 @@ export const SmartBanner = ({ setIsOpenDownload }: SmartBannerProps) => ( inSports – the Home of Sports Streaming { diff --git a/src/config/clients/insports.tsx b/src/config/clients/insports.tsx index ec1258c0..95bb14cb 100644 --- a/src/config/clients/insports.tsx +++ b/src/config/clients/insports.tsx @@ -15,6 +15,7 @@ export const insports: ClientConfig = { name: ClientNames.Insports, privacyLink: '/privacy-policy-and-statement?client_id=insports-ott-web', showSearch: true, + showSmartBanner: true, styles: { background: 'background-image: url(/images/Checker.png);', logo: 'insports-logo.svg', diff --git a/src/config/clients/types.tsx b/src/config/clients/types.tsx index febb8d15..77f01e9b 100644 --- a/src/config/clients/types.tsx +++ b/src/config/clients/types.tsx @@ -35,6 +35,7 @@ export type ClientConfig = { privacyLink: string, requests?: Record, showSearch?: boolean, + showSmartBanner?: boolean, styles: { background?: string, homePageHeader?: StyledCss, diff --git a/src/config/userAgent.tsx b/src/config/userAgent.tsx index b0405c07..15dcc250 100644 --- a/src/config/userAgent.tsx +++ b/src/config/userAgent.tsx @@ -1,3 +1,5 @@ export const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) +export const isAndroid = /Android/.test(navigator.userAgent) + export const isMobileDevice = /iPhone|Android/.test(navigator.userAgent) diff --git a/src/features/HeaderMobile/index.tsx b/src/features/HeaderMobile/index.tsx index 86d26f4c..2435e6f8 100644 --- a/src/features/HeaderMobile/index.tsx +++ b/src/features/HeaderMobile/index.tsx @@ -1,7 +1,7 @@ import { useRecoilValue } from 'recoil' -import { isIOS } from 'config/userAgent' -import { isLffClient } from 'config/clients' +import { isAndroid, isIOS } from 'config/userAgent' +import { client, isLffClient } from 'config/clients' import { HeaderMenu } from 'features/HeaderMenu' import { DateFilter } from 'features/HeaderFilters' @@ -10,6 +10,8 @@ import { SportsFilter } from 'features/SportsFilter' import { isSportFilterShownAtom } from 'features/HomePage/Atoms/HomePageAtoms' import { SmartBanner } from 'components/SmartBanner' +import { UserInfo } from 'requests' + import { HeaderStyled, ScoreSwitchWrapper, @@ -19,16 +21,22 @@ import { type HeaderBannerProps = { isOpenDownload: boolean, setIsOpenDownload: (open: boolean) => void, + userInfo?: UserInfo, } -export const HeaderMobile = ({ isOpenDownload, setIsOpenDownload }: HeaderBannerProps) => { +export const HeaderMobile = ({ + isOpenDownload, + setIsOpenDownload, + userInfo, +}: HeaderBannerProps) => { const isSportFilterShown = useRecoilValue(isSportFilterShownAtom) return ( <> { isOpenDownload - && !isIOS + && (isAndroid || (isIOS && userInfo?.has_subscription)) + && client.showSmartBanner && } diff --git a/src/features/HomePage/hooks.tsx b/src/features/HomePage/hooks.tsx index c8b11b82..83cc160b 100644 --- a/src/features/HomePage/hooks.tsx +++ b/src/features/HomePage/hooks.tsx @@ -34,7 +34,7 @@ const getTimezoneOffset = (date: Date) => { const getDate = (date: Date) => format(date, 'yyyy-MM-dd') export const useHomePage = () => { - const { user } = useAuthStore() + const { user, userInfo } = useAuthStore() const { selectedDate } = useHeaderFiltersStore() const [isOpenDownload, setIsOpenDownload] = useState(false) const [isShowConfirmPopup, setIsShowConfirmPopup] = useState(false) @@ -54,6 +54,7 @@ export const useHomePage = () => { })() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) + useEffect(() => { const dateLastOpenSmartBanner = localStorage.getItem('dateLastOpenSmartBanner') if (!dateLastOpenSmartBanner @@ -85,5 +86,6 @@ export const useHomePage = () => { isOpenDownload, isShowConfirmPopup, setIsOpenDownload, + userInfo, } } diff --git a/src/features/HomePage/index.tsx b/src/features/HomePage/index.tsx index 6f9fd6ca..e4e476a2 100644 --- a/src/features/HomePage/index.tsx +++ b/src/features/HomePage/index.tsx @@ -29,6 +29,7 @@ const Home = () => { isOpenDownload, isShowConfirmPopup, setIsOpenDownload, + userInfo, } = useHomePage() return ( @@ -37,6 +38,7 @@ const Home = () => { ) : (
diff --git a/src/requests/getUserInfo.tsx b/src/requests/getUserInfo.tsx index db8c30a2..e02528b6 100644 --- a/src/requests/getUserInfo.tsx +++ b/src/requests/getUserInfo.tsx @@ -18,6 +18,7 @@ export type UserInfo = { }, email: string, firstname: string | null, + has_subscription: boolean, is_unsubscribed: boolean | null, language: { id: number | null, -- 2.30.2 From 407a9d9261778d812d98804d7722dd52f962ba8f Mon Sep 17 00:00:00 2001 From: Rakov Roman Date: Wed, 7 Dec 2022 18:09:00 +0300 Subject: [PATCH 13/31] fix(#3099): save match stats 5 sec --- src/features/MultiSourcePlayer/hooks/index.tsx | 11 ++++++++--- src/features/StreamPlayer/hooks/index.tsx | 11 ++++++++--- src/requests/saveMatchStats.tsx | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/features/MultiSourcePlayer/hooks/index.tsx b/src/features/MultiSourcePlayer/hooks/index.tsx index 25a261fb..22022292 100644 --- a/src/features/MultiSourcePlayer/hooks/index.tsx +++ b/src/features/MultiSourcePlayer/hooks/index.tsx @@ -22,9 +22,9 @@ import { } from 'hooks' import { - intervalMs, MatchInfo, saveMatchStats, + VIEW_INTERVAL_MS, } from 'requests' import { useProgressChangeHandler } from './useProgressChangeHandler' @@ -74,6 +74,9 @@ export const useMultiSourcePlayer = ({ const { profileId, sportType } = usePageParams() + /** время для сохранения статистики просмотра матча */ + const timeForStatistics = useRef(0) + const numberOfChapters = size(chapters) const [ { @@ -195,6 +198,8 @@ export const useMultiSourcePlayer = ({ const chapter = getActiveChapter() const value = Math.max(playedMs - chapter.startOffsetMs, 0) + timeForStatistics.current = (value + chapter.startMs) / 1000 + setPlayerState({ playedProgress: value }) } @@ -283,11 +288,11 @@ export const useMultiSourcePlayer = ({ callback: () => { saveMatchStats({ matchId: profileId, - matchSecond: videoRef.current?.currentTime!, + matchSecond: timeForStatistics.current, sportType, }) }, - intervalDuration: intervalMs, + intervalDuration: VIEW_INTERVAL_MS, startImmediate: false, }) diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx index 28573a8b..f552a7e3 100644 --- a/src/features/StreamPlayer/hooks/index.tsx +++ b/src/features/StreamPlayer/hooks/index.tsx @@ -1,5 +1,6 @@ import type { MouseEvent } from 'react' import { + useRef, useCallback, useEffect, useState, @@ -25,7 +26,7 @@ import { useNoNetworkPopupStore } from 'features/NoNetworkPopup' import { useLiveMatch } from 'features/MatchPage/components/LiveMatch/hooks' import { useLexicsStore } from 'features/LexicsStore' -import { intervalMs, saveMatchStats } from 'requests' +import { VIEW_INTERVAL_MS, saveMatchStats } from 'requests' import { REWIND_SECONDS } from '../config' import { useHlsPlayer } from './useHlsPlayer' @@ -96,6 +97,9 @@ export const useVideoPlayer = ({ const { lang } = useLexicsStore() const { profileId, sportType } = usePageParams() + /** время для сохранения статистики просмотра матча */ + const timeForStatistics = useRef(0) + const { url } = chapters[0] ?? { url: '' } const numberOfChapters = size(chapters) const { hls, videoRef } = useHlsPlayer({ @@ -219,6 +223,7 @@ export const useVideoPlayer = ({ const chapter = getActiveChapter() const value = Math.max(playedMs - chapter.startOffsetMs, 0) setPlayerState({ playedProgress: value }) + timeForStatistics.current = (value + chapter.startMs) / 1000 progressChangeCallback(value / 1000) } @@ -443,11 +448,11 @@ export const useVideoPlayer = ({ callback: () => { saveMatchStats({ matchId: profileId, - matchSecond: videoRef.current?.currentTime!, + matchSecond: timeForStatistics.current, sportType, }) }, - intervalDuration: intervalMs, + intervalDuration: VIEW_INTERVAL_MS, startImmediate: false, }) diff --git a/src/requests/saveMatchStats.tsx b/src/requests/saveMatchStats.tsx index 2307ecad..fba03804 100644 --- a/src/requests/saveMatchStats.tsx +++ b/src/requests/saveMatchStats.tsx @@ -8,7 +8,7 @@ type Props = { sportType: SportTypes, } -export const intervalMs = 15000 +export const VIEW_INTERVAL_MS = 5000 export const saveMatchStats = ({ matchId, @@ -19,7 +19,7 @@ export const saveMatchStats = ({ const config = { body: { - interval: intervalMs / 1000, + interval: VIEW_INTERVAL_MS / 1000, match_id: matchId, second: matchSecond, sport_id: sportType, -- 2.30.2 From 6c4bb15a4a5174b9f50a00a490dd791b58a31a7d Mon Sep 17 00:00:00 2001 From: "andrey.dekterev" Date: Thu, 8 Dec 2022 16:32:49 +0000 Subject: [PATCH 14/31] Update '.drone.yml' --- .drone.yml | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.drone.yml b/.drone.yml index 4ab93d7c..f2ea0ebf 100644 --- a/.drone.yml +++ b/.drone.yml @@ -173,32 +173,32 @@ steps: - make-lff - deploy-facr - - name: make-diwansport - image: node:16-alpine - environment: - REACT_APP_STRIPE_PK: - from_secret: REACT_APP_STRIPE_PK - commands: - - apk add --no-cache make - - make diwansport-prod - depends_on: - - npm-install - - - name: deploy-diwansport - image: amazon/aws-cli:latest - environment: - AWS_ACCESS_KEY_ID: - from_secret: AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY: - from_secret: AWS_SECRET_ACCESS_KEY - AWS_DEFAULT_REGION: - from_secret: AWS_DEFAULT_REGION - commands: - - aws s3 sync build_insports-diwansport s3://insports-diwansport --delete - - aws cloudfront create-invalidation --distribution-id E3LKAH6TR4O2JL --paths "/*" - depends_on: - - make-diwansport - - deploy-lff +# - name: make-diwansport +# image: node:16-alpine +# environment: +# REACT_APP_STRIPE_PK: +# from_secret: REACT_APP_STRIPE_PK +# commands: +# - apk add --no-cache make +# - make diwansport-prod +# depends_on: +# - npm-install +# +# - name: deploy-diwansport +# image: amazon/aws-cli:latest +# environment: +# AWS_ACCESS_KEY_ID: +# from_secret: AWS_ACCESS_KEY_ID +# AWS_SECRET_ACCESS_KEY: +# from_secret: AWS_SECRET_ACCESS_KEY +# AWS_DEFAULT_REGION: +# from_secret: AWS_DEFAULT_REGION +# commands: +# - aws s3 sync build_insports-diwansport s3://insports-diwansport --delete +# - aws cloudfront create-invalidation --distribution-id E3LKAH6TR4O2JL --paths "/*" +# depends_on: +# - make-diwansport +# - deploy-lff --- kind: pipeline -- 2.30.2 From c18009f2d889951621078e2152bbd70009c2356e Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Sat, 10 Dec 2022 15:36:22 +0300 Subject: [PATCH 15/31] Revert "feat(in-132): videoplayer bugfix" This reverts commit 44e70269ba4e4c3ea8c912424bbb3a0e479f07f4. --- src/features/MatchPage/store/hooks/index.tsx | 4 ++-- src/features/StreamPlayer/hooks/index.tsx | 6 +----- .../StreamPlayer/hooks/useHlsPlayer.tsx | 18 ++---------------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index 58a33ed2..8b472265 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -57,11 +57,11 @@ export const useMatchPage = () => { let getIntervalMatch: ReturnType if (matchProfile?.live && !matchProfile.youtube_link) { getIntervalMatch = setInterval( - () => getMatchInfo(sportType, matchId).then(setMatchProfile), 5000, + () => getMatchInfo(sportType, matchId).then(setMatchProfile), 1000 * 60 * 3, ) } return () => clearInterval(getIntervalMatch) - }) + }, [matchProfile, sportType, matchId]) const { events, diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx index f552a7e3..c9d7460a 100644 --- a/src/features/StreamPlayer/hooks/index.tsx +++ b/src/features/StreamPlayer/hooks/index.tsx @@ -102,11 +102,7 @@ export const useVideoPlayer = ({ const { url } = chapters[0] ?? { url: '' } const numberOfChapters = size(chapters) - const { hls, videoRef } = useHlsPlayer({ - isLive, - resumeFrom, - src: url, - }) + const { hls, videoRef } = useHlsPlayer(url, resumeFrom) const [isLiveTime, setIsLiveTime] = useState(false) const [isPausedTime, setIsPausedTime] = useState(false) const [pausedProgress, setPausedProgress] = useState(0) diff --git a/src/features/StreamPlayer/hooks/useHlsPlayer.tsx b/src/features/StreamPlayer/hooks/useHlsPlayer.tsx index 2a04c637..34c995c4 100644 --- a/src/features/StreamPlayer/hooks/useHlsPlayer.tsx +++ b/src/features/StreamPlayer/hooks/useHlsPlayer.tsx @@ -9,17 +9,7 @@ import isNumber from 'lodash/isNumber' import { streamConfig } from '../config' -type useHlsPlayerType = { - isLive?: boolean, - resumeFrom?: number, - src: string, -} - -export const useHlsPlayer = ({ - isLive, - resumeFrom, - src, -}: useHlsPlayerType) => { +export const useHlsPlayer = (src: string, resumeFrom?: number) => { const hls = useMemo(() => { if (!Hls.isSupported()) return null @@ -29,11 +19,7 @@ export const useHlsPlayer = ({ } return new Hls(newStreamConfig) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - resumeFrom, - src, - isLive, - ]) + }, [resumeFrom, src]) const videoRef = useRef(null) -- 2.30.2 From ad94da060f510f6335f734767a3468703e372a0a Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Wed, 14 Dec 2022 11:20:51 +0300 Subject: [PATCH 16/31] fix(fix bugs with quality video): fix bugs with quality video and icon kind of sports --- public/index.html | 19 +++++++++----- src/components/SportIcon/SportIcon.tsx | 26 ++++++++++--------- .../StreamPlayer/hooks/useVideoQuality.tsx | 6 ++--- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/public/index.html b/public/index.html index f73b0ba2..f2343432 100644 --- a/public/index.html +++ b/public/index.html @@ -54,14 +54,21 @@ id="ze-snippet" src="https://static.zdassets.com/ekr/snippet.js?key=2f84e9fe-830c-42bf-afa4-32c90d7c5f7b" > - + - + <% } %> diff --git a/src/components/SportIcon/SportIcon.tsx b/src/components/SportIcon/SportIcon.tsx index e28d1f7d..4a01f6fc 100644 --- a/src/components/SportIcon/SportIcon.tsx +++ b/src/components/SportIcon/SportIcon.tsx @@ -52,21 +52,23 @@ export const SportIcon = ({ sport, }: Props) => { const sportType = getSportLexic(sport) - const IconSport = sportIcons[sportType].icon + const IconSport = sportIcons[sportType]?.icon return ( - + {IconSport && ( + + )} ) } diff --git a/src/features/StreamPlayer/hooks/useVideoQuality.tsx b/src/features/StreamPlayer/hooks/useVideoQuality.tsx index 43b968c1..25d1924e 100644 --- a/src/features/StreamPlayer/hooks/useVideoQuality.tsx +++ b/src/features/StreamPlayer/hooks/useVideoQuality.tsx @@ -43,7 +43,7 @@ const getVideoQualities = (levels: Array) => { Number, 'desc', ) - return uniqBy([...sorted, autoQuality], 'label') + return uniqBy([...sorted], 'label') } export const useVideoQuality = (hls: Hls | null) => { @@ -73,15 +73,13 @@ export const useVideoQuality = (hls: Hls | null) => { const listener = () => { const qualities = getVideoQualities(hls.levels) - const quality = find(qualities, { label: selectedQuality }) || autoQuality - + const quality = find(qualities, { label: selectedQuality }) || qualities[0] // eslint-disable-next-line no-param-reassign hls.currentLevel = quality.level setSelectedQuality(quality.label) setVideoQualities(qualities) } hls.on(Hls.Events.MANIFEST_PARSED, listener) - return () => { hls.off(Hls.Events.MANIFEST_PARSED, listener) } -- 2.30.2 From f1451a3bcb61fad3984913610d1a0595120fd5ac Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Wed, 14 Dec 2022 15:27:55 +0300 Subject: [PATCH 17/31] fix(return autoquality): return select autoquality --- src/features/StreamPlayer/hooks/useVideoQuality.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/features/StreamPlayer/hooks/useVideoQuality.tsx b/src/features/StreamPlayer/hooks/useVideoQuality.tsx index 25d1924e..43b968c1 100644 --- a/src/features/StreamPlayer/hooks/useVideoQuality.tsx +++ b/src/features/StreamPlayer/hooks/useVideoQuality.tsx @@ -43,7 +43,7 @@ const getVideoQualities = (levels: Array) => { Number, 'desc', ) - return uniqBy([...sorted], 'label') + return uniqBy([...sorted, autoQuality], 'label') } export const useVideoQuality = (hls: Hls | null) => { @@ -73,13 +73,15 @@ export const useVideoQuality = (hls: Hls | null) => { const listener = () => { const qualities = getVideoQualities(hls.levels) - const quality = find(qualities, { label: selectedQuality }) || qualities[0] + const quality = find(qualities, { label: selectedQuality }) || autoQuality + // eslint-disable-next-line no-param-reassign hls.currentLevel = quality.level setSelectedQuality(quality.label) setVideoQualities(qualities) } hls.on(Hls.Events.MANIFEST_PARSED, listener) + return () => { hls.off(Hls.Events.MANIFEST_PARSED, listener) } -- 2.30.2 From f6d8f5fea993c82a1938251c263a8b852d4144ae Mon Sep 17 00:00:00 2001 From: Andrei Dekterev Date: Thu, 15 Dec 2022 11:42:43 +0300 Subject: [PATCH 18/31] build(change pk apikey): change apikey for stripe --- Makefile | 12 ++++++------ src/config/env.tsx | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 128c4b80..bd0669a8 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ build-stage: clean REACT_APP_TYPE=ott \ REACT_APP_ENV=preproduction \ REACT_APP_CLIENT=insports \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW5XxhC6ntKZKddXgKHq5HOCDmJTdfSKluMYCdLHOcUA3Miuy8HesxG1eS4c0dQRQpMsEHRrQL00USpu5xIq \ npm run build build-a: clean @@ -142,7 +142,7 @@ prod: clean REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ REACT_APP_CLIENT=insports \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW5XxhC6ntKZKddXgKHq5HOCDmJTdfSKluMYCdLHOcUA3Miuy8HesxG1eS4c0dQRQpMsEHRrQL00USpu5xIq \ npm run build && cp -r .well-known build preprod: clean @@ -150,7 +150,7 @@ preprod: clean REACT_APP_ENV=preproduction \ REACT_APP_STAGE=test \ REACT_APP_CLIENT=insports \ - REACT_APP_STRIPE_PK=pk_live_ANI76cBhSo69DZUxPmyRVIZW \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW5XxhC6ntKZKddXgKHq5HOCDmJTdfSKluMYCdLHOcUA3Miuy8HesxG1eS4c0dQRQpMsEHRrQL00USpu5xIq \ npm run build india-prod: @@ -158,7 +158,7 @@ india-prod: REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ REACT_APP_CLIENT=india \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW5XxhC6ntKZKddXgKHq5HOCDmJTdfSKluMYCdLHOcUA3Miuy8HesxG1eS4c0dQRQpMsEHRrQL00USpu5xIq \ BUILD_PATH=build_india \ npm run build && cp -r .well-known build_india @@ -166,7 +166,7 @@ facr-prod: rm -rf build_facr && \ REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW5XxhC6ntKZKddXgKHq5HOCDmJTdfSKluMYCdLHOcUA3Miuy8HesxG1eS4c0dQRQpMsEHRrQL00USpu5xIq \ REACT_APP_CLIENT=facr \ BUILD_PATH=build_facr \ npm run build && cp -r .well-known build_facr @@ -175,7 +175,7 @@ lff-prod: rm -rf build_lff && \ REACT_APP_TYPE=ott \ REACT_APP_ENV=production \ - REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW7v2lF8GGogrm7XaaICZ9CN876sITIBBauZgB2ommUTUOiY868jzpbhQjZcoBOjIRX5Vs54Aq00y4C3USyB \ + REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW5XxhC6ntKZKddXgKHq5HOCDmJTdfSKluMYCdLHOcUA3Miuy8HesxG1eS4c0dQRQpMsEHRrQL00USpu5xIq \ REACT_APP_CLIENT=lff \ BUILD_PATH=build_lff \ npm run build && cp -r .well-known build_lff diff --git a/src/config/env.tsx b/src/config/env.tsx index ebe71c86..f0c0b415 100644 --- a/src/config/env.tsx +++ b/src/config/env.tsx @@ -16,7 +16,7 @@ export const isProduction = ENV === 'production' || ENV === 'preproduction' export const stageENV = process.env.REACT_APP_STAGE || 'test' -export const STRIPE_PUBLIC_KEY = process.env.REACT_APP_STRIPE_PK || 'pk_test_51J5TEYEDSxVnTgDWhKLstuDAhx9XmGJmj2awyZ1HghpWdU46MhXqbQt1PyW9XsRlES5JFyuQWbPRjoSsiW3wvXOH00KMirJEGZ' +export const STRIPE_PUBLIC_KEY = process.env.REACT_APP_STRIPE_PK || 'pk_test_51J5TEYEDSxVnTgDWyF63HykCAwKKObIdYCKiCwotte7xvfPw0VhmZiQKzYJIgZ3tCVvQ57JNpGYN7YbxR4JckYUB00HeDWE4YR' export const GOOGLE_CLIENT_ID = process.env.REACT_APP_GOOGLE_CLIENT_ID || '1043133237396-kebgih109kro71b5c7c8qphtgjbd2gdk.apps.googleusercontent.com' export const FACEBOOK_CLIENT_ID = process.env.REACT_APP_FACEBOOK_CLIENT_ID || '798254931203361' -- 2.30.2 From c1b374760396a22d1d327a7a000d956cdc494fd5 Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov home Date: Thu, 15 Dec 2022 18:12:57 +0700 Subject: [PATCH 19/31] fix deploy --- .drone.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.drone.yml b/.drone.yml index f2ea0ebf..88d7706e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -44,6 +44,7 @@ steps: from_secret: AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION: from_secret: AWS_DEFAULT_REGION + AWS_MAX_ATTEMPTS: 10 commands: # - aws s3 sync build s3://insports-prod --delete # - aws cloudfront create-invalidation --distribution-id E3KY6BCU3AYHEW --paths "/*" @@ -72,12 +73,12 @@ steps: from_secret: AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION: from_secret: AWS_DEFAULT_REGION + AWS_MAX_ATTEMPTS: 10 commands: - aws s3 sync build s3://insports-auth --delete - aws cloudfront create-invalidation --distribution-id EERIKX9X2SRPJ --paths "/*" depends_on: - make-auth - - deploy-prod - name: deploy-old-auth-server image: node:16-alpine @@ -112,12 +113,12 @@ steps: from_secret: AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION: from_secret: AWS_DEFAULT_REGION + AWS_MAX_ATTEMPTS: 10 commands: - aws s3 sync build_india s3://insports-india --delete - aws cloudfront create-invalidation --distribution-id E5DKN8IPOMASO --paths "/*" depends_on: - make-india - - deploy-S3-auth - name: make-facr image: node:16-alpine @@ -139,12 +140,12 @@ steps: from_secret: AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION: from_secret: AWS_DEFAULT_REGION + AWS_MAX_ATTEMPTS: 10 commands: - aws s3 sync build_facr s3://insports-facr-tv --delete - aws cloudfront create-invalidation --distribution-id E1ZYJS9RAJO89D --paths "/*" depends_on: - make-facr - - deploy-india - name: make-lff image: node:16-alpine @@ -166,12 +167,12 @@ steps: from_secret: AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION: from_secret: AWS_DEFAULT_REGION + AWS_MAX_ATTEMPTS: 10 commands: - aws s3 sync build_lff s3://insports-tv-lff-lv --delete - aws cloudfront create-invalidation --distribution-id E2127IDW4TEH4S --paths "/*" depends_on: - make-lff - - deploy-facr # - name: make-diwansport # image: node:16-alpine @@ -193,12 +194,12 @@ steps: # from_secret: AWS_SECRET_ACCESS_KEY # AWS_DEFAULT_REGION: # from_secret: AWS_DEFAULT_REGION +# AWS_MAX_ATTEMPTS: 10 # commands: # - aws s3 sync build_insports-diwansport s3://insports-diwansport --delete # - aws cloudfront create-invalidation --distribution-id E3LKAH6TR4O2JL --paths "/*" # depends_on: # - make-diwansport -# - deploy-lff --- kind: pipeline -- 2.30.2 From b972a6f6ce917780636a77f91ab4dc983a478939 Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov home Date: Fri, 16 Dec 2022 20:04:27 +0700 Subject: [PATCH 20/31] add autodeploy test auth server --- .drone.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.drone.yml b/.drone.yml index 88d7706e..7db483ca 100644 --- a/.drone.yml +++ b/.drone.yml @@ -676,15 +676,15 @@ steps: from_secret: AWS_DEFAULT_REGION REACT_APP_STRIPE_PK: from_secret: REACT_APP_STRIPE_PK_TEST - SSH_KEY_AUTH: - from_secret: SSH_KEY_AUTH + SSH_KEY_AUTH_TEST: + from_secret: SSH_KEY_AUTH_TEST commands: - apk add --no-cache aws-cli bash git openssh-client make rsync - npm install --legacy-peer-deps - make auth-build - eval $(ssh-agent -s) - - echo -n "$SSH_KEY_AUTH" | tr -d '\r' | ssh-add - + - echo -n "$SSH_KEY_AUTH_TEST" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh && chmod 700 ~/.ssh - ssh-keyscan auth.test.insports.tv >> ~/.ssh/known_hosts - rsync -v -r -C build_auth/ ubuntu@auth.test.insports.tv:/home/ubuntu/ott-auth/src/frontend/ -- 2.30.2 From 376aedaea22fb52eab6b01c559bbf82e6d5f111f Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Wed, 9 Nov 2022 18:58:14 +0500 Subject: [PATCH 21/31] feat(in-142): match stats tab --- public/images/matchTabs/bets.svg | 3 + public/images/matchTabs/chat.svg | 3 + public/images/matchTabs/players.svg | 6 + public/images/matchTabs/plays.svg | 4 + public/images/matchTabs/stats.svg | 12 + public/images/matchTabs/watch.svg | 3 + src/config/lexics/indexLexics.tsx | 2 + .../components/PlayersPlaylists/styled.tsx | 1 - .../components/PlayersTable/index.tsx | 243 +++++++++++++++ .../components/PlayersTable/styled.tsx | 86 ++++++ .../components/TabPlayers/index.tsx | 31 ++ .../components/TabStats/config.tsx | 5 + .../components/TabStats/index.tsx | 34 +++ .../components/TabStats/styled.tsx | 108 +++++++ .../components/TabVideo/index.tsx | 2 + .../components/TabWatch/index.tsx | 23 +- .../components/TeamsStats/index.tsx | 276 ++++++++++++++++++ .../components/TeamsStats/styled.tsx | 56 ++++ src/features/MatchSidePlaylists/config.tsx | 3 +- src/features/MatchSidePlaylists/hooks.tsx | 12 +- src/features/MatchSidePlaylists/index.tsx | 43 ++- src/features/MatchSidePlaylists/styled.tsx | 79 ++++- src/features/Tooltip/index.tsx | 2 +- 23 files changed, 997 insertions(+), 40 deletions(-) create mode 100644 public/images/matchTabs/bets.svg create mode 100644 public/images/matchTabs/chat.svg create mode 100644 public/images/matchTabs/players.svg create mode 100644 public/images/matchTabs/plays.svg create mode 100644 public/images/matchTabs/stats.svg create mode 100644 public/images/matchTabs/watch.svg create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx create mode 100644 src/features/MatchSidePlaylists/components/TabPlayers/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/TabStats/config.tsx create mode 100644 src/features/MatchSidePlaylists/components/TabStats/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/TabStats/styled.tsx create mode 100644 src/features/MatchSidePlaylists/components/TeamsStats/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx diff --git a/public/images/matchTabs/bets.svg b/public/images/matchTabs/bets.svg new file mode 100644 index 00000000..d112cddb --- /dev/null +++ b/public/images/matchTabs/bets.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/matchTabs/chat.svg b/public/images/matchTabs/chat.svg new file mode 100644 index 00000000..02d75c4b --- /dev/null +++ b/public/images/matchTabs/chat.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/matchTabs/players.svg b/public/images/matchTabs/players.svg new file mode 100644 index 00000000..ffa6cb02 --- /dev/null +++ b/public/images/matchTabs/players.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/images/matchTabs/plays.svg b/public/images/matchTabs/plays.svg new file mode 100644 index 00000000..0850a8e7 --- /dev/null +++ b/public/images/matchTabs/plays.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/matchTabs/stats.svg b/public/images/matchTabs/stats.svg new file mode 100644 index 00000000..12afb401 --- /dev/null +++ b/public/images/matchTabs/stats.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/images/matchTabs/watch.svg b/public/images/matchTabs/watch.svg new file mode 100644 index 00000000..fdb9114f --- /dev/null +++ b/public/images/matchTabs/watch.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx index 5d6e1344..e44e4d09 100644 --- a/src/config/lexics/indexLexics.tsx +++ b/src/config/lexics/indexLexics.tsx @@ -22,6 +22,7 @@ const matchPopupLexics = { match_interviews: 13031, match_settings: 13490, no_data: 15397, + others: 19902, players_episodes: 13398, playlist_format: 13406, playlist_format_all_actions: 13408, @@ -31,6 +32,7 @@ const matchPopupLexics = { sec_before: 13411, selected_player_actions: 13413, started_streaming_at: 16042, + stats: 18179, streamed_live_on: 16043, video: 1017, views: 13440, diff --git a/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx b/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx index 5ab9e064..619eba54 100644 --- a/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx @@ -6,7 +6,6 @@ export const Wrapper = styled.div` display: flex; flex-direction: column; align-items: center; - margin-top: 25px; ` export const List = styled.ul` diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx new file mode 100644 index 00000000..46520e1b --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx @@ -0,0 +1,243 @@ +import { + Table, + Thead, + Th, + Tbody, + Tr, + Td, + PlayerNum, + ParamShortTitle, +} from './styled' + +export const PlayersTable = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Min + + Pt + + Reb + + Ass + + To +
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
+) diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx new file mode 100644 index 00000000..3d88c1f6 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx @@ -0,0 +1,86 @@ +import styled, { css } from 'styled-components/macro' + +import { customScrollbar } from 'features/Common' + +export const Table = styled.table` + width: 100%; + border-radius: 5px; + border-collapse: collapse; + letter-spacing: -0.078px; + background-color: #333333; + table-layout: fixed; + + ${customScrollbar} +` + +export const Thead = styled.thead` + height: 45px; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); +` + +type ThProps = { + sorted?: boolean, +} + +export const Th = styled.th` + font-size: 11px; + color: ${({ theme }) => theme.colors.white}; + text-transform: uppercase; + + :first-child { + width: 115px; + } + + ${({ sorted }) => (sorted + ? '' + : css` + opacity: 0.5; + `)} +` + +export const ParamShortTitle = styled.span`` + +export const Tbody = styled.tbody`` + +export const Tr = styled.tr` + height: 45px; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); + + :last-child { + border-bottom: none; + } +` + +type TdProps = { + clickable?: boolean, + sorted?: boolean, +} + +export const Td = styled.td` + font-size: 11px; + text-align: center; + color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)}; + + :first-child { + padding-left: 13px; + text-align: left; + color: ${({ theme }) => theme.colors.white}; + } + + + ${({ sorted }) => (sorted + ? css` + font-weight: bold; + ` + : '')} + + ${({ clickable }) => (clickable + ? css` + cursor: pointer; + ` + : '')} +` + +export const PlayerNum = styled.span` + color: rgba(255, 255, 255, 0.5); +` diff --git a/src/features/MatchSidePlaylists/components/TabPlayers/index.tsx b/src/features/MatchSidePlaylists/components/TabPlayers/index.tsx new file mode 100644 index 00000000..bd8244ac --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TabPlayers/index.tsx @@ -0,0 +1,31 @@ +import isEmpty from 'lodash/isEmpty' + +import type { Playlists, PlaylistOption } from 'features/MatchPage/types' +import type { MatchInfo } from 'requests' + +import { PlayersPlaylists } from '../PlayersPlaylists' + +type Props = { + onSelect: (option: PlaylistOption) => void, + playlists: Playlists, + profile: MatchInfo, + selectedPlaylist?: PlaylistOption, +} + +export const TabPlayers = ({ + onSelect, + playlists, + profile, + selectedPlaylist, +}: Props) => { + if (isEmpty(playlists.players.team1)) return null + + return ( + + ) +} diff --git a/src/features/MatchSidePlaylists/components/TabStats/config.tsx b/src/features/MatchSidePlaylists/components/TabStats/config.tsx new file mode 100644 index 00000000..099a117f --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TabStats/config.tsx @@ -0,0 +1,5 @@ +export enum Tabs { + TEAMS, + TEAM1, + TEAM2, +} diff --git a/src/features/MatchSidePlaylists/components/TabStats/index.tsx b/src/features/MatchSidePlaylists/components/TabStats/index.tsx new file mode 100644 index 00000000..c43592bb --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TabStats/index.tsx @@ -0,0 +1,34 @@ +import { Tooltip } from 'features/Tooltip' + +import { PlayersTable } from '../PlayersTable' +import { TeamsStats } from '../TeamsStats' + +import { + Container, + Header, + TabList, + Tab, + Switch, + SwitchTitle, + SwitchButton, +} from './styled' + +export const TabStats = () => ( + +
+ + Teams + DIN + SPA + + + Final Stats + + + + +
+ + {/* */} +
+) diff --git a/src/features/MatchSidePlaylists/components/TabStats/styled.tsx b/src/features/MatchSidePlaylists/components/TabStats/styled.tsx new file mode 100644 index 00000000..f2f58203 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TabStats/styled.tsx @@ -0,0 +1,108 @@ +import styled, { css } from 'styled-components/macro' + +import { TooltipWrapper } from 'features/Tooltip' + +export const Container = styled.div`` + +export const Header = styled.div` + display: flex; + justify-content: space-between; + margin-bottom: 23px; +` + +export const TabList = styled.div.attrs({ role: 'tablist' })` + display: flex; +` + +type TabProps = { + selected?: boolean, +} + +export const Tab = styled.div.attrs(({ selected }: TabProps) => ({ + 'aria-pressed': selected, + role: 'tab', +}))` + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 15px 10px; + font-size: 12px; + color: ${({ theme }) => theme.colors.white}; + opacity: ${({ selected }) => (selected ? '1' : '0.4')}; + cursor: pointer; + border-bottom: 2px solid transparent; + + + ${({ selected, theme }) => (selected + ? css` + border-color: ${theme.colors.white}; + ` + : '')} +` + +export const Switch = styled.div` + display: flex; +` + +export const SwitchTitle = styled.span` + font-size: 12px; + color: ${({ theme }) => theme.colors.white}; +` + +export const SwitchButton = styled.button` + position: relative; + width: 20px; + height: 7px; + margin-left: 5px; + margin-top: 5px; + border-radius: 2px; + border: none; + border: 1px solid ${({ theme }) => theme.colors.white}; + cursor: pointer; + + ${TooltipWrapper} { + left: auto; + right: 0; + padding: 2px 10px; + border-radius: 6px; + transform: none; + + ::before { + display: none; + } + } + + :hover { + ${TooltipWrapper} { + display: block; + } + } + + ${({ theme }) => (true // Позже будет добавлен пропс + ? css` + background-image: linear-gradient( + to right, + ${theme.colors.white} 33.333%, + ${theme.colors.black} 33.333%, + ${theme.colors.black} 66.666%, + ${theme.colors.white} 66.666%, + ${theme.colors.white} 72%, + ${theme.colors.black} 72%, + ${theme.colors.black} 100%) + ` + : css` + border-color: transparent; + background-image: linear-gradient( + to right, + ${theme.colors.white} 33.333%, + ${theme.colors.black} 33.333%, + ${theme.colors.black} 38%, + ${theme.colors.white} 38%, + ${theme.colors.white} 66.666%, + ${theme.colors.black} 66.666%, + ${theme.colors.black} 72%, + ${theme.colors.white} 72%, + ${theme.colors.white} 100%) + ` + )} +` diff --git a/src/features/MatchSidePlaylists/components/TabVideo/index.tsx b/src/features/MatchSidePlaylists/components/TabVideo/index.tsx index 83d165dc..2a8740d6 100644 --- a/src/features/MatchSidePlaylists/components/TabVideo/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabVideo/index.tsx @@ -77,6 +77,8 @@ export const TabVideo = ({ setOverflow(hasScroll) }, [ref, selectedDate]) + if (tournamentData.matches.length <= 1) return null + return ( void, playlists: Playlists, profile: MatchInfo, selectedPlaylist?: PlaylistOption, + tournamentData: TournamentData, } export const TabWatch = ({ @@ -23,6 +27,7 @@ export const TabWatch = ({ playlists, profile, selectedPlaylist, + tournamentData, }: Props) => ( - {!isEmpty(playlists.players.team1) && ( - - )} + ) diff --git a/src/features/MatchSidePlaylists/components/TeamsStats/index.tsx b/src/features/MatchSidePlaylists/components/TeamsStats/index.tsx new file mode 100644 index 00000000..17a1dad5 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TeamsStats/index.tsx @@ -0,0 +1,276 @@ +import { + Container, + Row, + TeamShortName, + ParamValueContainer, + ParamValue, + ParamTitle, +} from './styled' + +export const TeamsStats = () => ( + + + DIN + SPA + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + + + 90 + + Points + 123 + + +) diff --git a/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx b/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx new file mode 100644 index 00000000..222b9918 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx @@ -0,0 +1,56 @@ +import styled, { css } from 'styled-components/macro' + +import { customScrollbar } from 'features/Common' + +export const Container = styled.div` + width: 100%; + font-size: 11px; + background-color: #333333; + + ${customScrollbar} +` + +export const TeamShortName = styled.span` + color: ${({ theme }) => theme.colors.white}; + letter-spacing: -0.078px; + text-transform: uppercase; + font-weight: 600; + opacity: 0.5; +` + +export const Row = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + height: 45px; + padding: 0 12px; + border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); + + :last-child { + border-bottom: none; + } +` + +export const ParamValueContainer = styled.div`` + +type TParamValue = { + clickable?: boolean, +} + +export const ParamValue = styled.span` + color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)}; + + ${({ clickable }) => (clickable + ? css` + cursor: pointer; + ` + : '')} +` + +export const ParamTitle = styled.span` + color: ${({ theme }) => theme.colors.white}; + letter-spacing: -0.078px; + text-transform: uppercase; + font-weight: 600; + opacity: 0.5; +` diff --git a/src/features/MatchSidePlaylists/config.tsx b/src/features/MatchSidePlaylists/config.tsx index 9ab22db3..fc7219fd 100644 --- a/src/features/MatchSidePlaylists/config.tsx +++ b/src/features/MatchSidePlaylists/config.tsx @@ -1,5 +1,6 @@ export enum Tabs { WATCH, EVENTS, - VIDEO + STATS, + PLAYERS, } diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index a953144c..689c6fe5 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -15,7 +15,6 @@ export const useMatchSidePlaylists = () => { closePopup, events, matchPlaylists: playlists, - tournamentData, } = useMatchPageStore() const [selectedTab, setSelectedTab] = useState(Tabs.WATCH) const isWatchTabVisible = useMemo(() => { @@ -35,10 +34,6 @@ export const useMatchSidePlaylists = () => { events.length > 0 ), [events]) - const isVideoTabVisible = useMemo(() => ( - tournamentData.matches.length > 1 - ), [tournamentData]) - useEffect(() => { switch (true) { case isWatchTabVisible: @@ -47,11 +42,8 @@ export const useMatchSidePlaylists = () => { case isEventTabVisible: setSelectedTab(Tabs.EVENTS) break - case isVideoTabVisible: - setSelectedTab(Tabs.VIDEO) - break } - }, [isEventTabVisible, isVideoTabVisible, isWatchTabVisible]) + }, [isEventTabVisible, isWatchTabVisible]) useEffect(() => { if (selectedTab !== Tabs.EVENTS) closePopup() @@ -59,7 +51,7 @@ export const useMatchSidePlaylists = () => { return { isEventTabVisible, - isVideoTabVisible, + isStatsTabVisible: true, isWatchTabVisible, onTabClick: setSelectedTab, selectedTab, diff --git a/src/features/MatchSidePlaylists/index.tsx b/src/features/MatchSidePlaylists/index.tsx index b3a0edc9..25b08a12 100644 --- a/src/features/MatchSidePlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/index.tsx @@ -6,8 +6,6 @@ import { import type { TCircleAnimation, TSetCircleAnimation } from 'features/CircleAnimationBar' import type { PlaylistOption } from 'features/MatchPage/types' -import { Tab, TabsGroup } from 'features/Common' -import { T9n } from 'features/T9n' import { useMatchPageStore } from 'features/MatchPage/store' import { useEventListener } from 'hooks' @@ -17,18 +15,24 @@ import { isIOS } from 'config/userAgent' import { Tabs } from './config' import { TabEvents } from './components/TabEvents' import { TabWatch } from './components/TabWatch' -import { TabVideo } from './components/TabVideo' +import { TabPlayers } from './components/TabPlayers' +import { TabStats } from './components/TabStats' import { useMatchSidePlaylists } from './hooks' import { Wrapper, TabsWrapper, + TabsGroup, + Tab, + TabIcon, + TabTitle, Container, } from './styled' const tabPanes = { [Tabs.WATCH]: TabWatch, [Tabs.EVENTS]: TabEvents, - [Tabs.VIDEO]: TabVideo, + [Tabs.STATS]: TabStats, + [Tabs.PLAYERS]: TabPlayers, } type Props = { @@ -38,6 +42,8 @@ type Props = { setCircleAnimation?: TSetCircleAnimation, } +const hasLessThanFourTabs = false + export const MatchSidePlaylists = ({ circleAnimation, onSelect, @@ -54,7 +60,7 @@ export const MatchSidePlaylists = ({ const { isEventTabVisible, - isVideoTabVisible, + isStatsTabVisible, isWatchTabVisible, onTabClick, selectedTab, @@ -99,13 +105,14 @@ export const MatchSidePlaylists = ({ return ( - + {isWatchTabVisible ? ( onTabClick(Tabs.WATCH)} > - + + ) : null} {isEventTabVisible ? ( @@ -113,15 +120,26 @@ export const MatchSidePlaylists = ({ selected={selectedTab === Tabs.EVENTS} onClick={() => onTabClick(Tabs.EVENTS)} > - + + + + ) : null} + {isStatsTabVisible ? ( + onTabClick(Tabs.PLAYERS)} + > + + ) : null} - {isVideoTabVisible ? ( + {isStatsTabVisible ? ( onTabClick(Tabs.VIDEO)} + selected={selectedTab === Tabs.STATS} + onClick={() => onTabClick(Tabs.STATS)} > - + + ) : null} @@ -130,7 +148,6 @@ export const MatchSidePlaylists = ({ ` + display: flex; + height: 45px; + padding-top: 10px; + + ${({ hasLessThanFourTabs }) => (hasLessThanFourTabs + ? css` + height: 40px; + + ${Tab} { + justify-content: initial; + flex-direction: row; + gap: 5px; + } + ` + : '')} + + ${isMobileDevice + ? css` + ` + : ''}; +` + +type TabProps = { + selected?: boolean, +} + +export const Tab = styled.div.attrs(({ selected }: TabProps) => ({ + 'aria-pressed': selected, + role: 'tab', +}))` + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + flex: 1; + opacity: ${({ selected }) => (selected ? '1' : '0.4')}; + cursor: pointer; + + :hover { + opacity: 1; + } +` + +type TabIconProps = { + icon: 'watch' | 'plays' | 'players' | 'stats', +} + +export const TabIcon = styled.div` + width: 20px; + height: 20px; + background-image: url(/images/matchTabs/${({ icon }) => `${icon}.svg`}); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + + ${({ icon }) => (icon === 'players' + ? css` + background-size: 23px; + ` + : '')} +` + +export const TabTitle = styled(T9n)` + font-size: 8px; + text-transform: uppercase; + color: ${({ theme }) => theme.colors.white}; +` + type TContainer = { - forVideoTab?: boolean, hasScroll: boolean, } export const Container = styled.div` width: 320px; - margin-top: 14px; + margin-top: 23px; max-height: calc(100vh - 130px); overflow-y: ${({ forVideoTab }) => (forVideoTab ? 'hidden' : 'auto')}; padding-right: ${({ forVideoTab }) => (forVideoTab ? '0' : '')}; diff --git a/src/features/Tooltip/index.tsx b/src/features/Tooltip/index.tsx index b0683b49..a436eb2d 100644 --- a/src/features/Tooltip/index.tsx +++ b/src/features/Tooltip/index.tsx @@ -25,7 +25,7 @@ export const TooltipWrapper = styled(TooltipBlockWrapper)` ` type Props = { - children: ReactNode, + children?: ReactNode, lexic: string, } -- 2.30.2 From ee3b93c6221d892dd23c2e9550625199fafa3a54 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Tue, 15 Nov 2022 18:42:55 +0500 Subject: [PATCH 22/31] feat(in-142): match stats tab --- src/config/lexics/indexLexics.tsx | 5 + src/features/MatchPage/store/hooks/index.tsx | 4 + .../MatchPage/store/hooks/useMatchData.tsx | 6 +- .../MatchPage/store/hooks/useTeamsStats.tsx | 58 + .../components/PlayersPlaylists/index.tsx | 5 - .../components/PlayersPlaylists/styled.tsx | 5 +- .../components/PlayersTable/config.tsx | 1 + .../components/PlayersTable/hooks.tsx | 61 + .../components/PlayersTable/index.tsx | 1951 +++++++++++++++-- .../components/PlayersTable/styled.tsx | 79 +- .../components/TabStats/config.tsx | 5 + .../components/TabStats/hooks.tsx | 32 + .../components/TabStats/index.tsx | 77 +- .../components/TabStats/styled.tsx | 39 +- .../components/TeamsStats/styled.tsx | 6 +- src/features/MatchSidePlaylists/hooks.tsx | 35 +- src/features/MatchSidePlaylists/index.tsx | 16 +- src/features/MatchSidePlaylists/styled.tsx | 18 +- src/hooks/usePageParams.tsx | 1 + src/requests/getTeamsStats.tsx | 56 + src/requests/index.tsx | 1 + 21 files changed, 2147 insertions(+), 314 deletions(-) create mode 100644 src/features/MatchPage/store/hooks/useTeamsStats.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/config.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx create mode 100644 src/features/MatchSidePlaylists/components/TabStats/hooks.tsx create mode 100644 src/requests/getTeamsStats.tsx diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx index e44e4d09..545eea28 100644 --- a/src/config/lexics/indexLexics.tsx +++ b/src/config/lexics/indexLexics.tsx @@ -9,8 +9,12 @@ const matchPopupLexics = { apply: 13491, choose_fav_team: 19776, commentators: 15424, + current_stats: 19592, + display_all_stats: 19932, + display_stats_according_to_video: 19931, episode_duration: 13410, events: 1020, + final_stats: 19591, from_end_match: 15396, from_price: 3992, from_start_match: 15395, @@ -160,6 +164,7 @@ export const indexLexics = { no_match_access_body: 13419, no_match_access_title: 13418, player: 14975, + players: 164, players_video: 13032, privacy_policy_and_statement: 15404, round_highilights: 13050, diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index 8b472265..8320833d 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -65,10 +65,12 @@ export const useMatchPage = () => { const { events, + fetchTeamsStats, handlePlaylistClick, matchPlaylists, selectedPlaylist, setFullMatchPlaylistDuration, + teamsStats, } = useMatchData(matchProfile) const profile = matchProfile @@ -156,6 +158,7 @@ export const useMatchPage = () => { countOfFilters, disablePlayingEpisodes, events, + fetchTeamsStats, filteredEvents, handlePlaylistClick, hideProfileCard, @@ -183,6 +186,7 @@ export const useMatchPage = () => { setUnreversed, setWatchAllEpisodesTimer, showProfileCard, + teamsStats, toggleActiveEvents, toggleActivePlayers, togglePopup, diff --git a/src/features/MatchPage/store/hooks/useMatchData.tsx b/src/features/MatchPage/store/hooks/useMatchData.tsx index 4cee0488..3f732f7c 100644 --- a/src/features/MatchPage/store/hooks/useMatchData.tsx +++ b/src/features/MatchPage/store/hooks/useMatchData.tsx @@ -6,7 +6,7 @@ import { import debounce from 'lodash/debounce' -import { MatchInfo } from 'requests/getMatchInfo' +import type { MatchInfo } from 'requests/getMatchInfo' import { usePageParams } from 'hooks/usePageParams' import { useInterval } from 'hooks/useInterval' @@ -16,6 +16,7 @@ import { useMatchPopupStore } from 'features/MatchPopup' import { useMatchPlaylists } from './useMatchPlaylists' import { useEvents } from './useEvents' +import { useTeamsStats } from './useTeamsStats' const MATCH_DATA_POLL_INTERVAL = 60000 const MATCH_PLAYLISTS_DELAY = 5000 @@ -33,6 +34,7 @@ export const useMatchData = (profile: MatchInfo) => { setSelectedPlaylist, } = useMatchPlaylists(profile) const { events, fetchMatchEvents } = useEvents() + const { fetchTeamsStats, teamsStats } = useTeamsStats(profile) const fetchPlaylistsDebounced = useMemo( () => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY), @@ -92,9 +94,11 @@ export const useMatchData = (profile: MatchInfo) => { return { events, + fetchTeamsStats, handlePlaylistClick, matchPlaylists, selectedPlaylist, setFullMatchPlaylistDuration, + teamsStats, } } diff --git a/src/features/MatchPage/store/hooks/useTeamsStats.tsx b/src/features/MatchPage/store/hooks/useTeamsStats.tsx new file mode 100644 index 00000000..dd4a979a --- /dev/null +++ b/src/features/MatchPage/store/hooks/useTeamsStats.tsx @@ -0,0 +1,58 @@ +import { + useEffect, + useState, + useMemo, + useCallback, +} from 'react' + +import flatMap from 'lodash/flatMap' +import reduce from 'lodash/reduce' +import includes from 'lodash/includes' + +import type { MatchInfo } from 'requests' +import { getTeamsStats, TeamStatItem } from 'requests' + +import { usePageParams } from 'hooks/usePageParams' + +import { useLexicsConfig } from 'features/LexicsStore' + +export const useTeamsStats = (matchProfile: MatchInfo) => { + const [teamsStats, setTeamsStats] = useState<{ + [teamId: string]: Array, + }>({}) + + const { profileId: matchId, sportName } = usePageParams() + + const lexics = useMemo(() => reduce>( + flatMap(teamsStats), + (acc, curr) => { + if (curr.param1?.lexic && !includes(acc, curr.param1.lexic)) { + acc.push(curr.param1.lexic) + } + + return acc + }, + [], + ), [teamsStats]) + + useLexicsConfig(lexics) + + const fetchTeamsStats = useCallback((second?: number) => { + if (!sportName) return + + getTeamsStats({ + matchId, + second, + sportName, + }).then(setTeamsStats) + }, [matchId, sportName]) + + useEffect(() => { + fetchTeamsStats() + }, [fetchTeamsStats]) + + return { + fetchTeamsStats, + teamsStats, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersPlaylists/index.tsx b/src/features/MatchSidePlaylists/components/PlayersPlaylists/index.tsx index d05ac36e..22b69298 100644 --- a/src/features/MatchSidePlaylists/components/PlayersPlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersPlaylists/index.tsx @@ -15,12 +15,10 @@ import type { } from 'features/MatchPage/types' import { Name } from 'features/Name' -import { T9n } from 'features/T9n' import { isEqual } from '../../helpers' import { PlayButton } from '../PlayButton' -import { BlockTitle } from '../../styled' import { Wrapper, List, @@ -58,9 +56,6 @@ export const PlayersPlaylists = ({ return ( - - - ` position: relative; border: none; - height: 34px; padding: 0; background-color: transparent; font-size: 12px; diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx new file mode 100644 index 00000000..095cfcbe --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx @@ -0,0 +1 @@ +export const CELL_WIDTH = 47 diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx new file mode 100644 index 00000000..811ddda6 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx @@ -0,0 +1,61 @@ +import type { SyntheticEvent } from 'react' +import { + useRef, + useState, + useEffect, +} from 'react' + +import { isMobileDevice } from 'config/userAgent' + +import { CELL_WIDTH } from './config' + +export const usePlayersTable = () => { + const containerRef = useRef(null) + const tableWrapperRef = useRef(null) + + const [showLeftArrow, setShowLeftArrow] = useState(false) + const [showRightArrow, setShowRightArrow] = useState(false) + + const cellWidth = isMobileDevice + ? ((containerRef.current?.clientWidth || 0) - 98) / 4 + : CELL_WIDTH + + const slideLeft = () => tableWrapperRef.current!.scrollBy(-cellWidth, 0) + const slideRight = () => tableWrapperRef.current!.scrollBy(cellWidth, 0) + + const handleScroll = (e: SyntheticEvent) => { + const { + clientWidth, + scrollLeft, + scrollWidth, + } = e.currentTarget + + const scrollRight = scrollWidth - (scrollLeft + clientWidth) + + setShowLeftArrow(scrollLeft > 1) + setShowRightArrow(scrollRight > 1) + } + + useEffect(() => { + const { + clientWidth = 0, + scrollLeft = 0, + scrollWidth = 0, + } = tableWrapperRef.current || {} + + const scrollRight = scrollWidth - (scrollLeft + clientWidth) + + setShowRightArrow(scrollRight > 1) + }, []) + + return { + cellWidth, + containerRef, + handleScroll, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + tableWrapperRef, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx index 46520e1b..0be29a9c 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx @@ -1,4 +1,7 @@ +import { usePlayersTable } from './hooks' import { + Container, + TableWrapper, Table, Thead, Th, @@ -7,237 +10,1721 @@ import { Td, PlayerNum, ParamShortTitle, + ArrowButtonRight, + ArrowButtonLeft, + Arrow, } from './styled' -export const PlayersTable = () => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - Min - - Pt - - Reb - - Ass - - To -
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
57 Selikhov9712214
-) +export const PlayersTable = () => { + const { + cellWidth, + containerRef, + handleScroll, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + tableWrapperRef, + } = usePlayersTable() + + return ( + + + {showLeftArrow && ( + + + + )} + {showRightArrow && ( + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Min + + Pt + + Reb + + Ass + + To + + Min + + Pt + + Reb + + Ass + + To + + Min + + Pt + + Reb + + Ass + + + To + + + Min + + Pt + + Reb + + Ass + + To +
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
+
+
+ ) +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx index 3d88c1f6..303332dd 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx @@ -1,16 +1,33 @@ import styled, { css } from 'styled-components/macro' +import { isMobileDevice } from 'config/userAgent' + import { customScrollbar } from 'features/Common' +import { + ArrowButton as ArrowButtonBase, + Arrow as ArrowBase, +} from 'features/HeaderFilters/components/DateFilter/styled' + +import { CELL_WIDTH } from './config' + +export const Container = styled.div` + position: relative; +` + +export const TableWrapper = styled.div` + max-height: calc(100vh - 235px); + border-radius: 5px; + overflow-x: auto; + scroll-behavior: smooth; + ${customScrollbar} +` export const Table = styled.table` width: 100%; border-radius: 5px; border-collapse: collapse; letter-spacing: -0.078px; - background-color: #333333; table-layout: fixed; - - ${customScrollbar} ` export const Thead = styled.thead` @@ -20,21 +37,33 @@ export const Thead = styled.thead` type ThProps = { sorted?: boolean, + width?: number, } -export const Th = styled.th` +export const Th = styled.th.attrs({ tabIndex: 0 })` + position: sticky; + left: 0; + top: 0; + width: ${({ width }) => width || CELL_WIDTH}px; font-size: 11px; color: ${({ theme }) => theme.colors.white}; text-transform: uppercase; + cursor: pointer; + background-color: #333333; + z-index: 2; :first-child { - width: 115px; + width: 90px; + z-index: 3; + cursor: default; } ${({ sorted }) => (sorted ? '' : css` - opacity: 0.5; + ${ParamShortTitle} { + opacity: 0.5; + } `)} ` @@ -56,18 +85,26 @@ type TdProps = { sorted?: boolean, } -export const Td = styled.td` +export const Td = styled.td.attrs(({ clickable }: TdProps) => ({ + ...clickable && { tabIndex: 0 }, +}))` font-size: 11px; text-align: center; color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)}; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + background-color: #333333; :first-child { + position: sticky; + left: 0; + z-index: 1; padding-left: 13px; text-align: left; color: ${({ theme }) => theme.colors.white}; } - ${({ sorted }) => (sorted ? css` font-weight: bold; @@ -84,3 +121,29 @@ export const Td = styled.td` export const PlayerNum = styled.span` color: rgba(255, 255, 255, 0.5); ` + +const ArrowButton = styled(ArrowButtonBase)` + position: absolute; + margin-top: 2px; + z-index: 4; + + ${isMobileDevice + ? css` + height: 45px; + margin-top: 0; + ` + : ''}; +` + +export const ArrowButtonRight = styled(ArrowButton)` + right: 0; +` + +export const ArrowButtonLeft = styled(ArrowButton)` + left: 75px; +` + +export const Arrow = styled(ArrowBase)` + width: 10px; + height: 10px; +` diff --git a/src/features/MatchSidePlaylists/components/TabStats/config.tsx b/src/features/MatchSidePlaylists/components/TabStats/config.tsx index 099a117f..3c14e7ff 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/config.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/config.tsx @@ -3,3 +3,8 @@ export enum Tabs { TEAM1, TEAM2, } + +export enum StatsType { + FINAL_STATS, + CURRENT_STATS, +} diff --git a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx new file mode 100644 index 00000000..f481f1ec --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx @@ -0,0 +1,32 @@ +import { useState } from 'react' + +import { useMatchPageStore } from 'features/MatchPage/store' + +import { StatsType, Tabs } from './config' + +export const useTabStats = () => { + const [statsType, setStatsType] = useState(StatsType.FINAL_STATS) + const [selectedTab, setSelectedTab] = useState(Tabs.TEAMS) + + const { fetchTeamsStats, teamsStats } = useMatchPageStore() + + const isFinalStatsType = statsType === StatsType.FINAL_STATS + + const switchTitleLexic = isFinalStatsType ? 'final_stats' : 'current_stats' + const tooltipLexic = isFinalStatsType ? 'display_stats_according_to_video' : 'display_all_stats' + + const toggleStatsType = () => { + const newStatsType = isFinalStatsType ? StatsType.CURRENT_STATS : StatsType.FINAL_STATS + + setStatsType(newStatsType) + } + + return { + isFinalStatsType, + selectedTab, + setSelectedTab, + switchTitleLexic, + toggleStatsType, + tooltipLexic, + } +} diff --git a/src/features/MatchSidePlaylists/components/TabStats/index.tsx b/src/features/MatchSidePlaylists/components/TabStats/index.tsx index c43592bb..1487e01f 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/index.tsx @@ -1,5 +1,8 @@ import { Tooltip } from 'features/Tooltip' +import { T9n } from 'features/T9n' +import { Tabs } from './config' +import { useTabStats } from './hooks' import { PlayersTable } from '../PlayersTable' import { TeamsStats } from '../TeamsStats' @@ -13,22 +16,58 @@ import { SwitchButton, } from './styled' -export const TabStats = () => ( - -
- - Teams - DIN - SPA - - - Final Stats - - - - -
- - {/* */} -
-) +const tabPanes = { + [Tabs.TEAMS]: TeamsStats, + [Tabs.TEAM1]: PlayersTable, + [Tabs.TEAM2]: PlayersTable, +} + +export const TabStats = () => { + const { + isFinalStatsType, + selectedTab, + setSelectedTab, + switchTitleLexic, + toggleStatsType, + tooltipLexic, + } = useTabStats() + + const TabPane = tabPanes[selectedTab] + + return ( + +
+ + setSelectedTab(Tabs.TEAMS)} + > + + + {/* setSelectedTab(Tabs.TEAM1)} + > + DIN + */} + {/* setSelectedTab(Tabs.TEAM2)} + > + SPA + */} + + + + + + + +
+ +
+ ) +} diff --git a/src/features/MatchSidePlaylists/components/TabStats/styled.tsx b/src/features/MatchSidePlaylists/components/TabStats/styled.tsx index f2f58203..477a56c0 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/styled.tsx @@ -1,6 +1,7 @@ import styled, { css } from 'styled-components/macro' import { TooltipWrapper } from 'features/Tooltip' +import { T9n } from 'features/T9n' export const Container = styled.div`` @@ -14,42 +15,40 @@ export const TabList = styled.div.attrs({ role: 'tablist' })` display: flex; ` -type TabProps = { - selected?: boolean, -} - -export const Tab = styled.div.attrs(({ selected }: TabProps) => ({ - 'aria-pressed': selected, - role: 'tab', -}))` +export const Tab = styled.button.attrs({ role: 'tab' })` display: flex; justify-content: space-between; align-items: center; - padding: 0 15px 10px; + padding: 0 10px 10px; font-size: 12px; color: ${({ theme }) => theme.colors.white}; - opacity: ${({ selected }) => (selected ? '1' : '0.4')}; + opacity: 0.4; cursor: pointer; + border: none; + background: none; border-bottom: 2px solid transparent; - - ${({ selected, theme }) => (selected - ? css` - border-color: ${theme.colors.white}; - ` - : '')} + &[aria-pressed="true"] { + opacity: 1; + border-color: currentColor; + } ` export const Switch = styled.div` display: flex; ` -export const SwitchTitle = styled.span` +export const SwitchTitle = styled(T9n)` font-size: 12px; color: ${({ theme }) => theme.colors.white}; + white-space: nowrap; ` -export const SwitchButton = styled.button` +type SwitchButtonProps = { + isFinalStatsType: boolean, +} + +export const SwitchButton = styled.button` position: relative; width: 20px; height: 7px; @@ -66,6 +65,8 @@ export const SwitchButton = styled.button` padding: 2px 10px; border-radius: 6px; transform: none; + font-size: 11px; + line-height: 1; ::before { display: none; @@ -78,7 +79,7 @@ export const SwitchButton = styled.button` } } - ${({ theme }) => (true // Позже будет добавлен пропс + ${({ isFinalStatsType, theme }) => (!isFinalStatsType ? css` background-image: linear-gradient( to right, diff --git a/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx b/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx index 222b9918..166f5c2f 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx @@ -1,13 +1,8 @@ import styled, { css } from 'styled-components/macro' -import { customScrollbar } from 'features/Common' - export const Container = styled.div` width: 100%; font-size: 11px; - background-color: #333333; - - ${customScrollbar} ` export const TeamShortName = styled.span` @@ -25,6 +20,7 @@ export const Row = styled.div` height: 45px; padding: 0 12px; border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); + background-color: #333333; :last-child { border-bottom: none; diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index 689c6fe5..6a4b303c 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -5,6 +5,8 @@ import { } from 'react' import reduce from 'lodash/reduce' +import isEmpty from 'lodash/isEmpty' +import compact from 'lodash/compact' import { useMatchPageStore } from 'features/MatchPage/store' @@ -15,6 +17,7 @@ export const useMatchSidePlaylists = () => { closePopup, events, matchPlaylists: playlists, + teamsStats, } = useMatchPageStore() const [selectedTab, setSelectedTab] = useState(Tabs.WATCH) const isWatchTabVisible = useMemo(() => { @@ -34,6 +37,21 @@ export const useMatchSidePlaylists = () => { events.length > 0 ), [events]) + const isPlayersTabVisible = useMemo(() => ( + !isEmpty(playlists.players.team1) + ), [playlists.players.team1]) + + const isStatsTabVisible = useMemo(() => ( + !isEmpty(teamsStats) + ), [teamsStats]) + + const hasLessThanFourTabs = compact([ + isWatchTabVisible, + isEventTabVisible, + isPlayersTabVisible, + isStatsTabVisible, + ]).length < 4 + useEffect(() => { switch (true) { case isWatchTabVisible: @@ -42,16 +60,29 @@ export const useMatchSidePlaylists = () => { case isEventTabVisible: setSelectedTab(Tabs.EVENTS) break + case isPlayersTabVisible: + setSelectedTab(Tabs.PLAYERS) + break + case isStatsTabVisible: + setSelectedTab(Tabs.STATS) + break } - }, [isEventTabVisible, isWatchTabVisible]) + }, [ + isEventTabVisible, + isPlayersTabVisible, + isStatsTabVisible, + isWatchTabVisible, + ]) useEffect(() => { if (selectedTab !== Tabs.EVENTS) closePopup() }, [selectedTab, closePopup]) return { + hasLessThanFourTabs, isEventTabVisible, - isStatsTabVisible: true, + isPlayersTabVisible, + isStatsTabVisible, isWatchTabVisible, onTabClick: setSelectedTab, selectedTab, diff --git a/src/features/MatchSidePlaylists/index.tsx b/src/features/MatchSidePlaylists/index.tsx index 25b08a12..b3ae4097 100644 --- a/src/features/MatchSidePlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/index.tsx @@ -42,8 +42,6 @@ type Props = { setCircleAnimation?: TSetCircleAnimation, } -const hasLessThanFourTabs = false - export const MatchSidePlaylists = ({ circleAnimation, onSelect, @@ -59,7 +57,9 @@ export const MatchSidePlaylists = ({ } = useMatchPageStore() const { + hasLessThanFourTabs, isEventTabVisible, + isPlayersTabVisible, isStatsTabVisible, isWatchTabVisible, onTabClick, @@ -108,7 +108,7 @@ export const MatchSidePlaylists = ({ {isWatchTabVisible ? ( onTabClick(Tabs.WATCH)} > @@ -117,25 +117,25 @@ export const MatchSidePlaylists = ({ ) : null} {isEventTabVisible ? ( onTabClick(Tabs.EVENTS)} > ) : null} - {isStatsTabVisible ? ( + {isPlayersTabVisible ? ( onTabClick(Tabs.PLAYERS)} > - + ) : null} {isStatsTabVisible ? ( onTabClick(Tabs.STATS)} > diff --git a/src/features/MatchSidePlaylists/styled.tsx b/src/features/MatchSidePlaylists/styled.tsx index 1a8a9e36..eec58e2d 100644 --- a/src/features/MatchSidePlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/styled.tsx @@ -43,7 +43,7 @@ export const TabsGroup = styled.div.attrs({ role: 'tablist' })` height: 40px; ${Tab} { - justify-content: initial; + justify-content: center; flex-direction: row; gap: 5px; } @@ -56,23 +56,18 @@ export const TabsGroup = styled.div.attrs({ role: 'tablist' })` : ''}; ` -type TabProps = { - selected?: boolean, -} - -export const Tab = styled.div.attrs(({ selected }: TabProps) => ({ - 'aria-pressed': selected, - role: 'tab', -}))` +export const Tab = styled.button.attrs({ role: 'tab' })` display: flex; flex-direction: column; justify-content: space-between; align-items: center; flex: 1; - opacity: ${({ selected }) => (selected ? '1' : '0.4')}; + opacity: 0.4; cursor: pointer; + border: none; + background: none; - :hover { + &[aria-pressed="true"], :hover { opacity: 1; } ` @@ -103,6 +98,7 @@ export const TabTitle = styled(T9n)` ` type TContainer = { + forVideoTab?: boolean, hasScroll: boolean, } diff --git a/src/hooks/usePageParams.tsx b/src/hooks/usePageParams.tsx index 4810663c..4d1df1c7 100644 --- a/src/hooks/usePageParams.tsx +++ b/src/hooks/usePageParams.tsx @@ -22,6 +22,7 @@ export const usePageParams = () => { return { profileId: Number(pageId), profileType: ProfileTypes[toUpper(profileName) as keyof typeof ProfileTypes], + sportName, sportType: SportTypes[toUpper(sportName) as keyof typeof SportTypes], } } diff --git a/src/requests/getTeamsStats.tsx b/src/requests/getTeamsStats.tsx new file mode 100644 index 00000000..027598ff --- /dev/null +++ b/src/requests/getTeamsStats.tsx @@ -0,0 +1,56 @@ +import isUndefined from 'lodash/isUndefined' + +import { callApi } from 'helpers' + +type Param = { + clickable: boolean, + data_type: string, + id: number, + lexic: number, + markers: Array, + name_en: string, + name_ru: string, + val: number, +} + +export type TeamStatItem = { + lexic: number, + name_en: string, + name_ru: string, + order: number, + param1: Param, + param2: Param | null, +} + +type Response = { + data?: { + [teamId: string]: Array, + }, + error?: string, + message?: string, +} + +type GetTeamsStatsArgs = { + matchId: number, + second?: number, + sportName: string, +} + +export const getTeamsStats = async ({ + matchId, + second, + sportName, +}: GetTeamsStatsArgs) => { + const config = { + method: 'GET', + } + + const response: Response = await callApi({ + config, + url: `http://3.248.230.144:8888/${sportName}/matches/${matchId}/teams/stats?group_num=0${isUndefined(second) ? '' : `&second=${second}`}`, + }) + + if (response.error) Promise.reject(response) + + return Promise.resolve(response.data || {}) +} diff --git a/src/requests/index.tsx b/src/requests/index.tsx index b8074c36..50471756 100644 --- a/src/requests/index.tsx +++ b/src/requests/index.tsx @@ -25,3 +25,4 @@ export * from './getPlayerPlaylists' export * from './getSubscriptions' export * from './buySubscription' export * from './saveMatchStats' +export * from './getTeamsStats' -- 2.30.2 From 49403a674655c0f8892eb77ed9514fb359e0de83 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Thu, 17 Nov 2022 15:16:48 +0500 Subject: [PATCH 23/31] feat(in-142): match stats tab --- .../components/FinishedMatch/index.tsx | 7 +- .../components/LiveMatch/hooks/index.tsx | 8 +- src/features/MatchPage/store/hooks/index.tsx | 8 + .../MatchPage/store/hooks/useMatchData.tsx | 12 +- .../MatchPage/store/hooks/useTeamsStats.tsx | 57 ++-- .../components/MatchPlaylists/index.tsx | 39 ++- .../components/VideoDate/index.tsx | 0 .../components/VideoDate/styled.tsx | 0 .../{TabVideo => Matches}/index.tsx | 12 +- .../{TabVideo => Matches}/styled.tsx | 9 +- .../components/PlayersPlaylists/styled.tsx | 2 + .../components/TabStats/hooks.tsx | 3 +- .../components/TabStats/index.tsx | 4 +- .../components/TabWatch/index.tsx | 77 +++-- .../components/TeamsStats/index.tsx | 276 ------------------ .../components/TeamsStatsTable/hooks.tsx | 30 ++ .../components/TeamsStatsTable/index.tsx | 93 ++++++ .../styled.tsx | 17 +- src/features/MatchSidePlaylists/hooks.tsx | 28 +- src/features/MatchSidePlaylists/index.tsx | 3 + src/features/MatchSidePlaylists/styled.tsx | 6 +- .../MultiSourcePlayer/hooks/index.tsx | 3 + src/requests/getTeamsStats.tsx | 4 +- 23 files changed, 320 insertions(+), 378 deletions(-) rename src/features/MatchSidePlaylists/components/{TabVideo => Matches}/components/VideoDate/index.tsx (100%) rename src/features/MatchSidePlaylists/components/{TabVideo => Matches}/components/VideoDate/styled.tsx (100%) rename src/features/MatchSidePlaylists/components/{TabVideo => Matches}/index.tsx (90%) rename src/features/MatchSidePlaylists/components/{TabVideo => Matches}/styled.tsx (63%) delete mode 100644 src/features/MatchSidePlaylists/components/TeamsStats/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx create mode 100644 src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx rename src/features/MatchSidePlaylists/components/{TeamsStats => TeamsStatsTable}/styled.tsx (70%) diff --git a/src/features/MatchPage/components/FinishedMatch/index.tsx b/src/features/MatchPage/components/FinishedMatch/index.tsx index d10f60d0..eabc0ea3 100644 --- a/src/features/MatchPage/components/FinishedMatch/index.tsx +++ b/src/features/MatchPage/components/FinishedMatch/index.tsx @@ -17,7 +17,11 @@ import { useMatchPageStore } from '../../store' export const FinishedMatch = () => { const [circleAnimation, setCircleAnimation] = useState(initialCircleAnimation) - const { isOpenPopup, profile } = useMatchPageStore() + const { + isOpenPopup, + profile, + setPlayingProgress, + } = useMatchPageStore() const { chapters, closeSettingsPopup, @@ -51,6 +55,7 @@ export const FinishedMatch = () => { isOpenPopup={isOpenPopup} chapters={chapters} onPlayingChange={onPlayingChange} + onPlayerProgressChange={setPlayingProgress} profile={profile} /> diff --git a/src/features/MatchPage/components/LiveMatch/hooks/index.tsx b/src/features/MatchPage/components/LiveMatch/hooks/index.tsx index e4240ad0..eab6f4b1 100644 --- a/src/features/MatchPage/components/LiveMatch/hooks/index.tsx +++ b/src/features/MatchPage/components/LiveMatch/hooks/index.tsx @@ -21,6 +21,7 @@ export const useLiveMatch = () => { profile, selectedPlaylist, setFullMatchPlaylistDuration, + setPlayingProgress, } = useMatchPageStore() const { profileId: matchId, sportType } = usePageParams() const resume = useResumeUrlParam() @@ -45,7 +46,7 @@ export const useLiveMatch = () => { } = usePlaylistLogger() const { - onPlayerProgressChange, + onPlayerProgressChange: playerProgressChange, onPlayingChange: notifyProgressLogger, } = usePlayerProgressReporter() @@ -66,6 +67,11 @@ export const useLiveMatch = () => { handlePlaylistClick(playlist, e) } + const onPlayerProgressChange = (seconds: number, period = 0) => { + playerProgressChange(seconds, period) + setPlayingProgress(seconds * 1000) + } + return { chapters, isPlayFilterEpisodes, diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index 8320833d..748c0b7c 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -68,8 +68,12 @@ export const useMatchPage = () => { fetchTeamsStats, handlePlaylistClick, matchPlaylists, + playingProgress, selectedPlaylist, setFullMatchPlaylistDuration, + setPlayingProgress, + setStatsType, + statsType, teamsStats, } = useMatchData(matchProfile) @@ -173,6 +177,7 @@ export const useMatchPage = () => { plaingOrder, playEpisodes, playNextEpisode, + playingProgress, profile, profileCardShown, resetEvents, @@ -182,10 +187,13 @@ export const useMatchPage = () => { setFullMatchPlaylistDuration, setIsPlayinFiltersEpisodes, setPlaingOrder, + setPlayingProgress, setReversed, + setStatsType, setUnreversed, setWatchAllEpisodesTimer, showProfileCard, + statsType, teamsStats, toggleActiveEvents, toggleActivePlayers, diff --git a/src/features/MatchPage/store/hooks/useMatchData.tsx b/src/features/MatchPage/store/hooks/useMatchData.tsx index 3f732f7c..3aa9f0fe 100644 --- a/src/features/MatchPage/store/hooks/useMatchData.tsx +++ b/src/features/MatchPage/store/hooks/useMatchData.tsx @@ -25,6 +25,7 @@ export const useMatchData = (profile: MatchInfo) => { const { profileId: matchId, sportType } = usePageParams() const { chapters } = useMatchPopupStore() const [matchDuration, setMatchDuration] = useState(0) + const [playingProgress, setPlayingProgress] = useState(0) const { fetchMatchPlaylists, handlePlaylistClick, @@ -34,7 +35,12 @@ export const useMatchData = (profile: MatchInfo) => { setSelectedPlaylist, } = useMatchPlaylists(profile) const { events, fetchMatchEvents } = useEvents() - const { fetchTeamsStats, teamsStats } = useTeamsStats(profile) + const { + fetchTeamsStats, + setStatsType, + statsType, + teamsStats, + } = useTeamsStats(profile, playingProgress) const fetchPlaylistsDebounced = useMemo( () => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY), @@ -97,8 +103,12 @@ export const useMatchData = (profile: MatchInfo) => { fetchTeamsStats, handlePlaylistClick, matchPlaylists, + playingProgress, selectedPlaylist, setFullMatchPlaylistDuration, + setPlayingProgress, + setStatsType, + statsType, teamsStats, } } diff --git a/src/features/MatchPage/store/hooks/useTeamsStats.tsx b/src/features/MatchPage/store/hooks/useTeamsStats.tsx index dd4a979a..b7a6d000 100644 --- a/src/features/MatchPage/store/hooks/useTeamsStats.tsx +++ b/src/features/MatchPage/store/hooks/useTeamsStats.tsx @@ -2,42 +2,33 @@ import { useEffect, useState, useMemo, - useCallback, } from 'react' -import flatMap from 'lodash/flatMap' -import reduce from 'lodash/reduce' -import includes from 'lodash/includes' +import throttle from 'lodash/throttle' import type { MatchInfo } from 'requests' import { getTeamsStats, TeamStatItem } from 'requests' import { usePageParams } from 'hooks/usePageParams' -import { useLexicsConfig } from 'features/LexicsStore' +import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' -export const useTeamsStats = (matchProfile: MatchInfo) => { +const REQUEST_DELAY = 3000 +const STATS_POLL_INTERVAL = 30000 + +export const useTeamsStats = (matchProfile: MatchInfo, playingProgress: number) => { + const [statsType, setStatsType] = useState(StatsType.FINAL_STATS) const [teamsStats, setTeamsStats] = useState<{ [teamId: string]: Array, }>({}) const { profileId: matchId, sportName } = usePageParams() - const lexics = useMemo(() => reduce>( - flatMap(teamsStats), - (acc, curr) => { - if (curr.param1?.lexic && !includes(acc, curr.param1.lexic)) { - acc.push(curr.param1.lexic) - } - - return acc - }, - [], - ), [teamsStats]) + const progressSec = Math.floor(playingProgress / 1000) - useLexicsConfig(lexics) + const isCurrentStats = statsType === StatsType.CURRENT_STATS - const fetchTeamsStats = useCallback((second?: number) => { + const fetchTeamsStats = useMemo(() => throttle((second?: number) => { if (!sportName) return getTeamsStats({ @@ -45,14 +36,36 @@ export const useTeamsStats = (matchProfile: MatchInfo) => { second, sportName, }).then(setTeamsStats) - }, [matchId, sportName]) + }, REQUEST_DELAY), [matchId, sportName]) + + useEffect(() => { + let timer: ReturnType + + if (!isCurrentStats) { + fetchTeamsStats() + } + + if (matchProfile?.live) { + timer = setInterval(() => { + if (isCurrentStats) return + + fetchTeamsStats() + }, STATS_POLL_INTERVAL) + } + + return () => clearInterval(timer) + }, [fetchTeamsStats, matchProfile?.live, isCurrentStats]) useEffect(() => { - fetchTeamsStats() - }, [fetchTeamsStats]) + if (isCurrentStats) { + fetchTeamsStats(progressSec) + } + }, [fetchTeamsStats, progressSec, isCurrentStats]) return { fetchTeamsStats, + setStatsType, + statsType, teamsStats, } } diff --git a/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx b/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx index e0e49fb9..a0245220 100644 --- a/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx @@ -1,8 +1,8 @@ -import { useMemo } from 'react' +import type { ForwardedRef } from 'react' +import { forwardRef } from 'react' import styled, { css } from 'styled-components/macro' -import filter from 'lodash/filter' import isEmpty from 'lodash/isEmpty' import map from 'lodash/map' @@ -15,6 +15,8 @@ import { T9n } from 'features/T9n' import { PlayButton } from '../PlayButton' +export const LIST_ITEM_INDENT = 12 + type Props = { live?: boolean, onSelect?: (selectedMathPlaylist: PlaylistOption) => void, @@ -25,7 +27,7 @@ type Props = { const List = styled.ul`` const Item = styled.li` - margin-bottom: 12px; + margin-bottom: ${LIST_ITEM_INDENT}px; width: 100%; height: 36px; ${isMobileDevice @@ -36,24 +38,17 @@ const Item = styled.li` : ''}; ` -export const MatchPlaylists = ({ - live, - onSelect, - playlists, - selectedMathPlaylist, -}: Props) => { - const filteredPlayListByDuration = useMemo(() => ( - filter(playlists, (playlist) => ( - live - ? Boolean(playlist.duration) || (playlist.id === 'full_game') - : Boolean(playlist.duration) - )) - ), [playlists, live]) - - return ( - +export const MatchPlaylists = forwardRef( + ({ + live, + onSelect, + playlists, + selectedMathPlaylist, + }: Props, + ref: ForwardedRef) => ( + { - map(filteredPlayListByDuration, (playlist) => ( + map(playlists, (playlist) => ( - ) -} + ), +) diff --git a/src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/index.tsx b/src/features/MatchSidePlaylists/components/Matches/components/VideoDate/index.tsx similarity index 100% rename from src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/index.tsx rename to src/features/MatchSidePlaylists/components/Matches/components/VideoDate/index.tsx diff --git a/src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/styled.tsx b/src/features/MatchSidePlaylists/components/Matches/components/VideoDate/styled.tsx similarity index 100% rename from src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/styled.tsx rename to src/features/MatchSidePlaylists/components/Matches/components/VideoDate/styled.tsx diff --git a/src/features/MatchSidePlaylists/components/TabVideo/index.tsx b/src/features/MatchSidePlaylists/components/Matches/index.tsx similarity index 90% rename from src/features/MatchSidePlaylists/components/TabVideo/index.tsx rename to src/features/MatchSidePlaylists/components/Matches/index.tsx index 2a8740d6..11d9d7de 100644 --- a/src/features/MatchSidePlaylists/components/TabVideo/index.tsx +++ b/src/features/MatchSidePlaylists/components/Matches/index.tsx @@ -23,13 +23,15 @@ import { VideoDate } from './components/VideoDate' import { MatchesWrapper } from './styled' type Props = { + additionalScrollHeight: number, profile: MatchInfo, tournamentData: TournamentData, } const formatDate = (date: Date) => format(date, 'yyyy-MM-dd') -export const TabVideo = ({ +export const Matches = ({ + additionalScrollHeight, profile, tournamentData, }: Props) => { @@ -75,7 +77,7 @@ export const TabVideo = ({ const hasScroll = scrollHeight > clientHeight setOverflow(hasScroll) - }, [ref, selectedDate]) + }, [ref.current?.clientHeight, selectedDate]) if (tournamentData.matches.length <= 1) return null @@ -88,7 +90,11 @@ export const TabVideo = ({ profileDate={profileDate} onDateClick={setSelectedDate} /> - + { map(sortBy(matches, ({ live }) => !live), (match) => ( ` +type MatchesWrapperProps = { + additionalScrollHeight: number, + hasScroll?: boolean, +} + +export const MatchesWrapper = styled.div` overflow-y: auto; - max-height: calc(100vh - 170px); + max-height: calc(100vh - 165px - ${({ additionalScrollHeight }) => additionalScrollHeight}px); padding-right: ${({ hasScroll }) => (hasScroll ? '10px' : '')}; > * { diff --git a/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx b/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx index 119cec6f..c250bfbb 100644 --- a/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx @@ -28,6 +28,7 @@ export const PlayerAvatar = styled(ProfileLogo)` ` export const Tabs = styled.div` + margin-top: -10px; margin-bottom: 23px; ` @@ -38,6 +39,7 @@ type TabProps = { export const Tab = styled.button` position: relative; border: none; + height: 34px; padding: 0; background-color: transparent; font-size: 12px; diff --git a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx index f481f1ec..935f81b5 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx @@ -5,10 +5,9 @@ import { useMatchPageStore } from 'features/MatchPage/store' import { StatsType, Tabs } from './config' export const useTabStats = () => { - const [statsType, setStatsType] = useState(StatsType.FINAL_STATS) const [selectedTab, setSelectedTab] = useState(Tabs.TEAMS) - const { fetchTeamsStats, teamsStats } = useMatchPageStore() + const { setStatsType, statsType } = useMatchPageStore() const isFinalStatsType = statsType === StatsType.FINAL_STATS diff --git a/src/features/MatchSidePlaylists/components/TabStats/index.tsx b/src/features/MatchSidePlaylists/components/TabStats/index.tsx index 1487e01f..6320ab53 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/index.tsx @@ -4,7 +4,7 @@ import { T9n } from 'features/T9n' import { Tabs } from './config' import { useTabStats } from './hooks' import { PlayersTable } from '../PlayersTable' -import { TeamsStats } from '../TeamsStats' +import { TeamsStatsTable } from '../TeamsStatsTable' import { Container, @@ -17,7 +17,7 @@ import { } from './styled' const tabPanes = { - [Tabs.TEAMS]: TeamsStats, + [Tabs.TEAMS]: TeamsStatsTable, [Tabs.TEAM1]: PlayersTable, [Tabs.TEAM2]: PlayersTable, } diff --git a/src/features/MatchSidePlaylists/components/TabWatch/index.tsx b/src/features/MatchSidePlaylists/components/TabWatch/index.tsx index 3c1acf33..368e957e 100644 --- a/src/features/MatchSidePlaylists/components/TabWatch/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabWatch/index.tsx @@ -1,6 +1,11 @@ -import { Fragment } from 'react' +import { + Fragment, + useMemo, + useRef, +} from 'react' import size from 'lodash/size' +import filter from 'lodash/filter' import type { PlaylistOption, @@ -10,12 +15,13 @@ import type { import type { MatchInfo } from 'requests' import { DropdownSection } from '../DropdownSection' -import { MatchPlaylists } from '../MatchPlaylists' +import { MatchPlaylists, LIST_ITEM_INDENT } from '../MatchPlaylists' import { SideInterviews } from '../SideInterviews' -import { TabVideo } from '../../components/TabVideo' +import { Matches } from '../Matches' type Props = { onSelect: (option: PlaylistOption) => void, + playListFilter: number, playlists: Playlists, profile: MatchInfo, selectedPlaylist?: PlaylistOption, @@ -24,31 +30,50 @@ type Props = { export const TabWatch = ({ onSelect, + playListFilter, playlists, profile, selectedPlaylist, tournamentData, -}: Props) => ( - - - - { + const matchPlaylistsRef = useRef(null) + + const additionalScrollHeight = (matchPlaylistsRef.current?.clientHeight || 0) + LIST_ITEM_INDENT + + const filteredPlayListByDuration = useMemo(() => ( + filter(playlists.match, (playlist) => ( + profile?.live + ? Boolean(playlist.duration) || (playlist.id === 'full_game') + : Boolean(playlist.duration) + )) + ), [playlists.match, profile?.live]) + + return ( + + {playListFilter > 1 && ( + + )} + + + + - - - -) +
+ ) +} diff --git a/src/features/MatchSidePlaylists/components/TeamsStats/index.tsx b/src/features/MatchSidePlaylists/components/TeamsStats/index.tsx deleted file mode 100644 index 17a1dad5..00000000 --- a/src/features/MatchSidePlaylists/components/TeamsStats/index.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import { - Container, - Row, - TeamShortName, - ParamValueContainer, - ParamValue, - ParamTitle, -} from './styled' - -export const TeamsStats = () => ( - - - DIN - SPA - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - - - 90 - - Points - 123 - - -) diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx new file mode 100644 index 00000000..800a83de --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx @@ -0,0 +1,30 @@ +import isNumber from 'lodash/isNumber' +import find from 'lodash/find' + +import type { Param } from 'requests' + +import { useMatchPageStore } from 'features/MatchPage/store' + +export const useTeamsStatsTable = () => { + const { profile, teamsStats } = useMatchPageStore() + + const getDisplayedValue = (val: any) => ( + isNumber(val) ? val : '-' + ) + + const getStatItemById = (paramId: number) => { + if (!profile) return null + + return find(teamsStats[profile?.team2.id], ({ param1 }) => param1.id === paramId) || null + } + + const isClickable = (param: Param) => ( + isNumber(param.val) && param.clickable + ) + + return { + getDisplayedValue, + getStatItemById, + isClickable, + } +} diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx new file mode 100644 index 00000000..610d2c8c --- /dev/null +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx @@ -0,0 +1,93 @@ +import { Fragment } from 'react' + +import map from 'lodash/map' + +import { useMatchPageStore } from 'features/MatchPage/store' +import { useLexicsStore } from 'features/LexicsStore' + +import { useTeamsStatsTable } from './hooks' +import { + Container, + Row, + TeamShortName, + ParamValueContainer, + ParamValue, + StatItemTitle, + Divider, +} from './styled' + +export const TeamsStatsTable = () => { + const { profile, teamsStats } = useMatchPageStore() + const { + getDisplayedValue, + getStatItemById, + isClickable, + } = useTeamsStatsTable() + const { lang } = useLexicsStore() + + if (!profile) return null + + return ( + + + + + + + {map(teamsStats[profile.team1.id], (team1StatItem) => { + const team2StatItem = getStatItemById(team1StatItem.param1.id) + const statItemTitle = team1StatItem[`name_${lang === 'ru' ? 'ru' : 'en'}`] + + return ( + + + + {getDisplayedValue(team1StatItem.param1.val)} + + {team1StatItem.param2 && ( + + / + + {getDisplayedValue(team1StatItem.param2.val)} + + + )} + + + {statItemTitle} + + {team2StatItem && ( + + + {getDisplayedValue(team2StatItem.param1.val)} + + {team2StatItem.param2 && ( + + / + + {getDisplayedValue(team2StatItem.param2.val)} + + + )} + + )} + + ) + })} + + ) +} diff --git a/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx similarity index 70% rename from src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx rename to src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx index 166f5c2f..0eb38886 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStats/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx @@ -1,11 +1,13 @@ import styled, { css } from 'styled-components/macro' +import { Name } from 'features/Name' + export const Container = styled.div` width: 100%; font-size: 11px; ` -export const TeamShortName = styled.span` +export const TeamShortName = styled(Name)` color: ${({ theme }) => theme.colors.white}; letter-spacing: -0.078px; text-transform: uppercase; @@ -33,7 +35,10 @@ type TParamValue = { clickable?: boolean, } -export const ParamValue = styled.span` +export const ParamValue = styled.span.attrs(({ clickable }: TParamValue) => ({ + ...clickable && { tabIndex: 0 }, +}))` + font-weight: 600; color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)}; ${({ clickable }) => (clickable @@ -43,10 +48,16 @@ export const ParamValue = styled.span` : '')} ` -export const ParamTitle = styled.span` +export const StatItemTitle = styled.span` color: ${({ theme }) => theme.colors.white}; letter-spacing: -0.078px; text-transform: uppercase; font-weight: 600; opacity: 0.5; ` + +export const Divider = styled.span` + color: ${({ theme }) => theme.colors.white}; + opacity: 0.5; + font-weight: 600; +` diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index 6a4b303c..1fbf40d4 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -18,20 +18,23 @@ export const useMatchSidePlaylists = () => { events, matchPlaylists: playlists, teamsStats, + tournamentData, } = useMatchPageStore() const [selectedTab, setSelectedTab] = useState(Tabs.WATCH) - const isWatchTabVisible = useMemo(() => { - const playListFilter = reduce( - playlists.match, - (acc, item) => { - let result = acc - if (item.duration) result++ - return result - }, - 0, - ) - return playListFilter > 1 - }, [playlists]) + + const playListFilter = useMemo(() => reduce( + playlists.match, + (acc, item) => { + let result = acc + if (item.duration) result++ + return result + }, + 0, + ), [playlists.match]) + + const isWatchTabVisible = useMemo(() => ( + playListFilter > 1 || tournamentData.matchDates.length > 1 + ), [playListFilter, tournamentData.matchDates.length]) const isEventTabVisible = useMemo(() => ( events.length > 0 @@ -85,6 +88,7 @@ export const useMatchSidePlaylists = () => { isStatsTabVisible, isWatchTabVisible, onTabClick: setSelectedTab, + playListFilter, selectedTab, } } diff --git a/src/features/MatchSidePlaylists/index.tsx b/src/features/MatchSidePlaylists/index.tsx index b3ae4097..a7baaa77 100644 --- a/src/features/MatchSidePlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/index.tsx @@ -63,6 +63,7 @@ export const MatchSidePlaylists = ({ isStatsTabVisible, isWatchTabVisible, onTabClick, + playListFilter, selectedTab, } = useMatchSidePlaylists() @@ -148,6 +149,7 @@ export const MatchSidePlaylists = ({ diff --git a/src/features/MatchSidePlaylists/styled.tsx b/src/features/MatchSidePlaylists/styled.tsx index eec58e2d..ab6ec05f 100644 --- a/src/features/MatchSidePlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/styled.tsx @@ -98,7 +98,7 @@ export const TabTitle = styled(T9n)` ` type TContainer = { - forVideoTab?: boolean, + forWatchTab?: boolean, hasScroll: boolean, } @@ -106,8 +106,8 @@ export const Container = styled.div` width: 320px; margin-top: 23px; max-height: calc(100vh - 130px); - overflow-y: ${({ forVideoTab }) => (forVideoTab ? 'hidden' : 'auto')}; - padding-right: ${({ forVideoTab }) => (forVideoTab ? '0' : '')}; + overflow-y: ${({ forWatchTab }) => (forWatchTab ? 'hidden' : 'auto')}; + padding-right: ${({ forWatchTab }) => (forWatchTab ? '0' : '')}; padding-left: 14px; padding-right: ${({ hasScroll }) => (hasScroll ? '10px' : '')}; diff --git a/src/features/MultiSourcePlayer/hooks/index.tsx b/src/features/MultiSourcePlayer/hooks/index.tsx index 22022292..c4e596f8 100644 --- a/src/features/MultiSourcePlayer/hooks/index.tsx +++ b/src/features/MultiSourcePlayer/hooks/index.tsx @@ -56,6 +56,7 @@ export type Props = { chapters: Chapters, isOpenPopup?: boolean, onError?: () => void, + onPlayerProgressChange?: (ms: number) => void, onPlayingChange: (playing: boolean) => void, profile: MatchInfo, setCircleAnimation: TSetCircleAnimation, @@ -64,6 +65,7 @@ export type Props = { export const useMultiSourcePlayer = ({ chapters, onError, + onPlayerProgressChange, onPlayingChange, setCircleAnimation, }: Props) => { @@ -201,6 +203,7 @@ export const useMultiSourcePlayer = ({ timeForStatistics.current = (value + chapter.startMs) / 1000 setPlayerState({ playedProgress: value }) + onPlayerProgressChange?.(playedMs + chapter.startMs) } const onEnded = () => { diff --git a/src/requests/getTeamsStats.tsx b/src/requests/getTeamsStats.tsx index 027598ff..bfaf4c61 100644 --- a/src/requests/getTeamsStats.tsx +++ b/src/requests/getTeamsStats.tsx @@ -2,7 +2,7 @@ import isUndefined from 'lodash/isUndefined' import { callApi } from 'helpers' -type Param = { +export type Param = { clickable: boolean, data_type: string, id: number, @@ -10,7 +10,7 @@ type Param = { markers: Array, name_en: string, name_ru: string, - val: number, + val: number | null, } export type TeamStatItem = { -- 2.30.2 From 7488e1ebd24a41e1dc35c5b0ad03bfd860452ffe Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Thu, 17 Nov 2022 15:40:47 +0500 Subject: [PATCH 24/31] feat(in-142): pr fixes --- src/features/MatchPage/components/FinishedMatch/index.tsx | 4 ++-- src/features/MatchPage/store/hooks/index.tsx | 4 ++-- src/features/StreamPlayer/components/YoutubePlayer/index.tsx | 4 ++-- src/features/StreamPlayer/index.tsx | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/features/MatchPage/components/FinishedMatch/index.tsx b/src/features/MatchPage/components/FinishedMatch/index.tsx index eabc0ea3..d8e22586 100644 --- a/src/features/MatchPage/components/FinishedMatch/index.tsx +++ b/src/features/MatchPage/components/FinishedMatch/index.tsx @@ -18,7 +18,7 @@ import { useMatchPageStore } from '../../store' export const FinishedMatch = () => { const [circleAnimation, setCircleAnimation] = useState(initialCircleAnimation) const { - isOpenPopup, + isOpenFiltersPopup, profile, setPlayingProgress, } = useMatchPageStore() @@ -52,7 +52,7 @@ export const FinishedMatch = () => { { countOfFilters, filters, isEmptyFilters, - isOpen: isOpenPopup, + isOpen: isOpenFiltersPopup, resetEvents, resetPlayers, toggle: togglePopup, @@ -168,7 +168,7 @@ export const useMatchPage = () => { hideProfileCard, isEmptyFilters, isLiveMatch, - isOpenPopup, + isOpenFiltersPopup, isPlayFilterEpisodes, isStarted, likeImage, diff --git a/src/features/StreamPlayer/components/YoutubePlayer/index.tsx b/src/features/StreamPlayer/components/YoutubePlayer/index.tsx index 75c2b2bd..99815ad5 100644 --- a/src/features/StreamPlayer/components/YoutubePlayer/index.tsx +++ b/src/features/StreamPlayer/components/YoutubePlayer/index.tsx @@ -7,7 +7,7 @@ import { PlayerWrapper } from '../../styled' import { useVideoPlayer, Props } from '../../hooks' export const YoutubePlayer = (props: Props) => { - const { isOpenPopup, profile } = useMatchPageStore() + const { isOpenFiltersPopup, profile } = useMatchPageStore() const { onMouseMove, @@ -34,7 +34,7 @@ export const YoutubePlayer = (props: Props) => { onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} > - {isOpenPopup && } + {isOpenFiltersPopup && } { - const { isOpenPopup, profile } = useMatchPageStore() + const { isOpenFiltersPopup, profile } = useMatchPageStore() const { user } = useAuthStore() const { @@ -96,7 +96,7 @@ export const StreamPlayer = (props: Props) => { onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} > - {isOpenPopup && } + {isOpenFiltersPopup && } -- 2.30.2 From df015ab1dd0ad926aa9916816ae4aff28225619c Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Thu, 17 Nov 2022 16:56:55 +0500 Subject: [PATCH 25/31] feat(in-142): change stats api --- src/requests/getTeamsStats.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requests/getTeamsStats.tsx b/src/requests/getTeamsStats.tsx index bfaf4c61..4be9afee 100644 --- a/src/requests/getTeamsStats.tsx +++ b/src/requests/getTeamsStats.tsx @@ -47,7 +47,7 @@ export const getTeamsStats = async ({ const response: Response = await callApi({ config, - url: `http://3.248.230.144:8888/${sportName}/matches/${matchId}/teams/stats?group_num=0${isUndefined(second) ? '' : `&second=${second}`}`, + url: `https://statistic.insports.tv/${sportName}/matches/${matchId}/teams/stats?group_num=0${isUndefined(second) ? '' : `&second=${second}`}`, }) if (response.error) Promise.reject(response) -- 2.30.2 From df3a2fd6bce8d4adb63ce0af558a0c558c2d9019 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Thu, 17 Nov 2022 19:27:23 +0500 Subject: [PATCH 26/31] feat(in-142): fixes --- src/features/MatchSidePlaylists/components/TabStats/hooks.tsx | 2 +- src/features/MatchSidePlaylists/components/TabStats/index.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx index 935f81b5..0346586f 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx @@ -12,7 +12,7 @@ export const useTabStats = () => { const isFinalStatsType = statsType === StatsType.FINAL_STATS const switchTitleLexic = isFinalStatsType ? 'final_stats' : 'current_stats' - const tooltipLexic = isFinalStatsType ? 'display_stats_according_to_video' : 'display_all_stats' + const tooltipLexic = isFinalStatsType ? 'display_all_stats' : 'display_stats_according_to_video' const toggleStatsType = () => { const newStatsType = isFinalStatsType ? StatsType.CURRENT_STATS : StatsType.FINAL_STATS diff --git a/src/features/MatchSidePlaylists/components/TabStats/index.tsx b/src/features/MatchSidePlaylists/components/TabStats/index.tsx index 6320ab53..82311d18 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/index.tsx @@ -1,3 +1,5 @@ +import { isMobileDevice } from 'config/userAgent' + import { Tooltip } from 'features/Tooltip' import { T9n } from 'features/T9n' @@ -63,7 +65,7 @@ export const TabStats = () => { isFinalStatsType={isFinalStatsType} onClick={toggleStatsType} > - + {!isMobileDevice && }
-- 2.30.2 From 943e3672bdfc6906855441c5fde580d82a796dfd Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Tue, 22 Nov 2022 15:59:28 +0500 Subject: [PATCH 27/31] feat(in-142): fixes --- .../components/TabStats/styled.tsx | 1 + .../components/TeamsStatsTable/styled.tsx | 4 +++- src/features/MatchSidePlaylists/styled.tsx | 17 +++++++++++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/features/MatchSidePlaylists/components/TabStats/styled.tsx b/src/features/MatchSidePlaylists/components/TabStats/styled.tsx index 477a56c0..13318a33 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/styled.tsx @@ -62,6 +62,7 @@ export const SwitchButton = styled.button` ${TooltipWrapper} { left: auto; right: 0; + top: 15px; padding: 2px 10px; border-radius: 6px; transform: none; diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx index 0eb38886..39b3a3c7 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx @@ -5,6 +5,9 @@ import { Name } from 'features/Name' export const Container = styled.div` width: 100%; font-size: 11px; + overflow: hidden; + border-radius: 5px; + background-color: #333333; ` export const TeamShortName = styled(Name)` @@ -22,7 +25,6 @@ export const Row = styled.div` height: 45px; padding: 0 12px; border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); - background-color: #333333; :last-child { border-bottom: none; diff --git a/src/features/MatchSidePlaylists/styled.tsx b/src/features/MatchSidePlaylists/styled.tsx index ab6ec05f..75a962a4 100644 --- a/src/features/MatchSidePlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/styled.tsx @@ -56,6 +56,12 @@ export const TabsGroup = styled.div.attrs({ role: 'tablist' })` : ''}; ` +export const TabTitle = styled(T9n)` + font-size: 8px; + text-transform: uppercase; + color: ${({ theme }) => theme.colors.white}; +` + export const Tab = styled.button.attrs({ role: 'tab' })` display: flex; flex-direction: column; @@ -69,6 +75,11 @@ export const Tab = styled.button.attrs({ role: 'tab' })` &[aria-pressed="true"], :hover { opacity: 1; + + ${TabTitle} { + font-size: 9px; + font-weight: 600; + } } ` @@ -91,12 +102,6 @@ export const TabIcon = styled.div` : '')} ` -export const TabTitle = styled(T9n)` - font-size: 8px; - text-transform: uppercase; - color: ${({ theme }) => theme.colors.white}; -` - type TContainer = { forWatchTab?: boolean, hasScroll: boolean, -- 2.30.2 From 7c17307b7507881090125a417f44ed469b99ef92 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Tue, 29 Nov 2022 15:46:11 +0500 Subject: [PATCH 28/31] feat(in-142): fixes --- .../MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx index 800a83de..965decfb 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx @@ -19,7 +19,7 @@ export const useTeamsStatsTable = () => { } const isClickable = (param: Param) => ( - isNumber(param.val) && param.clickable + Boolean(param.val) && param.clickable ) return { -- 2.30.2 From 7148a5ec3c244b215f842191d761a437733402b6 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Fri, 16 Dec 2022 18:39:24 +0500 Subject: [PATCH 29/31] feat(in-142): players stats --- src/features/MatchPage/store/hooks/index.tsx | 10 +- .../MatchPage/store/hooks/useMatchData.tsx | 24 +- .../MatchPage/store/hooks/usePlayersStats.tsx | 159 ++ .../MatchPage/store/hooks/useStatsTab.tsx | 12 + .../MatchPage/store/hooks/useTeamsStats.tsx | 15 +- .../components/PlayersTable/config.tsx | 7 +- .../components/PlayersTable/hooks.tsx | 61 - .../components/PlayersTable/hooks/index.tsx | 58 + .../PlayersTable/hooks/usePlayers.tsx | 83 + .../PlayersTable/hooks/useTable.tsx | 171 ++ .../components/PlayersTable/index.tsx | 1826 ++--------------- .../components/PlayersTable/styled.tsx | 214 +- .../components/PlayersTable/types.tsx | 8 + .../components/TabStats/hooks.tsx | 41 +- .../components/TabStats/index.tsx | 66 +- .../components/TeamsStatsTable/hooks.tsx | 3 +- src/features/MatchSidePlaylists/hooks.tsx | 29 +- src/helpers/getTeamAbbr/index.tsx | 25 + src/helpers/index.tsx | 1 + src/requests/getMatchParticipants.tsx | 65 + src/requests/getPlayersStats.tsx | 54 + src/requests/getTeamsStats.tsx | 2 +- src/requests/index.tsx | 2 + 23 files changed, 1071 insertions(+), 1865 deletions(-) create mode 100644 src/features/MatchPage/store/hooks/usePlayersStats.tsx create mode 100644 src/features/MatchPage/store/hooks/useStatsTab.tsx delete mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/types.tsx create mode 100644 src/helpers/getTeamAbbr/index.tsx create mode 100644 src/requests/getMatchParticipants.tsx create mode 100644 src/requests/getPlayersStats.tsx diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index d407fa08..d0c0b76a 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -65,10 +65,11 @@ export const useMatchPage = () => { const { events, - fetchTeamsStats, handlePlaylistClick, + isEmptyPlayersStats, matchPlaylists, - playingProgress, + playersData, + playersStats, selectedPlaylist, setFullMatchPlaylistDuration, setPlayingProgress, @@ -162,11 +163,11 @@ export const useMatchPage = () => { countOfFilters, disablePlayingEpisodes, events, - fetchTeamsStats, filteredEvents, handlePlaylistClick, hideProfileCard, isEmptyFilters, + isEmptyPlayersStats, isLiveMatch, isOpenFiltersPopup, isPlayFilterEpisodes, @@ -177,7 +178,8 @@ export const useMatchPage = () => { plaingOrder, playEpisodes, playNextEpisode, - playingProgress, + playersData, + playersStats, profile, profileCardShown, resetEvents, diff --git a/src/features/MatchPage/store/hooks/useMatchData.tsx b/src/features/MatchPage/store/hooks/useMatchData.tsx index 3aa9f0fe..39fbf3b5 100644 --- a/src/features/MatchPage/store/hooks/useMatchData.tsx +++ b/src/features/MatchPage/store/hooks/useMatchData.tsx @@ -17,6 +17,8 @@ import { useMatchPopupStore } from 'features/MatchPopup' import { useMatchPlaylists } from './useMatchPlaylists' import { useEvents } from './useEvents' import { useTeamsStats } from './useTeamsStats' +import { useStatsTab } from './useStatsTab' +import { usePlayersStats } from './usePlayersStats' const MATCH_DATA_POLL_INTERVAL = 60000 const MATCH_PLAYLISTS_DELAY = 5000 @@ -35,12 +37,21 @@ export const useMatchData = (profile: MatchInfo) => { setSelectedPlaylist, } = useMatchPlaylists(profile) const { events, fetchMatchEvents } = useEvents() + const { setStatsType, statsType } = useStatsTab() + const { teamsStats } = useTeamsStats({ + matchProfile: profile, + playingProgress, + statsType, + }) const { - fetchTeamsStats, - setStatsType, + isEmptyPlayersStats, + playersData, + playersStats, + } = usePlayersStats({ + matchProfile: profile, + playingProgress, statsType, - teamsStats, - } = useTeamsStats(profile, playingProgress) + }) const fetchPlaylistsDebounced = useMemo( () => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY), @@ -100,10 +111,11 @@ export const useMatchData = (profile: MatchInfo) => { return { events, - fetchTeamsStats, handlePlaylistClick, + isEmptyPlayersStats, matchPlaylists, - playingProgress, + playersData, + playersStats, selectedPlaylist, setFullMatchPlaylistDuration, setPlayingProgress, diff --git a/src/features/MatchPage/store/hooks/usePlayersStats.tsx b/src/features/MatchPage/store/hooks/usePlayersStats.tsx new file mode 100644 index 00000000..326d4f51 --- /dev/null +++ b/src/features/MatchPage/store/hooks/usePlayersStats.tsx @@ -0,0 +1,159 @@ +import { + useMemo, + useEffect, + useState, +} from 'react' + +import throttle from 'lodash/throttle' +import isEmpty from 'lodash/isEmpty' +import every from 'lodash/every' +import find from 'lodash/find' + +import type { + MatchInfo, + PlayersStats, + Player, +} from 'requests' +import { getPlayersStats, getMatchParticipants } from 'requests' + +import { useObjectState, usePageParams } from 'hooks' + +import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' + +const REQUEST_DELAY = 3000 +const STATS_POLL_INTERVAL = 30000 + +type UsePlayersStatsArgs = { + matchProfile: MatchInfo, + playingProgress: number, + statsType: StatsType, +} + +type PlayersData = { + team1: Array, + team2: Array, +} + +export const usePlayersStats = ({ + matchProfile, + playingProgress, + statsType, +}: UsePlayersStatsArgs) => { + const [playersStats, setPlayersStats] = useObjectState>({}) + const [playersData, setPlayersData] = useState({ team1: [], team2: [] }) + + const { + profileId: matchId, + sportName, + sportType, + } = usePageParams() + + const isCurrentStats = statsType === StatsType.CURRENT_STATS + + const progressSec = Math.floor(playingProgress / 1000) + + const isEmptyPlayersStats = (teamId: number) => ( + isEmpty(playersStats[teamId]) + || every(playersStats[teamId], isEmpty) + || isEmpty(playersData[matchProfile?.team1.id === teamId ? 'team1' : 'team2']) + ) + + const fetchPlayers = useMemo(() => throttle((second?: number) => { + if (!matchProfile?.team1.id || !matchProfile?.team1.id) return + + try { + getMatchParticipants({ + matchId, + second, + sportType, + }).then((data) => { + const team1Players = find(data, { team_id: matchProfile.team1.id })?.players || [] + const team2Players = find(data, { team_id: matchProfile.team2.id })?.players || [] + + setPlayersData({ + team1: team1Players, + team2: team2Players, + }) + }) + + // eslint-disable-next-line no-empty + } catch (e) {} + }, REQUEST_DELAY), [ + matchId, + matchProfile?.team1.id, + matchProfile?.team2.id, + sportType, + ]) + + const fetchPlayersStats = useMemo(() => throttle((second?: number) => { + if (!sportName || !matchProfile?.team1.id || !matchProfile?.team2.id) return + + try { + getPlayersStats({ + matchId, + second, + sportName, + teamId: matchProfile.team1.id, + }).then((data) => setPlayersStats({ [matchProfile.team1.id]: data })) + + getPlayersStats({ + matchId, + second, + sportName, + teamId: matchProfile.team2.id, + }).then((data) => setPlayersStats({ [matchProfile?.team2.id]: data })) + // eslint-disable-next-line no-empty + } catch (e) {} + }, REQUEST_DELAY), [ + matchId, + matchProfile?.team1.id, + matchProfile?.team2.id, + setPlayersStats, + sportName, + ]) + + useEffect(() => { + let interval: NodeJS.Timeout + + fetchPlayers() + + if (!isCurrentStats) { + fetchPlayersStats() + } + + if (matchProfile?.live) { + interval = setInterval(() => { + if (isCurrentStats) return + + fetchPlayersStats() + fetchPlayers() + }, STATS_POLL_INTERVAL) + } + + return () => clearInterval(interval) + }, [ + fetchPlayersStats, + fetchPlayers, + isCurrentStats, + matchProfile?.live, + ]) + + useEffect(() => { + if (isCurrentStats) { + fetchPlayersStats(progressSec) + fetchPlayers(progressSec) + } + }, [ + fetchPlayersStats, + fetchPlayers, + progressSec, + isCurrentStats, + matchProfile?.live, + ]) + + return { + isEmptyPlayersStats, + playersData, + playersStats, + } +} diff --git a/src/features/MatchPage/store/hooks/useStatsTab.tsx b/src/features/MatchPage/store/hooks/useStatsTab.tsx new file mode 100644 index 00000000..9a2a18f1 --- /dev/null +++ b/src/features/MatchPage/store/hooks/useStatsTab.tsx @@ -0,0 +1,12 @@ +import { useState } from 'react' + +import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' + +export const useStatsTab = () => { + const [statsType, setStatsType] = useState(StatsType.FINAL_STATS) + + return { + setStatsType, + statsType, + } +} diff --git a/src/features/MatchPage/store/hooks/useTeamsStats.tsx b/src/features/MatchPage/store/hooks/useTeamsStats.tsx index b7a6d000..f9f6ea58 100644 --- a/src/features/MatchPage/store/hooks/useTeamsStats.tsx +++ b/src/features/MatchPage/store/hooks/useTeamsStats.tsx @@ -16,8 +16,17 @@ import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/confi const REQUEST_DELAY = 3000 const STATS_POLL_INTERVAL = 30000 -export const useTeamsStats = (matchProfile: MatchInfo, playingProgress: number) => { - const [statsType, setStatsType] = useState(StatsType.FINAL_STATS) +type UseTeamsStatsArgs = { + matchProfile: MatchInfo, + playingProgress: number, + statsType: StatsType, +} + +export const useTeamsStats = ({ + matchProfile, + playingProgress, + statsType, +}: UseTeamsStatsArgs) => { const [teamsStats, setTeamsStats] = useState<{ [teamId: string]: Array, }>({}) @@ -63,8 +72,6 @@ export const useTeamsStats = (matchProfile: MatchInfo, playingProgress: number) }, [fetchTeamsStats, progressSec, isCurrentStats]) return { - fetchTeamsStats, - setStatsType, statsType, teamsStats, } diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx index 095cfcbe..c0ac6c10 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx @@ -1 +1,6 @@ -export const CELL_WIDTH = 47 +export const PARAM_COLUMN_WIDTH = 50 +export const REQUEST_DELAY = 3000 +export const STATS_POLL_INTERVAL = 30000 +export const DISPLAYED_PARAMS_COLUMNS = 4 +export const FIRST_COLUMN_WIDTH_DEFAULT = 100 +export const SCROLLBAR_WIDTH = 8 diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx deleted file mode 100644 index 811ddda6..00000000 --- a/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import type { SyntheticEvent } from 'react' -import { - useRef, - useState, - useEffect, -} from 'react' - -import { isMobileDevice } from 'config/userAgent' - -import { CELL_WIDTH } from './config' - -export const usePlayersTable = () => { - const containerRef = useRef(null) - const tableWrapperRef = useRef(null) - - const [showLeftArrow, setShowLeftArrow] = useState(false) - const [showRightArrow, setShowRightArrow] = useState(false) - - const cellWidth = isMobileDevice - ? ((containerRef.current?.clientWidth || 0) - 98) / 4 - : CELL_WIDTH - - const slideLeft = () => tableWrapperRef.current!.scrollBy(-cellWidth, 0) - const slideRight = () => tableWrapperRef.current!.scrollBy(cellWidth, 0) - - const handleScroll = (e: SyntheticEvent) => { - const { - clientWidth, - scrollLeft, - scrollWidth, - } = e.currentTarget - - const scrollRight = scrollWidth - (scrollLeft + clientWidth) - - setShowLeftArrow(scrollLeft > 1) - setShowRightArrow(scrollRight > 1) - } - - useEffect(() => { - const { - clientWidth = 0, - scrollLeft = 0, - scrollWidth = 0, - } = tableWrapperRef.current || {} - - const scrollRight = scrollWidth - (scrollLeft + clientWidth) - - setShowRightArrow(scrollRight > 1) - }, []) - - return { - cellWidth, - containerRef, - handleScroll, - showLeftArrow, - showRightArrow, - slideLeft, - slideRight, - tableWrapperRef, - } -} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx new file mode 100644 index 00000000..537e480a --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx @@ -0,0 +1,58 @@ +import { useState } from 'react' + +import type { SortCondition, PlayersTableProps } from '../types' +import { usePlayers } from './usePlayers' +import { useTable } from './useTable' + +export const usePlayersTable = ({ teamId }: PlayersTableProps) => { + const [sortCondition, setSortCondition] = useState({ dir: 'asc', paramId: null }) + + const { + getFullName, + getPlayerParams, + players, + } = usePlayers({ sortCondition, teamId }) + + const { + containerRef, + firstColumnWidth, + getDisplayedValue, + handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + showExpandButton, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + tableWrapperRef, + toggleIsExpanded, + } = useTable({ + setSortCondition, + teamId, + }) + + return { + containerRef, + firstColumnWidth, + getDisplayedValue, + getFullName, + getPlayerParams, + handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + players, + showExpandButton, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + sortCondition, + tableWrapperRef, + toggleIsExpanded, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx new file mode 100644 index 00000000..ff2b8e3a --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx @@ -0,0 +1,83 @@ +import { useMemo, useCallback } from 'react' + +import orderBy from 'lodash/orderBy' +import isNil from 'lodash/isNil' +import trim from 'lodash/trim' + +import type { Player, PlayerParam } from 'requests' + +import { useToggle } from 'hooks' + +import { useMatchPageStore } from 'features/MatchPage/store' +import { useLexicsStore } from 'features/LexicsStore' + +import type { SortCondition } from '../types' + +type UsePlayersArgs = { + sortCondition: SortCondition, + teamId: number, +} + +export const usePlayers = ({ sortCondition, teamId }: UsePlayersArgs) => { + const { isOpen: isExpanded, toggle: toggleIsExpanded } = useToggle() + const { + playersData, + playersStats, + profile: matchProfile, + } = useMatchPageStore() + const { suffix } = useLexicsStore() + + const getPlayerParams = useCallback( + (playerId: number) => playersStats[teamId][playerId] || {}, + [playersStats, teamId], + ) + + const getDisplayedValue = ({ val }: PlayerParam) => (isNil(val) ? '-' : val) + + const getFullName = useCallback((player: Player) => ( + trim(`${player[`firstname_${suffix}`]} ${player[`lastname_${suffix}`]}`) + ), [suffix]) + + const getParamValue = useCallback((playerId: number, paramId: number) => { + const playerParams = getPlayerParams(playerId) + const { val } = playerParams[paramId] || {} + + return val + }, [getPlayerParams]) + + const sortedPlayers = useMemo(() => { + const players = playersData[matchProfile?.team1.id === teamId ? 'team1' : 'team2'] + + return isNil(sortCondition.paramId) + ? orderBy(players, getFullName) + : orderBy( + players, + [ + (player) => { + const paramValue = getParamValue(player.id, sortCondition.paramId!) + + return isNil(paramValue) ? -1 : paramValue + }, + getFullName, + ], + sortCondition.dir, + ) + }, [ + getFullName, + getParamValue, + playersData, + matchProfile?.team1.id, + sortCondition.dir, + sortCondition.paramId, + teamId, + ]) + + return { + getDisplayedValue, + getFullName, + getPlayerParams, + isExpanded, + players: sortedPlayers, + toggleIsExpanded, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx new file mode 100644 index 00000000..5bc2f55c --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx @@ -0,0 +1,171 @@ +import type { + SyntheticEvent, + Dispatch, + SetStateAction, +} from 'react' +import { + useRef, + useState, + useEffect, + useMemo, +} from 'react' + +import size from 'lodash/size' +import isNil from 'lodash/isNil' +import reduce from 'lodash/reduce' +import forEach from 'lodash/forEach' +import values from 'lodash/values' +import round from 'lodash/round' +import map from 'lodash/map' + +import { isMobileDevice } from 'config' + +import type { PlayerParam, PlayersStats } from 'requests' + +import { useToggle } from 'hooks' + +import { useMatchPageStore } from 'features/MatchPage/store' +import { useLexicsConfig } from 'features/LexicsStore' + +import type { SortCondition } from '../types' +import { + PARAM_COLUMN_WIDTH, + DISPLAYED_PARAMS_COLUMNS, + FIRST_COLUMN_WIDTH_DEFAULT, + SCROLLBAR_WIDTH, +} from '../config' + +type UseTableArgs = { + setSortCondition: Dispatch>, + teamId: number, +} + +type HeaderParam = Pick + +export const useTable = ({ + setSortCondition, + teamId, +}: UseTableArgs) => { + const containerRef = useRef(null) + const tableWrapperRef = useRef(null) + + const [showLeftArrow, setShowLeftArrow] = useState(false) + const [showRightArrow, setShowRightArrow] = useState(false) + + const { isOpen: isExpanded, toggle: toggleIsExpanded } = useToggle() + const { playersStats } = useMatchPageStore() + + const params = useMemo(() => ( + reduce>( + playersStats[teamId], + (acc, curr) => { + forEach(values(curr), ({ + id, + lexic, + lexica_short, + }) => { + acc[id] = acc[id] || { + id, + lexic, + lexica_short, + } + }) + + return acc + }, + {}, + ) + ), [playersStats, teamId]) + + const lexics = useMemo(() => ( + reduce>( + values(params), + (acc, { lexic, lexica_short }) => { + if (lexic) acc.push(lexic) + if (lexica_short) acc.push(lexica_short) + + return acc + }, + [], + ) + // eslint-disable-next-line react-hooks/exhaustive-deps + ), [map(params, 'id').sort().join('')]) + + useLexicsConfig(lexics) + + const paramsCount = size(params) + + const getParamColumnWidth = () => { + const rest = ( + (containerRef.current?.clientWidth || 0) - FIRST_COLUMN_WIDTH_DEFAULT - SCROLLBAR_WIDTH + ) + const desktopWith = PARAM_COLUMN_WIDTH + const mobileWidth = paramsCount < DISPLAYED_PARAMS_COLUMNS ? 0 : rest / DISPLAYED_PARAMS_COLUMNS + + return isMobileDevice ? mobileWidth : desktopWith + } + + const getFirstColumnWidth = () => { + if (isExpanded) return 0 + + return paramsCount < DISPLAYED_PARAMS_COLUMNS ? 0 : FIRST_COLUMN_WIDTH_DEFAULT + } + + const paramColumnWidth = getParamColumnWidth() + const firstColumnWidth = getFirstColumnWidth() + + const slideLeft = () => tableWrapperRef.current?.scrollBy(-paramColumnWidth, 0) + const slideRight = () => tableWrapperRef.current?.scrollBy(paramColumnWidth, 0) + + const getDisplayedValue = ({ val }: PlayerParam) => (isNil(val) ? '-' : round(val, 2)) + + const handleScroll = (e: SyntheticEvent) => { + const { + clientWidth, + scrollLeft, + scrollWidth, + } = e.currentTarget + + const scrollRight = scrollWidth - (scrollLeft + clientWidth) + + setShowLeftArrow(scrollLeft > 0) + setShowRightArrow(scrollRight > 0) + } + + const handleSortClick = (paramId: number) => () => { + setSortCondition((curr) => ({ + dir: curr.dir === 'asc' || curr.paramId !== paramId ? 'desc' : 'asc', + paramId, + })) + } + + useEffect(() => { + const { + clientWidth = 0, + scrollLeft = 0, + scrollWidth = 0, + } = tableWrapperRef.current || {} + + const scrollRight = scrollWidth - (scrollLeft + clientWidth) + + setShowRightArrow(scrollRight > 0) + }, [isExpanded]) + + return { + containerRef, + firstColumnWidth, + getDisplayedValue, + handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + showExpandButton: !isMobileDevice && paramsCount > DISPLAYED_PARAMS_COLUMNS, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + tableWrapperRef, + toggleIsExpanded, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx index 0be29a9c..9e5ce602 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx @@ -1,1728 +1,164 @@ +import { Fragment } from 'react' + +import map from 'lodash/map' +import includes from 'lodash/includes' + +import { PlayerParam } from 'requests' + +import { T9n } from 'features/T9n' + +import type { PlayersTableProps } from './types' import { usePlayersTable } from './hooks' import { Container, TableWrapper, Table, - Thead, - Th, - Tbody, - Tr, - Td, + FirstColumn, + Cell, + Row, PlayerNum, + PlayerNameWrapper, + PlayerName, ParamShortTitle, ArrowButtonRight, ArrowButtonLeft, Arrow, + ExpandButton, + Tooltip, } from './styled' -export const PlayersTable = () => { +export const PlayersTable = (props: PlayersTableProps) => { const { - cellWidth, containerRef, + firstColumnWidth, + getDisplayedValue, + getFullName, + getPlayerParams, handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + players, + showExpandButton, showLeftArrow, showRightArrow, slideLeft, slideRight, + sortCondition, tableWrapperRef, - } = usePlayersTable() + toggleIsExpanded, + } = usePlayersTable(props) return ( - + - {showLeftArrow && ( - - - - )} - {showRightArrow && ( - - - + {!isExpanded && ( + + {showLeftArrow && ( + + + + )} + {showRightArrow && ( + + + + )} + )} + + + + {showExpandButton && ( + + + + + )} + + + {map(players, (player) => { + const fullName = getFullName(player) + + return ( + + + + {player.club_shirt_num} + {' '} + + + {fullName} + + + {fullName} + + + + + ) + })} + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + return ( + + {value} + + ) + })} + + ))}
- - Min - - Pt - - Reb - - Ass - - To - - Min - - Pt - - Reb - - Ass - - To - - Min - - Pt - - Reb - - Ass - + + {map(params, ({ + id, + lexic, + lexica_short, + }) => ( + + + + + + + ))} + - To - + {map(players, (player) => ( + + {map(params, ({ id }) => { + const playerParam = getPlayerParams(player.id)[id] as PlayerParam | undefined + const value = playerParam ? getDisplayedValue(playerParam) : '-' + const clickable = Boolean(playerParam?.clickable) && !includes([0, '-'], value) + const sorted = sortCondition.paramId === id - Min - - Pt - - Reb - - Ass - - To -
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx index 303332dd..a0d9f33d 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx @@ -1,138 +1,211 @@ import styled, { css } from 'styled-components/macro' -import { isMobileDevice } from 'config/userAgent' +import { isMobileDevice } from 'config' import { customScrollbar } from 'features/Common' +import { TooltipWrapper } from 'features/Tooltip' import { ArrowButton as ArrowButtonBase, Arrow as ArrowBase, } from 'features/HeaderFilters/components/DateFilter/styled' +import { T9n } from 'features/T9n' -import { CELL_WIDTH } from './config' +type ContainerProps = { + isExpanded?: boolean, +} -export const Container = styled.div` - position: relative; +export const Container = styled.div` + ${({ isExpanded }) => (isExpanded + ? '' + : css` + position: relative; + `)} ` -export const TableWrapper = styled.div` +type TableWrapperProps = { + isExpanded?: boolean, +} + +export const TableWrapper = styled.div` + display: flex; + max-width: 100%; max-height: calc(100vh - 235px); border-radius: 5px; overflow-x: auto; scroll-behavior: smooth; + background-color: #333333; + z-index: 50; ${customScrollbar} + + ${({ isExpanded }) => (isExpanded + ? css` + position: absolute; + right: 14px; + ` + : '')} ` -export const Table = styled.table` - width: 100%; +export const Table = styled.div` + flex-grow: 1; border-radius: 5px; border-collapse: collapse; letter-spacing: -0.078px; - table-layout: fixed; ` -export const Thead = styled.thead` - height: 45px; - border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); -` - -type ThProps = { - sorted?: boolean, - width?: number, -} - -export const Th = styled.th.attrs({ tabIndex: 0 })` - position: sticky; - left: 0; - top: 0; - width: ${({ width }) => width || CELL_WIDTH}px; +export const Tooltip = styled(TooltipWrapper)` + left: auto; + padding: 2px 10px; + border-radius: 6px; + transform: none; font-size: 11px; - color: ${({ theme }) => theme.colors.white}; - text-transform: uppercase; - cursor: pointer; - background-color: #333333; - z-index: 2; + line-height: 1; + color: ${({ theme }) => theme.colors.black}; - :first-child { - width: 90px; - z-index: 3; - cursor: default; + ::before { + display: none; } - - ${({ sorted }) => (sorted - ? '' - : css` - ${ParamShortTitle} { - opacity: 0.5; - } - `)} ` -export const ParamShortTitle = styled.span`` - -export const Tbody = styled.tbody`` +export const ParamShortTitle = styled(T9n)` + text-transform: uppercase; +` -export const Tr = styled.tr` +export const Row = styled.div` + display: flex; + width: 100%; height: 45px; border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); - :last-child { - border-bottom: none; + :first-child { + position: sticky; + left: 0; + top: 0; + z-index: 1; } ` type TdProps = { clickable?: boolean, + columnWidth?: number, + headerCell?: boolean, sorted?: boolean, } -export const Td = styled.td.attrs(({ clickable }: TdProps) => ({ +export const Cell = styled.div.attrs(({ clickable }: TdProps) => ({ ...clickable && { tabIndex: 0 }, }))` + position: relative; + display: flex; + justify-content: center; + align-items: center; + flex-shrink: 0; + width: ${({ columnWidth }) => (columnWidth ? `${columnWidth}px` : 'auto')}; font-size: 11px; - text-align: center; - color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)}; - text-overflow: ellipsis; - overflow: hidden; + color: ${({ + clickable, + headerCell, + theme, + }) => (clickable && !headerCell ? '#5EB2FF' : theme.colors.white)}; white-space: nowrap; background-color: #333333; - :first-child { - position: sticky; - left: 0; - z-index: 1; - padding-left: 13px; - text-align: left; - color: ${({ theme }) => theme.colors.white}; + ${Tooltip} { + top: 35px; + } + + :hover { + ${Tooltip} { + display: block; + } } + ${({ headerCell }) => (headerCell + ? '' + : css` + :first-child { + justify-content: unset; + padding-left: 13px; + color: ${({ theme }) => theme.colors.white}; + } + `)} + ${({ sorted }) => (sorted ? css` font-weight: bold; ` : '')} - ${({ clickable }) => (clickable + ${({ clickable, headerCell }) => (clickable || headerCell ? css` cursor: pointer; ` : '')} ` +type FirstColumnProps = { + columnWidth?: number, +} + +export const FirstColumn = styled.div` + position: sticky; + left: 0; + width: ${({ columnWidth }) => (columnWidth ? `${columnWidth}px` : 'auto')}; +` + export const PlayerNum = styled.span` + display: inline-block; + width: 20px; + flex-shrink: 0; + text-align: center; color: rgba(255, 255, 255, 0.5); ` +type PlayerNameProps = { + columnWidth?: number, +} + +export const PlayerName = styled.span` + display: inline-block; + margin-top: 2px; + text-overflow: ellipsis; + overflow: hidden; + + ${({ columnWidth }) => (columnWidth + ? css` + max-width: calc(${columnWidth}px - 31px); + ` + : css` + max-width: 110px; + `)} +` + +export const PlayerNameWrapper = styled.span` + position: relative; + + ${Tooltip} { + top: 15px; + } + + :hover { + ${Tooltip} { + display: block; + } + } +` + const ArrowButton = styled(ArrowButtonBase)` position: absolute; + width: 17px; margin-top: 2px; - z-index: 4; + background-color: #333333; + z-index: 3; ${isMobileDevice ? css` height: 45px; margin-top: 0; ` - : ''}; + : ''}; ` export const ArrowButtonRight = styled(ArrowButton)` @@ -146,4 +219,23 @@ export const ArrowButtonLeft = styled(ArrowButton)` export const Arrow = styled(ArrowBase)` width: 10px; height: 10px; + + ${isMobileDevice + ? css` + border-color: ${({ theme }) => theme.colors.white}; + ` + : ''}; +` + +export const ExpandButton = styled(ArrowButton)` + left: 20px; + top: 0; + + ${Arrow} { + left: 0; + + :last-child { + margin-left: 7px; + } + } ` diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/types.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/types.tsx new file mode 100644 index 00000000..85b9d054 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/types.tsx @@ -0,0 +1,8 @@ +export type PlayersTableProps = { + teamId: number, +} + +export type SortCondition = { + dir: 'asc' | 'desc', + paramId: number | null, +} diff --git a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx index 0346586f..1d621ce3 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx @@ -1,4 +1,6 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' + +import isEmpty from 'lodash/isEmpty' import { useMatchPageStore } from 'features/MatchPage/store' @@ -7,21 +9,56 @@ import { StatsType, Tabs } from './config' export const useTabStats = () => { const [selectedTab, setSelectedTab] = useState(Tabs.TEAMS) - const { setStatsType, statsType } = useMatchPageStore() + const { + isEmptyPlayersStats, + profile: matchProfile, + setStatsType, + statsType, + teamsStats, + } = useMatchPageStore() const isFinalStatsType = statsType === StatsType.FINAL_STATS const switchTitleLexic = isFinalStatsType ? 'final_stats' : 'current_stats' const tooltipLexic = isFinalStatsType ? 'display_all_stats' : 'display_stats_according_to_video' + const isVisibleTeamsTab = !isEmpty(teamsStats) + const isVisibleTeam1PlayersTab = Boolean( + matchProfile && !isEmptyPlayersStats(matchProfile.team1.id), + ) + const isVisibleTeam2PlayersTab = Boolean( + matchProfile && !isEmptyPlayersStats(matchProfile.team2.id), + ) + const toggleStatsType = () => { const newStatsType = isFinalStatsType ? StatsType.CURRENT_STATS : StatsType.FINAL_STATS setStatsType(newStatsType) } + useEffect(() => { + switch (true) { + case isVisibleTeamsTab: + setSelectedTab(Tabs.TEAMS) + break + + case isVisibleTeam1PlayersTab: + setSelectedTab(Tabs.TEAM1) + break + + case isVisibleTeam2PlayersTab: + setSelectedTab(Tabs.TEAM2) + break + + default: + } + }, [isVisibleTeam1PlayersTab, isVisibleTeam2PlayersTab, isVisibleTeamsTab]) + return { isFinalStatsType, + isVisibleTeam1PlayersTab, + isVisibleTeam2PlayersTab, + isVisibleTeamsTab, selectedTab, setSelectedTab, switchTitleLexic, diff --git a/src/features/MatchSidePlaylists/components/TabStats/index.tsx b/src/features/MatchSidePlaylists/components/TabStats/index.tsx index 82311d18..d5b20d74 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/index.tsx @@ -1,7 +1,11 @@ import { isMobileDevice } from 'config/userAgent' +import { getTeamAbbr } from 'helpers' + import { Tooltip } from 'features/Tooltip' import { T9n } from 'features/T9n' +import { useMatchPageStore } from 'features/MatchPage/store' +import { Name } from 'features/Name' import { Tabs } from './config' import { useTabStats } from './hooks' @@ -27,37 +31,59 @@ const tabPanes = { export const TabStats = () => { const { isFinalStatsType, + isVisibleTeam1PlayersTab, + isVisibleTeam2PlayersTab, + isVisibleTeamsTab, selectedTab, setSelectedTab, switchTitleLexic, toggleStatsType, tooltipLexic, } = useTabStats() + const { profile: matchProfile } = useMatchPageStore() const TabPane = tabPanes[selectedTab] + if (!matchProfile) return null + + const { team1, team2 } = matchProfile + return (
- setSelectedTab(Tabs.TEAMS)} - > - - - {/* setSelectedTab(Tabs.TEAM1)} - > - DIN - */} - {/* setSelectedTab(Tabs.TEAM2)} - > - SPA - */} + {isVisibleTeamsTab && ( + setSelectedTab(Tabs.TEAMS)} + > + + + )} + {isVisibleTeam1PlayersTab && ( + setSelectedTab(Tabs.TEAM1)} + > + + + )} + {isVisibleTeam2PlayersTab && ( + setSelectedTab(Tabs.TEAM2)} + > + + + )} @@ -69,7 +95,9 @@ export const TabStats = () => {
- +
) } diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx index 965decfb..d4698aea 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx @@ -1,5 +1,6 @@ import isNumber from 'lodash/isNumber' import find from 'lodash/find' +import round from 'lodash/round' import type { Param } from 'requests' @@ -9,7 +10,7 @@ export const useTeamsStatsTable = () => { const { profile, teamsStats } = useMatchPageStore() const getDisplayedValue = (val: any) => ( - isNumber(val) ? val : '-' + isNumber(val) ? round(val, 2) : '-' ) const getStatItemById = (paramId: number) => { diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index 1fbf40d4..8a2bcf37 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -16,7 +16,9 @@ export const useMatchSidePlaylists = () => { const { closePopup, events, + isEmptyPlayersStats, matchPlaylists: playlists, + profile: matchProfile, teamsStats, tournamentData, } = useMatchPageStore() @@ -46,7 +48,14 @@ export const useMatchSidePlaylists = () => { const isStatsTabVisible = useMemo(() => ( !isEmpty(teamsStats) - ), [teamsStats]) + || (matchProfile?.team1.id && !isEmptyPlayersStats(matchProfile.team1.id)) + || (matchProfile?.team2.id && !isEmptyPlayersStats(matchProfile.team2.id)) + ), [ + isEmptyPlayersStats, + matchProfile?.team1.id, + matchProfile?.team2.id, + teamsStats, + ]) const hasLessThanFourTabs = compact([ isWatchTabVisible, @@ -57,15 +66,15 @@ export const useMatchSidePlaylists = () => { useEffect(() => { switch (true) { - case isWatchTabVisible: - setSelectedTab(Tabs.WATCH) - break - case isEventTabVisible: - setSelectedTab(Tabs.EVENTS) - break - case isPlayersTabVisible: - setSelectedTab(Tabs.PLAYERS) - break + // case isWatchTabVisible: + // setSelectedTab(Tabs.WATCH) + // break + // case isEventTabVisible: + // setSelectedTab(Tabs.EVENTS) + // break + // case isPlayersTabVisible: + // setSelectedTab(Tabs.PLAYERS) + // break case isStatsTabVisible: setSelectedTab(Tabs.STATS) break diff --git a/src/helpers/getTeamAbbr/index.tsx b/src/helpers/getTeamAbbr/index.tsx new file mode 100644 index 00000000..62a1eb51 --- /dev/null +++ b/src/helpers/getTeamAbbr/index.tsx @@ -0,0 +1,25 @@ +import toUpper from 'lodash/toUpper' +import split from 'lodash/split' +import size from 'lodash/size' + +import pipe from 'lodash/fp/pipe' +import take from 'lodash/fp/take' +import join from 'lodash/fp/join' +import map from 'lodash/fp/map' + +export const getTeamAbbr = (teamName: string) => { + const nameParts = split(teamName, ' ') + + return size(nameParts) > 1 + ? pipe( + map(take(1)), + join(''), + toUpper, + )(nameParts) + + : pipe( + take(3), + join(''), + toUpper, + )(nameParts[0]) +} diff --git a/src/helpers/index.tsx b/src/helpers/index.tsx index 734a5130..0577a810 100644 --- a/src/helpers/index.tsx +++ b/src/helpers/index.tsx @@ -8,3 +8,4 @@ export * from './secondsToHms' export * from './redirectToUrl' export * from './getRandomString' export * from './selectedApi' +export * from './getTeamAbbr' diff --git a/src/requests/getMatchParticipants.tsx b/src/requests/getMatchParticipants.tsx new file mode 100644 index 00000000..645c3c03 --- /dev/null +++ b/src/requests/getMatchParticipants.tsx @@ -0,0 +1,65 @@ +import isUndefined from 'lodash/isUndefined' + +import { SportTypes } from 'config' + +import { callApi } from 'helpers' + +export type Player = { + birthday: string | null, + c_country: number, + c_gender: number, + club_f_team: number, + club_shirt_num: number, + firstname_eng: string, + firstname_national: string | null, + firstname_rus: string, + height: number | null, + id: number, + is_gk: boolean, + lastname_eng: string, + lastname_national: string | null, + lastname_rus: string, + national_f_team: number | null, + national_shirt_num: number, + nickname_eng: string | null, + nickname_rus: string | null, + weight: number | null, +} + +type DataItem = { + players: Array, + team_id: number, +} + +type Response = { + data?: Array, + error?: { + code: string, + message: string, + }, +} + +type GetMatchParticipantsArgs = { + matchId: number, + second?: number, + sportType: SportTypes, +} + +export const getMatchParticipants = async ({ + matchId, + second, + sportType, +}: GetMatchParticipantsArgs) => { + const config = { + method: 'GET', + } + + const response: Response = await callApi({ + config, + url: `http://136.243.17.103:8888/ask/participants?sport_id=${sportType}&match_id=${matchId}${isUndefined(second) ? '' : `&second=${second}`}`, + }) + + if (response.error) Promise.reject(response) + + return Promise.resolve(response.data || []) +} diff --git a/src/requests/getPlayersStats.tsx b/src/requests/getPlayersStats.tsx new file mode 100644 index 00000000..3fb5d93f --- /dev/null +++ b/src/requests/getPlayersStats.tsx @@ -0,0 +1,54 @@ +import isUndefined from 'lodash/isUndefined' + +import { callApi } from 'helpers' + +export type PlayerParam = { + clickable: boolean, + data_type: string, + id: number, + lexic: number, + lexica_short: number | null, + markers: Array | null, + name_en: string, + name_ru: string, + val: number | null, +} + +export type PlayersStats = { + [playerId: string]: { + [paramId: string]: PlayerParam, + }, +} + +type Response = { + data?: PlayersStats, + error?: string, + message?: string, +} + +type GetPlayersStatsArgs = { + matchId: number, + second?: number, + sportName: string, + teamId: number, +} + +export const getPlayersStats = async ({ + matchId, + second, + sportName, + teamId, +}: GetPlayersStatsArgs) => { + const config = { + method: 'GET', + } + + const response: Response = await callApi({ + config, + url: `http://136.243.17.103:8888/${sportName}/matches/${matchId}/teams/${teamId}/players/stats${isUndefined(second) ? '' : `?second=${second}`}`, + }) + + if (response.error) Promise.reject(response) + + return Promise.resolve(response.data || {}) +} diff --git a/src/requests/getTeamsStats.tsx b/src/requests/getTeamsStats.tsx index 4be9afee..acdf40bd 100644 --- a/src/requests/getTeamsStats.tsx +++ b/src/requests/getTeamsStats.tsx @@ -47,7 +47,7 @@ export const getTeamsStats = async ({ const response: Response = await callApi({ config, - url: `https://statistic.insports.tv/${sportName}/matches/${matchId}/teams/stats?group_num=0${isUndefined(second) ? '' : `&second=${second}`}`, + url: `http://136.243.17.103:8888/${sportName}/matches/${matchId}/teams/stats?group_num=0${isUndefined(second) ? '' : `&second=${second}`}`, }) if (response.error) Promise.reject(response) diff --git a/src/requests/index.tsx b/src/requests/index.tsx index 50471756..2e54b0ae 100644 --- a/src/requests/index.tsx +++ b/src/requests/index.tsx @@ -26,3 +26,5 @@ export * from './getSubscriptions' export * from './buySubscription' export * from './saveMatchStats' export * from './getTeamsStats' +export * from './getPlayersStats' +export * from './getMatchParticipants' -- 2.30.2 From b14f399c90ea6a7ae22122628e2c0ea574212505 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Fri, 16 Dec 2022 19:16:45 +0500 Subject: [PATCH 30/31] feat(in-141): temporarily hide stats tab --- src/features/MatchSidePlaylists/hooks.tsx | 26 +++++++++++------------ src/features/MatchSidePlaylists/index.tsx | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index 8a2bcf37..17e889c5 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -61,28 +61,28 @@ export const useMatchSidePlaylists = () => { isWatchTabVisible, isEventTabVisible, isPlayersTabVisible, - isStatsTabVisible, + // isStatsTabVisible, ]).length < 4 useEffect(() => { switch (true) { - // case isWatchTabVisible: - // setSelectedTab(Tabs.WATCH) - // break - // case isEventTabVisible: - // setSelectedTab(Tabs.EVENTS) - // break - // case isPlayersTabVisible: - // setSelectedTab(Tabs.PLAYERS) - // break - case isStatsTabVisible: - setSelectedTab(Tabs.STATS) + case isWatchTabVisible: + setSelectedTab(Tabs.WATCH) break + case isEventTabVisible: + setSelectedTab(Tabs.EVENTS) + break + case isPlayersTabVisible: + setSelectedTab(Tabs.PLAYERS) + break + // case isStatsTabVisible: + // setSelectedTab(Tabs.STATS) + // break } }, [ isEventTabVisible, isPlayersTabVisible, - isStatsTabVisible, + // isStatsTabVisible, isWatchTabVisible, ]) diff --git a/src/features/MatchSidePlaylists/index.tsx b/src/features/MatchSidePlaylists/index.tsx index a7baaa77..e50cafe2 100644 --- a/src/features/MatchSidePlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/index.tsx @@ -60,7 +60,7 @@ export const MatchSidePlaylists = ({ hasLessThanFourTabs, isEventTabVisible, isPlayersTabVisible, - isStatsTabVisible, + // isStatsTabVisible, isWatchTabVisible, onTabClick, playListFilter, @@ -134,7 +134,7 @@ export const MatchSidePlaylists = ({ ) : null} - {isStatsTabVisible ? ( + {/* {isStatsTabVisible ? ( onTabClick(Tabs.STATS)} @@ -142,7 +142,7 @@ export const MatchSidePlaylists = ({ - ) : null} + ) : null} */} -- 2.30.2 From d06526a10405a9ff3641b5ecf867b8f1e7adece6 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Mon, 19 Dec 2022 16:47:47 +0500 Subject: [PATCH 31/31] feat(in-142): fixes --- .../components/PlayersPlaylists/styled.tsx | 2 +- .../components/PlayersTable/config.tsx | 1 + src/features/MatchSidePlaylists/styled.tsx | 11 +++++------ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx b/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx index c250bfbb..0fa2373a 100644 --- a/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx @@ -29,7 +29,7 @@ export const PlayerAvatar = styled(ProfileLogo)` export const Tabs = styled.div` margin-top: -10px; - margin-bottom: 23px; + margin-bottom: 6px; ` type TabProps = { diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx index c0ac6c10..e43e46af 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx @@ -4,3 +4,4 @@ export const STATS_POLL_INTERVAL = 30000 export const DISPLAYED_PARAMS_COLUMNS = 4 export const FIRST_COLUMN_WIDTH_DEFAULT = 100 export const SCROLLBAR_WIDTH = 8 +export const CELL_WIDTH = PARAM_COLUMN_WIDTH diff --git a/src/features/MatchSidePlaylists/styled.tsx b/src/features/MatchSidePlaylists/styled.tsx index 75a962a4..0ba4d49a 100644 --- a/src/features/MatchSidePlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/styled.tsx @@ -57,7 +57,8 @@ export const TabsGroup = styled.div.attrs({ role: 'tablist' })` ` export const TabTitle = styled(T9n)` - font-size: 8px; + font-size: 10px; + font-weight: 500; text-transform: uppercase; color: ${({ theme }) => theme.colors.white}; ` @@ -77,7 +78,6 @@ export const Tab = styled.button.attrs({ role: 'tab' })` opacity: 1; ${TabTitle} { - font-size: 9px; font-weight: 600; } } @@ -88,8 +88,8 @@ type TabIconProps = { } export const TabIcon = styled.div` - width: 20px; - height: 20px; + width: 22px; + height: 22px; background-image: url(/images/matchTabs/${({ icon }) => `${icon}.svg`}); background-repeat: no-repeat; background-position: center; @@ -109,7 +109,7 @@ type TContainer = { export const Container = styled.div` width: 320px; - margin-top: 23px; + margin-top: 14px; max-height: calc(100vh - 130px); overflow-y: ${({ forWatchTab }) => (forWatchTab ? 'hidden' : 'auto')}; padding-right: ${({ forWatchTab }) => (forWatchTab ? '0' : '')}; @@ -118,7 +118,6 @@ export const Container = styled.div` ${customScrollbar} - @media ${devices.tablet} { margin-top: 15px; } -- 2.30.2