diff --git a/client/app.js b/client/app.js index 228c1c07..316038fb 100644 --- a/client/app.js +++ b/client/app.js @@ -3,6 +3,7 @@ var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); +var atcRouter = require('./routes/api/atc'); var indexRouter = require('./routes/index'); var uikitRouter = require('./routes/uikit'); var usersRouter = require('./routes/users'); @@ -16,6 +17,7 @@ app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', indexRouter); +app.use('/api/atc', atcRouter); app.use('/users', usersRouter); app.use('/uikit', uikitRouter); diff --git a/client/public/stylesheets/atc.css b/client/public/stylesheets/atc.css index 61f79d75..e69de29b 100644 --- a/client/public/stylesheets/atc.css +++ b/client/public/stylesheets/atc.css @@ -1,211 +0,0 @@ -/*** Control panel ***/ - -#atc-control-panel { - align-self: flex-end; - background: white; - border-radius: 10px; - display:flex; - margin: 0 0 50px 100px; - padding:5px; - position: absolute; - z-index: 9999; -} - -.atc-tool { - align-self: center; - border-radius: 10px; - display:none; - justify-self: center; - padding: 10px; - position: absolute; - z-index: 9999; -} - - -.atc-enabled .atc-tool { - display:flex; -} - - - - -#atc-flight-list { - flex-direction: column; -} - -#atc-flight-list table { - color:white; -} - -#atc-flight-list table td { - padding:0 10px; - text-align: center; -} - -#atc-flight-list table td:first-of-type { - text-align: left; -} - -#atc-flight-list table tr[data-status='checkedIn'] td { - background-color:goldenrod; -} - -#atc-flight-list table tr[data-status='readyToTaxi'] td { - background-color:darkgreen; -} - -#atc-flight-list table button { - background-color: #666; - border:1px solid white; - color:white; - font-weight: bold; - margin:2px 0; -} - - -.atc-strip-board { - align-self: center; - display:flex; - justify-self: center; - position: absolute; - z-index: 9999 ; -} - -.atc-strip-board-header { - display:none; -} - -.atc-strip-board-strips { - display:flex; - flex-direction: column; -} - -.atc-strip-board-strip { - display:flex; - flex-direction: row; -} - - -/* -.atc-strip-board-header { - background:black; - color:white; - display:none; - justify-content: right; -} - - -.atc-strip-board { - display:flex; - flex-direction: column; - row-gap: 5px; -} - -.atc-strip-board-strips { - display:flex; - flex-direction: column; - padding:10px; - row-gap: 5px; -} - -.atc-strip-board-strips > div { - align-items: center; - color:white; - column-gap: 2px; - display: flex; - flex-direction: row; - padding: 5px; -} - -.atc-strip-board-header > div, .atc-strip-board-strips > div > div { - text-align: center; - width: 75px; -} - -.atc-strip-board-header > .name { - width:150px; -} - -.atc-strip-board-header > div, .atc-strip-board-strips > div > div { - text-align: center; - width: 75px; -} - -.atc-strip-board-strips > div > .name { - text-align: left; - width:150px; -} - -.atc-strip-board-strips > div { - align-items: center; - column-gap: 5px; - display: flex; - flex-direction: row; - font-size:12px; - font-weight: 600; - padding: 5px; - row-gap: 5px; -} - - -/* - -.atc-strip-board-header, .atc-strip-board-strips > div { - align-items: center; - background:#FFF3; - color:white; - column-gap: 5px; - display: flex; - flex-direction: row; - font-size:12px; - font-weight: 600; - padding: 5px; - row-gap: 5px; -} - -.atc-strip-board-header { - background:black; - color:white; - display:none; - justify-content: right; -} - -.atc-strip-board-strips > div { - border-bottom:1px solid black; -} - -.atc-strip-board-header > div, .atc-strip-board-strips > div > div { - text-align: center; - width: 75px; -} - -.atc-strip-board-header > .name { - width:150px; -} - -.atc-strip-board-strips > div > .handle { - background: black; - border-radius: 50%; - cursor:grab; - height:10px; - width:10px; -} - -.atc-strip-board-strips > div > .name { - text-align: left; - width:150px; -} - -.atc-strip-board-strips > div > .warning { - background:red; - color: white; - font-weight: bold; -} - -.atc-strip-board-strips > div > .link-warning { - border: 1px solid red; - color: red; - font-weight: bold; - -} - */ diff --git a/client/routes/api/atc.js b/client/routes/api/atc.js new file mode 100644 index 00000000..616d1361 --- /dev/null +++ b/client/routes/api/atc.js @@ -0,0 +1,120 @@ +var express = require('express'); +var app = express(); + +const bodyParser = require('body-parser'); +app.use(bodyParser.urlencoded({ extended: false})); +app.use(bodyParser.json()); + + +/* + + Flight: + "name" + "take-off time" + "priority" + "status" + +//*/ + +function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + + + +function Flight( name ) { + this.id = uuidv4(); + this.name = name; +} + +Flight.prototype.getData = function() { + return { + "id": this.id, + "name": this.name + }; +} + +function ATCDataHandler( data ) { + this.data = data; +} + +ATCDataHandler.prototype.addFlight = function( flight ) { + + if ( flight instanceof Flight === false ) { + throw new Error( "Given flight is not an instance of Flight" ); + } + + this.data.flights[ flight.id ] = flight; + +} + + +ATCDataHandler.prototype.deleteFlight = function( flightId ) { + delete this.data.flights[ flightId ]; +} + + +ATCDataHandler.prototype.getFlight = function( flightId ) { + return this.data.flights[ flightId ] || false; +} + + +ATCDataHandler.prototype.getFlights = function() { + return this.data.flights; +} + + +const dataHandler = new ATCDataHandler( { + "flights": {} +} ); + + + +/**************************************************************************************************************/ +// Endpoints +/**************************************************************************************************************/ + + +app.get( "/flight", ( req, res ) => { + + res.json( dataHandler.getFlights() ); + +}); + + +app.post( "/flight", ( req, res ) => { + + if ( !req.body.name ) { + res.status( 400 ).send( "Invalid/missing flight name" ); + } + + const flight = new Flight( req.body.name ); + + dataHandler.addFlight( flight ); + + res.status( 201 ); + + res.json( flight.getData() ); + +}); + + +app.delete( "/flight/:flightId", ( req, res ) => { + + const flight = dataHandler.getFlight( req.params.flightId ); + + if ( !flight ) { + res.status( 400 ).send( `Unrecognised flight ID (given: "${req.params.flightId}")` ); + } + + dataHandler.deleteFlight( req.params.flightId ); + + res.status( 204 ).send( "" ); + +}); + + +module.exports = app; \ No newline at end of file diff --git a/client/src/atc/atc.ts b/client/src/atc/atc.ts deleted file mode 100644 index 14710071..00000000 --- a/client/src/atc/atc.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { ToggleableFeature } from "../toggleablefeature"; -import Sortable from 'sortablejs'; -import { ATCFLightList } from "./flightlist"; - -export class ATC extends ToggleableFeature { - - constructor() { - - super( true ); - - //this.#generateFlightList(); - - let $list = document.getElementById( "atc-strip-board-arrivals" ); - - if ( $list instanceof HTMLElement ) { - Sortable.create( $list, { - "handle": ".handle" - }); - } - - } - - - #generateFlightList() { - - const flightList = new ATCFLightList(); - const flights:any = flightList.getFlights( true ); - - const $tbody = document.getElementById( "atc-flight-list-table-body" ); - - if ( $tbody instanceof HTMLElement ) { - - if ( flights.length > 0 ) { - - let flight:any = {}; - - let $button, i; - - for ( [ i, flight ] of flights.entries() ) { - - const $row = document.createElement( "tr" ); - $row.dataset.status = flight.status - - let $td = document.createElement( "td" ); - $td.innerText = flight.name; - $row.appendChild( $td ); - - $td = document.createElement( "td" ); - $td.innerText = flight.takeOffTime; - $row.appendChild( $td ); - - $td = document.createElement( "td" ); - $td.innerText = "00:0" + ( 5 + i ); - $row.appendChild( $td ); - - $td = document.createElement( "td" ); - $td.innerText = flight.status; - $row.appendChild( $td ); - - - $td = document.createElement( "td" ); - $button = document.createElement( "button" ); - $button.innerText = "..."; - - $td.appendChild( $button ); - - $row.appendChild( $td ); - - - $tbody.appendChild( $row ); - - } - - } - - } - - } - - - protected onStatusUpdate(): void { - - document.body.classList.toggle( "atc-enabled", this.getStatus() ); - - } - -} \ No newline at end of file diff --git a/client/src/atc/atcmockapi.ts b/client/src/atc/atcmockapi.ts deleted file mode 100644 index 9720e2d0..00000000 --- a/client/src/atc/atcmockapi.ts +++ /dev/null @@ -1,7 +0,0 @@ -export abstract class ATCMockAPI { - - constructor() {} - - generateMockData() {} - -} \ No newline at end of file diff --git a/client/src/atc/atcmockapi/flights.ts b/client/src/atc/atcmockapi/flights.ts deleted file mode 100644 index 6d6b6435..00000000 --- a/client/src/atc/atcmockapi/flights.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ATCMockAPI } from "../atcmockapi"; - -export class ATCMockAPI_Flights extends ATCMockAPI { - - - generateMockData() { - - let data = []; - const statuses = [ "unknown", "checkedIn", "readyToTaxi" ] - - for ( const [ i, flightName ] of [ "Shark", "Whale", "Dolphin" ].entries() ) { - - data.push({ - "name": flightName, - "status": statuses[ i ], - "takeOffTime": "18:0" + i - }); - - } - - localStorage.setItem( "flightList", JSON.stringify( data ) ); - - } - - - get( generateMockDataIfEmpty?:boolean ) : object { - - generateMockDataIfEmpty = generateMockDataIfEmpty || false; - - let data = localStorage.getItem( "flightList" ) || "[]"; - - if ( data === "[]" && generateMockDataIfEmpty ) { - this.generateMockData(); - } - - return JSON.parse( data ); - - } - -} \ No newline at end of file diff --git a/client/src/atc/flightlist.ts b/client/src/atc/flightlist.ts deleted file mode 100644 index 36185eef..00000000 --- a/client/src/atc/flightlist.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ATCMockAPI_Flights } from "./atcmockapi/flights"; - -export class ATCFLightList { - - - constructor() { - - - - } - - - getFlights( generateMockDataIfEmpty?:boolean ) { - let api = new ATCMockAPI_Flights(); - return api.get( generateMockDataIfEmpty ); - } - -} \ No newline at end of file diff --git a/client/views/atc.ejs b/client/views/atc.ejs index ee082b92..68537f08 100644 --- a/client/views/atc.ejs +++ b/client/views/atc.ejs @@ -1,106 +1,3 @@ -