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,