From 7716f56ea16a40a8e885781ab4ef8d69d7789cf2 Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Wed, 26 Jul 2023 15:45:21 +0200 Subject: [PATCH] loading of occupied seats (BROKEN) --- src/server/backend/api/getHandler.js | 20 +++- src/server/backend/api/postHandler.js | 44 ++++--- src/server/backend/db/data/booked.json | 0 src/server/backend/userAPIRoutes.js | 17 ++- .../userApp/seatplanComponents/standing.vue | 15 ++- .../seatplan/userApp/userWindow.vue | 111 ++++++++++++------ .../views/purchasing/TicketsOrderingView.vue | 17 +++ 7 files changed, 162 insertions(+), 62 deletions(-) create mode 100644 src/server/backend/db/data/booked.json diff --git a/src/server/backend/api/getHandler.js b/src/server/backend/api/getHandler.js index b652907..85689c1 100644 --- a/src/server/backend/api/getHandler.js +++ b/src/server/backend/api/getHandler.js @@ -14,18 +14,32 @@ class GETHandler { } - handleCall ( call, query ) { + handleCall ( call, query, session ) { return new Promise( ( resolve, reject ) => { if ( call === 'getSeatplan' ) { db.getJSONDataSimple( 'seatplan', query.location ).then( data => { if ( Object.keys( data ).length > 0 ) { resolve( data[ 'save' ] ); } else { - reject( 'No data found for this location' ); + reject( { 'code': 404, 'message': 'No data found for this location' } ); } } ).catch( error => { - reject( error ); + reject( { 'code': 500, 'message': error } ); } ); + } else if ( call === 'getReservedSeats' ) { + if ( query.event ) { + db.getJSONDataSimple( 'booked', query.event ).then( data => { + db.getDataSimple( 'temp', 'user_id', session.id ).then( dat => { + console.log( dat ); + resolve( { 'booked': data ?? {}, 'user': dat[ 0 ] ? JSON.parse( dat[ 0 ].data )[ query.event ] ?? {} : {} } ); + } ); + } ).catch( error => { + console.error( error ); + reject( { 'code': 500, 'message': error } ); + } ); + } else { + reject( { 'code': 400, 'message': 'Bad request, missing event query' } ); + } } } ); } diff --git a/src/server/backend/api/postHandler.js b/src/server/backend/api/postHandler.js index 917e685..d8bf2d3 100644 --- a/src/server/backend/api/postHandler.js +++ b/src/server/backend/api/postHandler.js @@ -11,12 +11,12 @@ const db = require( '../db/db.js' ); class POSTHandler { constructor () { - + this.allSelectedSeats = { 'TestEvent2': [ 'secAr1s1' ] }; } - handleCall ( call, data, lang, session ) { + // Add lang in the future + handleCall ( call, data, session ) { return new Promise( ( resolve, reject ) => { - console.log( lang ); if ( call === 'reserveTicket' ) { db.getDataSimple( 'temp', 'user_id', session.id ).then( dat => { let transmit = {}; @@ -25,14 +25,22 @@ class POSTHandler { } else { transmit[ data.eventID ] = {}; } - transmit[ data.eventID ][ data.id ] = data; - db.writeDataSimple( 'temp', 'user_id', session.id, { 'user_id': session.id, 'data': JSON.stringify( transmit ), 'timestamp': new Date().toString() } ).then( ret => { - resolve( ret ); - } ).catch( error => { - reject( error ); - } ); + if ( !this.allSelectedSeats[ data.eventID ] ) { + this.allSelectedSeats[ data.eventID ] = []; + } + if ( this.allSelectedSeats[ data.eventID ].includes( data.id ) ) { + reject( { 'code': 409, 'message': 'Seat already selected' } ); + } else { + this.allSelectedSeats[ data.eventID ].push( data.id ); + transmit[ data.eventID ][ data.id ] = data; + db.writeDataSimple( 'temp', 'user_id', session.id, { 'user_id': session.id, 'data': JSON.stringify( transmit ), 'timestamp': new Date().toString() } ).then( () => { + resolve( 'ok' ); + } ).catch( error => { + reject( { 'code': 500, 'message': error } ); + } ); + } } ).catch( error => { - reject( error ); + reject( { 'code': 500, 'message': error } ); } ); } else if ( call === 'deselectTicket' ) { db.getDataSimple( 'temp', 'user_id', session.id ).then( dat => { @@ -41,25 +49,29 @@ class POSTHandler { if ( transmit[ data.eventID ][ data.id ] ) { delete transmit[ data.eventID ][ data.id ]; } else { - reject( 'ERR_DATA_NONE_EXISTENT' ); + reject( { 'code': 404, 'message': 'ERR_DATA_NOT_FOUND' } ); } if ( Object.keys( transmit[ data.eventID ] ).length < 1 ) { delete transmit[ data.eventID ]; } } else { - reject( 'ERR_DATA_NONE_EXISTENT' ); + reject( { 'code': 404, 'message': 'ERR_DATA_NOT_FOUND' } ); } - db.writeDataSimple( 'temp', 'user_id', session.id, { 'user_id': session.id, 'data': JSON.stringify( transmit ) } ).then( ret => { - resolve( ret ); + db.writeDataSimple( 'temp', 'user_id', session.id, { 'user_id': session.id, 'data': JSON.stringify( transmit ) } ).then( () => { + resolve( 'ok' ); } ).catch( error => { - reject( error ); + reject( { 'code': 500, 'message': error } ); } ); } ).catch( error => { - reject( error ); + reject( { 'code': 500, 'message': error } ); } ); } } ); } + + getReservedSeats () { + return this.allSelectedSeats; + } } module.exports = POSTHandler; \ No newline at end of file diff --git a/src/server/backend/db/data/booked.json b/src/server/backend/db/data/booked.json new file mode 100644 index 0000000..e69de29 diff --git a/src/server/backend/userAPIRoutes.js b/src/server/backend/userAPIRoutes.js index 9dc87fa..9a5fa41 100644 --- a/src/server/backend/userAPIRoutes.js +++ b/src/server/backend/userAPIRoutes.js @@ -18,18 +18,25 @@ module.exports = ( app ) => { // Add specific routes here to have them be checked first to not get general handling app.get( '/getAPI/:call', ( req, res ) => { - getHandler.handleCall( req.params.call, req.query ).then( data => { - res.send( data ); + getHandler.handleCall( req.params.call, req.query, req.session ).then( data => { + if ( req.params.call === 'getReservedSeats' ) { + let dat = data; + dat[ 'reserved' ] = postHandler.getReservedSeats(); + res.send( dat ); + } else { + res.send( data ); + } } ).catch( error => { - res.status( 500 ).send( error ); + res.status( error.code ).send( error.message ); } ); } ); app.post( '/API/:call', ( req, res ) => { - postHandler.handleCall( req.params.call, req.body, req.query.lang, req.session ).then( data => { + // add lang in the future + postHandler.handleCall( req.params.call, req.body, req.session ).then( data => { res.send( data ); } ).catch( error => { - res.status( 500 ).send( error ); + res.status( error.code ).send( error.message ); } ); } ); diff --git a/src/webapp/main/src/components/seatplan/userApp/seatplanComponents/standing.vue b/src/webapp/main/src/components/seatplan/userApp/seatplanComponents/standing.vue index 6d1c332..f1d5025 100644 --- a/src/webapp/main/src/components/seatplan/userApp/seatplanComponents/standing.vue +++ b/src/webapp/main/src/components/seatplan/userApp/seatplanComponents/standing.vue @@ -71,10 +71,14 @@ export default { type: String, "default": "rectangular", }, + color: { + type: Object, + "default": { 'fg': '#FFFFFF', 'bg': '#999999' } + } }, data() { return { - style: 'border-style: none none solid none', + style: 'border-style: none none solid none;', circularStyle: 'top: 0; left 100%;', trapezoidStyle: 'rotate: 45deg', } @@ -82,18 +86,19 @@ export default { methods: { updateOrigin () { if ( this.origin === 1 ) { - this.style = 'border-style: none none solid none'; + this.style = 'border-style: none none solid none;'; this.circularStyle = 'top: 0; right: 100%;'; } else if ( this.origin === 2 ) { - this.style = 'border-style: none solid none none'; + this.style = 'border-style: none solid none none;'; this.circularStyle = 'top: 0; right: 0;'; } else if ( this.origin === 3 ) { - this.style = 'border-style: solid none none none'; + this.style = 'border-style: solid none none none;'; this.circularStyle = 'top: -100%; right: 0;'; } else if ( this.origin === 4 ) { - this.style = 'border-style: none none none solid'; + this.style = 'border-style: none none none solid;'; this.circularStyle = 'top: -100%; right: 100%;'; } + this.style += ` background-color: ${this.color.bg}; color: ${this.color.fg}`; }, }, watch: { diff --git a/src/webapp/main/src/components/seatplan/userApp/userWindow.vue b/src/webapp/main/src/components/seatplan/userApp/userWindow.vue index d18b1ef..e50c477 100644 --- a/src/webapp/main/src/components/seatplan/userApp/userWindow.vue +++ b/src/webapp/main/src/components/seatplan/userApp/userWindow.vue @@ -43,7 +43,7 @@ - + @@ -154,31 +154,72 @@ this.draggables[ element ][ 'data' ] = { 'sector': this.draggables[ element ][ 'sector' ], 'unavailableSeats': {}, 'categoryInfo': { 'pricing': categoryDetails[ this.draggables[ element ][ 'category' ] ] } }; } - if ( this.cart[ this.event.name ] ) { - let tickets = this.cart[ this.event.name ][ 'tickets' ]; - for ( let ticket in tickets ) { - this.draggables[ tickets[ ticket ].comp ][ 'data' ][ 'unavailableSeats' ][ ticket ] = 'sel'; - } - } - - // TODO: Check if all seats are available - let allSeatsAvailable = true; - // Method: Server sends all user selected seats + all selected seats. If seat is in both - // then selected, if just in all selected, taken, else available. - - if ( !allSeatsAvailable ) { - setTimeout( () => { - self.$refs.popups.openPopup( 'We are sorry to tell you that since the last time the seat plan was refreshed, one or more of the seats you have selected has/have been taken.', {}, 'string' ); - }, 500 ); - } - + this.seatChecks(); // TODO: Optimise for odd screen sizes and aspect ratios and fucking webkit - sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) ); - + // TODO: Trim scroll box to about 200px more than seatplan size window.addEventListener( 'visibilitychange', ( e ) => { this.seatPlanInit(); }, 1 ); }, + seatChecks () { + // TODO: Check if all seats are available + // Method: Server sends all user selected seats + all selected seats. If seat is in both + // then selected, if just in all selected, taken, else available. + let self = this; + let allSeatsAvailable = true; + + fetch( localStorage.getItem( 'url' ) + '/getAPI/getReservedSeats?event=' + this.event.name ).then( res => { + if ( res.status === 200 ) { + res.json().then( data => { + let tickets = {}; + if ( this.cart[ this.event.name ] ) { + tickets = this.cart[ this.event.name ][ 'tickets' ]; + } + if ( Object.keys( data.booked ).length > 0 && Object.keys( data.reserved ).length > 0 ) { + for ( let ticket in data.booked ) { + this.draggables[ data.booked[ ticket ].component ][ 'data' ][ 'unavailableSeats' ][ ticket ] = 'nav'; + } + for ( let ticket in data.reserved ) { + this.draggables[ data.reserved[ ticket ] ][ 'data' ][ 'unavailableSeats' ][ ticket ] = 'nav'; + } + } + + if ( data.user ) { + for ( let element in tickets ) { + if ( !data.user[ element ] ) { + allSeatsAvailable = false; + if ( Object.keys( this.cart[ this.event.name ][ 'tickets' ] ).length > 1 ) { + delete this.cart[ this.event.name ][ 'tickets' ][ element ]; + } else { + delete this.cart[ this.event.name ]; + } + } + } + } else { + delete this.cart[ this.event.name ]; + allSeatsAvailable = false; + } + + for ( let ticket in tickets ) { + this.draggables[ tickets[ ticket ].comp ][ 'data' ][ 'unavailableSeats' ][ ticket ] = 'sel'; + } + + if ( !allSeatsAvailable ) { + setTimeout( () => { + self.$refs.popups.openPopup( 'We are sorry to tell you that since the last time the seat plan was refreshed, one or more of the seats you have selected has/have been taken.', {}, 'string' ); + }, 500 ); + localStorage.setItem( 'cart', JSON.stringify( this.cart ) ); + } + + sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) ); + + // this.loadSeatplan(); + } ); + } else { + console.error( 'unable to load' ); + } + } ); + }, eventHandler ( e ) { if ( this.prevSize.h != window.innerHeight || this.prevSize.w != window.innerWidth ) { this.prevSize = { 'h': window.innerHeight, 'w': window.innerWidth }; @@ -314,10 +355,7 @@ localStorage.setItem( 'cart', JSON.stringify( this.cart ) ); }, reserveTicket ( option ) { - if ( option.status == 'ok' ) { - this.$refs[ 'component' + this.selectedSeat.componentID ][ 0 ].validateSeatSelection( this.selectedSeat, option.data ); - this.cartHandling( 'select', option.data ); - + if ( option.status == 'ok' && option.data ) { // Make call to server to reserve ticket to have server also keep track of reserved tickets const options = { method: 'post', @@ -328,9 +366,14 @@ } }; fetch( localStorage.getItem( 'url' ) + '/API/reserveTicket', options ).then( res => { - res.text().then( text => { - console.log( text ); - } ); + if ( res.status === 200 ) { + this.$refs[ 'component' + this.selectedSeat.componentID ][ 0 ].validateSeatSelection( this.selectedSeat, option.data ); + this.cartHandling( 'select', option.data ); + } else if ( res.status === 409 ) { + setTimeout( () => { + this.$refs.popups.openPopup( 'Unfortunately, the seat you just tried to select was reserved by somebody else since the last time the seat plan was refreshed. Please select another one. We are sorry for the inconvenience.', {}, 'string' ); + }, 300 ); + } } ); } }, @@ -394,7 +437,7 @@ } } } - + // TODO: Make call to server to reserve ticket if ( Object.keys( this.cart[ this.event.name ][ 'tickets' ] ).length < 1 ) { delete this.cart[ this.event.name ]; } @@ -416,8 +459,9 @@