From 127bd5b630785c2f8dcd991accac64a01247093d Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Wed, 2 Aug 2023 17:09:39 +0200 Subject: [PATCH] stripe almost working --- src/server/app.js | 3 +- src/server/backend/db/data/events.json | 1 + src/server/backend/db/mysqldb.js | 2 +- src/server/backend/payments/paymentHandler.js | 14 ++++ src/server/backend/payments/paymentRoutes.js | 8 +++ .../plugins/payments/stripe/stripeRoutes.js | 67 ++++++++++++++----- src/webapp/main/notes.md | 2 + src/webapp/main/src/components/noseatplan.vue | 36 +++++----- .../seatplan/userApp/userWindow.vue | 63 ++++++++--------- .../main/src/views/purchasing/CartView.vue | 2 +- .../src/views/purchasing/PurchaseView.vue | 52 ++++++++++++-- 11 files changed, 174 insertions(+), 76 deletions(-) create mode 100644 src/server/backend/payments/paymentHandler.js create mode 100644 src/server/backend/payments/paymentRoutes.js diff --git a/src/server/app.js b/src/server/app.js index 620f562..d403493 100644 --- a/src/server/app.js +++ b/src/server/app.js @@ -91,7 +91,8 @@ if ( settings.init ) { } console.log( '[ Server ] loading plugins' ); -// pluginManager.load( app, settings ); +// TODO: load dynamically +require( './backend/plugins/payments/stripe/stripeRoutes.js' )( app, settings ); // setup routes app.use( ( request, response ) => { response.sendFile( file ); diff --git a/src/server/backend/db/data/events.json b/src/server/backend/db/data/events.json index e69de29..7e0b892 100644 --- a/src/server/backend/db/data/events.json +++ b/src/server/backend/db/data/events.json @@ -0,0 +1 @@ +{ "test2": { "name": "TestEvent2", "location": "TestLocation2", "eventID": "test2", "date": "2023-07-15", "currency": "CHF", "categories": { "1": { "price": { "1":25, "2":35 }, "bg": "black", "fg": "white", "name": "Category 1" }, "2": { "price": { "1":15, "2":20 }, "bg": "green", "fg": "white", "name": "Category 2" } }, "ageGroups": { "1":{ "id": 1, "name":"Child", "age":"0 - 15.99" }, "2":{ "id": 2, "name": "Adult" } }, "maxTickets": 2 } } \ No newline at end of file diff --git a/src/server/backend/db/mysqldb.js b/src/server/backend/db/mysqldb.js index 1e4a987..85c717f 100644 --- a/src/server/backend/db/mysqldb.js +++ b/src/server/backend/db/mysqldb.js @@ -55,7 +55,7 @@ class SQLDB { if ( error ) throw error; if ( results[ 0 ][ '@@default_storage_engine' ] !== 'InnoDB' ) return 'DB HAS TO USE InnoDB!'; } ); - this.sqlConnection.query( 'CREATE TABLE libreevent_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, pass TEXT, street TEXT, house_number TINYTEXT, country TEXT, phone TEXT, name TEXT, first_name TEXT, two_fa TINYTEXT, PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', ( error ) => { + this.sqlConnection.query( 'CREATE TABLE libreevent_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, pass TEXT, name TEXT, first_name TEXT, two_fa TINYTEXT, user_data VARCHAR( 60000 ), PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', ( error ) => { if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error; this.sqlConnection.query( 'CREATE TABLE libreevent_orders ( order_id INT ( 10 ) NOT NULL AUTO_INCREMENT, account_id INT ( 10 ) NOT NULL, seats VARCHAR( 60000 ), PRIMARY KEY ( order_id ), FOREIGN KEY ( account_id ) REFERENCES libreevent_users( account_id ) ) ENGINE=INNODB;', ( error ) => { if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error; diff --git a/src/server/backend/payments/paymentHandler.js b/src/server/backend/payments/paymentHandler.js new file mode 100644 index 0000000..361068b --- /dev/null +++ b/src/server/backend/payments/paymentHandler.js @@ -0,0 +1,14 @@ +/* +* libreevent - successHandler.js +* +* Created by Janis Hutz 08/02/2023, Licensed under the GPL V3 License +* https://janishutz.com, development@janishutz.com +* +* +*/ + +class PaymentHandler { + constructor () {} +} + +module.exports = PaymentHandler; \ No newline at end of file diff --git a/src/server/backend/payments/paymentRoutes.js b/src/server/backend/payments/paymentRoutes.js new file mode 100644 index 0000000..0f66a76 --- /dev/null +++ b/src/server/backend/payments/paymentRoutes.js @@ -0,0 +1,8 @@ +/* +* libreevent - paymentRoutes.js +* +* Created by Janis Hutz 08/02/2023, Licensed under the GPL V3 License +* https://janishutz.com, development@janishutz.com +* +* +*/ \ No newline at end of file diff --git a/src/server/backend/plugins/payments/stripe/stripeRoutes.js b/src/server/backend/plugins/payments/stripe/stripeRoutes.js index 47c2218..df931c2 100644 --- a/src/server/backend/plugins/payments/stripe/stripeRoutes.js +++ b/src/server/backend/plugins/payments/stripe/stripeRoutes.js @@ -9,10 +9,16 @@ const fs = require( 'fs' ); const path = require( 'path' ); -const stripe = require( 'stripe' )( fs.readFileSync( path.join( __dirname + '/../../../../config/payments.config.secret.json' ) )[ 'stripe' ][ 'APIKey' ] ); +const db = require( '../../../db/db.js' ); +const stripConfig = JSON.parse( fs.readFileSync( path.join( __dirname + '/../../../../config/payments.config.secret.json' ) ) )[ 'stripe' ]; +const stripe = require( 'stripe' )( stripConfig[ 'APIKey' ] ); + +const endpointSecret = stripConfig[ 'endpointSecret' ]; + +// TODO: Remove all selected tickets if timestamp more than user defined amount ago module.exports = ( app, settings ) => { - app.post( '/payments/prepare', async ( req, res ) => { + app.post( '/payments/prepare', ( req, res ) => { let purchase = { 'line_items': [], 'mode': 'payment', @@ -22,20 +28,36 @@ module.exports = ( app, settings ) => { 'customer_email': req.body.mail }; - for ( let item in req.body.products ) { - purchase[ 'line_items' ].push( { - 'price_data': { - 'currency': req.body.currency, - 'product_data': { - 'name': req.body.products[ item ].name, - }, - 'unit_amount': req.body.products[ item ].price - }, - 'quantity': req.body.products[ item ].count ?? 1, - } ); - } - const session = await stripe.checkout.sessions.create( purchase ); - res.send( session.url ); + db.getDataSimple( 'temp', 'user_id', req.session.id ).then( dat => { + if ( dat[ 0 ] ) { + db.getJSONData( 'events' ).then( events => { + let data = JSON.parse( dat[ 0 ].data ); + ( async () => { + for ( let event in data ) { + for ( let item in data[ event ] ) { + purchase[ 'line_items' ].push( { + 'price_data': { + 'product_data': { + 'name': data[ event ][ item ].name, + }, + 'currency': events[ event ].currency, + 'unit_amount': Math.round( parseFloat( events[ event ][ 'categories' ][ data[ event ][ item ].category ].price[ data[ event ][ item ][ 'ticketOption' ] ] ) * 100 ), + }, + 'quantity': data[ event ][ item ].count ?? 1, + } ); + } + } + const session = await stripe.checkout.sessions.create( purchase ); + res.send( session.url ); + } )(); + } ); + } else { + res.status( 400 ).send( 'ERR_UID_NOT_FOUND' ); + } + } ).catch( error => { + console.error( '[ STRIPE ] DB ERROR: ' + error ); + res.status( 500 ).send( 'ERR_DB' ); + } ); } ); app.get( '/payments/status', ( request, response ) => { @@ -50,6 +72,17 @@ module.exports = ( app, settings ) => { } ); app.post( '/payments/webhook', ( req, res ) => { - // The webhook stripe sends data to + const payload = req.body; + const sig = req.headers[ 'stripe-signature' ]; + + let event; + + try { + event = stripe.webhooks.constructEvent( payload, sig, endpointSecret ); + } catch ( err ) { + return res.status( 400 ).send( 'Webhook Error' ); + } + + res.status( 200 ).end(); } ); }; \ No newline at end of file diff --git a/src/webapp/main/notes.md b/src/webapp/main/notes.md index 808cc40..356d677 100644 --- a/src/webapp/main/notes.md +++ b/src/webapp/main/notes.md @@ -3,6 +3,8 @@ - make pricing groups changeable in UI (event categories) +- create function that parses DB every 15 minutes and clears out junk + - Create password changing endpoint (to reset forgotten pwd) - Add Admin profile (page to change account settings per person like changing pwd) diff --git a/src/webapp/main/src/components/noseatplan.vue b/src/webapp/main/src/components/noseatplan.vue index ffbb499..92788c6 100644 --- a/src/webapp/main/src/components/noseatplan.vue +++ b/src/webapp/main/src/components/noseatplan.vue @@ -48,12 +48,12 @@ export default { methods: { selectTicket( id, option ) { let totalTicketsPerID = 0; - if ( this.cart[ this.event.name ] ) { - if ( this.cart[ this.event.name ][ 'tickets' ][ id + '_' + option ] ) { - const tickets = this.cart[ this.event.name ][ 'tickets' ]; + if ( this.cart[ this.event.eventID ] ) { + if ( this.cart[ this.event.eventID ][ 'tickets' ][ id + '_' + option ] ) { + const tickets = this.cart[ this.event.eventID ][ 'tickets' ]; for ( let ticket in tickets ) { if ( tickets[ ticket ][ 'id' ].split( '_' )[ 0 ] === id ) { - totalTicketsPerID += this.cart[ this.event.name ][ 'tickets' ][ tickets[ ticket ][ 'id' ] ][ 'count' ]; + totalTicketsPerID += this.cart[ this.event.eventID ][ 'tickets' ][ tickets[ ticket ][ 'id' ] ][ 'count' ]; } } if ( totalTicketsPerID < this.tickets[ id ].free ) { @@ -69,33 +69,33 @@ export default { }, cartHandling ( operation, data, option ) { if ( operation === 'select' ) { - if ( this.cart[ this.event.name ] ) { - if ( this.cart[ this.event.name ][ 'tickets' ][ data.id + '_' + option ] ) { - this.cart[ this.event.name ][ 'tickets' ][ data.id + '_' + option ][ 'count' ] += 1; + if ( this.cart[ this.event.eventID ] ) { + if ( this.cart[ this.event.eventID ][ 'tickets' ][ data.id + '_' + option ] ) { + this.cart[ this.event.eventID ][ 'tickets' ][ data.id + '_' + option ][ 'count' ] += 1; } else { - this.cart[ this.event.name ][ 'tickets' ][ data.id + '_' + option ] = { 'displayName': data.name + ' (' + this.event.ageGroups[ option ].name + ')', 'price': this.event.categories[ data.category ].price[ option ], 'id': data.id + '_' + option, 'count': 1 }; + this.cart[ this.event.eventID ][ 'tickets' ][ data.id + '_' + option ] = { 'displayName': data.name + ' (' + this.event.ageGroups[ option ].name + ')', 'price': this.event.categories[ data.category ].price[ option ], 'id': data.id + '_' + option, 'count': 1 }; } } else { - this.cart[ this.event.name ] = { 'displayName': this.event.name, 'tickets': {} }; - this.cart[ this.event.name ][ 'tickets' ][ data.id + '_' + option ] = { 'displayName': data.name + ' (' + this.event.ageGroups[ option ].name + ')', 'price': this.event.categories[ data.category ].price[ option ], 'id': data.id + '_' + option, 'count': 1 }; + this.cart[ this.event.eventID ] = { 'displayName': this.event.name, 'tickets': {} }; + this.cart[ this.event.eventID ][ 'tickets' ][ data.id + '_' + option ] = { 'displayName': data.name + ' (' + this.event.ageGroups[ option ].name + ')', 'price': this.event.categories[ data.category ].price[ option ], 'id': data.id + '_' + option, 'count': 1 }; } } else if ( operation === 'deselect' ) { - if ( this.cart[ this.event.name ][ 'tickets' ][ data + '_' + option ][ 'count' ] === 1 ) { - delete this.cart[ this.event.name ][ 'tickets' ][ data + '_' + option ]; + if ( this.cart[ this.event.eventID ][ 'tickets' ][ data + '_' + option ][ 'count' ] === 1 ) { + delete this.cart[ this.event.eventID ][ 'tickets' ][ data + '_' + option ]; } else { - this.cart[ this.event.name ][ 'tickets' ][ data + '_' + option ][ 'count' ] -= 1; + this.cart[ this.event.eventID ][ 'tickets' ][ data + '_' + option ][ 'count' ] -= 1; } - if ( Object.keys( this.cart[ this.event.name ][ 'tickets' ] ).length < 1 ) { - delete this.cart[ this.event.name ]; + if ( Object.keys( this.cart[ this.event.eventID ][ 'tickets' ] ).length < 1 ) { + delete this.cart[ this.event.eventID ]; } } this.$refs.cart.calculateTotal(); localStorage.setItem( 'cart', JSON.stringify( this.cart ) ); }, deselectTicket( id, option ) { - if ( this.cart[ this.event.name ] ) { - if ( this.cart[ this.event.name ][ 'tickets' ][ id + '_' + option ] ) { - if ( this.cart[ this.event.name ][ 'tickets' ][ id + '_' + option ][ 'count' ] > 0 ) { + if ( this.cart[ this.event.eventID ] ) { + if ( this.cart[ this.event.eventID ][ 'tickets' ][ id + '_' + option ] ) { + if ( this.cart[ this.event.eventID ][ 'tickets' ][ id + '_' + option ][ 'count' ] > 0 ) { this.cartHandling( 'deselect', id, option ); } } diff --git a/src/webapp/main/src/components/seatplan/userApp/userWindow.vue b/src/webapp/main/src/components/seatplan/userApp/userWindow.vue index 9e8b607..e1d50fd 100644 --- a/src/webapp/main/src/components/seatplan/userApp/userWindow.vue +++ b/src/webapp/main/src/components/seatplan/userApp/userWindow.vue @@ -79,7 +79,7 @@ data() { return { draggables: { 1: { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': 1, 'origin': 1, 'shape':'rectangular', 'type': 'seat', 'startingRow': 1, 'seatCountingStartingPoint': 1, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' }, 'ticketCount': 1, 'category': 1 } }, - event: { 'name': 'TestEvent2', 'location': 'TestLocation2', 'date': '2023-07-15', 'currency': 'CHF', 'categories': { '1': { 'price': { '1':25, '2':35 }, 'bg': 'black', 'fg': 'white', 'name': 'Category 1' }, '2': { 'price': { '1':15, '2':20 }, 'bg': 'green', 'fg': 'white', 'name': 'Category 2' } }, 'ageGroups': { '1':{ 'id': 1, 'name':'Child', 'age':'0 - 15.99' }, '2':{ 'id': 2, 'name': 'Adult' } }, 'maxTickets': 2 }, + event: { 'name': 'TestEvent2', 'location': 'TestLocation2', 'eventID': 'test2', 'date': '2023-07-15', 'currency': 'CHF', 'categories': { '1': { 'price': { '1':25, '2':35 }, 'bg': 'black', 'fg': 'white', 'name': 'Category 1' }, '2': { 'price': { '1':15, '2':20 }, 'bg': 'green', 'fg': 'white', 'name': 'Category 2' } }, 'ageGroups': { '1':{ 'id': 1, 'name':'Child', 'age':'0 - 15.99' }, '2':{ 'id': 2, 'name': 'Adult' } }, 'maxTickets': 2 }, available: { 'redo': false, 'undo': false }, scaleFactor: 1, sizePoll: null, @@ -167,7 +167,7 @@ let self = this; let allSeatsAvailable = true; - fetch( localStorage.getItem( 'url' ) + '/getAPI/getReservedSeats?event=' + this.event.name ).then( res => { + fetch( localStorage.getItem( 'url' ) + '/getAPI/getReservedSeats?event=' + this.event.eventID ).then( res => { if ( res.status === 200 ) { let unavailableSeats = {}; res.json().then( data => { @@ -194,23 +194,23 @@ } let tickets = {}; - if ( this.cart[ this.event.name ] ) { - tickets = this.cart[ this.event.name ][ 'tickets' ]; + if ( this.cart[ this.event.eventID ] ) { + tickets = this.cart[ this.event.eventID ][ 'tickets' ]; } 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 ]; + if ( Object.keys( this.cart[ this.event.eventID ][ 'tickets' ] ).length > 1 ) { + delete this.cart[ this.event.eventID ][ 'tickets' ][ element ]; } else { - delete this.cart[ this.event.name ]; + delete this.cart[ this.event.eventID ]; } } } } else { - delete this.cart[ this.event.name ]; + delete this.cart[ this.event.eventID ]; allSeatsAvailable = false; } @@ -299,8 +299,8 @@ this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) ); } - if ( this.cart[ this.event.name ] ) { - let tickets = this.cart[ this.event.name ][ 'tickets' ]; + if ( this.cart[ this.event.eventID ] ) { + let tickets = this.cart[ this.event.eventID ][ 'tickets' ]; for ( let seat in tickets ) { if ( !unavailableSeats[ data.user[ seat ].component ] ) { unavailableSeats[ data.reserved[ seat ].component ] = {}; @@ -350,17 +350,17 @@ }, cartHandling ( operation, data ) { if ( operation === 'select' ) { - if ( this.cart[ this.event.name ] ) { - this.cart[ this.event.name ][ 'tickets' ][ this.selectedSeat.id ] = { 'displayName': this.selectedSeat.displayName, 'price': this.selectedSeat.option[ data ].price, 'id': this.selectedSeat.id, 'option': data, 'comp': this.selectedSeat.componentID }; + if ( this.cart[ this.event.eventID ] ) { + this.cart[ this.event.eventID ][ 'tickets' ][ this.selectedSeat.id ] = { 'displayName': this.selectedSeat.displayName, 'price': this.selectedSeat.option[ data ].price, 'id': this.selectedSeat.id, 'option': data, 'comp': this.selectedSeat.componentID }; } else { - this.cart[ this.event.name ] = { 'displayName': this.event.name, 'tickets': {} }; - this.cart[ this.event.name ][ 'tickets' ][ this.selectedSeat.id ] = { 'displayName': this.selectedSeat.displayName, 'price': this.selectedSeat.option[ data ].price, 'id': this.selectedSeat.id, 'option': data, 'comp': this.selectedSeat.componentID }; + this.cart[ this.event.eventID ] = { 'displayName': this.event.name, 'tickets': {}, 'eventID': this.event.eventID }; + this.cart[ this.event.eventID ][ 'tickets' ][ this.selectedSeat.id ] = { 'displayName': this.selectedSeat.displayName, 'price': this.selectedSeat.option[ data ].price, 'id': this.selectedSeat.id, 'option': data, 'comp': this.selectedSeat.componentID }; } } else if ( operation === 'deselect' ) { - if ( Object.keys( this.cart[ this.event.name ][ 'tickets' ] ).length > 1 ) { - delete this.cart[ this.event.name ][ 'tickets' ][ this.selectedSeat.id ]; + if ( Object.keys( this.cart[ this.event.eventID ][ 'tickets' ] ).length > 1 ) { + delete this.cart[ this.event.eventID ][ 'tickets' ][ this.selectedSeat.id ]; } else { - delete this.cart[ this.event.name ]; + delete this.cart[ this.event.eventID ]; } } this.$refs.cart.calculateTotal(); @@ -371,7 +371,7 @@ // Make call to server to reserve ticket to have server also keep track of reserved tickets const options = { method: 'post', - body: JSON.stringify( { 'id': this.selectedSeat[ 'id' ], 'component': this.selectedSeat[ 'componentID' ], 'ticketOption': option.data, 'eventID': this.event.name } ), + body: JSON.stringify( { 'id': this.selectedSeat[ 'id' ], 'component': this.selectedSeat[ 'componentID' ], 'ticketOption': option.data, 'eventID': this.event.eventID, 'category': this.draggables[ this.selectedSeat[ 'componentID' ] ].category, 'name': this.selectedSeat.displayName } ), headers: { 'Content-Type': 'application/json', 'charset': 'utf-8' @@ -400,7 +400,7 @@ // Make call to server to deselect ticket const options = { method: 'post', - body: JSON.stringify( { 'id': seat[ 'id' ], 'eventID': this.event.name } ), + body: JSON.stringify( { 'id': seat[ 'id' ], 'eventID': this.event.eventID } ), headers: { 'Content-Type': 'application/json', 'charset': 'utf-8' @@ -416,10 +416,10 @@ const d = this.draggables[ id ]; const evG = this.event.ageGroups; let count = {}; - if ( this.cart[ this.event.name ] ) { + if ( this.cart[ this.event.eventID ] ) { for ( let ageGroup in evG ) { - if ( this.cart[ this.event.name ][ 'tickets' ][ 'ticket' + id + '_' + ageGroup ] ) { - count[ ageGroup ] = this.cart[ this.event.name ][ 'tickets' ][ 'ticket' + id + '_' + ageGroup ].count; + if ( this.cart[ this.event.eventID ][ 'tickets' ][ 'ticket' + id + '_' + ageGroup ] ) { + count[ ageGroup ] = this.cart[ this.event.eventID ][ 'tickets' ][ 'ticket' + id + '_' + ageGroup ].count; } else { count[ ageGroup ] = 0; } @@ -440,16 +440,17 @@ }, 'tickets' ); }, standingTicketHandling ( data ) { - if ( !this.cart[ this.event.name ] ) { - this.cart[ this.event.name ] = { 'displayName': this.event.name, 'tickets': {} }; + if ( !this.cart[ this.event.eventID ] ) { + this.cart[ this.event.eventID ] = { 'displayName': this.event.name, 'tickets': {}, 'eventID': this.event.eventID }; } for ( let group in data.data ) { - if ( !this.cart[ this.event.name ][ 'tickets' ][ 'ticket' + data.component + '_' + group ] ) { + if ( !this.cart[ this.event.eventID ][ 'tickets' ][ 'ticket' + data.component + '_' + group ] ) { if ( data.data[ group ] > 0 ) { const options = { method: 'post', - body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'component': data.component, 'ticketOption': '', 'eventID': this.event.name, 'count': data.data[ group ] } ), + // TODO: Add correct name here as well once it is working at all + body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'component': data.component, 'ticketOption': '', 'eventID': this.event.eventID, 'count': data.data[ group ], 'category': this.draggables[ data.component ].category, 'name': 'Ticket ' } ), headers: { 'Content-Type': 'application/json', 'charset': 'utf-8' @@ -457,24 +458,24 @@ }; fetch( localStorage.getItem( 'url' ) + '/API/reserveTicket', options ).then( res => { if ( res.status === 200 ) { - this.cart[ this.event.name ][ 'tickets' ][ 'ticket' + data.component + '_' + group ] = { 'displayName': 'Ticket ' + data.component + ' (' + this.event.ageGroups[ group ].name + ')', 'price': this.event.categories[ this.draggables[ data.component ].category ].price[ group ], 'id': 'ticket' + data.component + '_' + group, 'count': data.data[ group ], 'comp': data.component }; + this.cart[ this.event.eventID ][ 'tickets' ][ 'ticket' + data.component + '_' + group ] = { 'displayName': 'Ticket ' + data.component + ' (' + this.event.ageGroups[ group ].name + ')', 'price': this.event.categories[ this.draggables[ data.component ].category ].price[ group ], 'id': 'ticket' + data.component + '_' + group, 'count': data.data[ group ], 'comp': data.component }; } 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 ); } - if ( Object.keys( this.cart[ this.event.name ][ 'tickets' ] ).length < 1 ) { - delete this.cart[ this.event.name ]; + if ( Object.keys( this.cart[ this.event.eventID ][ 'tickets' ] ).length < 1 ) { + delete this.cart[ this.event.eventID ]; } this.$refs.cart.calculateTotal(); localStorage.setItem( 'cart', JSON.stringify( this.cart ) ); } ); } else { - delete this.cart[ this.event.name ][ 'tickets' ][ 'ticket' + data.component + '_' + group ]; + delete this.cart[ this.event.eventID ][ 'tickets' ][ 'ticket' + data.component + '_' + group ]; const options = { method: 'post', - body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'eventID': this.event.name } ), + body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'eventID': this.event.eventID } ), headers: { 'Content-Type': 'application/json', 'charset': 'utf-8' diff --git a/src/webapp/main/src/views/purchasing/CartView.vue b/src/webapp/main/src/views/purchasing/CartView.vue index f0d5a5f..ac9a122 100644 --- a/src/webapp/main/src/views/purchasing/CartView.vue +++ b/src/webapp/main/src/views/purchasing/CartView.vue @@ -20,7 +20,7 @@

{{ ticket.count }}x
{{ ticket.displayName }}:

- {{ backend.currency }} {{ ticket.price }} delete + {{ backend.currency }} {{ ticket.price }} delete diff --git a/src/webapp/main/src/views/purchasing/PurchaseView.vue b/src/webapp/main/src/views/purchasing/PurchaseView.vue index 62898bf..199108f 100644 --- a/src/webapp/main/src/views/purchasing/PurchaseView.vue +++ b/src/webapp/main/src/views/purchasing/PurchaseView.vue @@ -10,7 +10,7 @@ @@ -188,6 +194,19 @@ margin: 0; padding: 0; } + + .empty-cart-wrapper { + width: 100%; + height: 70vh; + display: flex; + justify-content: center; + align-items: center; + } + + .empty-cart { + display: block; + font-size: 20rem; + }