rework of purchase system

This commit is contained in:
2023-04-30 11:47:50 +02:00
parent c7bc810e18
commit eec30d8ed4
9 changed files with 186 additions and 99 deletions

View File

@@ -20,7 +20,7 @@ module.exports = ( app, settings ) => {
if ( settings.twoFA ) { if ( settings.twoFA ) {
response.send( '2fa' ); response.send( '2fa' );
} else { } else {
request.session.loggedIn = true; request.session.loggedInAdmin = true;
response.send( 'ok' ); response.send( 'ok' );
} }
} else { } else {
@@ -29,12 +29,17 @@ module.exports = ( app, settings ) => {
} ); } );
} ); } );
app.get( '/test/login', ( request, response ) => {
request.session.loggedInAdmin = true;
response.send( 'Logged in' );
} );
app.get( '/admin/logout', ( request, response ) => { app.get( '/admin/logout', ( request, response ) => {
request.session.loggedIn = false; request.session.loggedInAdmin = false;
response.send( 'logged out' ); response.send( 'logged out' );
} ); } );
app.get( '/admin/getLoginStatus', ( request, response ) => { app.get( '/api/getAuth', ( request, response ) => {
response.send( request.session.loggedIn ); response.send( { 'admin': request.session.loggedInAdmin ? true : false, 'user': request.session.loggedInUser ? true : false } );
} ); } );
}; };

View File

@@ -3,7 +3,8 @@
<router-link to="/">Home</router-link> | <router-link to="/">Home</router-link> |
<router-link to="/tickets">Tickets</router-link> | <router-link to="/tickets">Tickets</router-link> |
<router-link to="/cart">Cart</router-link> | <router-link to="/cart">Cart</router-link> |
<router-link to="/login">Account</router-link> <router-link to="/login">Account</router-link> |
<button @click="changeTheme();" v-html="theme" id="themeSelector"></button>
</nav> </nav>
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'" mode="out-in"> <transition :name="route.meta.transition || 'fade'" mode="out-in">
@@ -23,6 +24,7 @@
--accent-background-hover: #4380a8; --accent-background-hover: #4380a8;
--overlay-color: rgba(37, 37, 37, 0.575); --overlay-color: rgba(37, 37, 37, 0.575);
--inactive-color: rgb(100, 100, 100); --inactive-color: rgb(100, 100, 100);
--highlight-backdrop: rgb(143, 134, 192);
} }
:root.dark { :root.dark {
@@ -31,9 +33,10 @@
--secondary-color: black; --secondary-color: black;
--background-color: rgb(32, 32, 32); --background-color: rgb(32, 32, 32);
--accent-color: #42b983; --accent-color: #42b983;
--hover-color: rgb(165, 165, 165); --hover-color: rgb(83, 83, 83);
--accent-background-hover: #4380a8; --accent-background-hover: #4380a8;
--inactive-color: rgb(190, 190, 190); --inactive-color: rgb(190, 190, 190);
--highlight-backdrop: rgb(85, 63, 207);
} }
@media ( prefers-color-scheme: dark ) { @media ( prefers-color-scheme: dark ) {
@@ -43,22 +46,38 @@
--secondary-color: black; --secondary-color: black;
--background-color: rgb(32, 32, 32); --background-color: rgb(32, 32, 32);
--accent-color: #42b983; --accent-color: #42b983;
--hover-color: rgb(165, 165, 165); --hover-color: rgb(83, 83, 83);
--accent-background-hover: #4380a8; --accent-background-hover: #4380a8;
--inactive-color: rgb(190, 190, 190); --inactive-color: rgb(190, 190, 190);
--highlight-backdrop: rgb(85, 63, 207);
} }
} }
::selection {
background-color: var( --highlight-backdrop );
}
#themeSelector {
background-color: rgba( 0, 0, 0, 0 );
color: var( --primary-color );
font-size: 130%;
padding: 0;
margin: 0;
border: none;
cursor: pointer;
}
html, html,
body { body {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
background-color: var( --background-color );
} }
#app { #app {
transition: 0.5s;
background-color: var( --background-color );
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
@@ -111,3 +130,39 @@ nav a.router-link-exact-active {
'opsz' 48 'opsz' 48
} }
</style> </style>
<script>
export default {
name: 'app',
data () {
return {
theme: '',
}
},
methods: {
changeTheme () {
if ( this.theme === '&#9788;' ) {
document.documentElement.classList.remove( 'dark' );
document.documentElement.classList.add( 'light' );
sessionStorage.setItem( 'theme', '&#9789;' );
this.theme = '&#9789;';
} else if ( this.theme === '&#9789;' ) {
document.documentElement.classList.remove( 'light' );
document.documentElement.classList.add( 'dark' );
sessionStorage.setItem( 'theme', '&#9788;' );
this.theme = '&#9788;';
}
}
},
created () {
this.theme = sessionStorage.getItem( 'theme' ) ? sessionStorage.getItem( 'theme' ) : '';
if ( window.matchMedia( '(prefers-color-scheme: dark)' ).matches || this.theme === '&#9788;' ) {
document.documentElement.classList.add( 'dark' );
this.theme = '&#9788;';
} else {
document.documentElement.classList.add( 'light' );
this.theme = '&#9789;';
}
}
}
</script>

