@seatlayer/core 0.1.3 → 0.2.0
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.
- package/dist/{de-Y3E6YTGP.js → de-YMAVF5S2.js} +5 -2
- package/dist/de-YMAVF5S2.js.map +1 -0
- package/dist/{es-UM4ZS357.js → es-MLM3IFIY.js} +5 -2
- package/dist/es-MLM3IFIY.js.map +1 -0
- package/dist/{fr-IGRD2M4W.js → fr-N7AAVATM.js} +5 -2
- package/dist/fr-N7AAVATM.js.map +1 -0
- package/dist/index.cjs +255 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -5
- package/dist/index.d.ts +88 -5
- package/dist/index.js +240 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/de-Y3E6YTGP.js.map +0 -1
- package/dist/es-UM4ZS357.js.map +0 -1
- package/dist/fr-IGRD2M4W.js.map +0 -1
|
@@ -11,7 +11,10 @@ var de = {
|
|
|
11
11
|
"picker.seatsHeld": "Pl\xE4tze reserviert \u2014 {time}",
|
|
12
12
|
"picker.holdExpired": "Ihre Reservierung ist abgelaufen \u2014 die Pl\xE4tze wurden freigegeben. Bitte erneut ausw\xE4hlen.",
|
|
13
13
|
"picker.seatTaken": "Platz {label} wurde gerade von einem anderen K\xE4ufer gebucht.",
|
|
14
|
-
"picker.poweredBy": "Bereitgestellt von
|
|
14
|
+
"picker.poweredBy": "Bereitgestellt von SeatLayer",
|
|
15
|
+
"picker.testMode": "TESTMODUS",
|
|
16
|
+
"picker.colorblind": "Farbenblind-freundliche Farben",
|
|
17
|
+
"picker.orphanHint": "Dadurch bleibt ein einzelner Platz \xFCbrig \u2014 r\xFCcken Sie ggf. einen Platz weiter.",
|
|
15
18
|
"picker.seats.one": "{count} Platz",
|
|
16
19
|
"picker.seats.other": "{count} Pl\xE4tze",
|
|
17
20
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
@@ -67,4 +70,4 @@ var de = {
|
|
|
67
70
|
export {
|
|
68
71
|
de
|
|
69
72
|
};
|
|
70
|
-
//# sourceMappingURL=de-
|
|
73
|
+
//# sourceMappingURL=de-YMAVF5S2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/i18n/locales/de.ts"],"sourcesContent":["/**\n * German bundle — native-quality translations of the English reference dictionary.\n * Keys are identical to en.ts; values are translated to German (de).\n *\n * Conventions:\n * - flat dot-namespaced keys: \"<surface>.<element>\" (picker.holdSeats)\n * - {name} interpolation, {count} reserved for tCount plural keys\n * - plural keys end in \".one\" / \".other\" (Intl.PluralRules categories)\n */\n\nimport type { Dict } from '../index';\n\nexport const de: Dict = {\n // shared\n 'common.cancel': 'Abbrechen',\n 'common.close': 'Schließen',\n 'common.done': 'Fertig',\n 'common.copied': '✓ Kopiert',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Plätze reservieren & Kasse',\n 'picker.completeBooking': 'Buchung abschließen',\n 'picker.seatsHeld': 'Plätze reserviert — {time}',\n 'picker.holdExpired': 'Ihre Reservierung ist abgelaufen — die Plätze wurden freigegeben. Bitte erneut auswählen.',\n 'picker.seatTaken': 'Platz {label} wurde gerade von einem anderen Käufer gebucht.',\n 'picker.poweredBy': 'Bereitgestellt von SeatLayer',\n 'picker.testMode': 'TESTMODUS',\n 'picker.colorblind': 'Farbenblind-freundliche Farben',\n 'picker.orphanHint': 'Dadurch bleibt ein einzelner Platz übrig — rücken Sie ggf. einen Platz weiter.',\n 'picker.seats.one': '{count} Platz',\n 'picker.seats.other': '{count} Plätze',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Sitzplan. Mit Pfeiltasten zwischen Plätzen navigieren, Eingabe zum Auswählen.',\n 'map.seatsLeft': '{count} FREI',\n 'map.fromPrice': 'AB {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Sprache',\n 'picker.zoomToFit': 'Auf Größe anpassen',\n 'picker.viewMode': 'Ansichtsmodus',\n 'picker.floor': 'Etage',\n 'picker.zoomLevel': 'Zoomstufe',\n 'picker.rungTip.zones': 'Fernste Stufe — Zonen-Blöcke (Etage / Unteres Parterre / Oberes Parterre)',\n 'picker.rungTip.sections': 'Bereichs-Blöcke — Kategoriesortierung + Verfügbarkeitstönung',\n 'picker.rungTip.seats': 'Einzelne Plätze — Blöcke lösen sich zu Punkten auf',\n 'picker.rungLabel.zones': 'ZONEN',\n 'picker.rungLabel.sections': 'BEREICHE',\n 'picker.rungLabel.seats': 'PLÄTZE',\n 'picker.sectionSummaryAria': 'Bereichszusammenfassung {label}',\n 'picker.closeSectionSummary': 'Bereichszusammenfassung schließen',\n 'picker.seatsLeftInSection.one': '{count} Platz verfügbar',\n 'picker.seatsLeftInSection.other': '{count} Plätze verfügbar',\n 'picker.overview': 'Übersicht',\n 'picker.tapSeatHint': 'Tippen Sie auf einen Platz, um die Ansicht zu prüfen',\n 'picker.chartSize': 'Kartengröße',\n 'picker.custom': 'Benutzerdefiniert',\n 'picker.categories': 'Kategorien',\n 'picker.accessibility': 'Barrierefreiheit',\n 'picker.showAnyAccessible': 'Jeden barrierefreien Platz anzeigen',\n 'picker.any': 'Beliebig',\n 'picker.yourSeats': 'Ihre Plätze',\n 'picker.emptySeats': 'Tippen Sie auf die Plätze auf der Karte',\n 'picker.emptySeatsWithGa': 'Tippen Sie auf die Plätze auf der Karte · tippen Sie auf einen Stehbereich für Stehplatztickets',\n 'picker.oneFewer': 'Einen weniger',\n 'picker.oneMore': 'Einen mehr',\n 'picker.remove': '{label} entfernen',\n 'picker.ticketTierFor': 'Ticketklasse für {label}',\n 'picker.total': 'Gesamt: {amount}',\n 'picker.viewFromSeat': 'Ansicht von Platz {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VORSCHAU',\n 'picker.open360': 'Öffnen Sie die 360°-Ansicht',\n 'picker.sightline': '≈ {rows} Reihen von der Bühne · {angle}° seitlich versetzt',\n 'picker.bookedDemo': 'Gebucht! (Demo)',\n 'picker.bookButton.one': '{count} Ticket buchen — {amount}',\n 'picker.bookButton.other': '{count} Tickets buchen — {amount}',\n 'picker.simulateCrowd': 'Menschenmenge simulieren: {state}',\n 'picker.on': 'AN',\n 'picker.off': 'AUS',\n 'picker.panorama360': '360°-Veranstaltungsfotos',\n 'picker.illustrationCaption': 'Illustration · ≈ {m} m von der Bühne',\n};\n"],"mappings":";AAYO,IAAM,KAAW;AAAA;AAAA,EAEtB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA;AAAA,EAGtB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,8BAA8B;AAAA,EAC9B,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,4BAA4B;AAAA,EAC5B,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,8BAA8B;AAChC;","names":[]}
|
|
@@ -11,7 +11,10 @@ var es = {
|
|
|
11
11
|
"picker.seatsHeld": "Asientos retenidos \u2014 {time}",
|
|
12
12
|
"picker.holdExpired": "Tu retenci\xF3n expir\xF3 \u2014 los asientos fueron liberados. Elige de nuevo.",
|
|
13
13
|
"picker.seatTaken": "El asiento {label} fue tomado por otro comprador.",
|
|
14
|
-
"picker.poweredBy": "Con la tecnolog\xEDa de
|
|
14
|
+
"picker.poweredBy": "Con la tecnolog\xEDa de SeatLayer",
|
|
15
|
+
"picker.testMode": "MODO DE PRUEBA",
|
|
16
|
+
"picker.colorblind": "Colores aptos para daltonismo",
|
|
17
|
+
"picker.orphanHint": "Esto deja un asiento aislado \u2014 considera desplazarte un asiento.",
|
|
15
18
|
"picker.seats.one": "{count} asiento",
|
|
16
19
|
"picker.seats.other": "{count} asientos",
|
|
17
20
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
@@ -67,4 +70,4 @@ var es = {
|
|
|
67
70
|
export {
|
|
68
71
|
es
|
|
69
72
|
};
|
|
70
|
-
//# sourceMappingURL=es-
|
|
73
|
+
//# sourceMappingURL=es-MLM3IFIY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/i18n/locales/es.ts"],"sourcesContent":["/**\n * Spanish (es) bundle — neutral/international Spanish translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const es: Dict = {\n // shared\n 'common.cancel': 'Cancelar',\n 'common.close': 'Cerrar',\n 'common.done': 'Listo',\n 'common.copied': '✓ Copiado',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Retener asientos y comprar',\n 'picker.completeBooking': 'Completar reserva',\n 'picker.seatsHeld': 'Asientos retenidos — {time}',\n 'picker.holdExpired': 'Tu retención expiró — los asientos fueron liberados. Elige de nuevo.',\n 'picker.seatTaken': 'El asiento {label} fue tomado por otro comprador.',\n 'picker.poweredBy': 'Con la tecnología de SeatLayer',\n 'picker.testMode': 'MODO DE PRUEBA',\n 'picker.colorblind': 'Colores aptos para daltonismo',\n 'picker.orphanHint': 'Esto deja un asiento aislado — considera desplazarte un asiento.',\n 'picker.seats.one': '{count} asiento',\n 'picker.seats.other': '{count} asientos',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Mapa de asientos. Usa las flechas para moverte entre asientos, Intro para seleccionar.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.fromPrice': 'DESDE {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Idioma',\n 'picker.zoomToFit': 'Ajustar zoom',\n 'picker.viewMode': 'Modo de vista',\n 'picker.floor': 'Piso',\n 'picker.zoomLevel': 'Nivel de zoom',\n 'picker.rungTip.zones': 'Nivel más lejano — bloques de zona (Piso / Patio Bajo / Patio Alto)',\n 'picker.rungTip.sections': 'Bloques de sección — mezcla de categorías + matiz de disponibilidad',\n 'picker.rungTip.seats': 'Asientos individuales — los bloques se convierten en puntos',\n 'picker.rungLabel.zones': 'ZONAS',\n 'picker.rungLabel.sections': 'SECCIONES',\n 'picker.rungLabel.seats': 'ASIENTOS',\n 'picker.sectionSummaryAria': 'Resumen de sección {label}',\n 'picker.closeSectionSummary': 'Cerrar resumen de sección',\n 'picker.seatsLeftInSection.one': '{count} asiento disponible',\n 'picker.seatsLeftInSection.other': '{count} asientos disponibles',\n 'picker.overview': 'Descripción general',\n 'picker.tapSeatHint': 'Toca cualquier asiento para ver su vista',\n 'picker.chartSize': 'Tamaño del gráfico',\n 'picker.custom': 'Personalizado',\n 'picker.categories': 'Categorías',\n 'picker.accessibility': 'Accesibilidad',\n 'picker.showAnyAccessible': 'Mostrar cualquier asiento accesible',\n 'picker.any': 'Cualquiera',\n 'picker.yourSeats': 'Tus asientos',\n 'picker.emptySeats': 'Toca asientos en el mapa',\n 'picker.emptySeatsWithGa': 'Toca asientos en el mapa · toca un área de pie para entradas de entrada general',\n 'picker.oneFewer': 'Uno menos',\n 'picker.oneMore': 'Uno más',\n 'picker.remove': 'Eliminar {label}',\n 'picker.ticketTierFor': 'Categoría de entrada para {label}',\n 'picker.total': 'Total: {amount}',\n 'picker.viewFromSeat': 'Vista desde el asiento {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VISTA PREVIA',\n 'picker.open360': 'Abrir vista de 360°',\n 'picker.sightline': '≈ {rows} filas del escenario · {angle}° fuera del centro',\n 'picker.bookedDemo': '¡Reservado! (demostración)',\n 'picker.bookButton.one': 'Reservar {count} entrada — {amount}',\n 'picker.bookButton.other': 'Reservar {count} entradas — {amount}',\n 'picker.simulateCrowd': 'Simular multitud: {state}',\n 'picker.on': 'ACTIVADO',\n 'picker.off': 'DESACTIVADO',\n 'picker.panorama360': 'Foto de 360° del lugar',\n 'picker.illustrationCaption': 'ilustración · ≈ {m} m del escenario',\n};\n"],"mappings":";AAQO,IAAM,KAAW;AAAA;AAAA,EAEtB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA;AAAA,EAGtB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,8BAA8B;AAAA,EAC9B,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,4BAA4B;AAAA,EAC5B,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,8BAA8B;AAChC;","names":[]}
|
|
@@ -11,7 +11,10 @@ var fr = {
|
|
|
11
11
|
"picker.seatsHeld": "Si\xE8ges r\xE9serv\xE9s \u2014 {time}",
|
|
12
12
|
"picker.holdExpired": "Votre r\xE9servation a expir\xE9 \u2014 les si\xE8ges ont \xE9t\xE9 lib\xE9r\xE9s. S\xE9lectionnez \xE0 nouveau.",
|
|
13
13
|
"picker.seatTaken": "Le si\xE8ge {label} vient d'\xEAtre r\xE9serv\xE9 par un autre acheteur.",
|
|
14
|
-
"picker.poweredBy": "Propuls\xE9 par
|
|
14
|
+
"picker.poweredBy": "Propuls\xE9 par SeatLayer",
|
|
15
|
+
"picker.testMode": "MODE TEST",
|
|
16
|
+
"picker.colorblind": "Couleurs adapt\xE9es au daltonisme",
|
|
17
|
+
"picker.orphanHint": "Cela laisse un si\xE8ge isol\xE9 \u2014 pensez \xE0 vous d\xE9caler d'un si\xE8ge.",
|
|
15
18
|
"picker.seats.one": "{count} si\xE8ge",
|
|
16
19
|
"picker.seats.other": "{count} si\xE8ges",
|
|
17
20
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
@@ -67,4 +70,4 @@ var fr = {
|
|
|
67
70
|
export {
|
|
68
71
|
fr
|
|
69
72
|
};
|
|
70
|
-
//# sourceMappingURL=fr-
|
|
73
|
+
//# sourceMappingURL=fr-N7AAVATM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/i18n/locales/fr.ts"],"sourcesContent":["/**\n * French (fr) bundle — native French translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const fr: Dict = {\n // shared\n 'common.cancel': 'Annuler',\n 'common.close': 'Fermer',\n 'common.done': 'Terminé',\n 'common.copied': '✓ Copié',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Réserver les sièges et valider',\n 'picker.completeBooking': 'Terminer la réservation',\n 'picker.seatsHeld': 'Sièges réservés — {time}',\n 'picker.holdExpired': 'Votre réservation a expiré — les sièges ont été libérés. Sélectionnez à nouveau.',\n 'picker.seatTaken': 'Le siège {label} vient d\\'être réservé par un autre acheteur.',\n 'picker.poweredBy': 'Propulsé par SeatLayer',\n 'picker.testMode': 'MODE TEST',\n 'picker.colorblind': 'Couleurs adaptées au daltonisme',\n 'picker.orphanHint': \"Cela laisse un siège isolé — pensez à vous décaler d'un siège.\",\n 'picker.seats.one': '{count} siège',\n 'picker.seats.other': '{count} sièges',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Plan de salle. Utilisez les flèches pour naviguer entre les sièges, Entrée pour sélectionner.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.fromPrice': 'DÈS {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Langue',\n 'picker.zoomToFit': 'Ajuster le zoom',\n 'picker.viewMode': 'Mode d\\'affichage',\n 'picker.floor': 'Étage',\n 'picker.zoomLevel': 'Niveau de zoom',\n 'picker.rungTip.zones': 'Vue la plus large — blocs de zones (Étage / Parquet inférieur / Parquet supérieur)',\n 'picker.rungTip.sections': 'Blocs de sections — mélange de catégories + teinte de disponibilité',\n 'picker.rungTip.seats': 'Sièges individuels — les blocs se transforment en points',\n 'picker.rungLabel.zones': 'ZONES',\n 'picker.rungLabel.sections': 'SECTIONS',\n 'picker.rungLabel.seats': 'SIÈGES',\n 'picker.sectionSummaryAria': 'Résumé de la section {label}',\n 'picker.closeSectionSummary': 'Fermer le résumé de la section',\n 'picker.seatsLeftInSection.one': '{count} siège restant',\n 'picker.seatsLeftInSection.other': '{count} sièges restants',\n 'picker.overview': 'Vue d\\'ensemble',\n 'picker.tapSeatHint': 'Appuyez sur un siège pour vérifier sa vue',\n 'picker.chartSize': 'Taille du plan',\n 'picker.custom': 'Personnalisé',\n 'picker.categories': 'Catégories',\n 'picker.accessibility': 'Accessibilité',\n 'picker.showAnyAccessible': 'Afficher un siège accessible',\n 'picker.any': 'N\\'importe quel',\n 'picker.yourSeats': 'Vos sièges',\n 'picker.emptySeats': 'Appuyez sur les sièges sur le plan',\n 'picker.emptySeatsWithGa': 'Appuyez sur les sièges sur le plan · appuyez sur une zone debout pour les billets GA',\n 'picker.oneFewer': 'Un de moins',\n 'picker.oneMore': 'Un de plus',\n 'picker.remove': 'Supprimer {label}',\n 'picker.ticketTierFor': 'Catégorie de billet pour {label}',\n 'picker.total': 'Total : {amount}',\n 'picker.viewFromSeat': 'Vue depuis le siège {label}',\n 'picker.real360': 'VRAI 360°',\n 'picker.preview': 'APERÇU',\n 'picker.open360': 'Ouvrir la vue à 360°',\n 'picker.sightline': '≈ {rows} rangées de la scène · {angle}° décalé du centre',\n 'picker.bookedDemo': 'Réservé ! (démo)',\n 'picker.bookButton.one': 'Réserver {count} billet — {amount}',\n 'picker.bookButton.other': 'Réserver {count} billets — {amount}',\n 'picker.simulateCrowd': 'Simuler la foule : {state}',\n 'picker.on': 'ACTIVÉ',\n 'picker.off': 'DÉSACTIVÉ',\n 'picker.panorama360': 'Photo panoramique 360° du lieu',\n 'picker.illustrationCaption': 'illustration · ≈ {m} m de la scène',\n};\n"],"mappings":";AAQO,IAAM,KAAW;AAAA;AAAA,EAEtB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA;AAAA,EAGtB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,8BAA8B;AAAA,EAC9B,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,4BAA4B;AAAA,EAC5B,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,8BAA8B;AAChC;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -41,7 +41,10 @@ var init_es = __esm({
|
|
|
41
41
|
"picker.seatsHeld": "Asientos retenidos \u2014 {time}",
|
|
42
42
|
"picker.holdExpired": "Tu retenci\xF3n expir\xF3 \u2014 los asientos fueron liberados. Elige de nuevo.",
|
|
43
43
|
"picker.seatTaken": "El asiento {label} fue tomado por otro comprador.",
|
|
44
|
-
"picker.poweredBy": "Con la tecnolog\xEDa de
|
|
44
|
+
"picker.poweredBy": "Con la tecnolog\xEDa de SeatLayer",
|
|
45
|
+
"picker.testMode": "MODO DE PRUEBA",
|
|
46
|
+
"picker.colorblind": "Colores aptos para daltonismo",
|
|
47
|
+
"picker.orphanHint": "Esto deja un asiento aislado \u2014 considera desplazarte un asiento.",
|
|
45
48
|
"picker.seats.one": "{count} asiento",
|
|
46
49
|
"picker.seats.other": "{count} asientos",
|
|
47
50
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
@@ -118,7 +121,10 @@ var init_de = __esm({
|
|
|
118
121
|
"picker.seatsHeld": "Pl\xE4tze reserviert \u2014 {time}",
|
|
119
122
|
"picker.holdExpired": "Ihre Reservierung ist abgelaufen \u2014 die Pl\xE4tze wurden freigegeben. Bitte erneut ausw\xE4hlen.",
|
|
120
123
|
"picker.seatTaken": "Platz {label} wurde gerade von einem anderen K\xE4ufer gebucht.",
|
|
121
|
-
"picker.poweredBy": "Bereitgestellt von
|
|
124
|
+
"picker.poweredBy": "Bereitgestellt von SeatLayer",
|
|
125
|
+
"picker.testMode": "TESTMODUS",
|
|
126
|
+
"picker.colorblind": "Farbenblind-freundliche Farben",
|
|
127
|
+
"picker.orphanHint": "Dadurch bleibt ein einzelner Platz \xFCbrig \u2014 r\xFCcken Sie ggf. einen Platz weiter.",
|
|
122
128
|
"picker.seats.one": "{count} Platz",
|
|
123
129
|
"picker.seats.other": "{count} Pl\xE4tze",
|
|
124
130
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
@@ -195,7 +201,10 @@ var init_fr = __esm({
|
|
|
195
201
|
"picker.seatsHeld": "Si\xE8ges r\xE9serv\xE9s \u2014 {time}",
|
|
196
202
|
"picker.holdExpired": "Votre r\xE9servation a expir\xE9 \u2014 les si\xE8ges ont \xE9t\xE9 lib\xE9r\xE9s. S\xE9lectionnez \xE0 nouveau.",
|
|
197
203
|
"picker.seatTaken": "Le si\xE8ge {label} vient d'\xEAtre r\xE9serv\xE9 par un autre acheteur.",
|
|
198
|
-
"picker.poweredBy": "Propuls\xE9 par
|
|
204
|
+
"picker.poweredBy": "Propuls\xE9 par SeatLayer",
|
|
205
|
+
"picker.testMode": "MODE TEST",
|
|
206
|
+
"picker.colorblind": "Couleurs adapt\xE9es au daltonisme",
|
|
207
|
+
"picker.orphanHint": "Cela laisse un si\xE8ge isol\xE9 \u2014 pensez \xE0 vous d\xE9caler d'un si\xE8ge.",
|
|
199
208
|
"picker.seats.one": "{count} si\xE8ge",
|
|
200
209
|
"picker.seats.other": "{count} si\xE8ges",
|
|
201
210
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
@@ -257,6 +266,8 @@ __export(index_exports, {
|
|
|
257
266
|
ACCESSIBILITY_TYPES: () => ACCESSIBILITY_TYPES,
|
|
258
267
|
CHART_STORAGE_KEY: () => CHART_STORAGE_KEY,
|
|
259
268
|
DEFAULT_CURRENCY: () => DEFAULT_CURRENCY,
|
|
269
|
+
MAX_EVENT_INVENTORY: () => MAX_EVENT_INVENTORY,
|
|
270
|
+
MAX_GA_CAPACITY: () => MAX_GA_CAPACITY,
|
|
260
271
|
PickerController: () => PickerController,
|
|
261
272
|
SUPPORTED_LOCALES: () => SUPPORTED_LOCALES,
|
|
262
273
|
SeatmapRenderer: () => SeatmapRenderer,
|
|
@@ -277,8 +288,12 @@ __export(index_exports, {
|
|
|
277
288
|
floorsOf: () => floorsOf,
|
|
278
289
|
formatDate: () => formatDate,
|
|
279
290
|
formatMoney: () => formatMoney,
|
|
291
|
+
gaAreasOf: () => gaAreasOf,
|
|
292
|
+
gaUnitLabel: () => gaUnitLabel,
|
|
293
|
+
gaUnitLabels: () => gaUnitLabels,
|
|
280
294
|
getLocale: () => getLocale,
|
|
281
295
|
hiddenObjectIds: () => hiddenObjectIds,
|
|
296
|
+
isGaUnitLabel: () => isGaUnitLabel,
|
|
282
297
|
isSectionHidden: () => isSectionHidden,
|
|
283
298
|
layerOf: () => layerOf,
|
|
284
299
|
loadLocale: () => loadLocale,
|
|
@@ -660,16 +675,35 @@ function chartBounds(doc) {
|
|
|
660
675
|
};
|
|
661
676
|
}
|
|
662
677
|
|
|
678
|
+
// src/core/ga.ts
|
|
679
|
+
var PREFIX = "__sl_ga__";
|
|
680
|
+
var MAX_GA_CAPACITY = 1e5;
|
|
681
|
+
var MAX_EVENT_INVENTORY = 1e5;
|
|
682
|
+
function gaUnitLabel(areaId, index) {
|
|
683
|
+
return `${PREFIX}${encodeURIComponent(areaId)}__${index + 1}`;
|
|
684
|
+
}
|
|
685
|
+
function gaUnitLabels(area) {
|
|
686
|
+
const capacity = Math.min(MAX_GA_CAPACITY, Math.max(0, Math.floor(area.capacity)));
|
|
687
|
+
return Array.from({ length: capacity }, (_, i) => gaUnitLabel(area.id, i));
|
|
688
|
+
}
|
|
689
|
+
function gaAreasOf(doc) {
|
|
690
|
+
return allObjects(doc).filter((o) => o.type === "gaArea");
|
|
691
|
+
}
|
|
692
|
+
function isGaUnitLabel(label) {
|
|
693
|
+
return label.startsWith(PREFIX);
|
|
694
|
+
}
|
|
695
|
+
|
|
663
696
|
// src/core/sections.ts
|
|
664
697
|
var UNGROUPED_ID = "__ungrouped__";
|
|
665
698
|
function objectSeatLabels(o) {
|
|
666
699
|
if (o.type === "row") return expandRow(o).map((s) => s.label);
|
|
667
700
|
if (o.type === "table") return expandTable(o).map((s) => s.label);
|
|
668
701
|
if (o.type === "booth") return expandBooth(o).map((s) => s.label);
|
|
702
|
+
if (o.type === "gaArea") return gaUnitLabels(o);
|
|
669
703
|
return [];
|
|
670
704
|
}
|
|
671
705
|
function isSeatObject(o) {
|
|
672
|
-
return o.type === "row" || o.type === "table" || o.type === "booth";
|
|
706
|
+
return o.type === "row" || o.type === "table" || o.type === "booth" || o.type === "gaArea";
|
|
673
707
|
}
|
|
674
708
|
function computeSections(doc) {
|
|
675
709
|
const objs = allObjects(doc);
|
|
@@ -796,7 +830,10 @@ var en = {
|
|
|
796
830
|
"picker.seatsHeld": "Seats held \u2014 {time}",
|
|
797
831
|
"picker.holdExpired": "Your hold expired \u2014 the seats were released. Pick again.",
|
|
798
832
|
"picker.seatTaken": "Seat {label} was just taken by another buyer.",
|
|
799
|
-
"picker.poweredBy": "Powered by
|
|
833
|
+
"picker.poweredBy": "Powered by SeatLayer",
|
|
834
|
+
"picker.testMode": "TEST MODE",
|
|
835
|
+
"picker.colorblind": "Colorblind-friendly colors",
|
|
836
|
+
"picker.orphanHint": "This leaves a single seat stranded \u2014 consider shifting one seat over.",
|
|
800
837
|
"picker.seats.one": "{count} seat",
|
|
801
838
|
"picker.seats.other": "{count} seats",
|
|
802
839
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
@@ -913,6 +950,7 @@ var ZONE_SUB_PX = 12;
|
|
|
913
950
|
var HELD_FILL = "#6b7280";
|
|
914
951
|
var TAKEN_FILL = "#374151";
|
|
915
952
|
var NFS_STROKE = "#4b5563";
|
|
953
|
+
var CB_PALETTE = ["#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7"];
|
|
916
954
|
var ACCESS_RING = {
|
|
917
955
|
wheelchair: "#3b82f6",
|
|
918
956
|
companion: "#8b5cf6",
|
|
@@ -1015,6 +1053,10 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1015
1053
|
this.statusById = /* @__PURE__ */ new Map();
|
|
1016
1054
|
this.catColor = /* @__PURE__ */ new Map();
|
|
1017
1055
|
this.theme = {};
|
|
1056
|
+
/** Colorblind-safe mode (Okabe-Ito hues + hollow booked seats). */
|
|
1057
|
+
this.colorblind = false;
|
|
1058
|
+
/** Category order from the doc — the stable index into the CB palette. */
|
|
1059
|
+
this.catOrder = [];
|
|
1018
1060
|
this.selection = /* @__PURE__ */ new Set();
|
|
1019
1061
|
this.selectionRings = /* @__PURE__ */ new Map();
|
|
1020
1062
|
this.focusedId = null;
|
|
@@ -1265,6 +1307,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1265
1307
|
this.hoverRing.radius(this.seatR + 2);
|
|
1266
1308
|
this.catColor.clear();
|
|
1267
1309
|
this.catPrice.clear();
|
|
1310
|
+
this.catOrder = doc.categories.map((c) => c.key);
|
|
1268
1311
|
for (const c of doc.categories) {
|
|
1269
1312
|
this.catColor.set(c.key, c.color);
|
|
1270
1313
|
if (typeof c.price === "number") this.catPrice.set(c.key, c.price);
|
|
@@ -1788,12 +1831,18 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1788
1831
|
this.hasBoothText = true;
|
|
1789
1832
|
target.add(t2);
|
|
1790
1833
|
}
|
|
1834
|
+
/** The category's display color — Okabe-Ito hue when colorblind-safe is on. */
|
|
1835
|
+
seatBaseColor(categoryKey) {
|
|
1836
|
+
if (!this.colorblind) return this.catColor.get(categoryKey) ?? "#6e7bff";
|
|
1837
|
+
const idx = this.catOrder.indexOf(categoryKey);
|
|
1838
|
+
return CB_PALETTE[(idx >= 0 ? idx : 0) % CB_PALETTE.length];
|
|
1839
|
+
}
|
|
1791
1840
|
/** Apply fill/stroke/opacity for a seat's current status + selection. */
|
|
1792
1841
|
paintSeat(c, id) {
|
|
1793
1842
|
const seat = this.seatById.get(id);
|
|
1794
1843
|
const status = this.statusById.get(id) ?? "free";
|
|
1795
1844
|
const selected = this.selection.has(id);
|
|
1796
|
-
const base = this.
|
|
1845
|
+
const base = this.seatBaseColor(seat.categoryKey);
|
|
1797
1846
|
c.dash([]);
|
|
1798
1847
|
c.strokeWidth(0);
|
|
1799
1848
|
c.stroke("");
|
|
@@ -1806,8 +1855,15 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1806
1855
|
c.fill(HELD_FILL);
|
|
1807
1856
|
break;
|
|
1808
1857
|
case "booked":
|
|
1809
|
-
|
|
1810
|
-
|
|
1858
|
+
if (this.colorblind) {
|
|
1859
|
+
c.fill("rgba(0,0,0,0)");
|
|
1860
|
+
c.stroke(TAKEN_FILL);
|
|
1861
|
+
c.strokeWidth(1.5);
|
|
1862
|
+
c.opacity(0.9);
|
|
1863
|
+
} else {
|
|
1864
|
+
c.fill(TAKEN_FILL);
|
|
1865
|
+
c.opacity(0.45);
|
|
1866
|
+
}
|
|
1811
1867
|
break;
|
|
1812
1868
|
case "not_for_sale":
|
|
1813
1869
|
c.fill(TAKEN_FILL);
|
|
@@ -1829,6 +1885,24 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1829
1885
|
}
|
|
1830
1886
|
}
|
|
1831
1887
|
}
|
|
1888
|
+
/**
|
|
1889
|
+
* Colorblind-safe mode: swap category hues for the Okabe-Ito palette and
|
|
1890
|
+
* render booked seats hollow. Off restores the exact default rendering.
|
|
1891
|
+
*/
|
|
1892
|
+
setColorblindSafe(on) {
|
|
1893
|
+
if (on === this.colorblind) return;
|
|
1894
|
+
this.colorblind = on;
|
|
1895
|
+
for (const seat of this.seats) {
|
|
1896
|
+
const c = this.circleById.get(seat.id);
|
|
1897
|
+
if (c) this.paintSeat(c, seat.id);
|
|
1898
|
+
}
|
|
1899
|
+
if (this.cached) {
|
|
1900
|
+
this.seatLayer.clearCache();
|
|
1901
|
+
this.cacheSeatLayer();
|
|
1902
|
+
} else {
|
|
1903
|
+
this.seatLayer.batchDraw();
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1832
1906
|
/**
|
|
1833
1907
|
* Dim the seats of these section/zone ids (organizer manager use) so held-back
|
|
1834
1908
|
* inventory is visually distinct on the canvas without hiding it. `null`/empty
|
|
@@ -2767,6 +2841,38 @@ function createRenderer(container, opts) {
|
|
|
2767
2841
|
return new SeatmapRenderer(container, opts);
|
|
2768
2842
|
}
|
|
2769
2843
|
|
|
2844
|
+
// src/core/orphans.ts
|
|
2845
|
+
function seatIndex(id) {
|
|
2846
|
+
const n = Number(id.slice(id.lastIndexOf(":") + 1));
|
|
2847
|
+
return Number.isFinite(n) ? n : -1;
|
|
2848
|
+
}
|
|
2849
|
+
function strandedSingles(seats, statusOf, selectedIds) {
|
|
2850
|
+
const rows = /* @__PURE__ */ new Map();
|
|
2851
|
+
for (const s of seats) {
|
|
2852
|
+
if (s.kind === "booth") continue;
|
|
2853
|
+
const list = rows.get(s.rowId);
|
|
2854
|
+
if (list) list.push(s);
|
|
2855
|
+
else rows.set(s.rowId, [s]);
|
|
2856
|
+
}
|
|
2857
|
+
const unavailable = (s) => selectedIds.has(s.id) || statusOf(s.id) !== "free";
|
|
2858
|
+
const out = [];
|
|
2859
|
+
for (const list of rows.values()) {
|
|
2860
|
+
if (list.length < 3) continue;
|
|
2861
|
+
list.sort((a, b) => seatIndex(a.id) - seatIndex(b.id));
|
|
2862
|
+
for (let i = 1; i < list.length - 1; i++) {
|
|
2863
|
+
const seat = list[i];
|
|
2864
|
+
if (unavailable(seat)) continue;
|
|
2865
|
+
const left = list[i - 1];
|
|
2866
|
+
const right = list[i + 1];
|
|
2867
|
+
if (seatIndex(seat.id) - seatIndex(left.id) !== 1 || seatIndex(right.id) - seatIndex(seat.id) !== 1) continue;
|
|
2868
|
+
if (!unavailable(left) || !unavailable(right)) continue;
|
|
2869
|
+
if (!selectedIds.has(left.id) && !selectedIds.has(right.id)) continue;
|
|
2870
|
+
out.push(seat);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
return out;
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2770
2876
|
// src/picker/PickerController.ts
|
|
2771
2877
|
var DEFAULT_MAX_SELECTION = 10;
|
|
2772
2878
|
var MAX_BACKOFF_MS = 15e3;
|
|
@@ -2800,7 +2906,11 @@ var PickerController = class {
|
|
|
2800
2906
|
this.closed = false;
|
|
2801
2907
|
// hold state
|
|
2802
2908
|
this.hold_ = null;
|
|
2909
|
+
this.liveStatuses = /* @__PURE__ */ new Map();
|
|
2910
|
+
this.currency = "USD";
|
|
2803
2911
|
this.expiryTimer = null;
|
|
2912
|
+
/** Whether the last emitted hint was non-null (avoids clearing repeatedly). */
|
|
2913
|
+
this.hintShown = false;
|
|
2804
2914
|
this.opts = options;
|
|
2805
2915
|
this.api = options.transport;
|
|
2806
2916
|
this.key = options.eventKey;
|
|
@@ -2857,6 +2967,7 @@ var PickerController = class {
|
|
|
2857
2967
|
this.allIds.push(s.id);
|
|
2858
2968
|
}
|
|
2859
2969
|
const currency = res.event.currency ?? this.opts.currency;
|
|
2970
|
+
this.currency = currency ?? "USD";
|
|
2860
2971
|
const renderer = createRenderer(host, {
|
|
2861
2972
|
maxSelection: this.maxSelection,
|
|
2862
2973
|
confirmSelection: this.opts.confirmSelection,
|
|
@@ -2896,6 +3007,7 @@ var PickerController = class {
|
|
|
2896
3007
|
return null;
|
|
2897
3008
|
}
|
|
2898
3009
|
renderer.setChart(this.visibleDoc());
|
|
3010
|
+
if (this.opts.colorblindSafe) renderer.setColorblindSafe?.(true);
|
|
2899
3011
|
if (seats) this.applySeatsMap(seats);
|
|
2900
3012
|
this.connect();
|
|
2901
3013
|
return {
|
|
@@ -2904,7 +3016,9 @@ var PickerController = class {
|
|
|
2904
3016
|
eventName: res.event.name,
|
|
2905
3017
|
venue: res.event.venue,
|
|
2906
3018
|
startsAt: res.event.startsAt,
|
|
2907
|
-
currency
|
|
3019
|
+
currency,
|
|
3020
|
+
// 'test' ⇒ sandbox event: hosts render a TEST MODE ribbon (Phase 11).
|
|
3021
|
+
mode: res.event.mode ?? "live"
|
|
2908
3022
|
};
|
|
2909
3023
|
}
|
|
2910
3024
|
// ---- selection ------------------------------------------------------------
|
|
@@ -2927,21 +3041,72 @@ var PickerController = class {
|
|
|
2927
3041
|
* re-throws so the caller can choose the banner copy. Returns null only when
|
|
2928
3042
|
* there's nothing to hold.
|
|
2929
3043
|
*/
|
|
2930
|
-
async hold(labelsArg) {
|
|
3044
|
+
async hold(labelsArg, ttlMs) {
|
|
2931
3045
|
const r = this.renderer;
|
|
2932
3046
|
if (!r) return null;
|
|
2933
3047
|
const labels = labelsArg ?? r.getSelection().map((s) => s.label);
|
|
2934
|
-
|
|
2935
|
-
|
|
3048
|
+
const existingGA = (this.hold_?.items ?? []).filter((item) => item.objectType === "ga");
|
|
3049
|
+
const combinedLabels = [.../* @__PURE__ */ new Set([...existingGA.map((item) => item.label), ...labels])];
|
|
3050
|
+
if (!combinedLabels.length) return null;
|
|
3051
|
+
if (this.hold_ && this.holdCovers(combinedLabels)) return this.hold_;
|
|
2936
3052
|
try {
|
|
2937
|
-
const
|
|
2938
|
-
|
|
3053
|
+
const selections = combinedLabels.map((label) => {
|
|
3054
|
+
const ga = existingGA.find((item) => item.label === label);
|
|
3055
|
+
if (ga) return { label, tierId: ga.tierId };
|
|
3056
|
+
const seat = this.labelToSeat.get(label);
|
|
3057
|
+
const resolved = seat ? this.toSeat(seat) : null;
|
|
3058
|
+
return { label, ...resolved?.tierId ? { tierId: resolved.tierId } : {} };
|
|
3059
|
+
});
|
|
3060
|
+
const result = await this.api.hold(this.key, selections, ttlMs, this.hold_?.holdId);
|
|
3061
|
+
this.setHold({ holdId: result.holdId, labels: combinedLabels, expiresAt: result.expiresAt, items: result.items });
|
|
2939
3062
|
return this.hold_;
|
|
2940
3063
|
} catch (err) {
|
|
2941
3064
|
this.handle409Conflicts(err);
|
|
2942
3065
|
throw err;
|
|
2943
3066
|
}
|
|
2944
3067
|
}
|
|
3068
|
+
/** Public GA inventory derived from the live synthetic-unit status stream. */
|
|
3069
|
+
getGAAreas() {
|
|
3070
|
+
const doc = this.visibleDoc();
|
|
3071
|
+
if (!doc) return [];
|
|
3072
|
+
return gaAreasOf(doc).map((area) => {
|
|
3073
|
+
const category = doc.categories.find((candidate) => candidate.key === area.categoryKey);
|
|
3074
|
+
return {
|
|
3075
|
+
id: area.id,
|
|
3076
|
+
label: area.label,
|
|
3077
|
+
capacity: Math.max(0, Math.floor(area.capacity)),
|
|
3078
|
+
available: gaUnitLabels(area).filter((label) => (this.liveStatuses.get(label) ?? "free") === "free").length,
|
|
3079
|
+
categoryKey: area.categoryKey,
|
|
3080
|
+
tiers: category?.tiers,
|
|
3081
|
+
price: category?.tiers?.[0]?.price ?? category?.price ?? 0,
|
|
3082
|
+
currency: this.currency
|
|
3083
|
+
};
|
|
3084
|
+
});
|
|
3085
|
+
}
|
|
3086
|
+
/** Select a quantity from one GA area and hold it atomically. */
|
|
3087
|
+
async holdGA(areaId, qty, options = {}) {
|
|
3088
|
+
const doc = this.visibleDoc();
|
|
3089
|
+
if (!doc || !Number.isFinite(qty) || qty < 1) return null;
|
|
3090
|
+
const area = gaAreasOf(doc).find((candidate) => candidate.id === areaId);
|
|
3091
|
+
if (!area) return null;
|
|
3092
|
+
const labels = gaUnitLabels(area).filter((label) => !this.hold_?.labels.includes(label) && (this.liveStatuses.get(label) ?? "free") === "free").slice(0, Math.floor(qty));
|
|
3093
|
+
if (labels.length !== Math.floor(qty)) return null;
|
|
3094
|
+
const selections = /* @__PURE__ */ new Map();
|
|
3095
|
+
for (const item of this.hold_?.items ?? []) selections.set(item.label, { label: item.label, tierId: item.tierId });
|
|
3096
|
+
if (this.hold_ && !this.hold_?.items?.length) {
|
|
3097
|
+
for (const seat of this.hold_.seats) selections.set(seat.label, { label: seat.label, ...seat.tierId ? { tierId: seat.tierId } : {} });
|
|
3098
|
+
}
|
|
3099
|
+
for (const seat of this.renderer?.getSelection() ?? []) {
|
|
3100
|
+
const resolved = this.labelToSeat.get(seat.label);
|
|
3101
|
+
const chosen = resolved ? this.toSeat(resolved) : null;
|
|
3102
|
+
selections.set(seat.label, { label: seat.label, ...chosen?.tierId ? { tierId: chosen.tierId } : {} });
|
|
3103
|
+
}
|
|
3104
|
+
for (const label of labels) selections.set(label, { label, ...options.tierId ? { tierId: options.tierId } : {} });
|
|
3105
|
+
const combined = [...selections.values()];
|
|
3106
|
+
const result = await this.api.hold(this.key, combined, options.ttlMs, this.hold_?.holdId);
|
|
3107
|
+
this.setHold({ holdId: result.holdId, labels: combined.map((s) => s.label), expiresAt: result.expiresAt, items: result.items });
|
|
3108
|
+
return this.hold_;
|
|
3109
|
+
}
|
|
2945
3110
|
/** Server-picks `qty` best free seats and holds them atomically. Throws on failure. */
|
|
2946
3111
|
async bestAvailable(qty, categoryKey) {
|
|
2947
3112
|
const r = this.renderer;
|
|
@@ -2952,7 +3117,7 @@ var PickerController = class {
|
|
|
2952
3117
|
r.clearSelection();
|
|
2953
3118
|
const ids = result.labels.map((l) => this.labelToId.get(l)).filter((v) => !!v);
|
|
2954
3119
|
if (ids.length) r.setStatus(ids, "held");
|
|
2955
|
-
this.setHold({ holdId: result.holdId, labels: [...result.labels], expiresAt: result.expiresAt });
|
|
3120
|
+
this.setHold({ holdId: result.holdId, labels: [...result.labels], expiresAt: result.expiresAt, items: result.items });
|
|
2956
3121
|
const seats = result.labels.map((l) => this.labelToSeat.get(l)).filter((s) => !!s).map((s) => this.toSeat(s));
|
|
2957
3122
|
this.opts.onSelectionChange?.(seats);
|
|
2958
3123
|
return this.hold_;
|
|
@@ -2981,9 +3146,19 @@ var PickerController = class {
|
|
|
2981
3146
|
if (this.hold_ && this.holdCovers(labels)) {
|
|
2982
3147
|
holdId = this.hold_.holdId;
|
|
2983
3148
|
} else {
|
|
2984
|
-
const
|
|
3149
|
+
const replaceHoldId = this.hold_?.holdId;
|
|
3150
|
+
const h = await this.api.hold(
|
|
3151
|
+
this.key,
|
|
3152
|
+
labels.map((label) => {
|
|
3153
|
+
const seat = this.labelToSeat.get(label);
|
|
3154
|
+
const resolved = seat ? this.toSeat(seat) : null;
|
|
3155
|
+
return { label, ...resolved?.tierId ? { tierId: resolved.tierId } : {} };
|
|
3156
|
+
}),
|
|
3157
|
+
void 0,
|
|
3158
|
+
replaceHoldId
|
|
3159
|
+
);
|
|
2985
3160
|
holdId = h.holdId;
|
|
2986
|
-
this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt });
|
|
3161
|
+
this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt, items: h.items });
|
|
2987
3162
|
}
|
|
2988
3163
|
await this.api.book(this.key, labels, holdId, bookingRef);
|
|
2989
3164
|
} catch (err) {
|
|
@@ -3267,6 +3442,31 @@ var PickerController = class {
|
|
|
3267
3442
|
}
|
|
3268
3443
|
emitSelectionChange() {
|
|
3269
3444
|
this.opts.onSelectionChange?.(this.getSelection());
|
|
3445
|
+
this.emitOrphanHint();
|
|
3446
|
+
}
|
|
3447
|
+
/**
|
|
3448
|
+
* Orphan-seat advice on manual selection: when the buyer's current picks
|
|
3449
|
+
* strand one (or more) single free seats between unavailable same-row
|
|
3450
|
+
* neighbors, surface a localized, non-blocking hint. Cleared (null) as soon
|
|
3451
|
+
* as the selection stops stranding anyone.
|
|
3452
|
+
*/
|
|
3453
|
+
emitOrphanHint() {
|
|
3454
|
+
if (!this.opts.onHint) return;
|
|
3455
|
+
const r = this.renderer;
|
|
3456
|
+
if (!r) return;
|
|
3457
|
+
const selected = new Set(r.getSelection().map((s) => s.id));
|
|
3458
|
+
const stranded = selected.size ? strandedSingles(this.seatById.values(), (id) => r.getStatus(id), selected) : [];
|
|
3459
|
+
if (stranded.length > 0) {
|
|
3460
|
+
this.hintShown = true;
|
|
3461
|
+
this.opts.onHint(t("picker.orphanHint"));
|
|
3462
|
+
} else if (this.hintShown) {
|
|
3463
|
+
this.hintShown = false;
|
|
3464
|
+
this.opts.onHint(null);
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
/** Toggle colorblind-safe rendering at runtime (see PickerOptions.colorblindSafe). */
|
|
3468
|
+
setColorblindSafe(on) {
|
|
3469
|
+
this.renderer?.setColorblindSafe?.(on);
|
|
3270
3470
|
}
|
|
3271
3471
|
emitError(err) {
|
|
3272
3472
|
if (this.opts.onError) this.opts.onError(err);
|
|
@@ -3274,7 +3474,13 @@ var PickerController = class {
|
|
|
3274
3474
|
}
|
|
3275
3475
|
holdCovers(labels) {
|
|
3276
3476
|
const h = this.hold_;
|
|
3277
|
-
|
|
3477
|
+
if (!h || h.labels.length !== labels.length || !labels.every((l) => h.labels.includes(l))) return false;
|
|
3478
|
+
const tiers = new Map((h.items ?? []).map((item) => [item.label, item.tierId]));
|
|
3479
|
+
return labels.every((label) => {
|
|
3480
|
+
const seat = this.labelToSeat.get(label);
|
|
3481
|
+
const currentTier = seat ? this.toSeat(seat).tierId ?? null : null;
|
|
3482
|
+
return !tiers.has(label) || tiers.get(label) === currentTier;
|
|
3483
|
+
});
|
|
3278
3484
|
}
|
|
3279
3485
|
handle409Conflicts(err) {
|
|
3280
3486
|
const { status, conflicts } = errInfo(err);
|
|
@@ -3294,7 +3500,7 @@ var PickerController = class {
|
|
|
3294
3500
|
this.hold_ = full;
|
|
3295
3501
|
if (this.expiryTimer) clearTimeout(this.expiryTimer);
|
|
3296
3502
|
const ms = Math.max(0, full.expiresAt - Date.now());
|
|
3297
|
-
this.expiryTimer = setTimeout(() => this.
|
|
3503
|
+
this.expiryTimer = setTimeout(() => void this.expireActiveHold(), ms);
|
|
3298
3504
|
this.opts.onHold?.(full);
|
|
3299
3505
|
}
|
|
3300
3506
|
clearHold() {
|
|
@@ -3304,18 +3510,31 @@ var PickerController = class {
|
|
|
3304
3510
|
this.expiryTimer = null;
|
|
3305
3511
|
}
|
|
3306
3512
|
}
|
|
3307
|
-
|
|
3513
|
+
async expireActiveHold() {
|
|
3308
3514
|
const hold = this.hold_;
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
const
|
|
3312
|
-
if (
|
|
3515
|
+
if (!hold) return;
|
|
3516
|
+
try {
|
|
3517
|
+
const snap = await this.api.objects(this.key);
|
|
3518
|
+
if (this.hold_?.holdId !== hold.holdId) return;
|
|
3519
|
+
this.applySeatsMap(snap.seats);
|
|
3520
|
+
} catch {
|
|
3521
|
+
if (this.hold_?.holdId === hold.holdId) {
|
|
3522
|
+
this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 2e3);
|
|
3523
|
+
}
|
|
3524
|
+
return;
|
|
3313
3525
|
}
|
|
3526
|
+
if (this.hold_?.holdId !== hold.holdId) return;
|
|
3527
|
+
if (hold.labels.some((label) => this.liveStatuses.get(label) === "held")) {
|
|
3528
|
+
this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 1e3);
|
|
3529
|
+
return;
|
|
3530
|
+
}
|
|
3531
|
+
this.clearHold();
|
|
3314
3532
|
this.opts.onHoldExpired?.();
|
|
3315
3533
|
}
|
|
3316
3534
|
applySeatsMap(seats) {
|
|
3317
3535
|
const r = this.renderer;
|
|
3318
3536
|
if (!r) return;
|
|
3537
|
+
this.liveStatuses = new Map(Object.entries(seats));
|
|
3319
3538
|
if (this.allIds.length) r.setStatus(this.allIds, "free");
|
|
3320
3539
|
const byStatus = { free: [], held: [], booked: [], not_for_sale: [] };
|
|
3321
3540
|
for (const [label, st] of Object.entries(seats)) {
|
|
@@ -3326,6 +3545,10 @@ var PickerController = class {
|
|
|
3326
3545
|
if (byStatus[st].length) r.setStatus(byStatus[st], st);
|
|
3327
3546
|
});
|
|
3328
3547
|
this.opts.onStatusChange?.();
|
|
3548
|
+
this.clearBookedHoldIfSettled();
|
|
3549
|
+
}
|
|
3550
|
+
clearBookedHoldIfSettled() {
|
|
3551
|
+
if (this.hold_?.labels.every((label) => this.liveStatuses.get(label) === "booked")) this.clearHold();
|
|
3329
3552
|
}
|
|
3330
3553
|
async resnapshot() {
|
|
3331
3554
|
try {
|
|
@@ -3368,6 +3591,7 @@ var PickerController = class {
|
|
|
3368
3591
|
this.applySeatsMap(m.seats);
|
|
3369
3592
|
} else if (Array.isArray(m.changes)) {
|
|
3370
3593
|
for (const ch of m.changes) {
|
|
3594
|
+
this.liveStatuses.set(ch.label, ch.status);
|
|
3371
3595
|
const id = this.labelToId.get(ch.label);
|
|
3372
3596
|
if (!id) continue;
|
|
3373
3597
|
const next = mapStatus(ch.status);
|
|
@@ -3376,6 +3600,7 @@ var PickerController = class {
|
|
|
3376
3600
|
}
|
|
3377
3601
|
r.setStatus([id], next);
|
|
3378
3602
|
}
|
|
3603
|
+
this.clearBookedHoldIfSettled();
|
|
3379
3604
|
this.opts.onStatusChange?.();
|
|
3380
3605
|
}
|
|
3381
3606
|
};
|
|
@@ -3429,6 +3654,8 @@ async function loadLocale(code) {
|
|
|
3429
3654
|
ACCESSIBILITY_TYPES,
|
|
3430
3655
|
CHART_STORAGE_KEY,
|
|
3431
3656
|
DEFAULT_CURRENCY,
|
|
3657
|
+
MAX_EVENT_INVENTORY,
|
|
3658
|
+
MAX_GA_CAPACITY,
|
|
3432
3659
|
PickerController,
|
|
3433
3660
|
SUPPORTED_LOCALES,
|
|
3434
3661
|
SeatmapRenderer,
|
|
@@ -3449,8 +3676,12 @@ async function loadLocale(code) {
|
|
|
3449
3676
|
floorsOf,
|
|
3450
3677
|
formatDate,
|
|
3451
3678
|
formatMoney,
|
|
3679
|
+
gaAreasOf,
|
|
3680
|
+
gaUnitLabel,
|
|
3681
|
+
gaUnitLabels,
|
|
3452
3682
|
getLocale,
|
|
3453
3683
|
hiddenObjectIds,
|
|
3684
|
+
isGaUnitLabel,
|
|
3454
3685
|
isSectionHidden,
|
|
3455
3686
|
layerOf,
|
|
3456
3687
|
loadLocale,
|