From 99c765bde044ba05a56fe322c7b11b370a4091f1 Mon Sep 17 00:00:00 2001 From: zino Date: Tue, 16 Mar 2021 00:33:40 +0100 Subject: [PATCH] seats --- client/package-lock.json | 11 ++ client/package.json | 1 + client/src/inject.ts | 15 +- client/src/seatmap.ts | 289 ++++++++++++++++++++++++++++++++++++--- client/src/types.ts | 56 +++++++- client/src/utils.ts | 60 ++++++-- 6 files changed, 395 insertions(+), 37 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 6b44625..bdfee9f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,6 +8,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@panzoom/panzoom": "^4.3.2", "axios": "^0.21.1", "xml2js": "^0.4.23" }, @@ -23,6 +24,11 @@ "uglify-js": "^3.13.0" } }, + "node_modules/@panzoom/panzoom": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@panzoom/panzoom/-/panzoom-4.3.2.tgz", + "integrity": "sha512-6D4UDsYXowzMJ/1XSbylRj9BGhCR7mQQ5m/s6MiKx11ThLcEiU4kgq59vhS8+RnOGA789FcdmGvK1/hIxyRD+w==" + }, "node_modules/@types/axios": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", @@ -2065,6 +2071,11 @@ } }, "dependencies": { + "@panzoom/panzoom": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@panzoom/panzoom/-/panzoom-4.3.2.tgz", + "integrity": "sha512-6D4UDsYXowzMJ/1XSbylRj9BGhCR7mQQ5m/s6MiKx11ThLcEiU4kgq59vhS8+RnOGA789FcdmGvK1/hIxyRD+w==" + }, "@types/axios": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", diff --git a/client/package.json b/client/package.json index 3297cbc..28263a9 100644 --- a/client/package.json +++ b/client/package.json @@ -22,6 +22,7 @@ "uglify-js": "^3.13.0" }, "dependencies": { + "@panzoom/panzoom": "^4.3.2", "axios": "^0.21.1", "xml2js": "^0.4.23" } diff --git a/client/src/inject.ts b/client/src/inject.ts index f23847b..3d59c8c 100644 --- a/client/src/inject.ts +++ b/client/src/inject.ts @@ -2,7 +2,7 @@ var $ = require("jquery"); import 'jquery-ui'; import * as I from "./types"; -import Utils from './utils'; +// import Utils from './utils'; import * as communication from "./communication"; // import { getEventInfo } from './xml'; // var parseString = require('xml2js').parseString; @@ -14,13 +14,17 @@ import * as communication from "./communication"; // const util = require('util'); // var xml2jsParser = require('xml2js').parseString; -const config: I.Config = { +export const config: I.Config = { debug: true, branch: "staging", urlSeatmapStaging: "https://staging.tickets.zinomedia.de", urlSeatmapMaster: "https://tickets.zinomedia.de", - cssSeatmapMaster: "https://tickets.zinomedia.de/dist/style.css", - cssSeatmapStaging: "https://staging.tickets.zinomedia.de/dist/style.css", + urlCSSSeatmapMaster: "https://tickets.zinomedia.de/dist/style.css", + urlCSSSeatmapStaging: "https://staging.tickets.zinomedia.de/dist/style.css", + urlSeatChartsStaging: "https://staging.tickets.zinomedia.de/libs/jQuery-Seat-Charts/jquery.seat-charts.min.js", + urlSeatChartsMaster: "https://tickets.zinomedia.de/libs/jQuery-Seat-Charts/jquery.seat-charts.min.js", + urlCSSSeatChartsStaging: "https://staging.tickets.zinomedia.de/libs/jQuery-Seat-Charts/jquery.seat-charts.css", + urlCSSSeatChartsMaster: "https://tickets.zinomedia.de/libs/jQuery-Seat-Charts/jquery.seat-charts.css" } let inputsWithValue: I.InputsWithValue; @@ -41,7 +45,8 @@ window.addEventListener('load', function () { if (inputsWithValue["trxstate"] !== "20" || /posturl:"(.+?)"/.test(content) === false) return; - Utils.inject(config.cssSeatmapStaging, "css", "body"); + // Utils.inject(config.urlCSSSeatChartsStaging, "css", "body"); + // Utils.inject(config.urlCSSSeatmapStaging, "css", "body"); communication.listenToMessages(messagesHandler); getAdditionalInputs(content); console.log(inputsWithValue); diff --git a/client/src/seatmap.ts b/client/src/seatmap.ts index 3a00421..a396f85 100644 --- a/client/src/seatmap.ts +++ b/client/src/seatmap.ts @@ -3,15 +3,22 @@ import * as xml from "./xml"; import * as communication from "./communication"; import * as I from "./types"; import * as ui from "./ui"; +import { config } from "./inject"; +import Utils from './utils'; +import Panzoom from '@panzoom/panzoom'; +// var sc = require("../libs/jQuery-Seat-Charts/jquery.seat-charts.js"); // var parseString = require('xml2js').parseString; // import axios from 'axios'; // import Utils from './utils'; // let checkoutParams: string[]; // let posturl: string; + let inputsWithValue: I.InputsWithValue; +let seatmap: any; window.addEventListener('load', function () { + jQuery("#foobar").on("click", () => { communication.sendMessage({ message: "Hello from child", @@ -21,18 +28,15 @@ window.addEventListener('load', function () { }, "parent"); }); + Utils.inject(config.urlSeatChartsStaging, "js", "head"); + Utils.inject(config.urlCSSSeatChartsStaging, "css", "body"); + Utils.inject(config.urlCSSSeatmapStaging, "css", "body"); communication.listenToMessages(messagesHandler); + // Utils.waitForSeatmap(addSeatmap); - // jQuery("#dropdownSeatmap").on("change", (e: HTMLSelectElement) => { - // const value = (e).value; - // console.log(e); - // // console.log(e); - // }); - - - const dropdownSeatmap: HTMLElement | null = document.getElementById("dropdownSeatmap"); + const dropdownSeatmap: HTMLElement | null = document.getElementById("dropdownSeatmap"); if (dropdownSeatmap) { - dropdownSeatmap.addEventListener("change", function(this: HTMLSelectElement) { + dropdownSeatmap.addEventListener("change", function (this: HTMLSelectElement) { const value: string = this.value; const message: I.Message = { message: value, @@ -44,22 +48,99 @@ window.addEventListener('load', function () { }); } - + + + // const containerSeatmap: HTMLElement | null = document.getElementById("containerSeatmap"); + // if (containerSeatmap) { + + // const panzoom = Panzoom(containerSeatmap, { + // maxScale: 5 + // }); + + // const btnZoomIn: HTMLElement | null = document.getElementById("panmzoomZoomIn"); + // if (btnZoomIn) + // btnZoomIn.addEventListener('click', panzoom.zoomIn) + + // } + + + }); -// // dropdownSeatmap change -// jQuery('#dropdownSeatmap').on('change', function () { -// console.log("hi1"); -// // callback(this); -// }); +function addSeatmap(inSelector: string, inSeatmapInitMap: string[], inSeatmapInitRows: number[], inSeats: I.JSCSeats): void { + + const containerSeatmap: any = (window).jQuery(inSelector); + + seatmap = containerSeatmap.seatCharts({ + naming: { + top: false, + left: true, + rows: inSeatmapInitRows, + }, + map: inSeatmapInitMap, + // 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 + // } + + // }, + click: function () { + if (this.status() == 'available') { + console.log("available"); + console.log(this); + //do some stuff, i.e. add to the cart + return 'selected'; + } + else if (this.status() == 'selected') { + console.log("selected"); + //seat has been vacated + return 'available'; + } + else if (this.status() == 'unavailable') { + console.log("unavailable"); + //seat has been already booked + return 'unavailable'; + } + else { + return this.style(); + } + } + }); + + console.log(seatmap); + + // //Make all available 'c' seats unavailable + // sc.find('c.available').status('unavailable'); + + // /* + // // Get seats with ids 2_6, 1_7 (more on ids later on) + // put them in a jQuery set and change some css + // */ + // sc.get(['2_6', '1_7']).node().css({ + // color: '#ffcfcf' + // }); + + // console.log('Seat 1_2 costs ' + sc.get('1_2').data().price + ' and is currently ' + sc.status('1_2')); + +} - -function messagesHandler(e: any) { - if (typeof (e.data) !== 'string') +function messagesHandler(inE: any) { + if (typeof (inE.data) !== 'string') return; - const data: I.Message = JSON.parse(e.data); + const data: I.Message = JSON.parse(inE.data); console.log(`child: received from ${data.from}`); console.log(data); @@ -108,7 +189,13 @@ function messagesHandler(e: any) { } case "parent_sendSeatmapXML": { const XML: any = data.message.map_response; - console.log(XML); + const seatmapInitMap: string[] = generateMap(XML); + const seatmapInitRows: number[] = getRows(XML); + const seatmapInitSeats: I.JSCSeats = getSeats(XML); + console.log(seatmapInitSeats); + + addSeatmap("#containerSeatmapInner", seatmapInitMap, seatmapInitRows, seatmapInitSeats); + addPanzoom("#containerSeatmapInner", "#panzoomZoomIn", "#panzoomZoomOut", "#panzoomResetZoom"); break; } @@ -118,6 +205,165 @@ function messagesHandler(e: any) { } } +function getSeats(inXML: any): I.JSCSeats { + const pricescaleArr: I.SeatmapPricescale[] = inXML.seatmap[0].pricescale_config[0].pricescale; + let object: any = {}; + + for (let key in pricescaleArr) { + const seatsObj: I.JSCSeats2 = { + "classes": "foobar", + "seatsObj": pricescaleArr[key] + } + const seatsKey: string = String.fromCharCode(97 + parseInt(key)).toLocaleUpperCase(); + object[seatsKey] = seatsObj; + } + + const seatmapInitSeats: I.JSCSeats = object; + + return seatmapInitSeats; +} + +function addPanzoom(inSelector: string, inBtnZoomIn: string | null = null, inBtnZoomOut: string | null = null, inBtnResetZoom: string | null = null) { + const container: HTMLElement = jQuery(inSelector).get(0); + if (container) { + const panzoom = Panzoom(container, { + maxScale: 5, + animate: false, + overflow: "hidden", + }); + + container.parentElement!.addEventListener('wheel', panzoom.zoomWithWheel); + + if (inBtnZoomIn) { + const btnZoomIn: HTMLElement | undefined = jQuery(inBtnZoomIn).get(0); + if (btnZoomIn) + btnZoomIn.addEventListener('click', panzoom.zoomIn); + } + + if (inBtnZoomOut) { + const btnZoomOut: HTMLElement | undefined = jQuery(inBtnZoomOut).get(0); + if (btnZoomOut) + btnZoomOut.addEventListener('click', panzoom.zoomOut); + } + + if (inBtnResetZoom) { + const btnResetZoom: HTMLElement | undefined = jQuery(inBtnResetZoom).get(0); + if (btnResetZoom) + btnResetZoom.addEventListener('click', panzoom.reset); + } + + } +} + +function getRows(inXML: any): number[] { + const layout: I.SeatmapLayout = inXML.seatmap[0].layouts[0].layout[0]; + const height: number = parseInt(layout.height[0]); + + return Array.from({ length: height }, (_, i: number) => i + 1) + + // const rows: I.LayoutRow2[] = XML.seatmap[0].layouts[0].layout[0].rows[0].row; + // console.log(rows); + // let seatmapInitRows: number[] = []; + + // rows.forEach(element => { + // const row: I.LayoutRow2 = element; + // const Y: number = parseInt(row.y_cell_coord[0]); + // seatmapInitRows.push(Y); + // }); + + // return seatmapInitRows; +} + +function generateMap(inXML: any): string[] { + const layout: I.SeatmapLayout = inXML.seatmap[0].layouts[0].layout[0]; + console.log(layout); + const rows: I.LayoutRow2[] = layout.rows[0].row; + const pricescaleArr: I.SeatmapPricescale[] = inXML.seatmap[0].pricescale_config[0].pricescale; + + // Form: arrMatrix[Y][X] + let arrMatrix: string[][] = createArrMatrix(parseInt(layout.height[0]), parseInt(layout.width[0]), "_"); + + arrMatrix = enterSeatsInMatrix(rows, arrMatrix, pricescaleArr); + const stringArrMatrix = generateStringArrMatrix(arrMatrix); + + return stringArrMatrix; +} + +function generateStringArrMatrix(inArrMatrix: string[][]): string[] { + const stringArrMatrix: string[] = []; + + inArrMatrix.forEach(element => { + stringArrMatrix.push(element.join("")); + }); + + return stringArrMatrix; +} + + +function enterSeatsInMatrix(inRows: I.LayoutRow2[], inArrMatrix: string[][], inPricescaleArr: I.SeatmapPricescale[]): string[][] { + inRows.forEach(element => { + const row: I.LayoutRow2 = element; + const Y: number = parseInt(row.y_cell_coord[0]); + const seatsArr: string[] = row.seats[0].split("|"); + + seatsArr.forEach(element => { + const seatStr: string = element; + // Form: + // "568420,568420,15,7024,13 ,1" + + const seatArr: string[] = splitSeatStr(seatStr); + // Form: + // 0: "568528" + // 1: "568528" + // 2: "21" + // 3: "7024" + // 4: "13" + // 5: "4" + + const X: number = parseInt(seatArr[5]); + const seatsKey = getSeatsKey(seatArr[0], inPricescaleArr); + + if (seatsKey) + inArrMatrix[Y][X] = generateSeatStr(seatsKey, seatArr); + }); + }); + + return inArrMatrix; +} + +function getSeatsKey(inSeatID: string, inPricescaleArr: I.SeatmapPricescale[]): string | undefined { + for (let key in inPricescaleArr) { + if (inPricescaleArr[key].mask[0].includes(inSeatID)) + return String.fromCharCode(97 + parseInt(key)).toLocaleUpperCase(); + } + + return undefined; +} + +function generateSeatStr(seatLetter: string, seatArr: string[]): string { + return `${seatLetter}[${seatArr[0]}, ]`; +} + +function splitSeatStr(inSeatStr: string): string[] { + const seatArr: string[] = inSeatStr.split(",").map(function (item) { + return item.trim(); + }); + + return seatArr; +} + +function createArrMatrix(inNumrows: number, inNumcols: number, inInitial: string) { + var arr: string[][] = []; + for (let i: number = 0; i < inNumrows; ++i) { + let columns: string[] = []; + for (let j: number = 0; j < inNumcols; ++j) { + columns[j] = inInitial; + } + arr[i] = columns; + } + + return arr; +} // window.addEventListener('message', function(e) { @@ -151,4 +397,5 @@ function messagesHandler(e: any) { // const urlParams: URLSearchParams = new URLSearchParams(window.location.search); // checkoutParams = JSON.parse(urlParams.get('checkoutParams')); // posturl = urlParams.get('posturl'); -// } \ No newline at end of file +// } + diff --git a/client/src/types.ts b/client/src/types.ts index 30c3d4d..43b827b 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -82,8 +82,12 @@ export interface Config { branch: string, urlSeatmapStaging: string, urlSeatmapMaster: string - cssSeatmapStaging: string, - cssSeatmapMaster: string + urlCSSSeatmapStaging: string, + urlCSSSeatmapMaster: string + urlSeatChartsStaging: string, + urlSeatChartsMaster: string, + urlCSSSeatChartsStaging: string, + urlCSSSeatChartsMaster: string, } export interface Message { @@ -303,4 +307,52 @@ export interface SeatmapConfig3 { id: string[]; timestamp: string[]; seatmap: Seatmap[]; +} + +// layout +export interface LayoutRow2 { + seats: string[]; + y_cell_coord: string[]; +} + +export interface LayoutRow { + row: LayoutRow2[]; +} + +export interface SeatmapLayout { + cell_coord: string[]; + code: string[]; + desc: string[]; + height: string[]; + id: string[]; + type: string[]; + width: string[]; + rows: LayoutRow[]; +} + +// pricescale +export interface SeatmapPricescale { + currency: string[]; + display_order: string[]; + id: string[]; + mask: string[]; + ref_price: string[]; +} + +// seats object +export interface SeatsObj { + currency: string[]; + display_order: string[]; + id: string[]; + mask: string[]; + ref_price: string[]; +} + +export interface JSCSeats2 { + classes: string; + seatsObj: SeatsObj; +} + +export interface JSCSeats { + [key: string]: JSCSeats2; } \ No newline at end of file diff --git a/client/src/utils.ts b/client/src/utils.ts index 35cfa11..3eed204 100644 --- a/client/src/utils.ts +++ b/client/src/utils.ts @@ -1,24 +1,66 @@ export default class Utils { - static waitForElement(selector: string, callback: Function, checkFrequencyInMs: number = 100, timeoutInMs: number = 10000) { - let startTimeInMs: number = Date.now(); + + static waitForElement(selector: any, callback: Function, type: string = "selector", checkFrequencyInMs: number = 1000, timeoutInMs: number = 10000) { + let startTimeInMs: number = Date.now(); (function loopSearch(): void { - if (document.querySelector(selector) != null) { - console.log("executing"); + let value: boolean; + console.log(selector); + + if (type === "selector") + value = Utils.querySelector(selector); + else if (type === "function") + value = Utils.isFunction(selector); + else + value = false; + + if (value) { + console.log("defined"); callback(); - return; - } + } else { - console.log("repeating"); setTimeout(function (): void { + console.log("repeating"); if (timeoutInMs && Date.now() - startTimeInMs > timeoutInMs) return; loopSearch(); }, checkFrequencyInMs); - } + } })(); } - static delay(ms: number) { + static waitForSeatmap(callback: Function, checkFrequencyInMs: number = 100, timeoutInMs: number = 10000) { + const seatCharts: any = (window).jQuery("#containerSeatmap").seatCharts; + let startTimeInMs: number = Date.now(); + + if (Utils.isFunction(seatCharts)) { + console.log("defined"); + callback(); + } + else { + setTimeout(function (): void { + console.log("repeating"); + if (timeoutInMs && Date.now() - startTimeInMs > timeoutInMs) + return; + Utils.waitForSeatmap(callback); + }, checkFrequencyInMs); + } + } + + static querySelector(selector: string): boolean { + if (document.querySelector(selector) != null) + return true; + else + return false; + } + + static isFunction(selector: string): boolean { + if (typeof selector === "function") + return true; + else + return false; + } + + static async delay(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); }