tickera-angular-components 0.0.1-dev.190 → 0.0.1-dev.191

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, makeEnvironmentProviders, PLATFORM_ID, Inject, Injectable, signal, LOCALE_ID, computed, inject, EventEmitter, Input, Output, Component, ViewEncapsulation, HostListener, Self, Optional, Injector, forwardRef, effect, untracked, ViewChild } from '@angular/core';
2
+ import { InjectionToken, makeEnvironmentProviders, PLATFORM_ID, Inject, Injectable, signal, LOCALE_ID, computed, inject, EventEmitter, Input, Output, Component, ViewEncapsulation, HostListener, Self, Optional, Injector, forwardRef, effect, untracked, ViewChild, viewChildren } from '@angular/core';
3
3
  import * as i1$3 from '@jsverse/transloco';
4
4
  import { provideTransloco, TranslocoModule, TranslocoService } from '@jsverse/transloco';
5
5
  import { from, throwError, BehaviorSubject, Subject, of, Observable, takeUntil as takeUntil$1 } from 'rxjs';
@@ -21,7 +21,7 @@ import { FormsModule, ReactiveFormsModule, Validators, NgControl, NG_VALUE_ACCES
21
21
  import * as i3 from '@ng-select/ng-select';
22
22
  import { NgSelectModule } from '@ng-select/ng-select';
23
23
  import { DEFAULT_TOOLBAR, Editor, toHTML, NgxEditorComponent, NgxEditorMenuComponent } from 'ngx-editor';
24
- import { StageComponent, CoreShapeComponent } from 'ng2-konva';
24
+ import { CoreShapeComponent, StageComponent } from 'ng2-konva';
25
25
  import QRCode from 'qrcode';
26
26
 
27
27
  var formErrors$1 = {
@@ -1174,6 +1174,11 @@ const TICKET_STATUS_LABELS = {
1174
1174
  };
1175
1175
  const TICKET_MAP_GRID_SIZE = 30;
1176
1176
  const TICKET_MAP_TITLE_HEIGHT = 30;
1177
+ // Hover por piso: al pasar el mouse sobre un elemento de un piso, los demás
1178
+ // pisos visibles se atenúan y el piso activo pasa al frente (ver
1179
+ // PerformanceBookingDataService.floorZOrder y PerformanceTicketMapComponent).
1180
+ const TICKET_MAP_FLOOR_HOVER_OPACITY = 0.25;
1181
+ const TICKET_MAP_FLOOR_HOVER_FADE_MS = 150;
1177
1182
 
1178
1183
  function drawRoundedRect(con, shape, x, y, width, height, cornerRadius) {
1179
1184
  con.beginPath();
@@ -3620,6 +3625,7 @@ class PerformanceBookingDataService {
3620
3625
  _selectedHallFloor = signal(null, ...(ngDevMode ? [{ debugName: "_selectedHallFloor" }] : []));
3621
3626
  _allRenderData = signal([], ...(ngDevMode ? [{ debugName: "_allRenderData" }] : []));
3622
3627
  _visibleFloorIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "_visibleFloorIds" }] : []));
3628
+ _hoveredFloorId = signal(null, ...(ngDevMode ? [{ debugName: "_hoveredFloorId" }] : []));
3623
3629
  _stageConfig = signal(DEFAULT_STAGE_CONFIG, ...(ngDevMode ? [{ debugName: "_stageConfig" }] : []));
3624
3630
  // Snapshot de tickets tal como llegó del último `setPerformanceBookingData`,
3625
3631
  // más los parches aplicados por `applySeatStatusUpdates` (SSE). Se guarda
