diff --git a/public/favicon.ico b/public/favicon.ico index a11777cc471a4344702741ab1c8a588998b1311a..024bc75ef8673d4c4be9d578c42c05be84569963 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..a72cfc2ec3abcdf83a52fd53644a13f9844d6224 Binary files /dev/null and b/public/favicon.png differ diff --git a/public/index.html b/public/index.html index 624e8a0d931011a538149b4b305ddba45719f1d1..960acce5c2bb3654ab7c92a991308c3c0bba0c81 100644 --- a/public/index.html +++ b/public/index.html @@ -19,11 +19,10 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - <title>React App</title> + <title>TACS</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> - <div id="form"></div> <div id="root"></div> <!-- This HTML file is a template. diff --git a/public/wimma.png b/public/wimma.png new file mode 100644 index 0000000000000000000000000000000000000000..9e687d39389b915f8effc5121d56fd999f16205e Binary files /dev/null and b/public/wimma.png differ diff --git a/src/App.css b/src/App.css index a0c99fee8d065ca947e7f47aaf956d4d918bf6c2..b0f08dddfc38b5c27752c025dbfe8113491b93d2 100644 --- a/src/App.css +++ b/src/App.css @@ -51,7 +51,7 @@ div.header button:hover { div.fade-main { position: fixed; top: 0; - z-index: 1020; + z-index: 1000; height: 100vh; width: 100vw; margin: auto; @@ -60,22 +60,22 @@ div.fade-main { } div.sticky { - position: fixed; - top: 0px; - right: 0px; - height: 100px; - width: 100px; - margin-right: 150px; + position: fixed; + top: 0px; + right: 0px; + height: 100px; + width: 100px; + margin-right: 150px; } .close { - position: fixed; - color: #f1f1f1; - height: 85px; - font-size: 100px; - font-weight: bold; - transition: transform 0.4s ease-in-out; - line-height: 70%; + position: fixed; + color: #f1f1f1; + height: 85px; + font-size: 100px; + font-weight: bold; + transition: transform 0.4s ease-in-out; + line-height: 70%; } .close:hover, @@ -138,61 +138,3 @@ div.login button:hover { background-color: darkblue; cursor: pointer; } - -.login .formDate { - width: 30%; -} - -.login label.formDate { - color: white; - width: 10%; - margin-left: 10%; - font-size: 180%; -} - -.login .formTime { - width: 30%; - margin-right: 20%; -} - -/* Editing text button in the toolbar */ -.leaflet-draw-toolbar .leaflet-draw-draw-textbox { - background-image: url("icons/button-textbox.png"); - background-size: 30px 30px; -} - -/* Editing tooltips */ -.leaflet-tooltip { - font-size: 18px; - /* Overriding tooltip layout by making it invisible */ - background-color: transparent; - box-shadow: none; - border: none; - padding: 0; -} - -/* remove the small triangle on tooltip */ -.leaflet-tooltip-bottom:before { - border: 0; -} - -/* Editing editable tooltips */ -.editable { - cursor: text; /* the cursor icon doesn't change by default when hovering on top of the text; overriding */ - min-width: 154px; - min-height: 18px; - color: #fff; - font-weight: bold; - /* text borders */ - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, - 1px 1px 0 #000; -} - -/* placeholder text for tooltip */ -[contenteditable="true"]:empty:before { - content: attr(placeholder); - display: block; /* For Firefox */ - color: #777; - text-shadow: none; - font-weight: normal; -} diff --git a/src/App.js b/src/App.js index a7f472449d5ddaf41c517bc9b63b969e042843c7..7342088361a7e2c36e0cf4cd71d5a6b7e269817b 100644 --- a/src/App.js +++ b/src/App.js @@ -31,7 +31,6 @@ class App extends Component { <div> <UserMap position={initialPosition} zoom={this.state.zoom} mapUrl={this.state.mapUrl} />, <Header handleLayerChange={this.handleLayerChange} /> - </div> ); } diff --git a/src/components/DrawTools.js b/src/components/DrawTools.js index 00ee52aa71938a5e4159edaaf65464381c1b525b..cad46ebc192b29ccec8321ab819882a32a767561 100644 --- a/src/components/DrawTools.js +++ b/src/components/DrawTools.js @@ -1,145 +1,120 @@ import React, { Component } from "react"; import { EditControl } from "react-leaflet-draw"; -import L from "leaflet"; -import "leaflet-draw"; -import { FeatureGroup } from "react-leaflet"; - -// class for text field -L.Draw.MarkerTextBox = L.Draw.Marker.extend({ - options: { - icon: L.divIcon({ - className: "", // empty class to override default styling - iconSize: [20, 20], - iconAnchor: [10, 20] - }), - repeatMode: false, - interactive: true - }, - initialize: function(map, options) { - this.type = "textbox"; // important to have a unique type, so that it won't get mixed up with other elements - this.featureTypeCode = "textbox"; - L.Draw.Feature.prototype.initialize.call(this, map, options); - } -}); - -// Overriding default toolbar -// Just adding one new button though lol -L.DrawToolbar.include({ - getModeHandlers: function(map) { - return [ - { - enabled: this.options.polyline, - handler: new L.Draw.Polyline(map, this.options.polyline), - title: L.drawLocal.draw.toolbar.buttons.polyline - }, - { - enabled: this.options.polygon, - handler: new L.Draw.Polygon(map, this.options.polygon), - title: L.drawLocal.draw.toolbar.buttons.polygon - }, - { - enabled: this.options.rectangle, - handler: new L.Draw.Rectangle(map, this.options.rectangle), - title: L.drawLocal.draw.toolbar.buttons.rectangle - }, - { - enabled: this.options.circle, - handler: new L.Draw.Circle(map, this.options.circle), - title: L.drawLocal.draw.toolbar.buttons.circle - }, - { - enabled: this.options.marker, - handler: new L.Draw.Marker(map, this.options.marker), - title: L.drawLocal.draw.toolbar.buttons.marker - }, - { - enabled: this.options.marker, - handler: new L.Draw.MarkerTextBox(map, this.options.marker), - title: "Write text" - } - ]; - } -}); +import { FeatureGroup, Marker, Polygon, Polyline } from "react-leaflet"; class DrawTools extends Component { constructor(props) { super(props); this.state = { - geoJSONAll: [] // property for all GeoJSON data in the map + geoJSONAll: [], // property for all GeoJSON data in the map + editModeActive: false }; } _onCreated = e => { - // check if a drawn polyline has just one point in it - if (e.layerType === "polyline" && e.layer.getLatLngs().length === 1) { - e.layer.remove(); - return; - } + let type = e.layerType; // from the example; isn't used right now, but may be relevant in the future + let layer = e.layer; + this.makeGeoJSON(e.layer); + }; - if (e.layerType === "textbox") { - // have to create tooltip as a DOM element to allow text selecting. maybe - let tooltip = L.DomUtil.create("div", "editable"); - tooltip.innerHTML = - '<div contenteditable="true" placeholder="Click here and type"></div>'; + _onEditMove = e => { + console.log("_onEditMove e:"); + console.log(e); + // to be added once back-end has functionality to recognize ids + // this.props.sendGeoJSON(e.layer); + }; - e.layer.bindTooltip(tooltip, { - permanent: true, - direction: "bottom", - interactive: true - }); + _onEditResize = e => { + console.log("_onEditResize e:"); + console.log(e); + }; - // disable dragging when cursor is over marker (tooltip) - // clicking on tooltip fires the marker's click handler, hence e.layer.on - e.layer.on("mouseover", function() { - e.layer._map.dragging.disable(); - }); + _onEditVertex = e => { + console.log("_onEditVertex e:"); + console.log(e); + // to be added once back-end has functionality to recognize ids + // this.props.sendGeoJSON(e.poly); + }; - // enable dragging again when cursor is out of marker (tooltip) - e.layer.on("mouseout", function() { - e.layer._map.dragging.enable(); - }); + _onEditDeleteStart = () => { + this.setState({ editModeActive: true }); + }; - // show placeholder text again upon emptying textbox - e.layer.on("keyup", function() { - // when the text area is emptied, a <br> appears - // manually removing it so that the placeholder text can show - if ( - tooltip.innerHTML === - '<div placeholder="Click here and type" contenteditable="true"><br></div>' || - tooltip.innerHTML === - '<div placeholder="Click here and type" contenteditable="true"><div><br></div></div>' - ) { - tooltip.innerHTML = - '<div placeholder="Click here and type" contenteditable="true"></div>'; - } - }); - } // end if (e.layerType === "textbox") + _onEditDeleteStop = () => { + this.setState({ editModeActive: false }); + }; - // turning layer data to GeoJSON - this.makeGeoJSON(e.layer); - }; // end _onCreated + _onDeleted = e => { + console.log(e.layers._layers); + /* to be added once back-end functionality is available + for(layer in e.layers._layers) { + this.sendGeoJSON(layer.options.id); + } + */ + }; + shouldComponentUpdate() { + // disable re-rendering when edit mode is active + return !this.state.editModeActive; + } + + // turn layer to GeoJSON data and add it to an array of all GeoJSON data of the current map makeGeoJSON = e => { let geoJSON = e.toGeoJSON(); - let newGeoJSONAll = this.state.geoJSONAll; - newGeoJSONAll.push(geoJSON); // can't do +=, need to use push function - console.log(JSON.stringify(newGeoJSONAll, null, 4)); - this.setState({ geoJSONAll: newGeoJSONAll }); + console.log( + "UserMapille lähetettävä layeri: " + JSON.stringify(geoJSON, null, 4) + ); // printing GeoJSON data of the previous object create + this.props.sendGeoJSON(geoJSON); + }; + + addFetchedLayerToMap = (id, feature) => { + if (feature.geometry.type === "Point") { + // GeoJSON saves latitude first, not longitude like usual. swapping + let position = [ + feature.geometry.coordinates[1], + feature.geometry.coordinates[0] + ]; + // keys are required to be able to edit + return <Marker key={Math.random()} position={position} id={id} />; + } else if (feature.geometry.type === "Polygon") { + // polygons have, for some reason, an extra single element array above other arrays. no other objects have this + let coords = feature.geometry.coordinates[0]; + let positions = coords.map(item => { + return [item[1], item[0]]; + }); + return <Polygon key={Math.random()} positions={positions} id={id} />; + } else if (feature.geometry.type === "LineString") { + let coords = feature.geometry.coordinates; + let positions = coords.map(item => { + return [item[1], item[0]]; + }); + return <Polyline key={Math.random()} positions={positions} id={id} />; + } }; render() { return ( - // "It's important to wrap EditControl component into FeatureGroup component from react-leaflet. The elements you draw will be added to this FeatureGroup layer, when you hit edit button only items in this layer will be edited." + // "It's important to wrap EditControl component into FeatureGroup component from react-leaflet. + // The elements you draw will be added to this FeatureGroup layer, + // when you hit edit button only items in this layer will be edited." <FeatureGroup> <EditControl position="topright" onCreated={this._onCreated} + onEditStart={this._onEditDeleteStart} + onEditStop={this._onEditDeleteStop} + onEditMove={this._onEditMove} + onEditResize={this._onEditResize} + onEditVertex={this._onEditVertex} + onDeleted={this._onDeleted} + onDeleteStart={this._onEditDeleteStart} + onDeleteStop={this._onEditDeleteStop} draw={{ circle: { repeatMode: true, // allows using the tool again after finishing the previous shape shapeOptions: { color: "#f9f10c", - opacity: 1 // affects the outline only. for some reason it wasn't at full opacity, so this is needed for more clarity + opacity: 1 } }, rectangle: { @@ -165,11 +140,24 @@ class DrawTools extends Component { } }, marker: { - repeatMode: false + repeatMode: true }, circlemarker: false }} + edit={{ + marker: true + }} /> + + {/* iterate through every element fetched from back-end */} + {this.props.geoJSONLayer.features.map((feature, arrayIndex) => { + // first element in geoJSONLayer has an extra one element array for some reason + if (arrayIndex === 0) { + return this.addFetchedLayerToMap(feature[0], feature[1][0]); + } else { + return this.addFetchedLayerToMap(feature[0], feature[1]); + } + })} </FeatureGroup> ); } diff --git a/src/components/EditGameForm.js b/src/components/EditGameForm.js index dd4e9bd08d7b4c74390a6f4877f97679edecb363..c755815199a7bdba408c8d4206461e6573fed6c8 100644 --- a/src/components/EditGameForm.js +++ b/src/components/EditGameForm.js @@ -1,18 +1,18 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Map, TileLayer } from 'react-leaflet'; +import React from "react"; +import ReactDOM from "react-dom"; +import { Map, TileLayer } from "react-leaflet"; export class EditGameForm extends React.Component { constructor(props) { super(props); this.state = { - gamename: '', - description: '', - startDate: '', - startTime: '', - endDate: '', - endTime: '', + gamename: "", + description: "", + startDate: "", + startTime: "", + endDate: "", + endTime: "", zoom: 13, mapCenter: { lat: 62.2416479, @@ -58,13 +58,13 @@ export class EditGameForm extends React.Component { handleGameSave = e => { let startDate = - this.state.startDate + 'T' + this.state.startTime + ':00.000Z'; - let endDate = this.state.endDate + 'T' + this.state.endTime + ':00.000Z'; + this.state.startDate + "T" + this.state.startTime + ":00.000Z"; + let endDate = this.state.endDate + "T" + this.state.endTime + ":00.000Z"; const gameObject = { name: this.state.gamename, desc: this.state.description, - map: '', + map: "", startdate: startDate, enddate: endDate, center: this.state.mapCenter @@ -72,15 +72,15 @@ export class EditGameForm extends React.Component { e.preventDefault(); - let token = sessionStorage.getItem('token'); + let token = sessionStorage.getItem("token"); // Send Game info to the server - fetch('http://localhost:5000/game/edit/' + this.props.gameId, { - method: 'PUT', + fetch("http://localhost:5000/game/edit/" + this.props.gameId, { + method: "PUT", headers: { - Authorization: 'Bearer ' + token, - Accept: 'application/json', - 'Content-Type': 'application/json' + Authorization: "Bearer " + token, + Accept: "application/json", + "Content-Type": "application/json" }, body: JSON.stringify(gameObject) }) @@ -89,20 +89,20 @@ export class EditGameForm extends React.Component { alert(result.message); this.handleView(); }) - .catch(error => console.log('Error: ', error)); + .catch(error => console.log("Error: ", error)); }; componentDidMount() { - document.addEventListener('keyup', this.handleEsc); + document.addEventListener("keyup", this.handleEsc); this.getGameInfo(this.props.gameId); } componentWillUnmount() { - document.removeEventListener('keyup', this.handleEsc); + document.removeEventListener("keyup", this.handleEsc); } getGameInfo(gameId) { - fetch('http://localhost:5000/game/' + gameId) + fetch("http://localhost:5000/game/" + gameId) .then(response => response.json()) .then(json => this.handleGameInfo(json)) .catch(error => console.log(error)); @@ -201,7 +201,7 @@ export class EditGameForm extends React.Component { className="" center={[this.state.mapCenter.lat, this.state.mapCenter.lng]} zoom={this.state.zoom} - style={{ height: '400px', width: '400px' }} + style={{ height: "400px", width: "400px" }} onmoveend={this.handleMapDrag} onzoomend={this.handleMapScroll} > @@ -218,7 +218,7 @@ export class EditGameForm extends React.Component { </form> </div> </div>, - document.getElementById('form') + document.getElementById("form") ); } } diff --git a/src/components/GameList.js b/src/components/GameList.js index 26d32824205167bf9320b097955d9d405704c488..2d11775cd2eee56a0f6f4bc58d5ffcdcef4c9ebd 100644 --- a/src/components/GameList.js +++ b/src/components/GameList.js @@ -1,5 +1,5 @@ -import React, { Fragment } from 'react'; -import EditGameForm from './EditGameForm'; +import React, { Fragment } from "react"; +import EditGameForm from "./EditGameForm"; class GameList extends React.Component { constructor(props) { @@ -18,7 +18,7 @@ class GameList extends React.Component { } getGames() { - fetch('http://localhost:5000/game/listgames') + fetch("http://localhost:5000/game/listgames") .then(response => response.json()) .then(games => { this.setState({ @@ -39,7 +39,7 @@ class GameList extends React.Component { handleEditClick = e => { if (this.state.selectedGame === null) { - alert('No game selected'); + alert("No game selected"); } else { this.setState({ editForm: true @@ -69,11 +69,11 @@ class GameList extends React.Component { return ( <Fragment> <label>Game: </label> - <select id='changeActiveGameList' onChange={this.handleChange}> + <select id="changeActiveGameList" onChange={this.handleChange}> {items} </select> - {sessionStorage.getItem('token') && ( - <button id='editGameButton' onClick={this.handleEditClick}> + {sessionStorage.getItem("token") && ( + <button id="editGameButton" onClick={this.handleEditClick}> Edit game </button> )} diff --git a/src/components/Header.js b/src/components/Header.js index 6a0f788fcea295fff261cf87a6163a92889ebe45..8b64035f0fc43487dd1a54844dc214d03555c1eb 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,13 +1,13 @@ -import React from 'react'; +import React from "react"; -import LoginForm from './LoginForm'; -import RegisterForm from './RegisterForm'; -import GameList from './GameList'; -import NewGameForm from './NewGameForm'; +import LoginForm from "./LoginForm"; +import RegisterForm from "./RegisterForm"; +import GameList from "./GameList"; +import NewGameForm from "./NewGameForm"; class Header extends React.Component { state = { - form: '', // Popup form (login, register etc.) + form: "", // Popup form (login, register etc.) username: null, token: null }; @@ -20,23 +20,23 @@ class Header extends React.Component { }; handleState = data => { - sessionStorage.setItem('name', data.name); - sessionStorage.setItem('token', data.token); + sessionStorage.setItem("name", data.name); + sessionStorage.setItem("token", data.token); this.setState({ username: data.name, token: data.token }); }; handleLogout = () => { this.setState({ username: null, token: null }); - sessionStorage.removeItem('token'); + sessionStorage.removeItem("token"); }; // verifies the token (if it exists) on element mount with backend server componentDidMount() { - let token = sessionStorage.getItem('token'); + let token = sessionStorage.getItem("token"); if (token) { - fetch('http://localhost:5000/user/verify', { + fetch(`${process.env.REACT_APP_URL}/user/verify`, { headers: { - Authorization: 'Bearer ' + token + Authorization: "Bearer " + token } }) .then(res => res.json()) @@ -45,7 +45,7 @@ class Header extends React.Component { // if token is still valid, login user if (result === true) { this.setState({ - username: sessionStorage.getItem('name'), + username: sessionStorage.getItem("name"), token: token }); // logout user if token has expired / is invalid @@ -63,56 +63,56 @@ class Header extends React.Component { render() { return ( <div> - <div className='header'> + <div className="header"> {!this.state.username && ( <button - id='registerButton' - onClick={() => this.toggleView('register')} + id="registerButton" + onClick={() => this.toggleView("register")} > register </button> )} {!this.state.username && ( - <button id='loginButton' onClick={() => this.toggleView('login')}> + <button id="loginButton" onClick={() => this.toggleView("login")}> login </button> )} {this.state.username && ( <button - id='newGameButton' - onClick={() => this.toggleView('newgame')} + id="newGameButton" + onClick={() => this.toggleView("newgame")} > New Game </button> )} {this.state.username && ( - <button id='logoutButton' onClick={this.handleLogout}> + <button id="logoutButton" onClick={this.handleLogout}> logout </button> )} {this.state.username && <button>{this.state.username}</button>} - <button id='changeLayerButton' onClick={this.props.handleLayerChange}> + <button id="changeLayerButton" onClick={this.props.handleLayerChange}> change layer </button> <GameList /> </div> - {this.state.form === 'register' && ( + {this.state.form === "register" && ( <RegisterForm - view='' + view="" handleState={this.handleState} toggleView={this.toggleView} /> )} - {this.state.form === 'login' && ( + {this.state.form === "login" && ( <LoginForm - view='' + view="" handleState={this.handleState} toggleView={this.toggleView} /> )} - {this.state.form === 'newgame' && ( + {this.state.form === "newgame" && ( <NewGameForm - view='' + view="" handleState={this.handleState} toggleView={this.toggleView} /> diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js index f37999dd525befe0f4f8cf95f15090f10478b046..3c559b053bd7e78408fcac4f0e2f6aab17bfce08 100644 --- a/src/components/LoginForm.js +++ b/src/components/LoginForm.js @@ -1,13 +1,13 @@ -import React from 'react'; +import React from "react"; export class LoginForm extends React.Component { constructor(props) { super(props); this.state = { - errorMsg: '', - username: '', - password: '' + errorMsg: "", + username: "", + password: "" }; } @@ -38,11 +38,11 @@ export class LoginForm extends React.Component { e.preventDefault(); // Send login info to the server - fetch('http://localhost:5000/user/login', { - method: 'POST', + fetch(`${process.env.REACT_APP_URL}/user/login`, { + method: "POST", headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' + Accept: "application/json", + "Content-Type": "application/json" }, body: JSON.stringify({ name: name, @@ -69,48 +69,53 @@ export class LoginForm extends React.Component { }; componentDidMount() { - document.addEventListener('keyup', this.handleEsc); + document.addEventListener("keyup", this.handleEsc); } componentWillUnmount() { - document.removeEventListener('keyup', this.handleEsc); + document.removeEventListener("keyup", this.handleEsc); } render() { return ( - <div className='fade-main'> - <div className='sticky'> - <span id="closeLoginFormX" className='close' onClick={this.handleView}> + <div className="fade-main"> + <div className="sticky"> + <span + id="closeLoginFormX" + className="close" + onClick={this.handleView} + > × </span> </div> - <div className='login'> + <div className="login"> <form onSubmit={this.handleLogin}> <h1>demo login</h1> <br /> <input - placeholder='Enter Username' - name='username' + placeholder="Enter Username" + name="username" value={this.state.username} onChange={this.handleChange} id="loginUsernameInput" /> <br /> <input - placeholder='Enter password' - type='password' - name='password' + placeholder="Enter password" + type="password" + name="password" value={this.state.password} onChange={this.handleChange} id="loginPasswordInput" /> <br /> - <button id="submitLoginButton" type='submit'>login</button> + <button id="submitLoginButton" type="submit"> + login + </button> <h2>{this.state.errorMsg}</h2> </form> </div> </div> - ); } } diff --git a/src/components/NewGameForm.js b/src/components/NewGameForm.js index 3f83ccfa0f2cc7a87b500ffb2f938bfe39b72b41..aeee892c1dc2c7f106470eb93bb12aa31c8410c3 100644 --- a/src/components/NewGameForm.js +++ b/src/components/NewGameForm.js @@ -1,18 +1,18 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Map, TileLayer } from 'react-leaflet'; +import React from "react"; +import ReactDOM from "react-dom"; +import { Map, TileLayer } from "react-leaflet"; export class NewGameForm extends React.Component { constructor(props) { super(props); this.state = { - gamename: '', - description: '', - startDate: '', - startTime: '', - endDate: '', - endTime: '', + gamename: "", + description: "", + startDate: "", + startTime: "", + endDate: "", + endTime: "", passwords: [], zoom: 13, mapCenter: { @@ -59,13 +59,13 @@ export class NewGameForm extends React.Component { handleGameCreation = e => { let startDate = - this.state.startDate + 'T' + this.state.startTime + ':00.000Z'; - let endDate = this.state.endDate + 'T' + this.state.endTime + ':00.000Z'; + this.state.startDate + "T" + this.state.startTime + ":00.000Z"; + let endDate = this.state.endDate + "T" + this.state.endTime + ":00.000Z"; const gameObject = { name: this.state.gamename, desc: this.state.description, - map: '', + map: "", startdate: startDate, enddate: endDate, passwords: [this.state.password], @@ -74,15 +74,15 @@ export class NewGameForm extends React.Component { e.preventDefault(); - let token = sessionStorage.getItem('token'); + let token = sessionStorage.getItem("token"); // Send Game info to the server - fetch('http://localhost:5000/game/new', { - method: 'POST', + fetch("http://localhost:5000/game/new", { + method: "POST", headers: { - Authorization: 'Bearer ' + token, - Accept: 'application/json', - 'Content-Type': 'application/json' + Authorization: "Bearer " + token, + Accept: "application/json", + "Content-Type": "application/json" }, body: JSON.stringify(gameObject) }) @@ -90,15 +90,15 @@ export class NewGameForm extends React.Component { .then(result => { this.handleView(); }) - .catch(error => console.log('Error: ', error)); + .catch(error => console.log("Error: ", error)); }; componentDidMount() { - document.addEventListener('keyup', this.handleEsc); + document.addEventListener("keyup", this.handleEsc); } componentWillUnmount() { - document.removeEventListener('keyup', this.handleEsc); + document.removeEventListener("keyup", this.handleEsc); } render() { @@ -176,7 +176,7 @@ export class NewGameForm extends React.Component { className="" center={[this.state.mapCenter.lat, this.state.mapCenter.lng]} zoom={this.state.zoom} - style={{ height: '400px', width: '400px' }} + style={{ height: "400px", width: "400px" }} onmoveend={this.handleMapDrag} onzoomend={this.handleMapScroll} > @@ -193,7 +193,7 @@ export class NewGameForm extends React.Component { </form> </div> </div>, - document.getElementById('form') + document.getElementById("form") ); } } diff --git a/src/components/RegisterForm.js b/src/components/RegisterForm.js index 960731a446dc6ac6fd9210f7d9b74cbe46066874..56360b6f7c1565c49aa11d8ad7957ab156c35dce 100644 --- a/src/components/RegisterForm.js +++ b/src/components/RegisterForm.js @@ -62,7 +62,7 @@ export class RegisterForm extends React.Component { this.props.handleState(result); this.handleView(); } else { - this.handleError(result.message); + this.handleError(result.errorResponse.message); } }, // Note: it's important to handle errors here @@ -87,11 +87,7 @@ export class RegisterForm extends React.Component { return ( <div className='fade-main'> <div className='sticky'> - <span - id='closeRegisterFormX' - className='close' - onClick={this.handleView} - > + <span className='close' onClick={this.handleView}> × </span> </div> @@ -104,7 +100,8 @@ export class RegisterForm extends React.Component { name='username' value={this.state.username} onChange={this.handleChange} - id='registerUsernameInput' + autoFocus + required /> <br /> <input @@ -113,7 +110,7 @@ export class RegisterForm extends React.Component { name='password' value={this.state.password} onChange={this.handleChange} - id='registerPasswordInput' + required /> <br /> <input @@ -122,12 +119,10 @@ export class RegisterForm extends React.Component { name='password2' value={this.state.password2} onChange={this.handleChange} - id='registerPasswordVerifyInput' + required /> <br /> - <button id='submitRegisterButton' type='submit'> - register - </button> + <button type='submit'>register</button> <h2>{this.state.errorMsg}</h2> </form> </div> diff --git a/src/components/UserMap.js b/src/components/UserMap.js index 4b3e690ea038c66268066abdda38bedb7a22cdfa..052133ff11e4b65cbda0397c9b0795e9d42f1590 100644 --- a/src/components/UserMap.js +++ b/src/components/UserMap.js @@ -1,17 +1,23 @@ import React, { Component } from "react"; import { Map, TileLayer, ZoomControl, Marker, Popup } from "react-leaflet"; -import L from "leaflet"; import DrawTools from "./DrawTools.js"; class UserMap extends Component { constructor(props) { super(props); + this.state = { ownLat: null, ownLng: null, - mapUrl: "https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg" + mapUrl: "https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg", + geoJSONLayer: { + type: "FeatureCollection", + features: [] + } }; + this.sendGeoJSON = this.sendGeoJSON.bind(this); + this.setCurrentPosition = this.setCurrentPosition.bind(this); this.watchPositionId = null; } @@ -19,6 +25,49 @@ class UserMap extends Component { this.getCurrentPosition(position => { this.setCurrentPosition(position); }); + this.fetchGeoJSON(); + } + // Sends the players drawings to the backend (and database) + sendGeoJSON(layerToDatabase) { + fetch("http://localhost:5000/draw/mapdrawing/insert-location", { + method: "PUT", + headers: { + Authorization: "Bearer " + sessionStorage.getItem("token"), + Accept: "application/json", + "Content-Type": "application/json" + }, + // need to add id once back-end is ready for it + body: JSON.stringify({ + type: "FeatureCollection", + features: layerToDatabase + }) + }); + } + // Get the drawings from the backend and add them to the state, so they can be drawn + fetchGeoJSON() { + fetch("http://localhost:5000/draw/mapdrawing/insert-location", { + method: "GET", + headers: { + Authorization: "Bearer " + sessionStorage.getItem("token"), + Accept: "application/json", + "Content-Type": "application/json" + } + }) + .then(res => res.json()) + .then(data => { + console.log(data); + let newFeatures = []; + data.map(item => { + newFeatures.push([item.id, item.features]); + }); + + this.setState({ + geoJSONLayer: { + type: "FeatureCollection", + features: [...newFeatures] + } + }); + }); } componentWillUnmount() { @@ -49,61 +98,45 @@ class UserMap extends Component { navigator.geolocation.clearWatch(this.watchPositionId); } - if(this.watchPositionId != null){navigator.geolocation.clearWatch(this.watchPositionId);} - - this.watchPositionId = navigator.geolocation.watchPosition((position) =>{ - //success - if(position != null){ - callback(position); - } - }, (error) =>{ - console.log(error); - // disable tracking - if(this.watchPositionId != null){ - navigator.geolocation.clearWatch(this.watchPositionId); - } - }, options); + this.watchPositionId = navigator.geolocation.watchPosition( + position => { + //success + if (position != null) { + callback(position); + } + }, + error => { + console.log(error); + // disable tracking + if (this.watchPositionId != null) { + navigator.geolocation.clearWatch(this.watchPositionId); + } + }, + options + ); } } - positionToGeoJSON(position) { - let geoJSON = { - type: "Feature", - properties: {}, - geometry: { - type: "Point", - coordinates: [position.coords.longitude, position.coords.latitude] - } - }; - - return JSON.stringify(geoJSON); - } - - testers = asd => { - console.log(asd.target.getZoom()); - }; - render() { return ( <Map - className='map' + className="map" center={this.props.position} zoom={this.props.zoom} - minZoom='7' - maxZoom='17' - zoomControl={false}> + minZoom="7" + maxZoom="17" + zoomControl={false} + > <TileLayer attribution='© <a href="https://www.maanmittauslaitos.fi/">Maanmittauslaitos</a>' url={this.props.mapUrl} /> - <ZoomControl position="topright" /> - <DrawTools position={this.props.position} /> - <Marker position={this.props.position}> - <Popup> - Se on perjantai, my dudes <br /> - </Popup> - </Marker> + <DrawTools + position={this.props.position} + sendGeoJSON={this.sendGeoJSON} + geoJSONLayer={this.state.geoJSONLayer} + /> {this.state.ownLat !== null && ( <Marker position={[this.state.ownLat, this.state.ownLng]}> <Popup> @@ -116,5 +149,4 @@ class UserMap extends Component { ); } } - export default UserMap; diff --git a/src/icons/button-textbox.png b/src/icons/button-textbox.png deleted file mode 100644 index e36a2872bdf8f68df996d35159335a77211ead7a..0000000000000000000000000000000000000000 Binary files a/src/icons/button-textbox.png and /dev/null differ diff --git a/src/icons/color-icon-2.png b/src/icons/color-icon-2.png new file mode 100644 index 0000000000000000000000000000000000000000..6623db24a39f19eb6f46f539c0eb3d7a0e9620bf Binary files /dev/null and b/src/icons/color-icon-2.png differ diff --git a/src/icons/color-icon.png b/src/icons/color-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..28e54479f3d7fbfecc52694f51a7c6d2dbec1a34 Binary files /dev/null and b/src/icons/color-icon.png differ diff --git a/src/icons/nil.png b/src/icons/nil.png deleted file mode 100644 index ae058ee7bffad41634a20cd463fc94219f0de69b..0000000000000000000000000000000000000000 Binary files a/src/icons/nil.png and /dev/null differ