File: /var/www/vhost/disk-apps/pwa.sports-crowd.com/src/app/pages/tickets/tickets.page.ts
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core";
import { NavController, ModalController, AlertController, IonRouterOutlet, PopoverController } from "@ionic/angular";
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { StorageService } from '../../services/storage.service';
import { TicketsService } from "../../services/tickets.service";
import { UtilsService } from "../../services/utils.service";
import { TranslateService } from "@ngx-translate/core";
import { CurrencyPipe, Location } from "@angular/common";
import { ModalListSuscriptionPage } from "../modal-list-suscription/modal-list-suscription.page";
import { AboutPopoverTicketPage } from "../about-popover-ticket/about-popover-ticket";
import { UserService } from "../../services/user.service";
import { ActivatedRoute, Router } from '@angular/router';
import { CityService } from "../../services/city.service";
import { ScreenOrientation, OrientationType } from '@capawesome/capacitor-screen-orientation';
import { InAppBrowser, UrlEvent } from '@capgo/inappbrowser'
import { Capacitor } from '@capacitor/core';
import { CorporateIdentityService } from "../../services/corporate-identity.service";
@Component({
selector: "app-tickets",
templateUrl: "./tickets.page.html",
styleUrls: ["./tickets.page.scss"],
})
export class TicketsPage implements OnInit {
@ViewChild("container_image") container_image: ElementRef<HTMLElement>;
@ViewChild("stadiumContainer") stadiumContainer: ElementRef<HTMLElement>;
@ViewChild("stadium") stadium: ElementRef<HTMLElement>;
stadiumContainerInvalid: boolean = true;
eventGroup: UntypedFormGroup;
matchEvents: any;
current_tab: number = 0;
current_zone: number;
current_sub_zone: number;
emptySettingsSlide: any;
list_seats: any = [];
group_seats: any;
name_zone: string = "";
match_event_price: any;
name_subzone: string = "";
slideOpts = {
zoom: {
maxRatio: 5,
},
};
params: any;
buy_tickets: any = [];
subtotal: number = 0;
serviceChargeEnabled: boolean = false;
serviceCharge: number = 0;
total: number = 0;
oldTotal: number = 0;
current_match: any;
ticket_type_id: any;
listPreSubcriber: any = [];
tribunesParent: any = [];
isPresaleSuscription: boolean = false;
valuePointsCoin: any;
currentCoinsInMoney: number = 0;
payWithCoins: boolean = false;
credit_locked: boolean = true;
coinsAfterPurchase: number = 0;
enablePaymentWithCoins: boolean = false;
isModalOpen = false;
typeTickets = [];
matchEventId: number;
showFabsNextButton: boolean = false;
time: number;
currency: string;
constructor(
public navCtrl: NavController,
private location: Location,
private _formBuilder: UntypedFormBuilder,
private storage: StorageService,
private ticketsService: TicketsService,
private utilsService: UtilsService,
public translateService: TranslateService,
public modalCtrl: ModalController,
public alertController: AlertController,
private currencyPipe: CurrencyPipe,
private routerOutlet: IonRouterOutlet,
public popoverController: PopoverController,
public userService: UserService,
private router: Router,
public cityProvider: CityService,
public route: ActivatedRoute,
private corporateIdentityService: CorporateIdentityService
) {
this.currency = this.corporateIdentityService.getCurrency();
}
async ngOnInit() {
this.time = new Date().getTime();
this.matchEventId = parseInt(this.route.snapshot.paramMap.get("matchEventId")) ?? 0;
this.emptySettingsSlide = {
showImage: false,
urlImage: "",
showText: true,
text: this.translateService.instant("tickets.empty_events"),
};
this.storage.get("parameters").then((parameters) => {
if (parameters) {
this.valuePointsCoin = parameters.value_points_coin;
this.serviceChargeEnabled = parameters.service_charge_enabled;
this.params = parameters;
if (
this.params.presale &&
this.utilsService.validateDate(this.params.presale_end, "end") &&
!this.utilsService.validateDateCustom(this.userService._infoUser.created_at, this.params.presale_date_condition, "start")
) {
this.alertForceBack(this.translateService.instant("tickets.alert"), this.params.presale_msj);
}
}
});
if (this.matchEventId) {
this.matchEvents = this.ticketsService.matchEvents;
this.current_match = this.ticketsService.matchEvents.find((item: any) => item.id == this.matchEventId);
this.eventGroup = this._formBuilder.group({
match_event: ["", Validators.required],
});
await this.loadStadiumZones();
setTimeout(() => {
this.buttonsFabsNext();
}, 500);
} else {
await this.getMatchEvents();
this.eventGroup = this._formBuilder.group({
match_event: ["", Validators.required],
});
this.eventGroup.controls.match_event.valueChanges.subscribe(async (value: string) => {
this.matchEventId = parseInt(value);
this.current_match = this.matchEvents.find((item: any) => item.id == this.matchEventId);
await this.loadStadiumZones();
setTimeout(() => {
this.buttonsFabsNext();
}, 500);
});
}
/*
if (this.userService._infoUser.coin_uid) {
this.enablePaymentWithCoins = true;
this.userService.getCurrentCoinsUser().then((resp) => {
this.credit_locked = !!resp["credit_locked"];
this.currentCoinsInMoney = resp['credit_coins'] * parseInt(this.valuePointsCoin);
}).catch(error => {
console.log('error getCurrentCoinsUser :>> ', error);
});
}
*/
}
async alertForceBack(header: string, message: string) {
const alert = await this.alertController.create({
header: header,
message: message,
backdropDismiss: false,
buttons: [
{
text: "Ok",
handler: () => {
this.back();
},
},
],
});
await alert.present();
}
get matchEventCtrl(): any {
return this.eventGroup.get("match_event");
}
getSeats() {
this.showFabsNextButton = false;
this.storage.get("token").then(async (token) => {
this.utilsService.presentLoading(this.translateService.instant("all.loading"));
(await this.ticketsService.getSeats(token.access_token, this.current_sub_zone, this.matchEventId)).subscribe(
(resp: any) => {
this.utilsService.dismissLoading();
if (!resp["original"].r) {
this.utilsService.presentAlertInfo("Localidad (" + this.name_subzone + ") no disponible", "", resp["original"].m);
return;
}
if (resp["original"]["r"]) {
this.list_seats = resp["original"]["data"];
this.group_seats = this.orderGroupBy(this.list_seats, "letter_id");
if (this.group_seats) {
this.group_seats = this.group_seats.slice().reverse();
if (this.userService._infoUser.user_info && !this.userService._infoUser.user_info.is_tutorial_viewed && this.group_seats.length) {
let el: HTMLElement = this.container_image.nativeElement;
el.click();
this.storage.get("token").then((token) => {
this.userService.updateViewTutorial(token.access_token);
});
}
}
this.getSeatPrice();
this.buttonsFabsNext();
} else {
this.current_sub_zone = null;
this.name_subzone = "";
this.utilsService.presentToast(4000, "warning", "top", resp["original"]["m"]);
}
},
(error) => {
this.utilsService.dismissLoading();
console.log("error getSeats: ", error);
}
);
});
}
orderGroupBy(collection: any, property: any) {
const groupedCollection = collection.reduce((previous: any, current: any) => {
if (!previous[current[property]]) {
previous[current[property]] = [current];
} else {
previous[current[property]].push(current);
}
return previous;
}, {});
return Object.keys(groupedCollection).map((key) => ({ key, value: groupedCollection[key] }));
}
getMatchEvents() {
this.storage.get("token").then(async (token) => {
this.utilsService.presentLoading(this.translateService.instant("all.loading"));
(await this.ticketsService.getMatchEvents(token.access_token)).subscribe(
(resp: any) => {
this.utilsService.dismissLoading();
if (this.params.is_social_distancing) {
this.alertConfirmBlock(this.translateService.instant("tickets.alert_distancing"));
}
this.matchEvents = [];
resp.forEach((item: any) => {
if (this.utilsService.validateDate(item.event_start_sale, "start") && this.utilsService.validateDate(item.event_end_sale, "end")) {
this.matchEvents.push(item);
}
});
},
(error) => {
this.utilsService.dismissLoading();
console.log("error getMatchEvents: ", error);
}
);
});
}
loadStadiumZones() {
this.stadiumContainerInvalid = true;
var me = this;
this.storage.get("token").then(async (token) => {
this.utilsService.presentLoading(this.translateService.instant("all.loading"));
(await this.ticketsService.loadStadiumZones(token.access_token, { matchEventId: this.matchEventId })).subscribe(
(resp: any) => {
this.stadium.nativeElement.innerHTML = this.current_match.stadium;
this.utilsService.dismissLoading();
if (!resp.r) {
this.stadium.nativeElement.style.opacity = '0.5';
this.stadium.nativeElement.style.pointerEvents = 'none';
this.alertForceBack(this.translateService.instant("tickets.alert"), resp.m);
return;
}
this.tribunesParent = resp.data;
if (!this.tribunesParent.length) {
this.stadium.nativeElement.style.opacity = '0.5';
this.stadium.nativeElement.style.pointerEvents = 'none';
this.alertForceBack(this.translateService.instant("tickets.alert"), ('No existen sectores configurados con precio para el evento (' + this.current_match.name + ').'));
return;
}
this.stadiumContainerInvalid = false;
let childNodes = this.stadium.nativeElement.childNodes[0].childNodes;
this.tribunesParent.forEach(element => {
let zones = this.getElementChildNodes(childNodes, element.alias);
if (zones.length) {
for (var j = 0; j < zones.length; j++) {
let elClone = zones[j].cloneNode(true);
zones[j].parentNode.replaceChild(elClone, zones[j]);
elClone.style.fill = 'D8D8D6';
if (element.locked) {
elClone.style.fill = '#6A6A6A';
elClone.addEventListener('click', function () { me.utilsService.presentToast(4000, "warning", "top", 'El sector "' + element.name + '" está bloqueada'); });
} else if (!element.available_seats) {
elClone.style.fill = '#FF0000';
elClone.addEventListener('click', function () { me.utilsService.presentToast(4000, "warning", "top", 'El sector "' + element.name + '" no tiene sillas disponibles'); });
} else {
elClone.addEventListener('click', function () { me.loadStadiumSeats(element.id, element.name); });
}
}
}
});
},
(error) => {
this.utilsService.dismissLoading();
console.log("error loadStadiumZones: ", error);
}
);
});
}
loadStadiumSeats(zoneId, zoneName) {
this.current_sub_zone = zoneId;
this.name_subzone = zoneName;
this.getSeats();
}
getSeatPrice() {
this.storage.get("token").then(async (token) => {
(await this.ticketsService.getSeatPrice(token.access_token, this.current_sub_zone, this.matchEventId)).subscribe(
(resp: any) => {
if (!resp["original"].r) {
this.alertConfirmBlock(resp["original"].m);
this.utilsService.dismissLoading();
return;
}
this.match_event_price = resp["original"].data;
},
(error) => {
console.log("error getSeatPrice: ", error);
}
);
});
}
ionViewDidLeave() {
this.unlockScreen();
}
selectionChange(e: any) {
this.resetTabs(e.selectedIndex);
}
buttonsFabsNext() {
if (this.current_tab == 3 && !this.buy_tickets.length) {
return;
}
this.current_tab += 1;
}
buttonsFabsBack() {
this.current_tab -= 1;
}
resetTabs(index: number) {
this.showFabsNextButton = false;
if (index == 0) {
this.buy_tickets = [];
this.name_subzone = "";
this.current_sub_zone = null;
this.group_seats = null;
this.showFabsNextButton = true;
}
if (index == 1) {
this.buy_tickets = [];
this.name_subzone = "";
this.current_sub_zone = null;
this.group_seats = null;
}
if (index == 2) {
if (!this.current_sub_zone) {
setTimeout(() => {
this.buttonsFabsBack();
}, 100);
}
if (this.buy_tickets.length) {
this.showFabsNextButton = true;
}
}
if (index == 3) {
this.payWithCoins = false;
this.calculateTotal();
if (this.buy_tickets.length) {
this.showFabsNextButton = true;
} else {
setTimeout(() => {
this.buttonsFabsBack();
}, 100);
}
}
this.current_tab = index;
}
back() {
this.lockScreen(OrientationType.PORTRAIT);
this.location.back();
}
async selectTypeTicket(seat: any, e: any) {
this.isModalOpen = true;
let inputs = [];
if (this.match_event_price) {
if (this.match_event_price.price > 0) {
let price = this.currencyPipe.transform(this.match_event_price.price, "USD", "symbol", "1.0-0");
inputs.push({
type: "radio",
label: this.translateService.instant("tickets.type_1") + " - " + price,
value: 1,
seat: seat,
e: e
});
}
if (this.match_event_price.price_suscription > 0 && this.current_match.season.is_suscription) {
let price_suscription = this.currencyPipe.transform(this.match_event_price.price_suscription, "USD", "symbol", "1.0-0");
if (this.match_event_price.subscriberPrices.length) {
let subscriberPrices = this.match_event_price.subscriberPrices.find((item: any) => item.seat_id == seat.id);
if (subscriberPrices) {
price_suscription = this.currencyPipe.transform(subscriberPrices.price_suscription, "USD", "symbol", "1.0-0");
}
}
inputs.push({
type: "radio",
label: this.translateService.instant("tickets.type_2") + " - " + price_suscription,
value: 2,
seat: seat,
e: e
});
}
this.typeTickets = inputs;
} else {
this.alertConfirmBlock(this.translateService.instant("tickets.alert_not_price"));
}
}
onTypeTicketSelect(event) {
let value = event.target.value;
let ticket_type_id = value.ticket_type_id ?? value.value;
if (this.validateAddSeat(ticket_type_id)) {
this.ticket_type_id = ticket_type_id;
this.addTicket(value.seat, ticket_type_id);
value.e.target.classList.add("bg-seat-selected");
this.isModalOpen = false;
}
}
addTicket(seat: any, ticket_type_id: any) {
let price = this.seatPrice(seat.id, ticket_type_id);
this.buy_tickets.push({
seat,
match_event_id: this.matchEventId,
ticket_type_id,
match_event_price: null,
price: price,
zone_name: this.name_subzone,
dataTicket: null,
});
this.calculateTotal();
}
seatPrice(seat_id, ticket_type_id: number) {
let price = 0;
if (ticket_type_id == 1) {
price = this.match_event_price.price;
}
if (ticket_type_id == 2) {
price = this.match_event_price.price_suscription;
if (this.match_event_price.subscriberPrices.length) {
let subscriberPrices = this.match_event_price.subscriberPrices.find((item: any) => item.seat_id == seat_id);
if (subscriberPrices) {
price = subscriberPrices.price_suscription;
}
}
}
return price;
}
calculateTotal() {
this.showFabsNextButton = false;
this.subtotal = 0;
this.serviceCharge = 0;
if (this.buy_tickets.length) {
this.showFabsNextButton = true;
this.buy_tickets.forEach((ticket: any) => {
this.subtotal += ticket.price;
});
if (this.serviceChargeEnabled && this.match_event_price.service_charge)
this.serviceCharge = this.match_event_price.service_charge;
}
this.total = this.subtotal + this.serviceCharge;
}
removeSeatListBuy(index: any) {
if (this.buy_tickets && this.buy_tickets.length) {
this.buy_tickets.splice(index, 1);
this.calculateTotal();
}
}
validateAddSeat(ticket_type_id: any) {
if (ticket_type_id == 1 && this.buy_tickets.length >= this.params.maximum_number_ballots) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.alert"),
"",
this.params.msj_maximum_number_tickets_buy ?? this.translateService.instant("tickets.title_message_1")
);
return false;
}
if (ticket_type_id == 2 && this.buy_tickets.length >= this.params.maximum_number_suscription) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.alert"),
"",
this.params.msj_maximum_number_subscriber_tickets_buy ?? this.translateService.instant("tickets.title_message_2")
);
return false;
}
if (this.isPresaleSuscription && ticket_type_id == 1) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.alert"),
"",
this.params.msj_exclusivity_only_subscriber_ticket_sales.replaceAll('{{ type_ticket }}', "Venta libre") ?? this.translateService.instant("tickets.title_message_6", { type_ticket: "Venta libre" })
);
return false;
}
if (ticket_type_id == 1 && this.buy_tickets.filter(ticket => ticket.ticket_type_id == 2).length) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.alert"),
"",
this.params.msj_add_tickets_same_type.replaceAll('{{ type_ticket }}', "Abonado") ?? this.translateService.instant("tickets.title_message_4", { type_ticket: "Abonado" })
);
return false;
}
if (ticket_type_id == 2 && this.buy_tickets.filter(ticket => ticket.ticket_type_id == 1).length) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.alert"),
"",
this.params.msj_add_tickets_same_type.replaceAll('{{ type_ticket }}', "Venta libre") ?? this.translateService.instant("tickets.title_message_4", { type_ticket: "Venta libre" })
);
return false;
}
if (this.isPresaleSuscription && this.buy_tickets.length >= this.listPreSubcriber.length) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.alert"),
"",
this.params.msj_buy_same_number_subscriber_tickets ?? this.translateService.instant("tickets.title_message_5")
);
return false;
}
return true;
}
selectSeat(e: any, seat: any) {
e.target.classList.remove("bg-seat-selected");
if (!seat.ticket && !seat.ticket_user_block && !seat.presubscription && !seat.match_event_stage.length) {
let is_add_seat = this.buy_tickets.find((item: any) => item.seat.id == seat.id);
if (is_add_seat) {
const current_list = (item: any) => item.seat.id == seat.id;
let index = this.buy_tickets.findIndex(current_list);
if (index >= 0) {
e.target.classList.remove("bg-seat-selected");
this.removeSeatListBuy(index);
}
} else {
this.selectTypeTicket(seat, e);
}
} else {
this.utilsService.presentToast(4000, "warning", "top", this.translateService.instant("seat_not_available", { seat: (seat.letter.name + seat.code) }));
}
}
async openListSuscription(index: any, ticket_type_id: any) {
if (ticket_type_id == 2) {
this.unlockScreen();
const modal = await this.modalCtrl.create({
component: ModalListSuscriptionPage,
swipeToClose: true,
presentingElement: this.routerOutlet.nativeEl,
componentProps: {
dataTicket: this.buy_tickets[index].dataTicket,
seasonId: this.current_match.season.id
},
});
const present = await modal.present();
const { data } = await modal.onWillDismiss();
if (data) {
this.buy_tickets[index].dataTicket = data;
}
return present;
}
}
async alertConfirmBlock(message, back = false, data = false) {
const alert = await this.alertController.create({
header: this.translateService.instant("tickets.alert"),
message: message,
backdropDismiss: false,
buttons: [
{
text: "Ok",
handler: () => {
if (back) {
this.back();
setTimeout(() => {
this.ticketsService.purchaseTickets(data);
InAppBrowser.addListener("urlChangeEvent", (state: UrlEvent) => {
if (state.url.indexOf("/close") != -1) {
InAppBrowser.close();
}
});
}, 1000);
}
},
},
],
});
await alert.present();
}
async presentAlertConfirmExit() {
const alert = await this.alertController.create({
header: this.translateService.instant("tickets.alert"),
message: this.translateService.instant("tickets.exit_alert"),
backdropDismiss: false,
buttons: [
{
text: "No",
role: "cancel",
cssClass: "secondary",
handler: () => { },
},
{
text: "Si",
handler: () => {
this.back();
},
},
],
});
await alert.present();
}
createBlocks() {
if (this.userService.validateAlertsUseApp() && this.buy_tickets && this.buy_tickets.length) {
if (this.ticket_type_id == 2) {
let no_data_tickets = this.buy_tickets.filter(ticket => ticket.dataTicket == null).length;
if (no_data_tickets > 0) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.alert"),
"",
this.params.msj_complete_information_subscriber_tickets ?? this.translateService.instant("tickets.title_message_7")
);
return;
}
}
this.storage.get("token").then(async (token) => {
this.utilsService.presentLoading(this.translateService.instant("all.loading"));
let info = {
tickets: this.buy_tickets,
type_process: "block",
subtotal: this.subtotal,
serviceCharge: this.serviceCharge,
amount: this.total,
ticket_type_id: this.ticket_type_id,
season_id: this.current_match.season.id,
payWithCoins: this.payWithCoins,
coinsInMoney: this.oldTotal,
coinsUsed: Math.round(this.oldTotal / this.valuePointsCoin),
currentValuePoint: this.valuePointsCoin
};
(await this.ticketsService.createBlocks(token.access_token, info)).subscribe(
async (resp: any) => {
if (resp.r) {
if (!this.payWithCoins) {
this.utilsService.dismissLoading();
this.utilsService.presentToast(6000, "success", "top", resp.m);
this.router.navigate(["/payment-gateway-selection"], { state: { ticketId: resp.data } });
} else {
(await this.ticketsService.generateTicketBycoins(token.access_token, resp.data)).subscribe(
(resp: any) => {
this.utilsService.dismissLoading();
if (resp.r) {
this.alertForceBack(this.translateService.instant("tickets.alert"), this.translateService.instant("tickets.msg_ticketByCoins"));
} else {
if (resp.locked) {
this.credit_locked = true;
}
this.utilsService.presentToast(6000, "danger", "top", resp.m);
}
},
(error) => {
this.utilsService.dismissLoading();
console.log("error generateTicketBycoins: ", error);
});
}
} else {
this.utilsService.dismissLoading();
this.utilsService.presentToast(6000, "danger", "top", resp.m);
}
},
(error) => {
this.utilsService.dismissLoading();
console.log("error createBlocks: ", error);
}
);
});
}
}
async presentPopover(ev: any) {
const popover = await this.popoverController.create({
component: AboutPopoverTicketPage,
cssClass: "my-custom-class",
event: ev,
translucent: true,
});
return await popover.present();
}
validatePayWithCoins() {
if (!this.payWithCoins && this.currentCoinsInMoney > this.total) {
this.total = this.oldTotal;
this.coinsAfterPurchase = 0;
}
if (this.payWithCoins && this.currentCoinsInMoney < this.total) {
this.utilsService.presentAlertInfo(
this.translateService.instant("tickets.title_insufficientCoins"),
"",
this.translateService.instant("tickets.msg_insufficientCoins", { 'coins': Math.round(((this.total - this.currentCoinsInMoney) / this.valuePointsCoin)) })
);
setTimeout(() => {
this.payWithCoins = false;
}, 500);
return;
} else if (this.payWithCoins && this.currentCoinsInMoney > this.total) {
this.coinsAfterPurchase = this.currentCoinsInMoney - this.total;
this.oldTotal = this.total;
this.total = 0;
}
}
closeModal() {
this.isModalOpen = false;
}
lockScreen(orientation) {
if (Capacitor.isNativePlatform()) {
ScreenOrientation.lock({ type: orientation });
}
}
unlockScreen() {
if (Capacitor.isNativePlatform()) {
ScreenOrientation.unlock();
}
}
getElementChildNodes(childNodes, alias, childs = []) {
for (var i = 0; i < childNodes.length; i++) {
if (childNodes[i].attributes && childNodes[i].attributes.alt && childNodes[i].attributes.alt.value == alias) {
childs.push(childNodes[i]);
} else if (childNodes[i].childNodes) {
this.getElementChildNodes(childNodes[i].childNodes, alias, childs);
}
}
return childs;
}
zoomIn() {
this.resize(1.2);
}
zoomOut() {
this.resize(0.8);
}
resize(scale = 1) {
const svg: any = this.stadium.nativeElement.firstChild;
let svgWidth = parseInt(svg.width.animVal.value);
svg.setAttribute('width', `${svgWidth * scale}`);
// let svgHeight = parseInt(svg.height.animVal.value);
// svg.setAttribute('height', `${svgHeight * scale}`);
}
}