File: /var/www/vhost/disk-apps/alq-webapp-boleteria/src/views/Tickets.vue
<template>
<div>
<Header></Header>
<div class="container marketing">
<br>
<div class="row featurette">
<div class="col-md-7 order-md-2">
<h2 class="featurette-heading">Hola {{user.first_name}}. <span class="text-muted">Boletería DIM ahora también aquí.</span></h2>
<p class="lead">Este es un nuevo portal en donde podrás realizar la compra de boletería DIM.</p>
</div>
<div class="col-md-5 order-md-1">
<br><br>
<img src="@/assets/stadium.png" alt="" height="300" width="350" class="mx-auto">
<!-- <svg class="bd-placeholder-img bd-placeholder-img-lg featurette-image img-fluid mx-auto" width="500" height="500" xmlns="@/assets/stadium.png" role="img" aria-label="Placeholder: 500x500" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="#eee"></rect><text x="50%" y="50%" fill="#aaa" dy=".3em">500x500</text></svg> -->
</div>
</div>
<hr class="featurette-divider">
</div>
<div class="container">
<main>
<!-- Message -->
<div class="py-5 text-center">
<h2>Tickets</h2>
<p class="lead">Escoge todas las sillas que deseas y procede con el proceso de compra por medios digitales.</p>
</div>
<div class="row g-5">
<!-- Tickets -->
<div class="col-md-5 col-lg-4 order-md-last">
<h4 class="d-flex justify-content-between align-items-center mb-3">
<span class="text-primary">Tus Tickets</span>
<span><span class="badge bg-primary rounded-pill">{{quantityTickets}}</span> <fa icon="trash-can" color="red" v-on:click="getStart()" /></span>
</h4>
<ul class="list-group mb-3">
<div v-if="quantityTickets == 0">
<li class="list-group-item d-flex justify-content-between">
<div>
<h6 class="my-0">Ningún Ticket seleccionado</h6>
</div>
</li>
</div>
<div v-else>
<li v-for="ticket in ticketsSelected" :key="ticket" class="list-group-item d-flex justify-content-between lh-sm">
<div><fa icon="trash" color="black" v-on:click="deleteTicket(ticket)" /></div>
<div>
<h6 class="my-0">{{ticket.Event.name}}</h6>
<small class="text-muted">{{ticket.Tribuna}} - {{ticket.Zone.name.split('_')[0]}} {{ticket.Zone.name.split('_')[1]}} - {{ticket.Seat.letter.name}}{{ticket.Seat.code}}</small>
</div>
<span class="text-muted">$ {{new Intl.NumberFormat().format(ticket.Price)}}</span>
</li>
</div>
<li class="list-group-item d-flex justify-content-between">
<strong><span>Total (COP)</span></strong>
<strong>$ {{new Intl.NumberFormat().format(totalToPay)}}</strong>
</li>
</ul>
<div class="card p-2">
<button type="button" class="btn btn-primary aling-center btn-lg" v-on:click="goToPay()">Pagar</button>
</div>
</div>
<!-- Choose seat -->
<div class="col-md-7 col-lg-8">
<h4 class="mb-3">Selecciona silla</h4>
<form class="needs-validation" validate>
<div class="row g-3">
<div class="col-12">
<label for="event" class="form-label">Partido</label>
<select class="form-select" id="event" v-model="eventSelected" required>
<option value="">Seleccionar...</option>
<option v-for="event in events" :value="event" :key="event.id">{{event.name}} - {{new Date(event.event_start)}}</option>
</select>
</div>
</div><br>
<div class="row g-3">
<div class="col-12">
<label for="event" class="form-label">Tribuna</label>
<select @change="selectTribuna($event)" v-model="tribunaSelected" class="form-select" id="event" required>
<option value="">Seleccionar...</option>
<option value="4">Norte</option>
<option value="5">Sur</option>
<option value="3">Oriental</option>
<option value="2">Occidental</option>
</select>
</div>
</div><br>
<div class="row g-3">
<div class="col-12">
<label for="event" class="form-label">Sector</label>
<select @change="selectSubZone($event)" v-model="subZoneSelected" class="form-select" id="event" required>
<option value="">Seleccionar...</option>
<option v-for="sub_zone in sub_zones" :value="sub_zone" :key="sub_zone.id">{{sub_zone.name.split('_')[0]}} {{sub_zone.name.split('_')[1]}}</option>
</select>
</div>
</div><br>
<div class="row g-3">
<div class="col-12">
<label for="event" class="form-label">Silla</label>
<select v-model="seatSelected" class="form-select" id="event" required>
<option value="">Seleccionar...</option>
<option v-for="seat in seats" :value="seat" :key="seat.id">{{seat.letter.name}} - {{seat.code}}</option>
</select>
</div>
</div>
<hr class="my-4">
<button class="w-100 btn btn-success btn-lg" type="button" v-on:click="addTicket()">Agregar silla</button>
</form>
</div>
</div>
</main>
</div>
<Footer></Footer>
</div>
</template>
<script>
import Header from '@/components/Header.vue'
import Footer from '@/components/Footer.vue'
import axios from 'axios'
const urlApi = 'https://alq-cali.bikenow.co/api/'
const urlAdmin = 'https://alq-cali.bikenow.co/'
export default {
name: 'Tickets',
components: {
Header,
Footer
},
data: function () {
return {
user: JSON.parse(localStorage.user_info),
events: [],
sub_zones: [],
seats: [],
eventSelected: '',
tribunaSelected: '',
subZoneSelected: '',
seatSelected: '',
ticketsSelected: [],
quantityTickets: 0,
totalToPay: 0,
tickets_to_pay: [],
priceSeatSelected: Number
}
},
mounted: function () {
const config = {
headers: { Authorization: `Bearer ${localStorage.token}` }
}
axios.get(urlApi + 'tickets/match_events', config)
.then(matchEvents => {
matchEvents.data.forEach(element => {
if (new Date(Date.now()) >= new Date(element.event_start_sale) && new Date(Date.now()) <= new Date(element.event_end_sale)) {
this.events.push(element)
}
})
// console.log(this.events)
})
},
methods: {
selectTribuna () {
this.subZoneSelected = ''
this.seatSelected = ''
this.sub_zones = []
this.seats = []
axios.get(urlApi + 'tickets/get_sub_zones/' + event.target.value, { headers: { Authorization: `Bearer ${localStorage.token}` } })
.then(subZones => {
if (subZones.data.r) {
// console.log('Sub Zones: ' + subZones.data.data)
this.sub_zones = subZones.data.data
} else {
console.log('Error getting sub_zones: ' + subZones.data)
}
})
},
selectSubZone () {
this.seatSelected = ''
this.seats = []
axios.get(urlApi + 'tickets/get_seats/' + this.subZoneSelected.id + '/' + this.eventSelected.id, { headers: { Authorization: `Bearer ${localStorage.token}` } })
.then(seats => {
if (seats.data.original.r) {
// console.log('Seats: ' + seats.data.original.data)
seats.data.original.data.forEach(element => {
if (!element.ticket && !element.ticket_user_block) {
this.seats.push(element)
}
})
} else {
console.log('Error getting seats: ' + seats.data.original)
this.$swal('Zona no disponible para la venta')
}
})
},
addTicket () {
// Validaciones
if (!this.eventSelected) {
this.$swal('Por favor selecciona un partido')
return
}
if (!this.tribunaSelected) {
this.$swal('Por favor selecciona una tribuna')
return
}
if (!this.subZoneSelected) {
this.$swal('Por favor selecciona una zona')
return
}
if (!this.seatSelected) {
this.$swal('Por favor selecciona una silla')
return
}
// Verifica que el ticket sea del mismo partido, tribuna y sector
if (this.ticketsSelected.length !== 0) {
if (this.ticketsSelected[0].Event.id !== this.eventSelected.id || this.ticketsSelected[0].Zone.id !== this.subZoneSelected.id) {
this.$swal('Solo puedes agregar tickets correspondientes al mismo partido, a la misma tribuna y a la misma zona ya agregada')
return
}
}
let tribuna
let ticketsEqual = 0
// Valida precio
axios.get(urlApi + 'tickets/get_seat_price/' + this.subZoneSelected.id + '/' + this.eventSelected.id, { headers: { Authorization: `Bearer ${localStorage.token}` } })
.then(seatsPrice => {
// console.log(seatsPrice)
if (seatsPrice.data.original.r) {
// Verifica tickets escogidos
this.ticketsSelected.forEach(item => {
if (item.Event.id === this.eventSelected.id && item.Seat.id === this.seatSelected.id) {
ticketsEqual = ticketsEqual + 1
}
})
// Valida si el ticket no ha sido escogido
if (ticketsEqual === 0) {
this.priceSeatSelected = seatsPrice.data.original.data.price
// Organiza elemento
if (this.tribunaSelected === '2') {
tribuna = 'Occidental'
}
if (this.tribunaSelected === '3') {
tribuna = 'Oriental'
}
if (this.tribunaSelected === '4') {
tribuna = 'Norte'
}
if (this.tribunaSelected === '5') {
tribuna = 'Sur'
}
this.ticketsSelected.push({ Event: this.eventSelected, Tribuna: tribuna, Zone: this.subZoneSelected, Seat: this.seatSelected, Price: this.priceSeatSelected })
this.tickets_to_pay.push({
seat: this.seatSelected,
match_event_id: this.eventSelected.id,
ticket_type_id: 1,
match_event_price: seatsPrice.data.original.data,
zone_name: tribuna + ' - ' + this.subZoneSelected.name.split('_')[0] + ' ' + this.subZoneSelected.name.split('_')[1]
})
this.quantityTickets = this.quantityTickets + 1
this.totalToPay = this.totalToPay + this.priceSeatSelected
this.seatSelected = ''
} else {
this.$swal('Este ticket ya ha sido agregado')
this.seatSelected = ''
}
} else {
console.log('Error getting seatsPrice: ' + seatsPrice.data.original.m)
this.$swal(seatsPrice.data.original.m)
this.seatSelected = ''
}
})
},
goToPay () {
if (this.quantityTickets === 0) {
this.$swal('Primero agrega un ticket')
return
}
this.$swal({
title: '¿Seguro que deseas realizar la compra?',
showDenyButton: true,
confirmButtonText: 'Si',
icon: 'question',
showClass: {
popup: 'animate__animated animate__fadeInDown'
},
hideClass: {
popup: 'animate__animated animate__fadeOutUp'
}
}).then((result) => {
if (result.isConfirmed) {
const info = {
tickets: this.tickets_to_pay,
type_process: 'block',
amount: this.totalToPay,
ticket_type_id: 1,
tournament_id: 1
}
console.log(info)
console.log(this.ticketsSelected)
console.log(this.totalToPay)
console.log(this.tickets_to_pay)
axios.post(urlApi + 'tickets/createBlocks', info, { headers: { Authorization: `Bearer ${localStorage.token}` } })
.then(response => {
if (response.data.r) {
console.log(response.data)
window.open(urlAdmin + 'tickets/purchase?id=' + response.data.data, '_blank')
this.getStart()
this.$swal(response.data.m)
} else {
console.log(response.data)
this.$swal(response.data.m)
}
})
}
})
},
getStart () {
this.eventSelected = ''
this.tribunaSelected = ''
this.subZoneSelected = ''
this.seatSelected = ''
this.ticketsSelected = []
this.quantityTickets = 0
this.totalToPay = 0
this.tickets_to_pay = []
},
deleteTicket (ticketDelete) {
this.tickets_to_pay = this.tickets_to_pay.filter(function (ticket) {
return (ticket.seat.id !== ticketDelete.Seat.id && ticket.match_event_id === ticketDelete.Event.id) || ticket.match_event_id !== ticketDelete.Event.id
})
this.ticketsSelected = this.ticketsSelected.filter(function (ticket) {
return (ticket.Seat.id !== ticketDelete.Seat.id && ticket.Event.id === ticketDelete.Event.id) || ticket.Event.id !== ticketDelete.Event.id
})
this.quantityTickets = 0
this.totalToPay = 0
this.tickets_to_pay.forEach(element => {
this.quantityTickets = this.quantityTickets + 1
this.totalToPay = this.totalToPay + element.match_event_price.price
})
}
}
}
</script>
<style scoped>
/* GLOBAL STYLES
-------------------------------------------------- */
/* Padding below the footer and lighter body text */
body {
padding-top: 3rem;
padding-bottom: 3rem;
color: #5a5a5a;
}
/* CUSTOMIZE THE CAROUSEL
-------------------------------------------------- */
/* Carousel base class */
.carousel {
margin-bottom: 4rem;
}
/* Since positioning the image, we need to help out the caption */
.carousel-caption {
bottom: 3rem;
z-index: 10;
}
/* Declare heights because of positioning of img element */
.carousel-item {
height: 32rem;
}
.carousel-item > img {
position: absolute;
top: 0;
left: 0;
min-width: 100%;
height: 32rem;
}
/* MARKETING CONTENT
-------------------------------------------------- */
/* Center align the text within the three columns below the carousel */
.marketing .col-lg-4 {
margin-bottom: 1.5rem;
text-align: center;
}
.marketing h2 {
font-weight: 400;
}
/* rtl:begin:ignore */
.marketing .col-lg-4 p {
margin-right: .75rem;
margin-left: .75rem;
}
/* rtl:end:ignore */
/* Featurettes
------------------------- */
.featurette-divider {
margin: 5rem 0; /* Space out the Bootstrap <hr> more */
}
/* Thin out the marketing headings */
.featurette-heading {
font-weight: 300;
line-height: 1;
/* rtl:remove */
letter-spacing: -.05rem;
}
/* RESPONSIVE CSS
-------------------------------------------------- */
@media (min-width: 40em) {
/* Bump up size of carousel content */
.carousel-caption p {
margin-bottom: 1.25rem;
font-size: 1.25rem;
line-height: 1.4;
}
.featurette-heading {
font-size: 50px;
}
}
@media (min-width: 62em) {
.featurette-heading {
margin-top: 7rem;
}
}
</style>