ticket gen working + various changes

This commit is contained in:
janishutz committed 2023-08-07 12:24:52 +02:00
1 parent 5cbf624284
commit ed38edd880
24 files changed
+211 -98

No files matched your search

+7 -3
View File
@@ -3,11 +3,13 @@
- make pricing groups changeable in UI (event categories)
- create function that parses DB every 15 minutes and clears out junk
- create function that parses DB every 15 minutes and clears out junk --> Also update data in db when user goes to purchase to prevent clearing during purchase
- Require user to confirm email before purchasing
- Guest purchase in the future (remove from matura shit)
- Guest purchase in the future (maybe remove from matura)
- Create password changing endpoint (to reset forgotten pwd)
- Add Admin profile (page to change account settings per person like changing pwd)
@@ -19,7 +21,9 @@
- Implement Permission system
- Seat numbering
- Seat numbering!!
- Add localization for date
- add webpack (or any other minifying tool) to project website to decrease file size (OPTIONAL)
@@ -169,7 +169,7 @@
} );
if ( !sessionStorage.getItem( 'seatplan-history' ) ) {
sessionStorage.setItem( 'seatplaTODO:n-history', JSON.stringify( { '1': this.scaleDown( this.draggables ) } ) );
sessionStorage.setItem( 'seatplan-history', JSON.stringify( { '1': this.scaleDown( this.draggables ) } ) );
}
let history = sessionStorage.getItem( 'seatplan-history' ) ? JSON.parse( sessionStorage.getItem( 'seatplan-history' ) ) : {};
@@ -9,7 +9,6 @@
<template>
<div id="window">
<h2>Seat plan: {{ event.name }}</h2>
<div class="parent" id="parent" @wheel="( e ) => { handleScroll( e ); }" @mousemove="( e ) => { handleDrag( e ); }" @mousedown="( e ) => { setOffset( e ); }">
<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"
@@ -42,7 +41,7 @@
<button title="Reset zoom [=]" @click="zoom( 1 );"><span class="material-symbols-outlined">center_focus_strong</span></button>
<button title="Zoom out [-]" @click="zoom( -0.2 )"><span class="material-symbols-outlined">zoom_out</span></button>
</div>
<sideCartView :cart="cart" ref="cart"></sideCartView>
<sideCartView :cart="cart" :name="event.name" ref="cart"></sideCartView>
<notifications ref="notification" location="topright"></notifications>
<popups ref="popups" size="normal" @data="data => { reserveTicket( data ) }"
@ticket="data => { standingTicketHandling( data ) }"></popups>
@@ -156,7 +155,6 @@
}
this.seatChecks();
// TODO: Optimise for odd screen sizes and aspect ratios and fucking webkit
// TODO: Trim scroll box to about 200px more than seatplan size
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
window.addEventListener( 'visibilitychange', ( e ) => {
@@ -171,15 +169,6 @@
if ( res.status === 200 ) {
let unavailableSeats = {};
res.json().then( data => {
for ( let seat in data.booked ) {
if ( data.booked[ seat ] ) {
if ( !unavailableSeats[ data.booked[ seat ].component ] ) {
unavailableSeats[ data.booked[ seat ].component ];
}
unavailableSeats[ data.booked[ seat ].component ][ data.booked[ seat ].id ] = 'nav';
}
}
for ( let seat in data.reserved ) {
if ( data.reserved[ seat ] ) {
if ( !unavailableSeats[ data.reserved[ seat ].component ] ) {
@@ -198,6 +187,15 @@
}
}
for ( let seat in data.booked ) {
if ( data.booked[ seat ] ) {
if ( !unavailableSeats[ data.booked[ seat ].component ] ) {
unavailableSeats[ data.booked[ seat ].component ];
}
unavailableSeats[ data.booked[ seat ].component ][ data.booked[ seat ].id ] = 'nav';
}
}
let tickets = {};
if ( this.cart[ this.event.eventID ] ) {
tickets = this.cart[ this.event.eventID ][ 'tickets' ];
@@ -449,8 +447,7 @@
if ( data.data[ group ] > 0 ) {
const options = {
method: 'post',
// TODO: Add correct name here as well once it is working at all
body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'component': data.component, 'ticketOption': '', 'eventID': this.event.eventID, 'count': data.data[ group ], 'category': this.draggables[ data.component ].category, 'name': 'Ticket ' } ),
body: JSON.stringify( { 'id': 'ticket' + data.component + '_' + group, 'component': data.component, 'ticketOption': group, 'eventID': this.event.eventID, 'count': data.data[ group ], 'category': this.draggables[ data.component ].category, 'name': 'Ticket ' + data.component + ' (' + this.event.ageGroups[ group ].name + ')' } ),
headers: {
'Content-Type': 'application/json',
'charset': 'utf-8'
@@ -510,7 +507,7 @@
.parent {
height: 80vh;
width: 70vw;
top: 17vh;
top: 90px;
left: 5vw;
position: absolute;
border: black 1px solid;
@@ -548,7 +545,7 @@
.toolbar {
display: flex;
position: fixed;
top: 17vh;
top: 90px;
left: 5.5vw;
}
.toolbar button {
@@ -9,6 +9,7 @@
<template>
<div id="sideCartView">
<h1>Seat plan: {{ name }}</h1>
<h2>Cart</h2>
<div v-if="Object.keys( cart ).length > 0" style="height: 100%; width: 100%;">
<div class="scroll-wrapper">
@@ -64,6 +65,10 @@ export default {
'height': {
type: Number,
default: 17
},
'name': {
type: String,
default: ''
}
},
data() {
@@ -92,7 +97,7 @@ export default {
position: fixed;
right: 0;
height: 100vh;
top: 17vh;
top: 90px;
width: 25vw;
background-color: var( --accent-background );
color: var( --secondary-color );
@@ -21,7 +21,7 @@
</td>
</tr>
</table>
<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>
<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. Only one may be used at any given time.</p>
<div class="admin-settings">
<h2>Admin Accounts</h2>
@@ -103,8 +103,8 @@
'value': 'stripe'
},
'adyen': {
'displayName':'Adyen',
'value': 'adyen'
'displayName':'Payrexx',
'value': 'payrexx'
},
}
},
@@ -8,7 +8,6 @@
</form>
<button @click="loadPDF();" class="toolbar-item">Load file</button>
<button @click="saveTemplate()" class="toolbar-item" title="Save your ticket">Save Template</button>
<button @click="testNotifications();" class="toolbar-item">Test notifications</button>
</div>
<div id="editor">Loading editor...</div>
<notifications ref="notification" location="topleft"></notifications>
@@ -16,7 +15,7 @@
</template>
<script>
import { Designer, BLANK_PDF } from '@pdfme/ui';
import { Designer } from '@pdfme/ui';
import notifications from '@/components/notifications/notifications.vue';
export default {
@@ -31,8 +30,7 @@
},
methods: {
saveTemplate() {
// Save to server instead
this.$refs.notification.createNotification( 'Saving...', 5, 'progress', 'normal' );
const saving = this.$refs.notification.createNotification( 'Saving...', 5, 'progress', 'normal' );
let fetchOptions = {
method: 'post',
body: JSON.stringify( { 'location': sessionStorage.getItem( 'selectedTicket' ), 'data': this.designer.getTemplate() } ),
@@ -44,21 +42,12 @@
fetch( '/admin/api/saveTickets', fetchOptions ).then( res => {
if ( res.status === 200 ) {
res.text().then( text => {
// TODO: Finish up
console.log( text );
res.text().then( () => {
this.$refs.notification.cancelNotification( saving );
this.$refs.notification.createNotification( 'Saved successfully', 5, 'ok', 'normal' );
} );
}
} );
console.log( this.designer.getTemplate() );
},
testNotifications () {
this.$refs.notification.createNotification( 'Warning', 10, 'warning', 'normal' );
this.$refs.notification.createNotification( 'Error', 10, 'error', 'normal' );
this.$refs.notification.createNotification( 'Info', 10, 'info', 'normal' );
this.$refs.notification.createNotification( 'Ok', 10, 'ok', 'normal' );
this.$refs.notification.createNotification( 'Progress', 10, 'progress', 'normal' );
},
loadPDF () {
let files = document.getElementById( 'pdfTemplate' ).files;
@@ -93,39 +82,76 @@
created() {
setTimeout( () => {
const domContainer = document.getElementById( 'editor' );
// TODO: Load from server if available
const template = {
basePdf: BLANK_PDF,
schemas: [
{
locationAndTime: {
type: 'text',
position: { x: 0, y: 0 },
width: 10,
height: 10,
},
ticketName: {
type: 'text',
position: { x: 10, y: 10 },
width: 10,
height: 10,
},
ticketQRCode: {
type: 'qrcode',
position: { x: 20, y: 20 },
width: 10,
height: 10,
},
},
],
}
this.designer = new Designer( { domContainer, template } );
// designer.updateTemplate( ) -> Used to update the template AND base PDF
fetch( '/admin/API/getTicketTemplate?ticket=' + sessionStorage.getItem( 'selectedTicket' ) ).then( res => {
const template = {
basePdf: "data:application/pdf;base64,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 truncated
schemas: [
{
"locationAndTime":{
"type":"text",
"position":{"x":90,"y":70},
"width":85,
"height":10,
"fontName":"Roboto"
},"eventName":{
"type":"text",
"position":{"x":89.7,"y":30},
"width":85,
"height":15,
"alignment":"left",
"fontSize":18,
"characterSpacing":0,
"lineHeight":1,
"fontName":"Roboto"
},"ticketName":{
"type":"text",
"position":{"x":90,"y":55},
"width":85,
"height":10,
"fontName":"Roboto",
"alignment":"left"
},"ticketQRCode":{
"type":"qrcode",
"position":{"x":25,"y":30.05},
"width":50,"height":50
}
}
],
"columns":[
"locationAndTime",
"eventName",
"ticketName",
"ticketQRCode"
],
"sampledata":[
{
"locationAndTime":"Time and date of event",
"eventName":"Your Event name will be filled in automatically",
"ticketName":"Ticket details go here (Ticket name)",
"ticketQRCode":"QR-Code for entry control will appear here"
}
],
}
if ( res.status === 200 ) {
res.json().then( data => {
if ( Object.keys( data ) ) {
this.designer = new Designer( { domContainer, data } );
} else {
this.designer = new Designer( { domContainer, template } );
}
} ).catch( () => {
this.designer = new Designer( { domContainer, template } );
} );
} else {
this.designer = new Designer( { domContainer, template } );
}
// designer.updateTemplate( ) -> Used to update the template AND base PDF
} );
}, 300 );
}
}
</script>
</script>
<style>
nav {
display: none;
@@ -43,6 +43,12 @@
<input type="password" v-model="formData[ 'password2' ]" name="password2" id="password2" required><br><br>
</td>
</tr>
<tr>
<td>
<label for="news">Do you want to potentially get newsletter?</label><br>
<input type="checkbox" v-model="formData[ 'newsletter' ]" name="news" id="news"><br><br>
</td>
</tr>
</table>
<!-- TODO: Ask for permission to send emails (Make question sound really optional) -->
</form>