ensl_gathers/app/javascripts/components/main.js

536 lines
14 KiB
JavaScript
Raw Normal View History

2016-02-03 18:04:06 +00:00
import {News} from "javascripts/components/news";
2016-01-26 10:44:34 +00:00
import {Events} from "javascripts/components/event";
2016-03-19 13:31:30 +00:00
import {Gather, GatherMenu} from "javascripts/components/gather";
2016-02-03 16:12:08 +00:00
import {InfoButton} from "javascripts/components/info";
2016-02-12 23:22:46 +00:00
import {AdminPanel} from "javascripts/components/admin";
2016-02-03 16:12:08 +00:00
import {Chatroom} from "javascripts/components/message";
2016-01-26 10:44:34 +00:00
import {SoundPanel} from "javascripts/components/sound";
import {SettingsPanel} from "javascripts/components/settings";
2016-02-18 15:36:03 +00:00
import {ArchivedGathers} from "javascripts/components/gatherArchive";
2016-02-12 23:22:46 +00:00
import {CurrentUser, ProfileModal, UserMenu} from "javascripts/components/user";
2016-02-18 15:36:03 +00:00
import {TeamSpeakButton, TeamSpeakModal} from "javascripts/components/teamspeak";
2016-01-26 10:44:34 +00:00
2016-01-22 10:12:23 +00:00
const React = require("react");
2016-01-22 10:12:23 +00:00
const Sound = require("javascripts/components/sound");
2016-01-26 10:44:34 +00:00
const SoundController = Sound.SoundController;
2016-01-22 21:39:03 +00:00
const helper = require("javascripts/helper");
const storageAvailable = helper.storageAvailable;
const io = require("socket.io-client");
2016-02-03 16:55:34 +00:00
2016-02-18 15:36:03 +00:00
const App = React.createClass({
2016-01-22 10:12:23 +00:00
getInitialState() {
return {
2016-01-26 10:44:34 +00:00
status: "connecting",
2016-01-22 10:12:23 +00:00
socket: null
}
},
componentDidMount() {
const socketUrl = window.location.origin;
const socket = io(socketUrl)
.on("connect", () => {
2016-01-26 10:44:34 +00:00
this.setState({ status: "connected" });
socket
2016-02-03 16:55:34 +00:00
.on("reconnect", () => {})
.on("disconnect", () => {});
2016-01-22 10:12:23 +00:00
})
.on("error", error => {
if (error === "Authentication Failed") {
this.setState({ status: "authFailed" });
} else if (error === "Gather Banned") {
this.setState({ status: "banned" });
} else {
socket.disconnect();
}
2016-01-22 10:12:23 +00:00
});
2018-11-18 21:13:47 +00:00
this.setState({ socket: socket });
socket.open();
2016-01-22 10:12:23 +00:00
},
render() {
const status = this.state.status;
2016-01-26 10:44:34 +00:00
2016-01-22 10:12:23 +00:00
if (status === "connected") {
2016-02-18 15:36:03 +00:00
return <GatherPage socket={this.state.socket} />;
}
2016-01-22 10:12:23 +00:00
let splash;
if (status === "authFailed") {
2016-01-26 10:44:34 +00:00
splash = <AuthFailedSplash />;
2016-01-22 10:12:23 +00:00
} else if (status === "banned") {
2016-01-26 10:44:34 +00:00
splash = <BannedSplash />;
} else if (status === "connecting") {
splash = <ConnectingSplash />;
2016-01-22 10:12:23 +00:00
}
return (
<div>
2016-01-26 10:44:34 +00:00
<div style={{"minHeight": "750px"}}>
<div className="container-fluid">
2016-01-22 10:12:23 +00:00
{splash}
</div>
</div>
</div>
);
}
});
const AuthFailedSplash = React.createClass({
render() {
return (
2016-01-26 10:44:34 +00:00
<div className="row" id="auth-required">
<div className="col-lg-6 col-lg-offset-3">
<div className="add-top jumbotron jumbo-auth text-center">
2016-01-22 10:12:23 +00:00
<div>
<img src="/ensl_logo.png" alt="ENSL Logo" />
</div>
<h3>You need to be logged in to the ENSL website to access gathers</h3>
<h3><small>If you are logged on, try visiting a few pages on ENSL.org so the server can update your cookies</small></h3>
<h3><small>If this error persists please contact an admin to fix it</small></h3>
<br />
2017-04-18 14:14:51 +00:00
<p><a className="btn btn-primary btn-lg" href="https://www.ensl.org" role="button">Go to website</a></p>
2016-01-22 10:12:23 +00:00
</div>
</div>
</div>
);
}
});
const BannedSplash = React.createClass({
render() {
return (
<div className="row">
<div className="col-lg-6 col-lg-offset-3">
<div className="add-top jumbotron jumbo-auth text-center">
<div>
<img src="/ensl_logo.png" alt="ENSL Logo" />
</div>
<h3>You're currently barred from joining gathers</h3>
<h3><small>Either wait for the ban to expire or talk to an admin to get it lifted</small></h3>
<br />
2017-04-18 14:14:51 +00:00
<p><a className="btn btn-primary btn-lg" href="https://www.ensl.org/bans" role="button">See the ban list</a></p>
2016-01-22 10:12:23 +00:00
</div>
</div>
</div>
);
}
});
const ConnectingSplash = React.createClass({
render() {
return (
<div className="row" id="authenticating">
<div className="col-lg-6 col-lg-offset-3">
<div className="add-top jumbotron jumbo-auth text-center">
<div>
<img src="/ensl_logo.png" className="jumbo-img" alt="ENSL Logo" />
</div>
<br />
<h3>Authenticating your ENSL account</h3>
<br />
<div>
<img src="/spinner.svg" className="spinner" alt="Loading" />
</div>
</div>
</div>
</div>
);
}
});
2016-02-18 15:36:03 +00:00
const GatherPage = React.createClass({
2016-01-26 10:44:34 +00:00
propTypes: {
socket: React.PropTypes.object.isRequired
},
2015-10-29 19:50:38 +00:00
getInitialState() {
let updateTitle = true;
2016-01-02 21:32:26 +00:00
let showEventsPanel = true;
2015-10-29 19:50:38 +00:00
2016-01-02 21:32:26 +00:00
if (storageAvailable('localStorage')) {
if (localStorage.getItem("updateTitle") !== null) {
updateTitle = JSON.parse(localStorage.getItem("updateTitle"));
}
if (localStorage.getItem("showEventsPanel") !== null) {
showEventsPanel = JSON.parse(localStorage.getItem("showEventsPanel"));
}
2015-10-29 19:50:38 +00:00
}
2015-10-01 10:22:23 +00:00
return {
2016-02-03 16:12:08 +00:00
modal: null,
2016-03-19 13:31:30 +00:00
gatherPool: {
2016-04-01 12:32:46 +00:00
classic: {
gatherers: [],
type: "classic"
2016-03-19 13:31:30 +00:00
}
2015-10-01 10:22:23 +00:00
},
2016-04-01 12:32:46 +00:00
currentGather: "classic",
2015-10-01 10:22:23 +00:00
users: [],
2015-10-02 14:53:11 +00:00
messages: [],
maps: [],
2015-11-15 16:26:32 +00:00
user: null,
2015-10-02 14:53:11 +00:00
servers: [],
archive: [],
2015-11-15 16:26:32 +00:00
socket: null,
2016-01-26 10:44:34 +00:00
events: [],
updateTitle: updateTitle,
showEventsPanel: showEventsPanel,
2016-01-28 12:01:08 +00:00
soundController: new SoundController(),
showMessageBox: true,
collapseMenu: false,
2016-04-18 23:16:10 +00:00
chatContainerHeight: 500,
connectionState: "connected"
2015-10-29 19:50:38 +00:00
};
2015-10-01 10:22:23 +00:00
},
2016-03-19 13:31:30 +00:00
currentGather() {
return this.state.gatherPool[this.state.currentGather];
},
2015-10-01 10:22:23 +00:00
componentDidMount() {
let self = this;
2015-10-02 14:53:11 +00:00
let socket = this.props.socket;
2016-01-22 10:12:23 +00:00
let soundController = this.state.soundController;
2015-10-02 17:52:04 +00:00
2015-10-29 19:50:38 +00:00
this.updateTitle();
2016-04-18 23:16:10 +00:00
$(window).resize(_.debounce(this.reloadChatContainerHeight, 250));
this.reloadChatContainerHeight();
2015-12-24 20:16:46 +00:00
socket.on('stateChange', data => {
let state = data.state;
if (state.from === 'gathering'
&& state.to === 'election'
2016-03-19 13:31:30 +00:00
&& this.thisGatherer(data.type)) {
2015-10-02 17:52:04 +00:00
soundController.playGatherMusic();
}
if (state.from === 'election'
&& state.to === 'gathering') {
soundController.stop();
}
2015-10-02 17:52:04 +00:00
});
2015-10-01 10:22:23 +00:00
socket.on("notify", data => toastr[data.type](data.message));
2015-12-29 16:26:11 +00:00
socket.on('event:append', data => {
let events = self.state.events;
events.unshift(data);
self.setState({
2016-02-12 23:22:46 +00:00
events: events.slice(0, 100)
2015-12-29 16:26:11 +00:00
});
});
socket.on('users:update',
2016-01-26 10:44:34 +00:00
data => self.setState({
2015-10-02 14:53:11 +00:00
users: data.users,
user: data.currentUser
})
);
2015-10-01 10:22:23 +00:00
socket.on("message:append", data => {
2016-01-26 10:44:34 +00:00
self.setState({
messages: self.state.messages.concat(data.messages)
2015-10-01 10:22:23 +00:00
.sort((a, b) => {
return new Date(a.createdAt) - new Date(b.createdAt);
})
});
});
socket.on("message:refresh", data => {
2016-01-26 10:44:34 +00:00
self.setState({
2015-10-02 14:53:11 +00:00
messages: data.messages
});
});
socket.on("gather:refresh", (data) => {
2016-03-19 13:31:30 +00:00
const gatherPool = this.state.gatherPool;
const type = data.type;
gatherPool[type] = data.gather;
2016-01-26 10:44:34 +00:00
self.setState({
2015-10-02 14:53:11 +00:00
maps: data.maps,
servers: data.servers,
2016-03-19 13:31:30 +00:00
gatherPool: gatherPool
2015-10-02 14:53:11 +00:00
});
2015-10-03 22:39:51 +00:00
this.updateTitle();
2015-10-02 14:53:11 +00:00
});
socket.on("gather:archive:refresh", data => {
2016-01-26 10:44:34 +00:00
self.setState({
2015-10-02 14:53:11 +00:00
archive: data.archive,
maps: data.maps,
servers: data.servers
2015-10-01 10:22:23 +00:00
});
});
socket.on("connect", () => {
this.setState({ connectionState: "connected" });
});
socket.on("disconnect", () => {
this.setState({ connectionState: "disconnected" });
});
socket.on("reconnecting", () => {
this.setState({ connectionState: "reconnecting" });
});
socket.on("reconnect", () => {
this.setState({ connectionState: "connected" });
});
2015-10-01 10:22:23 +00:00
socket.emit("users:refresh");
socket.emit("message:refresh");
2016-01-22 10:12:23 +00:00
socket.emit("gather:refresh");
2015-10-01 10:22:23 +00:00
},
2016-02-03 16:55:34 +00:00
updateTitle() {
2016-03-19 13:31:30 +00:00
let gather = this.currentGather();
2016-02-03 16:55:34 +00:00
if (gather && this.state.updateTitle) {
document.title = `NSL Gathers (${gather.gatherers.length}/${gather.teamSize * 2})`;
2016-04-18 22:11:18 +00:00
} else {
document.title = "NSL Gathers";
2016-02-03 16:55:34 +00:00
}
},
2016-04-18 23:16:10 +00:00
reloadChatContainerHeight() {
let chatContainer = document.getElementById("chat-container");
if (chatContainer) {
this.setState({ chatContainerHeight: chatContainer.clientHeight });
}
},
2016-02-03 16:55:34 +00:00
toggleEventsPanel(event) {
let newState = event.target.checked;
this.setState({ showEventsPanel: newState });
if (storageAvailable('localStorage')) {
localStorage.setItem("showEventsPanel", newState)
}
},
toggleUpdateTitle(event) {
let newState = event.target.checked;
this.setState({ updateTitle: newState });
if (storageAvailable('localStorage')) {
localStorage.setItem("updateTitle", newState)
}
this.updateTitle();
},
2016-03-19 13:31:30 +00:00
thisGatherer(gatherType) {
if (gatherType === undefined) gatherType = this.state.currentGather;
let gather = this.state.gatherPool[gatherType];
2016-02-03 16:55:34 +00:00
let user = this.state.user;
if (gather && user && gather.gatherers.length) {
return gather.gatherers
.filter(gatherer => gatherer.id === user.id)
.pop() || null;
}
return null;
},
mountModal(options) {
this.setState({ modal: options });
},
2016-02-03 16:55:34 +00:00
closeModal() {
this.setState({ modal: null });
},
modal() {
const options = this.state.modal;
if (!options) return;
const Component = options.component;
return (
<div className="modal fade in" style={{display: "block"}}>
<Component {...options.props} close={this.closeModal} />
</div>
);
},
2016-01-28 12:01:08 +00:00
toggleMessageBox(e) {
e.preventDefault();
this.setState({
showMessageBox: !this.state.showMessageBox
});
},
toggleCollapseMenu(e) {
e.preventDefault();
this.setState({
collapseMenu: !this.state.collapseMenu
});
},
2016-02-03 16:55:34 +00:00
openProfileModal(e) {
e.preventDefault();
this.mountModal({
component: ProfileModal,
props: {
user: this.state.user,
socket: this.props.socket
}
});
},
2016-03-19 13:31:30 +00:00
onGatherSelected(gatherName) {
let gather = this.state.gatherPool[gatherName];
if (gather === undefined) return;
this.setState({
currentGather: gather.type
});
2016-04-18 22:11:18 +00:00
setTimeout(this.updateTitle, 200);
2016-03-19 13:31:30 +00:00
},
2015-10-01 10:22:23 +00:00
render() {
2016-01-26 10:44:34 +00:00
const socket = this.props.socket;
2016-01-02 21:32:26 +00:00
let eventsPanel;
if (this.state.showEventsPanel) {
eventsPanel = <Events events={this.state.events} />;
}
2016-02-03 16:55:34 +00:00
let chatroom, currentUser, profileLink;
2016-01-26 10:44:34 +00:00
if (this.state.user) {
2016-02-03 16:55:34 +00:00
profileLink = (
<li className="dropdown messages-menu">
<a href="#" className="dropdown-toggle" onClick={this.openProfileModal}>
<i className="fa fa-user"></i>
</a>
</li>
);
chatroom = <Chatroom messages={this.state.messages}
user={this.state.user} socket={socket}
2016-04-18 23:16:10 +00:00
containerHeight={this.state.chatContainerHeight}/>;
2016-01-26 10:44:34 +00:00
currentUser = (
<ul className="nav navbar-top-links navbar-right" id="currentuser">
2016-02-03 16:12:08 +00:00
<CurrentUser user={this.state.user} />
</ul>
2016-01-26 10:44:34 +00:00
);
}
const user = this.state.user;
let username, avatar;
if (user) {
username = user.username;
avatar = user.avatar;
}
2016-01-28 12:01:08 +00:00
let appClass = ["skin-blue", "sidebar-mini", "fixed"];
if (this.state.showMessageBox) appClass.push("control-sidebar-open");
if (this.state.collapseMenu) appClass.push("sidebar-collapse");
let connectionStatus;
const connectionState = this.state.connectionState;
if (connectionState === "connected") {
connectionStatus = <a href="#"><i className="fa fa-circle text-success"></i> Online</a>;
} else if (connectionState === "reconnecting") {
connectionStatus = <a href="#"><i className="fa fa-circle text-warning"></i> Reconnecting</a>;
} else if (connectionState === "disconnected") {
connectionStatus = <a href="#"><i className="fa fa-circle text-danger"></i> Disconnected</a>;
}
2016-02-12 23:22:46 +00:00
let adminPanel;
if (user && user.admin) adminPanel = <AdminPanel socket={socket}
2016-03-19 23:37:28 +00:00
gatherPool={this.state.gatherPool} />;
2016-02-12 23:22:46 +00:00
2016-01-26 10:44:34 +00:00
return (
2016-01-28 12:01:08 +00:00
<div className={appClass.join(" ")}>
2016-02-03 16:12:08 +00:00
{this.modal()}
<header className="main-header">
<a href="/" className="logo">
2016-01-26 10:44:34 +00:00
<span className="logo-mini">NSL Gathers</span>
<span className="logo-lg">NSL Gathers</span>
</a>
<nav className="navbar navbar-static-top" role="navigation">
2016-02-03 16:12:08 +00:00
<a href="#" className="sidebar-toggle" onClick={this.toggleCollapseMenu} role="button">
<span className="sr-only">Toggle navigation</span>
</a>
<div className="navbar-custom-menu">
<ul className="nav navbar-nav">
2016-02-12 23:22:46 +00:00
{adminPanel}
2016-02-12 17:05:46 +00:00
<SoundPanel soundController={this.state.soundController} />
2016-02-03 16:55:34 +00:00
{profileLink}
2016-02-03 18:04:06 +00:00
<News />
2016-02-03 16:12:08 +00:00
<li>
2016-02-03 16:55:34 +00:00
<a href="#" onClick={this.toggleMessageBox} className="dropdown-toggle">
<i className="fa fa-comment"></i>
</a>
2016-02-03 16:12:08 +00:00
</li>
2016-01-28 12:01:08 +00:00
</ul>
</div>
2016-02-03 16:12:08 +00:00
</nav>
</header>
<aside className="main-sidebar">
<section className="sidebar" style={{height: "auto"}}>
<div className="user-panel">
<div className="pull-left image">
<img src={avatar} className="img-circle" alt="User Image" />
</div>
<div className="pull-left info">
<p>{username}</p>
{connectionStatus}
</div>
</div>
<GatherMenu
gatherPool={this.state.gatherPool}
currentGather={this.state.currentGather}
gatherSelectedCallback={this.onGatherSelected} />
<ul className="sidebar-menu">
<li className="header">Information</li>
<TeamSpeakButton />
<InfoButton />
</ul>
2016-02-03 16:12:08 +00:00
<ul className="sidebar-menu">
<li className="header">
<span className="badge">{this.state.users.length}</span> Players Online
</li>
</ul>
<UserMenu users={this.state.users} user={this.state.user}
2016-02-03 16:12:08 +00:00
socket={socket} mountModal={this.mountModal}/>
</section>
</aside>
<div className="content-wrapper" style={{"minHeight": "916px"}}>
<section className="content">
2016-02-12 23:22:46 +00:00
<div className="row">
2016-04-19 11:37:00 +00:00
<div className="col-lg-12 col-md-12 col-sm-12">
<Gather
2016-02-12 23:22:46 +00:00
socket={socket}
maps={this.state.maps}
user={this.state.user}
2016-03-19 13:31:30 +00:00
gather={this.currentGather()}
2016-02-12 23:22:46 +00:00
servers={this.state.servers}
thisGatherer={this.thisGatherer()}
soundController={this.state.soundController} />
{eventsPanel}
2016-02-18 14:59:42 +00:00
</div>
</div>
<hr />
<div className="row">
2016-04-19 11:37:00 +00:00
<div className="col-lg-12 col-md-12 col-sm-12">
2016-02-12 23:22:46 +00:00
<ArchivedGathers archive={this.state.archive}
maps={this.state.maps}
servers={this.state.servers} />
</div>
</div>
2016-02-03 16:12:08 +00:00
</section>
</div>
<aside className="control-sidebar control-sidebar-dark"
2016-04-18 23:16:10 +00:00
style={{"position": "fixed", "height": "auto"}}>
2016-02-03 16:12:08 +00:00
<div className="chat-container">
{chatroom}
2016-01-28 12:01:08 +00:00
</div>
</aside>
<div className="control-sidebar-bg"
2016-04-18 23:16:10 +00:00
id="chat-container"
style={{"position":"fixed", "height":"auto"}}></div>
2016-02-03 16:12:08 +00:00
</div>
2016-01-26 10:44:34 +00:00
);
2015-10-01 10:22:23 +00:00
}
2016-01-22 10:12:23 +00:00
});
2016-02-18 15:36:03 +00:00
module.exports = App;