Skip to content

Commit

Permalink
Added user statistic popover hexlet-codebattle#437
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Liauchuk authored and puku committed Jan 26, 2019
1 parent 37d67d6 commit aba3006
Show file tree
Hide file tree
Showing 15 changed files with 209 additions and 117 deletions.
1 change: 1 addition & 0 deletions services/app/assets/js/widgets/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const updateExecutionOutput = createAction('UPDATE_EXECUTION_OUTPUT');

export const setCurrentUser = createAction('SET_CURRENT_USER');
export const updateUsers = createAction('UPDATE_USERS');
export const updateUsersStats = createAction('UPDATE_USERS_STATS');

export const sendPlayerCode = createAction('SEND_PLAYER_CODE');
export const updateEditorLang = createAction('UPDATE_EDITOR_LANG');
Expand Down
19 changes: 9 additions & 10 deletions services/app/assets/js/widgets/components/Loading.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { Component } from 'react';
import React from 'react';
import ReactLoading from 'react-loading';

export default class Messages extends Component {
render() {
return (
<div className="d-flex my-0 py-1 justify-content-center" >
<ReactLoading type="spin" color="#6c757d" height={50} width={50} />
</div>
);
}
}
export default ({ small }) => {
const size = small ? 30 : 50;
return (
<div className="d-flex my-0 py-1 justify-content-center">
<ReactLoading type="spin" color="#6c757d" height={size} width={size} />
</div>
);
};
23 changes: 23 additions & 0 deletions services/app/assets/js/widgets/components/UserStats.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import Loading from './Loading';

const UserStats = ({ stats }) => {
if (stats) {
return (
<div>
Won:
<b className="text-success">{stats.won}</b>
<br />
Lost:
<b className="text-danger">{stats.lost}</b>
<br />
Gave up:
<b className="text-warning">{stats.gave_up}</b>
</div>
);
}

return <Loading small />;
};

export default UserStats;
14 changes: 6 additions & 8 deletions services/app/assets/js/widgets/containers/ChatWidget.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React from 'react';
import { connect } from 'react-redux';
import { fetchState, addMessage } from '../middlewares/Chat';
import { chatUsersSelector, chatMessagesSelector, currentChatUserSelector } from '../selectors';
import * as selectors from '../selectors';
import Messages from '../components/Messages';
import UserName from '../components/UserName';
import UserInfo from './UserInfo';
import InputWithEmoji from '../components/InputWithEmoji';