View File

@@ -3,7 +3,7 @@
<img alt="Vue logo" src="../assets/logo.png"> <img alt="Vue logo" src="../assets/logo.png">
<div> <div>
<h1>Welcome to myevent!</h1> <h1>Welcome to myevent!</h1>
<p>Let's start the setup by entering the setup key below! You may define a setup key in the config file of myevent. See <a href="https://myevent.janishutz.com/docs/setup/" target="_blank">here</a> for more instructions</p> <p>Let's start the setup by entering the setup key below! You may define a setup key in the config file of myevent. See <a href="https://myevent.janishutz.com/docs/setup/setup" target="_blank">here</a> for more instructions</p>
<form> <form>
<label for="key">Your setup key</label><br> <label for="key">Your setup key</label><br>
<input type="text" v-model="formData[ 'key' ]" required name="key" id="key"> <input type="text" v-model="formData[ 'key' ]" required name="key" id="key">

View File

@@ -22,16 +22,6 @@ const router = createRouter( {
router.afterEach( ( to, from ) => { router.afterEach( ( to, from ) => {
document.title = to.meta.title ? to.meta.title : 'myevent'; document.title = to.meta.title ? to.meta.title : 'myevent';
} ); } );
let doSetup = true;
if ( doSetup ) {
import( '@/router/setupRoutes' ).then( data => {
router.addRoute( data.default );
router.replace( window.location.pathname );
} );
}
let UserAccountPages = [ 'account' ]; let UserAccountPages = [ 'account' ];
let authRequired = false; let authRequired = false;
@@ -58,4 +48,16 @@ router.beforeEach( ( to, from ) => {
} }
} ); } );
let doSetup = true;
if ( doSetup ) {
import( '@/router/setupRoutes' ).then( data => {
router.addRoute( data.default );
setTimeout( function () {
router.replace( window.location.pathname );
}, 300 );
} );
}
export default router; export default router;

View File

