@session-services/web-elements 0.1.21 → 0.1.23
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/cjs/session-services-ticketing.cjs.entry.js +104 -76
- package/dist/collection/components/session-services-ticketing/session-services-ticketing.css +136 -68
- package/dist/collection/components/session-services-ticketing/session-services-ticketing.js +46 -23
- package/dist/collection/components/session-services-ticketing/session-services-ticketing.logic.js +33 -26
- package/dist/collection/components/session-services-ticketing/session-services-ticketing.logic.test.js +106 -14
- package/dist/collection/components/session-services-ticketing/session-services-ticketing.test.js +46 -2
- package/dist/components/session-services-ticketing.js +104 -76
- package/dist/esm/session-services-ticketing.entry.js +104 -76
- package/dist/session-services-elements/p-ddf8ca4b.entry.js +1 -0
- package/dist/session-services-elements/session-services-elements.esm.js +1 -1
- package/dist/types/components/session-services-ticketing/session-services-ticketing.d.ts +1 -0
- package/dist/types/components/session-services-ticketing/session-services-ticketing.logic.d.ts +4 -1
- package/package.json +4 -4
- package/dist/session-services-elements/p-b8703bf3.entry.js +0 -1
package/dist/collection/components/session-services-ticketing/session-services-ticketing.css
CHANGED
|
@@ -184,7 +184,13 @@
|
|
|
184
184
|
padding: 0;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
button,
|
|
188
|
+
input,
|
|
189
|
+
select,
|
|
190
|
+
textarea {
|
|
191
|
+
font: inherit;
|
|
192
|
+
}
|
|
193
|
+
|
|
188
194
|
*:focus {
|
|
189
195
|
outline: none;
|
|
190
196
|
}
|
|
@@ -245,8 +251,40 @@
|
|
|
245
251
|
margin: 0 0 var(--internal-spacing-md);
|
|
246
252
|
}
|
|
247
253
|
|
|
248
|
-
.
|
|
249
|
-
|
|
254
|
+
.ticket-section.loading-ticket-section {
|
|
255
|
+
overflow: visible;
|
|
256
|
+
background: transparent;
|
|
257
|
+
border: 0;
|
|
258
|
+
box-shadow: none;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.loading-ticket-section .admissions-list {
|
|
262
|
+
display: flex;
|
|
263
|
+
flex-direction: column;
|
|
264
|
+
gap: var(--internal-spacing-sm);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.admission-card.loading-admission {
|
|
268
|
+
min-height: 5.25rem;
|
|
269
|
+
padding: 0;
|
|
270
|
+
background: oklch(from var(--internal-foreground) l c h / 0.07);
|
|
271
|
+
border: 0;
|
|
272
|
+
border-radius: var(--internal-radius);
|
|
273
|
+
box-shadow: none;
|
|
274
|
+
pointer-events: none;
|
|
275
|
+
animation: loading-card 1.6s ease-out infinite;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
@keyframes loading-card {
|
|
279
|
+
0%,
|
|
280
|
+
100% {
|
|
281
|
+
opacity: 0.48;
|
|
282
|
+
}
|
|
283
|
+
50% {
|
|
284
|
+
opacity: 0.74;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
250
288
|
.passcode-form,
|
|
251
289
|
.passcode-form input,
|
|
252
290
|
.ticket-section,
|
|
@@ -280,8 +318,11 @@
|
|
|
280
318
|
transform: translateY(-1px);
|
|
281
319
|
}
|
|
282
320
|
|
|
283
|
-
.
|
|
284
|
-
|
|
321
|
+
.external-ticket-button:focus-visible {
|
|
322
|
+
outline: 2px solid var(--internal-ring);
|
|
323
|
+
outline-offset: 2px;
|
|
324
|
+
}
|
|
325
|
+
|
|
285
326
|
.passcode-form {
|
|
286
327
|
display: flex;
|
|
287
328
|
flex-direction: column;
|
|
@@ -292,14 +333,36 @@
|
|
|
292
333
|
border-radius: var(--internal-radius);
|
|
293
334
|
}
|
|
294
335
|
|
|
295
|
-
.
|
|
296
|
-
|
|
297
|
-
|
|
336
|
+
.passcode-form h2 {
|
|
337
|
+
color: var(--internal-foreground);
|
|
338
|
+
font-size: var(--internal-font-size-base);
|
|
339
|
+
font-weight: var(--internal-font-weight-semibold);
|
|
340
|
+
line-height: 1.3;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.passcode-form p {
|
|
344
|
+
color: var(--internal-muted-foreground);
|
|
345
|
+
font-size: var(--internal-font-size-sm);
|
|
346
|
+
line-height: 1.5;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.door-alert,
|
|
350
|
+
.empty-ticketing-state,
|
|
351
|
+
.message-state {
|
|
352
|
+
display: flex;
|
|
353
|
+
flex-direction: column;
|
|
354
|
+
gap: calc(var(--internal-spacing-xs) * 1.5);
|
|
355
|
+
margin-bottom: var(--internal-spacing-md);
|
|
356
|
+
padding: 0;
|
|
357
|
+
background: transparent;
|
|
358
|
+
border: none;
|
|
359
|
+
border-radius: 0;
|
|
360
|
+
box-shadow: none;
|
|
298
361
|
}
|
|
299
362
|
|
|
300
363
|
.door-alert strong,
|
|
301
364
|
.empty-ticketing-state strong,
|
|
302
|
-
.
|
|
365
|
+
.message-state strong {
|
|
303
366
|
color: var(--internal-foreground);
|
|
304
367
|
font-size: var(--internal-font-size-base);
|
|
305
368
|
font-weight: var(--internal-font-weight-semibold);
|
|
@@ -308,19 +371,45 @@
|
|
|
308
371
|
|
|
309
372
|
.door-alert span,
|
|
310
373
|
.empty-ticketing-state span,
|
|
311
|
-
.
|
|
374
|
+
.message-state span {
|
|
312
375
|
color: var(--internal-muted-foreground);
|
|
313
376
|
font-size: var(--internal-font-size-sm);
|
|
314
|
-
line-height: 1.
|
|
377
|
+
line-height: 1.4;
|
|
315
378
|
}
|
|
316
379
|
|
|
317
380
|
.external-ticket-button {
|
|
381
|
+
flex-direction: column;
|
|
382
|
+
gap: calc(var(--internal-spacing-xs) * 0.5);
|
|
318
383
|
width: 100%;
|
|
319
384
|
padding: calc(var(--internal-spacing-sm) + var(--internal-spacing-xs))
|
|
320
385
|
var(--internal-spacing-lg);
|
|
386
|
+
text-decoration: none;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.external-ticket-panel {
|
|
390
|
+
display: flex;
|
|
391
|
+
flex-direction: column;
|
|
392
|
+
gap: var(--internal-spacing-md);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.external-ticket-warning {
|
|
396
|
+
color: var(--internal-muted-foreground);
|
|
397
|
+
font-size: var(--internal-font-size-sm);
|
|
398
|
+
font-weight: var(--internal-font-weight-medium);
|
|
399
|
+
line-height: 1.35;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.external-ticket-label {
|
|
321
403
|
font-size: var(--internal-font-size-base);
|
|
322
404
|
font-weight: var(--internal-font-weight-bold);
|
|
323
|
-
|
|
405
|
+
line-height: 1.2;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.external-ticket-domain {
|
|
409
|
+
font-size: var(--internal-font-size-xs);
|
|
410
|
+
font-weight: var(--internal-font-weight-medium);
|
|
411
|
+
line-height: 1.2;
|
|
412
|
+
opacity: 0.82;
|
|
324
413
|
}
|
|
325
414
|
|
|
326
415
|
.passcode-form input {
|
|
@@ -563,22 +652,6 @@
|
|
|
563
652
|
flex-shrink: 0;
|
|
564
653
|
}
|
|
565
654
|
|
|
566
|
-
.sold-out-badge {
|
|
567
|
-
display: inline-flex;
|
|
568
|
-
align-items: center;
|
|
569
|
-
justify-content: center;
|
|
570
|
-
padding: 0;
|
|
571
|
-
background: transparent;
|
|
572
|
-
color: var(--internal-muted-foreground);
|
|
573
|
-
border: none;
|
|
574
|
-
font-size: var(--internal-font-size-sm);
|
|
575
|
-
font-weight: var(--internal-font-weight-medium);
|
|
576
|
-
text-transform: uppercase;
|
|
577
|
-
letter-spacing: 0.05em;
|
|
578
|
-
margin-left: auto;
|
|
579
|
-
opacity: 0.7;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
655
|
.admission-price-info {
|
|
583
656
|
display: flex;
|
|
584
657
|
align-items: center;
|
|
@@ -591,6 +664,7 @@
|
|
|
591
664
|
.admission-price-wrapper {
|
|
592
665
|
display: flex;
|
|
593
666
|
flex-direction: column;
|
|
667
|
+
row-gap: calc(var(--internal-spacing-xs) * 0.5);
|
|
594
668
|
}
|
|
595
669
|
|
|
596
670
|
.admission-price {
|
|
@@ -614,12 +688,18 @@
|
|
|
614
688
|
text-decoration: line-through;
|
|
615
689
|
}
|
|
616
690
|
|
|
691
|
+
.admission-booking-fee {
|
|
692
|
+
color: var(--internal-muted-foreground);
|
|
693
|
+
font-size: var(--internal-font-size-xs);
|
|
694
|
+
font-weight: var(--internal-font-weight-medium);
|
|
695
|
+
line-height: 1.2;
|
|
696
|
+
}
|
|
697
|
+
|
|
617
698
|
.admission-savings,
|
|
618
699
|
.admission-availability {
|
|
619
700
|
font-size: var(--internal-font-size-xs);
|
|
620
701
|
font-weight: var(--internal-font-weight-medium);
|
|
621
|
-
line-height: 1.
|
|
622
|
-
margin-top: var(--internal-spacing-xs);
|
|
702
|
+
line-height: 1.2;
|
|
623
703
|
}
|
|
624
704
|
|
|
625
705
|
.admission-savings {
|
|
@@ -654,6 +734,10 @@
|
|
|
654
734
|
transition: all var(--internal-transition-fast);
|
|
655
735
|
}
|
|
656
736
|
|
|
737
|
+
.quantity-controls:has(.quantity-value:focus-visible) {
|
|
738
|
+
box-shadow: 0 0 0 2px var(--internal-ring);
|
|
739
|
+
}
|
|
740
|
+
|
|
657
741
|
.quantity-btn {
|
|
658
742
|
width: calc(var(--internal-spacing-lg) * 1.5);
|
|
659
743
|
height: calc(var(--internal-spacing-lg) * 1.5);
|
|
@@ -715,6 +799,10 @@
|
|
|
715
799
|
padding: 0 var(--internal-spacing-xs);
|
|
716
800
|
}
|
|
717
801
|
|
|
802
|
+
.quantity-value:focus-visible {
|
|
803
|
+
outline: none;
|
|
804
|
+
}
|
|
805
|
+
|
|
718
806
|
.quantity-value::-webkit-inner-spin-button,
|
|
719
807
|
.quantity-value::-webkit-outer-spin-button {
|
|
720
808
|
appearance: none;
|
|
@@ -733,20 +821,26 @@
|
|
|
733
821
|
justify-content: center;
|
|
734
822
|
min-width: calc(var(--internal-spacing-lg) * 1.5 * 2 + 2.5rem);
|
|
735
823
|
height: calc(var(--internal-spacing-lg) * 1.5);
|
|
736
|
-
padding: 0
|
|
737
|
-
background:
|
|
738
|
-
border
|
|
824
|
+
padding: 0;
|
|
825
|
+
background: transparent;
|
|
826
|
+
border: none;
|
|
827
|
+
box-shadow: none;
|
|
739
828
|
}
|
|
740
829
|
|
|
741
830
|
.sold-out-controls,
|
|
742
831
|
.sold-out-text {
|
|
743
|
-
color: var(--internal-
|
|
832
|
+
color: var(--internal-destructive);
|
|
744
833
|
font-size: var(--internal-font-size-xs);
|
|
745
834
|
font-weight: var(--internal-font-weight-medium);
|
|
746
835
|
letter-spacing: 0.025em;
|
|
747
836
|
text-transform: uppercase;
|
|
748
837
|
}
|
|
749
838
|
|
|
839
|
+
.sold-out-controls.success,
|
|
840
|
+
.sold-out-controls.success .sold-out-text {
|
|
841
|
+
color: var(--internal-success);
|
|
842
|
+
}
|
|
843
|
+
|
|
750
844
|
.checkout-actions {
|
|
751
845
|
margin: var(--internal-spacing-lg) 0 0 0;
|
|
752
846
|
width: 100%;
|
|
@@ -816,7 +910,7 @@
|
|
|
816
910
|
background: var(--internal-secondary);
|
|
817
911
|
color: var(--internal-foreground);
|
|
818
912
|
border-radius: calc(var(--internal-radius) - 2px);
|
|
819
|
-
font-size: var(--internal-font-size-
|
|
913
|
+
font-size: var(--internal-font-size-xs);
|
|
820
914
|
font-weight: var(--internal-font-weight-medium);
|
|
821
915
|
cursor: pointer;
|
|
822
916
|
transition: all var(--internal-transition-fast);
|
|
@@ -914,40 +1008,9 @@
|
|
|
914
1008
|
}
|
|
915
1009
|
}
|
|
916
1010
|
|
|
917
|
-
/* Loading & Error States */
|
|
918
|
-
.loading-state {
|
|
919
|
-
display: flex;
|
|
920
|
-
justify-content: center;
|
|
921
|
-
align-items: center;
|
|
922
|
-
padding: var(--internal-spacing-xl);
|
|
923
|
-
text-align: center;
|
|
924
|
-
min-height: 200px;
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
.error-banner {
|
|
928
|
-
background: oklch(
|
|
929
|
-
from var(--internal-destructive) calc(l + 0.4) calc(c * 0.2) h / 0.05
|
|
930
|
-
);
|
|
931
|
-
border: 1px solid oklch(from var(--internal-destructive) l c h / 0.2);
|
|
932
|
-
border-radius: var(--internal-radius);
|
|
933
|
-
padding: var(--internal-spacing-lg);
|
|
934
|
-
margin: var(--internal-spacing-lg);
|
|
935
|
-
text-align: center;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
.error-banner strong {
|
|
939
|
-
display: block;
|
|
940
|
-
color: var(--internal-destructive);
|
|
941
|
-
font-size: var(--internal-font-size-lg);
|
|
942
|
-
margin-bottom: var(--internal-spacing-sm);
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
.error-banner p {
|
|
946
|
-
color: var(--internal-muted-foreground);
|
|
947
|
-
margin-bottom: var(--internal-spacing-md);
|
|
948
|
-
}
|
|
949
|
-
|
|
950
1011
|
.retry-button {
|
|
1012
|
+
align-self: flex-start;
|
|
1013
|
+
margin-top: var(--internal-spacing-xs);
|
|
951
1014
|
background: var(--internal-primary);
|
|
952
1015
|
color: var(--internal-primary-foreground);
|
|
953
1016
|
border: 1px solid oklch(from var(--internal-primary) calc(l - 0.08) c h);
|
|
@@ -1000,6 +1063,11 @@
|
|
|
1000
1063
|
padding-bottom: calc(var(--internal-spacing-xl) * 3);
|
|
1001
1064
|
}
|
|
1002
1065
|
|
|
1066
|
+
:host([data-sticky-checkout="true"]) .checkout-actions > .checkout-btn,
|
|
1067
|
+
:host([data-sticky-checkout="true"]) .inline-external-ticket-button {
|
|
1068
|
+
display: none;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1003
1071
|
.sticky-checkout-bar {
|
|
1004
1072
|
display: block;
|
|
1005
1073
|
}
|
|
@@ -44,6 +44,16 @@ function eventVenueName(event) {
|
|
|
44
44
|
function optionalId(id) {
|
|
45
45
|
return id || undefined;
|
|
46
46
|
}
|
|
47
|
+
function urlDomain(url) {
|
|
48
|
+
if (!url)
|
|
49
|
+
return "external site";
|
|
50
|
+
try {
|
|
51
|
+
return new URL(url).hostname.replace(/^www\./, "");
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return "external site";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
47
57
|
function admissionAriaLabel(admission, section, status) {
|
|
48
58
|
if (section)
|
|
49
59
|
return `${admission.name} in ${section.name} - ${status}`;
|
|
@@ -981,21 +991,21 @@ export class SessionsTicketing {
|
|
|
981
991
|
previewItem: quoteItemsBySelection(this.previewQuote).get(key),
|
|
982
992
|
});
|
|
983
993
|
const savings = admissionPriceSavings(price);
|
|
984
|
-
return (h("div", { class: "admission-price-info" }, h("div", { class: "admission-price-wrapper" }, this.renderAdmissionPrice(price),
|
|
994
|
+
return (h("div", { class: "admission-price-info" }, h("div", { class: "admission-price-wrapper" }, savings > 0 && (h("span", { class: "admission-savings" }, "Save ", this.formatPriceValue(savings))), this.renderAdmissionPrice(price), price.fees > 0 && (h("span", { class: "admission-booking-fee" }, this.formatPriceValue(price.fees), " Booking Fee")), state.showScarcity && (h("span", { class: "admission-availability" }, admission.available, " tickets remaining")), state.label && (h("span", { class: `admission-sale-label ${state.label.tone}` }, state.label.text))), this.renderAdmissionControls(admission, sectionId, state, mode)));
|
|
985
995
|
}
|
|
986
996
|
renderAdmissionPrice(price) {
|
|
987
997
|
if (price.discounted) {
|
|
988
|
-
return (h("span", { class: "admission-price-row" }, h("span", { class: "admission-price discounted" }, this.formatPriceValue(price.
|
|
998
|
+
return (h("span", { class: "admission-price-row" }, h("span", { class: "admission-price discounted" }, this.formatPriceValue(price.base)), price.gross !== undefined && (h("span", { class: "admission-price-original" }, this.formatPriceValue(price.gross)))));
|
|
989
999
|
}
|
|
990
|
-
return (h("span", { class: "admission-price" }, this.formatPriceValue(price.
|
|
1000
|
+
return (h("span", { class: "admission-price" }, this.formatPriceValue(price.base)));
|
|
991
1001
|
}
|
|
992
1002
|
renderAdmissionControls(admission, sectionId, state, mode) {
|
|
993
|
-
if (
|
|
994
|
-
return
|
|
995
|
-
if (!state.soldOut) {
|
|
996
|
-
return this.renderQuantityControls(admission, sectionId, state.disabled, state.maxQuantity);
|
|
1003
|
+
if (state.statusLabel) {
|
|
1004
|
+
return (h("div", { class: `sold-out-controls ${state.statusTone ?? ""}` }, h("span", { class: "sold-out-text" }, state.statusLabel)));
|
|
997
1005
|
}
|
|
998
|
-
|
|
1006
|
+
if (mode === "door")
|
|
1007
|
+
return null;
|
|
1008
|
+
return this.renderQuantityControls(admission, sectionId, state.disabled, state.maxQuantity);
|
|
999
1009
|
}
|
|
1000
1010
|
renderAdmission(admission, event, section, isSectionSoldOut = false, mode = "default") {
|
|
1001
1011
|
const state = getAdmissionDisplayState({
|
|
@@ -1011,13 +1021,16 @@ export class SessionsTicketing {
|
|
|
1011
1021
|
return `admission-card ${state.soldOut ? "sold-out" : ""} ${state.disabled && !state.soldOut ? "unavailable" : ""} ${section ? "" : "solo-admission"}`;
|
|
1012
1022
|
}
|
|
1013
1023
|
getAdmissionAriaLabel(admission, section, state) {
|
|
1014
|
-
const status = this.admissionStatusText(admission, state.soldOut);
|
|
1024
|
+
const status = state.statusLabel ?? this.admissionStatusText(admission, state.soldOut);
|
|
1015
1025
|
return admissionAriaLabel(admission, section, status);
|
|
1016
1026
|
}
|
|
1017
1027
|
admissionStatusText(admission, soldOut) {
|
|
1018
1028
|
if (soldOut)
|
|
1019
1029
|
return "Sold Out";
|
|
1020
|
-
|
|
1030
|
+
if ((admission.price.booking ?? 0) <= 0) {
|
|
1031
|
+
return this.formatPriceValue(admission.price.base);
|
|
1032
|
+
}
|
|
1033
|
+
return `${this.formatPriceValue(admission.price.base)} plus ${this.formatPriceValue(admission.price.booking)} booking fee`;
|
|
1021
1034
|
}
|
|
1022
1035
|
renderAdmissionHeader(admission) {
|
|
1023
1036
|
return (h("div", { class: "admission-header" }, h("div", { class: "admission-header-text" }, h("h3", { class: "admission-title" }, admission.name), admission.subtitle && (h("p", { class: "admission-subtitle" }, admission.subtitle))), this.renderMoreInfoButton(admission)));
|
|
@@ -1033,29 +1046,29 @@ export class SessionsTicketing {
|
|
|
1033
1046
|
}
|
|
1034
1047
|
return (h(h.Fragment, null, this.renderEventTimeAndLocation(event), this.renderPriceAndControls(admission, sectionId, state, mode)));
|
|
1035
1048
|
}
|
|
1036
|
-
renderSectionHeader(section, admissions
|
|
1037
|
-
return (h("div", { class: "section-header" }, h("h2", { class: "section-name" }, section.name
|
|
1049
|
+
renderSectionHeader(section, admissions) {
|
|
1050
|
+
return (h("div", { class: "section-header" }, h("h2", { class: "section-name" }, section.name), this.renderAdmissionTime(admissions[0], "section-time"), this.renderSectionLocation(section)));
|
|
1038
1051
|
}
|
|
1039
1052
|
renderSectionWithAdmissions(section, admissions, event, mode) {
|
|
1040
1053
|
const soldOut = isSectionSoldOut({
|
|
1041
1054
|
admissions,
|
|
1042
1055
|
section,
|
|
1043
1056
|
});
|
|
1044
|
-
return (h("div", { class: `ticket-section ${soldOut ? "section-sold-out" : ""}`, key: section.id }, this.renderSectionHeader(section, admissions
|
|
1057
|
+
return (h("div", { class: `ticket-section ${soldOut ? "section-sold-out" : ""}`, key: section.id }, this.renderSectionHeader(section, admissions), h("div", { class: "admissions-list" }, admissions.map((admission) => this.renderAdmission(admission, event, section, soldOut, mode)))));
|
|
1045
1058
|
}
|
|
1046
1059
|
renderLoadingState() {
|
|
1047
|
-
return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "loading-
|
|
1060
|
+
return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, "Get Tickets"), h("div", { class: "ticket-section loading-ticket-section" }, h("div", { class: "admissions-list" }, [0, 1, 2].map((item) => (h("div", { "aria-hidden": "true", class: "admission-card loading-admission", key: item })))))))));
|
|
1048
1061
|
}
|
|
1049
1062
|
renderErrorState() {
|
|
1050
1063
|
if (this.passcodeDenied)
|
|
1051
1064
|
return this.renderPasscodeState();
|
|
1052
|
-
return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "
|
|
1065
|
+
return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "message-state" }, h("strong", null, "Tickets Couldn\u2019t Load"), h("span", null, "We couldn\u2019t load ticket details. Try again in a moment."), h("button", { type: "button", class: "retry-button", onClick: () => this.loadEventData() }, "Try Again")))));
|
|
1053
1066
|
}
|
|
1054
1067
|
renderPasscodeState() {
|
|
1055
1068
|
return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("form", { class: "passcode-form", onSubmit: (e) => this.submitPasscode(e) }, h("h2", null, "Enter passcode"), h("p", null, "Enter the event passcode to view tickets and event details."), h("input", { type: "text", name: "passcode", value: this.passcodeInput, onInput: this.handlePasscodeInput, autocomplete: "one-time-code", placeholder: "Passcode", "aria-label": "Passcode" }), this.passcodeDenied && this.activePasscode && (h("span", { class: "error-message" }, "Incorrect passcode")), h("button", { type: "submit", class: "checkout-btn", disabled: !this.passcodeInput.trim() }, "Unlock event")))));
|
|
1056
1069
|
}
|
|
1057
1070
|
renderNotFoundState() {
|
|
1058
|
-
return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "
|
|
1071
|
+
return (h(Host, { "data-theme": this.currentTheme }, h("div", { class: "session-services-ticketing-container" }, h("div", { class: "message-state" }, h("strong", null, "Event not found"), h("span", null, "We couldn\u2019t find this event. The link may be incorrect or expired.")))));
|
|
1059
1072
|
}
|
|
1060
1073
|
renderCouponPanel() {
|
|
1061
1074
|
const hasInput = this.couponInput.trim().length > 0;
|
|
@@ -1137,6 +1150,13 @@ export class SessionsTicketing {
|
|
|
1137
1150
|
return null;
|
|
1138
1151
|
return (h("div", { class: "sticky-checkout-bar" }, h("button", { type: "button", class: `checkout-btn sticky-checkout-btn ${this.selectionPrompt ? "selection-prompt" : ""}`, onClick: () => this.handleStickyCheckoutClick(state), disabled: this.isStickyCheckoutDisabled(state), "aria-label": this.quoteLoading ? "Updating" : undefined }, this.renderStickyCheckoutButtonContent(state))));
|
|
1139
1152
|
}
|
|
1153
|
+
renderStickyExternalTicketing(state) {
|
|
1154
|
+
if (!this.stickyCheckout)
|
|
1155
|
+
return null;
|
|
1156
|
+
if (!state.externalTicketUrl)
|
|
1157
|
+
return null;
|
|
1158
|
+
return (h("div", { class: "sticky-checkout-bar" }, h("a", { class: "external-ticket-button sticky-checkout-btn", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer" }, h("span", { class: "external-ticket-label" }, "Get tickets"))));
|
|
1159
|
+
}
|
|
1140
1160
|
renderModal() {
|
|
1141
1161
|
if (!this.openModalAdmissionId)
|
|
1142
1162
|
return null;
|
|
@@ -1163,7 +1183,7 @@ export class SessionsTicketing {
|
|
|
1163
1183
|
if (mode !== "door")
|
|
1164
1184
|
return null;
|
|
1165
1185
|
const location = event.location?.name?.trim() || "the venue";
|
|
1166
|
-
return (h("div", { class: "door-alert" }, h("strong", null, "Tickets are available at ", location), h("span", null, "Online sales are closed.
|
|
1186
|
+
return (h("div", { class: "door-alert" }, h("strong", null, "Tickets are available at ", location), h("span", null, "Online sales are closed. Tickets are available at the venue when you arrive.")));
|
|
1167
1187
|
}
|
|
1168
1188
|
loadingView() {
|
|
1169
1189
|
return this.loading ? this.renderLoadingState() : undefined;
|
|
@@ -1183,7 +1203,7 @@ export class SessionsTicketing {
|
|
|
1183
1203
|
return this.renderNotFoundState();
|
|
1184
1204
|
const state = getTicketingState(event);
|
|
1185
1205
|
if (state.showExternalTicketing) {
|
|
1186
|
-
return this.renderExternalTicketing(state.
|
|
1206
|
+
return (h(Host, { "data-theme": this.currentTheme, "data-sticky-checkout": this.stickyCheckout ? "true" : undefined }, h("div", { class: "session-services-ticketing-container" }, this.renderExternalTicketing(state)), this.renderStickyExternalTicketing(state)));
|
|
1187
1207
|
}
|
|
1188
1208
|
return (h(Host, { "data-theme": this.currentTheme, "data-sticky-checkout": this.stickyCheckout ? "true" : undefined }, h("div", { class: "session-services-ticketing-container" }, state.showTicketing
|
|
1189
1209
|
? this.renderTicketSections(event)
|
|
@@ -1191,13 +1211,16 @@ export class SessionsTicketing {
|
|
|
1191
1211
|
state.showTicketing &&
|
|
1192
1212
|
this.renderCheckoutActions()), this.renderStickyCheckout(state), this.renderModal()));
|
|
1193
1213
|
}
|
|
1194
|
-
renderExternalTicketing(
|
|
1195
|
-
|
|
1214
|
+
renderExternalTicketing(state) {
|
|
1215
|
+
const domain = urlDomain(state.externalTicketUrl);
|
|
1216
|
+
if (!state.externalTicketUrl)
|
|
1217
|
+
return null;
|
|
1218
|
+
return (h("div", { class: "tickets-wrapper" }, h("h2", { class: "tickets-heading" }, state.ticketHeading), h("div", { class: "external-ticket-panel" }, h("p", { class: "external-ticket-warning" }, "This event sells through an external ticketing site. Checkout, tickets, and support are handled there."), h("a", { class: "external-ticket-button inline-external-ticket-button", href: state.externalTicketUrl, target: "_blank", rel: "noreferrer" }, h("span", { class: "external-ticket-label" }, "Get tickets"), h("span", { class: "external-ticket-domain" }, "via ", domain)))));
|
|
1196
1219
|
}
|
|
1197
1220
|
renderUnavailableState(state) {
|
|
1198
|
-
return (h("div", { class: "empty-ticketing-state" }, h("strong", null,
|
|
1199
|
-
? "
|
|
1200
|
-
: "Tickets are not
|
|
1221
|
+
return (h("div", { class: "empty-ticketing-state" }, h("strong", null, "Tickets Unavailable"), h("span", null, state.isEnded
|
|
1222
|
+
? "This event has ended, so tickets are no longer available."
|
|
1223
|
+
: "Tickets are not available for this event right now.")));
|
|
1201
1224
|
}
|
|
1202
1225
|
render() {
|
|
1203
1226
|
return this.pendingView() ?? this.renderReadyState();
|
package/dist/collection/components/session-services-ticketing/session-services-ticketing.logic.js
CHANGED
|
@@ -62,25 +62,7 @@ function hasPurchasableAdmissions(event) {
|
|
|
62
62
|
const zone = eventTimeZone(event);
|
|
63
63
|
return event.admissions.some((admission) => isAdmissionPurchasable(admission, zone, sections));
|
|
64
64
|
}
|
|
65
|
-
function postSaleLabel(value) {
|
|
66
|
-
if (value === "SOLD_OUT")
|
|
67
|
-
return "Sold out";
|
|
68
|
-
if (value === "DOOR")
|
|
69
|
-
return "Tickets available at the door";
|
|
70
|
-
return "Sale ended";
|
|
71
|
-
}
|
|
72
|
-
function postSaleTone(value) {
|
|
73
|
-
if (value === "DOOR")
|
|
74
|
-
return "success";
|
|
75
|
-
return "muted";
|
|
76
|
-
}
|
|
77
65
|
function admissionSaleLabel(admission, zone) {
|
|
78
|
-
if (isNaiveDateTimePast(admission.saleEndsAt, zone)) {
|
|
79
|
-
return {
|
|
80
|
-
text: postSaleLabel(admission.saleEndsBehavior),
|
|
81
|
-
tone: postSaleTone(admission.saleEndsBehavior),
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
66
|
if (!isNaiveDateTimeFuture(admission.saleStartsAt, zone)) {
|
|
85
67
|
return null;
|
|
86
68
|
}
|
|
@@ -89,6 +71,16 @@ function admissionSaleLabel(admission, zone) {
|
|
|
89
71
|
tone: "muted",
|
|
90
72
|
};
|
|
91
73
|
}
|
|
74
|
+
function admissionStatus(input) {
|
|
75
|
+
if (input.value === "DOOR" && (input.soldOut || input.saleEnded)) {
|
|
76
|
+
return { text: "Available At Door", tone: "success" };
|
|
77
|
+
}
|
|
78
|
+
if (input.soldOut)
|
|
79
|
+
return { text: "Sold Out", tone: "destructive" };
|
|
80
|
+
if (!input.saleEnded)
|
|
81
|
+
return null;
|
|
82
|
+
return { text: "Sale Ended", tone: "destructive" };
|
|
83
|
+
}
|
|
92
84
|
function endedStatus(admissions, zone) {
|
|
93
85
|
const ended = admissions.filter((admission) => isNaiveDateTimePast(admission.saleEndsAt, zone));
|
|
94
86
|
if (ended.length === 0)
|
|
@@ -189,12 +181,19 @@ export function getAdmissionDisplayState(input) {
|
|
|
189
181
|
const zone = eventTimeZone(input.event);
|
|
190
182
|
const saleNotStarted = isNaiveDateTimeFuture(input.admission.saleStartsAt, zone);
|
|
191
183
|
const saleEnded = isNaiveDateTimePast(input.admission.saleEndsAt, zone);
|
|
184
|
+
const saleEndedSoldOut = saleEnded && input.admission.saleEndsBehavior === "SOLD_OUT";
|
|
192
185
|
const soldOut = Boolean(input.sectionSoldOut) ||
|
|
186
|
+
saleEndedSoldOut ||
|
|
193
187
|
isAdmissionSoldOut({
|
|
194
188
|
admission: input.admission,
|
|
195
189
|
section: input.section,
|
|
196
190
|
});
|
|
197
191
|
const disabled = soldOut || saleNotStarted || saleEnded;
|
|
192
|
+
const status = admissionStatus({
|
|
193
|
+
saleEnded,
|
|
194
|
+
soldOut,
|
|
195
|
+
value: input.admission.saleEndsBehavior,
|
|
196
|
+
});
|
|
198
197
|
return {
|
|
199
198
|
disabled,
|
|
200
199
|
label: admissionSaleLabel(input.admission, zone),
|
|
@@ -202,6 +201,8 @@ export function getAdmissionDisplayState(input) {
|
|
|
202
201
|
postSale: saleEnded,
|
|
203
202
|
showScarcity: showScarcity(input.admission, soldOut, disabled),
|
|
204
203
|
soldOut,
|
|
204
|
+
statusLabel: status?.text ?? null,
|
|
205
|
+
statusTone: status?.tone ?? null,
|
|
205
206
|
};
|
|
206
207
|
}
|
|
207
208
|
function quoteItemUnits(item) {
|
|
@@ -211,29 +212,35 @@ export function getAdmissionPriceDisplay(input) {
|
|
|
211
212
|
const item = input.quoteItem ?? input.previewItem;
|
|
212
213
|
if (item) {
|
|
213
214
|
const units = quoteItemUnits(item);
|
|
214
|
-
const
|
|
215
|
+
const base = Math.round(Math.max((item.price.base + item.price.discount) / units, 0));
|
|
216
|
+
const fees = Math.round(item.price.booking / units);
|
|
215
217
|
if (!item.price.discount || item.price.discount >= 0) {
|
|
216
218
|
return {
|
|
219
|
+
base,
|
|
217
220
|
discounted: false,
|
|
218
|
-
|
|
221
|
+
fees,
|
|
219
222
|
};
|
|
220
223
|
}
|
|
221
224
|
return {
|
|
225
|
+
base,
|
|
222
226
|
discounted: true,
|
|
223
|
-
|
|
224
|
-
|
|
227
|
+
fees,
|
|
228
|
+
gross: Math.round(item.price.base / units),
|
|
225
229
|
};
|
|
226
230
|
}
|
|
227
231
|
if (input.initialPrice && input.initialPrice.discount < 0) {
|
|
232
|
+
const fees = input.admission.price.booking ?? 0;
|
|
228
233
|
return {
|
|
234
|
+
base: Math.max(input.initialPrice.total - fees, 0),
|
|
229
235
|
discounted: true,
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
fees,
|
|
237
|
+
gross: Math.max(input.initialPrice.gross - fees, 0),
|
|
232
238
|
};
|
|
233
239
|
}
|
|
234
240
|
return {
|
|
241
|
+
base: input.admission.price.base ?? 0,
|
|
235
242
|
discounted: false,
|
|
236
|
-
|
|
243
|
+
fees: input.admission.price.booking ?? 0,
|
|
237
244
|
};
|
|
238
245
|
}
|
|
239
246
|
export function quoteItemsBySelection(quote) {
|
|
@@ -242,7 +249,7 @@ export function quoteItemsBySelection(quote) {
|
|
|
242
249
|
export function admissionPriceSavings(price) {
|
|
243
250
|
if (!price.discounted || price.gross === undefined)
|
|
244
251
|
return 0;
|
|
245
|
-
return Math.max(price.gross - price.
|
|
252
|
+
return Math.max(price.gross - price.base, 0);
|
|
246
253
|
}
|
|
247
254
|
export function previewQuoteItems(event) {
|
|
248
255
|
const ids = new Set(event.sections.map((section) => section.id));
|