mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 05:14:23 +00:00
popups, fixes, location editing
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
# Account view:
|
||||
- Load: email, settings, change pw, change mail, see all tickets
|
||||
|
||||
- set page title based on settings
|
||||
- set page title based on settings
|
||||
|
||||
- make pricing groups changeable in UI (event categories)
|
||||
@@ -32,7 +32,7 @@
|
||||
--accent-color: #42b983;
|
||||
--hover-color: rgb(165, 165, 165);
|
||||
--accent-background-hover: #4380a8;
|
||||
--overlay-color: rgba(37, 37, 37, 0.575);
|
||||
--overlay-color: rgba(0, 0, 0, 0.7);
|
||||
--inactive-color: rgb(100, 100, 100);
|
||||
--highlight-backdrop: rgb(143, 134, 192);
|
||||
--PI: 3.14159265358979;
|
||||
|
||||
@@ -1,131 +1,100 @@
|
||||
<template>
|
||||
<div id="notifications" @click="handleNotifications();">
|
||||
<div class="message-box" :class="messageType">
|
||||
<div class="message-container">
|
||||
<span class="material-symbols-outlined types" v-if="messageType == 'ok'" style="background-color: green;">done</span>
|
||||
<span class="material-symbols-outlined types" v-else-if="messageType == 'error'" style="background-color: red;">close</span>
|
||||
<span class="material-symbols-outlined types progress-spinner" v-else-if="messageType == 'progress'" style="background-color: blue;">progress_activity</span>
|
||||
<span class="material-symbols-outlined types" v-else-if="messageType == 'info'" style="background-color: lightblue;">info</span>
|
||||
<p class="message">{{ message }}</p>
|
||||
<div id="popup-backdrop" :class="status">
|
||||
<div class="popup-container">
|
||||
<div class="popup" :class="size">
|
||||
<span class="material-symbols-outlined" @click="closePopup();">close</span>
|
||||
<div class="message-container">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Options to be passed in: HTML, Settings (for settings component), strings, numbers, confirm, radio, dropdowns, selection -->
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'notifications',
|
||||
name: 'popups',
|
||||
prop: {
|
||||
size: {
|
||||
type: String,
|
||||
'default': 'normal',
|
||||
},
|
||||
message: {
|
||||
type: Object,
|
||||
'default': '{}',
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
notifications: {},
|
||||
queue: [],
|
||||
message: '',
|
||||
messageType: 'hide',
|
||||
notificationDisplayTime: 1,
|
||||
notificationPriority: 'normal',
|
||||
currentlyDisplayedNotificationID: 0,
|
||||
currentID: { 'critical': 0, 'medium': 1000, 'low': 100000 },
|
||||
displayTimeCurrentNotification: 0,
|
||||
notificationScheduler: null,
|
||||
status: 'hidden',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createNotification( message, showDuration, messageType, priority ) {
|
||||
/*
|
||||
Takes a notification options array that contains: message, showDuration (in seconds), messageType (ok, error, progress, info) and priority (low, medium, critical).
|
||||
Returns a notification ID which can be used to cancel the notification. The component will throttle notifications and display
|
||||
one at a time and prioritize messages with higher priority. Use vue refs to access these methods.
|
||||
*/
|
||||
let id = 0;
|
||||
closePopup() {
|
||||
this.shown = 'hidden'
|
||||
},
|
||||
openPopup () {
|
||||
|
||||
if ( priority === 'critical' ) {
|
||||
this.currentID[ 'critical' ] += 1;
|
||||
id = this.currentID[ 'critical' ];
|
||||
} else if ( priority === 'normal' ) {
|
||||
this.currentID[ 'medium' ] += 1;
|
||||
id = this.currentID[ 'medium' ];
|
||||
} else if ( priority === 'low' ) {
|
||||
this.currentID[ 'low' ] += 1;
|
||||
id = this.currentID[ 'low' ];
|
||||
}
|
||||
this.notifications[ id ] = { 'message': message, 'showDuration': showDuration, 'messageType': messageType, 'priority': priority };
|
||||
this.queue.push( id );
|
||||
console.log( 'scheduled notification: ' + id + ' (' + message + ')' );
|
||||
return id;
|
||||
},
|
||||
cancelNotification ( id ) {
|
||||
/*
|
||||
This method deletes a notification and, in case the notification is being displayed, hides it.
|
||||
*/
|
||||
delete notifications[ id ];
|
||||
delete this.queue[ this.queue.findIndex( id ) ];
|
||||
if ( this.currentlyDisplayedNotificationID == id ) {
|
||||
this.handleNotifications();
|
||||
}
|
||||
},
|
||||
handleNotifications () {
|
||||
/*
|
||||
This methods should NOT be called in any other component than this one!
|
||||
*/
|
||||
this.displayTimeCurrentNotification = 0;
|
||||
this.queue.sort();
|
||||
if ( this.queue.length > 0 ) {
|
||||
this.message = this.notifications[ this.queue[ 0 ] ][ 'message' ];
|
||||
this.messageType = this.notifications[ this.queue[ 0 ] ][ 'messageType' ];
|
||||
this.priority = this.notifications[ this.queue[ 0 ] ][ 'priority' ];
|
||||
this.notificationDisplayTime = this.notifications[ this.queue[ 0 ] ][ 'showDuration' ];
|
||||
this.queue.reverse();
|
||||
this.queue.pop();
|
||||
} else {
|
||||
this.messageType = 'hide';
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.notificationScheduler = setInterval( () => {
|
||||
if ( this.displayTimeCurrentNotification >= this.notificationDisplayTime ) {
|
||||
this.handleNotifications();
|
||||
} else {
|
||||
this.displayTimeCurrentNotification += 0.5;
|
||||
}
|
||||
}, 500 );
|
||||
},
|
||||
unmounted ( ) {
|
||||
clearInterval( this.notificationScheduler );
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.message-box {
|
||||
#popup-backdrop {
|
||||
position: fixed;
|
||||
left: 0.5%;
|
||||
z-index: 5;
|
||||
top: 3%;
|
||||
color: white;
|
||||
height: 10vh;
|
||||
width: 15vw;
|
||||
opacity: 1;
|
||||
transition: all 0.5s;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: var( --overlay-color );
|
||||
display: none;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
.shown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.popup-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.types {
|
||||
color: white;
|
||||
border-radius: 100%;
|
||||
margin-right: auto;
|
||||
margin-left: 5%;
|
||||
font-size: 200%;
|
||||
.popup {
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
background-color: var( --popup-color );
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-right: 5%;
|
||||
.small {
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
}
|
||||
|
||||
.normal {
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.big {
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
}
|
||||
|
||||
.bigger {
|
||||
width: 70%;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.huge {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
}
|
||||
</style>
|
||||
@@ -80,5 +80,14 @@ export default {
|
||||
adminAuthRequired: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'locations/view',
|
||||
name: 'locationDetails',
|
||||
component: () => import( '../views/admin/locations/LocationEditView.vue' ),
|
||||
meta: {
|
||||
title: 'Admin - libreevent',
|
||||
adminAuthRequired: true,
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -11,7 +11,22 @@
|
||||
<div>
|
||||
<h2>Locations</h2>
|
||||
<p>Here you can change everything regarding event locations. All locations can have a seating plan.</p>
|
||||
<div class="bigButtons"></div>
|
||||
<div class="location-app" v-if="Object.keys( locations ).length">
|
||||
<ul>
|
||||
<li v-for="location in locations">
|
||||
<router-link to="/admin/locations/view" class="location" @click="selectLocation( location.locationID );">
|
||||
<div class="location-name">
|
||||
<h3>{{ location.name }}</h3>
|
||||
<p v-if="location['seatplan-enabled']">This location has a seatplan.</p>
|
||||
<p v-else>This location has NO seatplan.</p>
|
||||
</div>
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-else class="no-location-hint">
|
||||
No locations configured, please <b @click="addLocation();" style="cursor: pointer;">add</b> one
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -19,13 +34,57 @@
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
formData: {}
|
||||
locations: { 'test':{ 'name':'TestLocation', 'locationID':'test', 'seatplan-enabled': true, 'seatplan': {} } },
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setup () {
|
||||
|
||||
}
|
||||
selectLocation ( locationID ) {
|
||||
sessionStorage.setItem( 'locationID', locationID );
|
||||
},
|
||||
addLocation () {
|
||||
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.location-app {
|
||||
text-align: justify;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.location {
|
||||
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;
|
||||
}
|
||||
|
||||
.location:hover {
|
||||
background-color: var( --hover-color );
|
||||
transition: 0.4s;
|
||||
}
|
||||
|
||||
.location-name {
|
||||
margin-right: auto;
|
||||
max-width: 35%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2>Seatplan Editor</h2>
|
||||
<h2>Seat Plan Editor</h2>
|
||||
<window />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
84
src/webapp/src/views/admin/locations/LocationEditView.vue
Normal file
84
src/webapp/src/views/admin/locations/LocationEditView.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<!--
|
||||
* libreevent - TicketsDetailsView.vue
|
||||
*
|
||||
* Created by Janis Hutz 05/14/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="details">
|
||||
<h2>{{ event.name }}</h2>
|
||||
<div class="category-wrapper">
|
||||
<table class="category">
|
||||
<tr>
|
||||
<td>Location name</td>
|
||||
<td>
|
||||
<input type="text" v-model="event.name">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Seat plan editor</td>
|
||||
<router-link to="/admin/seatplan">Edit seat plan</router-link>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<popups ref="popup"></popups>
|
||||
<notifications ref="notification" location="topright"></notifications>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.details {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.ticket-settings {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.category-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.category {
|
||||
width: 50%;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.category-details {
|
||||
margin-left: 7%;;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import settings from '@/components/settings/settings.vue';
|
||||
import notifications from '@/components/notifications/notifications.vue';
|
||||
import popups from '@/components/notifications/popups.vue';
|
||||
|
||||
export default {
|
||||
name: 'TicketsDetailsView',
|
||||
components: {
|
||||
settings,
|
||||
notifications,
|
||||
popups,
|
||||
},
|
||||
created () {
|
||||
if ( !sessionStorage.getItem( 'selectedTicket' ) ) {
|
||||
this.$router.push( '/admin/events' );
|
||||
}
|
||||
this.eventID = sessionStorage.getItem( 'selectedTicket' );
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
event: { 'name': 'TestEvent', 'description': 'This is a description for the TestEvent to test multiline support and proper positioning of the Fields', 'freeSeats': 2, 'maxSeats': 2, 'date':'TestDate', 'startingPrice':15, 'location': 'TestLocation', 'eventID': 'test', 'currency': 'CHF', 'logo': 'logo.png', 'categories': { '1': { 'price': { '1': { 'price':25, 'name':'Child (0-15.99 years)'}, '2': { 'price':35, 'name':'Adult'} }, 'bg': 'black', 'fg': 'white', 'name': 'Category 1' }, '2': { 'price': { '1': { 'price':25, 'name':'Child (0-15.99 years)' }, '2': { 'price':35, 'name':'Adult'} }, 'bg': 'green', 'fg': 'white', 'name': 'Category 2' } } },
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user