mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 13:24:24 +00:00
lots of progress
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
# Account view:
|
||||
- Load: email, settings, change pw, change mail, see all tickets
|
||||
|
||||
- set page title based on settings
|
||||
|
||||
- make pricing groups changeable in UI (event categories)
|
||||
|
||||
- Fix text field overflow (text too big for box)
|
||||
- Other optimisation for seat plan editor
|
||||
|
||||
- Implement Permission system
|
||||
|
||||
|
||||
|
||||
|
||||
- add webpack to project website to decrease file size
|
||||
@@ -12,7 +12,7 @@
|
||||
<router-link to="/">Home</router-link> |
|
||||
<router-link to="/tickets">Tickets</router-link> |
|
||||
<router-link to="/cart">Cart</router-link> |
|
||||
<router-link to="/login">Account</router-link> |
|
||||
<router-link to="/account">Account</router-link> |
|
||||
<button @click="changeTheme();" v-html="theme" id="themeSelector"></button>
|
||||
</nav>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
@@ -31,7 +31,7 @@
|
||||
--popup-color: rgb(224, 224, 224);
|
||||
--accent-color: #42b983;
|
||||
--hover-color: rgb(165, 165, 165);
|
||||
--accent-background-hover: #4380a8;
|
||||
--accent-background-hover: rgb(124, 140, 236);
|
||||
--overlay-color: rgba(0, 0, 0, 0.7);
|
||||
--inactive-color: rgb(100, 100, 100);
|
||||
--highlight-backdrop: rgb(143, 134, 192);
|
||||
|
||||
@@ -30,20 +30,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay" id="placeNotAvailable">
|
||||
<div class="popup">
|
||||
<div class="popup-content">
|
||||
<div class="close-container">
|
||||
<span class="material-symbols-outlined close-button" @click="closePlaceNotAvailablePopup()">close</span>
|
||||
</div>
|
||||
<div class="popup-content-wrapper">
|
||||
<h3>One or more seat(s) you have previously selected is/are no longer available!</h3>
|
||||
<p>Please select another one!</p>
|
||||
<button class="button" @click="closePlaceNotAvailablePopup()">Ok</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -86,10 +72,7 @@ export default {
|
||||
}
|
||||
|
||||
if ( showError ) {
|
||||
setTimeout( function () {
|
||||
$( '#placeNotAvailable' ).show( 200 );
|
||||
console.log( 'showing error message' );
|
||||
}, 500 );
|
||||
// TODO: Show popup that no more tickets in a category are available
|
||||
}
|
||||
|
||||
|
||||
@@ -133,9 +116,6 @@ export default {
|
||||
sessionStorage.setItem( 'cart', JSON.stringify( cart ) );
|
||||
}
|
||||
},
|
||||
closePlaceNotAvailablePopup () {
|
||||
$( '#placeNotAvailable' ).hide( 300 );
|
||||
},
|
||||
selectSeat( placeID, rowID ) {
|
||||
/*
|
||||
This function allows the user to select a seat and deselect it, if it has previously
|
||||
|
||||
@@ -209,7 +209,7 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
internal: {},
|
||||
categories: {},
|
||||
categories: { '1':{} },
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -219,7 +219,7 @@ export default {
|
||||
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 );
|
||||
this.internal[ value ][ info ] = Math.round( ( this.draggables[ value ][ info ] / this.scaleFactor ) * 1000 ) / 1000;
|
||||
} else {
|
||||
this.internal[ value ][ info ] = this.draggables[ value ][ info ];
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
<div id="window">
|
||||
<!-- TODO: Add additional div with v-if to check if a location has been selected and warn if not so. -->
|
||||
<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" id="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"
|
||||
v-model:active="draggable.active" v-model:draggable="draggable.draggable" :resizable="draggable.resizable" :parent="true" @activated="activateComponent( draggable.id );"
|
||||
@drag-end="saveHistory();" @resize-end="saveHistory();" @contextmenu="( e ) => { e.preventDefault(); }" class="draggable-box">
|
||||
<circularSeatplanComponent v-if="draggable.shape == 'circular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"></circularSeatplanComponent>
|
||||
<trapezoidSeatplanComponent 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"></trapezoidSeatplanComponent>
|
||||
<rectangularSeatplanComponent v-else-if="draggable.shape == 'rectangular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></rectangularSeatplanComponent>
|
||||
<circularSeatplanComponent v-if="draggable.shape == 'circular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow" :id="draggable.id" @seatingInfo="( info ) => { handleSeatCountInfo( info ); }"></circularSeatplanComponent>
|
||||
<trapezoidSeatplanComponent 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" :id="draggable.id" @seatingInfo="( info ) => { handleSeatCountInfo( info ); }"></trapezoidSeatplanComponent>
|
||||
<rectangularSeatplanComponent v-else-if="draggable.shape == 'rectangular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :id="draggable.id" @seatingInfo="( info ) => { handleSeatCountInfo( info ); }"></rectangularSeatplanComponent>
|
||||
<stagesSeatplanComponent v-else-if="draggable.type == 'stage'" :origin="draggable.origin" :shape="draggable.shape"></stagesSeatplanComponent>
|
||||
<standingSeatplanComponent v-else-if="draggable.type == 'stand'" :origin="draggable.origin" :shape="draggable.shape"></standingSeatplanComponent>
|
||||
<textFieldSeatplanComponent v-else-if="draggable.type == 'text'" :text="draggable.text.text" :text-size="draggable.text.textSize" :colour="draggable.text.colour" :origin="draggable.origin" :scale-factor="scaleFactor"></textFieldSeatplanComponent>
|
||||
@@ -79,6 +79,7 @@
|
||||
zoomFactor: 1,
|
||||
historyPos: 0,
|
||||
generalSettings: { 'namingScheme': 'numeric' },
|
||||
seatCountInfo: { 'data': {}, 'count': 0 },
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -184,7 +185,7 @@
|
||||
returnArray[ entry ] = {};
|
||||
for ( let attributes in valueArray[ entry ] ) {
|
||||
if ( allowedAttributes.includes( attributes ) ) {
|
||||
returnArray[ entry ][ attributes ] = Math.round( valueArray[ entry ][ attributes ] / this.scaleFactor );
|
||||
returnArray[ entry ][ attributes ] = Math.round( ( valueArray[ entry ][ attributes ] / this.scaleFactor ) * 1000 ) / 1000;
|
||||
} else {
|
||||
returnArray[ entry ][ attributes ] = valueArray[ entry ][ attributes ];
|
||||
}
|
||||
@@ -199,7 +200,7 @@
|
||||
returnArray[ entry ] = {};
|
||||
for ( let attributes in valueArray[ entry ] ) {
|
||||
if ( allowedAttributes.includes( attributes ) ) {
|
||||
returnArray[ entry ][ attributes ] = valueArray[ entry ][ attributes ] * this.scaleFactor;
|
||||
returnArray[ entry ][ attributes ] = Math.round( ( valueArray[ entry ][ attributes ] * this.scaleFactor ) * 1000 ) / 1000;
|
||||
} else {
|
||||
returnArray[ entry ][ attributes ] = valueArray[ entry ][ attributes ];
|
||||
}
|
||||
@@ -262,6 +263,7 @@
|
||||
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
||||
},
|
||||
saveDraft () {
|
||||
// TODO: Save seat count and seat config to server as well
|
||||
let progressNotification = this.$refs.notification.createNotification( 'Saving as draft', 5, 'progress', 'normal' );
|
||||
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
||||
this.$refs.notification.createNotification( 'Saved as draft', 5, 'ok', 'normal' );
|
||||
@@ -275,6 +277,8 @@
|
||||
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, 'seatCountingStartingPoint': 0, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' }, 'ticketCount': 1 };
|
||||
this.saveHistory();
|
||||
document.getElementById( 'parent' ).scrollTop = 0;
|
||||
document.getElementById( 'parent' ).scrollLeft = 0;
|
||||
this.$refs.notification.createNotification( 'New component added successfully', 5, 'ok', 'normal' );
|
||||
},
|
||||
deleteSelected () {
|
||||
@@ -314,8 +318,11 @@
|
||||
this.loadSeatplan();
|
||||
}
|
||||
},
|
||||
handleSeatCountInfo ( info ) {
|
||||
this.seatCountInfo[ 'data' ][ info.id ] = info.data;
|
||||
},
|
||||
getSeatCount () {
|
||||
console.log( 'Seat count is: ' + document.getElementsByClassName( 'seats' ).length );
|
||||
this.seatCountInfo[ 'count' ] = document.getElementsByClassName( 'seats' ).length;
|
||||
},
|
||||
},
|
||||
created () {
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -44,6 +44,10 @@ export default {
|
||||
startingRow: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -58,10 +62,12 @@ export default {
|
||||
let w = Math.round( this.w / this.scaleFactor );
|
||||
let h = Math.round( this.h / this.scaleFactor );
|
||||
const size = 33;
|
||||
let count = Math.min( Math.floor( w / size ), Math.floor( h / size ) );
|
||||
let count = Math.min( Math.floor( w / size ), Math.floor( h / size ) );
|
||||
this.seats = {};
|
||||
let details = { 'data': {}, 'id': this.id };
|
||||
for ( let row = this.startingRow; row < count; row++ ) {
|
||||
let nn = row * ( Math.PI / 2 );
|
||||
details.data[ row ] = Math.floor( nn );
|
||||
let r = row * size;
|
||||
this.seats[ row ] = {};
|
||||
for ( let n = 0; n < nn; n++ ) {
|
||||
@@ -77,6 +83,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$emit( 'seatingInfo', details );
|
||||
},
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
|
||||
@@ -41,6 +41,10 @@ export default {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -55,6 +59,7 @@ export default {
|
||||
let h = Math.floor( this.h / this.scaleFactor );
|
||||
const size = 33;
|
||||
this.seats = {};
|
||||
let details = { 'data': { '0': Math.floor( w / size ) }, 'id': this.id };
|
||||
for ( let row = 0; row < Math.floor( h / size ); row++ ) {
|
||||
this.seats[ row ] = {};
|
||||
for ( let n = 0; n < Math.floor( w / size ); n++ ) {
|
||||
@@ -69,6 +74,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$emit( 'seatingInfo', details );
|
||||
},
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
|
||||
@@ -44,6 +44,10 @@ export default {
|
||||
startingRow: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -64,9 +68,11 @@ export default {
|
||||
let count = Math.floor( heightTriangle / ( sideOffset * 2 ) );
|
||||
const angle = Math.PI / 4;
|
||||
this.seats = {};
|
||||
let details = { 'data': {}, 'id': this.id };
|
||||
for ( let row = this.startingRow; row < count; row++ ) {
|
||||
let nn = 2 + ( row - 1 ) * 2;
|
||||
this.seats[ row ] = {};
|
||||
details.data[ row ] = Math.floor( nn );
|
||||
for ( let n = 0; n < nn; n++ ) {
|
||||
let side = n * sideOffset;
|
||||
if ( this.origin === 1 ) {
|
||||
@@ -80,6 +86,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$emit( 'seatingInfo', details );
|
||||
},
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
|
||||
251
src/webapp/src/components/seatplan/userApp/userWindow.vue
Normal file
251
src/webapp/src/components/seatplan/userApp/userWindow.vue
Normal file
@@ -0,0 +1,251 @@
|
||||
<!--
|
||||
* libreevent - window.vue
|
||||
*
|
||||
* Created by Janis Hutz 05/12/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div id="window">
|
||||
<!-- TODO: Add additional div with v-if to check if a location has been selected and warn if not so. -->
|
||||
<div class="parent" id="parent">
|
||||
<div class="content-parent">
|
||||
<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" @contextmenu="( e ) => { e.preventDefault(); }" class="draggable-box">
|
||||
<circularSeatplanComponent v-if="draggable.shape == 'circular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"></circularSeatplanComponent>
|
||||
<trapezoidSeatplanComponent 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"></trapezoidSeatplanComponent>
|
||||
<rectangularSeatplanComponent v-else-if="draggable.shape == 'rectangular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></rectangularSeatplanComponent>
|
||||
<stagesSeatplanComponent v-else-if="draggable.type == 'stage'" :origin="draggable.origin" :shape="draggable.shape"></stagesSeatplanComponent>
|
||||
<standingSeatplanComponent v-else-if="draggable.type == 'stand'" :origin="draggable.origin" :shape="draggable.shape"></standingSeatplanComponent>
|
||||
<textFieldSeatplanComponent v-else-if="draggable.type == 'text'" :text="draggable.text.text" :text-size="draggable.text.textSize" :colour="draggable.text.colour" :origin="draggable.origin" :scale-factor="scaleFactor"></textFieldSeatplanComponent>
|
||||
</Vue3DraggableResizable>
|
||||
</div>
|
||||
</div>
|
||||
<notifications ref="notification" location="topleft"></notifications>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue3DraggableResizable from 'vue3-draggable-resizable';
|
||||
import circularSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/circular.vue';
|
||||
import rectangularSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/rectangular.vue';
|
||||
import trapezoidSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/trapezoid.vue';
|
||||
import stagesSeatplanComponent from '@/components/seatplan/seatplanComponents/stages.vue';
|
||||
import standingSeatplanComponent from '@/components/seatplan/seatplanComponents/standing.vue';
|
||||
import textFieldSeatplanComponent from '@/components/seatplan/seatplanComponents/textField.vue';
|
||||
import notifications from '@/components/notifications/notifications.vue';
|
||||
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css';
|
||||
|
||||
export default {
|
||||
'name': 'window',
|
||||
components: {
|
||||
Vue3DraggableResizable,
|
||||
circularSeatplanComponent,
|
||||
rectangularSeatplanComponent,
|
||||
trapezoidSeatplanComponent,
|
||||
stagesSeatplanComponent,
|
||||
standingSeatplanComponent,
|
||||
textFieldSeatplanComponent,
|
||||
notifications,
|
||||
},
|
||||
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, 'seatCountingStartingPoint': 1, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' } }, 'ticketCount': 1 },
|
||||
available: { 'redo': false, 'undo': false },
|
||||
scaleFactor: 1,
|
||||
sizePoll: null,
|
||||
prevSize: { 'h': window.innerHeight, 'w': window.innerWidth },
|
||||
zoomFactor: 1,
|
||||
historyPos: 0,
|
||||
generalSettings: { 'namingScheme': 'numeric' },
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/*
|
||||
Coords are from top left corner of box.
|
||||
The below function is executed as the init hook (created hook)
|
||||
of vue.js, so whenever this particular page is loaded.
|
||||
It loads previous data (if available) and starts the event listeners
|
||||
for keyevents (like delete) and also check if the user uses a desktop
|
||||
browser that meets all the requirements for being able to use the editor
|
||||
reliably according to testing done.
|
||||
*/
|
||||
runHook () {
|
||||
let self = this;
|
||||
this.zoomFactor = sessionStorage.getItem( 'zoom' ) ? parseFloat( sessionStorage.getItem( 'zoom' ) ) : 1;
|
||||
|
||||
/*
|
||||
Keybinds:
|
||||
- Delete: delete selected object
|
||||
- Ctrl + S: Save
|
||||
- Ctrl + Z: Undo
|
||||
- Ctrl + Y: Redo
|
||||
*/
|
||||
document.onkeydown = function ( event ) {
|
||||
if ( event.key === 'Delete' ) {
|
||||
event.preventDefault();
|
||||
self.deleteSelected();
|
||||
} else if ( event.ctrlKey && event.key === 's' ) {
|
||||
event.preventDefault();
|
||||
self.saveDraft();
|
||||
} else if ( ( event.ctrlKey && event.key === 'y' ) ) {
|
||||
event.preventDefault();
|
||||
self.historyOp( 'redo' );
|
||||
} else if ( event.ctrlKey && event.key === 'z' ) {
|
||||
event.preventDefault();
|
||||
self.historyOp( 'undo' );
|
||||
} else if ( event.ctrlKey && event.key === 'i' ) {
|
||||
event.preventDefault();
|
||||
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 );
|
||||
}
|
||||
};
|
||||
|
||||
this.loadSeatplan();
|
||||
// TODO: Add warning for untested browsers & suboptimal window sizes!
|
||||
},
|
||||
eventHandler ( e ) {
|
||||
if ( this.prevSize.h != window.innerHeight || this.prevSize.w != window.innerWidth ) {
|
||||
this.prevSize = { 'h': window.innerHeight, 'w': window.innerWidth };
|
||||
this.loadSeatplan();
|
||||
}
|
||||
},
|
||||
loadSeatplan () {
|
||||
/*
|
||||
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
|
||||
*/
|
||||
// TODO: load from server
|
||||
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;
|
||||
}
|
||||
}
|
||||
},
|
||||
scaleUp ( valueArray ) {
|
||||
const allowedAttributes = [ 'w', 'h', 'x', 'y' ]
|
||||
let returnArray = {};
|
||||
for ( let entry in valueArray ) {
|
||||
returnArray[ entry ] = {};
|
||||
for ( let attributes in valueArray[ entry ] ) {
|
||||
if ( allowedAttributes.includes( attributes ) ) {
|
||||
returnArray[ entry ][ attributes ] = Math.round( ( valueArray[ entry ][ attributes ] * this.scaleFactor ) * 1000 ) / 1000;
|
||||
} else {
|
||||
returnArray[ entry ][ attributes ] = valueArray[ entry ][ attributes ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnArray;
|
||||
},
|
||||
handleUpdate ( value ) {
|
||||
this.draggables = value;
|
||||
this.selectedObject = value;
|
||||
this.saveHistory();
|
||||
},
|
||||
zoom ( scale ) {
|
||||
if ( scale == 1 ) {
|
||||
this.zoomFactor = 1;
|
||||
sessionStorage.setItem( 'zoom', this.zoomFactor );
|
||||
this.loadSeatplan();
|
||||
} else {
|
||||
if ( ( this.zoomFactor < 0.3 && scale < 0 ) || ( this.zoomFactor > 2.9 && scale > 0 ) ) {
|
||||
if ( this.zoomFactor < 0.3 ) {
|
||||
this.$refs.notification.createNotification( 'Minimum zoom factor reached', 5, 'warning', 'normal' );
|
||||
} else {
|
||||
this.$refs.notification.createNotification( 'Maximum zoom factor reached', 5, 'warning', 'normal' );
|
||||
}
|
||||
} else {
|
||||
this.zoomFactor += scale;
|
||||
}
|
||||
sessionStorage.setItem( 'zoom', this.zoomFactor );
|
||||
this.loadSeatplan();
|
||||
}
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.runHook();
|
||||
this.sizePoll = setInterval( this.eventHandler, 250 );
|
||||
},
|
||||
unmounted() {
|
||||
clearInterval( this.sizePoll );
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.parent {
|
||||
height: 90vh;
|
||||
aspect-ratio: 16 / 9;
|
||||
top: 7.5vh;
|
||||
left: 3vw;
|
||||
position: absolute;
|
||||
border: black 1px solid;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.draggable-box {
|
||||
cursor: all-scroll;
|
||||
}
|
||||
|
||||
.properties {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
background-color: var( --accent-background );
|
||||
color: var( --secondary-color );
|
||||
width: 20vw;
|
||||
height: 90vh;
|
||||
top: 7.5vh;
|
||||
right: 0.5vw;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.content-parent {
|
||||
aspect-ratio: 16 / 9;
|
||||
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>
|
||||
@@ -10,7 +10,7 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useUserStore = defineStore ( 'user', {
|
||||
state: () => ( { 'isUserAuth': true, 'isAdminAuth': true, 'userPermissions': {} } ),
|
||||
state: () => ( { 'isUserAuth': true, 'isAdminAuth': true, 'userData': {} } ),
|
||||
getters: {
|
||||
getUserAuthenticated: ( state ) => state.isUserAuth,
|
||||
getAdminAuthenticated: ( state ) => state.isAdminAuth,
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
<nav class="side-nav">
|
||||
<div class="side-nav-wrapper">
|
||||
<img src="@/assets/logo.png" alt="libreevent logo" style="width: 80%; margin-left: 10%; margin-bottom: 5%;">
|
||||
<router-link to="/admin" class="admin-menu" @click="navMenu( 'hide' )">Home</router-link>
|
||||
<router-link to="/admin/pages" class="admin-menu" @click="navMenu( 'hide' )">Pages</router-link>
|
||||
<router-link to="/admin/events" class="admin-menu" @click="navMenu( 'hide' )">Events</router-link>
|
||||
<router-link to="/admin/locations" class="admin-menu" @click="navMenu( 'hide' )">Locations</router-link>
|
||||
<router-link to="/admin/plugins" class="admin-menu" @click="navMenu( 'hide' )">Plugins</router-link>
|
||||
<router-link to="/admin/settings" class="admin-menu" @click="navMenu( 'hide' )">Settings</router-link>
|
||||
<button to="/admin/login" class="admin-menu" @click="logout()">Logout</button>
|
||||
<router-link to="/admin" class="admin-menu" @click="navMenu( 'hide' )" title="The home page of the admin panel">Home</router-link>
|
||||
<router-link to="/admin/pages" class="admin-menu" @click="navMenu( 'hide' )" title="Modify your landing page, your terms of service, etc.">Pages</router-link>
|
||||
<router-link to="/admin/events" class="admin-menu" @click="navMenu( 'hide' )" title="Change, view and analyse everything about your events">Events</router-link>
|
||||
<router-link to="/admin/locations" class="admin-menu" @click="navMenu( 'hide' )" title="Change settings about your event locations">Locations</router-link>
|
||||
<router-link to="/admin/plugins" class="admin-menu" @click="navMenu( 'hide' )" title="Install, Uninstall and manage plugins">Plugins</router-link>
|
||||
<router-link to="/admin/settings" class="admin-menu" @click="navMenu( 'hide' )" title="Change global settings for libreevent">Settings</router-link>
|
||||
<button to="/admin/login" class="admin-menu" @click="logout()" title="Log out of the admin panel">Logout</button>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="backdrop" @click="navMenu( 'hide' )"></div>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<div>
|
||||
<h2>Locations</h2>
|
||||
<p>Here you can change everything regarding event locations. All locations can have a seating plan.</p>
|
||||
<button @click="addLocation();">Add new location</button>
|
||||
<div class="location-app" v-if="Object.keys( locations ).length">
|
||||
<ul>
|
||||
<li v-for="location in locations">
|
||||
@@ -28,6 +29,7 @@
|
||||
No locations configured, please <b @click="addLocation();" style="cursor: pointer;">add</b> one
|
||||
</div>
|
||||
<popups ref="popup" size="big"></popups>
|
||||
<popups ref="popup2" size="huge"></popups>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -75,7 +77,33 @@
|
||||
, 'settings' );
|
||||
},
|
||||
addLocation () {
|
||||
|
||||
this.$refs.popup.openPopup( 'Add a new location', {
|
||||
'locationName': {
|
||||
'display': 'Location name',
|
||||
'id': 'locationName',
|
||||
'tooltip':'Give the location the event takes place a name. This name will also be shown to customers',
|
||||
'value': '',
|
||||
'type': 'text',
|
||||
},
|
||||
'usesSeatplan': {
|
||||
'display': 'Use seat plan?',
|
||||
'id': 'usesSeatplan',
|
||||
'tooltip':'With this toggle you may specify whether or not this location has a seat plan or not.',
|
||||
'value': true,
|
||||
'type': 'toggle',
|
||||
},
|
||||
'seatplanEditor': {
|
||||
'display': 'Seat plan editor',
|
||||
'id': 'seatplanEditor',
|
||||
'tooltip':'The seat plan editor allows you to create a seat plan that closely resembles the location you host the event in.',
|
||||
'type': 'link',
|
||||
'restrictions': {
|
||||
'to': '/admin/seatplan',
|
||||
'displayName': 'Edit seat plan'
|
||||
}
|
||||
},
|
||||
}
|
||||
, 'settings' );
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,19 +11,37 @@
|
||||
<div>
|
||||
<h2>Settings</h2>
|
||||
<settings v-model:settings="settings"></settings>
|
||||
<p>Detailed explanation of payment gateways can be found <a href="https://libreevent.janishutz.com/docs/payments" target="_blank">here</a>. You may install more payment gateway integrations in the plugins section.</p>
|
||||
|
||||
<div class="admin-settings">
|
||||
<h2>Admin Accounts</h2>
|
||||
<p>Before setting or editing permissions here, please read the corresponding section of the documentation <a href="https://libreevent.janishutz.com/docs/admin-panel/settings/admin-accounts#permissions" target="_blank">here</a>.
|
||||
<br>Usually, the permissions automatically set by the system on account creation should be appropriate.</p>
|
||||
<div v-for="account in adminAccounts" class="account" @click="showAccountSettings( account.username );" title="Edit permissions of this account">
|
||||
<div class="location-name">
|
||||
<h3>{{ account.username }}</h3>
|
||||
<p>{{ account.email }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<popups ref="popup" size="big"></popups>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import settings from '@/components/settings/settings.vue';
|
||||
import popups from '@/components/notifications/popups.vue';
|
||||
|
||||
export default {
|
||||
name: 'adminSettingsView',
|
||||
components: {
|
||||
settings,
|
||||
popups,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
adminAccounts: { 'janis': { 'username': 'janis', 'email': 'info@janishutz.com', 'permissions': [ ] }, 'admin': { 'username': 'admin', 'email': 'development@janishutz.com', 'permissions': [ ] } },
|
||||
settings: {
|
||||
'2fa': {
|
||||
'display': 'Require Two-Factor-Authentication of user',
|
||||
@@ -45,9 +63,123 @@
|
||||
'value': 'never'
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
'addressRequired': {
|
||||
'display': 'Require user to provide address?',
|
||||
'id': 'addressRequired',
|
||||
'tooltip':'With this toggle you may specify whether or not a user has to provide their address when purchasing something. (Keep GDPR in mind when processing data!)',
|
||||
'value': false,
|
||||
'type': 'toggle',
|
||||
},
|
||||
'phoneNumberRequired': {
|
||||
'display': 'Require user to provide address?',
|
||||
'id': 'phoneNumberRequired',
|
||||
'tooltip':'With this toggle you may specify whether or not a user has to provide their address when purchasing something. (Keep GDPR in mind when processing data!)',
|
||||
'value': false,
|
||||
'type': 'toggle',
|
||||
},
|
||||
'paymentGateway': {
|
||||
'display': 'Select the payment gateway to use',
|
||||
'id': 'paymentGateway',
|
||||
'tooltip':'With this setting you may change which payment gateway you want to use. You will need to provide details below! If you are not sure what this setting means, please click the link below.',
|
||||
'value': 'stripe',
|
||||
'type': 'select',
|
||||
'restrictions': {
|
||||
'stripe': {
|
||||
'displayName':'Stripe',
|
||||
'value': 'stripe'
|
||||
},
|
||||
'adyen': {
|
||||
'displayName':'Adyen',
|
||||
'value': 'adyen'
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showAccountSettings ( account ) {
|
||||
this.$refs.popup.openPopup( 'Edit user permissions for ' + this.adminAccounts[ account ][ 'username' ], {
|
||||
'pagesSettings': {
|
||||
'display': 'Modify pages',
|
||||
'id': 'pagesSettings',
|
||||
'tooltip':'Change this setting to allow or disallow the selected user to access and change any settings of pages like the start page.',
|
||||
'value': false,
|
||||
'type': 'toggle',
|
||||
},
|
||||
'locationsSettings': {
|
||||
'display': 'Location settings and seat plans',
|
||||
'id': 'locationsSettings',
|
||||
'tooltip':'Change this setting to allow or disallow the selected user to modify, delete or create locations with their corresponding seat plans.',
|
||||
'value': false,
|
||||
'type': 'toggle',
|
||||
},
|
||||
'plugins': {
|
||||
'display': 'Plugin management',
|
||||
'id': 'plugins',
|
||||
'tooltip':'Change this setting to allow or disallow the selected user to install or uninstall plugins. Some plugins might allow you to set extra permissions inside of their settings panels',
|
||||
'value': false,
|
||||
'type': 'toggle',
|
||||
},
|
||||
'events': {
|
||||
'display': 'Event management',
|
||||
'id': 'events',
|
||||
'tooltip':'Change this setting to allow or disallow the selected user to install or uninstall plugins. Some plugins might allow you to set extra permissions inside of their settings panels',
|
||||
'value': false,
|
||||
'type': 'toggle',
|
||||
},
|
||||
'entryControl': {
|
||||
'display': 'Entry control',
|
||||
'id': 'entryControl',
|
||||
'tooltip':'Change this setting to allow or disallow the selected user to execute entry control at the entrance to your event location.',
|
||||
'value': true,
|
||||
'type': 'toggle',
|
||||
},
|
||||
}
|
||||
, 'settings' );
|
||||
}
|
||||
}
|
||||
};
|
||||
// TODO: Load gateways and settings in general from server.
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.admin-settings {
|
||||
text-align: justify;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.account {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
color: var( --primary-color );
|
||||
border-color: var( --primary-color );
|
||||
border-width: 1px;
|
||||
height: fit-content;
|
||||
border-style: solid;
|
||||
padding: 10px;
|
||||
transition: 0.4s;
|
||||
cursor: pointer;
|
||||
width: 60%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.account:hover {
|
||||
background-color: var( --hover-color );
|
||||
transition: 0.4s;
|
||||
}
|
||||
|
||||
.location-name {
|
||||
margin-right: auto;
|
||||
max-width: 35%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user