Private
Public Access
1
0

add search box to user list

This commit is contained in:
2017-01-26 14:18:34 +01:00
parent fe5378f69b
commit a8ac13850b
6 changed files with 247 additions and 50 deletions

View File

@@ -251,6 +251,11 @@ main div.txt {
margin: 50px auto 0 auto; margin: 50px auto 0 auto;
} }
main .txt h1 {
font-weight: bold;
text-align: center;
}
main div.txt h2 { main div.txt h2 {
margin: 0 0 50px 0; margin: 0 0 50px 0;
} }
@@ -276,10 +281,6 @@ main .technologies img {
margin: 20px; margin: 20px;
} }
main .technologies h1 {
font-weight: bold;
}
footer { footer {
background: #414040; background: #414040;
width: 100%; width: 100%;
@@ -320,7 +321,7 @@ footer nav ul li a:hover {
color: #FFFFFF; color: #FFFFFF;
} }
@media screen and (max-width: 1100px) { @media screen and (max-width: 1200px) {
header section #id_welcome { header section #id_welcome {
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@@ -143,14 +143,22 @@ header section div.buttons > a.small:hover {
main .user-list-container { main .user-list-container {
display: flex; display: flex;
align-items: center; align-items: flex-start;
justify-content: center; justify-content: center;
flex-wrap: wrap;
width: 100%; width: 100%;
} }
main .user-list-container .user-friend { main .user-list-container .user-friend {
background: #ccc;
width: 15%; width: 15%;
min-width: 145px;
text-align: center;
padding: 10px; padding: 10px;
margin: 5px;
-webkit-border-radius: 3px;
border-radius: 3px;
} }
main .user-list-container .user-friend h1 { main .user-list-container .user-friend h1 {
@@ -171,13 +179,12 @@ main .user-list-container .user-friend button {
color: #FFFFFF; color: #FFFFFF;
padding: 10px; padding: 10px;
-webkit-box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
-webkit-transition: all 250ms ease-in-out; -webkit-transition: all 250ms ease-in-out;
-moz-transition: all 250ms ease-in-out; -moz-transition: all 250ms ease-in-out;
-o-transition: all 250ms ease-in-out; -o-transition: all 250ms ease-in-out;
transition: all 250ms ease-in-out; transition: all 250ms ease-in-out;
-webkit-border-radius: 3px;
border-radius: 3px;
} }
main .user-list-container .user-friend button:hover { main .user-list-container .user-friend button:hover {
@@ -185,16 +192,80 @@ main .user-list-container .user-friend button:hover {
border: 1px solid #658fb8; border: 1px solid #658fb8;
color: #FFFFFF; color: #FFFFFF;
-webkit-box-shadow: 0 7px 15px rgba(0, 0, 0, 0.2);
box-shadow: 0 7px 15px rgba(0, 0, 0, 0.2);
-webkit-transition: all 250ms ease-in-out; -webkit-transition: all 250ms ease-in-out;
-moz-transition: all 250ms ease-in-out; -moz-transition: all 250ms ease-in-out;
-o-transition: all 250ms ease-in-out; -o-transition: all 250ms ease-in-out;
transition: all 250ms ease-in-out; transition: all 250ms ease-in-out;
} }
main .user-list-container .user-friend button.button-offline {
background: #a1a1a1;
border: 1px solid #929292;
@media screen and (max-width: 1100px) { cursor: default;
}
main .user-list-container .user-friend button.button-offline:hover {
background: #a1a1a1;
border: 1px solid #929292;
}
main .user-list-filter form {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
main .user-list-filter input {
border: 1px solid #ccc;
border-right: 0;
min-width: 300px;
padding: 10px;
-webkit-border-top-left-radius: 3px;
border-top-left-radius: 3px;
-webkit-border-bottom-left-radius: 3px;
border-bottom-left-radius: 3px;
}
main .user-list-filter button {
background: #ccc;
width: 42px;
height: 42px;
border: 0;
color: #fff;
-webkit-border-top-right-radius: 3px;
border-top-right-radius: 3px;
-webkit-border-bottom-right-radius: 3px;
border-bottom-right-radius: 3px;
}
main .user-request-container .user-friend {
background: #ff0000;
width: 150px;
color: #403f3f;
padding: 10px;
margin: 10px;
}
main .user-request-container h1 {
font-size: 14px;
color: #fff;
}
main .user-request-container button {
background: #fff;
width: 100%;
font-weight: bold;
color: #ff0000;
border: 0;
padding: 5px;
margin: 0 auto;
}
@media screen and (max-width: 1200px) {
header section { header section {
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@@ -5,6 +5,7 @@ import MineUserList from './mine-user-list/app';
let mineUserList = document.getElementById('mine-user-list'); let mineUserList = document.getElementById('mine-user-list');
ReactDOM.render( ReactDOM.render(
<MineUserList env={mineUserList.dataset.env}/>, <MineUserList env={mineUserList.dataset.env}
webPlayerName={mineUserList.dataset.webPlayerName}/>,
mineUserList mineUserList
); );

View File

@@ -9,10 +9,12 @@ class MineUserList extends React.Component {
this.state = { this.state = {
env: props.env, env: props.env,
webPlayerName: props.webPlayerName,
services: services, services: services,
session: null, session: null,
users: [], users: [],
requests: new Map(), requests: new Map(),
search: '',
}; };
} }
@@ -21,7 +23,7 @@ class MineUserList extends React.Component {
users = new Map(); users = new Map();
webUsers.forEach((item) => { webUsers.forEach((item) => {
if (!users.has(item.email)) { if (!users.has(item.email) && item.username !== this.state.webPlayerName) {
users.set(item.email, item); users.set(item.email, item);
} }
}); });
@@ -52,10 +54,14 @@ class MineUserList extends React.Component {
if (typeof payload.gameAssoc !== 'undefined') { if (typeof payload.gameAssoc !== 'undefined') {
switch (payload.type) { switch (payload.type) {
case 'REQ': case 'REQ':
let req = this.state.requests; let req = this.state.requests,
user = JSON.parse(Base64.decode(payload.user));
if (!req.has(payload.username)) { if (!req.has(user.username)) {
req.set(payload.username, payload); req.set(user.username, {
'gameAssoc': payload.gameAssoc,
'user': user,
});
} }
this.setState({reqests: req}); this.setState({reqests: req});
@@ -63,7 +69,7 @@ class MineUserList extends React.Component {
case 'RESP': case 'RESP':
window.location.href = window.location.origin + '/re-play/' + payload.gameAssoc; window.location.href = window.location.origin + '/re-play/' + payload.gameAssoc;
break; break;
case 'GAME': case 'SEARCH':
break; break;
} }
} }
@@ -81,12 +87,13 @@ class MineUserList extends React.Component {
getProfilePicture(id) { getProfilePicture(id) {
return id !== null ? return id !== null ?
<img src={"http://graph.facebook.com/" + id + "/picture?type=square&width=100&height=100"} <img src={"http://graph.facebook.com/" + id + "/picture?type=square&width=130&height=130"}
alt="Facebook profile"/> : alt="Facebook profile"/> :
""; "";
} }
clickChallengeFriend(username) { clickChallengeFriend(isOnline, username) {
if (isOnline) {
this.state.session.publish('mineseeker/userList', { this.state.session.publish('mineseeker/userList', {
'type': 'REQ', 'type': 'REQ',
'username': username, 'username': username,
@@ -94,14 +101,30 @@ class MineUserList extends React.Component {
}); });
} }
clickChallengeAccepted(data) { return 0;
}
clickChallengeAccepted(username, gameAssoc) {
this.state.session.publish('mineseeker/userList', { this.state.session.publish('mineseeker/userList', {
'type': 'RESP', 'type': 'RESP',
'username': data[0], 'username': username,
'gameAssoc': data[1] 'gameAssoc': gameAssoc
}); });
window.location.href = window.location.origin + '/re-play/' + data[1]; window.location.href = window.location.origin + '/re-play/' + gameAssoc;
}
onChangeSearch(event) {
this.setState({search: event.target.value});
}
handleSubmit(event) {
this.state.session.publish('mineseeker/userList', {
'type': 'SEARCH',
'username': this.state.search
});
event.preventDefault();
} }
render() { render() {
@@ -111,10 +134,14 @@ class MineUserList extends React.Component {
this.state.users.size > 0 this.state.users.size > 0
? this.state.users.forEach((item) => { ? this.state.users.forEach((item) => {
users.push(<div key={this.state.services.randomString(50)} className="user-friend"> users.push(<div key={this.state.services.randomString(50)} className="user-friend">
<div className="img">
{this.getProfilePicture(item.id)} {this.getProfilePicture(item.id)}
</div>
<h1>{item.name}</h1> <h1>{item.name}</h1>
<h2>{item.online ? 'online' : 'offline'}</h2> <button className={item.online ? 'button-online' : 'button-offline'}
<button onClick={this.clickChallengeFriend.bind(this, item.username)}>Challenge</button> onClick={this.clickChallengeFriend.bind(this, item.online, item.username)}>
{item.online ? 'Challenge' : 'Offline'}
</button>
</div>) </div>)
}) })
: ''; : '';
@@ -122,8 +149,12 @@ class MineUserList extends React.Component {
this.state.requests.size > 0 this.state.requests.size > 0
? this.state.requests.forEach((item) => { ? this.state.requests.forEach((item) => {
req.push(<div key={this.state.services.randomString(50)} className="user-friend"> req.push(<div key={this.state.services.randomString(50)} className="user-friend">
<h1>{item.username} <strong>challenged you</strong>!</h1> <div className="img">
<button onClick={this.clickChallengeAccepted.bind(this, [item.username, item.gameAssoc])}>Accept {this.getProfilePicture(item.user.id)}
</div>
<h1>{item.user.name} <br/><strong>challenged you</strong>!</h1>
<button onClick={this.clickChallengeAccepted.bind(this, item.user.username, item.gameAssoc)}>
Accept
</button> </button>
</div>) </div>)
}) })
@@ -134,8 +165,18 @@ class MineUserList extends React.Component {
<div className="user-request-container"> <div className="user-request-container">
{req} {req}
</div> </div>
<div className="user-list-filter">
<form onSubmit={this.handleSubmit.bind(this)}>
<input type="text"
onChange={this.onChangeSearch.bind(this)}
value={this.state.search}
autoFocus="autoFocus"
placeholder="Search users..."/>
<button type="submit"><i className="fa fa-search"></i></button>
</form>
</div>
<div className="user-list-container"> <div className="user-list-container">
{users} {users.length ? users : 'There is no users w/ this search results..'}
</div> </div>
</div> </div>
); );

View File

@@ -63,8 +63,12 @@
{% block body %} {% block body %}
<div class="txt"> <div class="txt">
<h1>Users</h1>
{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %} {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
<div id="mine-user-list" data-env="{{ env }}"></div> <div id="mine-user-list"
data-env="{{ env }}"
data-web-player-name="{{ app.user.username is defined ? app.user.username : '' }}">
</div>
{% endif %} {% endif %}
<div class="technologies"> <div class="technologies">
<h1>Used technologies</h1> <h1>Used technologies</h1>
@@ -96,6 +100,7 @@
{% block stylesheets %} {% block stylesheets %}
{{ parent() }} {{ parent() }}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Rajdhani:300,400,500,600,700&amp;subset=latin-ext" <link href="https://fonts.googleapis.com/css?family=Rajdhani:300,400,500,600,700&amp;subset=latin-ext"
rel="stylesheet"> rel="stylesheet">

View File

@@ -93,6 +93,8 @@ class UserListTopic implements TopicInterface
{ {
$user = $this->clientManipulator->getClient($connection); $user = $this->clientManipulator->getClient($connection);
$userName = is_string($user) ? $user : $user->getUsername(); $userName = is_string($user) ? $user : $user->getUsername();
if ($event['type'] === 'REQ' || $event['type'] === 'RESP') {
$reqUser = $this->clientManipulator->findByUsername($topic, $event['username']); $reqUser = $this->clientManipulator->findByUsername($topic, $event['username']);
/** user is still online */ /** user is still online */
@@ -100,7 +102,7 @@ class UserListTopic implements TopicInterface
$topic->broadcast( $topic->broadcast(
array( array(
'type' => $event['type'], 'type' => $event['type'],
'username' => $userName, 'user' => $this->findUser($topic, $userName),
'gameAssoc' => $event['gameAssoc'], 'gameAssoc' => $event['gameAssoc'],
), ),
array(), array(),
@@ -111,6 +113,26 @@ class UserListTopic implements TopicInterface
} }
} }
if ($event['type'] === 'SEARCH') {
$reqUser = $this->clientManipulator->findByUsername($topic, $userName);
/** user is still online */
if (false !== $reqUser) {
$topic->broadcast(
array(
'type' => $event['type'],
'users' => $this->findUsersForSearch($topic, $event['username']),
'gameAssoc' => true,
),
array(),
array(
$reqUser['connection']->WAMP->sessionId,
)
);
}
}
}
/** /**
* Like RPC is will use to prefix the channel * Like RPC is will use to prefix the channel
* *
@@ -121,6 +143,62 @@ class UserListTopic implements TopicInterface
return 'userlist.topic'; return 'userlist.topic';
} }
/**
* @param $topic
* @param $username
* @return array
*/
private function findUser($topic, $username)
{
$this->reConnect();
$userRepo = $this->em->getRepository('JotunheimrUserBundle:User');
$user = $userRepo->findOneByUsername($username);
$currentOnline = $this->clientManipulator->findByUsername($topic, $username)['client'];
return base64_encode(json_encode(array(
'id' => $user->getFacebookId(),
'name' => $user->getRealName(),
'email' => $user->getEmail(),
'username' => $user->getUsername(),
'online' => $currentOnline !== null
)));
}
/**
* @param $topic
* @param $username
* @return array
*/
private function findUsersForSearch($topic, $username)
{
$this->reConnect();
$userRepo = $this->em->getRepository('JotunheimrUserBundle:User');
$users = $userRepo
->createQueryBuilder('o')
->where('o.username LIKE :username')
->andWhere('o.realName LIKE :realname')
->setParameter('username', "%{$username}%")
->setParameter('realname', "%{$username}%")
->setMaxResults(10)
->getQuery()
->getResult();
$usersAvailable = array();
foreach ($users as $item) {
$usersAvailable[] = array(
'id' => $item->getFacebookId(),
'name' => $item->getRealName(),
'email' => $item->getEmail(),
'username' => $item->getUsername(),
'online' => $this->clientManipulator->findByUsername($topic, $item->getUsername())['client'] !== null
);
}
return base64_encode(json_encode(
$usersAvailable
));
}
/** /**
* Find all users online/offline * Find all users online/offline
* *