tickets selection + login

This commit is contained in:
2023-04-08 17:16:00 +02:00
parent f7e121708b
commit 8b8172d9f8
15 changed files with 489 additions and 48 deletions

View File

@@ -2,4 +2,4 @@ module.exports = {
presets: [ presets: [
'@vue/cli-plugin-babel/preset' '@vue/cli-plugin-babel/preset'
] ]
} };

View File

@@ -9,6 +9,7 @@
<title> <title>
<%= htmlWebpackPlugin.options.title %> <%= htmlWebpackPlugin.options.title %>
</title> </title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200">
</head> </head>
<body> <body>

View File

@@ -2,13 +2,19 @@
<nav> <nav>
<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="/login">Account</router-link> <router-link to="/login">Account</router-link>
</nav> </nav>
<router-view /> <router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</template> </template>
<style> <style>
html, body { html,
body {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0; margin: 0;
@@ -38,4 +44,33 @@ nav a {
nav a.router-link-exact-active { nav a.router-link-exact-active {
color: #42b983; color: #42b983;
} }
.scale-enter-active,
.scale-leave-active {
transition: all 0.5s ease;
}
.scale-enter-from,
.scale-leave-to {
opacity: 0;
transform: scale(0.9);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.4s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.material-symbols-outlined {
font-variation-settings:
'FILL' 0,
'wght' 400,
'GRAD' 0,
'opsz' 48
}
</style> </style>

View File

@@ -0,0 +1,33 @@
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<div>
<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>
<form>
<label for="key">Your setup key</label><br>
<input type="text" v-model="formData[ 'key' ]" required name="key" id="key">
</form>
<button @click="setup();" class="button">Start setup</button>
</div>
</div>
</template>
<script>
export default {
props: {
formData: Object
},
methods: {
setup () {
}
},
}
</script>
<style scoped>
img {
width: 20%;
}
</style>

View File

@@ -0,0 +1,130 @@
<template>
<div class="seatingWrapper">
<div class="sidebar">
<h2>{{ eventInfo.name }}</h2>
<h3>{{ eventInfo.date }}</h3>
<h3>{{ eventInfo.location }}</h3>
<h3>Selected tickets</h3>
<ul v-for="ticket in selectedSeats">
<li>{{ seating[ ticket[ 1 ] ][ 'content' ][ ticket[ 0 ] ][ 'name' ] }} {{ eventInfo[ 'categories' ][ seating[ ticket[ 1 ] ][ 'content' ][ ticket[ 0 ] ][ 'category' ] ][ 'price' ] }}</li>
</ul>
<h3>Total</h3>
<router-link to="/cart">To cart</router-link>
</div>
<div class="seatingPlan">
<h3>Seating plan</h3>
<p>{{ eventInfo.RoomName }}</p>
<div class="seating">
<table>
<tr v-for="row in seating">
<td>
{{ row.name }}
</td>
<td v-for="place in row.content">
<div :class="place.category" class="active" v-if="!place.available" @click="selectSeat( place.id, row.id )">
<div v-if="place.selected">
<span class="material-symbols-outlined">done</span>
</div>
<div v-else>
<span class="material-symbols-outlined">living</span>
</div>
</div>
<div v-else class="occupied">
<span class="material-symbols-outlined">close</span>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</template>
<script>
let index = sessionStorage.getItem( 'arrayIndex' ) ? parseInt( sessionStorage.getItem( 'arrayIndex' ) ) : 0;
export default {
name: 'noseatplan',
props: {
ticketID: String
},
data () {
return {
seating: { 'r1': { 'name': 'Row 1', 'id': 'r1', 'content':{ 'S1':{ 'name': 'Seat 1', 'id': 'S1', 'available': true, 'selected': false, 'category':'2' } } }, 'r2': { 'name': 'Row 2', 'id': 'r2', 'content':{ 'S1':{ 'name': 'S1', 'id': 'S1', 'available': false, 'selected': false, 'category':'2' } } } },
eventInfo: { 'name': 'TestEvent', 'location': 'TestLocation', 'date': 'TestDate', 'RoomName': 'TestRoom', 'currency': 'CHF', 'categories': { '1': { 'price': 20, 'bg': 'black', 'fg': 'white' }, '2': { 'price': 20, 'bg': 'green', 'fg': 'white' } } },
selectedSeats: {}
}
},
methods: {
selectSeat( placeID, rowID ) {
let data = {};
if ( sessionStorage.getItem( 'selectedSeats' ) ) {
data = JSON.parse( sessionStorage.getItem( 'selectedSeats' ) );
}
let isDeleting = false;
for ( let i in data ) {
if ( data[ i ][ 0 ] == placeID, data[ i ][ 1 ] == rowID ) {
delete data[ i ];
isDeleting = true;
}
}
this.seating[ rowID ][ 'content' ][ placeID ][ 'selected' ] = !isDeleting;
if ( !isDeleting ) {
data[ index ] = [ placeID, rowID ];
index += 1;
}
sessionStorage.setItem( 'arrayIndex', index );
sessionStorage.setItem( 'selectedSeats', JSON.stringify( data ) );
this.selectedSeats = data;
}
}
}
</script>
<style scoped>
.seatingWrapper {
display: grid;
grid-template-areas:
'main main main sidebar'
'main main main sidebar'
'main main main sidebar'
'main main main sidebar'
'main main main sidebar'
'main main main sidebar'
'main main main sidebar'
'main main main sidebar'
'main main main sidebar';
height: 100%;
}
.sidebar {
grid-area: sidebar;
background-color: rgb(30, 30, 82);
color: white;
}
.seatingPlan {
grid-area: main;
display: flex;
flex-direction: column;
align-items: center;
justify-content: justify;
}
.seating {
width: 90%;
}
.active {
cursor: pointer;
}
.occupied {
background-color: rgb(177, 177, 177);
padding: 0.4%;
}
</style>

View File

@@ -33,10 +33,36 @@ const routes = [
path: '/admin/login', path: '/admin/login',
name: 'adminLogin', name: 'adminLogin',
component: () => import( '../views/AdminLoginView.vue' ), component: () => import( '../views/AdminLoginView.vue' ),
meta: {
title: 'Login :: Admin - myevent'
}
},
{
path: '/admin',
name: 'admin',
component: () => import( '../views/HomeView.vue' ),
meta: {
title: 'Admin - myevent'
},
children: [
{
path: 'settings',
name: 'adminSettings',
component: () => import( '../views/AdminLoginView.vue' ),
meta: { meta: {
title: 'Admin - myevent' title: 'Admin - myevent'
} }
}, },
{
path: '',
name: 'adminMain',
component: () => import( '../views/AdminLoginView.vue' ),
meta: {
title: 'Admin - myevent'
}
},
]
},
{ {
path: '/signup', path: '/signup',
name: 'signup', name: 'signup',
@@ -44,6 +70,33 @@ const routes = [
meta: { meta: {
title: 'Signup - myevent' title: 'Signup - myevent'
} }
},
{
path: '/tickets/details',
name: 'ticketDetails',
component: () => import( '../views/TicketsDetailsView.vue' ),
meta: {
title: 'Details - myevent',
transition: 'scale'
}
},
{
path: '/cart',
name: 'cart',
component: () => import( '../views/CartView.vue' ),
meta: {
title: 'Cart - myevent',
transition: 'scale'
}
},
{
path: '/purchase',
name: 'purchase',
component: () => import( '@/views/PurchaseView.vue' ),
meta: {
title: 'Purchase - myevent',
transition: 'scale'
}
} }
] ]
@@ -58,4 +111,13 @@ router.afterEach( ( to, from ) => {
document.title = to.meta.title ? to.meta.title : 'default title'; document.title = to.meta.title ? to.meta.title : 'default title';
} ); } );
let disallowed = [ 'admin', 'adminMain' ];
let isAuthenticated = true;
router.beforeEach( ( to, from ) => {
if ( disallowed.includes( to.name ) && !isAuthenticated ) {
return { name: 'adminLogin' };
}
} );
export default router; export default router;