@@ -3633,17 +3639,44 @@ class PerformanceBookingDataService {
3633
3639
  stageConfig = computed(() => this._stageConfig(), ...(ngDevMode ? [{ debugName: "stageConfig" }] : []));
3634
3640
  roomMap = computed(() => this._roomMap(), ...(ngDevMode ? [{ debugName: "roomMap" }] : []));
3635
3641
  visibleFloorIds = computed(() => this._visibleFloorIds(), ...(ngDevMode ? [{ debugName: "visibleFloorIds" }] : []));
3642
+ hoveredFloorId = computed(() => this._hoveredFloorId(), ...(ngDevMode ? [{ debugName: "hoveredFloorId" }] : []));
3636
3643
  availableFloors = computed(() => {
3637
3644
  const allData = this._allRenderData();
3638
3645
  const floors = this._hallFloors();
3639
3646
  const floorIdsWithElements = new Set(allData.map((el) => el.hallFloorId).filter(Boolean));
3640
3647
  return floors.filter((f) => floorIdsWithElements.has(f.id));
3641
3648
  }, ...(ngDevMode ? [{ debugName: "availableFloors" }] : []));
3649
+ // Orden de los pisos visibles de "atrás hacia adelante": el orden natural
3650
+ // es el mismo que usa el selector de pisos (availableFloors), y el piso
3651
+ // que está en hover siempre se manda al final (= arriba del todo).
3652
+ floorZOrder = computed(() => {
3653
+ const visible = this._visibleFloorIds();
3654
+ const order = this.availableFloors()
3655
+ .map((floor) => floor.id)
3656
+ .filter((id) => visible.has(id));
3657
+ const hovered = this._hoveredFloorId();
3658
+ if (hovered != null && visible.has(hovered)) {
3659
+ const withoutHovered = order.filter((id) => id !== hovered);
3660
+ withoutHovered.push(hovered);
3661
+ return withoutHovered;
3662
+ }
3663
+ return order;
3664
+ }, ...(ngDevMode ? [{ debugName: "floorZOrder" }] : []));
3665
+ // Agrupado por piso según floorZOrder, para que tanto el hit-test
3666
+ // (findElementAtPosition, que asume "último = más arriba") como el
3667
+ // render por capas (una <ko-layer> por piso) usen el mismo z-order.
3642
3668
  renderData = computed(() => {
3643
3669
  const visible = this._visibleFloorIds();
3644
- return this._allRenderData()?.filter(({ hallFloorId }) => {
3645
- return hallFloorId != null && visible.has(hallFloorId);
3646
- });
3670
+ const order = this.floorZOrder();
3671
+ const byFloor = new Map();
3672
+ for (const el of this._allRenderData()) {
3673
+ if (el.hallFloorId == null || !visible.has(el.hallFloorId))
3674
+ continue;
3675
+ const arr = byFloor.get(el.hallFloorId) ?? [];
3676
+ arr.push(el);
3677
+ byFloor.set(el.hallFloorId, arr);
3678
+ }
3679
+ return order.flatMap((floorId) => byFloor.get(floorId) ?? []);
3647
3680
  }, ...(ngDevMode ? [{ debugName: "renderData" }] : []));
3648
3681
  setPerformanceBookingData({ data }) {
3649
3682
  this._performance.set(data.performance);
@@ -3718,6 +3751,11 @@ class PerformanceBookingDataService {
3718
3751
  const hallFloor = this._hallFloors().find((hallFloor) => hallFloor.id === id);
3719
3752
  this._selectedHallFloor.set(hallFloor ?? null);
3720
3753
  }
3754
+ setHoveredFloor(floorId) {
3755
+ if (this._hoveredFloorId() === floorId)
3756
+ return;
3757
+ this._hoveredFloorId.set(floorId);
3758
+ }
3721
3759
  toggleFloorVisibility(floorId) {
3722
3760
  const current = new Set(this._visibleFloorIds());
3723
3761
  if (current.has(floorId)) {
@@ -9808,6 +9846,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
9808
9846
  args: [{ selector: 'ticket-map-floor-selector', standalone: true, imports: [CommonModule], template: "@if (availableFloors().length > 1) {\n <div class=\"ticket-map-floor-selector\">\n @for (floor of availableFloors(); track floor.id) {\n <button\n class=\"floor-button\"\n [class.floor-button-active]=\"isFloorVisible(floor.id)\"\n [class.floor-button-locked]=\"isFloorVisible(floor.id) && !canToggleOff(floor.id)\"\n [disabled]=\"isFloorVisible(floor.id) && !canToggleOff(floor.id)\"\n (click)=\"toggleFloor(floor.id)\"\n [title]=\"floor.name\"\n >\n {{ floor.name }}\n </button>\n }\n </div>\n}\n", styles: [".ticket-map-floor-selector{display:flex;flex-direction:row;align-items:center;gap:.25rem;font-size:.75rem}.ticket-map-floor-selector .floor-button{align-items:center;background-color:#f3f4f6;border:1px solid #e5e7eb;border-radius:.375rem;color:#4b5563;cursor:pointer;display:flex;font-size:.75rem;font-weight:500;height:2rem;justify-content:center;padding-left:.75rem;padding-right:.75rem;transition:all .2s;white-space:nowrap}.ticket-map-floor-selector .floor-button:hover{background-color:#e5e7eb;color:#1f2937}.ticket-map-floor-selector .floor-button.floor-button-active{background-color:#4f46e5;border-color:#4f46e5;color:#fff}.ticket-map-floor-selector .floor-button.floor-button-active:hover{background-color:#4338ca}.ticket-map-floor-selector .floor-button.floor-button-active.floor-button-locked{opacity:.7;cursor:not-allowed}.ticket-map-floor-selector .floor-button.floor-button-active.floor-button-locked:hover{background-color:#4f46e5}\n"] }]
9809
9847
  }], ctorParameters: () => [{ type: PerformanceBookingDataService }] });
9810
9848
 
