Skip to content
Snippets Groups Projects
Commit 8fee3503 authored by Taneli Riihimäki's avatar Taneli Riihimäki
Browse files

Merged joinGame-form to development

parents 9ab0f85c 8463ac78
No related branches found
No related tags found
2 merge requests!26Development,!22Join, edit game form
.env 0 → 100644
REACT_APP_API_URL = "http://localhost:5000"
\ No newline at end of file
......@@ -57,6 +57,8 @@ div.fade-main {
margin: auto;
text-align: center;
background-color: rgba(0, 0, 0, 0.85);
color: white;
overflow: scroll;
}
div.sticky {
......
import React from "react";
import React, { Fragment } from "react";
import ReactDOM from "react-dom";
import { Map, TileLayer } from "react-leaflet";
......@@ -7,17 +7,26 @@ export class EditGameForm extends React.Component {
super(props);
this.state = {
zoom: 13,
gamename: "",
description: "",
startDate: "",
startTime: "",
endDate: "",
endTime: "",
zoom: 13,
map: "",
mapCenter: {
lat: 62.2416479,
lng: 25.7597186
}
},
factionNameInput: "", // >= 2 chars
factionPasswordInput: "", // >= 3 chars
factions: [],
objectivePointDescriptionInput: "", // >= 7
objectivePointMultiplierInput: "", // number
objectivePoints: [],
capture_time: 300,
confirmation_time: 60
};
this.handleMapDrag = this.handleMapDrag.bind(this);
......@@ -32,6 +41,142 @@ export class EditGameForm extends React.Component {
this.setState({ [name]: value });
};
handleFactionAdd = e => {
e.preventDefault();
if (
this.state.factionNameInput === "" ||
this.state.factionPasswordInput === ""
) {
return alert("Faction needs a name and password");
}
if (
this.state.factions.findIndex(
faction => faction.factionName === this.state.factionNameInput
) !== -1
) {
return alert(
"Faction " + this.state.factionNameInput + " already exists"
);
}
this.setState(state => {
let factions = state.factions;
factions.push({
factionName: this.state.factionNameInput,
factionPassword: this.state.factionPasswordInput,
multiplier: 1
});
return {
factions: factions,
factionNameInput: "",
factionPasswordInput: ""
};
});
};
removeFaction(factionName) {
this.setState(state => {
let factions = state.factions;
const index = factions.findIndex(
faction => faction.factionName === factionName
);
if (index !== -1) {
factions.splice(index, 1);
} else {
console.log("Faction is not in the faction list");
}
return factions;
});
}
handleObjectivePointAdd = e => {
e.preventDefault();
if (
this.state.objectivePointDescriptionInput === "" ||
this.state.objectivePointMultiplierInput === ""
) {
return alert("Capture point needs an ID and multiplier");
}
if (
this.state.objectivePoints.findIndex(
point =>
point.objectivePointDescription ===
this.state.objectivePointDescriptionInput
) !== -1
) {
return alert(
"Capture point " +
this.state.objectivePointDescriptionInput +
" already exists"
);
}
this.setState(state => {
let objectivePoints = state.objectivePoints;
objectivePoints.push({
objectivePointDescription: this.state.objectivePointDescriptionInput,
objectivePointMultiplier: parseFloat(
this.state.objectivePointMultiplierInput
)
});
return {
objectivePoints: objectivePoints,
objectivePointDescriptionInput: "",
objectivePointMultiplierInput: ""
};
});
};
removeObjectivePoint(objectivePointId) {
this.setState(state => {
let objectivePoints = state.objectivePoints;
const index = objectivePoints.findIndex(
point => point.objectivePointDescription === objectivePointId
);
if (index !== -1) {
objectivePoints.splice(index, 1);
} else {
console.log("Objective point is not in the point list");
}
return objectivePoints;
});
}
handleGameDeletion = e => {
e.preventDefault();
let token = sessionStorage.getItem("token");
if (window.confirm("Are you sure you want to delete this game")) {
alert("Game deleted");
fetch(
`${process.env.REACT_APP_API_URL}/game/delete/${this.props.gameId}`,
{
method: "DELETE",
headers: {
Authorization: "Bearer " + token
}
}
)
.then(result => result.json())
.then(result => {
console.log(result);
this.handleView();
})
.catch(error => console.log(error));
}
};
// show/hide this form
handleView = e => {
this.props.toggleView(this.props.view);
......@@ -57,20 +202,44 @@ export class EditGameForm extends React.Component {
};
handleGameSave = e => {
e.preventDefault();
let startDate =
this.state.startDate + "T" + this.state.startTime + ":00.000Z";
let endDate = this.state.endDate + "T" + this.state.endTime + ":00.000Z";
const gameObject = {
let objectivePoints = this.state.objectivePoints;
// objective points are not allowed if the game has no factions
if (this.state.factions.length === 0) {
objectivePoints = [];
}
// Object the form sends to server
let gameObject = {
name: this.state.gamename,
desc: this.state.description,
map: "",
startdate: startDate,
enddate: endDate,
center: this.state.mapCenter
center: this.state.mapCenter,
factions: this.state.factions,
objective_points: objectivePoints
};
e.preventDefault();
// Add node settings to the game if the game has objective points
if (objectivePoints.length > 0) {
gameObject.nodesettings = {
node_settings: {
capture_time: this.state.capture_time,
confirmation_time: this.state.confirmation_time,
owner: 0,
capture: 0,
buttons_available: 16,
heartbeat_interval: 60
}
};
}
let token = sessionStorage.getItem("token");
......@@ -87,7 +256,9 @@ export class EditGameForm extends React.Component {
.then(res => res.json())
.then(result => {
alert(result.message);
this.handleView();
if (result.code === 200) {
this.handleView();
}
})
.catch(error => console.log("Error: ", error));
};
......@@ -104,27 +275,113 @@ export class EditGameForm extends React.Component {
getGameInfo(gameId) {
fetch(`${process.env.REACT_APP_API_URL}/game/${gameId}`)
.then(response => response.json())
.then(json => this.handleGameInfo(json))
.then(json => this.setGameInfoToState(json))
.catch(error => console.log(error));
}
handleGameInfo(json) {
this.setState({
gamename: json.name,
description: json.desc,
startDate: json.startdate.substring(0, 10),
startTime: json.startdate.substring(11, 16),
endDate: json.enddate.substring(0, 10),
endTime: json.enddate.substring(11, 16),
zoom: 13,
mapCenter: {
lat: json.center.lat,
lng: json.center.lng
setGameInfoToState(json) {
let token = sessionStorage.getItem("token");
// Get factions and passwordds
fetch(
`${process.env.REACT_APP_API_URL}/game/get-factions/${this.props.gameId}`,
{
method: "GET",
headers: {
Authorization: "Bearer " + token
}
}
});
)
.then(result => result.json())
.then(result => {
let factions = result.map(faction => {
return {
factionName: faction.factionName,
factionPassword: faction.factionPassword,
multiplier: 1
};
});
// Remove objective point's id from the object
let objectivePoints = json.objective_points.map(point => {
return {
objectivePointDescription: point.objectivePointDescription,
objectivePointMultiplier: point.objectivePointMultiplier
};
});
// get node settings if the settings exists in the game
let nodesettings =
json.nodesettings !== null &&
json.nodesettings.node_settings !== undefined
? json.nodesettings.node_settings
: undefined;
this.setState({
gamename: json.name,
description: json.desc,
startDate: json.startdate.substring(0, 10),
startTime: json.startdate.substring(11, 16),
endDate: json.enddate.substring(0, 10),
endTime: json.enddate.substring(11, 16),
mapCenter: {
lat: json.center.lat,
lng: json.center.lng
},
factions: factions,
objectivePoints: objectivePoints,
capture_time:
nodesettings !== undefined
? json.nodesettings.node_settings.capture_time
: this.state.capture_time,
confirmation_time:
nodesettings !== undefined
? json.nodesettings.node_settings.confirmation_time
: this.state.confirmation_time
});
})
.catch(error => console.log(error));
}
render() {
let factions = [];
for (let i = 0; i < this.state.factions.length; i++) {
const faction = this.state.factions[i];
factions.push(
<li key={faction.factionName}>
<div>
{faction.factionName} : {faction.factionPassword}
</div>
<button
type="button"
onClick={() => this.removeFaction(faction.factionName)}
>
Remove
</button>
</li>
);
}
let objectivePoints = [];
for (let i = 0; i < this.state.objectivePoints.length; i++) {
const point = this.state.objectivePoints[i];
objectivePoints.push(
<li key={point.objectivePointDescription}>
<div>
{point.objectivePointDescription} : {point.objectivePointMultiplier}
</div>
<button
type="button"
onClick={() =>
this.removeObjectivePoint(point.objectivePointDescription)
}
>
Remove
</button>
</li>
);
}
return ReactDOM.createPortal(
<div className="fade-main">
<div className="sticky">
......@@ -137,85 +394,185 @@ export class EditGameForm extends React.Component {
</span>
</div>
<div className="">
<form onSubmit={this.handleGameSave}>
<h1>Demo Game Creation</h1>
<br />
<input
placeholder="Game name"
name="gamename"
value={this.state.gamename}
onChange={this.handleChange}
id="editGameNameInput"
/>
<br />
<input
placeholder="Description"
type="text"
name="description"
value={this.state.description}
onChange={this.handleChange}
id="editGameDescriptionInput"
/>
<br />
<label className="">Start:</label>
<input
className="formDate"
type="date"
name="startDate"
value={this.state.startDate}
onChange={this.handleChange}
id="editGameDateStartInput"
/>
<input
className="formTime"
type="time"
name="startTime"
value={this.state.startTime}
onChange={this.handleChange}
rid="editGameTimeStartInput"
/>
<br />
<label className="">End:</label>
<input
className="formDate"
type="date"
name="endDate"
value={this.state.endDate}
onChange={this.handleChange}
min={this.state.startDate}
id="editGameDateEndInput"
/>
<input
className="formTime"
type="time"
name="endTime"
value={this.state.endTime}
onChange={this.handleChange}
id="editGameTimeEndInput"
<form id="gameEditForm" onSubmit={this.handleGameSave} />
<form id="factionAddFrom" onSubmit={this.handleFactionAdd} />
<form id="gameDeletionForm" onSubmit={this.handleGameDeletion} />
<form
id="objectivePointAddFrom"
onSubmit={this.handleObjectivePointAdd}
/>
<h1>Demo Game Editor</h1>
<br />
<input
placeholder="Game name"
name="gamename"
value={this.state.gamename}
onChange={this.handleChange}
id="editGameNameInput"
form="gameEditForm"
required
/>
<br />
<input
placeholder="Description"
type="text"
name="description"
value={this.state.description}
onChange={this.handleChange}
id="editGameDescriptionInput"
form="gameEditForm"
required
/>
<br />
<label className="">Start:</label>
<input
className="formDate"
type="date"
name="startDate"
value={this.state.startDate}
onChange={this.handleChange}
id="editGameDateStartInput"
form="gameEditForm"
required
/>
<input
className="formTime"
type="time"
name="startTime"
value={this.state.startTime}
onChange={this.handleChange}
sid="editGameTimeStartInput"
form="gameEditForm"
required
/>
<br />
<label className="">End:</label>
<input
className="formDate"
type="date"
name="endDate"
value={this.state.endDate}
onChange={this.handleChange}
min={this.state.startDate}
id="editGameDateEndInput"
form="gameEditForm"
required
/>
<input
className="formTime"
type="time"
name="endTime"
value={this.state.endTime}
onChange={this.handleChange}
id="editGameTimeEndInput"
form="gameEditForm"
required
/>
<br />
<br />
<label>Factions</label>
<br />
<input
name="factionNameInput"
value={this.state.factionNameInput}
minLength="2"
onChange={this.handleChange}
placeholder="Add new faction"
form="factionAddFrom"
/>
<input
name="factionPasswordInput"
value={this.state.factionPasswordInput}
minLength="3"
onChange={this.handleChange}
placeholder="Faction password"
form="factionAddFrom"
/>
<button type="submit" form="factionAddFrom">
Add
</button>
<ul>{factions}</ul>
<br />
<br />
<label>Objective points</label>
<br />
<input
name="objectivePointDescriptionInput"
type="number"
value={this.state.objectivePointDescriptionInput}
onChange={this.handleChange}
placeholder="Objective point id"
min="1000000"
form="objectivePointAddFrom"
/>
<input
name="objectivePointMultiplierInput"
type="number"
value={this.state.objectivePointMultiplierInput}
onChange={this.handleChange}
placeholder="Objective point multiplier"
form="objectivePointAddFrom"
/>
<button type="submit" form="objectivePointAddFrom">
Add
</button>
<ul>{objectivePoints}</ul>
<br />
<br />
<label>Node things (set if objective points are in the game)</label>
<br />
<br />
<label className="" form="gameEditForm">
Capture time:
</label>
<input
name="capture_time"
type="number"
value={this.state.capture_time}
form="gameEditForm"
onChange={this.handleChange}
/>
<label className="">Confimation time:</label>
<input
name="confirmation_time"
type="number"
value={this.state.confirmation_time}
form="gameEditForm"
onChange={this.handleChange}
/>
<br />
<br />
<label>Map things</label>
<br />
<Map
id="editGameCenterMap"
className=""
center={[this.state.mapCenter.lat, this.state.mapCenter.lng]}
zoom={this.state.zoom}
maxZoom="13"
style={{ height: "400px", width: "400px" }}
onmoveend={this.handleMapDrag}
onzoomend={this.handleMapScroll}
>
<TileLayer
attribution="Maanmittauslaitoksen kartta"
url=" https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg"
/>
<br />
<label>Map things</label>
<br />
<Map
id="editGameCenterMap"
className=""
center={[this.state.mapCenter.lat, this.state.mapCenter.lng]}
zoom={this.state.zoom}
style={{ height: "400px", width: "400px" }}
onmoveend={this.handleMapDrag}
onzoomend={this.handleMapScroll}
>
<TileLayer
attribution="Maanmittauslaitoksen kartta"
url=" https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg"
/>
</Map>
<br />
<button id="editGameSubmitButton" type="submit">
Save changes
</button>
<h2>{this.state.errorMsg}</h2>
</form>
</Map>
<br />
<button
style={{ backgroundColor: "red" }}
type="submit"
form="gameDeletionForm"
>
Delete
</button>
<button id="editGameSubmitButton" type="submit" form="gameEditForm">
Save changes
</button>
<h2>{this.state.errorMsg}</h2>
</div>
</div>,
document.getElementById("form")
......
import React, { Fragment } from "react";
import EditGameForm from "./EditGameForm";
import JoinGameForm from "./JoinGameForm";
class GameList extends React.Component {
constructor(props) {
super(props);
this.state = {
games: [],
selectedGame: null,
editForm: false
selectedGame: undefined,
editForm: false,
joinForm: false
};
this.toggleView = this.toggleView.bind(this);
......@@ -21,9 +23,18 @@ class GameList extends React.Component {
fetch(`${process.env.REACT_APP_API_URL}/game/listgames`)
.then(response => response.json())
.then(games => {
let selectedGame =
this.state.selectedGame !== undefined
? this.state.selectedGame
: undefined;
this.setState({
games: games,
selectedGame: games !== undefined && games[0].id
selectedGame:
selectedGame !== undefined
? selectedGame
: games !== undefined
? games[0].id
: undefined
});
// taking the initialized gameID to UserMap.js (GameList.js -> Header.js -> App.js -> UserMap.js)
this.props.handleGameChange(games[0].id);
......@@ -46,7 +57,7 @@ class GameList extends React.Component {
};
handleEditClick = e => {
if (this.state.selectedGame === null) {
if (this.state.selectedGame === undefined) {
alert("No game selected");
} else {
this.setState({
......@@ -55,6 +66,17 @@ class GameList extends React.Component {
}
};
handleJoinClick = e => {
if (this.state.selectedGame === undefined) {
alert("No game selected");
} else {
this.setState({
joinForm: true,
editForm: false
});
}
};
toggleView = e => {
this.setState({
editForm: !this.state.editForm
......@@ -81,16 +103,27 @@ class GameList extends React.Component {
{items}
</select>
{sessionStorage.getItem("token") && (
<button id="editGameButton" onClick={this.handleEditClick}>
Edit game
</button>
<Fragment>
<button id="editGameButton" onClick={this.handleEditClick}>
Edit game
</button>
<button id="editGameButton" onClick={this.handleJoinClick}>
Join Game
</button>
</Fragment>
)}
{this.state.editForm && this.state.selectedGame !== null && (
{this.state.editForm && this.state.selectedGame !== undefined && (
<EditGameForm
gameId={this.state.selectedGame}
toggleView={this.toggleView}
/>
)}
{this.state.joinForm && this.state.selectedGame !== undefined && (
<JoinGameForm
gameId={this.state.selectedGame}
toggleView={this.toggleView}
/>
)}
</Fragment>
);
}
......
import React from "react";
import NewGameForm from "./NewGameForm";
import GameList from "./GameList";
export default class GameSidebar extends React.Component {
state = {
form: ""
};
toggleView = view => {
this.setState({
form: view
});
};
render() {
return (
<div className="game-sidebar">
<GameList />
{this.props.loggedIn && (
<button id="newGameButton" onClick={() => this.toggleView("newgame")}>
New Game
</button>
)}
{this.state.form === "newgame" && (
<NewGameForm view="" toggleView={() => this.toggleView("")} />
)}
</div>
);
}
}
......@@ -2,9 +2,8 @@ import React from "react";
import LoginForm from "./LoginForm";
import RegisterForm from "./RegisterForm";
import GameList from "./GameList";
import NewGameForm from "./NewGameForm";
import TaskListButton from "./TaskListButton";
import GameSidebar from "./GameSidebar";
class Header extends React.Component {
constructor(props) {
......@@ -14,7 +13,8 @@ class Header extends React.Component {
state = {
form: "", // Popup form (login, register etc.)
username: null,
token: null
token: null,
sidebar: false
};
// toggles the login/register view
......@@ -82,14 +82,7 @@ class Header extends React.Component {
login
</button>
)}
{this.state.username && (
<button
id="newGameButton"
onClick={() => this.toggleView("newgame")}
>
New Game
</button>
)}
{this.state.username && (
<button id="logoutButton" onClick={this.handleLogout}>
logout
......@@ -99,8 +92,16 @@ class Header extends React.Component {
<button id="changeLayerButton" onClick={this.props.handleLayerChange}>
change layer
</button>
<GameList handleGameChange={this.props.handleGameChange} />
{this.state.username && <TaskListButton />}
<button
id="sidebarButton"
onClick={() => this.setState({ sidebar: !this.state.sidebar })}
>
Tools
</button>
{this.state.sidebar && (
<GameSidebar loggedIn={this.state.username ? true : false} />
)}
</div>
{this.state.form === "register" && (
<RegisterForm
......@@ -116,13 +117,6 @@ class Header extends React.Component {
toggleView={this.toggleView}
/>
)}
{this.state.form === "newgame" && (
<NewGameForm
view=""
handleState={this.handleState}
toggleView={this.toggleView}
/>
)}
</div>
);
}
......
import React from "react";
export default class JoinGameForm extends React.Component {
constructor(props) {
super(props);
this.state = {
gameJSON: undefined
};
}
componentDidMount() {
if (this.props.gameId === undefined) {
alert("game not selected");
} else {
fetch(`${process.env.REACT_APP_API_URL}/game/${this.props.gameId}`)
.then(result => result.json())
.then(json => {
this.setState({
gameJSON: json
});
})
.catch(error => console.log(error));
}
}
render() {
if (this.state.gameJSON === undefined) {
return false;
}
return (
<div>
<form>
<label>Join game: {this.state.gameJSON.name}</label>
<div>{this.state.gameJSON.desc}</div>
<button onClick={() => console.log("clicked")}>Submit</button>
</form>
</div>
);
}
}
......@@ -98,7 +98,7 @@ export class LoginForm extends React.Component {
value={this.state.username}
onChange={this.handleChange}
id="loginUsernameInput"
autofocus
autoFocus
/>
<br />
<input
......
......@@ -86,7 +86,12 @@ export class NewGameForm extends React.Component {
})
.then(res => res.json())
.then(result => {
this.handleView();
if (result.code) {
alert(result.message);
} else {
alert(`Game ${this.state.gamename} added`);
this.handleView();
}
})
.catch(error => console.log("Error: ", error));
};
......@@ -112,83 +117,98 @@ export class NewGameForm extends React.Component {
</span>
</div>
<div className="">
<form onSubmit={this.handleGameCreation}>
<h1>Demo Game Creation</h1>
<br />
<input
placeholder="Game name"
name="gamename"
value={this.state.gamename}
onChange={this.handleChange}
id="newGameNameInput"
/>
<br />
<input
placeholder="Description"
type="text"
name="description"
value={this.state.description}
onChange={this.handleChange}
id="newGameDescriptionInput"
/>
<br />
<label className="">Start:</label>
<input
className="formDate"
type="date"
name="startDate"
value={this.state.startDate}
onChange={this.handleChange}
id="newGameDateStartInput"
/>
<input
className="formTime"
type="time"
name="startTime"
onChange={this.handleChange}
id="newGameTimeStartInput"
/>
<br />
<label className="">End:</label>
<input
className="formDate"
type="date"
name="endDate"
value={this.state.endDate}
onChange={this.handleChange}
min={this.state.startDate}
id="newGameDateEndInput"
/>
<input
className="formTime"
type="time"
name="endTime"
onChange={this.handleChange}
id="newGameTimeEndInput"
<form id="gameCreationForm" onSubmit={this.handleGameCreation} />
<h1>Demo Game Creation</h1>
<br />
<input
placeholder="Game name"
name="gamename"
value={this.state.gamename}
onChange={this.handleChange}
id="newGameNameInput"
form="gameCreationForm"
required
/>
<br />
<input
placeholder="Description"
type="text"
name="description"
value={this.state.description}
onChange={this.handleChange}
id="newGameDescriptionInput"
form="gameCreationForm"
required
/>
<br />
<label className="">Start:</label>
<input
className="formDate"
type="date"
name="startDate"
value={this.state.startDate}
onChange={this.handleChange}
id="newGameDateStartInput"
form="gameCreationForm"
required
/>
<input
className="formTime"
type="time"
name="startTime"
onChange={this.handleChange}
id="newGameTimeStartInput"
form="gameCreationForm"
required
/>
<br />
<label className="">End:</label>
<input
className="formDate"
type="date"
name="endDate"
value={this.state.endDate}
onChange={this.handleChange}
min={this.state.startDate}
id="newGameDateEndInput"
form="gameCreationForm"
required
/>
<input
className="formTime"
type="time"
name="endTime"
onChange={this.handleChange}
id="newGameTimeEndInput"
form="gameCreationForm"
required
/>
<br />
<label>Map things</label>
<br />
<Map
id="newGameCenterMap"
className=""
center={[this.state.mapCenter.lat, this.state.mapCenter.lng]}
zoom={this.state.zoom}
style={{ height: "400px", width: "400px" }}
onmoveend={this.handleMapDrag}
onzoomend={this.handleMapScroll}
>
<TileLayer
attribution="Maanmittauslaitoksen kartta"
url=" https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg"
/>
<br />
<label>Map things</label>
<br />
<Map
id="newGameCenterMap"
className=""
center={[this.state.mapCenter.lat, this.state.mapCenter.lng]}
zoom={this.state.zoom}
style={{ height: "400px", width: "400px" }}
onmoveend={this.handleMapDrag}
onzoomend={this.handleMapScroll}
>
<TileLayer
attribution="Maanmittauslaitoksen kartta"
url=" https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg"
/>
</Map>
<br />
<button id="newGameSubmitButton" type="submit">
Submit
</button>
<h2>{this.state.errorMsg}</h2>
</form>
</Map>
<br />
<button
id="newGameSubmitButton"
type="submit"
form="gameCreationForm"
>
Submit
</button>
<h2>{this.state.errorMsg}</h2>
</div>
</div>,
document.getElementById("form")
......
......@@ -62,7 +62,7 @@ export class RegisterForm extends React.Component {
this.props.handleState(result);
this.handleView();
} else {
this.handleError(result.errorResponse.message);
this.handleError(result.message);
}
},
// Note: it's important to handle errors here
......@@ -82,7 +82,7 @@ export class RegisterForm extends React.Component {
componentWillUnmount() {
document.removeEventListener("keyup", this.handleEsc);
}
// UNCOMMENT "REQUIRED" FOR PRODUCTION
render() {
return (
<div className="fade-main">
......
import React, { Fragment } from "react";
import React from "react";
class TaskItem extends React.Component {
constructor(props) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment