mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 13:24:24 +00:00
rework of purchase system
This commit is contained in:
@@ -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 {
|
||||||
@@ -28,13 +28,18 @@ 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 } );
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
@@ -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 === '☼' ) {
|
||||||
|
document.documentElement.classList.remove( 'dark' );
|
||||||
|
document.documentElement.classList.add( 'light' );
|
||||||
|
sessionStorage.setItem( 'theme', '☽' );
|
||||||
|
this.theme = '☽';
|
||||||
|
} else if ( this.theme === '☽' ) {
|
||||||
|
document.documentElement.classList.remove( 'light' );
|
||||||
|
document.documentElement.classList.add( 'dark' );
|
||||||
|
sessionStorage.setItem( 'theme', '☼' );
|
||||||
|
this.theme = '☼';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.theme = sessionStorage.getItem( 'theme' ) ? sessionStorage.getItem( 'theme' ) : '';
|
||||||
|
if ( window.matchMedia( '(prefers-color-scheme: dark)' ).matches || this.theme === '☼' ) {
|
||||||
|
document.documentElement.classList.add( 'dark' );
|
||||||
|
this.theme = '☼';
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add( 'light' );
|
||||||
|
this.theme = '☽';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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%;
|
||||||
|
|||||||
0
src/webapp/src/views/GuestPurchaseView.vue
Normal file
0
src/webapp/src/views/GuestPurchaseView.vue
Normal 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>
|
||||||
|
|||||||
@@ -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' );
|
||||||
|
} );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user