9849
+ const FLOOR_LAYER_NAME_PREFIX = 'ticket-map-floor-layer-';
9811
9850
  class PerformanceTicketMapComponent {
9812
9851
  platformId;
9813
9852
  bookingDataService;
@@ -9850,6 +9889,29 @@ class PerformanceTicketMapComponent {
9850
9889
  stageReady = signal(false, ...(ngDevMode ? [{ debugName: "stageReady" }] : []));
9851
9890
  autoFitDone = false;
9852
9891
  resizeObserver;
9892
+ // Una <ko-layer #floorLayer> por piso (ver template). No asumimos que su
9893
+ // orden coincida con floorGroups(); cada capa se identifica por su `name`
9894
+ // de Konva (ver FLOOR_LAYER_NAME_PREFIX).
9895
+ floorLayerRefs = viewChildren('floorLayer', ...(ngDevMode ? [{ debugName: "floorLayerRefs", read: CoreShapeComponent }] : [{ read: CoreShapeComponent }]));
9896
+ floorLayerName(floorId) {
9897
+ return `${FLOOR_LAYER_NAME_PREFIX}${floorId}`;
9898
+ }
9899
+ floorGroups = computed(() => {
9900
+ const order = this.bookingDataService.floorZOrder();
9901
+ const elements = this.renderData();
9902
+ const byFloor = new Map();
9903
+ for (const el of elements) {
9904
+ if (el.hallFloorId == null)
9905
+ continue;
9906
+ const arr = byFloor.get(el.hallFloorId) ?? [];
9907
+ arr.push(el);
9908
+ byFloor.set(el.hallFloorId, arr);
9909
+ }
9910
+ return order.map((floorId) => ({
9911
+ floorId,
9912
+ elements: byFloor.get(floorId) ?? [],
9913
+ }));
9914
+ }, ...(ngDevMode ? [{ debugName: "floorGroups" }] : []));
9853
9915
  constructor(platformId, bookingDataService, feedbackModalService, selectionService, zoomService) {
9854
9916
  this.platformId = platformId;
9855
9917
  this.bookingDataService = bookingDataService;
@@ -9864,6 +9926,47 @@ class PerformanceTicketMapComponent {
9864
9926
  this.zoomService.fitToContainer();
9865
9927
  }
9866
9928
  });
9929
+ // Trae al frente y atenúa/resalta cada capa (piso) según el hover.
9930
+ // Todo esto se hace de forma 100% imperativa sobre el nodo Konva real
9931
+ // (moveToTop + .to() para el fade), en vez de reordenar el @for y
9932
+ // esperar a que el MutationObserver de ng2-konva sincronice el zIndex:
9933
+ // ese camino depende de que Angular vuelva a renderizar la plantilla.
9934
+ // Así el cambio es instantáneo pase lo que pase con el ciclo de detección
9935
+ // de cambios.
9936
+ effect(() => {
9937
+ const hoveredFloorId = this.bookingDataService.hoveredFloorId();
9938
+ const order = this.bookingDataService.floorZOrder();
9939
+ const layerRefs = this.floorLayerRefs();
9940
+ const layerNodeByFloorId = new Map();
9941
+ for (const layerComponent of layerRefs) {
9942
+ const layerNode = layerComponent.getStage();
9943
+ const name = layerNode?.name?.() ?? '';
9944
+ if (!name.startsWith(FLOOR_LAYER_NAME_PREFIX))
9945
+ continue;
9946
+ const floorId = Number(name.slice(FLOOR_LAYER_NAME_PREFIX.length));
9947
+ if (Number.isFinite(floorId)) {
9948
+ layerNodeByFloorId.set(floorId, layerNode);
9949
+ }
9950
+ }
9951
+ let needsRedraw = false;
9952
+ for (const floorId of order) {
9953
+ const layerNode = layerNodeByFloorId.get(floorId);
9954
+ if (!layerNode)
9955
+ continue;
9956
+ layerNode.moveToTop();
9957
+ needsRedraw = true;
9958
+ const targetOpacity = hoveredFloorId == null || hoveredFloorId === floorId ? 1 : TICKET_MAP_FLOOR_HOVER_OPACITY;
9959
+ if (layerNode.opacity() !== targetOpacity) {
9960
+ layerNode.to({
9961
+ opacity: targetOpacity,
9962
+ duration: TICKET_MAP_FLOOR_HOVER_FADE_MS / 1000,
9963
+ });
9964
+ }
9965
+ }
9966
+ if (needsRedraw) {
9967
+ this.stageComponent?.getStage()?.batchDraw();
9968
+ }
9969
+ });
9867
9970
  }
