mirror of
https://github.com/ENSL/ensl_gathers.git
synced 2025-02-20 18:52:27 +00:00
Finish player selection phase
This commit is contained in:
parent
9515c8c6f7
commit
755cb50dcd
7 changed files with 286 additions and 106 deletions
|
@ -9,7 +9,6 @@ var userController = require("../lib/user/controller");
|
|||
|
||||
var getRandomUser = function (callback) {
|
||||
var id = Math.floor(Math.random() * 5000) + 1;
|
||||
console.log(id);
|
||||
client.getUserById({
|
||||
id: id
|
||||
}, function (error, response, body) {
|
||||
|
@ -29,6 +28,7 @@ module.exports = function (io) {
|
|||
return next(error)
|
||||
};
|
||||
socket._user = new User(body);
|
||||
console.log("You:", body.username, body.id);
|
||||
next();
|
||||
})
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* Server API
|
||||
* gather:refresh - Refreshes active gather
|
||||
* gather:select - Selects a player for team
|
||||
* gather:notification - Creates a notification
|
||||
*
|
||||
* Client API
|
||||
|
@ -40,6 +41,7 @@ for (var i = 0; i < 11; i++) {
|
|||
instructions.push(function (callback) {
|
||||
getRandomUser(function (error, response, body) {
|
||||
if (error) return callback(error);
|
||||
console.log(body.username, body.id)
|
||||
if (gather.can("addGatherer")) {
|
||||
gather.addGatherer(new User(body));
|
||||
}
|
||||
|
@ -82,6 +84,13 @@ module.exports = function (namespace) {
|
|||
}
|
||||
});
|
||||
|
||||
socket.on("gather:refresh", function () {
|
||||
socket.emit("gather:refresh", {
|
||||
gather: gather.toJson(),
|
||||
currentGatherer: gather.getGatherer(socket._user)
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("gather:leave", function (data) {
|
||||
if (gather.can("removeGatherer")) {
|
||||
gather.removeGatherer(socket._user);
|
||||
|
@ -89,6 +98,38 @@ module.exports = function (namespace) {
|
|||
}
|
||||
});
|
||||
|
||||
socket.on("gather:select", function (data) {
|
||||
var playerId = data.player;
|
||||
// Check team & leader
|
||||
var gatherLeader = gather.getGatherer(socket._user);
|
||||
|
||||
// Cancel if not gatherer or leader
|
||||
if (gatherLeader === null || gatherLeader.leader === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Cancel if id belongs to a leader
|
||||
var selectedPlayer = gather.getGatherer({id: playerId});
|
||||
|
||||
if (selectedPlayer === null || selectedPlayer.leader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var team = gatherLeader.team;
|
||||
|
||||
var method = (team === 'alien') ? gather.moveToAlien : gather.moveToMarine;
|
||||
method.call(gather, selectedPlayer.user);
|
||||
|
||||
refreshGather();
|
||||
});
|
||||
|
||||
socket.on("gather:select:confirm", function () {
|
||||
var user = socket._user;
|
||||
if (gather.can("confirmSelection")) {
|
||||
gather.confirmSelection(user);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("disconnect", function () {
|
||||
|
||||
});
|
||||
|
|
|
@ -59,33 +59,39 @@ var JoinGatherButton = React.createClass({
|
|||
var SelectPlayerButton = React.createClass({
|
||||
selectPlayer: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:select", {
|
||||
player: parseInt(e.target.value, 10)
|
||||
})
|
||||
},
|
||||
render: function () {
|
||||
if (!this.props.currentGatherer.leader) {
|
||||
return false;
|
||||
if (this.props.gatherer.leader) {
|
||||
return (<button
|
||||
className="btn btn-xs btn-default"
|
||||
data-disabled="true">Leader</button>);
|
||||
} else {
|
||||
return (<button
|
||||
onClick={this.selectPlayer}
|
||||
value={this.props.gatherer.id}
|
||||
className="btn btn-xs btn-primary"> Select
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var GatherTeams = React.createClass({
|
||||
alienGatherers: function () {
|
||||
return this.props.gather.gatherers.filter(function (gatherer) {
|
||||
return gatherer.team === "alien";
|
||||
}).sort(function (gatherer) {
|
||||
return (gatherer.leader) ? 1 : 0;
|
||||
return (gatherer.leader) ? 1 : -1;
|
||||
});
|
||||
},
|
||||
marineGatherers: function () {
|
||||
return this.props.gather.gatherers.filter(function (gatherer) {
|
||||
return gatherer.team === "marine";
|
||||
}).sort(function (gatherer) {
|
||||
return (gatherer.leader) ? 1 : 0;
|
||||
return (gatherer.leader) ? 1 : -1;
|
||||
});
|
||||
},
|
||||
render: function () {
|
||||
|
@ -224,6 +230,79 @@ var GatherProgress = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var GatherActions = React.createClass({
|
||||
leaveGather: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:leave");
|
||||
},
|
||||
confirmTeam: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:select:confirm");
|
||||
},
|
||||
inviteToGather: function (e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
render: function () {
|
||||
var joinButton;
|
||||
if (this.props.currentGatherer) {
|
||||
joinButton = (<li><button
|
||||
onClick={this.leaveGather}
|
||||
className="btn btn-danger">Leave Gather</button></li>);
|
||||
} else {
|
||||
joinButton = (<li><JoinGatherButton /></li>);
|
||||
}
|
||||
|
||||
var confirmTeam;
|
||||
if (this.props.currentGatherer &&
|
||||
this.props.currentGatherer.leader &&
|
||||
this.props.gather.state === 'selection' &&
|
||||
this.props.gather.gatherers.every(function (gatherer) {
|
||||
return gatherer.team !== 'lobby';
|
||||
}) ) {
|
||||
if (this.props.currentGatherer.confirm) {
|
||||
confirmTeam = (
|
||||
<li>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
data-disabled="true"
|
||||
>
|
||||
Confirmed
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
confirmTeam = (
|
||||
<li>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={this.confirmTeam}
|
||||
>
|
||||
Confirm Team
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var inviteButton;
|
||||
if (this.props.gather.state === 'gathering') {
|
||||
inviteButton = (<li><button
|
||||
onClick={this.inviteToGather}
|
||||
className="btn btn-primary">Invite to Gather</button></li>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="panel-footer text-right">
|
||||
<ul className="list-inline">
|
||||
{confirmTeam}
|
||||
{inviteButton}
|
||||
{joinButton}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Gather = React.createClass({
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
|
@ -232,9 +311,6 @@ var Gather = React.createClass({
|
|||
}
|
||||
}
|
||||
},
|
||||
joinedGather: function () {
|
||||
return this.props.currentGatherer !== null;
|
||||
},
|
||||
componentDidMount: function () {
|
||||
var self = this;
|
||||
socket.on("gather:refresh", function (data) {
|
||||
|
@ -244,28 +320,13 @@ var Gather = React.createClass({
|
|||
});
|
||||
});
|
||||
},
|
||||
leaveGather: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:leave", {});
|
||||
},
|
||||
inviteToGather: function (e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var joinButton;
|
||||
if (this.joinedGather()) {
|
||||
joinButton = (<li><button
|
||||
onClick={this.leaveGather}
|
||||
className="btn btn-danger">Leave Gather</button></li>);
|
||||
} else {
|
||||
joinButton = (<li><JoinGatherButton /></li>);
|
||||
}
|
||||
var inviteButton;
|
||||
if (this.props.gather.state === 'gathering') {
|
||||
inviteButton = (<li><button
|
||||
onClick={this.inviteToGather}
|
||||
className="btn btn-primary">Invite to Gather</button></li>);
|
||||
if (this.props.gather.state === 'done') {
|
||||
return (<h1>Gather Completed! Now restart the app</h1>);
|
||||
}
|
||||
|
||||
|
||||
var gatherTeams;
|
||||
if (this.props.gather.state === 'selection') {
|
||||
gatherTeams = <GatherTeams gather={this.props.gather} />
|
||||
|
@ -279,12 +340,7 @@ var Gather = React.createClass({
|
|||
<Gatherers gather={this.props.gather} currentGatherer={this.props.currentGatherer} />
|
||||
{gatherTeams}
|
||||
<GatherProgress gather={this.props.gather} />
|
||||
<div className="panel-footer text-right">
|
||||
<ul className="list-inline">
|
||||
{inviteButton}
|
||||
{joinButton}
|
||||
</ul>
|
||||
</div>
|
||||
<GatherActions {...this.props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -294,19 +350,20 @@ var Gatherers = React.createClass({
|
|||
render: function () {
|
||||
var self = this;
|
||||
var gatherers = this.props.gather.gatherers.map(function (gatherer) {
|
||||
var lifeforms = (
|
||||
gatherer.user.ability.lifeforms.map(function (lifeform) {
|
||||
return (<span className="label label-default">{lifeform}</span>);
|
||||
})
|
||||
);
|
||||
|
||||
// Switch this to online status
|
||||
var online= (<span src="/images/commander.png"
|
||||
alt="online"
|
||||
className="user-online"> </span>);
|
||||
var online= (<div className="dot online"></div>);
|
||||
|
||||
var division = (<span className="label label-primary">{gatherer.user.ability.division}</span>);
|
||||
var action = lifeforms;
|
||||
var action;
|
||||
|
||||
if (self.props.gather.state === 'gathering') {
|
||||
action = (
|
||||
gatherer.user.ability.lifeforms.map(function (lifeform) {
|
||||
return (<span className="label label-default">{lifeform}</span>);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (self.props.gather.state === "election") {
|
||||
var votes = self.props.gather.gatherers.reduce(function (acc, voter) {
|
||||
if (voter.leaderVote === gatherer.id) acc++;
|
||||
|
@ -320,12 +377,20 @@ var Gatherers = React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
if (self.props.gather.state === 'selection') {
|
||||
action = (
|
||||
<span>
|
||||
<SelectPlayerButton gatherer={gatherer} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={gatherer.user.id}>
|
||||
<td className="col-md-1">{online}</td>
|
||||
<td className="col-md-5">{gatherer.user.username}</td>
|
||||
<td className="col-md-2">{online}</td>
|
||||
<td className="col-md-4">{gatherer.user.username}</td>
|
||||
<td className="col-md-3">{division} </td>
|
||||
<td className="col-md-2 text-right">{action} </td>
|
||||
<td className="col-md-3 text-right">{action} </td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
|
|
|
@ -19,6 +19,9 @@ var UserLogin = React.createClass({
|
|||
socket.emit("users:authorize", {
|
||||
id: id
|
||||
});
|
||||
setTimeout(function () {
|
||||
socket.emit("gather:refresh");
|
||||
}, 5000);
|
||||
},
|
||||
handleSubmit: function (e) {
|
||||
e.preventDefault();
|
||||
|
|
|
@ -21,12 +21,15 @@
|
|||
margin: 0px 10px;
|
||||
}
|
||||
|
||||
.user-online {
|
||||
.dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
|
||||
background-image: -moz-radial-gradient(45px 45px 45deg, circle cover, yellow 0%, orange 100%, red 95%);
|
||||
background-image: -webkit-radial-gradient(45px 45px, circle cover, yellow, orange);
|
||||
background-image: radial-gradient(45px 45px 45deg, circle cover, yellow 0%, orange 100%, red 95%);
|
||||
vertical-align: middle;
|
||||
position:relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.online {
|
||||
background: #0f0;
|
||||
}
|
162
public/js/app.js
162
public/js/app.js
|
@ -59,33 +59,39 @@ var JoinGatherButton = React.createClass({displayName: "JoinGatherButton",
|
|||
var SelectPlayerButton = React.createClass({displayName: "SelectPlayerButton",
|
||||
selectPlayer: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:select", {
|
||||
player: parseInt(e.target.value, 10)
|
||||
})
|
||||
},
|
||||
render: function () {
|
||||
if (!this.props.currentGatherer.leader) {
|
||||
return false;
|
||||
if (this.props.gatherer.leader) {
|
||||
return (React.createElement("button", {
|
||||
className: "btn btn-xs btn-default",
|
||||
"data-disabled": "true"}, "Leader"));
|
||||
} else {
|
||||
return (React.createElement("button", {
|
||||
onClick: this.selectPlayer,
|
||||
value: this.props.gatherer.id,
|
||||
className: "btn btn-xs btn-primary"}, " Select"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var GatherTeams = React.createClass({displayName: "GatherTeams",
|
||||
alienGatherers: function () {
|
||||
return this.props.gather.gatherers.filter(function (gatherer) {
|
||||
return gatherer.team === "alien";
|
||||
}).sort(function (gatherer) {
|
||||
return (gatherer.leader) ? 1 : 0;
|
||||
return (gatherer.leader) ? 1 : -1;
|
||||
});
|
||||
},
|
||||
marineGatherers: function () {
|
||||
return this.props.gather.gatherers.filter(function (gatherer) {
|
||||
return gatherer.team === "marine";
|
||||
}).sort(function (gatherer) {
|
||||
return (gatherer.leader) ? 1 : 0;
|
||||
return (gatherer.leader) ? 1 : -1;
|
||||
});
|
||||
},
|
||||
render: function () {
|
||||
|
@ -224,6 +230,79 @@ var GatherProgress = React.createClass({displayName: "GatherProgress",
|
|||
}
|
||||
});
|
||||
|
||||
var GatherActions = React.createClass({displayName: "GatherActions",
|
||||
leaveGather: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:leave");
|
||||
},
|
||||
confirmTeam: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:select:confirm");
|
||||
},
|
||||
inviteToGather: function (e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
render: function () {
|
||||
var joinButton;
|
||||
if (this.props.currentGatherer) {
|
||||
joinButton = (React.createElement("li", null, React.createElement("button", {
|
||||
onClick: this.leaveGather,
|
||||
className: "btn btn-danger"}, "Leave Gather")));
|
||||
} else {
|
||||
joinButton = (React.createElement("li", null, React.createElement(JoinGatherButton, null)));
|
||||
}
|
||||
|
||||
var confirmTeam;
|
||||
if (this.props.currentGatherer &&
|
||||
this.props.currentGatherer.leader &&
|
||||
this.props.gather.state === 'selection' &&
|
||||
this.props.gather.gatherers.every(function (gatherer) {
|
||||
return gatherer.team !== 'lobby';
|
||||
}) ) {
|
||||
if (this.props.currentGatherer.confirm) {
|
||||
confirmTeam = (
|
||||
React.createElement("li", null,
|
||||
React.createElement("button", {
|
||||
className: "btn btn-default",
|
||||
"data-disabled": "true"
|
||||
},
|
||||
"Confirmed"
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
confirmTeam = (
|
||||
React.createElement("li", null,
|
||||
React.createElement("button", {
|
||||
className: "btn btn-primary",
|
||||
onClick: this.confirmTeam
|
||||
},
|
||||
"Confirm Team"
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var inviteButton;
|
||||
if (this.props.gather.state === 'gathering') {
|
||||
inviteButton = (React.createElement("li", null, React.createElement("button", {
|
||||
onClick: this.inviteToGather,
|
||||
className: "btn btn-primary"}, "Invite to Gather")));
|
||||
}
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "panel-footer text-right"},
|
||||
React.createElement("ul", {className: "list-inline"},
|
||||
confirmTeam,
|
||||
inviteButton,
|
||||
joinButton
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Gather = React.createClass({displayName: "Gather",
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
|
@ -232,9 +311,6 @@ var Gather = React.createClass({displayName: "Gather",
|
|||
}
|
||||
}
|
||||
},
|
||||
joinedGather: function () {
|
||||
return this.props.currentGatherer !== null;
|
||||
},
|
||||
componentDidMount: function () {
|
||||
var self = this;
|
||||
socket.on("gather:refresh", function (data) {
|
||||
|
@ -244,28 +320,13 @@ var Gather = React.createClass({displayName: "Gather",
|
|||
});
|
||||
});
|
||||
},
|
||||
leaveGather: function (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:leave", {});
|
||||
},
|
||||
inviteToGather: function (e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var joinButton;
|
||||
if (this.joinedGather()) {
|
||||
joinButton = (React.createElement("li", null, React.createElement("button", {
|
||||
onClick: this.leaveGather,
|
||||
className: "btn btn-danger"}, "Leave Gather")));
|
||||
} else {
|
||||
joinButton = (React.createElement("li", null, React.createElement(JoinGatherButton, null)));
|
||||
}
|
||||
var inviteButton;
|
||||
if (this.props.gather.state === 'gathering') {
|
||||
inviteButton = (React.createElement("li", null, React.createElement("button", {
|
||||
onClick: this.inviteToGather,
|
||||
className: "btn btn-primary"}, "Invite to Gather")));
|
||||
if (this.props.gather.state === 'done') {
|
||||
return (React.createElement("h1", null, "Gather Completed! Now restart the app"));
|
||||
}
|
||||
|
||||
|
||||
var gatherTeams;
|
||||
if (this.props.gather.state === 'selection') {
|
||||
gatherTeams = React.createElement(GatherTeams, {gather: this.props.gather})
|
||||
|
@ -279,12 +340,7 @@ var Gather = React.createClass({displayName: "Gather",
|
|||
React.createElement(Gatherers, {gather: this.props.gather, currentGatherer: this.props.currentGatherer}),
|
||||
gatherTeams,
|
||||
React.createElement(GatherProgress, {gather: this.props.gather}),
|
||||
React.createElement("div", {className: "panel-footer text-right"},
|
||||
React.createElement("ul", {className: "list-inline"},
|
||||
inviteButton,
|
||||
joinButton
|
||||
)
|
||||
)
|
||||
React.createElement(GatherActions, React.__spread({}, this.props))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -294,19 +350,20 @@ var Gatherers = React.createClass({displayName: "Gatherers",
|
|||
render: function () {
|
||||
var self = this;
|
||||
var gatherers = this.props.gather.gatherers.map(function (gatherer) {
|
||||
var lifeforms = (
|
||||
gatherer.user.ability.lifeforms.map(function (lifeform) {
|
||||
return (React.createElement("span", {className: "label label-default"}, lifeform));
|
||||
})
|
||||
);
|
||||
|
||||
// Switch this to online status
|
||||
var online= (React.createElement("span", {src: "/images/commander.png",
|
||||
alt: "online",
|
||||
className: "user-online"}, " "));
|
||||
var online= (React.createElement("div", {className: "dot online"}));
|
||||
|
||||
var division = (React.createElement("span", {className: "label label-primary"}, gatherer.user.ability.division));
|
||||
var action = lifeforms;
|
||||
var action;
|
||||
|
||||
if (self.props.gather.state === 'gathering') {
|
||||
action = (
|
||||
gatherer.user.ability.lifeforms.map(function (lifeform) {
|
||||
return (React.createElement("span", {className: "label label-default"}, lifeform));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (self.props.gather.state === "election") {
|
||||
var votes = self.props.gather.gatherers.reduce(function (acc, voter) {
|
||||
if (voter.leaderVote === gatherer.id) acc++;
|
||||
|
@ -320,12 +377,20 @@ var Gatherers = React.createClass({displayName: "Gatherers",
|
|||
);
|
||||
}
|
||||
|
||||
if (self.props.gather.state === 'selection') {
|
||||
action = (
|
||||
React.createElement("span", null,
|
||||
React.createElement(SelectPlayerButton, {gatherer: gatherer})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
React.createElement("tr", {key: gatherer.user.id},
|
||||
React.createElement("td", {className: "col-md-1"}, online),
|
||||
React.createElement("td", {className: "col-md-5"}, gatherer.user.username),
|
||||
React.createElement("td", {className: "col-md-2"}, online),
|
||||
React.createElement("td", {className: "col-md-4"}, gatherer.user.username),
|
||||
React.createElement("td", {className: "col-md-3"}, division, " "),
|
||||
React.createElement("td", {className: "col-md-2 text-right"}, action, " ")
|
||||
React.createElement("td", {className: "col-md-3 text-right"}, action, " ")
|
||||
)
|
||||
);
|
||||
})
|
||||
|
@ -543,6 +608,9 @@ var UserLogin = React.createClass({displayName: "UserLogin",
|
|||
socket.emit("users:authorize", {
|
||||
id: id
|
||||
});
|
||||
setTimeout(function () {
|
||||
socket.emit("gather:refresh");
|
||||
}, 5000);
|
||||
},
|
||||
handleSubmit: function (e) {
|
||||
e.preventDefault();
|
||||
|
|
|
@ -37,9 +37,6 @@
|
|||
</div>
|
||||
|
||||
<ul class="nav navbar-top-links navbar-right">
|
||||
<li>
|
||||
<a href="#" data-toggle="modal" data-target="#designmodal">Design Goals</a>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-user fa-fw"></i> Settings <i class="fa fa-caret-down"></i>
|
||||
|
@ -51,8 +48,11 @@
|
|||
</li>
|
||||
<li><a href="#"><i class="fa fa-music fa-fw"></i> Sounds</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-toggle="modal" data-target="#designmodal">Design Goals</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="login.html"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
|
||||
<li><a href="login.html"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
Loading…
Reference in a new issue