@@ -1,7 +1,7 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
export const useUserStore = defineStore ( 'user', { export const useUserStore = defineStore ( 'user', {
state: () => ( { 'isUserAuth': false, 'isAdminAuth': true, 'userPermissions': {} } ), state: () => ( { 'isUserAuth': true, 'isAdminAuth': true, 'userPermissions': {} } ),
getters: { getters: {
getUserAuthenticated: ( state ) => state.isUserAuth, getUserAuthenticated: ( state ) => state.isUserAuth,
getAdminAuthenticated: ( state ) => state.isAdminAuth, getAdminAuthenticated: ( state ) => state.isAdminAuth,

View File

@@ -40,40 +40,6 @@
text-align: justify; text-align: justify;
} }
.ticket {
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;
}
.ticket:hover {
background-color: var( --hover-color );
transition: 0.4s;
}
.ticket-logo {
height: 20vh;
width: auto;
margin-left: auto;
}
.ticket-name {
margin-right: auto;
}
.ticket-info {
margin-left: auto;
margin-right: auto
}
.tool-wrapper { .tool-wrapper {
display: flex; display: flex;
width: 100%; width: 100%;

View File

@@ -1,66 +1,95 @@
<template> <template>
<div class="purchase"> <div class="purchase">
<h1>Purchase</h1> <h1>Purchase</h1>
<h3>Personal information</h3>
<div class="purchase-app"> <div class="purchase-app">
<div v-if="!isAuthenticated"> <div v-if="!isAuthenticated" class="wrapper">
<form> <router-link to="/login" class="option-button">Log in with an existing account</router-link><br>
<label for="email">Email address *</label><br> <router-link to="/signup" class="option-button">Create new account</router-link><br>
<input type="email" name="email" id="email" required v-model="formData.email"> <router-link to="/guest" v-if="!settings.accountRequired" class="option-button">Purchase as guest</router-link>
</form> </div>
<router-link to="/login">Log in with an existing account</router-link> <div v-else class="wrapper">
<h3>Order summary</h3>
<div v-if="cartNotEmpty" class="cart-list">
<h3>Your tickets</h3>
<ul v-for="event in tickets" class="cart-list">
<li>{{ event.name }}
<ul v-for="ticket in event.selectedSeats">
<li>{{ ticket.name }} ({{ ticket.category.name }}, {{ ticket.ageGroup }}) {{ event.currency }} {{ ticket.price }}</li>
</ul>
</li>
</ul>
<div class="tool-wrapper wrapper-loggedIn">
<h4>Total: {{ backend.currency }} {{ backend.total }}</h4>
<router-link to="/pay">Buy now</router-link>
</div>
</div>
<div v-else>
Cart is empty. Please add tickets <router-link to="/tickets">here</router-link>
</div>
</div> </div>
<div v-else></div>
</div> </div>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.purchase {
height: 100%;
}
.purchase-app { .purchase-app {
text-align: justify; text-align: justify;
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 80%;
}
.option-button {
border-style: solid;
border-color: var( --primary-color );
border-radius: 20px;
padding: 6% 7%;
display: block;
width: 100%;
text-align: center;
margin: 0.5%;
color: var( --primary-color );
text-decoration: none;
}
.option-button:hover {
background-color: var( --hover-color );
color: var( --secondary-color )
}
.wrapper {
width: 40%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
height: 100%;
}
.wrapper-loggedIn {
width: 70%;
} }
ul { ul {
list-style: none; list-style: none;
width: 80%; text-align: justify;
} }
.ticket { .cart-list {
width: 100%;
}
.tool-wrapper {
display: flex; display: flex;
align-items: center; width: 100%;
flex-direction: column;
justify-content: center; justify-content: center;
text-decoration: none; align-items: center;
color: var( --primary-color );
border-color: var( --primary-color );
border-width: 1px;
height: fit-content;
border-style: solid;
padding: 10px;
transition: 0.4s;
}
.ticket:hover {
background-color: var( --hover-color );
transition: 0.4s;
}
.ticket-logo {
height: 20vh;
width: auto;
margin-left: auto;
}
.ticket-name {
margin-right: auto;
}
.ticket-info {
margin-left: auto;
margin-right: auto
} }
</style> </style>
@@ -69,10 +98,30 @@ export default {
name: 'PurchaseView', name: 'PurchaseView',
data () { data () {
return { return {
settings: { 'accountRequired':true }, settings: { 'accountRequired': true },
isAuthenticated: false, isAuthenticated: true,
formData: {} tickets: {},
backend: {},
cartNotEmpty: false,
} }
},
methods: {
loadData () {
this.cartNotEmpty = false;
let tickets = JSON.parse( sessionStorage.getItem( 'cart' ) );
for ( let event in tickets ) {
if ( Object.keys( tickets[ event ][ 'selectedSeats' ] ).length ) {
this.cartNotEmpty = true;
};
}
this.tickets = tickets;
this.backend = JSON.parse( sessionStorage.getItem( 'backend' ) );
},
},
created () {
this.loadData();
} }
}; };
</script> </script>

View File

@@ -10,7 +10,7 @@
<router-link to="/admin/events" class="admin-menu">Events</router-link> <router-link to="/admin/events" class="admin-menu">Events</router-link>
<router-link to="/admin/plugins" class="admin-menu">Plugins</router-link> <router-link to="/admin/plugins" class="admin-menu">Plugins</router-link>
<router-link to="/admin/settings" class="admin-menu">Settings</router-link> <router-link to="/admin/settings" class="admin-menu">Settings</router-link>
<router-link to="/admin/login" class="admin-menu" @click="logout()">Logout</router-link> <button to="/admin/login" class="admin-menu" @click="logout()">Logout</button>
</nav> </nav>
<div class="main-view"> <div class="main-view">
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
@@ -69,9 +69,14 @@
padding: 4% 0%; padding: 4% 0%;
width: 100%; width: 100%;
background-color: rgba( 0, 0, 0, 0 ); background-color: rgba( 0, 0, 0, 0 );
color: white; color: var( --secondary-color );
cursor: pointer;
font-family: Avenir, Helvetica, Arial, sans-serif;
font-weight: bold;
text-decoration: none; text-decoration: none;
transition: 1s; transition: 1s;
font-size: 100%;
border-style: none;
} }
nav a.router-link-exact-active { nav a.router-link-exact-active {
@@ -106,7 +111,12 @@
}, },
methods: { methods: {
logout () { logout () {
this.userStore.setAdminAuth( false ); if ( confirm( 'Do you really want to log out?' ) ) {
fetch( '/admin/logout' ).then( _ => {
this.userStore.setAdminAuth( false );
this.$router.push( '/admin/login' );
} );
}
} }
} }
}; };