hexlet-codebattle/codebattle

View on GitHub
services/app/apps/codebattle/assets/js/widgets/pages/tournament/UsersMatchList.jsx

Summary

Maintainability
C
1 day
Test Coverage
import React, { memo } from 'react';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import cn from 'classnames';
import moment from 'moment';
import { useSelector } from 'react-redux';

import useMatchesStatistics from '@/utils/useMatchesStatistics';

import Loading from '../../components/Loading';
import UserInfo from '../../components/UserInfo';

import MatchAction from './MatchAction';
import TournamentMatchBadge from './TournamentMatchBadge';

export const toLocalTime = time => moment.utc(time).local().format('HH:mm:ss');

const matchClassName = cn(
  'd-flex flex-column flex-xl-row flex-lg-row flex-md-row',
  'justify-content-between border-bottom p-2',
);
const matchInfoClassName = cn(
  'd-flex',
  'flex-column flex-xl-row flex-lg-row flex-md-row',
  'align-items-center justify-content-between',
);

function UserTournamentInfo({ userId }) {
  const user = useSelector(state => state.tournament.players[userId]);

  if (!user) {
    return <Loading adaptive />;
  }

  return <UserInfo user={user} hideOnlineIndicator hideLink />;
}

function UsersMatchList({
  currentUserId,
  playerId,
  canModerate,
  matches,
  hideStats = false,
  hideBots = false,
}) {
  const [player] = useMatchesStatistics(playerId, matches);

  if (matches.length === 0) {
    return (
      <div
        className="d-flex flex-colum justify-content-center align-items-center p-2"
      >
        No Matches Yet
      </div>
    );
  }

  return (
    <div className="d-flex flex-column">
      {!hideStats && matches.length > 0 && (
        <div className="d-flex py-2 border-bottom align-items-center overflow-auto">
          <span className="ml-2">
            {'Wins: '}
            {player.winMatches.length}
          </span>
          <span className="ml-1 pl-1 border-left border-dark">
            {'Round Score: '}
            {Math.ceil(player.score)}
          </span>
          <span className="ml-1 pl-1 border-left border-dark">
            {'AVG Tests: '}
            {Math.ceil(player.avgTests)}
            %
          </span>
          <span className="ml-1 pl-1 border-left border-dark">
            {'AVG Duration: '}
            {Math.ceil(player.avgDuration)}
            {' sec'}
          </span>
        </div>
      )}
      {matches.map(match => {
        const currentUserIsPlayer = currentUserId === match.playerIds[0]
          || currentUserId === match.playerIds[1];
        const isWinner = playerId === match.winnerId;
        const matchPlayerIds = hideBots
          ? match.playerIds.filter(id => id >= 0)
          : match.playerIds;
        const matchResult = match.playerResults[playerId];

        return (
          <div
            key={match.id}
            className={matchClassName}
          >
            <div className={matchInfoClassName}>
              <div
                className="d-flex align-items-center justify-content-center w-100 p-0 px-2 p-sm-1"
              >
                <span className="d-flex align-items-center">
                  <TournamentMatchBadge
                    matchState={match.state}
                    isWinner={isWinner}
                    currentUserIsPlayer={currentUserIsPlayer}
                  />
                </span>
                <div className="d-flex flex-column flex-xl-row flex-lg-row flex-md-row flex-sm-row">
                  {matchPlayerIds.length === 1 ? (
                    <div className="d-flex align-items-center">
                      {match.winnerId === matchPlayerIds[0] && (
                        <FontAwesomeIcon className="text-warning mx-1" icon="trophy" />
                      )}
                      <UserTournamentInfo userId={matchPlayerIds[0]} />
                    </div>
                  ) : (
                    <>
                      <div className="d-flex align-items-center">
                        {match.winnerId === matchPlayerIds[0] && (
                          <FontAwesomeIcon className="text-warning mx-1" icon="trophy" />
                        )}
                        <UserTournamentInfo userId={matchPlayerIds[0]} />
                      </div>
                      <span className="px-2 pl-5 pl-xl-2 pl-lg-2 pl-md-2 pl-sm-2">VS</span>
                      <div className="d-flex align-items-center">
                        {match.winnerId === matchPlayerIds[1] && (
                          <FontAwesomeIcon className="text-warning mx-1" icon="trophy" />
                        )}
                        <UserTournamentInfo userId={matchPlayerIds[1]} />
                      </div>
                    </>
                  )}
                </div>
              </div>
              {matchResult && matchResult.result !== 'undefined' && (
                <div
                  className="d-flex align-items-center justify-content-center w-100 p-0 p-sm-1"
                >
                  <span
                    title="Match score"
                    className="text-nowrap mx-2"
                  >
                    <FontAwesomeIcon className="text-secondary mr-2" icon="trophy" />
                    {matchResult.score}
                  </span>
                  <span
                    title="Match success tests percent"
                    className="text-nowrap mx-2"
                  >
                    <FontAwesomeIcon className="text-success mr-2" icon="tasks" />
                    {matchResult.resultPercent}
                  </span>
                  {match.durationSec && (
                    <span
                      title="Match duration seconds"
                      className="text-nowrap mx-2"
                    >
                      <FontAwesomeIcon className="text-primary mr-2" icon="stopwatch" />
                      {match.durationSec}
                    </span>
                  )}

                  {match.startedAt && (
                    <span
                      title="Match finished at"
                      className="text-nowrap ml-2"
                    >
                      <FontAwesomeIcon className="text-primary mr-2" icon="flag-checkered" />
                      {toLocalTime(match.startedAt)}
                    </span>
                  )}
                  {match.finishedAt && (
                    <span
                      title="Match finished at"
                      className="text-nowrap mr-2"
                    >
                      <span className="mx-2">-</span>
                      {toLocalTime(match.finishedAt)}
                    </span>
                  )}
                </div>
              )}
            </div>
            <div className="d-flex justify-content-center ml-lg-2 ml-xl-2 p-0 px-2 p-sm-1">
              <MatchAction
                match={match}
                canModerate={canModerate}
                currentUserIsPlayer={currentUserIsPlayer}
              />
            </div>
          </div>
        );
      })}
    </div>
  );
}

export default memo(UsersMatchList);