View File

@@ -1,11 +1,11 @@
<template> <template>
<div class="login"> <div class="login">
<div class="login-app"> <div class="login-app">
<h1>Log into your account</h1> <h1>Log into your admin account</h1>
<form> <form>
<label for="username">Username</label><br> <label for="mail">Email address</label><br>
<input type="text" v-model="formData[ 'username' ]" name="username" id="username" required><br><br> <input type="email" v-model="formData[ 'mail' ]" name="mail" id="mail" required><br><br>
<label for="username">Password</label><br> <label for="password">Password</label><br>
<input type="text" v-model="formData[ 'password' ]" name="password" id="password" required> <input type="text" v-model="formData[ 'password' ]" name="password" id="password" required>
</form> </form>
<button @click="login();" class="button">Log in</button> <button @click="login();" class="button">Log in</button>

View File

@@ -0,0 +1,59 @@
<template>
<div class="order">
<h1>Cart</h1>
<h3>Your tickets</h3>
<ul>
<li>Ticket</li>
</ul>
<router-link to="/purchase">Purchase now</router-link>
</div>
</template>
<style scoped>
.order-app {
text-align: justify;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
ul {
list-style: none;
width: 80%;
}
.ticket {
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
color: black;
border-color: black;
border-width: 1px;
height: fit-content;
border-style: solid;
padding: 10px;
transition: 0.4s;
}
.ticket:hover {
background-color: rgb(165, 165, 165);
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>

View File

@@ -1,24 +1,23 @@
<template> <template>
<div class="home"> <initial formData="formData"></initial>
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template> </template>
<script> <script>
// @ is an alias to /src import initial from '@/components/initial.vue';
import HelloWorld from '@/components/HelloWorld.vue'
export default { export default {
name: 'HomeView', data () {
components: { return {
HelloWorld formData: {}
} }
} },
</script> methods: {
setup () {
<style scoped>
img {
width: 20%;
} }
</style> },
components: {
initial
}
};
</script>

View File

@@ -1,12 +1,12 @@
<template> <template>
<div class="login"> <div class="login">
<div class="login-app"> <div class="login-app">
<h1>Log into your account</h1> <h1>Log in</h1>
<form> <form>
<label for="username">Username</label><br> <label for="mail">Email</label><br>
<input type="text" v-model="formData[ 'username' ]" name="username" id="username" required><br><br> <input type="email" v-model="formData[ 'mail' ]" name="mail" id="mail" required><br><br>
<label for="username">Password</label><br> <label for="password">Password</label><br>
<input type="text" v-model="formData[ 'password' ]" name="password" id="password" required> <input type="password" v-model="formData[ 'password' ]" name="password" id="password" required>
</form> </form>
<button @click="login();" class="button">Log in</button> <button @click="login();" class="button">Log in</button>
<router-link to="/signup" class="button">Sign up instead</router-link> <router-link to="/signup" class="button">Sign up instead</router-link>

View File

@@ -3,7 +3,20 @@
<h1>Order tickets</h1> <h1>Order tickets</h1>
<div class="order-app"> <div class="order-app">
<ul> <ul>
<li>T</li> <li>
<router-link to="/tickets/details" class="ticket">
<div class="ticket-name">
<h3>Event name</h3>
<p>Event description</p>
</div>
<div class="ticket-info">
<p>Free seats / max seats</p>
<p>Date & time of event</p>
<h4>Starting at CHF 20.00</h4>
</div>
<img src="../assets/logo.png" alt="event logo" class="ticket-logo">
</router-link>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -18,16 +31,42 @@
justify-content: center; justify-content: center;
} }
li { ul {
list-style: none;
width: 80%;
}
.ticket {
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
color: black;
border-color: black; border-color: black;
border-width: 1px; border-width: 1px;
height: fit-content; height: fit-content;
border-style: solid; border-style: solid;
padding: 10px; padding: 10px;
transition: 0.4s;
} }
ul { .ticket:hover {
list-style: none; background-color: rgb(165, 165, 165);
width: 80%; 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>

View File

@@ -0,0 +1,55 @@
<template>
<div class="order">
<h1>Purchase</h1>
<h3>Please choose a payment option</h3>
</div>
</template>
<style scoped>
.order-app {
text-align: justify;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
ul {
list-style: none;
width: 80%;
}
.ticket {
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
color: black;
border-color: black;
border-width: 1px;
height: fit-content;
border-style: solid;
padding: 10px;
transition: 0.4s;
}
.ticket:hover {
background-color: rgb(165, 165, 165);
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>

View File

@@ -1,15 +1,19 @@
<template> <template>
<div class="login"> <div class="login">
<div class="login-app"> <div class="login-app">
<h1>Log into your account</h1> <h1>Sign up</h1>
<form> <form>
<label for="username">Username</label><br> <label for="mail">Email</label><br>
<input type="text" v-model="formData[ 'username' ]" name="username" id="username" required><br><br> <input type="email" v-model="formData[ 'mail' ]" name="mail" id="mail" required><br><br>
<label for="username">Password</label><br> <label for="name">Full name</label><br>
<input type="text" v-model="formData[ 'password' ]" name="password" id="password" required> <input type="text" v-model="formData[ 'name' ]" name="name" id="name" required><br><br>
<label for="password">Password</label><br>
<input type="password" v-model="formData[ 'password' ]" name="password" id="password" required><br><br>
<label for="password2">Confirm password</label><br>
<input type="password" v-model="formData[ 'password2' ]" name="password2" id="password2" required>
</form> </form>
<button @click="login();" class="button">Log in</button> <button @click="signup();" class="button">Sign up</button>
<router-link to="/signup" class="button">Sign up instead</router-link> <router-link to="/login" class="button">Log in instead</router-link>
</div> </div>
</div> </div>
</template> </template>
@@ -22,7 +26,7 @@
} }
}, },
methods: { methods: {
login () { signup () {
} }
}, },

View File

@@ -0,0 +1,24 @@
<template>
<div class="details">
<!-- Load correct component depending on what the event's config is -->
<seatplan ticketID="haoag"></seatplan>
</div>
</template>
<style scoped>
.details {
flex-grow: 1;
}
</style>
<script>
import seatplan from '@/components/seatplan.vue';
export default {
name: 'TicketsDetailsView',
components: {
seatplan
}
};
</script>