hexlet-codebattle/codebattle

View on GitHub
services/app/apps/codebattle/assets/js/widgets/components/UserStats.jsx

Summary

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

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

import i18next from '../../i18n';
import { followUser, unfollowUser } from '../middlewares/Main';
import { redirectToNewGame } from '../slices';

import LanguageIcon from './LanguageIcon';
import Loading from './Loading';
import UserAchievements from './UserAchievements';

const UserStats = ({ data, user: userInfo }) => {
  const dispatch = useDispatch();

  const activeGameId = data?.activeGameId;
  const avatarUrl = userInfo.avatarUrl || data?.user?.avatarUrl || '/assets/images/logo.svg';
  const name = userInfo.name || data?.user?.name || 'Jon Doe';
  const lang = userInfo.lang || data?.user?.lang || 'js';

  const followId = useSelector(state => state.gameUI.followId);

  const handlePlayClick = useCallback(() => {
    if (activeGameId) {
      redirectToNewGame(activeGameId);
    }
  }, [activeGameId]);

  const toggleFollowClick = useCallback(() => {
    if (userInfo.id && followId === userInfo.id) {
      dispatch(unfollowUser(userInfo.id));
    } else {
      dispatch(followUser(userInfo.id));
    }
  }, [userInfo.id, followId, dispatch]);

  return (
    <div className="container-fluid p-2">
      <div className="row">
        <div className="col d-flex align-items-center justify-content-between">
          <div className="d-flex align-items-center">
            <img
              className="img-fluid rounded-lg"
              style={{ maxHeight: '40px', width: '40px' }}
              src={avatarUrl}
              alt="User avatar"
            />
            <div className="d-flex flex-column ml-2">
              <div className="d-flex justify-content-between">
                <div className="d-flex align-items-center">
                  <span>{name}</span>
                  <LanguageIcon className="ml-1" lang={lang} />
                </div>
                <div>
                  <button
                    type="button"
                    title="play active game"
                    className={cn(
                      'btn btn-sm text-primary border-0 rounded-lg',
                      {
                        'text-primary': !!activeGameId,
                        'text-muted': !activeGameId,
                      },
                    )}
                    onClick={handlePlayClick}
                    disabled={!activeGameId}
                  >
                    <FontAwesomeIcon icon="play" />
                  </button>
                  <button
                    type="button"
                    title="follow user"
                    className={cn(
                      'btn btn-sm border-0 rounded-lg',
                      {
                        'text-primary': followId !== userInfo.id,
                        'text-danger': followId === userInfo.id,
                      },
                    )}
                    onClick={toggleFollowClick}
                  >
                    <FontAwesomeIcon icon="binoculars" />
                  </button>
                </div>
              </div>
              <div className="d-flex justify-content-between align-items-baseline">
                <div className="d-flex align-items-baseline">
                  <img src="/assets/images/cup.svg" alt="rating" />
                  <span className="ml-1">
                    {data?.user?.rank || userInfo.rank || '####'}
                  </span>
                </div>
                <div className="d-flex align-items-baseline ml-2">
                  <img src="/assets/images/rating.svg" alt="rating" />
                  <span className="ml-1">
                    {data?.user?.rating || userInfo.rating || '####'}
                  </span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div className="row">
        <div className="col d-flex justify-content-between">
          <div>
            <span>{i18next.t('Won:')}</span>
            <b className="text-success">{data ? data.stats.games.won : '#'}</b>
          </div>
          <div className="ml-1">
            <span>{i18next.t('Lost:')}</span>
            <b className="text-danger">{data ? data.stats.games.lost : '#'}</b>
          </div>
          <div className="ml-1">
            <span>{i18next.t('GaveUp:')}</span>
            <b className="text-warning">
              {data ? data.stats.games.gaveUp : '#'}
            </b>
          </div>
        </div>
      </div>
      {!data ? (
        <Loading small />
      ) : (
        <UserAchievements achievements={data.user.achievements} />
      )}
    </div>
  );
};

export default UserStats;