9868
9971
  get isBrowser() {
9869
9972
  return isPlatformBrowser(this.platformId);
@@ -9970,6 +10073,7 @@ class PerformanceTicketMapComponent {
9970
10073
  return;
9971
10074
  const internalPos = this.getInternalPointer(stage);
9972
10075
  const hit = findElementAtPosition(this.bookingDataService.renderData(), internalPos.x, internalPos.y);
10076
+ this.bookingDataService.setHoveredFloor(hit?.element.hallFloorId ?? null);
9973
10077
  if (!hit) {
9974
10078
  this.tooltipData.set(null);
9975
10079
  return;
@@ -9996,6 +10100,7 @@ class PerformanceTicketMapComponent {
9996
10100
  }
9997
10101
  handleStageMouseLeave() {
9998
10102
  this.tooltipData.set(null);
10103
+ this.bookingDataService.setHoveredFloor(null);
9999
10104
  }
10000
10105
  handleWheel(konvaEvent) {
10001
10106
  const nativeEvent = konvaEvent.event?.evt;
@@ -10011,11 +10116,11 @@ class PerformanceTicketMapComponent {
10011
10116
  return floor;
10012
10117
  }
10013
10118
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceTicketMapComponent, deps: [{ token: PLATFORM_ID }, { token: PerformanceBookingDataService }, { token: FeedbackModalService }, { token: TicketSelectionService }, { token: TicketMapZoomService }], target: i0.ɵɵFactoryTarget.Component });
10014
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: PerformanceTicketMapComponent, isStandalone: true, selector: "performance-ticket-map", inputs: { readOnly: "readOnly", needsLogin: "needsLogin", isLoggedIn: "isLoggedIn" }, outputs: { selectionChange: "selectionChange", needsLoginError: "needsLoginError" }, viewQueries: [{ propertyName: "stageComponent", first: true, predicate: StageComponent, descendants: true }], ngImport: i0, template: "<div class=\"ticket-map-canvas-container\">\n @if (isBrowser) {\n <ko-stage\n [config]=\"bookingDataService.stageConfig()\"\n (click)=\"handleStageClick($event)\"\n (mousemove)=\"handleStageMouseMove($event)\"\n (mouseleave)=\"handleStageMouseLeave()\"\n (wheel)=\"handleWheel($event)\"\n >\n <ko-layer>\n @for (element of renderData(); track trackByElementId($index, element)) {\n <ko-shape [config]=\"element.shapeConfig\" />\n }\n </ko-layer>\n </ko-stage>\n\n @if (tooltipData(); as tooltip) {\n <div class=\"ticket-tooltip\" [style.left.px]=\"tooltip.x\" [style.top.px]=\"tooltip.y\">\n <div class=\"tooltip-header\">{{ tooltip.elementName }}</div>\n @if (tooltip.seatLabel) {\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Asiento:</span>\n <span class=\"tooltip-value\">{{ tooltip.seatLabel }}</span>\n </div>\n }\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Precio:</span>\n <span class=\"tooltip-value\">${{ tooltip.price | number: '1.0-0' }}</span>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Estado:</span>\n <span class=\"tooltip-status\">\n <span class=\"status-dot\" [style.background]=\"tooltip.statusColor\"></span>\n {{ tooltip.statusLabel }}\n </span>\n </div>\n @if (tooltip.isSelected) {\n <div class=\"tooltip-selected-badge\">Seleccionado</div>\n }\n </div>\n }\n }\n</div>\n", styles: [".ticket-map-canvas-container{min-height:500px;overflow:hidden;position:relative;touch-action:pan-x pan-y;width:100%}.ticket-tooltip{position:absolute;z-index:100;background:#1f2937;color:#f9fafb;border-radius:8px;padding:10px 14px;font-size:12px;line-height:1.5;pointer-events:none;min-width:160px;box-shadow:0 4px 12px #00000040}.tooltip-header{font-weight:600;font-size:13px;margin-bottom:6px;padding-bottom:6px;border-bottom:1px solid #374151}.tooltip-row{display:flex;justify-content:space-between;gap:12px}.tooltip-label{color:#9ca3af}.tooltip-value{color:#f9fafb;font-weight:500}.tooltip-status{display:flex;align-items:center;gap:6px;color:#f9fafb;font-weight:500}.status-dot{display:inline-block;width:8px;height:8px;border-radius:50%}.tooltip-selected-badge{margin-top:6px;padding-top:6px;border-top:1px solid #374151;color:#34d399;font-weight:500;font-size:11px}.zoom-controls{position:absolute;bottom:16px;right:16px;display:flex;align-items:center;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px 8px;box-shadow:0 1px 3px #0000001a}.zoom-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid #d1d5db;background:#f9fafb;border-radius:6px;cursor:pointer;font-size:16px;font-weight:600;color:#374151;line-height:1}.zoom-btn:hover{background:#e5e7eb}.zoom-level{font-size:12px;color:#6b7280;min-width:40px;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: StageComponent, selector: "ko-stage", inputs: ["config"], outputs: ["mouseover", "mousemove", "mouseout", "mouseenter", "mouseleave", "mousedown", "mouseup", "wheel", "contextmenu", "click", "dblclick", "touchstart", "touchmove", "touchend", "tap", "dbltap", "dragstart", "dragmove", "dragend", "transformstart", "transform", "transformend"] }, { kind: "component", type: CoreShapeComponent, selector: "ko-shape, ko-layer, ko-circle, ko-fastlayer, ko-group, ko-label, ko-rect, ko-ellipse, ko-wedge, ko-line, ko-sprite, ko-image, ko-text, ko-text-path, ko-star, ko-ring, ko-arc, ko-tag, ko-path, ko-regular-polygon, ko-arrow, ko-transformer", inputs: ["config"], outputs: ["configChange", "mouseover", "mousemove", "mouseout", "mouseenter", "mouseleave", "mousedown", "mouseup", "wheel", "contextmenu", "click", "dblclick", "touchstart", "touchmove", "touchend", "tap", "dbltap", "dragstart", "dragmove", "dragend", "transformstart", "transform", "transformend"] }, { kind: "pipe", type: i1$1.DecimalPipe, name: "number" }] });
10119
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: PerformanceTicketMapComponent, isStandalone: true, selector: "performance-ticket-map", inputs: { readOnly: "readOnly", needsLogin: "needsLogin", isLoggedIn: "isLoggedIn" }, outputs: { selectionChange: "selectionChange", needsLoginError: "needsLoginError" }, viewQueries: [{ propertyName: "floorLayerRefs", predicate: ["floorLayer"], descendants: true, read: CoreShapeComponent, isSignal: true }, { propertyName: "stageComponent", first: true, predicate: StageComponent, descendants: true }], ngImport: i0, template: "<div class=\"ticket-map-canvas-container\">\n @if (isBrowser) {\n <ko-stage\n [config]=\"bookingDataService.stageConfig()\"\n (click)=\"handleStageClick($event)\"\n (mousemove)=\"handleStageMouseMove($event)\"\n (mouseleave)=\"handleStageMouseLeave()\"\n (wheel)=\"handleWheel($event)\"\n >\n @for (group of floorGroups(); track group.floorId) {\n <ko-layer #floorLayer [config]=\"{ name: floorLayerName(group.floorId) }\">\n @for (element of group.elements; track trackByElementId($index, element)) {\n <ko-shape [config]=\"element.shapeConfig\" />\n }\n </ko-layer>\n }\n </ko-stage>\n\n @if (tooltipData(); as tooltip) {\n <div class=\"ticket-tooltip\" [style.left.px]=\"tooltip.x\" [style.top.px]=\"tooltip.y\">\n <div class=\"tooltip-header\">{{ tooltip.elementName }}</div>\n @if (tooltip.seatLabel) {\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Asiento:</span>\n <span class=\"tooltip-value\">{{ tooltip.seatLabel }}</span>\n </div>\n }\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Precio:</span>\n <span class=\"tooltip-value\">${{ tooltip.price | number: '1.0-0' }}</span>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Estado:</span>\n <span class=\"tooltip-status\">\n <span class=\"status-dot\" [style.background]=\"tooltip.statusColor\"></span>\n {{ tooltip.statusLabel }}\n </span>\n </div>\n @if (tooltip.isSelected) {\n <div class=\"tooltip-selected-badge\">Seleccionado</div>\n }\n </div>\n }\n }\n</div>\n", styles: [".ticket-map-canvas-container{min-height:500px;overflow:hidden;position:relative;touch-action:pan-x pan-y;width:100%}.ticket-tooltip{position:absolute;z-index:100;background:#1f2937;color:#f9fafb;border-radius:8px;padding:10px 14px;font-size:12px;line-height:1.5;pointer-events:none;min-width:160px;box-shadow:0 4px 12px #00000040}.tooltip-header{font-weight:600;font-size:13px;margin-bottom:6px;padding-bottom:6px;border-bottom:1px solid #374151}.tooltip-row{display:flex;justify-content:space-between;gap:12px}.tooltip-label{color:#9ca3af}.tooltip-value{color:#f9fafb;font-weight:500}.tooltip-status{display:flex;align-items:center;gap:6px;color:#f9fafb;font-weight:500}.status-dot{display:inline-block;width:8px;height:8px;border-radius:50%}.tooltip-selected-badge{margin-top:6px;padding-top:6px;border-top:1px solid #374151;color:#34d399;font-weight:500;font-size:11px}.zoom-controls{position:absolute;bottom:16px;right:16px;display:flex;align-items:center;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px 8px;box-shadow:0 1px 3px #0000001a}.zoom-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid #d1d5db;background:#f9fafb;border-radius:6px;cursor:pointer;font-size:16px;font-weight:600;color:#374151;line-height:1}.zoom-btn:hover{background:#e5e7eb}.zoom-level{font-size:12px;color:#6b7280;min-width:40px;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: StageComponent, selector: "ko-stage", inputs: ["config"], outputs: ["mouseover", "mousemove", "mouseout", "mouseenter", "mouseleave", "mousedown", "mouseup", "wheel", "contextmenu", "click", "dblclick", "touchstart", "touchmove", "touchend", "tap", "dbltap", "dragstart", "dragmove", "dragend", "transformstart", "transform", "transformend"] }, { kind: "component", type: CoreShapeComponent, selector: "ko-shape, ko-layer, ko-circle, ko-fastlayer, ko-group, ko-label, ko-rect, ko-ellipse, ko-wedge, ko-line, ko-sprite, ko-image, ko-text, ko-text-path, ko-star, ko-ring, ko-arc, ko-tag, ko-path, ko-regular-polygon, ko-arrow, ko-transformer", inputs: ["config"], outputs: ["configChange", "mouseover", "mousemove", "mouseout", "mouseenter", "mouseleave", "mousedown", "mouseup", "wheel", "contextmenu", "click", "dblclick", "touchstart", "touchmove", "touchend", "tap", "dbltap", "dragstart", "dragmove", "dragend", "transformstart", "transform", "transformend"] }, { kind: "pipe", type: i1$1.DecimalPipe, name: "number" }] });
10015
10120
  }
10016
10121
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: PerformanceTicketMapComponent, decorators: [{
10017
10122
  type: Component,
10018
- args: [{ selector: 'performance-ticket-map', standalone: true, imports: [CommonModule, StageComponent, CoreShapeComponent], template: "<div class=\"ticket-map-canvas-container\">\n @if (isBrowser) {\n <ko-stage\n [config]=\"bookingDataService.stageConfig()\"\n (click)=\"handleStageClick($event)\"\n (mousemove)=\"handleStageMouseMove($event)\"\n (mouseleave)=\"handleStageMouseLeave()\"\n (wheel)=\"handleWheel($event)\"\n >\n <ko-layer>\n @for (element of renderData(); track trackByElementId($index, element)) {\n <ko-shape [config]=\"element.shapeConfig\" />\n }\n </ko-layer>\n </ko-stage>\n\n @if (tooltipData(); as tooltip) {\n <div class=\"ticket-tooltip\" [style.left.px]=\"tooltip.x\" [style.top.px]=\"tooltip.y\">\n <div class=\"tooltip-header\">{{ tooltip.elementName }}</div>\n @if (tooltip.seatLabel) {\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Asiento:</span>\n <span class=\"tooltip-value\">{{ tooltip.seatLabel }}</span>\n </div>\n }\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Precio:</span>\n <span class=\"tooltip-value\">${{ tooltip.price | number: '1.0-0' }}</span>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Estado:</span>\n <span class=\"tooltip-status\">\n <span class=\"status-dot\" [style.background]=\"tooltip.statusColor\"></span>\n {{ tooltip.statusLabel }}\n </span>\n </div>\n @if (tooltip.isSelected) {\n <div class=\"tooltip-selected-badge\">Seleccionado</div>\n }\n </div>\n }\n }\n</div>\n", styles: [".ticket-map-canvas-container{min-height:500px;overflow:hidden;position:relative;touch-action:pan-x pan-y;width:100%}.ticket-tooltip{position:absolute;z-index:100;background:#1f2937;color:#f9fafb;border-radius:8px;padding:10px 14px;font-size:12px;line-height:1.5;pointer-events:none;min-width:160px;box-shadow:0 4px 12px #00000040}.tooltip-header{font-weight:600;font-size:13px;margin-bottom:6px;padding-bottom:6px;border-bottom:1px solid #374151}.tooltip-row{display:flex;justify-content:space-between;gap:12px}.tooltip-label{color:#9ca3af}.tooltip-value{color:#f9fafb;font-weight:500}.tooltip-status{display:flex;align-items:center;gap:6px;color:#f9fafb;font-weight:500}.status-dot{display:inline-block;width:8px;height:8px;border-radius:50%}.tooltip-selected-badge{margin-top:6px;padding-top:6px;border-top:1px solid #374151;color:#34d399;font-weight:500;font-size:11px}.zoom-controls{position:absolute;bottom:16px;right:16px;display:flex;align-items:center;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px 8px;box-shadow:0 1px 3px #0000001a}.zoom-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid #d1d5db;background:#f9fafb;border-radius:6px;cursor:pointer;font-size:16px;font-weight:600;color:#374151;line-height:1}.zoom-btn:hover{background:#e5e7eb}.zoom-level{font-size:12px;color:#6b7280;min-width:40px;text-align:center}\n"] }]
10123
+ args: [{ selector: 'performance-ticket-map', standalone: true, imports: [CommonModule, StageComponent, CoreShapeComponent], template: "<div class=\"ticket-map-canvas-container\">\n @if (isBrowser) {\n <ko-stage\n [config]=\"bookingDataService.stageConfig()\"\n (click)=\"handleStageClick($event)\"\n (mousemove)=\"handleStageMouseMove($event)\"\n (mouseleave)=\"handleStageMouseLeave()\"\n (wheel)=\"handleWheel($event)\"\n >\n @for (group of floorGroups(); track group.floorId) {\n <ko-layer #floorLayer [config]=\"{ name: floorLayerName(group.floorId) }\">\n @for (element of group.elements; track trackByElementId($index, element)) {\n <ko-shape [config]=\"element.shapeConfig\" />\n }\n </ko-layer>\n }\n </ko-stage>\n\n @if (tooltipData(); as tooltip) {\n <div class=\"ticket-tooltip\" [style.left.px]=\"tooltip.x\" [style.top.px]=\"tooltip.y\">\n <div class=\"tooltip-header\">{{ tooltip.elementName }}</div>\n @if (tooltip.seatLabel) {\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Asiento:</span>\n <span class=\"tooltip-value\">{{ tooltip.seatLabel }}</span>\n </div>\n }\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Precio:</span>\n <span class=\"tooltip-value\">${{ tooltip.price | number: '1.0-0' }}</span>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"tooltip-label\">Estado:</span>\n <span class=\"tooltip-status\">\n <span class=\"status-dot\" [style.background]=\"tooltip.statusColor\"></span>\n {{ tooltip.statusLabel }}\n </span>\n </div>\n @if (tooltip.isSelected) {\n <div class=\"tooltip-selected-badge\">Seleccionado</div>\n }\n </div>\n }\n }\n</div>\n", styles: [".ticket-map-canvas-container{min-height:500px;overflow:hidden;position:relative;touch-action:pan-x pan-y;width:100%}.ticket-tooltip{position:absolute;z-index:100;background:#1f2937;color:#f9fafb;border-radius:8px;padding:10px 14px;font-size:12px;line-height:1.5;pointer-events:none;min-width:160px;box-shadow:0 4px 12px #00000040}.tooltip-header{font-weight:600;font-size:13px;margin-bottom:6px;padding-bottom:6px;border-bottom:1px solid #374151}.tooltip-row{display:flex;justify-content:space-between;gap:12px}.tooltip-label{color:#9ca3af}.tooltip-value{color:#f9fafb;font-weight:500}.tooltip-status{display:flex;align-items:center;gap:6px;color:#f9fafb;font-weight:500}.status-dot{display:inline-block;width:8px;height:8px;border-radius:50%}.tooltip-selected-badge{margin-top:6px;padding-top:6px;border-top:1px solid #374151;color:#34d399;font-weight:500;font-size:11px}.zoom-controls{position:absolute;bottom:16px;right:16px;display:flex;align-items:center;gap:8px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px 8px;box-shadow:0 1px 3px #0000001a}.zoom-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid #d1d5db;background:#f9fafb;border-radius:6px;cursor:pointer;font-size:16px;font-weight:600;color:#374151;line-height:1}.zoom-btn:hover{background:#e5e7eb}.zoom-level{font-size:12px;color:#6b7280;min-width:40px;text-align:center}\n"] }]
10019
10124
  }], ctorParameters: () => [{ type: undefined, decorators: [{
10020
10125
  type: Inject,
10021
10126
  args: [PLATFORM_ID]
@@ -10032,7 +10137,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
10032
10137
  }], stageComponent: [{
10033
10138
  type: ViewChild,
10034
10139
  args: [StageComponent]
10035
- }] } });
10140
+ }], floorLayerRefs: [{ type: i0.ViewChildren, args: ['floorLayer', { ...{ read: CoreShapeComponent }, isSignal: true }] }] } });
10036
10141
 
