@ticketlayer/elements 0.3.3 → 1.0.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/README.md +3 -2
- package/dist/cjs/{index-BpfoKd9Q.js → index-DanPUX0s.js} +1 -1
- package/dist/cjs/index.cjs.js +2 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/ticket-selector-BYVL13k_.js +3623 -0
- package/dist/cjs/ticketlayer-elements.cjs.js +2 -2
- package/dist/cjs/tl-buy-modal.cjs.entry.js +4 -4
- package/dist/cjs/tl-buy-tickets-button.cjs.entry.js +89 -71
- package/dist/cjs/tl-buy-tickets-wrapper.cjs.entry.js +62 -31
- package/dist/cjs/tl-cart-badge.cjs.entry.js +75 -62
- package/dist/cjs/tl-cart-drawer.cjs.entry.js +52 -24
- package/dist/cjs/tl-cart.cjs.entry.js +72 -98
- package/dist/cjs/tl-checkout-wrapper.cjs.entry.js +52 -30
- package/dist/cjs/tl-event-card.cjs.entry.js +44 -105
- package/dist/cjs/tl-event-list.cjs.entry.js +73 -36
- package/dist/cjs/tl-login.cjs.entry.js +75 -141
- package/dist/cjs/tl-my-orders.cjs.entry.js +53 -92
- package/dist/cjs/tl-occurrence-selector_2.cjs.entry.js +205 -641
- package/dist/cjs/tl-order-confirmation.cjs.entry.js +72 -105
- package/dist/cjs/tl-order-tickets_2.cjs.entry.js +50 -76
- package/dist/cjs/tl-promo-code.cjs.entry.js +51 -47
- package/dist/cjs/tl-seat-map.cjs.entry.js +4 -4
- package/dist/cjs/web-query-Ce73jB4k.js +16 -0
- package/dist/collection/components/tl-buy-modal/tl-buy-modal.css +12 -19
- package/dist/collection/components/tl-buy-modal/tl-buy-modal.js +2 -2
- package/dist/collection/components/tl-buy-tickets-button/tl-buy-tickets-button.css +41 -4
- package/dist/collection/components/tl-buy-tickets-button/tl-buy-tickets-button.js +105 -76
- package/dist/collection/components/tl-buy-tickets-wrapper/tl-buy-tickets-wrapper.css +2 -2
- package/dist/collection/components/tl-buy-tickets-wrapper/tl-buy-tickets-wrapper.js +73 -30
- package/dist/collection/components/tl-cart/tl-cart.css +52 -51
- package/dist/collection/components/tl-cart/tl-cart.js +82 -101
- package/dist/collection/components/tl-cart-badge/tl-cart-badge.css +11 -11
- package/dist/collection/components/tl-cart-badge/tl-cart-badge.js +62 -62
- package/dist/collection/components/tl-cart-drawer/tl-cart-drawer.css +6 -6
- package/dist/collection/components/tl-cart-drawer/tl-cart-drawer.js +56 -24
- package/dist/collection/components/tl-checkout-wrapper/tl-checkout-wrapper.css +2 -2
- package/dist/collection/components/tl-checkout-wrapper/tl-checkout-wrapper.js +61 -29
- package/dist/collection/components/tl-event-card/event-card-adapter.js +11 -23
- package/dist/collection/components/tl-event-card/tl-event-card.css +22 -22
- package/dist/collection/components/tl-event-card/tl-event-card.js +51 -84
- package/dist/collection/components/tl-event-list/tl-event-list.css +17 -17
- package/dist/collection/components/tl-event-list/tl-event-list.js +82 -38
- package/dist/collection/components/tl-login/tl-login.css +26 -26
- package/dist/collection/components/tl-login/tl-login.js +83 -147
- package/dist/collection/components/tl-my-orders/tl-my-orders.css +40 -40
- package/dist/collection/components/tl-my-orders/tl-my-orders.js +58 -96
- package/dist/collection/components/tl-occurrence-selector/tl-occurrence-selector.css +54 -65
- package/dist/collection/components/tl-occurrence-selector/tl-occurrence-selector.js +137 -516
- package/dist/collection/components/tl-order-confirmation/tl-order-confirmation.css +38 -38
- package/dist/collection/components/tl-order-confirmation/tl-order-confirmation.js +81 -113
- package/dist/collection/components/tl-order-tickets/tl-order-tickets.css +9 -9
- package/dist/collection/components/tl-order-tickets/tl-order-tickets.js +57 -92
- package/dist/collection/components/tl-promo-code/tl-promo-code.css +25 -25
- package/dist/collection/components/tl-promo-code/tl-promo-code.js +55 -50
- package/dist/collection/components/tl-seat-map/tl-seat-map.css +10 -10
- package/dist/collection/components/tl-seat-map/tl-seat-map.js +2 -2
- package/dist/collection/components/tl-ticket/tl-ticket.css +13 -13
- package/dist/collection/components/tl-ticket-selector/tl-ticket-selector.css +74 -49
- package/dist/collection/components/tl-ticket-selector/tl-ticket-selector.js +95 -135
- package/dist/collection/utils/cart-totals.js +9 -0
- package/dist/collection/utils/order-summary.js +15 -99
- package/dist/collection/utils/testing/deep-text.js +29 -0
- package/dist/collection/utils/testing/fixtures.js +290 -0
- package/dist/collection/utils/testing/mock-sdk.js +13 -2
- package/dist/collection/utils/web-query.js +12 -0
- package/dist/collection/utils/web-storage.js +22 -0
- package/dist/components/ticket-selector.js +1 -0
- package/dist/components/tl-buy-modal.js +1 -1
- package/dist/components/tl-buy-tickets-button.js +1 -1
- package/dist/components/tl-buy-tickets-wrapper2.js +1 -1
- package/dist/components/tl-cart-badge.js +1 -1
- package/dist/components/tl-cart-drawer.js +1 -1
- package/dist/components/tl-cart2.js +1 -1
- package/dist/components/tl-checkout-wrapper2.js +1 -1
- package/dist/components/tl-event-card2.js +1 -1
- package/dist/components/tl-event-list.js +1 -1
- package/dist/components/tl-login2.js +1 -1
- package/dist/components/tl-my-orders.js +1 -1
- package/dist/components/tl-occurrence-selector2.js +1 -1
- package/dist/components/tl-order-confirmation.js +1 -1
- package/dist/components/tl-order-tickets2.js +1 -1
- package/dist/components/tl-promo-code.js +1 -1
- package/dist/components/tl-seat-map.js +1 -1
- package/dist/components/tl-ticket-selector2.js +1 -1
- package/dist/components/tl-ticket2.js +1 -1
- package/dist/components/web-query.js +1 -0
- package/dist/elements.docs.json +36 -36
- package/dist/esm/{index-CNX8hZa8.js → index-imfxp765.js} +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/ticket-selector-BwChnHVC.js +3606 -0
- package/dist/esm/ticketlayer-elements.js +3 -3
- package/dist/esm/tl-buy-modal.entry.js +4 -4
- package/dist/esm/tl-buy-tickets-button.entry.js +90 -72
- package/dist/esm/tl-buy-tickets-wrapper.entry.js +63 -32
- package/dist/esm/tl-cart-badge.entry.js +76 -63
- package/dist/esm/tl-cart-drawer.entry.js +53 -25
- package/dist/esm/tl-cart.entry.js +73 -99
- package/dist/esm/tl-checkout-wrapper.entry.js +53 -31
- package/dist/esm/tl-event-card.entry.js +45 -106
- package/dist/esm/tl-event-list.entry.js +74 -37
- package/dist/esm/tl-login.entry.js +76 -142
- package/dist/esm/tl-my-orders.entry.js +54 -93
- package/dist/esm/tl-occurrence-selector_2.entry.js +206 -642
- package/dist/esm/tl-order-confirmation.entry.js +73 -106
- package/dist/esm/tl-order-tickets_2.entry.js +51 -77
- package/dist/esm/tl-promo-code.entry.js +52 -48
- package/dist/esm/tl-seat-map.entry.js +4 -4
- package/dist/esm/web-query-Bdbb2lk5.js +14 -0
- package/dist/ticketlayer-elements/index.esm.js +1 -1
- package/dist/ticketlayer-elements/p-45923d2c.entry.js +1 -0
- package/dist/ticketlayer-elements/p-492adc77.entry.js +1 -0
- package/dist/ticketlayer-elements/p-4cfc9e53.entry.js +1 -0
- package/dist/ticketlayer-elements/p-5135630e.entry.js +1 -0
- package/dist/ticketlayer-elements/p-5bbce3b5.entry.js +1 -0
- package/dist/ticketlayer-elements/p-7d547721.entry.js +1 -0
- package/dist/ticketlayer-elements/p-7fe7b6ba.entry.js +1 -0
- package/dist/ticketlayer-elements/p-8122f0c1.entry.js +1 -0
- package/dist/ticketlayer-elements/p-98d40869.entry.js +1 -0
- package/dist/ticketlayer-elements/p-Bdbb2lk5.js +1 -0
- package/dist/ticketlayer-elements/p-BwChnHVC.js +1 -0
- package/dist/ticketlayer-elements/p-abec290a.entry.js +1 -0
- package/dist/ticketlayer-elements/p-ac79a3f6.entry.js +1 -0
- package/dist/ticketlayer-elements/p-d01f4429.entry.js +1 -0
- package/dist/ticketlayer-elements/p-d7ffaf46.entry.js +1 -0
- package/dist/ticketlayer-elements/p-e7170f3c.entry.js +1 -0
- package/dist/ticketlayer-elements/p-e787e862.entry.js +1 -0
- package/dist/ticketlayer-elements/p-f1ff931f.entry.js +1 -0
- package/dist/ticketlayer-elements/p-imfxp765.js +3 -0
- package/dist/ticketlayer-elements/ticketlayer-elements.css +1 -1
- package/dist/ticketlayer-elements/ticketlayer-elements.esm.js +1 -1
- package/dist/types/components/tl-buy-tickets-button/tl-buy-tickets-button.d.ts +40 -8
- package/dist/types/components/tl-buy-tickets-wrapper/tl-buy-tickets-wrapper.d.ts +20 -1
- package/dist/types/components/tl-cart/tl-cart.d.ts +40 -32
- package/dist/types/components/tl-cart-badge/tl-cart-badge.d.ts +22 -7
- package/dist/types/components/tl-cart-drawer/tl-cart-drawer.d.ts +28 -5
- package/dist/types/components/tl-checkout-wrapper/tl-checkout-wrapper.d.ts +18 -1
- package/dist/types/components/tl-event-card/event-card-adapter.d.ts +9 -20
- package/dist/types/components/tl-event-card/tl-event-card.d.ts +25 -28
- package/dist/types/components/tl-event-list/tl-event-list.d.ts +46 -6
- package/dist/types/components/tl-login/tl-login.d.ts +68 -22
- package/dist/types/components/tl-my-orders/tl-my-orders.d.ts +30 -12
- package/dist/types/components/tl-occurrence-selector/tl-occurrence-selector.d.ts +73 -161
- package/dist/types/components/tl-order-confirmation/tl-order-confirmation.d.ts +48 -15
- package/dist/types/components/tl-order-tickets/tl-order-tickets.d.ts +29 -31
- package/dist/types/components/tl-promo-code/tl-promo-code.d.ts +28 -10
- package/dist/types/components/tl-ticket/tl-ticket.d.ts +2 -11
- package/dist/types/components/tl-ticket-selector/tl-ticket-selector.d.ts +61 -32
- package/dist/types/components.d.ts +302 -62
- package/dist/types/utils/cart-totals.d.ts +10 -0
- package/dist/types/utils/order-summary.d.ts +16 -65
- package/dist/types/utils/testing/deep-text.d.ts +13 -0
- package/dist/types/utils/testing/fixtures.d.ts +225 -0
- package/dist/types/utils/testing/mock-sdk.d.ts +14 -1
- package/dist/types/utils/web-query.d.ts +18 -0
- package/dist/types/utils/web-storage.d.ts +16 -0
- package/elements.catalogue.json +676 -55
- package/package.json +14 -6
- package/dist/cjs/order-summary-ZMkJ5bez.js +0 -116
- package/dist/components/order-summary.js +0 -1
- package/dist/esm/order-summary-BGekdjN9.js +0 -103
- package/dist/ticketlayer-elements/p-0b1d16f8.entry.js +0 -1
- package/dist/ticketlayer-elements/p-1471f6d8.entry.js +0 -1
- package/dist/ticketlayer-elements/p-1c51cbc1.entry.js +0 -1
- package/dist/ticketlayer-elements/p-5169f68b.entry.js +0 -1
- package/dist/ticketlayer-elements/p-895ba1f3.entry.js +0 -1
- package/dist/ticketlayer-elements/p-8d5722e1.entry.js +0 -1
- package/dist/ticketlayer-elements/p-917d8e09.entry.js +0 -1
- package/dist/ticketlayer-elements/p-9629029a.entry.js +0 -1
- package/dist/ticketlayer-elements/p-BGekdjN9.js +0 -1
- package/dist/ticketlayer-elements/p-CNX8hZa8.js +0 -3
- package/dist/ticketlayer-elements/p-a22714d0.entry.js +0 -1
- package/dist/ticketlayer-elements/p-bf73044b.entry.js +0 -1
- package/dist/ticketlayer-elements/p-e02079fa.entry.js +0 -1
- package/dist/ticketlayer-elements/p-e04ace15.entry.js +0 -1
- package/dist/ticketlayer-elements/p-e6fab1d5.entry.js +0 -1
- package/dist/ticketlayer-elements/p-f826b753.entry.js +0 -1
- package/dist/ticketlayer-elements/p-fa639d88.entry.js +0 -1
- package/dist/ticketlayer-elements/p-fbaca948.entry.js +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { h } from "@stencil/core";
|
|
2
|
-
import {
|
|
2
|
+
import { createElement, orderTicketsCore, } from "@ticketlayer/elements-core";
|
|
3
|
+
import { getSDK, whenSDK } from "../../utils/sdk-connector";
|
|
3
4
|
/**
|
|
4
5
|
* tl-order-tickets - renders all the tickets for an order as scannable QR
|
|
5
6
|
* cards with PDF download. Fetches the order through the SDK (order-access
|
|
@@ -7,101 +8,73 @@ import { whenSDK } from "../../utils/sdk-connector";
|
|
|
7
8
|
*
|
|
8
9
|
* Usage: <tl-order-tickets order-id="ord_xxx"></tl-order-tickets>
|
|
9
10
|
*
|
|
10
|
-
* On an empty result it waits rather than concluding there is nothing
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* waiting.
|
|
19
|
-
*
|
|
20
|
-
* So: an empty order is treated as issuance in flight and polled, with the
|
|
21
|
-
* gaps widening, for about a minute. Then it stops and says the tickets are
|
|
22
|
-
* coming by email, because at that point something probably is wrong and a
|
|
23
|
-
* page that polls forever is worse than one that admits it.
|
|
11
|
+
* On an empty result it waits rather than concluding there is nothing: tickets
|
|
12
|
+
* are issued a moment after the order is paid, so a confirmation page renders
|
|
13
|
+
* before the passes exist. The waiting, the widening schedule behind it and
|
|
14
|
+
* the point at which it gives up are all in `orderTicketsCore`
|
|
15
|
+
* (`@ticketlayer/elements-core`, AGENTS.md, TKT-11), along with every string.
|
|
16
|
+
* This harness renders and forwards, and the one thing it owns is pairing
|
|
17
|
+
* `mount()` with its teardown - which is what stops the polling when the
|
|
18
|
+
* element goes off screen.
|
|
24
19
|
*/
|
|
25
20
|
export class TlOrderTickets {
|
|
26
21
|
constructor() {
|
|
27
22
|
/** Columns in the grid (default 2). */
|
|
28
23
|
this.columns = 2;
|
|
29
|
-
this.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
this.element = createElement(orderTicketsCore, {
|
|
25
|
+
client: () => getSDK(),
|
|
26
|
+
clientReady: () => whenSDK(),
|
|
27
|
+
emit: (event, detail) => this.forward(event, detail),
|
|
28
|
+
});
|
|
29
|
+
/** The core's whole view. Assigning it is what makes Stencil re-render. */
|
|
30
|
+
this.view = this.element.view;
|
|
35
31
|
}
|
|
32
|
+
/** A different order: forget this one and read again, from the top. */
|
|
36
33
|
watchOrder() {
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
34
|
+
this.syncProps();
|
|
35
|
+
this.element.actions.orderIdChanged();
|
|
39
36
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
disconnectedCallback() {
|
|
44
|
-
this.stopPolling();
|
|
37
|
+
syncProps() {
|
|
38
|
+
this.element.setProps({ orderId: this.orderId, columns: this.columns });
|
|
45
39
|
}
|
|
46
|
-
|
|
47
|
-
this.
|
|
48
|
-
this.
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
connectedCallback() {
|
|
41
|
+
this.syncProps();
|
|
42
|
+
this.unsubscribe ?? (this.unsubscribe = this.element.subscribe((view) => {
|
|
43
|
+
this.view = view;
|
|
44
|
+
}));
|
|
45
|
+
this.view = this.element.view;
|
|
46
|
+
this.teardown = this.element.mount();
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Off screen: run the mount's teardown, which is what stops the polling.
|
|
50
|
+
* Not `destroy()`: Stencil calls this for a DOM move as well as a removal,
|
|
51
|
+
* and a destroyed core never mounts again.
|
|
52
|
+
*/
|
|
53
|
+
disconnectedCallback() {
|
|
54
|
+
this.teardown?.();
|
|
55
|
+
this.teardown = undefined;
|
|
56
|
+
this.unsubscribe?.();
|
|
57
|
+
this.unsubscribe = undefined;
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const sdk = await whenSDK();
|
|
62
|
-
const orders = sdk.getOrdersManager?.();
|
|
63
|
-
if (!orders)
|
|
64
|
-
throw new Error('Tickets are not available');
|
|
65
|
-
const order = (await orders.get(this.orderId));
|
|
66
|
-
this.tickets = order?.tickets ?? [];
|
|
67
|
-
if (this.tickets.length > 0) {
|
|
68
|
-
// Arrived. Stop asking.
|
|
69
|
-
this.issuing = false;
|
|
70
|
-
this.stopPolling();
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
const delay = TlOrderTickets.POLL_DELAYS_MS[this.poll];
|
|
74
|
-
// `undefined` once the schedule runs out: give up waiting, and say so.
|
|
75
|
-
this.issuing = delay !== undefined;
|
|
76
|
-
if (delay !== undefined) {
|
|
77
|
-
this.poll += 1;
|
|
78
|
-
this.stopPolling();
|
|
79
|
-
this.timer = setTimeout(() => this.load(), delay);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
// A failed request is a different thing from an order with no tickets,
|
|
85
|
-
// and stops the polling: retrying a 403 a dozen times helps nobody.
|
|
86
|
-
this.stopPolling();
|
|
87
|
-
this.issuing = false;
|
|
88
|
-
this.error = err instanceof Error ? err.message : 'Failed to load tickets';
|
|
89
|
-
}
|
|
90
|
-
finally {
|
|
91
|
-
this.loading = false;
|
|
92
|
-
}
|
|
59
|
+
/** The core declares no events, so nothing ever reaches here. */
|
|
60
|
+
forward(_event, _detail) {
|
|
61
|
+
// Intentionally empty: tl-order-tickets announces nothing to its host.
|
|
93
62
|
}
|
|
94
63
|
render() {
|
|
95
|
-
|
|
96
|
-
|
|
64
|
+
const { status, state, strings, derived } = this.view;
|
|
65
|
+
if (status === 'loading') {
|
|
66
|
+
return h("div", { class: "state" }, strings.loading);
|
|
97
67
|
}
|
|
98
|
-
if (
|
|
99
|
-
return h("div", { class: "state error" },
|
|
68
|
+
if (status === 'error') {
|
|
69
|
+
return h("div", { class: "state error" }, state.error);
|
|
100
70
|
}
|
|
101
|
-
if (
|
|
102
|
-
return
|
|
71
|
+
if (status === 'issuing') {
|
|
72
|
+
return (h("div", { class: "state issuing", role: "status", "aria-live": "polite" }, h("span", { class: "spinner", "aria-hidden": "true" }), strings.preparing));
|
|
103
73
|
}
|
|
104
|
-
|
|
74
|
+
if (status === 'delayed') {
|
|
75
|
+
return (h("div", { class: "state", role: "status" }, strings.delayed));
|
|
76
|
+
}
|
|
77
|
+
return (h("div", { class: `grid cols-${derived.columns}` }, derived.tickets.map((t) => (h("tl-ticket", { key: t.id, ticket: t, orderId: derived.orderId })))));
|
|
105
78
|
}
|
|
106
79
|
static get is() { return "tl-order-tickets"; }
|
|
107
80
|
static get encapsulation() { return "shadow"; }
|
|
@@ -160,24 +133,16 @@ export class TlOrderTickets {
|
|
|
160
133
|
}
|
|
161
134
|
static get states() {
|
|
162
135
|
return {
|
|
163
|
-
"
|
|
164
|
-
"loading": {},
|
|
165
|
-
"error": {},
|
|
166
|
-
"issuing": {}
|
|
136
|
+
"view": {}
|
|
167
137
|
};
|
|
168
138
|
}
|
|
169
139
|
static get watchers() {
|
|
170
140
|
return [{
|
|
171
141
|
"propName": "orderId",
|
|
172
142
|
"methodName": "watchOrder"
|
|
143
|
+
}, {
|
|
144
|
+
"propName": "columns",
|
|
145
|
+
"methodName": "syncProps"
|
|
173
146
|
}];
|
|
174
147
|
}
|
|
175
148
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Gaps between polls, in milliseconds. Front-loaded because issuance
|
|
178
|
-
* usually lands in the first few seconds, then widening so a genuinely
|
|
179
|
-
* stuck order is not hammered. Sums to roughly one minute.
|
|
180
|
-
*/
|
|
181
|
-
TlOrderTickets.POLL_DELAYS_MS = [
|
|
182
|
-
1000, 1500, 2000, 3000, 4000, 5000, 6000, 8000, 10000, 12000,
|
|
183
|
-
];
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
:host {
|
|
2
2
|
display: block;
|
|
3
|
-
font-family: var(--tl-font-family
|
|
4
|
-
color: var(--tl-foreground
|
|
3
|
+
font-family: var(--tl-font-family);
|
|
4
|
+
color: var(--tl-foreground);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
.field {
|
|
8
8
|
display: flex;
|
|
9
|
-
gap: var(--tl-spacing-2
|
|
9
|
+
gap: var(--tl-spacing-2);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.input {
|
|
13
13
|
flex: 1;
|
|
14
14
|
min-width: 0;
|
|
15
|
-
padding: var(--tl-spacing-3
|
|
15
|
+
padding: var(--tl-spacing-3);
|
|
16
16
|
font: inherit;
|
|
17
17
|
font-size: 0.875rem;
|
|
18
|
-
color: var(--tl-foreground
|
|
19
|
-
background: var(--tl-background
|
|
20
|
-
border: 1px solid var(--tl-border
|
|
21
|
-
border-radius: var(--tl-radius-md
|
|
18
|
+
color: var(--tl-foreground);
|
|
19
|
+
background: var(--tl-background);
|
|
20
|
+
border: 1px solid var(--tl-border);
|
|
21
|
+
border-radius: var(--tl-radius-md);
|
|
22
22
|
text-transform: uppercase;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
.input::placeholder {
|
|
26
26
|
text-transform: none;
|
|
27
|
-
color: var(--tl-muted-foreground
|
|
27
|
+
color: var(--tl-muted-foreground);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
.input:focus {
|
|
31
|
-
outline: 2px solid var(--tl-primary
|
|
31
|
+
outline: 2px solid var(--tl-primary);
|
|
32
32
|
outline-offset: 1px;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
.apply {
|
|
36
|
-
padding: var(--tl-spacing-3
|
|
36
|
+
padding: var(--tl-spacing-3) var(--tl-spacing-4);
|
|
37
37
|
font: inherit;
|
|
38
38
|
font-size: 0.875rem;
|
|
39
39
|
font-weight: 500;
|
|
40
|
-
color: var(--tl-primary-foreground
|
|
41
|
-
background: var(--tl-primary
|
|
40
|
+
color: var(--tl-primary-foreground);
|
|
41
|
+
background: var(--tl-primary);
|
|
42
42
|
border: none;
|
|
43
|
-
border-radius: var(--tl-radius-md
|
|
43
|
+
border-radius: var(--tl-radius-md);
|
|
44
44
|
cursor: pointer;
|
|
45
45
|
white-space: nowrap;
|
|
46
46
|
}
|
|
@@ -56,45 +56,45 @@
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
.error {
|
|
59
|
-
margin: var(--tl-spacing-2
|
|
59
|
+
margin: var(--tl-spacing-2) 0 0;
|
|
60
60
|
font-size: 0.8125rem;
|
|
61
|
-
color: var(--tl-error
|
|
61
|
+
color: var(--tl-error);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
.applied {
|
|
65
65
|
display: flex;
|
|
66
66
|
align-items: center;
|
|
67
67
|
justify-content: space-between;
|
|
68
|
-
gap: var(--tl-spacing-3
|
|
69
|
-
padding: var(--tl-spacing-3
|
|
68
|
+
gap: var(--tl-spacing-3);
|
|
69
|
+
padding: var(--tl-spacing-3);
|
|
70
70
|
font-size: 0.875rem;
|
|
71
|
-
background: var(--tl-muted
|
|
72
|
-
border: 1px solid var(--tl-border
|
|
73
|
-
border-radius: var(--tl-radius-md
|
|
71
|
+
background: var(--tl-muted);
|
|
72
|
+
border: 1px solid var(--tl-border);
|
|
73
|
+
border-radius: var(--tl-radius-md);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
.applied-text {
|
|
77
77
|
display: flex;
|
|
78
78
|
align-items: center;
|
|
79
|
-
gap: var(--tl-spacing-2
|
|
79
|
+
gap: var(--tl-spacing-2);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
.icon {
|
|
83
83
|
width: 1rem;
|
|
84
84
|
height: 1rem;
|
|
85
85
|
flex-shrink: 0;
|
|
86
|
-
color: var(--tl-success
|
|
86
|
+
color: var(--tl-success);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
.code {
|
|
90
|
-
font-family: var(--tl-font-family-mono
|
|
90
|
+
font-family: var(--tl-font-family-mono);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
.link {
|
|
94
94
|
padding: 0;
|
|
95
95
|
font: inherit;
|
|
96
96
|
font-size: 0.8125rem;
|
|
97
|
-
color: var(--tl-primary
|
|
97
|
+
color: var(--tl-primary);
|
|
98
98
|
background: none;
|
|
99
99
|
border: none;
|
|
100
100
|
cursor: pointer;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { h } from "@stencil/core";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createElement, promoCodeCore, } from "@ticketlayer/elements-core";
|
|
3
|
+
import { getSDK, whenSDK } from "../../utils/sdk-connector";
|
|
4
4
|
/**
|
|
5
5
|
* tl-promo-code - an input plus Apply button that redeems a presale or promo
|
|
6
6
|
* code for the current cart (POST /sales/presale-codes/redeem through the
|
|
@@ -10,6 +10,9 @@ import { errorMessage, isAuthError } from "../../utils/order-summary";
|
|
|
10
10
|
* The API has no un-redeem, so the applied state offers only "use a different
|
|
11
11
|
* code", which clears the input for another redemption.
|
|
12
12
|
*
|
|
13
|
+
* The web harness for `promoCodeCore`: the redemption, the two error messages
|
|
14
|
+
* and every string are the core's (AGENTS.md, TKT-11).
|
|
15
|
+
*
|
|
13
16
|
* Usage: <tl-promo-code></tl-promo-code>
|
|
14
17
|
*
|
|
15
18
|
* @event tlPromoApplied - a code was redeemed ({ code, benefit, alreadyHeld, cart })
|
|
@@ -21,59 +24,55 @@ export class TlPromoCode {
|
|
|
21
24
|
this.placeholder = 'Promo or presale code';
|
|
22
25
|
/** Apply button label. */
|
|
23
26
|
this.buttonLabel = 'Apply';
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
this.element = createElement(promoCodeCore, {
|
|
28
|
+
client: () => getSDK(),
|
|
29
|
+
clientReady: () => whenSDK(),
|
|
30
|
+
emit: (event, detail) => this.forward(event, detail),
|
|
31
|
+
});
|
|
32
|
+
/** The core's whole view. Assigning it is what makes Stencil re-render. */
|
|
33
|
+
this.view = this.element.view;
|
|
28
34
|
this.handleInput = (e) => {
|
|
29
|
-
this.
|
|
30
|
-
this.error = null;
|
|
35
|
+
this.element.actions.setCode(e.target.value);
|
|
31
36
|
};
|
|
32
37
|
this.handleSubmit = (e) => {
|
|
33
38
|
e.preventDefault();
|
|
34
|
-
this.apply();
|
|
35
|
-
};
|
|
36
|
-
this.reset = () => {
|
|
37
|
-
this.applied = null;
|
|
38
|
-
this.error = null;
|
|
39
|
+
this.element.actions.apply();
|
|
39
40
|
};
|
|
41
|
+
this.reset = () => this.element.actions.reset();
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.tlError.emit(
|
|
67
|
-
}
|
|
68
|
-
finally {
|
|
69
|
-
this.applying = false;
|
|
70
|
-
}
|
|
43
|
+
syncProps() {
|
|
44
|
+
this.element.setProps({ placeholder: this.placeholder, buttonLabel: this.buttonLabel });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* This core has nothing to do on mount, and the harness calls `mount()`
|
|
48
|
+
* anyway: a harness never asks what a core's lifecycle means (TKT-197).
|
|
49
|
+
*/
|
|
50
|
+
connectedCallback() {
|
|
51
|
+
this.syncProps();
|
|
52
|
+
this.unsubscribe ?? (this.unsubscribe = this.element.subscribe((view) => {
|
|
53
|
+
this.view = view;
|
|
54
|
+
}));
|
|
55
|
+
this.view = this.element.view;
|
|
56
|
+
this.teardown = this.element.mount();
|
|
57
|
+
}
|
|
58
|
+
disconnectedCallback() {
|
|
59
|
+
this.teardown?.();
|
|
60
|
+
this.teardown = undefined;
|
|
61
|
+
this.unsubscribe?.();
|
|
62
|
+
this.unsubscribe = undefined;
|
|
63
|
+
}
|
|
64
|
+
forward(event, detail) {
|
|
65
|
+
if (event === 'tlPromoApplied')
|
|
66
|
+
this.tlPromoApplied.emit(detail);
|
|
67
|
+
else if (event === 'tlError')
|
|
68
|
+
this.tlError.emit(detail);
|
|
71
69
|
}
|
|
72
70
|
render() {
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const { status, state, strings, derived } = this.view;
|
|
72
|
+
if (status === 'applied') {
|
|
73
|
+
return (h("div", { class: "applied", role: "status" }, h("span", { class: "applied-text" }, h("svg", { class: "icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "aria-hidden": "true" }, h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", "stroke-width": "2", d: "M5 13l4 4L19 7" })), strings.codePrefix, h("strong", { class: "code" }, derived.appliedCode), derived.appliedSuffix), h("button", { type: "button", class: "link", onClick: this.reset }, strings.useDifferent)));
|
|
75
74
|
}
|
|
76
|
-
return (h("form", { class: "promo", onSubmit: this.handleSubmit }, h("div", { class: "field" }, h("input", { class: "input", type: "text", autocomplete: "off", autoCapitalize: "characters", spellcheck: false, "aria-label": this.placeholder, placeholder: this.placeholder, value:
|
|
75
|
+
return (h("form", { class: "promo", onSubmit: this.handleSubmit }, h("div", { class: "field" }, h("input", { class: "input", type: "text", autocomplete: "off", autoCapitalize: "characters", spellcheck: false, "aria-label": this.placeholder, placeholder: this.placeholder, value: state.code, disabled: derived.disabled, onInput: this.handleInput }), h("button", { type: "submit", class: "apply", disabled: derived.disabled }, derived.actionLabel)), state.error && (h("p", { class: "error", role: "alert" }, state.error))));
|
|
77
76
|
}
|
|
78
77
|
static get is() { return "tl-promo-code"; }
|
|
79
78
|
static get encapsulation() { return "shadow"; }
|
|
@@ -133,10 +132,7 @@ export class TlPromoCode {
|
|
|
133
132
|
}
|
|
134
133
|
static get states() {
|
|
135
134
|
return {
|
|
136
|
-
"
|
|
137
|
-
"applying": {},
|
|
138
|
-
"applied": {},
|
|
139
|
-
"error": {}
|
|
135
|
+
"view": {}
|
|
140
136
|
};
|
|
141
137
|
}
|
|
142
138
|
static get events() {
|
|
@@ -178,4 +174,13 @@ export class TlPromoCode {
|
|
|
178
174
|
}
|
|
179
175
|
}];
|
|
180
176
|
}
|
|
177
|
+
static get watchers() {
|
|
178
|
+
return [{
|
|
179
|
+
"propName": "placeholder",
|
|
180
|
+
"methodName": "syncProps"
|
|
181
|
+
}, {
|
|
182
|
+
"propName": "buttonLabel",
|
|
183
|
+
"methodName": "syncProps"
|
|
184
|
+
}];
|
|
185
|
+
}
|
|
181
186
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
:host {
|
|
6
6
|
display: block;
|
|
7
|
-
font-family: var(--tl-font-family
|
|
7
|
+
font-family: var(--tl-font-family);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
.seat-map-container {
|
|
11
11
|
position: relative;
|
|
12
12
|
overflow: hidden;
|
|
13
|
-
border-radius: var(--tl-radius-md
|
|
14
|
-
background: var(--tl-color-background
|
|
13
|
+
border-radius: var(--tl-radius-md);
|
|
14
|
+
background: var(--tl-color-background);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.seat-map-iframe {
|
|
@@ -32,22 +32,22 @@
|
|
|
32
32
|
flex-direction: column;
|
|
33
33
|
align-items: center;
|
|
34
34
|
justify-content: center;
|
|
35
|
-
background: var(--tl-color-background
|
|
36
|
-
color: var(--tl-color-foreground
|
|
35
|
+
background: var(--tl-color-background);
|
|
36
|
+
color: var(--tl-color-foreground);
|
|
37
37
|
gap: 1rem;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
.loading p {
|
|
41
41
|
margin: 0;
|
|
42
42
|
font-size: 0.875rem;
|
|
43
|
-
color: var(--tl-color-muted-foreground
|
|
43
|
+
color: var(--tl-color-muted-foreground);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
.spinner {
|
|
47
47
|
width: 40px;
|
|
48
48
|
height: 40px;
|
|
49
|
-
border: 3px solid var(--tl-color-border
|
|
50
|
-
border-top-color: var(--tl-color-primary
|
|
49
|
+
border: 3px solid var(--tl-color-border);
|
|
50
|
+
border-top-color: var(--tl-color-primary);
|
|
51
51
|
border-radius: 50%;
|
|
52
52
|
animation: tl-seat-map-spin 1s linear infinite;
|
|
53
53
|
}
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
flex-direction: column;
|
|
67
67
|
align-items: center;
|
|
68
68
|
justify-content: center;
|
|
69
|
-
background: var(--tl-color-background
|
|
70
|
-
color: var(--tl-color-error
|
|
69
|
+
background: var(--tl-color-background);
|
|
70
|
+
color: var(--tl-color-error);
|
|
71
71
|
padding: 1.5rem;
|
|
72
72
|
text-align: center;
|
|
73
73
|
}
|
|
@@ -132,10 +132,10 @@ export class TlSeatMap {
|
|
|
132
132
|
// Render
|
|
133
133
|
// -------------------------------------------------------------------------
|
|
134
134
|
render() {
|
|
135
|
-
return (h("div", { key: '
|
|
135
|
+
return (h("div", { key: '1c6a23b0aa021c58fa62c106a92a2e970ca7f6d1', class: "seat-map-container", style: {
|
|
136
136
|
width: this.width,
|
|
137
137
|
height: this.height,
|
|
138
|
-
} }, this.isLoading && (h("div", { key: '
|
|
138
|
+
} }, this.isLoading && (h("div", { key: '4a09ddbdbd38eb68675bb320cf33fd3ead5974a4', class: "loading" }, h("div", { key: 'c622ba1f996427f0624cfda2c782abd49ec72e19', class: "spinner" }), h("p", { key: '802f42554fc238a1ddc0f8a0f6a6b0de89bdfb60' }, "Loading seat map..."))), this.error && (h("div", { key: 'dde73e2430bad68c0a67306c0aa2b44810007cc5', class: "error" }, h("p", { key: '392d51bbc47ab34eab5670aa7a2faf800dabe638', class: "error-title" }, "Error"), h("p", { key: 'fcf6810f767f34bf3490c1af21320d262bdb961b', class: "error-message" }, this.error))), h("iframe", { key: '2333206fa6eb4fe6cdcbb1d30864d56d54583e1f', ref: (el) => (this.iframeRef = el), src: this.getIframeSrc(), class: {
|
|
139
139
|
'seat-map-iframe': true,
|
|
140
140
|
hidden: this.isLoading || !!this.error,
|
|
141
141
|
}, title: "Ticketlayer Seat Map", allow: "fullscreen" })));
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
:host {
|
|
2
2
|
display: block;
|
|
3
|
-
font-family: var(--tl-font-family
|
|
3
|
+
font-family: var(--tl-font-family);
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
.ticket {
|
|
7
|
-
border: 1px solid var(--tl-border
|
|
8
|
-
border-radius: var(--tl-radius-lg
|
|
9
|
-
background: var(--tl-card
|
|
10
|
-
padding: var(--tl-spacing-5
|
|
7
|
+
border: 1px solid var(--tl-border);
|
|
8
|
+
border-radius: var(--tl-radius-lg);
|
|
9
|
+
background: var(--tl-card);
|
|
10
|
+
padding: var(--tl-spacing-5);
|
|
11
11
|
text-align: center;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
left: 50%;
|
|
40
40
|
transform: translate(-50%, -50%);
|
|
41
41
|
padding: 0.25rem 0.5rem;
|
|
42
|
-
border-radius: var(--tl-radius-sm
|
|
42
|
+
border-radius: var(--tl-radius-sm);
|
|
43
43
|
background: rgba(17, 24, 39, 0.85);
|
|
44
44
|
color: #ffffff;
|
|
45
45
|
font-size: 0.7rem;
|
|
@@ -51,37 +51,37 @@
|
|
|
51
51
|
.name {
|
|
52
52
|
margin: 1rem 0 0;
|
|
53
53
|
font-weight: 600;
|
|
54
|
-
color: var(--tl-foreground
|
|
54
|
+
color: var(--tl-foreground);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
.meta {
|
|
58
58
|
margin: 0.125rem 0 0;
|
|
59
59
|
font-size: 0.875rem;
|
|
60
|
-
color: var(--tl-muted-foreground
|
|
60
|
+
color: var(--tl-muted-foreground);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
.barcode {
|
|
64
64
|
margin: 0.25rem 0 0;
|
|
65
65
|
font-family: ui-monospace, monospace;
|
|
66
66
|
font-size: 0.625rem;
|
|
67
|
-
color: var(--tl-muted-foreground
|
|
67
|
+
color: var(--tl-muted-foreground);
|
|
68
68
|
word-break: break-all;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
.download {
|
|
72
72
|
margin-top: 0.75rem;
|
|
73
73
|
padding: 0.375rem 0.75rem;
|
|
74
|
-
border: 1px solid var(--tl-border
|
|
75
|
-
border-radius: var(--tl-radius-md
|
|
74
|
+
border: 1px solid var(--tl-border);
|
|
75
|
+
border-radius: var(--tl-radius-md);
|
|
76
76
|
background: transparent;
|
|
77
|
-
color: var(--tl-foreground
|
|
77
|
+
color: var(--tl-foreground);
|
|
78
78
|
font-size: 0.875rem;
|
|
79
79
|
font-weight: 500;
|
|
80
80
|
cursor: pointer;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
.download:hover {
|
|
84
|
-
background: var(--tl-muted
|
|
84
|
+
background: var(--tl-muted);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
.download:disabled {
|