setup changes, almost complete seatplan

This commit is contained in:
2023-06-17 20:01:41 +02:00
parent 4729384fc8
commit 4bbe9fbec9
5 changed files with 213 additions and 49 deletions

2
src/webapp/notes.md Normal file
View File

@@ -0,0 +1,2 @@
# Account view:
- Load: email, settings, change pw, change mail, see all tickets

View File

@@ -10,7 +10,28 @@
<template> <template>
<div id="properties"> <div id="properties">
<h2>Properties</h2> <h2>Properties</h2>
<h3>General settings</h3>
<table>
<tr>
<td>Zoom Factor:</td>
<td>
{{ Math.round( zoomFactor * 1000 ) / 1000 }}x
</td>
</tr>
<tr>
<td>Row naming scheme</td>
<td>
<select v-model="generalSettings[ 'namingScheme' ]">
<option value="numeric">Numeric</option>
<option value="alphabetic">Alphabetic</option>
<option value="roman">Roman numerals</option>
</select>
</td>
</tr>
</table>
<h3>Component settings</h3>
<table v-if="active"> <table v-if="active">
<tr> <tr>
<td>Position X:</td> <td>Position X:</td>
<td> <td>
@@ -47,6 +68,16 @@
<input type="number" min="1" max="4" v-model="internal[ active ].origin" @change="resubmit()"> <input type="number" min="1" max="4" v-model="internal[ active ].origin" @change="resubmit()">
</td> </td>
</tr> </tr>
<tr>
<td>Seat numbering:</td>
<td>
<select v-model="internal[ active ].seatCountingStartingPoint" @change="resubmit()">
<option value="0">Continue</option>
<option value="1">Start left</option>
<option value="2">Start right</option>
</select>
</td>
</tr>
<tr> <tr>
<td>Type:</td> <td>Type:</td>
<td> <td>
@@ -69,7 +100,7 @@
</tr> </tr>
</table> </table>
<div v-else class="no-select"> <div v-else class="no-select">
<b>No Object selected</b><br> <b>No component selected</b><br>
Please select one to view details here. Please select one to view details here.
</div> </div>
</div> </div>
@@ -87,10 +118,22 @@ export default {
type: Number, type: Number,
"default": 1, "default": 1,
}, },
generalSettings: {
type: Object,
"default": {},
},
zoomFactor: {
type: Number,
"default": 1
},
active: { active: {
type: Number, type: Number,
"default": 1, "default": 1,
}, },
historyPos: {
type: Number,
"default": 0,
}
}, },
data () { data () {
return { return {
@@ -100,11 +143,29 @@ export default {
methods: { methods: {
loadInternal () { loadInternal () {
for ( let value in this.draggables ) { for ( let value in this.draggables ) {
this.internal[ value ] = this.draggables[ value ]; this.internal[ value ] = {};
for ( let info in this.draggables[ value ] ) {
if ( info === 'w' || info === 'h' || info === 'x' || info === 'y' ) {
this.internal[ value ][ info ] = Math.round( this.draggables[ value ][ info ] / this.scaleFactor );
} else {
this.internal[ value ][ info ] = this.draggables[ value ][ info ];
}
}
} }
}, },
resubmit () { resubmit () {
this.$emit( 'updated', this.internal ); let ret = {};
for ( let value in this.internal ) {
ret[ value ] = {};
for ( let info in this.internal[ value ] ) {
if ( info === 'w' || info === 'h' || info === 'x' || info === 'y' ) {
ret[ value ][ info ] = Math.round( this.internal[ value ][ info ] * this.scaleFactor );
} else {
ret[ value ][ info ] = this.internal[ value ][ info ];
}
}
}
this.$emit( 'updated', ret );
} }
}, },
watch: { watch: {
@@ -113,6 +174,12 @@ export default {
}, },
active ( value ) { active ( value ) {
this.loadInternal(); this.loadInternal();
},
scaleFactor ( value ) {
this.loadInternal();
},
historyPos ( value ) {
this.loadInternal();
} }
}, },
created () { created () {

View File

@@ -9,7 +9,7 @@
<template> <template>
<div id="window"> <div id="window">
<properties class="properties" v-model:draggables="draggables" @updated="handleUpdate" :scale-factor="scaleFactor" :active="active"></properties> <properties class="properties" v-model:draggables="draggables" @updated="handleUpdate" :scale-factor="scaleFactor" :active="active" :history-pos="historyPos" :zoom-factor="zoomFactor" v-model:general-settings="generalSettings"></properties>
<div class="parent"> <div class="parent">
<div class="content-parent"> <div class="content-parent">
<Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" v-model:x="draggable.x" v-model:y="draggable.y" v-model:w="draggable.w" v-model:h="draggable.h" <Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" v-model:x="draggable.x" v-model:y="draggable.y" v-model:w="draggable.w" v-model:h="draggable.h"
@@ -23,15 +23,20 @@
</Vue3DraggableResizable> </Vue3DraggableResizable>
</div> </div>
</div> </div>
<div> <div class="toolbar">
<button v-if="available.undo" @click="historyOp( 'undo' )">Undo</button> <button title="Go back to location settings" @click="this.$router.push( '/admin/locations' )"><span class="material-symbols-outlined">arrow_back</span></button>
<button v-else disabled>Undo</button> <button title="Undo [Ctrl + Z]" v-if="available.undo" @click="historyOp( 'undo' )"><span class="material-symbols-outlined">undo</span></button>
<button v-if="available.redo" @click="historyOp( 'redo' )">Redo</button> <button title="Undo (unavailable)" v-else disabled>Undo</button>
<button v-else disabled>Redo</button> <button title="Redo [Ctrl + Y]" v-if="available.redo" @click="historyOp( 'redo' )"><span class="material-symbols-outlined">redo</span></button>
<button @click="zoom( 1.2 )">+</button> <button title="Redo (unavailable)" v-else disabled><span class="material-symbols-outlined">redo</span></button>
<button @click="zoom( 0.8 )">-</button> <button title="Zoom in [+]" @click="zoom( 0.2 )"><span class="material-symbols-outlined">zoom_in</span></button>
<button @click="addNewElement()">Add</button> <button title="Reset zoom [=]" @click="zoom( 1 );"><span class="material-symbols-outlined">center_focus_strong</span></button>
<button @click="deleteSelected()">Delete</button> <button title="Zoom out [-]" @click="zoom( -0.2 )"><span class="material-symbols-outlined">zoom_out</span></button>
<button title="Add component [Ctrl + I]" @click="addNewElement()"><span class="material-symbols-outlined">add</span></button>
<button title="Remove selected component [Delete]" @click="deleteSelected()"><span class="material-symbols-outlined">delete</span></button>
<!-- TODO: Create real save function -->
<button title="Save this seatplan as a draft" @click="save()"><span class="material-symbols-outlined">save</span></button>
<button title="Deploy this seatplan (save it for use)" @click="save()"><span class="material-symbols-outlined">system_update_alt</span></button>
</div> </div>
</div> </div>
</template> </template>
@@ -60,12 +65,14 @@
data() { data() {
return { return {
active: 0, 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 } }, 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': 0 } },
available: { 'redo': false, 'undo': false }, available: { 'redo': false, 'undo': false },
scaleFactor: 1, scaleFactor: 1,
sizePoll: null, sizePoll: null,
prevSize: { 'h': window.innerHeight, 'w': window.innerWidth }, prevSize: { 'h': window.innerHeight, 'w': window.innerWidth },
zoomFactor: 1, zoomFactor: 1,
historyPos: 0,
generalSettings: { 'namingScheme': 'numeric' },
} }
}, },
methods: { methods: {
@@ -80,7 +87,7 @@
*/ */
runHook () { runHook () {
let self = this; let self = this;
this.zoomFactor = sessionStorage.getItem( 'zoom' ) ? sessionStorage.getItem( 'zoom' ) : 1; this.zoomFactor = sessionStorage.getItem( 'zoom' ) ? parseFloat( sessionStorage.getItem( 'zoom' ) ) : 1;
/* /*
Keybinds: Keybinds:
@@ -105,6 +112,12 @@
} else if ( event.ctrlKey && event.key === 'i' ) { } else if ( event.ctrlKey && event.key === 'i' ) {
event.preventDefault(); event.preventDefault();
self.addNewElement(); self.addNewElement();
} else if ( event.key === '+' ) {
self.zoom( 0.2 );
} else if ( event.key === '-' ) {
self.zoom( -0.2 );
} else if ( event.key === '=' ) {
self.zoom( 1 );
} }
}; };
@@ -194,6 +207,7 @@
saveHistory () { saveHistory () {
let history = sessionStorage.getItem( 'seatplan-history' ) ? JSON.parse( sessionStorage.getItem( 'seatplan-history' ) ) : {}; let history = sessionStorage.getItem( 'seatplan-history' ) ? JSON.parse( sessionStorage.getItem( 'seatplan-history' ) ) : {};
let count = parseInt( Object.keys( history ).length + 1 ); let count = parseInt( Object.keys( history ).length + 1 );
this.historyPos = count;
if ( count - 1 > parseInt( sessionStorage.getItem( 'historyPos' ) ) ) { if ( count - 1 > parseInt( sessionStorage.getItem( 'historyPos' ) ) ) {
for ( let i = parseInt( sessionStorage.getItem( 'historyPos' ) ) + 1; i < count; i++ ) { for ( let i = parseInt( sessionStorage.getItem( 'historyPos' ) ) + 1; i < count; i++ ) {
delete history[ i ]; delete history[ i ];
@@ -236,19 +250,25 @@
this.available.redo = false; this.available.redo = false;
} }
} }
this.historyPos = sessionStorage.getItem( 'historyPos' );
}, },
save () { save () {
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) ); sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
}, },
addNewElement () { addNewElement () {
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 }; 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, 'seatCountingStartingPoint': 0 };
this.saveHistory(); this.saveHistory();
}, },
deleteSelected () { deleteSelected () {
if ( this.active ) {
this.draggables[ this.active ].active = true; this.draggables[ this.active ].active = true;
if ( confirm( 'Do you really want to delete the selected item?' ) ) { if ( confirm( 'Do you really want to delete the selected item?' ) ) {
delete this.draggables[ this.active ]; delete this.draggables[ this.active ];
this.saveHistory(); this.saveHistory();
this.active = 0;
}
} else {
alert( 'Please select a component first!' );
} }
}, },
handleUpdate ( value ) { handleUpdate ( value ) {
@@ -257,10 +277,22 @@
this.saveHistory(); this.saveHistory();
}, },
zoom ( scale ) { zoom ( scale ) {
this.zoomFactor = this.zoomFactor * scale; if ( scale == 1 ) {
this.zoomFactor = 1;
this.loadSeatplan();
} else {
if ( ( this.zoomFactor < 0.3 && scale < 0 ) || ( this.zoomFactor > 2.9 && scale > 0 ) ) {
if ( this.zoomFactor < 0.3 ) {
alert( 'Minimum zoom factor reached' );
} else {
alert( 'Maximum zoom factor reached' );
}
} else {
this.zoomFactor += scale;
}
sessionStorage.setItem( 'zoom', this.zoomFactor ); sessionStorage.setItem( 'zoom', this.zoomFactor );
this.scaleFactor = this.scaleFactor * scale; this.loadSeatplan();
this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) ); }
} }
}, },
created () { created () {
@@ -275,11 +307,11 @@
<style scoped> <style scoped>
.parent { .parent {
height: 90vh;
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
max-height: 90vh; top: 7.5vh;
max-width: 90vw; left: 3vw;
left: 5%; position: absolute;
position: relative;
border: black 1px solid; border: black 1px solid;
user-select: none; user-select: none;
-moz-user-select: none; -moz-user-select: none;
@@ -301,13 +333,32 @@
background-color: var( --accent-background ); background-color: var( --accent-background );
color: var( --secondary-color ); color: var( --secondary-color );
width: 20vw; width: 20vw;
height: 75vh; height: 90vh;
top: 10vh; top: 7.5vh;
left: 79vw; right: 0.5vw;
} }
.content-parent { .content-parent {
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
height: 400%; height: 400%;
} }
.toolbar {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: absolute;
top: 7.5vh;
left: 0.5vw;
height: 90vh;
}
.toolbar button {
margin-top: 10%;
cursor: pointer;
}
.toolbar button:disabled {
cursor: default;
}
</style> </style>

View File

@@ -9,9 +9,9 @@
<template> <template>
<div id="stages" class="stages"> <div id="stages" class="stages">
<div id="rectangular" v-if="shape == 'rectangular'" class="stages"></div> <div id="rectangular" v-if="shape == 'rectangular'" class="stages" :style="style"></div>
<div id="trapezoid" v-else-if="shape == 'trapezoid'" class="stages"><div id="trapezoid-ingredient"></div></div> <div id="trapezoid" v-else-if="shape == 'trapezoid'" class="stages"><div id="trapezoid-ingredient" :style="trapezoidStyle"><div id="trapezoid-line"></div></div></div>
<div id="circular" v-else-if="shape == 'circular'" class="stages"><div id="circular-ingredient"></div></div> <div id="circular" v-else-if="shape == 'circular'" class="stages"><div id="circular-ingredient" :style="circularStyle"></div></div>
</div> </div>
</template> </template>
@@ -22,21 +22,30 @@
} }
#rectangular { #rectangular {
border: solid black 2px; border-color: black;
border-width: 2px;
} }
#trapezoid, #circular { #circular, #trapezoid {
overflow: hidden; overflow: hidden;
} }
#trapezoid-ingredient { #trapezoid-ingredient {
border: solid black 2px; display: flex;
rotate: 45deg; justify-content: center;
height: 100vw; align-items: center;
width: 100vw; height: 200%;
width: 200%;
position: relative; position: relative;
top: 29vh; bottom: 50%;
right: 120vh; right: 50%;
}
#trapezoid-line {
border: black solid 1px;
height: 0%;
width: 100%;
display: block;
} }
#circular-ingredient { #circular-ingredient {
@@ -45,8 +54,6 @@
height: 199%; height: 199%;
width: 199%; width: 199%;
position: relative; position: relative;
top: 0;
right: 100%;
} }
</style> </style>
@@ -62,6 +69,38 @@ export default {
type: String, type: String,
"default": "rectangular", "default": "rectangular",
}, },
},
data() {
return {
style: 'border-style: none none solid none',
circularStyle: 'top: 0; left 100%;',
trapezoidStyle: 'rotate: 45deg',
}
},
methods: {
updateOrigin () {
if ( this.origin === 1 ) {
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.circularStyle = 'top: 0; right: 0;';
} else if ( this.origin === 3 ) {
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.circularStyle = 'top: -100%; right: 100%;';
}
}
},
watch: {
origin ( value ) {
this.updateOrigin();
}
},
created() {
this.updateOrigin();
} }
} }
</script> </script>

View File

@@ -11,14 +11,14 @@
<div> <div>
<nav class="setup-nav"> <nav class="setup-nav">
<router-link to="/setup">Start</router-link> | <router-link to="/setup">Start</router-link> |
<router-link to="/setup/root">Root account</router-link> | <router-link to="/setup/root" @click="unlock( 'page' )">Root account</router-link> |
<router-link to="/setup/page" v-if="backendStore.getVisitedSetupPages[ 'page' ]">Landing page</router-link> <router-link to="/setup/page" v-if="backendStore.getVisitedSetupPages[ 'page' ]" @click="unlock( 'payments' )">Landing page</router-link>
<a v-else class="inactive">Landing page</a> | <a v-else class="inactive">Landing page</a> |
<router-link to="/setup/payments" v-if="backendStore.getVisitedSetupPages[ 'payments' ]">Payments</router-link> <router-link to="/setup/payments" v-if="backendStore.getVisitedSetupPages[ 'payments' ]" @click="unlock( 'events' )">Payments</router-link>
<a v-else class="inactive">Payments</a> | <a v-else class="inactive">Payments</a> |
<router-link to="/setup/events" v-if="backendStore.getVisitedSetupPages[ 'events' ]">Events</router-link> <router-link to="/setup/events" v-if="backendStore.getVisitedSetupPages[ 'events' ]" @click="unlock( 'tos' )">Events</router-link>
<a v-else class="inactive">Events</a> | <a v-else class="inactive">Events</a> |
<router-link to="/setup/tos" v-if="backendStore.getVisitedSetupPages[ 'tos' ]">TOS</router-link> <router-link to="/setup/tos" v-if="backendStore.getVisitedSetupPages[ 'tos' ]" @click="unlock( 'complete' )">TOS</router-link>
<a v-else class="inactive">TOS</a> | <a v-else class="inactive">TOS</a> |
<router-link to="/setup/complete" v-if="backendStore.getVisitedSetupPages[ 'complete' ]">Complete</router-link> <router-link to="/setup/complete" v-if="backendStore.getVisitedSetupPages[ 'complete' ]">Complete</router-link>
<a v-else class="inactive">Complete</a> <a v-else class="inactive">Complete</a>
@@ -49,6 +49,11 @@
created () { created () {
this.backendStore.loadVisitedSetupPages(); this.backendStore.loadVisitedSetupPages();
}, },
methods: {
unlock ( page ) {
this.backendStore.addVisitedSetupPages( page, true );
}
}
}; };
</script> </script>