class ChatWidget extends React.Component {
state = { message: '' };

messagesEnd = null;

componentDidMount() {
const { dispatch } = this.props;
dispatch(fetchState());
Expand Down Expand Up @@ -68,7 +66,7 @@ class ChatWidget extends React.Component {
>
{users.map(user => (
<div key={user.id} className="my-2">
<UserName user={user} />
<UserInfo user={user} />
</div>
))}
</div>
Expand All @@ -81,9 +79,9 @@ class ChatWidget extends React.Component {
}

const mapStateToProps = state => ({
users: chatUsersSelector(state),
messages: chatMessagesSelector(state),
currentUser: currentChatUserSelector(state),
users: selectors.chatUsersSelector(state),
messages: selectors.chatMessagesSelector(state),
currentUser: selectors.currentChatUserSelector(state),
});

export default connect(
Expand Down
54 changes: 24 additions & 30 deletions services/app/assets/js/widgets/containers/GameList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import React, { Fragment } from 'react';
import _ from 'lodash';
import moment from 'moment';
import { connect } from 'react-redux';
// import PropTypes from 'prop-types';
import Gon from 'gon';
import { Tooltip, OverlayTrigger } from 'react-bootstrap';
import { fetchState } from '../middlewares/Lobby';
import GameStatusCodes from '../config/gameStatusCodes';
import Loading from '../components/Loading';
import GamesHeatmap from '../components/GamesHeatmap';
import UserName from '../components/UserName';
import UserInfo from './UserInfo';

class GameList extends React.Component {
levelToClass = {
Expand Down Expand Up @@ -60,19 +59,19 @@ class GameList extends React.Component {
if (users.length === 1) {
return (
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }} colSpan={2}>
<UserName user={users[0]} />
<UserInfo user={users[0]} />
</td>
);
}
return (
<Fragment>
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{this.renderResultIcon(gameId, users[0], users[1])}
<UserName user={users[0]} />
<UserInfo user={users[0]} />
</td>
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{this.renderResultIcon(gameId, users[1], users[0])}
<UserName user={users[1]} />
<UserInfo user={users[1]} />
</td>
</Fragment>
);
Expand Down Expand Up @@ -178,7 +177,7 @@ class GameList extends React.Component {
</div>
</div>
);
}
};

renderActiveGames = () => {
const { activeGames } = this.props;
Expand Down Expand Up @@ -206,40 +205,36 @@ class GameList extends React.Component {
</tr>
</thead>
<tbody>
{activeGames.map((game) => {
console.log(game);
return (
<tr key={game.game_id}>
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{moment
.utc(game.game_info.inserted_at)
.local()
.format('YYYY-MM-DD HH:mm')}
</td>
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{this.renderGameLevelBadge(game.game_info.level)}
</td>
{activeGames.map(game => (
<tr key={game.game_id}>
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{moment
.utc(game.game_info.inserted_at)
.local()
.format('YYYY-MM-DD HH:mm')}
</td>
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{this.renderGameLevelBadge(game.game_info.level)}
</td>

{this.renderPlayers(game.id, game.users)}
{this.renderPlayers(game.id, game.users)}

<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{game.game_info.state}
</td>
<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{game.game_info.state}
</td>

<td className="p-3 align-middle">{this.renderGameActionButton(game)}</td>
</tr>
);
})}
<td className="p-3 align-middle">{this.renderGameActionButton(game)}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
};

render() {
const { activeGames, completedGames } = this.props;

if (!activeGames) {
return <Loading />;
}
Expand Down Expand Up @@ -278,7 +273,6 @@ class GameList extends React.Component {
{this.renderGameLevelBadge(game.level)}
</td>
{this.renderPlayers(game.id, game.players)}

<td className="p-3 align-middle" style={{ whiteSpace: 'nowrap' }}>
{moment.duration(game.duration, 'seconds').humanize()}
</td>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';
// import i18n from '../../i18n';
import GameStatusCodes from '../config/gameStatusCodes';
import * as selectors from '../selectors';
import {
checkGameResult, changeCurrentLangAndSetTemplate, compressEditorHeight, expandEditorHeight,
} from '../middlewares/Game';
import LanguagePicker from '../components/LanguagePicker';
import UserName from '../components/UserName';
import UserInfo from './UserInfo';
import GameResultIcon from '../components/GameResultIcon';

class LeftEditorToolbar extends Component {
static defaultProps = {
status: GameStatusCodes.initial,
title: '',
onlineUsers: [],
}
};

renderNameplate = (player = {}, onlineUsers) => {
const color = _.find(onlineUsers, { id: player.id }) ? 'green' : '#ccc';
return (
<div>
<UserName user={player} />
<UserInfo user={player} />
<span
className="fa fa-plug align-middle ml-2"
style={{ color }}
Expand Down
123 changes: 61 additions & 62 deletions services/app/assets/js/widgets/containers/RightEditorToolbar.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';
// import i18n from '../../i18n';
import GameStatusCodes from '../config/gameStatusCodes';
import * as selectors from '../selectors';
import {
checkGameResult, changeCurrentLangAndSetTemplate, compressEditorHeight, expandEditorHeight,
} from '../middlewares/Game';
import LanguagePicker from '../components/LanguagePicker';
import UserName from '../components/UserName';
import UserInfo from './UserInfo';
import GameResultIcon from '../components/GameResultIcon';

class RightEditorToolbar extends Component {
Expand All @@ -17,74 +16,74 @@ class RightEditorToolbar extends Component {
title: '',
users: {},
onlineUsers: [],
}
};

renderNameplate = (player = {}, onlineUsers) => {
const color = _.find(onlineUsers, { id: player.id }) ? 'green' : '#ccc';
return (
<div>
<UserInfo user={player} />
<span
className="fa fa-plug align-middle ml-2"
style={{ color }}
/>
</div>
);
};

renderNameplate = (player = {}, onlineUsers) => {
const color = _.find(onlineUsers, { id: player.id }) ? 'green' : '#ccc';
return (
<div>
<UserName user={player} />
<span
className="fa fa-plug align-middle ml-2"
style={{ color }}
/>
renderEditorHeightButtons = (compressEditor, expandEditor, userId) => (
<div className="btn-group btn-group-sm mr-2" role="group" aria-label="Editor height">
<button
type="button"
className="btn btn-sm border rounded"
onClick={() => compressEditor(userId)}
>
<i className="fa fa-compress" aria-hidden="true" />
</button>
<button
type="button"
className="btn btn-sm border rounded ml-2"
onClick={() => expandEditor(userId)}
>
<i className="fa fa-expand" aria-hidden="true" />
</button>
</div>
);
};

renderEditorHeightButtons = (compressEditor, expandEditor, userId) => (
<div className="btn-group btn-group-sm mr-2" role="group" aria-label="Editor height">
<button
type="button"
className="btn btn-sm border rounded"
onClick={() => compressEditor(userId)}
>
<i className="fa fa-compress" aria-hidden="true" />
</button>
<button
type="button"
className="btn btn-sm border rounded ml-2"
onClick={() => expandEditor(userId)}
>
<i className="fa fa-expand" aria-hidden="true" />
</button>
</div>
);
render() {
const {
rightEditorLangSlug,
rightUserId,
leftUserId,
onlineUsers,
players,
compressEditor,
expandEditor,
} = this.props;

render() {
const {
rightEditorLangSlug,
rightUserId,
leftUserId,
onlineUsers,
players,
compressEditor,
expandEditor,
} = this.props;

if (rightEditorLangSlug === null) {
return null;
}
if (rightEditorLangSlug === null) {
return null;
}

return (
<div className="py-2 px-3 btn-toolbar justify-content-between" role="toolbar">
<GameResultIcon
className="mr-2"
resultUser1={_.get(players, [[rightUserId], 'game_result'])}
resultUser2={_.get(players, [[leftUserId], 'game_result'])}
/>
{this.renderNameplate(players[rightUserId], onlineUsers)}
<div className="ml-auto btn-group" role="group" aria-label="Editor settings">
{this.renderEditorHeightButtons(compressEditor, expandEditor, rightUserId)}
<LanguagePicker
currentLangSlug={rightEditorLangSlug}
onChange={_.noop}
disabled
return (
<div className="py-2 px-3 btn-toolbar justify-content-between" role="toolbar">
<GameResultIcon
className="mr-2"
resultUser1={_.get(players, [[rightUserId], 'game_result'])}
resultUser2={_.get(players, [[leftUserId], 'game_result'])}
/>
{this.renderNameplate(players[rightUserId], onlineUsers)}
<div className="ml-auto btn-group" role="group" aria-label="Editor settings">
{this.renderEditorHeightButtons(compressEditor, expandEditor, rightUserId)}
<LanguagePicker
currentLangSlug={rightEditorLangSlug}
onChange={_.noop}
disabled
/>
</div>
</div>
</div>
);
}
);
}
}

const mapStateToProps = (state) => {
Expand Down
Loading

0 comments on commit aba3006

Please sign in to comment.