mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 05:14:23 +00:00
seatplan saving and loading for admin & user
This commit is contained in:
43
src/server/admin/adminAPIRoutes.js
Normal file
43
src/server/admin/adminAPIRoutes.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* libreevent - adminAPIRoutes.js
|
||||
*
|
||||
* Created by Janis Hutz 07/20/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const posth = require( './api/postHandler.js' );
|
||||
const geth = require( './api/getHandler.js' );
|
||||
const postHandler = new posth();
|
||||
const getHandler = new geth();
|
||||
const path = require( 'path' );
|
||||
|
||||
// settings is missing in arguments which shouldn't pose any problem
|
||||
module.exports = ( app ) => {
|
||||
// Add specific routes here to have them be checked first to not get general handling
|
||||
|
||||
app.get( '/admin/getAPI/:call', ( req, res ) => {
|
||||
if ( req.session.loggedInAdmin ) {
|
||||
getHandler.handleCall( req.params.call, req.query ).then( data => {
|
||||
res.send( data );
|
||||
} ).catch( error => {
|
||||
res.status( 500 ).send( error );
|
||||
} );
|
||||
} else {
|
||||
res.status( 403 ).sendFile( path.join( __dirname + '/../ui/' + ( req.query.lang ?? 'en' ) + '/errors/403.html' ) );
|
||||
}
|
||||
} );
|
||||
|
||||
app.post( '/admin/API/:call', ( req, res ) => {
|
||||
if ( req.session.loggedInAdmin ) {
|
||||
postHandler.handleCall( req.params.call, req.body, req.query.lang ).then( data => {
|
||||
res.send( data );
|
||||
} ).catch( error => {
|
||||
res.status( 500 ).send( error );
|
||||
} );
|
||||
} else {
|
||||
res.status( 403 ).sendFile( path.join( __dirname + '/../ui/' + ( req.query.lang ?? 'en' ) + '/errors/403.html' ) );
|
||||
}
|
||||
} );
|
||||
};
|
||||
48
src/server/admin/api/getHandler.js
Normal file
48
src/server/admin/api/getHandler.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* libreevent - getHandler.js
|
||||
*
|
||||
* Created by Janis Hutz 07/20/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const db = require( '../../backend/db/db.js' );
|
||||
|
||||
class GETHandler {
|
||||
constructor () {
|
||||
|
||||
}
|
||||
|
||||
handleCall ( call, query ) {
|
||||
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' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
reject( error );
|
||||
} );
|
||||
} else if ( call === 'getSeatplanDraft' ) {
|
||||
db.getJSONDataSimple( 'seatplan', query.location ).then( data => {
|
||||
if ( Object.keys( data ).length > 0 ) {
|
||||
if ( Object.keys( data[ 'draft' ] ).length > 0 ) {
|
||||
resolve( data[ 'draft' ] );
|
||||
} else {
|
||||
resolve( data[ 'save' ] );
|
||||
}
|
||||
} else {
|
||||
reject( 'No data found for this location' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
reject( error );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GETHandler;
|
||||
41
src/server/admin/api/postHandler.js
Normal file
41
src/server/admin/api/postHandler.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* libreevent - postHandler.js
|
||||
*
|
||||
* Created by Janis Hutz 07/20/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const db = require( '../../backend/db/db.js' );
|
||||
|
||||
class POSTHandler {
|
||||
constructor () {
|
||||
|
||||
}
|
||||
|
||||
handleCall ( call, data, lang ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
console.log( lang );
|
||||
if ( call === 'saveSeatplanDraft' ) {
|
||||
db.getJSONDataSimple( 'seatplan', data.location ).then( res => {
|
||||
let dat = res;
|
||||
dat[ 'draft' ] = data.data;
|
||||
db.writeJSONDataSimple( 'seatplan', data.location, dat ).then( resp => {
|
||||
resolve( resp );
|
||||
} ).catch( error => {
|
||||
reject( error );
|
||||
} );
|
||||
} );
|
||||
} else if ( call === 'saveSeatplan' ) {
|
||||
db.writeJSONDataSimple( 'seatplan', data.location, { 'draft': {}, 'save': data.data } ).then( resp => {
|
||||
resolve( resp );
|
||||
} ).catch( error => {
|
||||
reject( error );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = POSTHandler;
|
||||
@@ -48,6 +48,8 @@ let file = path.join( __dirname + '/../webapp/main/dist/index.html' );
|
||||
|
||||
if ( settings.init ) {
|
||||
require( './admin/adminRoutes.js' )( app, settings ); // admin routes
|
||||
require( './admin/adminAPIRoutes.js' )( app, settings ); // admin api routes
|
||||
require( './backend/userAPIRoutes.js' )( app, settings ); // admin api routes
|
||||
require( './backend/userRoutes.js' )( app, settings ); // user routes
|
||||
} else {
|
||||
require( './setup/setupRoutes.js' )( app, settings ); // setup routes
|
||||
|
||||
34
src/server/backend/api/getHandler.js
Normal file
34
src/server/backend/api/getHandler.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* libreevent - getHandler.js
|
||||
*
|
||||
* Created by Janis Hutz 07/20/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const db = require( '../db/db.js' );
|
||||
|
||||
class GETHandler {
|
||||
constructor () {
|
||||
|
||||
}
|
||||
|
||||
handleCall ( call, query ) {
|
||||
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' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
reject( error );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GETHandler;
|
||||
41
src/server/backend/api/postHandler.js
Normal file
41
src/server/backend/api/postHandler.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* libreevent - postHandler.js
|
||||
*
|
||||
* Created by Janis Hutz 07/20/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const db = require( '../db/db.js' );
|
||||
|
||||
class POSTHandler {
|
||||
constructor () {
|
||||
|
||||
}
|
||||
|
||||
handleCall ( call, data, lang ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
console.log( lang );
|
||||
if ( call === 'saveSeatplanDraft' ) {
|
||||
db.getJSONDataSimple( 'seatplan', data.location ).then( res => {
|
||||
let dat = res;
|
||||
dat[ 'draft' ] = data.data;
|
||||
db.writeJSONDataSimple( 'seatplan', data.location, dat ).then( resp => {
|
||||
resolve( resp );
|
||||
} ).catch( error => {
|
||||
reject( error );
|
||||
} );
|
||||
} );
|
||||
} else if ( call === 'saveSeatplan' ) {
|
||||
db.writeJSONDataSimple( 'seatplan', data.location, { 'draft': {}, 'save': data.data } ).then( resp => {
|
||||
resolve( resp );
|
||||
} ).catch( error => {
|
||||
reject( error );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = POSTHandler;
|
||||
1
src/server/backend/db/data/seatplan.json
Normal file
1
src/server/backend/db/data/seatplan.json
Normal file
@@ -0,0 +1 @@
|
||||
{"test2":{"draft":{},"save":{"seatInfo":{"data":{"1":{"0":22},"2":{"0":9},"3":{"0":9}},"count":0},"data":{"1":{"x":299.02,"y":17.157,"h":564.951,"w":731.618,"active":false,"draggable":true,"resizable":true,"id":1,"origin":1,"shape":"rectangular","type":"seat","startingRow":1,"seatNumberingPosition":1,"sector":"A","text":{"text":"TestText","textSize":20,"colour":"#20FFFF"},"numberingDirection":"left","category":"1"},"2":{"x":359.069,"y":661.765,"h":121.324,"w":604.167,"active":false,"draggable":true,"resizable":true,"id":2,"origin":3,"shape":"rectangular","type":"stage","startingRow":1,"seatNumberingPosition":1,"sector":"A","text":{"text":"TestText","textSize":20,"colour":"#20FFFF"},"ticketCount":1,"numberingDirection":"left","category":"1"},"3":{"x":519.608,"y":671.569,"h":83.333,"w":306.373,"active":false,"draggable":true,"resizable":true,"id":3,"origin":1,"shape":"rectangular","type":"text","startingRow":1,"seatNumberingPosition":2,"sector":"A","text":{"text":"Stage","textSize":25,"colour":"#2160ff"},"ticketCount":1,"numberingDirection":"left","category":"1"}}}},"test":{"draft":{},"save":{"seatInfo":{"data":{"1":{"0":22}},"count":0},"data":{"1":{"x":122.549,"y":122.549,"h":371.324,"w":735.294,"active":false,"draggable":true,"resizable":true,"id":1,"origin":1,"shape":"rectangular","type":"seat","startingRow":1,"seatNumberingPosition":1,"sector":"A","text":{"text":"TestText","textSize":20,"colour":"#20FFFF"},"numberingDirection":"left","category":"1"}}}}}
|
||||
@@ -26,7 +26,7 @@ if ( settings.db === 'mysql' ) {
|
||||
dbh.connect();
|
||||
}
|
||||
|
||||
module.exports.getDataSimple = function getData ( db, column, searchQuery ) {
|
||||
module.exports.getDataSimple = ( db, column, searchQuery ) => {
|
||||
return new Promise( resolve => {
|
||||
dbh.query( { 'command': 'getFilteredData', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( data => {
|
||||
console.log( data );
|
||||
@@ -37,23 +37,78 @@ module.exports.getDataSimple = function getData ( db, column, searchQuery ) {
|
||||
} );
|
||||
};
|
||||
|
||||
module.exports.writeDataSimple = function writeData ( db, column, searchQuery ) {
|
||||
module.exports.writeDataSimple = ( db, column, searchQuery ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
|
||||
} );
|
||||
};
|
||||
|
||||
module.exports.getJSONData = function getData ( file ) {
|
||||
module.exports.getJSONData = ( file ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fs.readFile( path.join( __dirname + '/../../' + file ), ( error, data ) => {
|
||||
fs.readFile( path.join( __dirname + '/data/' + file + '.json' ), ( error, data ) => {
|
||||
if ( error ) {
|
||||
reject( 'Error occurred: Error trace: ' + error );
|
||||
} else {
|
||||
if ( data.byteLength > 0 ) {
|
||||
resolve( JSON.parse( data ) ?? {} );
|
||||
} else {
|
||||
resolve( { } );
|
||||
}
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
module.exports.getJSONDataSimple = ( file, identifier ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fs.readFile( path.join( __dirname + '/data/' + file + '.json' ), ( error, data ) => {
|
||||
if ( error ) {
|
||||
reject( 'Error occurred: Error trace: ' + error );
|
||||
} else {
|
||||
if ( data.byteLength > 0 ) {
|
||||
resolve( JSON.parse( data )[ identifier ] ?? {} );
|
||||
} else {
|
||||
resolve( { } );
|
||||
}
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
module.exports.getJSONDataSync = ( file ) => {
|
||||
return JSON.parse( fs.readFileSync( path.join( __dirname + '/../../' + file ) ) );
|
||||
};
|
||||
|
||||
module.exports.writeJSONDataSimple = ( db, identifier, values ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fs.readFile( path.join( __dirname + '/data/' + db + '.json' ), ( error, data ) => {
|
||||
if ( error ) {
|
||||
reject( 'Error occurred: Error trace: ' + error );
|
||||
} else {
|
||||
let dat = {};
|
||||
if ( data.byteLength > 0 ) {
|
||||
dat = JSON.parse( data ) ?? {};
|
||||
}
|
||||
dat[ identifier ] = values;
|
||||
fs.writeFile( path.join( __dirname + '/data/' + db + '.json' ), JSON.stringify( dat ), ( error ) => {
|
||||
if ( error ) {
|
||||
reject( 'Error occurred: Error trace: ' + error );
|
||||
}
|
||||
resolve( JSON.parse( data ) );
|
||||
resolve( true );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
module.exports.getJSONDataSync = function getData ( file ) {
|
||||
return JSON.parse( fs.readFileSync( path.join( __dirname + '/../../' + file ) ) );
|
||||
module.exports.writeJSONData = ( db, data ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fs.writeFile( path.join( __dirname + '/data/' + db + '.json' ), JSON.stringify( data ), ( error ) => {
|
||||
if ( error ) {
|
||||
reject( 'Error occurred: Error trace: ' + error );
|
||||
} else {
|
||||
resolve( true );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
35
src/server/backend/userAPIRoutes.js
Normal file
35
src/server/backend/userAPIRoutes.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* libreevent - adminAPIRoutes.js
|
||||
*
|
||||
* Created by Janis Hutz 07/20/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const posth = require( './api/postHandler.js' );
|
||||
const geth = require( './api/getHandler.js' );
|
||||
const postHandler = new posth();
|
||||
const getHandler = new geth();
|
||||
const path = require( 'path' );
|
||||
|
||||
// settings is missing in arguments which shouldn't pose any problem
|
||||
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 );
|
||||
} ).catch( error => {
|
||||
res.status( 500 ).send( error );
|
||||
} );
|
||||
} );
|
||||
|
||||
app.post( '/API/:call', ( req, res ) => {
|
||||
postHandler.handleCall( req.params.call, req.body, req.query.lang ).then( data => {
|
||||
res.send( data );
|
||||
} ).catch( error => {
|
||||
res.status( 500 ).send( error );
|
||||
} );
|
||||
} );
|
||||
};
|
||||
@@ -1,9 +1,19 @@
|
||||
const express = require( 'express' );
|
||||
let app = express();
|
||||
const http = require( 'http' );
|
||||
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
let result = '';
|
||||
|
||||
app.use( express.static( '.' ) );
|
||||
// https://stackoverflow.com/questions/36129721/convert-number-to-alphabet-letter
|
||||
function printToLetter( number ) {
|
||||
let charIndex = number % alphabet.length;
|
||||
let quotient = number / alphabet.length;
|
||||
if ( charIndex - 1 === -1 ) {
|
||||
charIndex = alphabet.length;
|
||||
quotient --;
|
||||
}
|
||||
result = alphabet.charAt( charIndex - 1 ) + result;
|
||||
if ( quotient >= 1 ) {
|
||||
printToLetter( parseInt( quotient ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const PORT = process.env.PORT || 8081;
|
||||
http.createServer( app ).listen( PORT );
|
||||
printToLetter( 150036 );
|
||||
console.log( result );
|
||||
11
src/server/ui/en/errors/403.html
Normal file
11
src/server/ui/en/errors/403.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>403</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>403</h1>
|
||||
</body>
|
||||
</html>
|
||||
@@ -106,9 +106,7 @@
|
||||
<tr v-if="internal[ active ].type == 'seat' || internal[ active ].type == 'stand'">
|
||||
<td>Category:</td>
|
||||
<td>
|
||||
<select v-model="internal[ active ].seatCountingStartingPoint" @change="resubmit()">
|
||||
<option v-for="category in categories" :value="category.value">{{ category.name }}</option>
|
||||
</select>
|
||||
<input type="text" v-model="internal[ active ].category" @change="resubmit()">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
data() {
|
||||
return {
|
||||
active: 0,
|
||||
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, 'seatNumberingPosition': 1, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' }, 'numberingDirection': 'left' } },
|
||||
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, 'seatNumberingPosition': 1, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' }, 'numberingDirection': 'left', 'seatNumberingPosition': 1, 'category': '1' } },
|
||||
available: { 'redo': false, 'undo': false },
|
||||
scaleFactor: 1,
|
||||
sizePoll: null,
|
||||
@@ -128,7 +128,41 @@
|
||||
}
|
||||
};
|
||||
|
||||
this.loadSeatplan();
|
||||
// TODO: Create 1min interval saving
|
||||
|
||||
/*
|
||||
Calculate scale factor (this adds support for differently sized screens)
|
||||
900px is the "default" height
|
||||
*/
|
||||
|
||||
let height = $( document ).height() * 0.8;
|
||||
this.scaleFactor = ( height / 900 ) * this.zoomFactor;
|
||||
|
||||
/*
|
||||
Load seatplan
|
||||
*/
|
||||
fetch( localStorage.getItem( 'url' ) + '/admin/getAPI/getSeatplanDraft?location=' + sessionStorage.getItem( 'locationID' ) ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.json().then( data => {
|
||||
this.draggables = this.scaleUp( data.data );
|
||||
sessionStorage.setItem( 'seatplan', JSON.stringify( data.data ) );
|
||||
for ( let element in this.draggables ) {
|
||||
if ( this.draggables[ element ].active ) {
|
||||
this.draggables[ element ].active = false;
|
||||
}
|
||||
}
|
||||
} );
|
||||
} else if ( res.status === 500 ) {
|
||||
if ( sessionStorage.getItem( 'seatplan' ) ) {
|
||||
this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) );
|
||||
}
|
||||
for ( let element in this.draggables ) {
|
||||
if ( this.draggables[ element ].active ) {
|
||||
this.draggables[ element ].active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
if ( !sessionStorage.getItem( 'seatplan-history' ) ) {
|
||||
sessionStorage.setItem( 'seatplan-history', JSON.stringify( { '1': this.scaleDown( this.draggables ) } ) );
|
||||
@@ -163,10 +197,7 @@
|
||||
|
||||
let height = $( document ).height() * 0.8;
|
||||
this.scaleFactor = ( height / 900 ) * this.zoomFactor;
|
||||
/*
|
||||
Load seatplan
|
||||
*/
|
||||
// TODO: load from server
|
||||
|
||||
if ( sessionStorage.getItem( 'seatplan' ) ) {
|
||||
this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) );
|
||||
}
|
||||
@@ -263,21 +294,59 @@
|
||||
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
||||
},
|
||||
saveDraft () {
|
||||
// TODO: Save seat count and seat config to server as well
|
||||
this.getSeatCount();
|
||||
let progressNotification = this.$refs.notification.createNotification( 'Saving as draft', 5, 'progress', 'normal' );
|
||||
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
||||
const options = {
|
||||
method: 'post',
|
||||
body: JSON.stringify( { 'data':{ 'seatInfo': this.seatCountInfo, 'data': this.scaleDown( this.draggables ) }, 'location': sessionStorage.getItem( 'locationID' ) } ),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'charset': 'utf-8'
|
||||
}
|
||||
};
|
||||
fetch( localStorage.getItem( 'url' ) + '/admin/api/saveSeatplanDraft', options ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.text().then( text => {
|
||||
console.log( text );
|
||||
this.$refs.notification.cancelNotification( progressNotification );
|
||||
this.$refs.notification.createNotification( 'Saved as draft', 5, 'ok', 'normal' );
|
||||
// TODO: Save to server and add warning if no component has a seat start point if any component is a seat component
|
||||
} );
|
||||
} else if ( res.status === 403 ) {
|
||||
this.$refs.notification.cancelNotification( progressNotification );
|
||||
this.$refs.notification.createNotification( 'Unauthenticated', 5, 'ok', 'error' );
|
||||
}
|
||||
} );
|
||||
// TODO: add warning if no component has a seat start point if any component is a seat component
|
||||
},
|
||||
deploy () {
|
||||
// TODO: Save to server
|
||||
this.$refs.notification.createNotification( 'Deploying...', 5, 'progress', 'normal' );
|
||||
let deployNotification = this.$refs.notification.createNotification( 'Deploying...', 5, 'progress', 'normal' );
|
||||
const options = {
|
||||
method: 'post',
|
||||
body: JSON.stringify( { 'data':{ 'seatInfo': this.seatCountInfo, 'data': this.scaleDown( this.draggables ) }, 'location': sessionStorage.getItem( 'locationID' ) } ),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'charset': 'utf-8'
|
||||
}
|
||||
};
|
||||
fetch( localStorage.getItem( 'url' ) + '/admin/api/saveSeatplan', options ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.text().then( text => {
|
||||
console.log( text );
|
||||
this.$refs.notification.cancelNotification( deployNotification );
|
||||
this.$refs.notification.createNotification( 'Deployed successfully', 5, 'ok', 'normal' );
|
||||
} );
|
||||
} else if ( res.status === 403 ) {
|
||||
this.$refs.notification.cancelNotification( deployNotification );
|
||||
this.$refs.notification.createNotification( 'Unauthenticated', 5, 'ok', 'error' );
|
||||
}
|
||||
} );
|
||||
// TODO: add warning if no component has a seat start point if any component is a seat component
|
||||
},
|
||||
addNewElement () {
|
||||
// TODO: Check that this algorithm actually works in practice. If not, replace with one that
|
||||
// searches for the first available ID or uses a var to determine ID.
|
||||
this.draggables[ Object.keys( this.draggables ).length + 1 ] = { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': Object.keys( this.draggables ).length + 1, 'origin': 1, 'shape':'rectangular', 'type': 'seat', 'startingRow': 1, 'seatNumberingPosition': Object.keys( this.draggables ).length, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' }, 'ticketCount': 1, 'numberingDirection': 'left' };
|
||||
this.draggables[ Object.keys( this.draggables ).length + 1 ] = { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': ( Object.keys( this.draggables ).length + 1 ), 'origin': 1, 'shape':'rectangular', 'type': 'seat', 'startingRow': 1, 'seatNumberingPosition': Object.keys( this.draggables ).length, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' }, 'ticketCount': 1, 'numberingDirection': 'left', 'category': '1' };
|
||||
this.saveHistory();
|
||||
document.getElementById( 'parent' ).scrollTop = 0;
|
||||
document.getElementById( 'parent' ).scrollLeft = 0;
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
<span class="material-symbols-outlined" :style="seat.scaling" @click="selectSeat( seat.row, seat.seat )" v-if="seat.status == 'av'"
|
||||
:title="seat.displayName + ', Available'">living</span>
|
||||
<span class="material-symbols-outlined" :style="seat.scaling" v-else-if="seat.status == 'nav'"
|
||||
:title="seat.displayName + ', Unavailable'">close</span>
|
||||
:title="seat.displayName + ', Unavailable'">disabled_by_default</span>
|
||||
<span class="material-symbols-outlined" :style="seat.scaling" v-else-if="seat.status == 'sel'"
|
||||
:title="seat.displayName + ', Selected'">done</span>
|
||||
:title="seat.displayName + ', Selected'" @click="deselectSeat( seat.row, seat.seat )">check_box</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,7 +54,11 @@ export default {
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
"default": { 'sector': 'A', 'sectorCount': 1, 'unavailableSeats': { 'secAr0s0': true } }
|
||||
"default": { 'sector': 'A', 'sectorCount': 1, 'unavailableSeats': { 'secAr0s0': 'nav' }, 'categoryInfo': { 'pricing': { '1': { 'displayName': 'Adults - CHF 20.-', 'value': '1', 'price': 20 }, '2': { 'displayName': 'Child (0 - 15.99y) - CHF 15.-', 'value': '2', 'price': 15 } } } }
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -76,7 +80,7 @@ export default {
|
||||
let r = row * size;
|
||||
this.seats[ row ] = {};
|
||||
for ( let n = 0; n < nn; n++ ) {
|
||||
this.seats[ row ][ n ] = { 'style': '', 'id': 'sec' + this.data.sector + 'r' + row + 's' + n, 'displayName': ( this.data.sectorCount > 1 ? 'Sector ' + this.data.sector + ', ' : '' ) + 'Row ' + ( row + 1 ) + ', Seat ' + ( n + 1 ), 'status': 'av', 'row': row, 'seat': n };
|
||||
this.seats[ row ][ n ] = { 'style': '', 'id': 'sec' + this.data.sector + 'r' + row + 's' + n, 'displayName': ( this.data.sectorCount > 1 ? 'Sector ' + this.data.sector + ', ' : '' ) + 'Row ' + row + ', Seat ' + ( n + 1 ), 'status': 'av', 'row': row, 'seat': n };
|
||||
let phi = n * size / ( row * size );
|
||||
if ( this.origin === 1 ) {
|
||||
this.seats[ row ][ n ][ 'style' ] = `bottom: ${ r * Math.cos( phi ) * this.scaleFactor }px; left: ${ r * Math.sin( phi ) * this.scaleFactor }px; rotate: ${ phi }rad`;
|
||||
@@ -88,19 +92,42 @@ export default {
|
||||
this.seats[ row ][ n ][ 'style' ] = `top: ${ r * Math.cos( phi ) * this.scaleFactor }px; left: ${ r * Math.sin( phi ) * this.scaleFactor }px; rotate: ${ Math.PI - phi }rad`;
|
||||
}
|
||||
this.seats[ row ][ n ][ 'scaling' ] = `font-size: ${this.scaleFactor * 200}%; `;
|
||||
if ( this.data.categoryInfo.color ) {
|
||||
this.seats[ row ][ n ][ 'style' ] += `color: ${ this.data.categoryInfo.color.fg ? this.data.categoryInfo.color.fg : 'black' }; background-color: ${ this.data.categoryInfo.color.bg ? this.data.categoryInfo.color.bg : 'rgba( 0, 0, 0, 0 )' }`;
|
||||
}
|
||||
|
||||
if ( this.data.unavailableSeats ) {
|
||||
if ( this.data.unavailableSeats[ this.seats[ row ][ n ][ 'id' ] ] ) {
|
||||
this.seats[ row ][ n ][ 'status' ] = this.data.unavailableSeats[ this.seats[ row ][ n ][ 'id' ] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
for ( let seat in this.seats[ row ] ) {
|
||||
let styles = this.seats[ row ][ seat ].style.substring( this.seats[ row ][ seat ].style.indexOf( ';' ) + 1 );
|
||||
this.seats[ row ][ seat ].style = `font-size: ${this.scaleFactor * 200}%;` + styles;
|
||||
this.seats[ row ][ seat ].scaling = `font-size: ${this.scaleFactor * 200}%;`;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectSeat ( row, seat ) {
|
||||
console.log( row + ' ' + seat );
|
||||
console.log( this.data.categoryInfo );
|
||||
let selectedSeat = this.seats[ row ][ seat ];
|
||||
selectedSeat[ 'sector' ] = this.data.sector;
|
||||
selectedSeat[ 'option' ] = this.data.categoryInfo.pricing;
|
||||
selectedSeat[ 'componentID' ] = this.id;
|
||||
console.log( selectedSeat );
|
||||
this.$emit( 'seatSelected', selectedSeat );
|
||||
},
|
||||
deselectSeat( row, seat ) {
|
||||
this.$emit( 'seatDeselected', this.seats[ row ][ seat ] );
|
||||
this.seats[ row ][ seat ][ 'status' ] = 'av';
|
||||
},
|
||||
validateSeatSelection( seatObject, selectedTicketOption ) {
|
||||
console.log( seatObject );
|
||||
this.seats[ seatObject[ 'row' ] ][ seatObject[ 'seat' ] ][ 'status' ] = 'sel';
|
||||
this.seats[ seatObject[ 'row' ] ][ seatObject[ 'seat' ] ][ 'ticketOption' ] = selectedTicketOption;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -44,6 +44,10 @@ export default {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
startingRow: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
origin: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
@@ -74,7 +78,6 @@ export default {
|
||||
this.seats[ row ] = {};
|
||||
for ( let n = 0; n < Math.floor( w / size ); n++ ) {
|
||||
this.seats[ row ][ n ] = { 'style': '', 'id': 'sec' + this.data.sector + 'r' + row + 's' + n, 'displayName': ( this.data.sectorCount > 1 ? 'Sector ' + this.data.sector + ', ' : '' ) + 'Row ' + ( row + 1 ) + ', Seat ' + ( n + 1 ), 'status': 'av', 'row': row, 'seat': n };
|
||||
// TODO: apply style of category
|
||||
if ( this.origin === 1 ) {
|
||||
this.seats[ row ][ n ][ 'style' ] = `bottom: ${ row * size * this.scaleFactor }px; left: ${ n * size * this.scaleFactor }px; rotate: ${ this.origin / 4 - 0.25 }turn;`;
|
||||
} else if ( this.origin === 2 ) {
|
||||
@@ -84,7 +87,9 @@ export default {
|
||||
} else if ( this.origin === 4 ) {
|
||||
this.seats[ row ][ n ][ 'style' ] = `top: ${ row * size * this.scaleFactor }px; left: ${ n * size * this.scaleFactor }px; rotate: ${ this.origin / 4 - 0.25 }turn;`;
|
||||
}
|
||||
|
||||
this.seats[ row ][ n ][ 'scaling' ] = `font-size: ${this.scaleFactor * 200}%; `;
|
||||
|
||||
if ( this.data.categoryInfo.color ) {
|
||||
this.seats[ row ][ n ][ 'style' ] += `color: ${ this.data.categoryInfo.color.fg ? this.data.categoryInfo.color.fg : 'black' }; background-color: ${ this.data.categoryInfo.color.bg ? this.data.categoryInfo.color.bg : 'rgba( 0, 0, 0, 0 )' }`;
|
||||
}
|
||||
@@ -100,8 +105,7 @@ export default {
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
for ( let seat in this.seats[ row ] ) {
|
||||
let styles = this.seats[ row ][ seat ].style.substring( this.seats[ row ][ seat ].style.indexOf( ';' ) + 1 );
|
||||
this.seats[ row ][ seat ].style = `font-size: ${this.scaleFactor * 200}%;` + styles;
|
||||
this.seats[ row ][ seat ].scaling = `font-size: ${this.scaleFactor * 200}%;`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
<span class="material-symbols-outlined" :style="seat.scaling" @click="selectSeat( seat.row, seat.seat )" v-if="seat.status == 'av'"
|
||||
:title="seat.displayName + ', Available'">living</span>
|
||||
<span class="material-symbols-outlined" :style="seat.scaling" v-else-if="seat.status == 'nav'"
|
||||
:title="seat.displayName + ', Unavailable'">close</span>
|
||||
:title="seat.displayName + ', Unavailable'">disabled_by_default</span>
|
||||
<span class="material-symbols-outlined" :style="seat.scaling" v-else-if="seat.status == 'sel'"
|
||||
:title="seat.displayName + ', Selected'">done</span>
|
||||
:title="seat.displayName + ', Selected'" @click="deselectSeat( seat.row, seat.seat )">check_box</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,7 +54,11 @@ export default {
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
"default": { 'sector': 'A', 'sectorCount': 1, 'unavailableSeats': { 'secAr0s0': true } }
|
||||
"default": { 'sector': 'A', 'sectorCount': 1, 'unavailableSeats': { 'secAr0s0': 'nav' }, 'categoryInfo': { 'pricing': { '1': { 'displayName': 'Adults - CHF 20.-', 'value': '1', 'price': 20 }, '2': { 'displayName': 'Child (0 - 15.99y) - CHF 15.-', 'value': '2', 'price': 15 } } } }
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -79,7 +83,7 @@ export default {
|
||||
let nn = 2 + ( row - 1 ) * 2;
|
||||
this.seats[ row ] = {};
|
||||
for ( let n = 0; n < nn; n++ ) {
|
||||
this.seats[ row ][ n ] = { 'style': '', 'id': 'sec' + this.data.sector + 'r' + row + 's' + n, 'displayName': ( this.data.sectorCount > 1 ? 'Sector ' + this.data.sector + ', ' : '' ) + 'Row ' + ( row + 1 ) + ', Seat ' + ( n + 1 ), 'status': 'av', 'row': row, 'seat': n };
|
||||
this.seats[ row ][ n ] = { 'style': '', 'id': 'sec' + this.data.sector + 'r' + row + 's' + n, 'displayName': ( this.data.sectorCount > 1 ? 'Sector ' + this.data.sector + ', ' : '' ) + 'Row ' + row + ', Seat ' + ( n + 1 ), 'status': 'av', 'row': row, 'seat': n };
|
||||
let side = n * sideOffset;
|
||||
if ( this.origin === 1 ) {
|
||||
this.seats[ row ][ n ][ 'style' ] = `bottom: ${ ( side + 5 ) * this.scaleFactor }px; left: ${ ( row * sideOffset * 2 - side ) * this.scaleFactor }px; rotate: ${ angle }rad`;
|
||||
@@ -90,20 +94,43 @@ export default {
|
||||
} else if ( this.origin === 4 ) {
|
||||
this.seats[ row ][ n ][ 'style' ] = `top: ${ ( side + 5 ) * this.scaleFactor }px; left: ${ ( row * sideOffset * 2 - side ) * this.scaleFactor }px; rotate: ${ Math.PI - angle }rad`;
|
||||
}
|
||||
|
||||
this.seats[ row ][ n ][ 'scaling' ] = `font-size: ${this.scaleFactor * 200}%; `;
|
||||
|
||||
if ( this.data.categoryInfo.color ) {
|
||||
this.seats[ row ][ n ][ 'style' ] += `color: ${ this.data.categoryInfo.color.fg ? this.data.categoryInfo.color.fg : 'black' }; background-color: ${ this.data.categoryInfo.color.bg ? this.data.categoryInfo.color.bg : 'rgba( 0, 0, 0, 0 )' }`;
|
||||
}
|
||||
|
||||
if ( this.data.unavailableSeats ) {
|
||||
if ( this.data.unavailableSeats[ this.seats[ row ][ n ][ 'id' ] ] ) {
|
||||
this.seats[ row ][ n ][ 'status' ] = this.data.unavailableSeats[ this.seats[ row ][ n ][ 'id' ] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
for ( let seat in this.seats[ row ] ) {
|
||||
let styles = this.seats[ row ][ seat ].style.substring( this.seats[ row ][ seat ].style.indexOf( ';' ) + 1 );
|
||||
this.seats[ row ][ seat ].style = `font-size: ${this.scaleFactor * 200}%;` + styles;
|
||||
this.seats[ row ][ seat ].scaling = `font-size: ${this.scaleFactor * 200}%;`;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectSeat ( row, seat ) {
|
||||
console.log( row + ' ' + seat );
|
||||
let selectedSeat = this.seats[ row ][ seat ];
|
||||
selectedSeat[ 'sector' ] = this.data.sector;
|
||||
selectedSeat[ 'option' ] = this.data.categoryInfo.pricing;
|
||||
selectedSeat[ 'componentID' ] = this.id;
|
||||
this.$emit( 'seatSelected', selectedSeat );
|
||||
},
|
||||
deselectSeat( row, seat ) {
|
||||
this.$emit( 'seatDeselected', this.seats[ row ][ seat ] );
|
||||
this.seats[ row ][ seat ][ 'status' ] = 'av';
|
||||
},
|
||||
validateSeatSelection( seatObject, selectedTicketOption ) {
|
||||
console.log( seatObject );
|
||||
this.seats[ seatObject[ 'row' ] ][ seatObject[ 'seat' ] ][ 'status' ] = 'sel';
|
||||
this.seats[ seatObject[ 'row' ] ][ seatObject[ 'seat' ] ][ 'ticketOption' ] = selectedTicketOption;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -15,16 +15,19 @@
|
||||
<Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" :x="draggable.x" :y="draggable.y" :w="draggable.w" :h="draggable.h"
|
||||
:active="false" :draggable="false" :resizable="false" :parent="true" class="draggable-box">
|
||||
|
||||
<circularSeatplanComponent :ref="'component' + draggable.id" v-if="draggable.shape == 'circular' && draggable.type == 'seat'" :scale-factor="scaleFactor"
|
||||
:w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"
|
||||
@seatSelected="( seat ) => { seatSelected( seat ) }"></circularSeatplanComponent>
|
||||
<circularSeatplanComponent v-if="draggable.shape == 'circular' && draggable.type == 'seat'" :ref="'component' + draggable.id"
|
||||
:scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"
|
||||
:data="draggable.data" :id="draggable.id"
|
||||
@seatSelected="( seat ) => { seatSelected( seat ) }" @seatDeselected="( seat ) => { seatDeselected( seat ) }"></circularSeatplanComponent>
|
||||
|
||||
<trapezoidSeatplanComponent :ref="'component' + draggable.id" v-else-if="draggable.shape == 'trapezoid' && draggable.type == 'seat'" :scale-factor="scaleFactor"
|
||||
:w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"
|
||||
@seatSelected="( seat ) => { seatSelected( seat ) }"></trapezoidSeatplanComponent>
|
||||
<trapezoidSeatplanComponent v-else-if="draggable.shape == 'trapezoid' && draggable.type == 'seat'" :ref="'component' + draggable.id"
|
||||
:scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"
|
||||
:data="draggable.data" :id="draggable.id"
|
||||
@seatSelected="( seat ) => { seatSelected( seat ) }" @seatDeselected="( seat ) => { seatDeselected( seat ) }"></trapezoidSeatplanComponent>
|
||||
|
||||
<rectangularSeatplanComponent :ref="'component' + draggable.id" v-else-if="draggable.shape == 'rectangular' && draggable.type == 'seat'" :scale-factor="scaleFactor"
|
||||
:w="draggable.w" :h="draggable.h" :origin="draggable.origin" :data="draggable.data"
|
||||
<rectangularSeatplanComponent v-else-if="draggable.shape == 'rectangular' && draggable.type == 'seat'" :ref="'component' + draggable.id"
|
||||
:scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"
|
||||
:data="draggable.data" :id="draggable.id"
|
||||
@seatSelected="( seat ) => { seatSelected( seat ) }" @seatDeselected="( seat ) => { seatDeselected( seat ) }"></rectangularSeatplanComponent>
|
||||
|
||||
<stagesSeatplanComponent :ref="'component' + draggable.id" v-else-if="draggable.type == 'stage'" :origin="draggable.origin" :shape="draggable.shape"></stagesSeatplanComponent>
|
||||
@@ -110,12 +113,25 @@
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Load cart
|
||||
this.cart = localStorage.getItem( 'cart' ) ? JSON.parse( localStorage.getItem( 'cart' ) ): {};
|
||||
|
||||
// Load seat plan
|
||||
this.loadSeatplan();
|
||||
|
||||
// Load seatplan from server
|
||||
let height = $( document ).height() * 0.8;
|
||||
this.scaleFactor = ( height / 900 ) * this.zoomFactor;
|
||||
fetch( localStorage.getItem( 'url' ) + '/getAPI/getSeatplan?location=' + sessionStorage.getItem( 'selectedTicket' ) ).then( res => {
|
||||
if ( res.status === 200 ) {
|
||||
res.json().then( data => {
|
||||
this.draggables = this.scaleUp( data.data );
|
||||
sessionStorage.setItem( 'seatplan', JSON.stringify( data.data ) );
|
||||
} );
|
||||
} else if ( res.status === 500 ) {
|
||||
if ( sessionStorage.getItem( 'seatplan' ) ) {
|
||||
this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
// TODO: remove scaleDown function again once backend is up
|
||||
// TODO: Optimise for odd screen sizes and aspect ratios and fucking webkit
|
||||
@@ -188,7 +204,6 @@
|
||||
/*
|
||||
Load seatplan
|
||||
*/
|
||||
// TODO: load from server
|
||||
if ( sessionStorage.getItem( 'seatplan' ) ) {
|
||||
this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) );
|
||||
}
|
||||
@@ -286,6 +301,7 @@
|
||||
localStorage.setItem( 'cart', JSON.stringify( this.cart ) );
|
||||
},
|
||||
reserveTicket ( option ) {
|
||||
console.log( this.selectedSeat.componentID );
|
||||
if ( option.status == 'ok' ) {
|
||||
this.$refs[ 'component' + this.selectedSeat.componentID ][ 0 ].validateSeatSelection( this.selectedSeat, option.data );
|
||||
this.cartHandling( 'select', option.data );
|
||||
|
||||
@@ -19,7 +19,7 @@ app.use( createPinia() );
|
||||
|
||||
let userStore = useUserStore();
|
||||
|
||||
let prod = false;
|
||||
let prod = true;
|
||||
|
||||
if ( prod ) {
|
||||
fetch( '/api/getAuth' ).then( res => {
|
||||
|
||||
@@ -181,11 +181,12 @@ export default {
|
||||
name: 'PurchaseView',
|
||||
data () {
|
||||
return {
|
||||
settings: { 'accountRequired': true, 'requiresAddress': true, 'requiresAge': true, 'requiresSpecialNumber': true, 'specialNumberDisplayName': { 'de': '', 'en': 'id number' } },
|
||||
settings: { 'accountRequired': true, 'requiresAddress': true, 'requiresAge': true, 'requiresSpecialNumber': true, 'specialRequirement': { 'display': { 'de': '', 'en': 'id number' }, 'rules': {} } },
|
||||
isAuthenticated: false,
|
||||
cart: {},
|
||||
backend: { 'currency': 'CHF' },
|
||||
cartNotEmpty: false,
|
||||
userData: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
Reference in New Issue
Block a user