10037
10142
  class TicketMapPriceZonesComponent {
10038
10143
  title = 'Precios por zona';
@@ -11150,5 +11255,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
11150
11255
  * Generated bundle index. Do not edit.
11151
11256
  */
11152
11257
 
11153
- export { ADMIN_API_ROUTES, ADMISSION_API_ROUTES, ALERT_ICONS, AdminSelectComponent, AdminService, AdmissionQueueService, ApiService, AppAlertComponent, AppBadgeComponent, AppBreadcumbComponent, AppButtonComponent, AppLinkButtonComponent, AppModalComponent, AsyncSelectComponent, AuditInformationComponent, BASE_BUTTON_CLASSES, BASE_INPUT_CLASSES, BUTTON_SIZES_CLASSES, BUTTON_VARIANT_CLASSES, BaseModalService, BrowserZoomLockService, BulkSaveBarComponent, CITY_API_ENDPOINTS, COUNTRY_API_ENDPOINTS, CUSTOMERS_API_ROUTES, ChangePasswordFormComponent, ChangePasswordFormService, CitiesService, CitySelectComponent, ColorPickerComponent, ConfirmationOrderModalComponent, ConfirmationOrderModalService, CorporateBondStatus, CountrySelectComponent, CountryService, CouponApplicability, CouponDiscountType, CouponStatus, CreatorType, CustomerSelectComponent, CustomerService, DEFAULT_STAGE_CONFIG, DOCUMENT_TYPES_OPTIONS, DateInputComponent, DateService, DaySelectorGridComponent, DeleteConfirmationComponent, DeleteConfirmationService, DynamicTableComponent, ERROR_INPUT_CLASSES, EndDateGreaterThanStartValidator, FORM_ERROR_MESSAGES, FeedbackModalComponent, FeedbackModalService, FileType, FileUploadComponent, FileUploadPreviewComponent, FormEditorComponent, FormInputComponent, FormSelectComponent, FormTextareaComponent, GiftBondPurchaseStatus, GiftBondStatus, IdentityDocumentInputComponent, KONVA_SHAPE_MAPPINGS, LanguageSwitcherComponent, MembershipStatus, MinTodayValidator, MustMatchValidator, NumberInputComponent, ORDER_DISCOUNT_COLORS, ORDER_ITEM_TYPES_COLORS, ORDER_STATUS_COLORS, OrderBillingInfoComponent, OrderDiscountAppliedComponent, OrderInformationComponent, OrderItemType, OrderItemTypeBadgeComponent, OrderItemsComponent, OrderStatus, OrderStatusBadgeComponent, OrderTransactionDetailsModalComponent, OrderTransactionDetailsModalService, OrderTransactionsComponent, PAYMENT_METHODS_OPTIONS, PERFORMANCES_API_ROUTES, PERFORMANCE_STATUS_COLORS, PERFORMANCE_TICKET_STATUS_COLORS, PHONE_COUNTRIES, PRICE_ZONES_API_ROUTES, PRODUCTS_API_ROUTES, PRODUCT_CATEGORIES_API_ROUTES, PRODUCT_TAGS_API_ROUTES, PRODUCT_TYPES_API_ROUTES, PaymentMethod, PendingChangesService, PerformanceBookingDataService, PerformanceCardComponent, PerformanceCardListComponent, PerformanceMultiSelectComponent, PerformanceSelectComponent, PerformanceService, PerformanceStatus, PerformanceStatusBadgeComponent, PerformanceStepperComponent, PerformanceTicketMapComponent, PerformanceTicketStatus, PerformanceTicketStatusBadgeComponent, PerformancesListEventsService, PhoneInputComponent, PriceZoneEventService, PriceZoneFormModalService, PriceZoneSelectComponent, PriceZoneService, ProductCategoryService, ProductMultiSelectComponent, ProductSelectComponent, ProductService, ProductTagService, ProductTypeService, PurchaseLimitService, QuickStatusEditComponent, RoomMapElementOrientation, RoomMapElementType, SHOWS_API_ROUTES, SHOW_TYPE_COLORS, STATE_API_ENDPOINTS, SeatAvailabilitySseService, SeatSelectionEmptySummaryComponent, SeatSelectionSummaryComponent, SeatSelectionSummaryItemComponent, SelectedDiscountCardType, ShowCardComponent, ShowCardSkeletonComponent, ShowMultiSelectComponent, ShowSelectComponent, ShowService, ShowType, ShowTypeBadgeComponent, ShowsFilterComponent, StateSelectComponent, StatesService, TICKERA_COMPONENTS_CONFIG, TICKET_ELEMENT_TYPES, TICKET_MAP_GRID_SIZE, TICKET_MAP_LAST_TICKETS_LIMIT, TICKET_MAP_TITLE_HEIGHT, TICKET_STATUS_COLORS, TICKET_STATUS_FILLS, TICKET_STATUS_LABELS, TIcketMapProductSelectionComponent, TRANSACTION_STATUS_COLORS, TextExpandableComponent, TickeraTranslocoLoader, TicketMapFloorSelectorComponent, TicketMapPriceZonesComponent, TicketMapProductSelectionItemComponent, TicketMapTotalsComponent, TicketMapWidgetComponent, TicketMapWidgetHeaderComponent, TicketMapWrapperComponent, TicketMapZoomControlsComponent, TicketMapZoomService, TicketQrComponent, TicketQrModalComponent, TicketQrModalService, TicketQrService, TicketSelectionDetailsService, TicketSelectionDiscountService, TicketSelectionService, TicketSelectionTotalsService, ToastService, ToggleSwitchComponent, TransactionStatus, VENUES_API_ROUTES, VIP_CARDS_API_ROUTES, VipBalanceCardComponent, VipCardService, VipCardStatus, VipCardStatusBadgeComponent, VipRechargeModalComponent, VipTransactionType, VipTransactionsTableComponent, ZonePriceItemComponent, ZonePriceListComponent, authInterceptor, drawChairIcon$1 as drawChairIcon, drawHappyFace, drawRoundedRect, drawWheelchairIcon, emailValidator, findElementAtPosition, findTicketAtPosition, formatCitiesResponseToSelect, generateExitScene, generateHallwayScene, generateProductionAreaScene, generateSeatBlockScene, generateSeatBlockTicketScene, generateStageScene, generateStairScene, generateTableScene, generateTableTicketScene, generateUnavailableSpaceScene, generateZoneScene, getBrowserLanguage, getCustomerFullname, getItemTypeIcon, getOrderDiscount, getStoredLanguage, numberToLetter$1 as numberToLetter, parseJsonToFormDataAdvanced, phoneCountryFlag, processElementsToRenderData, provideTickeraComponents, resolveLanguage, setStoredLanguage, ticketCanOpenQr, tintColor, transformImageToFile, transformUrlParams };
11258
+ export { ADMIN_API_ROUTES, ADMISSION_API_ROUTES, ALERT_ICONS, AdminSelectComponent, AdminService, AdmissionQueueService, ApiService, AppAlertComponent, AppBadgeComponent, AppBreadcumbComponent, AppButtonComponent, AppLinkButtonComponent, AppModalComponent, AsyncSelectComponent, AuditInformationComponent, BASE_BUTTON_CLASSES, BASE_INPUT_CLASSES, BUTTON_SIZES_CLASSES, BUTTON_VARIANT_CLASSES, BaseModalService, BrowserZoomLockService, BulkSaveBarComponent, CITY_API_ENDPOINTS, COUNTRY_API_ENDPOINTS, CUSTOMERS_API_ROUTES, ChangePasswordFormComponent, ChangePasswordFormService, CitiesService, CitySelectComponent, ColorPickerComponent, ConfirmationOrderModalComponent, ConfirmationOrderModalService, CorporateBondStatus, CountrySelectComponent, CountryService, CouponApplicability, CouponDiscountType, CouponStatus, CreatorType, CustomerSelectComponent, CustomerService, DEFAULT_STAGE_CONFIG, DOCUMENT_TYPES_OPTIONS, DateInputComponent, DateService, DaySelectorGridComponent, DeleteConfirmationComponent, DeleteConfirmationService, DynamicTableComponent, ERROR_INPUT_CLASSES, EndDateGreaterThanStartValidator, FORM_ERROR_MESSAGES, FeedbackModalComponent, FeedbackModalService, FileType, FileUploadComponent, FileUploadPreviewComponent, FormEditorComponent, FormInputComponent, FormSelectComponent, FormTextareaComponent, GiftBondPurchaseStatus, GiftBondStatus, IdentityDocumentInputComponent, KONVA_SHAPE_MAPPINGS, LanguageSwitcherComponent, MembershipStatus, MinTodayValidator, MustMatchValidator, NumberInputComponent, ORDER_DISCOUNT_COLORS, ORDER_ITEM_TYPES_COLORS, ORDER_STATUS_COLORS, OrderBillingInfoComponent, OrderDiscountAppliedComponent, OrderInformationComponent, OrderItemType, OrderItemTypeBadgeComponent, OrderItemsComponent, OrderStatus, OrderStatusBadgeComponent, OrderTransactionDetailsModalComponent, OrderTransactionDetailsModalService, OrderTransactionsComponent, PAYMENT_METHODS_OPTIONS, PERFORMANCES_API_ROUTES, PERFORMANCE_STATUS_COLORS, PERFORMANCE_TICKET_STATUS_COLORS, PHONE_COUNTRIES, PRICE_ZONES_API_ROUTES, PRODUCTS_API_ROUTES, PRODUCT_CATEGORIES_API_ROUTES, PRODUCT_TAGS_API_ROUTES, PRODUCT_TYPES_API_ROUTES, PaymentMethod, PendingChangesService, PerformanceBookingDataService, PerformanceCardComponent, PerformanceCardListComponent, PerformanceMultiSelectComponent, PerformanceSelectComponent, PerformanceService, PerformanceStatus, PerformanceStatusBadgeComponent, PerformanceStepperComponent, PerformanceTicketMapComponent, PerformanceTicketStatus, PerformanceTicketStatusBadgeComponent, PerformancesListEventsService, PhoneInputComponent, PriceZoneEventService, PriceZoneFormModalService, PriceZoneSelectComponent, PriceZoneService, ProductCategoryService, ProductMultiSelectComponent, ProductSelectComponent, ProductService, ProductTagService, ProductTypeService, PurchaseLimitService, QuickStatusEditComponent, RoomMapElementOrientation, RoomMapElementType, SHOWS_API_ROUTES, SHOW_TYPE_COLORS, STATE_API_ENDPOINTS, SeatAvailabilitySseService, SeatSelectionEmptySummaryComponent, SeatSelectionSummaryComponent, SeatSelectionSummaryItemComponent, SelectedDiscountCardType, ShowCardComponent, ShowCardSkeletonComponent, ShowMultiSelectComponent, ShowSelectComponent, ShowService, ShowType, ShowTypeBadgeComponent, ShowsFilterComponent, StateSelectComponent, StatesService, TICKERA_COMPONENTS_CONFIG, TICKET_ELEMENT_TYPES, TICKET_MAP_FLOOR_HOVER_FADE_MS, TICKET_MAP_FLOOR_HOVER_OPACITY, TICKET_MAP_GRID_SIZE, TICKET_MAP_LAST_TICKETS_LIMIT, TICKET_MAP_TITLE_HEIGHT, TICKET_STATUS_COLORS, TICKET_STATUS_FILLS, TICKET_STATUS_LABELS, TIcketMapProductSelectionComponent, TRANSACTION_STATUS_COLORS, TextExpandableComponent, TickeraTranslocoLoader, TicketMapFloorSelectorComponent, TicketMapPriceZonesComponent, TicketMapProductSelectionItemComponent, TicketMapTotalsComponent, TicketMapWidgetComponent, TicketMapWidgetHeaderComponent, TicketMapWrapperComponent, TicketMapZoomControlsComponent, TicketMapZoomService, TicketQrComponent, TicketQrModalComponent, TicketQrModalService, TicketQrService, TicketSelectionDetailsService, TicketSelectionDiscountService, TicketSelectionService, TicketSelectionTotalsService, ToastService, ToggleSwitchComponent, TransactionStatus, VENUES_API_ROUTES, VIP_CARDS_API_ROUTES, VipBalanceCardComponent, VipCardService, VipCardStatus, VipCardStatusBadgeComponent, VipRechargeModalComponent, VipTransactionType, VipTransactionsTableComponent, ZonePriceItemComponent, ZonePriceListComponent, authInterceptor, drawChairIcon$1 as drawChairIcon, drawHappyFace, drawRoundedRect, drawWheelchairIcon, emailValidator, findElementAtPosition, findTicketAtPosition, formatCitiesResponseToSelect, generateExitScene, generateHallwayScene, generateProductionAreaScene, generateSeatBlockScene, generateSeatBlockTicketScene, generateStageScene, generateStairScene, generateTableScene, generateTableTicketScene, generateUnavailableSpaceScene, generateZoneScene, getBrowserLanguage, getCustomerFullname, getItemTypeIcon, getOrderDiscount, getStoredLanguage, numberToLetter$1 as numberToLetter, parseJsonToFormDataAdvanced, phoneCountryFlag, processElementsToRenderData, provideTickeraComponents, resolveLanguage, setStoredLanguage, ticketCanOpenQr, tintColor, transformImageToFile, transformUrlParams };
11154
11259
  //# sourceMappingURL=tickera-angular-components.mjs.map