From 51e78042b50312fd780f36c8a38c77ea9672dcde Mon Sep 17 00:00:00 2001 From: zino Date: Fri, 14 May 2021 20:16:39 +0200 Subject: [PATCH] before state inputswithvalue --- client/src/inject.ts | 1 - client/src/modules/cart.ts | 154 +++++++ client/src/modules/events.ts | 86 ++++ client/src/modules/jsc.ts | 119 ++++- client/src/modules/state.ts | 55 +++ client/src/modules/ui.ts | 83 +++- client/src/modules/xmlhelper.ts | 118 ++++- client/src/seatmap.ts | 784 ++++---------------------------- client/src/types/types.d.ts | 3 +- 9 files changed, 700 insertions(+), 703 deletions(-) create mode 100644 client/src/modules/cart.ts create mode 100644 client/src/modules/state.ts diff --git a/client/src/inject.ts b/client/src/inject.ts index df35752..34b3d97 100644 --- a/client/src/inject.ts +++ b/client/src/inject.ts @@ -56,7 +56,6 @@ function messageHandler(e: any) { if (typeof (e.data) !== 'string') return; - // Decode JSON postMessage data const data: I.Message = JSON.parse(e.data); console.log(`parent: received from ${data.from}`); diff --git a/client/src/modules/cart.ts b/client/src/modules/cart.ts new file mode 100644 index 0000000..4d98918 --- /dev/null +++ b/client/src/modules/cart.ts @@ -0,0 +1,154 @@ +import * as XMLHelper from "./xmlhelper"; +import { config } from "./config"; +import * as I from "../types/types"; +import * as UI from "./ui"; +import * as Events from "./events"; + +export function addItem(inSeatObj: I.JSCSelectedSeat, inVenueXML: I.VenueXML, inInputsWithValue: I.InputsWithValue) { + const color = `#${XMLHelper.getVenuePricescalePropertyByPricescaleID("color", inSeatObj.data.seatsObj.id[0], inVenueXML)}`; + const category = XMLHelper.getVenuePricescalePropertyByPricescaleID("desc", inSeatObj.data.seatsObj.id[0], inVenueXML); + const seat = config.state.layoutRows[inSeatObj.id][5]; + const row = config.state.layoutRows[inSeatObj.id][4]; + const sectionID = config.state.layoutRows[inSeatObj.id][3]; + const sectionDesc = XMLHelper.getSectionDescBySectionID(inVenueXML, sectionID); + const seatStr = `${sectionDesc}
Reihe ${row} Platz ${seat}`; + const buyerTypes: (string | undefined)[][] | undefined = getBuyerTypesByPricescaleID(inSeatObj.data.seatsObj.id[0], inVenueXML); + const cartId = `cartItem-${inSeatObj.id}`; + const dropdownBuyerTypesSelector = `#${cartId} .dropdownBuyerTypes`; + + appendHTML(cartId, color, category, seatStr); + addDropdownBuyerTypesOptions(buyerTypes, dropdownBuyerTypesSelector); + Events.addCartDropdownBuyerTypes(dropdownBuyerTypesSelector, inSeatObj, inVenueXML, inInputsWithValue); +} + +function appendHTML(inCartId: string, inColor: string, inCategory: string | undefined, inSeatStr: string) { + jQuery("#cartItemHTML .fl-html").append(` +
+
+
${inCategory}
+
${inSeatStr}
+ +
`); +} + +// todo: generalize dropdown fill options +function addDropdownBuyerTypesOptions(inBuyerTypes: (string | undefined)[][] | undefined, inSelector: string) { + if (!inBuyerTypes) + return; + + const dropdownBuyerTypes = jQuery(inSelector).get(0); + + inBuyerTypes.forEach(arr => { + if (!arr[0]) + return; + + let opt = document.createElement('option'); + opt.value = arr[0]; + opt.innerHTML = `${arr[2]} €${arr[1]}`; + dropdownBuyerTypes.appendChild(opt); + }); +} + +// function appendOptionDropdownBuyerTypesOptions() { +// let opt = document.createElement('option'); +// opt.value = arr[0]; +// opt.innerHTML = `${arr[2]} €${arr[1]}`; +// dropdownBuyerTypes.appendChild(opt); +// } + +function getBuyerTypesByPricescaleID(inPricescaleID: string, inVenueXML: I.VenueXML) { + const venuePricescaleArr = inVenueXML.price_structure[0].pricescale; + const buyerTypesArr = venuePricescaleArr.find(obj => { + return obj.id[0] === inPricescaleID; + })?.buyer_type; + + if (!buyerTypesArr) + return; + + const buyerTypes: (string | undefined)[][] = buyerTypesArr.map(arr => { + const buyerTypeDesc = inVenueXML.venue[0].buyer_types[0].buyer_type.find(obj => { + return obj.id[0] === arr.id[0] ? obj.desc[0] : undefined; + })?.desc[0]; + + return [arr.id[0], arr.price[0], buyerTypeDesc]; + }); + + return buyerTypes; +} + +export function removeCartItems() { + jQuery("#cartItemHTML .cartItem").each(function () { + this.remove(); + }); +} + +export function changedDropdownBuyerType(inSelect: HTMLSelectElement, inSeatObj: I.JSCSelectedSeat, inVenueXML: I.VenueXML, inInputsWithValue: I.InputsWithValue) { + const index = config.state.selectedSeatsArr.findIndex(arr => { + return arr[0] === inSeatObj.id; + }); + + config.state.selectedSeatsArr[index][1] = inSelect.value; + + const buyerTypeCode = XMLHelper.getBuyerTypeCodeByBuyerTypeID(inVenueXML, inSelect.value); + + if (buyerTypeCode) + config.state.selectedSeatsArr[index][2] = buyerTypeCode; + + calcOverallPrice(inVenueXML); + UI.setBtnCartText(); + + const url = XMLHelper.generateCheckoutUrl(inInputsWithValue); + console.log(url); + Events.addRedirectCheckout(url); + + console.log(config.state); +} + +export function calcOverallPrice(inVenueXML: I.VenueXML): string | undefined { + if (!config.state.selectedSeatsArr.length) { + config.state.priceOverall = "0"; + return "0"; + } + + let overallPrice: number = 0; + + config.state.selectedSeatsArr.forEach(arr => { + const seatID: string = arr[0]; + const buyertypeID: string = arr[1]; + const selectedSeat: I.JSCSelectedSeat = config.state.selectedSeatsObj[seatID]; + const pricescaleID: string = selectedSeat.data.seatsObj.id[0]; + const pricescaleObj: I.Pricescale5 | undefined = XMLHelper.getVenuePriceStructurePropertyByPricescaleID(inVenueXML, pricescaleID); + + if (!pricescaleObj) + return; + + const seatPrice: number | undefined = XMLHelper.getPriceByBuyertypeID(buyertypeID, pricescaleObj); + + if (!seatPrice) + return; + + overallPrice += seatPrice; + }); + + config.state.priceOverall = overallPrice.toFixed(2); + + return config.state.priceOverall; +} + +export function generateCartItems(inVenueXML: I.VenueXML, inInputsWithValue: I.InputsWithValue) { + if (!config.state.selectedSeatsArr.length) + return; + + for (const key in config.state.selectedSeatsObj) { + if (Object.prototype.hasOwnProperty.call(config.state.selectedSeatsObj, key)) { + const element = config.state.selectedSeatsObj[key]; + addItem(element, inVenueXML, inInputsWithValue); + } + } +} + +export function initModalCart() { + jQuery("#modalCart-overlay").hide(); + Events.addCartBack(); + Events.addCartClose(); +} \ No newline at end of file diff --git a/client/src/modules/events.ts b/client/src/modules/events.ts index d22fc04..7f6df72 100644 --- a/client/src/modules/events.ts +++ b/client/src/modules/events.ts @@ -1,5 +1,10 @@ import * as Communication from "./communication"; import * as UI from "./ui"; +import { config } from "./config"; +import * as XMLHelper from "./xmlhelper"; +import * as I from "../types/types"; +import * as JSC from "./jsc"; +import * as Cart from "./cart"; export function addCloseModal() { const btnCloseModal: HTMLElement | undefined = jQuery("#btnCloseModal").get(0); @@ -17,3 +22,84 @@ export function addDropdownSeatmap(inPanzoom: any) { }); } } + +export function addModalCart(inInputsWithValue: I.InputsWithValue) { + const btnCart: HTMLElement | undefined = jQuery("#modalCart .uabb-button").get(0); + if (btnCart) { + btnCart.addEventListener("click", () => { + if (!config.state.selectedSeatsArr.length) + UI.showJBoxNotice(`Sie haben bislang keinen Platz ausgewählt.`); + else if (config.state.cartChanged) + XMLHelper.isValidSeatSelection(inInputsWithValue); + else if (!config.state.cartChanged && config.state.isValidSeatSelection) + UI.showModalCart(); + else if (!config.state.cartChanged && !config.state.isValidSeatSelection) + UI.showJBoxNotice(`Auswahl nicht möglich: Bitte lassen Sie keinen einzelnen Platz frei.`); + }); + } +} + +export function addRedirectCheckout(inUrl: string | undefined) { + if (!inUrl) + return; + + const btnCheckout = jQuery("#modalCart-overlay #checkout .fl-button").get(0); + if (btnCheckout) { + btnCheckout.addEventListener("click", function () { + const message: I.Message = { + message: { + url: inUrl, + }, + from: "child", + event: "child_click_checkout", + date: Date.now() + }; + Communication.sendMessage(message, "parent"); + }); + } +} + +export function addCartClose() { + const btnClose = jQuery("#modalCart-overlay .uabb-close-icon").get(0); + if (btnClose) { + btnClose.addEventListener("click", function () { + Communication.sendEventToParent("child_show_dialog_titlebar"); + }); + } +} + +export function addCartBack() { + const btnBack = jQuery("#modalCart-overlay #goBack .fl-button").get(0); + if (btnBack) { + btnBack.addEventListener("click", function () { + jQuery("#modalCart-overlay .uabb-close-icon").trigger("click"); + }); + } +} + +export function dropdownLegendOnChange(inSelector: string, inSeatmap: any, inSeatmapXML: any) { + const dropdownLegend = jQuery(inSelector).get(0); + dropdownLegend.addEventListener("change", function (this: HTMLSelectElement) { + const value: string = this.value; + const className: string = `._${value}`; + + UI.changeDropdownLegendBGColor(inSelector, value, className); + + if (value === "all") { + inSeatmap.find('unavailable').status('available'); + JSC.setUnavailableSeats(inSeatmapXML, inSeatmap); + } + else { + inSeatmap.find('available').status('unavailable'); + JSC.activateSeatsBySectionID(inSeatmapXML, inSeatmap, value); + JSC.setUnavailableSeats(inSeatmapXML, inSeatmap); + } + + }); +} + +export function addCartDropdownBuyerTypes(inSelector: string, inSeatObj: I.JSCSelectedSeat, inVenueXML: I.VenueXML, inInputsWithValue: I.InputsWithValue) { + jQuery(inSelector).on('change', function (this: HTMLSelectElement) { + Cart.changedDropdownBuyerType(this, inSeatObj, inVenueXML, inInputsWithValue); + }); +} \ No newline at end of file diff --git a/client/src/modules/jsc.ts b/client/src/modules/jsc.ts index 9d980aa..1f30bef 100644 --- a/client/src/modules/jsc.ts +++ b/client/src/modules/jsc.ts @@ -1,5 +1,8 @@ import * as I from "../types/types"; -import { state } from "../seatmap"; +import { config } from "./config"; +import * as State from "./state"; +import * as Cart from "./cart"; +import * as UI from "./ui"; export function getSeats(inXML: any): I.JSCSeats { const pricescaleArr: I.SeatmapPricescale[] = inXML.seatmap[0].pricescale_config[0].pricescale; @@ -205,7 +208,7 @@ function enterSeatsInMatrix(inRows: I.LayoutRow2[], inArrMatrix: string[][], inP inArrMatrix[Y][X] = generateSeatStr(seatsKey, seatArr); // save seatArr in state with seatID as key - state.layoutRows[seatArr[0]] = seatArr; + config.state.layoutRows[seatArr[0]] = seatArr; }); }); @@ -244,4 +247,116 @@ export function createArrMatrix(inNumrows: number, inNumcols: number, inInitial: } return arr; +} + +export function addTrims(inSeatmapXML: any) { + const trimArr: I.Trim[] = inSeatmapXML.seatmap[0].trims[0].trim; + trimArr.forEach(arr => { + const [xTrim, yTrim] = arr.coord[0].split(",").map(Number); + const textArr: string[] = arr.text[0].split(";").filter(Boolean); + const x = xTrim / 20; + const y = Math.round(yTrim / 21.25); + + console.log(`xTrim: ${xTrim} yTrim: ${yTrim} -> x: ${x} y: ${y}`); + + decodeAddTrims(textArr, x, y); + }); +} + +function decodeAddTrims(textArr: string[], x: number, y: number) { + let i = 0; + const specialChar = new Map([ + ["Ž", "Ä"], + ["™", "Ö"], + ["š", "Ü"], + ["„", "ä"], + ["”", "ö"], + ["", "ü"], + ["á", "ß"] + ]); + + textArr.forEach(element => { + let character; + + if (specialChar.has(element)) + character = specialChar.get(element); + else { + const charCode = element.replace(/^\&\#/, "0"); + character = String.fromCharCode(parseInt(charCode, 16)); + } + + if (character) + applyTrim(x, y, i, character); + + i++; + }); +} + +function applyTrim(x: number, y: number, i: number, character: string) { + if (!/[^a-zA-Z0-9äöüÄÖÜß$]/.test(character)) { + const _x = (x - 1) + i; + const _y = y - 1; + console.log(`${character} -> ${_x} ${_y}`); + jQuery(".seatCharts-row")[_y].children[_x].innerHTML = `${character}` + } +} + +export function selectSeatsInCart(inSeatmap: any) { + config.state.selectedSeatsArr.forEach(arr => { + const seatID: string = arr[0]; + + if (inSeatmap.get(seatID)) + inSeatmap.status(seatID, "selected"); + }); +} + +export function addSeatmap(inSelector: string, inMap: string[], inRowsNaming: string[], inSeats: I.JSCSeats, inLegend: I.JSCLegend, inSeatmap: any, inVenueXML: I.VenueXML): void { + const containerSeatmap: any = (window).jQuery(inSelector); + + // console.log(inSeatmapInitMap); + // console.log(inSeats); + // console.log(inLegend); + + inSeatmap = containerSeatmap.seatCharts({ + naming: { + top: false, + left: false, + rows: inRowsNaming, + }, + map: inMap, + seats: inSeats, + legend: inLegend, + click: function () { + if (this.status() == 'available') { + const selectedSeat: I.JSCSelectedSeat = this.settings; + + console.log(selectedSeat); + + if (State.maximumSelectedSeatsReached(selectedSeat, inSeatmap)) + return "available"; + + State.addSeatToState(inVenueXML, selectedSeat); + Cart.calcOverallPrice(inVenueXML); + UI.setBtnCartText(); + + return "selected"; + } + else if (this.status() === "selected") { + const selectedSeat: I.JSCSelectedSeat = this.settings; + + State.removeSeatFromState(selectedSeat); + Cart.calcOverallPrice(inVenueXML); + UI.setBtnCartText(); + console.log(config.state.selectedSeatsArr); + + return "available"; + } + else if (this.status() == 'unavailable') { + return "unavailable"; + } + else { + return this.style(); + } + } + }); } \ No newline at end of file diff --git a/client/src/modules/state.ts b/client/src/modules/state.ts new file mode 100644 index 0000000..b77df2f --- /dev/null +++ b/client/src/modules/state.ts @@ -0,0 +1,55 @@ +import { config } from "./config"; +import * as I from "../types/types"; +import * as XMLHelper from "./xmlhelper"; +import * as UI from "./ui"; + +export function addSeatToState(inVenueXML: I.VenueXML, inSelectedSeat: I.JSCSelectedSeat) { + const seatID: string = inSelectedSeat.id; + const seatObj: I.StateJSCSelectedSeats = { + [seatID]: inSelectedSeat + } + + config.state.selectedSeatsObj = { ...config.state.selectedSeatsObj, ...seatObj }; + + const pricescaleID: string = config.state.selectedSeatsObj[seatID].data.seatsObj.id[0]; + const pricescaleObj: I.Pricescale5 | undefined = XMLHelper.getVenuePriceStructurePropertyByPricescaleID(inVenueXML, pricescaleID); + console.log(pricescaleObj); + + if (!pricescaleObj) { + console.warn(`Cannot find corresponding venueXML pricescaleObj for pricescale with ID ${pricescaleID}`); + return; + } + + // get id and code of first buyer type + const firstBuyerTypeID: string = pricescaleObj.buyer_type[0].id[0]; + // const firstPriceStructureCode: string = inVenueXML.price_structure[0].code[0]; // todo: code of first price_structure always correct? what about multiple schablonen? + const buyerTypeCode: string | undefined = XMLHelper.getBuyerTypeCodeByBuyerTypeID(inVenueXML, firstBuyerTypeID); + + if (buyerTypeCode) { + config.state.selectedSeatsArr.push([seatID, firstBuyerTypeID, buyerTypeCode]); + config.state.cartChanged = true; + } +} + +export function removeSeatFromState(inSelectedSeat: I.JSCSelectedSeat) { + const seatID: string = inSelectedSeat.id; + delete config.state.selectedSeatsObj[seatID]; + const index = config.state.selectedSeatsArr.findIndex(arr => { + return arr[0] === inSelectedSeat.id; + }); + config.state.selectedSeatsArr.splice(index, 1); + config.state.cartChanged = true; + + if (!config.state.selectedSeatsArr.length) + jQuery("#modalCart-overlay").hide(); +} + +export function maximumSelectedSeatsReached(inSeatObj: I.JSCSelectedSeat, inSeatmap: any): boolean { + if (config.state.selectedSeatsArr.length >= config.maxSelectedSeats) { + UI.showJBoxNotice(`Sie können maximal ${config.maxSelectedSeats} Plätze auswählen.`); + inSeatmap.status(inSeatObj.id, "available"); + return true; + } + + return false; +} \ No newline at end of file diff --git a/client/src/modules/ui.ts b/client/src/modules/ui.ts index 253da46..bed4a40 100644 --- a/client/src/modules/ui.ts +++ b/client/src/modules/ui.ts @@ -3,7 +3,8 @@ import * as Communication from "./communication"; import Panzoom from '@panzoom/panzoom'; import { PanzoomObject } from "@panzoom/panzoom/dist/src/types"; import { config } from "./config"; - +import jBox from "jbox"; +import * as XMLHelper from "./xmlhelper"; export function setOptionSelect(inSeatmapListing: I.Seatmap[], inId: string) { const seatmapDropdown: HTMLElement | null = document.getElementById(inId); @@ -171,4 +172,84 @@ export function showHideBtnCartLoading(inSwitch: string) { export function showModalCart() { jQuery("#modalCart-overlay").fadeIn(300); Communication.sendEventToParent("child_hide_dialog_titlebar"); +} + +export function showJBoxNotice(inContent: string, inAutoClose: number | boolean | undefined = 5000) { + new jBox('Notice', { + position: { x: 'center', y: 'top' }, + offset: { x: 0, y: 320 }, + content: inContent, + autoClose: inAutoClose, + animation: { open: "zoomIn", close: "zoomOut" }, + closeOnEsc: false, + closeButton: true, + closeOnMouseleave: false, + closeOnClick: false, + draggable: false, + color: "red", + stack: true, + showCountdown: true, + reposition: true, + responsiveWidth: true, + responsiveHeight: true, + }); +} + +export function showSeatmapBtnParent(): void { + console.log("child completely ready"); + Communication.sendEventToParent("child_seatmap_ready"); +} + +export function createSeatTooltips(inVenueXML: I.VenueXML) { + new jBox("Tooltip", { + attach: jQuery(".seatCharts-seat"), + onOpen: function (this: any) { + showSeatTooltip(this, inVenueXML); + }, + }); +} + +function showSeatTooltip(jBox: any, inVenueXML: I.VenueXML): void { + const seatID: string = jBox.source[0].id; + const seat = config.state.layoutRows[seatID][5]; + const row = config.state.layoutRows[seatID][4]; + const sectionID = config.state.layoutRows[seatID][3]; + const sectionDesc = XMLHelper.getSectionDescBySectionID(inVenueXML, sectionID); + const tooltipContent = `${sectionDesc}
Reihe ${row} Platz ${seat}`; + + jBox.setContent(tooltipContent); +} + +export function setBtnCartText() { + const numTickets = config.state.selectedSeatsArr.length; + let text: string = ""; + let textModal: string = ""; + + console.log(numTickets); + + if (config.state.priceOverall !== "") { + numTickets === 1 ? text = `${numTickets} Ticket für €${config.state.priceOverall}` : text = `${numTickets} Tickets für €${config.state.priceOverall}`; + textModal = `Summe (${numTickets} Plätze) €${config.state.priceOverall}`; + } + else { + text = "0 Tickets für €0.00"; + textModal = `Summe (0 Plätze) €0,00`; + } + + jQuery("#modalCart .uabb-button-text")[0].innerText = text; + jQuery("#modalCartSum .uabb-heading-text")[0].textContent = textModal; +} + +export function changeDropdownLegendBGColor(inSelector: string, inValue: string, inClassName: string) { + let bgColor: string = "#fafafa"; + let color: string = "#5c5c5c"; + + if (inValue !== "all") { + color = "white"; + bgColor = jQuery(inClassName).css("background-color"); + } + + jQuery(inSelector).css("color", color); + jQuery(inSelector).css("background-color", bgColor); + jQuery(`${inSelector} option[value="all"]`).css("color", color); } \ No newline at end of file diff --git a/client/src/modules/xmlhelper.ts b/client/src/modules/xmlhelper.ts index a3dd700..623e515 100644 --- a/client/src/modules/xmlhelper.ts +++ b/client/src/modules/xmlhelper.ts @@ -2,7 +2,10 @@ import axios, { AxiosResponse } from 'axios'; var xml2jsParser = require('xml2js').parseString; import * as I from "../types/types"; import Utils from './utils'; -//import { state } from "../seatmap"; +import * as UI from "./ui"; +import { config } from "./config"; +import * as Communication from "./communication"; + export function getXMLPromise(url: string): Promise { return axios.get(url) @@ -60,3 +63,116 @@ export function getEventInfo(inVenueXML: I.VenueXML): I.EventInfo { return eventInfo; } +export function isValidSeatSelection(inInputsWithValue: I.InputsWithValue) { + console.log("checking seat selection"); + console.log(inInputsWithValue); + jQuery("#modalCart-overlay").hide(); + + if (!config.state.selectedSeatsArr.length) + return; + + UI.showHideBtnCartLoading("show"); + + jQuery("#modalCart i").hide(); + jQuery("#modalCart .uabb-button-text").addClass("dot-pulse"); + + const url = generateCheckoutUrl(inInputsWithValue); + + // const selectedSeatIndexes: string = generateSelectedSeatIndexes(); + // const url: string = `${inputsWithValue["ticketPurchaseUrl"]}?user_context=${inputsWithValue.user_context}&pid=${inputsWithValue["pid"]}&selected_seat_indexes=${selectedSeatIndexes}&trxstate=148`; + + const message: I.Message = { + message: { + url: url, + }, + from: "child", + event: "child_needCheckoutResponse", + date: Date.now() + }; + Communication.sendMessage(message, "parent"); +} + +export function generateCheckoutUrl(inInputsWithValue: I.InputsWithValue): string | undefined { + console.log(inInputsWithValue); + if (!config.state.selectedSeatsArr.length) + return; + else { + const selectedSeatIndexes: string = generateSelectedSeatIndexes(); + return `${inInputsWithValue["ticketPurchaseUrl"]}?user_context=${inInputsWithValue.user_context}&pid=${inInputsWithValue["pid"]}&selected_seat_indexes=${selectedSeatIndexes}&trxstate=148`; + } +} + +function generateSelectedSeatIndexes(): string { + return (config.state.selectedSeatsArr.map(function (arr) { + return arr.join(","); + })).join("|"); +} + +export function getSectionDescBySectionID(inVenueXML: I.VenueXML, sectionID: string): string | undefined { + const sectionArr = inVenueXML.master_config[0].section_config[0].section; + + const sectionDesc = sectionArr.find(arr => { + return sectionID === arr.id[0]; + })?.desc[0]; + + return sectionDesc; +} + +export function processSMAP(inInputsWithValue: I.InputsWithValue) { + if (!inInputsWithValue.smap) + return; + + const smapArr = inInputsWithValue.smap.split("").map(Number); + + if (!smapArr[0]) + jQuery("#eventInfoCapacity").hide(); +} + +export function getVenuePricescalePropertyByPricescaleID(property: I.Pricescale2Properties, pricescaleID: string, inVenueXML: I.VenueXML) { + const venuePricescaleArr: I.Pricescale2[] = inVenueXML.venue[0].pricescales[0].pricescale; + + return venuePricescaleArr.find(obj => { + if (obj.id[0] === pricescaleID) + return obj; + + return undefined; + })?.[property][0]; +} + +export function getBuyerTypeCodeByBuyerTypeID(inVenueXML: I.VenueXML, inBuyerTypeID: string): string | undefined { + const venueBuyerTypeArr = inVenueXML.venue[0].buyer_types[0].buyer_type; + return venueBuyerTypeArr.find(arr => { + return inBuyerTypeID === arr.id[0]; + })?.code[0]; +} + +export function getPriceByBuyertypeID(inBuyertypeID: string, inPricescaleObj: I.Pricescale5) { + const price = inPricescaleObj?.buyer_type.find(arr => { + return arr.id[0] === inBuyertypeID; + })?.price[0]; + + if (price) + return parseFloat(price); + + return undefined; +} + +export function getVenuePriceStructurePropertyByPricescaleID(inVenueXML: I.VenueXML, inID: string): I.Pricescale5 | undefined { + const venuePricescaleArr: I.Pricescale5[] = inVenueXML.price_structure[0].pricescale; + return venuePricescaleArr.find(obj => { + return obj.id[0] === inID; + }); +} + +export function generatePricescaleCSS(inVenueXML: I.VenueXML): string { + const venuePricescalesArr: I.Pricescale2[] = inVenueXML.venue[0].pricescales[0].pricescale; + let cssArr: string[] = []; + + venuePricescalesArr.forEach(element => { + const ID: string = element.id[0]; + let color: string = `#${element.color[0]} !important`; // Update: Colors are always defined: fallback colors exist in system so every XML provides them + cssArr.push(`._${ID} { background-color: ${color}; }`); + }); + + return (cssArr.join("\r\n")); +} \ No newline at end of file diff --git a/client/src/seatmap.ts b/client/src/seatmap.ts index 23d0f85..3a08c80 100644 --- a/client/src/seatmap.ts +++ b/client/src/seatmap.ts @@ -7,26 +7,19 @@ import * as JSC from "./modules/jsc"; import { config } from "./modules/config"; import Utils from "./modules/utils"; import { PanzoomObject } from "@panzoom/panzoom"; -import jBox from "jbox"; import * as Events from "./modules/events"; require("jbox/dist/jBox.all.css"); +import * as Cart from "./modules/cart"; let inputsWithValue: I.InputsWithValue; let seatmap: any; let panzoom: PanzoomObject | undefined; let inVenueXML: I.VenueXML; let seatmapXML: any; -export let state: I.State = { - priceOverall: "", - cartChanged: false, - selectedSeatsArr: [], - selectedSeatsObj: {}, - layoutRows: {}, - isValidSeatSelection: false -} window.addEventListener('load', () => { - // Inject JSC (jQuery Seat Charts) and inject CSS for JSC, child and jQuery dialog + // Inject JSC (jQuery Seat Charts) + // Inject CSS for JSC, child and jQuery dialog Utils.inject(config.urlJSCStaging, "js", "head"); Utils.inject(config.urlCSSJSCStaging, "css", "body"); Utils.inject(config.urlCSSChildStaging, "css", "body"); @@ -36,484 +29,20 @@ window.addEventListener('load', () => { Communication.listenToMessages(messageHandler); // Div with ID "containerSeatmap" is not yet ready, wait for it, then display seatmap button on trxstate 20 - Utils.waitForSeatmap(showSeatmapBtnParent); + Utils.waitForSeatmap(UI.showSeatmapBtnParent); // Modal overlay for cart is not yet ready, wait for it, then initialize - Utils.waitForElement("#modalCart-overlay", initModalCart); + Utils.waitForElement("#modalCart-overlay", Cart.initModalCart); + // Add event listeners Events.addCloseModal(); - //Events.addCart(inputsWithValue); - Events.addDropdownSeatmap(panzoom); - - const btnCart: HTMLElement | undefined = jQuery("#modalCart .uabb-button").get(0); - if (btnCart) { - btnCart.addEventListener("click", () => { - if (!state.selectedSeatsArr.length) - showJBoxNotice(`Sie haben bislang keinen Platz ausgewählt.`); - else if (state.cartChanged) - isValidSeatSelection(inputsWithValue); - else if (!state.cartChanged && state.isValidSeatSelection) - UI.showModalCart(); - else if (!state.cartChanged && !state.isValidSeatSelection) - showJBoxNotice(`Auswahl nicht möglich: Bitte lassen Sie keinen einzelnen Platz frei.`); - }); - } + Events.addModalCart(inputsWithValue); + Events.addDropdownSeatmap(panzoom); }); -function showJBoxNotice(inContent: string, inAutoClose: number | boolean | undefined = 5000) { - new jBox('Notice', { - position: { x: 'center', y: 'top' }, - offset: { x: 0, y: 320 }, - content: inContent, - autoClose: inAutoClose, - animation: { open: "zoomIn", close: "zoomOut" }, - closeOnEsc: false, - closeButton: true, - closeOnMouseleave: false, - closeOnClick: false, - draggable: false, - color: "red", - stack: true, - showCountdown: true, - reposition: true, - responsiveWidth: true, - responsiveHeight: true, - }); -} - -function isValidSeatSelection(inInputsWithValue: I.InputsWithValue) { - jQuery("#modalCart-overlay").hide(); - - if (!state.selectedSeatsArr.length) - return; - - UI.showHideBtnCartLoading("show"); - - jQuery("#modalCart i").hide(); - jQuery("#modalCart .uabb-button-text").addClass("dot-pulse"); - - const url = generateCheckoutUrl(inInputsWithValue); - - // const selectedSeatIndexes: string = generateSelectedSeatIndexes(); - // const url: string = `${inputsWithValue["ticketPurchaseUrl"]}?user_context=${inputsWithValue.user_context}&pid=${inputsWithValue["pid"]}&selected_seat_indexes=${selectedSeatIndexes}&trxstate=148`; - - const message: I.Message = { - message: { - url: url, - }, - from: "child", - event: "child_needCheckoutResponse", - date: Date.now() - }; - Communication.sendMessage(message, "parent"); -} - -function generateCheckoutUrl(inInputsWithValue: I.InputsWithValue): string | undefined { - if (!state.selectedSeatsArr.length) - return; - else { - const selectedSeatIndexes: string = generateSelectedSeatIndexes(); - return `${inInputsWithValue["ticketPurchaseUrl"]}?user_context=${inInputsWithValue.user_context}&pid=${inInputsWithValue["pid"]}&selected_seat_indexes=${selectedSeatIndexes}&trxstate=148`; - } -} - -function generateSelectedSeatIndexes(): string { - return (state.selectedSeatsArr.map(function (arr) { - return arr.join(","); - })).join("|"); -} - -function showSeatmapBtnParent(): void { - console.log("child completely ready"); - Communication.sendEventToParent("child_seatmap_ready"); -} - -function messageHandler(inE: any) { - if (typeof (inE.data) !== 'string') - return; - - const data: I.Message = JSON.parse(inE.data); - console.log(`child: received from ${data.from}`); - console.log(data); - - switch (data.event) { - case "parent_init_venue": { - UI.controlLoftloader("show"); - Communication.sendEventToParent("child_init_needInputsWithValue"); - break; - } - case "parent_init_sendVenueXML": { - inVenueXML = data.message.map_response; - - // generate pricescale css classes - const css = generatePricescaleCSS(inVenueXML); - Utils.inject(css, "cssCustom", "body"); - console.log(css); - - // fill event info - const eventInfo = XMLHelper.getEventInfo(inVenueXML); - UI.setEventInfo(eventInfo, inputsWithValue); - - // fill select dropdown - const seatmapListing: I.Seatmap[] = XMLHelper.getSeatmapListing(inVenueXML); - console.log(seatmapListing); - UI.setOptionSelect(seatmapListing, "dropdownSeatmap"); - - // display first seatmapXML - const id: string = seatmapListing[0].id[0]; - jQuery("#dropdownSeatmap").val(id); - Communication.needSeatmapXML(id); - - break; - } - case "parent_init_sendInputsWithValue": { - inputsWithValue = data.message; - UI.changeVenueImage(inputsWithValue); - Communication.sendEventToParent("child_init_needVenueXML"); - break; - } - case "parent_sendSeatmapXML": { - seatmapXML = data.message.map_response; - const map: string[] = JSC.generateMap(seatmapXML); - const rowsNaming: string[] = JSC.getRowsNaming(seatmapXML); - const seats: I.JSCSeats = JSC.getSeats(seatmapXML); - const legend: I.JSCLegend = JSC.generateLegend(inVenueXML, seatmapXML, "#JSCLegendInner"); - - addSeatmap("#containerSeatmapInner", map, rowsNaming, seats, legend); - - JSC.setUnavailableSeats(seatmapXML, seatmap); - selectSeatsInCart(); - UI.convertLegendToDropdown("dropdownLegend"); - dropdownLegendOnChange("#dropdownLegend"); - // jQuery("#containerSeatmapInner").append('
foobar
'); - - - addTrims(); - - processSMAP(); - - panzoom = UI.addPanzoom("#containerSeatmapInner", ".panzoomZoomIn", ".panzoomZoomOut", "#panzoomResetZoom"); - UI.controlLoftloader("hide"); - - - new jBox("Tooltip", { - attach: jQuery(".seatCharts-seat"), - onOpen: function (this: any) { - showSeatTooltip(this); - }, - }); - - - break; - } - case "parent_sendCheckoutResponse": { - console.log(data.message); - state.isValidSeatSelection = data.message.isValidSeatSelection; - - if (!state.isValidSeatSelection) { - showJBoxNotice(`Auswahl nicht möglich: Bitte lassen Sie keinen einzelnen Platz frei.`); - UI.showHideBtnCartLoading("hide"); - } - else { - removeCartItems(); - generateCartItems(); - const url = generateCheckoutUrl(inputsWithValue); - setCheckoutBtn(url); - UI.showModalCart(); - UI.showHideBtnCartLoading("hide"); - } - - state.cartChanged = false; - - break; - } - - default: - break; - } -} - -function processSMAP() { - if (!inputsWithValue.smap) - return; - - const smapArr = inputsWithValue.smap.split("").map(Number); - - if (!smapArr[0]) - jQuery("#eventInfoCapacity").hide(); -} - -function addTrims() { - const trimArr: I.Trim[] = seatmapXML.seatmap[0].trims[0].trim; - trimArr.forEach(arr => { - const [xTrim, yTrim] = arr.coord[0].split(",").map(Number); - const textArr: string[] = arr.text[0].split(";").filter(Boolean); - const x = xTrim / 20; - const y = Math.round(yTrim / 21.25); - - console.log(`xTrim: ${xTrim} yTrim: ${yTrim} -> x: ${x} y: ${y}`); - - decodeAddTrims(textArr, x, y); - }); -} - -function decodeAddTrims(textArr: string[], x: number, y: number) { - let i = 0; - const specialChar = new Map([ - ["Ž", "Ä"], - ["™", "Ö"], - ["š", "Ü"], - ["„", "ä"], - ["”", "ö"], - ["", "ü"], - ["á", "ß"] - ]); - - textArr.forEach(element => { - let character; - - if (specialChar.has(element)) - character = specialChar.get(element); - else { - const charCode = element.replace(/^\&\#/, "0"); - character = String.fromCharCode(parseInt(charCode, 16)); - } - - if (character) - applyTrim(x, y, i, character); - - i++; - }); -} - -function applyTrim(x: number, y: number, i: number, character: string) { - if (!/[^a-zA-Z0-9äöüÄÖÜß$]/.test(character)) { - const _x = (x - 1) + i; - const _y = y - 1; - console.log(`${character} -> ${_x} ${_y}`); - jQuery(".seatCharts-row")[_y].children[_x].innerHTML = `${character}` - } -} - - -function showSeatTooltip(jBox: any): void { - const seatID: string = jBox.source[0].id; - const seat = state.layoutRows[seatID][5]; - const row = state.layoutRows[seatID][4]; - const sectionID = state.layoutRows[seatID][3]; - const sectionDesc = getSectionDescBySectionID(inVenueXML, sectionID); - const tooltipContent = `${sectionDesc}
Reihe ${row} Platz ${seat}`; - - jBox.setContent(tooltipContent); -} - -function getSectionDescBySectionID(inVenueXML: I.VenueXML, sectionID: string): string | undefined { - const sectionArr = inVenueXML.master_config[0].section_config[0].section; - - const sectionDesc = sectionArr.find(arr => { - return sectionID === arr.id[0]; - })?.desc[0]; - - return sectionDesc; -} - -function setCheckoutBtn(inUrl: string | undefined) { - if (!inUrl) - return; - - const btnCheckout = jQuery("#modalCart-overlay #checkout .fl-button").get(0); - if (btnCheckout) { - btnCheckout.addEventListener("click", function () { - const message: I.Message = { - message: { - url: inUrl, - }, - from: "child", - event: "child_click_checkout", - date: Date.now() - }; - Communication.sendMessage(message, "parent"); - }); - } -} - - - -function getVenuePricescalePropertyByPricescaleID(property: I.Pricescale2Properties, pricescaleID: string, inVenueXML: I.VenueXML) { - const venuePricescaleArr: I.Pricescale2[] = inVenueXML.venue[0].pricescales[0].pricescale; - - return venuePricescaleArr.find(obj => { - if (obj.id[0] === pricescaleID) - return obj; - - return undefined; - })?.[property][0]; -} - -function addCartItem(inSeatObj: I.JSCSelectedSeat) { - const color = `#${getVenuePricescalePropertyByPricescaleID("color", inSeatObj.data.seatsObj.id[0], inVenueXML)}`; - const category = getVenuePricescalePropertyByPricescaleID("desc", inSeatObj.data.seatsObj.id[0], inVenueXML); - const seat = state.layoutRows[inSeatObj.id][5]; - const row = state.layoutRows[inSeatObj.id][4]; - const sectionID = state.layoutRows[inSeatObj.id][3]; - const sectionDesc = getSectionDescBySectionID(inVenueXML, sectionID); - const seatStr = `${sectionDesc}
Reihe ${row} Platz ${seat}`; - const buyerTypes: (string | undefined)[][] | undefined = getBuyerTypesByPricescaleID(inSeatObj.data.seatsObj.id[0]); - const cartId = `cartItem-${inSeatObj.id}`; - const dropdownBuyerTypesSelector = `#${cartId} .dropdownBuyerTypes`; - - jQuery("#cartItemHTML .fl-html").append(` -
-
-
${category}
-
${seatStr}
- -
`); - - fillDropdownBuyerTypes(buyerTypes, dropdownBuyerTypesSelector); - - // todo: shorter version? - jQuery(dropdownBuyerTypesSelector).on('change', function (this: HTMLSelectElement) { - changedDropdownBuyerType(this, inSeatObj); - }); -} - -function changedDropdownBuyerType(inSelect: HTMLSelectElement, inSeatObj: I.JSCSelectedSeat) { - const index = state.selectedSeatsArr.findIndex(arr => { - return arr[0] === inSeatObj.id; - }); - - - - state.selectedSeatsArr[index][1] = inSelect.value; - - const buyerTypeCode = getBuyerTypeCodeByBuyerTypeID(inVenueXML, inSelect.value); - - if (buyerTypeCode) - state.selectedSeatsArr[index][2] = buyerTypeCode; - - calcOverallPrice(inVenueXML); - setBtnCartText(); - - const url = generateCheckoutUrl(inputsWithValue); - console.log(url); - setCheckoutBtn(url); - - - console.log(state); -} - -// todo: generalize dropdown fill options -function fillDropdownBuyerTypes(inBuyerTypes: (string | undefined)[][] | undefined, inSelector: string) { - if (!inBuyerTypes) - return; - - const dropdownBuyerTypes = jQuery(inSelector).get(0); - console.log(dropdownBuyerTypes); - console.log(inBuyerTypes); - - inBuyerTypes.forEach(arr => { - if (!arr[0]) - return; - - let opt = document.createElement('option'); - opt.value = arr[0]; - opt.innerHTML = `${arr[2]} €${arr[1]}`; - dropdownBuyerTypes.appendChild(opt); - }); -} - -function getBuyerTypesByPricescaleID(inPricescaleID: string) { - const venuePricescaleArr = inVenueXML.price_structure[0].pricescale; - const buyerTypesArr = venuePricescaleArr.find(obj => { - return obj.id[0] === inPricescaleID; - })?.buyer_type; - - if (!buyerTypesArr) - return; - - const buyerTypes: (string | undefined)[][] = buyerTypesArr.map(arr => { - const buyerTypeDesc = inVenueXML.venue[0].buyer_types[0].buyer_type.find(obj => { - return obj.id[0] === arr.id[0] ? obj.desc[0] : undefined; - })?.desc[0]; - - return [arr.id[0], arr.price[0], buyerTypeDesc]; - }); - - return buyerTypes; -} - -function removeCartItems() { - jQuery("#cartItemHTML .cartItem").each(function () { - this.remove(); - }); -} - -function generateCartItems() { - if (!state.selectedSeatsArr.length) - return; - - for (const key in state.selectedSeatsObj) { - if (Object.prototype.hasOwnProperty.call(state.selectedSeatsObj, key)) { - const element = state.selectedSeatsObj[key]; - addCartItem(element); - console.log(element); - } - } -} - -function selectSeatsInCart() { - state.selectedSeatsArr.forEach(arr => { - const seatID: string = arr[0]; - - if (seatmap.get(seatID)) - seatmap.status(seatID, "selected"); - }); -} - -function generatePricescaleCSS(inVenueXML: I.VenueXML): string { - const venuePricescalesArr: I.Pricescale2[] = inVenueXML.venue[0].pricescales[0].pricescale; - let cssArr: string[] = []; - - venuePricescalesArr.forEach(element => { - const ID: string = element.id[0]; - - // update: color always defined: fallback colors exist in system - let color: string = `#${element.color[0]} !important`; - // if (color === "") { - // console.log("no default color"); - // color = Utils.generateRandomColor(); - // } - - cssArr.push(`._${ID} { background-color: ${color}; }`); - }); - - return (cssArr.join("\r\n")); -} - -function initModalCart() { - jQuery("#modalCart-overlay").hide(); - - const btnClose = jQuery("#modalCart-overlay .uabb-close-icon").get(0); - const btnBack = jQuery("#modalCart-overlay #goBack .fl-button").get(0); - - - // const btnClose = jQuery("#modalCart-overlay .uabb-close-icon").get(0); - - if (btnClose) { - btnClose.addEventListener("click", function () { - Communication.sendEventToParent("child_show_dialog_titlebar"); - }); - } - - if (btnBack) { - btnBack.addEventListener("click", function () { - jQuery("#modalCart-overlay .uabb-close-icon").trigger("click"); - }); - } -} - +// Hide header when height of window is smaller than ... +// Note: Cannot determine width of inner iframe, therefore need to use window.innerHeight window.onresize = function () { const innerHeight = window.innerHeight; if (innerHeight < 576) { @@ -527,242 +56,103 @@ window.onresize = function () { } } - - -function dropdownLegendOnChange(inSelector: string) { - const dropdownLegend = jQuery(inSelector).get(0); - dropdownLegend.addEventListener("change", function (this: HTMLSelectElement) { - const value: string = this.value; - const className: string = `._${value}`; - - changeDropdownLegendBGColor(inSelector, value, className); - - if (value === "all") { - seatmap.find('unavailable').status('available'); - JSC.setUnavailableSeats(seatmapXML, seatmap); - } - else { - seatmap.find('available').status('unavailable'); - JSC.activateSeatsBySectionID(seatmapXML, seatmap, value); - JSC.setUnavailableSeats(seatmapXML, seatmap); - } - - }); -} - -function changeDropdownLegendBGColor(inSelector: string, inValue: string, inClassName: string) { - let bgColor: string = "#fafafa"; - let color: string = "#5c5c5c"; - - if (inValue !== "all") { - color = "white"; - bgColor = jQuery(inClassName).css("background-color"); - } - - jQuery(inSelector).css("color", color); - jQuery(inSelector).css("background-color", bgColor); - jQuery(`${inSelector} option[value="all"]`).css("color", color); -} - -function addSeatToState(inVenueXML: I.VenueXML, inSelectedSeat: I.JSCSelectedSeat) { - const seatID: string = inSelectedSeat.id; - const seatObj: I.StateJSCSelectedSeats = { - [seatID]: inSelectedSeat - } - - state.selectedSeatsObj = { ...state.selectedSeatsObj, ...seatObj }; - - const pricescaleID: string = state.selectedSeatsObj[seatID].data.seatsObj.id[0]; - const pricescaleObj: I.Pricescale5 | undefined = getVenuePriceStructurePropertyByPricescaleID(inVenueXML, pricescaleID); - console.log(pricescaleObj); - - if (!pricescaleObj) { - console.warn(`Cannot find corresponding venueXML pricescaleObj for pricescale with ID ${pricescaleID}`); +function messageHandler(inE: any) { + if (typeof (inE.data) !== 'string') return; - } - // get id and code of first buyer type - const firstBuyerTypeID: string = pricescaleObj.buyer_type[0].id[0]; - // const firstPriceStructureCode: string = inVenueXML.price_structure[0].code[0]; // todo: code of first price_structure always correct? what about multiple schablonen? - const buyerTypeCode: string | undefined = getBuyerTypeCodeByBuyerTypeID(inVenueXML, firstBuyerTypeID); + const data: I.Message = JSON.parse(inE.data); - if (buyerTypeCode) { - state.selectedSeatsArr.push([seatID, firstBuyerTypeID, buyerTypeCode]); - state.cartChanged = true; - } -} + console.log(`child: received from ${data.from}`); + console.log(data); -function getBuyerTypeCodeByBuyerTypeID(inVenueXML: I.VenueXML, inBuyerTypeID: string): string | undefined { - const venueBuyerTypeArr = inVenueXML.venue[0].buyer_types[0].buyer_type; - return venueBuyerTypeArr.find(arr => { - return inBuyerTypeID === arr.id[0]; - })?.code[0]; -} + switch (data.event) { -function getVenuePriceStructurePropertyByPricescaleID(inVenueXML: I.VenueXML, inID: string): I.Pricescale5 | undefined { - const venuePricescaleArr: I.Pricescale5[] = inVenueXML.price_structure[0].pricescale; - return venuePricescaleArr.find(obj => { - return obj.id[0] === inID; - }); -} + case "parent_init_venue": { + UI.controlLoftloader("show"); + Communication.sendEventToParent("child_init_needInputsWithValue"); + break; + } -function removeSeatFromState(inSelectedSeat: I.JSCSelectedSeat) { - const seatID: string = inSelectedSeat.id; - delete state.selectedSeatsObj[seatID]; - const index = state.selectedSeatsArr.findIndex(arr => { - return arr[0] === inSelectedSeat.id; - }); - state.selectedSeatsArr.splice(index, 1); - state.cartChanged = true; + case "parent_init_sendVenueXML": { + inVenueXML = data.message.map_response; - if (!state.selectedSeatsArr.length) - jQuery("#modalCart-overlay").hide(); -} + // Generate pricescale css classes + const css = XMLHelper.generatePricescaleCSS(inVenueXML); + Utils.inject(css, "cssCustom", "body"); -function calcOverallPrice(inVenueXML: I.VenueXML): string | undefined { - if (!state.selectedSeatsArr.length) { - state.priceOverall = "0"; - return "0"; - } + // Fill event info + const eventInfo = XMLHelper.getEventInfo(inVenueXML); + UI.setEventInfo(eventInfo, inputsWithValue); - let overallPrice: number = 0; + // Fill select dropdown + const seatmapListing: I.Seatmap[] = XMLHelper.getSeatmapListing(inVenueXML); + UI.setOptionSelect(seatmapListing, "dropdownSeatmap"); - state.selectedSeatsArr.forEach(arr => { - const seatID: string = arr[0]; - const buyertypeID: string = arr[1]; - const selectedSeat: I.JSCSelectedSeat = state.selectedSeatsObj[seatID]; - const pricescaleID: string = selectedSeat.data.seatsObj.id[0]; - const pricescaleObj: I.Pricescale5 | undefined = getVenuePriceStructurePropertyByPricescaleID(inVenueXML, pricescaleID); + // Display first seatmapXML + const id: string = seatmapListing[0].id[0]; + jQuery("#dropdownSeatmap").val(id); + Communication.needSeatmapXML(id); - if (!pricescaleObj) - return; + console.log(css); + console.log(seatmapListing); - const seatPrice: number | undefined = getPriceByBuyertypeID(buyertypeID, pricescaleObj); + break; + } - if (!seatPrice) - return; + case "parent_init_sendInputsWithValue": { + inputsWithValue = data.message; + UI.changeVenueImage(inputsWithValue); + Communication.sendEventToParent("child_init_needVenueXML"); + break; + } - overallPrice += seatPrice; - }); + case "parent_sendSeatmapXML": { + seatmapXML = data.message.map_response; + const map: string[] = JSC.generateMap(seatmapXML); + const rowsNaming: string[] = JSC.getRowsNaming(seatmapXML); + const seats: I.JSCSeats = JSC.getSeats(seatmapXML); + const legend: I.JSCLegend = JSC.generateLegend(inVenueXML, seatmapXML, "#JSCLegendInner"); - state.priceOverall = overallPrice.toFixed(2); + JSC.addSeatmap("#containerSeatmapInner", map, rowsNaming, seats, legend, seatmap, inVenueXML); + JSC.setUnavailableSeats(seatmapXML, seatmap); + JSC.selectSeatsInCart(seatmap); + UI.convertLegendToDropdown("dropdownLegend"); + Events.dropdownLegendOnChange("#dropdownLegend", seatmap, seatmapXML); + JSC.addTrims(seatmapXML); + XMLHelper.processSMAP(inputsWithValue); + panzoom = UI.addPanzoom("#containerSeatmapInner", ".panzoomZoomIn", ".panzoomZoomOut", "#panzoomResetZoom"); + UI.controlLoftloader("hide"); + UI.createSeatTooltips(inVenueXML); - return state.priceOverall; -} + break; + } -function getPriceByBuyertypeID(inBuyertypeID: string, inPricescaleObj: I.Pricescale5) { - const price = inPricescaleObj?.buyer_type.find(arr => { - return arr.id[0] === inBuyertypeID; - })?.price[0]; + case "parent_sendCheckoutResponse": { + config.state.isValidSeatSelection = data.message.isValidSeatSelection; - if (price) - return parseFloat(price); + console.log(data.message); - return undefined; -} - -function setBtnCartText() { - const numTickets = state.selectedSeatsArr.length; - let text: string = ""; - let textModal: string = ""; - - console.log(numTickets); - - if (state.priceOverall !== "") { - numTickets === 1 ? text = `${numTickets} Ticket für €${state.priceOverall}` : text = `${numTickets} Tickets für €${state.priceOverall}`; - textModal = `Summe (${numTickets} Plätze) €${state.priceOverall}`; - } - else { - text = "0 Tickets für €0.00"; - textModal = `Summe (0 Plätze) €0,00`; - } - - jQuery("#modalCart .uabb-button-text")[0].innerText = text; - jQuery("#modalCartSum .uabb-heading-text")[0].textContent = textModal; - -} - -function maximumSelectedSeatsReached(inSeatObj: I.JSCSelectedSeat): boolean { - if (state.selectedSeatsArr.length >= config.maxSelectedSeats) { - showJBoxNotice(`Sie können maximal ${config.maxSelectedSeats} Plätze auswählen.`); - seatmap.status(inSeatObj.id, "available"); - return true; - } - - return false; -} - -function addSeatmap(inSelector: string, inMap: string[], inRowsNaming: string[], inSeats: I.JSCSeats, inLegend: I.JSCLegend): void { - - // console.log(inSeatmapInitMap); - // console.log(inSeats); - // console.log(inLegend); - - const containerSeatmap: any = (window).jQuery(inSelector); - - seatmap = containerSeatmap.seatCharts({ - naming: { - top: false, - left: false, - rows: inRowsNaming, - }, - map: inMap, - // map: [ - // 'aaaaaa__DDDDD', - // 'aaaaaa__aaaaa', - // 'aaaaaa__aaaaa', - // 'bbbbbb__bbbbb', - // 'bbbbbb__bbbbb', - // 'bbbbbb__bbbbb', - // 'ccccccccccccc' - // ], - seats: inSeats, - // seats: { - // A: { - // price: 99.99, - // classes: 'front-seat' //your custom CSS class - // } - - // }, - legend: inLegend, - click: function () { - if (this.status() == 'available') { - const selectedSeat: I.JSCSelectedSeat = this.settings; - console.log("seat selected"); - console.log(selectedSeat); - - if (maximumSelectedSeatsReached(selectedSeat)) - return "available"; - - addSeatToState(inVenueXML, selectedSeat); - - calcOverallPrice(inVenueXML); - setBtnCartText(); - console.log(state.selectedSeatsArr); - - return "selected"; - } - else if (this.status() === "selected") { - const selectedSeat: I.JSCSelectedSeat = this.settings; - console.log("seat unselected"); - - removeSeatFromState(selectedSeat); - calcOverallPrice(inVenueXML); - setBtnCartText(); - console.log(state.selectedSeatsArr); - - return "available"; - } - else if (this.status() == 'unavailable') { - console.log("unavailable"); - - return "unavailable"; + if (!config.state.isValidSeatSelection) { + UI.showJBoxNotice(`Auswahl nicht möglich: Bitte lassen Sie keinen einzelnen Platz frei.`); + UI.showHideBtnCartLoading("hide"); } else { - return this.style(); - } - } - }); + Cart.removeCartItems(); + Cart.generateCartItems(inVenueXML, inputsWithValue); - console.log(seatmap); + console.log(inputsWithValue); + const url = XMLHelper.generateCheckoutUrl(inputsWithValue); + Events.addRedirectCheckout(url); + + UI.showModalCart(); + UI.showHideBtnCartLoading("hide"); + } + + config.state.cartChanged = false; + break; + } + + default: + break; + } } \ No newline at end of file diff --git a/client/src/types/types.d.ts b/client/src/types/types.d.ts index 4dea3c3..423cbe1 100644 --- a/client/src/types/types.d.ts +++ b/client/src/types/types.d.ts @@ -90,9 +90,10 @@ export interface Config { childHasVenueXML: boolean; urlCSSjQueryUI: string; maxSelectedSeats: number; - state: I.State; + state: State; } + export interface Message { message: any | VenueXML, event: string,