@ticketlayer/elements 0.4.0 → 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/dist/cjs/{index-I9CoYv3k.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 +3 -3
- package/dist/cjs/tl-buy-tickets-button.cjs.entry.js +89 -74
- package/dist/cjs/tl-buy-tickets-wrapper.cjs.entry.js +61 -30
- package/dist/cjs/tl-cart-badge.cjs.entry.js +74 -61
- package/dist/cjs/tl-cart-drawer.cjs.entry.js +51 -23
- package/dist/cjs/tl-cart.cjs.entry.js +71 -103
- package/dist/cjs/tl-checkout-wrapper.cjs.entry.js +51 -29
- package/dist/cjs/tl-event-card.cjs.entry.js +43 -105
- package/dist/cjs/tl-event-list.cjs.entry.js +72 -35
- package/dist/cjs/tl-login.cjs.entry.js +74 -141
- package/dist/cjs/tl-my-orders.cjs.entry.js +52 -92
- package/dist/cjs/tl-occurrence-selector_2.cjs.entry.js +153 -921
- package/dist/cjs/tl-order-confirmation.cjs.entry.js +71 -107
- package/dist/cjs/tl-order-tickets_2.cjs.entry.js +48 -74
- package/dist/cjs/tl-promo-code.cjs.entry.js +50 -47
- package/dist/cjs/tl-seat-map.cjs.entry.js +3 -3
- package/dist/cjs/web-query-Ce73jB4k.js +16 -0
- 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 +37 -0
- package/dist/collection/components/tl-buy-tickets-button/tl-buy-tickets-button.js +105 -79
- package/dist/collection/components/tl-buy-tickets-wrapper/tl-buy-tickets-wrapper.js +73 -30
- package/dist/collection/components/tl-cart/tl-cart.js +82 -107
- package/dist/collection/components/tl-cart-badge/tl-cart-badge.js +62 -62
- package/dist/collection/components/tl-cart-drawer/tl-cart-drawer.js +56 -24
- 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.js +51 -84
- package/dist/collection/components/tl-event-list/tl-event-list.js +82 -38
- package/dist/collection/components/tl-login/tl-login.js +83 -147
- package/dist/collection/components/tl-my-orders/tl-my-orders.js +58 -96
- package/dist/collection/components/tl-occurrence-selector/tl-occurrence-selector.js +137 -516
- package/dist/collection/components/tl-order-confirmation/tl-order-confirmation.js +81 -115
- package/dist/collection/components/tl-order-tickets/tl-order-tickets.js +57 -92
- package/dist/collection/components/tl-promo-code/tl-promo-code.js +55 -50
- package/dist/collection/components/tl-seat-map/tl-seat-map.js +2 -2
- package/dist/collection/components/tl-ticket-selector/tl-ticket-selector.js +34 -20
- package/dist/collection/utils/order-summary.js +15 -135
- 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/web-query.js +1 -0
- package/dist/elements.docs.json +34 -34
- package/dist/esm/{index-OoYV1faY.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 +3 -3
- package/dist/esm/tl-buy-tickets-button.entry.js +90 -75
- package/dist/esm/tl-buy-tickets-wrapper.entry.js +62 -31
- package/dist/esm/tl-cart-badge.entry.js +75 -62
- package/dist/esm/tl-cart-drawer.entry.js +52 -24
- package/dist/esm/tl-cart.entry.js +72 -104
- package/dist/esm/tl-checkout-wrapper.entry.js +52 -30
- package/dist/esm/tl-event-card.entry.js +44 -106
- package/dist/esm/tl-event-list.entry.js +73 -36
- package/dist/esm/tl-login.entry.js +75 -142
- package/dist/esm/tl-my-orders.entry.js +53 -93
- package/dist/esm/tl-occurrence-selector_2.entry.js +152 -920
- package/dist/esm/tl-order-confirmation.entry.js +72 -108
- package/dist/esm/tl-order-tickets_2.entry.js +49 -75
- package/dist/esm/tl-promo-code.entry.js +51 -48
- package/dist/esm/tl-seat-map.entry.js +3 -3
- 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-ac264adc.entry.js → p-5135630e.entry.js} +1 -1
- 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 -42
- 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 +22 -4
- package/dist/types/components.d.ts +270 -62
- package/dist/types/utils/order-summary.d.ts +14 -97
- 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 +602 -50
- package/package.json +8 -6
- package/dist/cjs/money-BtmM2gt-.js +0 -118
- package/dist/cjs/order-summary-X3TlZxc2.js +0 -150
- package/dist/components/money.js +0 -1
- package/dist/components/order-summary.js +0 -1
- package/dist/esm/money-4ig0-WB6.js +0 -112
- package/dist/esm/order-summary-DiDtvfZM.js +0 -136
- package/dist/ticketlayer-elements/p-0814420f.entry.js +0 -1
- package/dist/ticketlayer-elements/p-0acabc26.entry.js +0 -1
- package/dist/ticketlayer-elements/p-109a3feb.entry.js +0 -1
- package/dist/ticketlayer-elements/p-1a4ba71c.entry.js +0 -1
- package/dist/ticketlayer-elements/p-318965c1.entry.js +0 -1
- package/dist/ticketlayer-elements/p-347c7fd1.entry.js +0 -1
- package/dist/ticketlayer-elements/p-3649c26d.entry.js +0 -1
- package/dist/ticketlayer-elements/p-40260cc9.entry.js +0 -1
- package/dist/ticketlayer-elements/p-4ig0-WB6.js +0 -1
- package/dist/ticketlayer-elements/p-55fd2f9f.entry.js +0 -1
- package/dist/ticketlayer-elements/p-62ee659b.entry.js +0 -1
- package/dist/ticketlayer-elements/p-7d4ecc2b.entry.js +0 -1
- package/dist/ticketlayer-elements/p-7f0abf95.entry.js +0 -1
- package/dist/ticketlayer-elements/p-BXpVGW51.js +0 -1
- package/dist/ticketlayer-elements/p-OoYV1faY.js +0 -3
- package/dist/ticketlayer-elements/p-a3c1b26c.entry.js +0 -1
- package/dist/ticketlayer-elements/p-aeb4c6fb.entry.js +0 -1
- package/dist/ticketlayer-elements/p-ba62541f.entry.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ticketlayer/elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Ticketlayer UI components built with Stencil.js",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"qrcode": "^1.5.4",
|
|
45
|
-
"@ticketlayer/elements-core": "^0.
|
|
45
|
+
"@ticketlayer/elements-core": "^0.2.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@ticketlayer/live": ">=
|
|
48
|
+
"@ticketlayer/live": ">=1.0.0"
|
|
49
49
|
},
|
|
50
50
|
"peerDependenciesMeta": {
|
|
51
51
|
"@ticketlayer/live": {
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
"react-dom": "^18.3.1",
|
|
77
77
|
"storybook": "^10.1.11",
|
|
78
78
|
"typescript": "^5.3.3",
|
|
79
|
-
"@ticketlayer/live": "^0.
|
|
80
|
-
"@ticketlayer/theme": "^0.
|
|
79
|
+
"@ticketlayer/live": "^1.0.0",
|
|
80
|
+
"@ticketlayer/theme": "^0.2.0"
|
|
81
81
|
},
|
|
82
82
|
"scripts": {
|
|
83
83
|
"build": "node scripts/write-global-css.mjs && stencil build && node scripts/patch-react-generated.js",
|
|
@@ -93,8 +93,10 @@
|
|
|
93
93
|
"build-storybook": "storybook build",
|
|
94
94
|
"build:catalogue": "node scripts/build-catalogue.mjs",
|
|
95
95
|
"build:catalogue:version": "node scripts/build-catalogue.mjs --version-only",
|
|
96
|
+
"build:stories": "node scripts/build-stories.mjs",
|
|
96
97
|
"test:catalogue": "node scripts/build-catalogue.mjs --check",
|
|
98
|
+
"test:stories": "node scripts/build-stories.mjs --check",
|
|
97
99
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
98
|
-
"lint": "node scripts/write-global-css.mjs --check && node scripts/check-token-usage.mjs && node scripts/check-core-tokens.mjs"
|
|
100
|
+
"lint": "node scripts/write-global-css.mjs --check && node scripts/check-token-usage.mjs && node scripts/check-core-tokens.mjs && node scripts/build-stories.mjs --check"
|
|
99
101
|
}
|
|
100
102
|
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The money rows a cart-shaped view renders: subtotal, the booking fee, a
|
|
5
|
-
* discount and the total.
|
|
6
|
-
*
|
|
7
|
-
* Pure: no Stencil, no DOM, no SDK. A core derives these figures and a harness
|
|
8
|
-
* renders what it returns, so the rule for what is shown can be unit tested on
|
|
9
|
-
* its own (the platform plan's headless-core split, AGENTS.md). It lived in
|
|
10
|
-
* `packages/elements/src/utils/cart-totals.ts` until the core split (TKT-68)
|
|
11
|
-
* and is re-exported from there, so every existing import still resolves.
|
|
12
|
-
*
|
|
13
|
-
* The client (`@ticketlayer/live`) already derives these figures from the
|
|
14
|
-
* sales-surface response and publishes `subtotal`, `fees`, `discount`,
|
|
15
|
-
* `total`, `hasFees` and `feeLabel` on the cart it hands us. Cores never
|
|
16
|
-
* import the client, so the same rule is stated here for the case where a
|
|
17
|
-
* host binds an older connector, or a bare sales cart: read what is there,
|
|
18
|
-
* and never invent money that is not.
|
|
19
|
-
*
|
|
20
|
-
* Money is integer minor units (2500 = 25.00) everywhere on this platform.
|
|
21
|
-
* Nothing here divides or multiplies money; the only division is the one
|
|
22
|
-
* `formatPrice` does to render it.
|
|
23
|
-
*/
|
|
24
|
-
/** Shown when the response names no fee of its own. */
|
|
25
|
-
const FEE_LABEL_FALLBACK = 'Booking fee';
|
|
26
|
-
/**
|
|
27
|
-
* Minor units, or null when the value is not minor units. Integers and
|
|
28
|
-
* all-digit strings only: a decimal is not minor units, and treating it as
|
|
29
|
-
* money here would put floating point into a total.
|
|
30
|
-
*/
|
|
31
|
-
function minorUnits(value) {
|
|
32
|
-
if (typeof value === 'number')
|
|
33
|
-
return Number.isInteger(value) ? value : null;
|
|
34
|
-
if (typeof value === 'string' && /^-?\d+$/.test(value))
|
|
35
|
-
return Number(value);
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* THE RULE: a fee of zero is not the same as no fee.
|
|
40
|
-
*
|
|
41
|
-
* Render the fee row when the response EXPRESSES a fee - an amount above
|
|
42
|
-
* zero, or a fee the surface has NAMED (a `type: 'fee'` line or a fee label)
|
|
43
|
-
* even where it computes to zero. A response with no fee figure at all, or a
|
|
44
|
-
* bare zero nothing names, expresses no fee: a channel with no fee profile
|
|
45
|
-
* renders no row, and we never show a "Booking fee 0.00" the surface did not
|
|
46
|
-
* put there.
|
|
47
|
-
*/
|
|
48
|
-
function expressesFee(fees, named) {
|
|
49
|
-
if (fees === null)
|
|
50
|
-
return named;
|
|
51
|
-
return fees > 0 || named;
|
|
52
|
-
}
|
|
53
|
-
const lineType = (line) => line.type || 'ticket';
|
|
54
|
-
function cartTotals(cart) {
|
|
55
|
-
const c = cart || {};
|
|
56
|
-
const lines = Array.isArray(c.items) ? c.items : [];
|
|
57
|
-
const feeLines = lines.filter((l) => lineType(l) === 'fee');
|
|
58
|
-
const discountLines = lines.filter((l) => lineType(l) === 'discount');
|
|
59
|
-
const subtotal = minorUnits(c.itemsSubtotal) ??
|
|
60
|
-
minorUnits(c.subtotal) ??
|
|
61
|
-
lines
|
|
62
|
-
.filter((l) => !['fee', 'tax', 'discount'].includes(lineType(l)))
|
|
63
|
-
.reduce((sum, l) => sum + (minorUnits(l.subtotal) ?? 0), 0);
|
|
64
|
-
const feeFromLines = feeLines.length
|
|
65
|
-
? feeLines.reduce((sum, l) => sum + (minorUnits(l.subtotal) ?? 0), 0)
|
|
66
|
-
: null;
|
|
67
|
-
const fees = minorUnits(c.totalFees) ?? minorUnits(c.fees) ?? feeFromLines;
|
|
68
|
-
const discountFromLines = discountLines.length
|
|
69
|
-
? discountLines.reduce((sum, l) => sum + Math.abs(minorUnits(l.subtotal) ?? 0), 0)
|
|
70
|
-
: null;
|
|
71
|
-
const discount = minorUnits(c.totalDiscounts) ?? minorUnits(c.discount) ?? discountFromLines;
|
|
72
|
-
const tax = minorUnits(c.totalTax) ?? 0;
|
|
73
|
-
const named = (typeof c.feeLabel === 'string' && !!c.feeLabel) ||
|
|
74
|
-
feeLines.some((l) => typeof l.name === 'string' && !!l.name);
|
|
75
|
-
const label = (typeof c.feeLabel === 'string' && c.feeLabel) ||
|
|
76
|
-
feeLines.map((l) => l.name).find((n) => typeof n === 'string' && !!n) ||
|
|
77
|
-
FEE_LABEL_FALLBACK;
|
|
78
|
-
return {
|
|
79
|
-
currency: c.currency || 'GBP',
|
|
80
|
-
subtotal,
|
|
81
|
-
fees: fees ?? 0,
|
|
82
|
-
discount: discount ?? 0,
|
|
83
|
-
// The server's total is what the buyer is charged, so it wins over any sum
|
|
84
|
-
// we could do here. We only add up when the response carries no total.
|
|
85
|
-
total: minorUnits(c.total) ?? subtotal + (fees ?? 0) + tax - (discount ?? 0),
|
|
86
|
-
// The client already applied the rule; honour its answer when it sent one.
|
|
87
|
-
showFee: typeof c.hasFees === 'boolean' ? c.hasFees : expressesFee(fees, named),
|
|
88
|
-
feeLabel: label,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* The totals for a selection that is not yet a cart (tl-ticket-selector).
|
|
93
|
-
*
|
|
94
|
-
* The buyer-facing surface quotes no fee before the cart exists - there is no
|
|
95
|
-
* quote or preview operation, and the channel's fee profile is not exposed to
|
|
96
|
-
* a publishable key - so `quote` is null on every call today and no fee row is
|
|
97
|
-
* rendered. It is a parameter rather than an assumption so that the row lights
|
|
98
|
-
* up from data the moment the surface quotes one, and so the rule stays
|
|
99
|
-
* testable now.
|
|
100
|
-
*/
|
|
101
|
-
function selectionTotals(lines, quote = null) {
|
|
102
|
-
const subtotal = (lines || []).reduce((sum, l) => sum + (minorUnits(l.price) ?? 0) * (Math.max(0, Math.trunc(l.quantity || 0)) || 0), 0);
|
|
103
|
-
const fees = quote ? minorUnits(quote.amount) : null;
|
|
104
|
-
const named = !!quote?.label;
|
|
105
|
-
return {
|
|
106
|
-
subtotal,
|
|
107
|
-
fees: fees ?? 0,
|
|
108
|
-
total: subtotal + (fees ?? 0),
|
|
109
|
-
showFee: quote ? expressesFee(fees, named) : false,
|
|
110
|
-
feeLabel: quote?.label || FEE_LABEL_FALLBACK,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
exports.FEE_LABEL_FALLBACK = FEE_LABEL_FALLBACK;
|
|
115
|
-
exports.cartTotals = cartTotals;
|
|
116
|
-
exports.expressesFee = expressesFee;
|
|
117
|
-
exports.minorUnits = minorUnits;
|
|
118
|
-
exports.selectionTotals = selectionTotals;
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var money = require('./money-BtmM2gt-.js');
|
|
4
|
-
|
|
5
|
-
/** Money arrives as minor-unit integers or decimal strings ("50.00"). */
|
|
6
|
-
function formatPrice(value, currency = 'GBP') {
|
|
7
|
-
if (value === null || value === undefined || value === '')
|
|
8
|
-
return '';
|
|
9
|
-
const fmt = new Intl.NumberFormat('en-GB', { style: 'currency', currency });
|
|
10
|
-
if (typeof value === 'number')
|
|
11
|
-
return fmt.format(value / 100);
|
|
12
|
-
const n = Number(value);
|
|
13
|
-
return Number.isNaN(n) ? String(value) : fmt.format(n);
|
|
14
|
-
}
|
|
15
|
-
function formatDateTime(iso) {
|
|
16
|
-
return new Date(iso).toLocaleDateString('en-GB', {
|
|
17
|
-
weekday: 'short',
|
|
18
|
-
day: 'numeric',
|
|
19
|
-
month: 'short',
|
|
20
|
-
year: 'numeric',
|
|
21
|
-
hour: '2-digit',
|
|
22
|
-
minute: '2-digit',
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
function formatDate(iso) {
|
|
26
|
-
return new Date(iso).toLocaleDateString('en-GB', {
|
|
27
|
-
day: 'numeric',
|
|
28
|
-
month: 'short',
|
|
29
|
-
year: 'numeric',
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
/** Line items that are tickets (fees, taxes and discounts have their own type). */
|
|
33
|
-
function ticketItems(order) {
|
|
34
|
-
return (order.items ?? []).filter((i) => !i.type || i.type === 'ticket');
|
|
35
|
-
}
|
|
36
|
-
function ticketCount(order) {
|
|
37
|
-
const fromItems = ticketItems(order).reduce((sum, i) => sum + (Number(i.quantity) || 0), 0);
|
|
38
|
-
return fromItems || order.tickets?.length || 0;
|
|
39
|
-
}
|
|
40
|
-
/** Event name as the order view exposes it: the first ticket line's name. */
|
|
41
|
-
function orderEventName(order) {
|
|
42
|
-
return order.eventName || ticketItems(order)[0]?.name || order.items?.[0]?.name || null;
|
|
43
|
-
}
|
|
44
|
-
function orderCustomerEmail(order, customer) {
|
|
45
|
-
const fromOrder = order?.customerEmail || order?.customer?.email;
|
|
46
|
-
if (fromOrder)
|
|
47
|
-
return fromOrder;
|
|
48
|
-
const c = customer;
|
|
49
|
-
return c?.email || null;
|
|
50
|
-
}
|
|
51
|
-
function statusLabel(status) {
|
|
52
|
-
if (!status)
|
|
53
|
-
return '';
|
|
54
|
-
return status.replace(/_/g, ' ').replace(/^\w/, (m) => m.toUpperCase());
|
|
55
|
-
}
|
|
56
|
-
function statusTone(status) {
|
|
57
|
-
switch (status) {
|
|
58
|
-
case 'confirmed':
|
|
59
|
-
return 'success';
|
|
60
|
-
case 'completed':
|
|
61
|
-
case 'fulfilled':
|
|
62
|
-
return 'info';
|
|
63
|
-
case 'pending':
|
|
64
|
-
case 'processing':
|
|
65
|
-
return 'warning';
|
|
66
|
-
case 'cancelled':
|
|
67
|
-
case 'expired':
|
|
68
|
-
case 'failed':
|
|
69
|
-
return 'error';
|
|
70
|
-
default:
|
|
71
|
-
return 'muted';
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function errorMessage(err, fallback) {
|
|
75
|
-
return err instanceof Error && err.message ? err.message : fallback;
|
|
76
|
-
}
|
|
77
|
-
/** True for the "not signed in" family of API errors (401/403, NO_SESSION, NOT_AUTHENTICATED). */
|
|
78
|
-
function isAuthError(err) {
|
|
79
|
-
const e = err;
|
|
80
|
-
if (!e || typeof e !== 'object')
|
|
81
|
-
return false;
|
|
82
|
-
return e.status === 401 || e.status === 403 || e.code === 'NO_SESSION' || e.code === 'NOT_AUTHENTICATED';
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Find the event and start time for an occurrence id. The order view only
|
|
86
|
-
* carries the occurrence id, so this walks the channel's listings (cached by
|
|
87
|
-
* live-api) until one owns the occurrence. Best effort: null when not found.
|
|
88
|
-
*/
|
|
89
|
-
async function resolveOccurrence(sdk, occurrenceId, maxEvents = 12) {
|
|
90
|
-
const events = sdk.getEventsManager();
|
|
91
|
-
const listing = await events.list({ limit: maxEvents });
|
|
92
|
-
const candidates = listing.items.slice(0, maxEvents);
|
|
93
|
-
for (const candidate of candidates) {
|
|
94
|
-
const detail = (await events.get(candidate.id).catch(() => null));
|
|
95
|
-
const occ = detail?.occurrences?.find((o) => o.id === occurrenceId);
|
|
96
|
-
if (occ) {
|
|
97
|
-
return {
|
|
98
|
-
eventId: detail?.id ?? candidate.id,
|
|
99
|
-
eventName: detail?.name ?? candidate.name ?? '',
|
|
100
|
-
startsAt: occ.startsAt ?? null,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
function orderTotals(order) {
|
|
107
|
-
const o = order || {};
|
|
108
|
-
const items = Array.isArray(o.items) ? o.items : [];
|
|
109
|
-
const feeLines = items.filter((i) => i.type === 'fee');
|
|
110
|
-
const discountLines = items.filter((i) => i.type === 'discount');
|
|
111
|
-
const tickets = ticketItems(o);
|
|
112
|
-
const feeFromLines = feeLines.length
|
|
113
|
-
? feeLines.reduce((sum, i) => sum + (money.minorUnits(i.subtotal) ?? 0), 0)
|
|
114
|
-
: null;
|
|
115
|
-
const fees = feeFromLines ?? money.minorUnits(o.totalFees) ?? 0;
|
|
116
|
-
const declaredSubtotal = money.minorUnits(o.subtotal);
|
|
117
|
-
const subtotal = tickets.length
|
|
118
|
-
? tickets.reduce((sum, i) => sum + (money.minorUnits(i.subtotal) ?? 0), 0)
|
|
119
|
-
: (declaredSubtotal ?? 0) - fees;
|
|
120
|
-
const discountFromLines = discountLines.length
|
|
121
|
-
? discountLines.reduce((sum, i) => sum + Math.abs(money.minorUnits(i.subtotal) ?? 0), 0)
|
|
122
|
-
: null;
|
|
123
|
-
const discount = money.minorUnits(o.totalDiscounts) ?? discountFromLines ?? 0;
|
|
124
|
-
const tax = money.minorUnits(o.totalTax) ?? 0;
|
|
125
|
-
const named = feeLines.some((i) => typeof i.name === 'string' && !!i.name);
|
|
126
|
-
return {
|
|
127
|
-
currency: o.currency || 'GBP',
|
|
128
|
-
subtotal,
|
|
129
|
-
fees,
|
|
130
|
-
feeLabel: feeLines.map((i) => i.name).find((n) => !!n) || money.FEE_LABEL_FALLBACK,
|
|
131
|
-
showFee: money.expressesFee(feeFromLines ?? money.minorUnits(o.totalFees), named),
|
|
132
|
-
tax,
|
|
133
|
-
discount,
|
|
134
|
-
total: money.minorUnits(o.total) ?? subtotal + fees + tax - discount,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
exports.errorMessage = errorMessage;
|
|
139
|
-
exports.formatDate = formatDate;
|
|
140
|
-
exports.formatDateTime = formatDateTime;
|
|
141
|
-
exports.formatPrice = formatPrice;
|
|
142
|
-
exports.isAuthError = isAuthError;
|
|
143
|
-
exports.orderCustomerEmail = orderCustomerEmail;
|
|
144
|
-
exports.orderEventName = orderEventName;
|
|
145
|
-
exports.orderTotals = orderTotals;
|
|
146
|
-
exports.resolveOccurrence = resolveOccurrence;
|
|
147
|
-
exports.statusLabel = statusLabel;
|
|
148
|
-
exports.statusTone = statusTone;
|
|
149
|
-
exports.ticketCount = ticketCount;
|
|
150
|
-
exports.ticketItems = ticketItems;
|
package/dist/components/money.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const t="Booking fee";function e(t){return"number"==typeof t?Number.isInteger(t)?t:null:"string"==typeof t&&/^-?\d+$/.test(t)?Number(t):null}function n(t,e){return null===t?e:t>0||e}const o=t=>t.type||"ticket";function s(s){const u=s||{},l=Array.isArray(u.items)?u.items:[],r=l.filter((t=>"fee"===o(t))),f=l.filter((t=>"discount"===o(t))),a=e(u.itemsSubtotal)??e(u.subtotal)??l.filter((t=>!["fee","tax","discount"].includes(o(t)))).reduce(((t,n)=>t+(e(n.subtotal)??0)),0),c=r.length?r.reduce(((t,n)=>t+(e(n.subtotal)??0)),0):null,i=e(u.totalFees)??e(u.fees)??c,y=f.length?f.reduce(((t,n)=>t+Math.abs(e(n.subtotal)??0)),0):null,b=e(u.totalDiscounts)??e(u.discount)??y,p=e(u.totalTax)??0,g="string"==typeof u.feeLabel&&!!u.feeLabel||r.some((t=>"string"==typeof t.name&&!!t.name)),h="string"==typeof u.feeLabel&&u.feeLabel||r.map((t=>t.name)).find((t=>"string"==typeof t&&!!t))||t;return{currency:u.currency||"GBP",subtotal:a,fees:i??0,discount:b??0,total:e(u.total)??a+(i??0)+p-(b??0),showFee:"boolean"==typeof u.hasFees?u.hasFees:n(i,g),feeLabel:h}}function u(o,s=null){const u=(o||[]).reduce(((t,n)=>t+(e(n.price)??0)*(Math.max(0,Math.trunc(n.quantity||0))||0)),0),l=s?e(s.amount):null;return{subtotal:u,fees:l??0,total:u+(l??0),showFee:!!s&&n(l,!!s?.label),feeLabel:s?.label||t}}export{t as F,s as c,n as e,e as m,u as s}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{m as n,e,F as t}from"./money.js";function r(n,e="GBP"){if(null==n||""===n)return"";const t=new Intl.NumberFormat("en-GB",{style:"currency",currency:e});if("number"==typeof n)return t.format(n/100);const r=Number(n);return Number.isNaN(r)?String(n):t.format(r)}function u(n){return new Date(n).toLocaleDateString("en-GB",{weekday:"short",day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"})}function c(n){return new Date(n).toLocaleDateString("en-GB",{day:"numeric",month:"short",year:"numeric"})}function s(n){return(n.items??[]).filter((n=>!n.type||"ticket"===n.type))}function a(n){return s(n).reduce(((n,e)=>n+(Number(e.quantity)||0)),0)||n.tickets?.length||0}function o(n){return n.eventName||s(n)[0]?.name||n.items?.[0]?.name||null}function i(n,e){const t=n?.customerEmail||n?.customer?.email;if(t)return t;const r=e;return r?.email||null}function f(n){return n?n.replace(/_/g," ").replace(/^\w/,(n=>n.toUpperCase())):""}function l(n){switch(n){case"confirmed":return"success";case"completed":case"fulfilled":return"info";case"pending":case"processing":return"warning";case"cancelled":case"expired":case"failed":return"error";default:return"muted"}}function m(n,e){return n instanceof Error&&n.message?n.message:e}function d(n){return!(!n||"object"!=typeof n||401!==n.status&&403!==n.status&&"NO_SESSION"!==n.code&&"NOT_AUTHENTICATED"!==n.code)}async function y(n,e,t=12){const r=n.getEventsManager(),u=(await r.list({limit:t})).items.slice(0,t);for(const n of u){const t=await r.get(n.id).catch((()=>null)),u=t?.occurrences?.find((n=>n.id===e));if(u)return{eventId:t?.id??n.id,eventName:t?.name??n.name??"",startsAt:u.startsAt??null}}return null}function h(r){const u=r||{},c=Array.isArray(u.items)?u.items:[],a=c.filter((n=>"fee"===n.type)),o=c.filter((n=>"discount"===n.type)),i=s(u),f=a.length?a.reduce(((e,t)=>e+(n(t.subtotal)??0)),0):null,l=f??n(u.totalFees)??0,m=n(u.subtotal),d=i.length?i.reduce(((e,t)=>e+(n(t.subtotal)??0)),0):(m??0)-l,y=o.length?o.reduce(((e,t)=>e+Math.abs(n(t.subtotal)??0)),0):null,h=n(u.totalDiscounts)??y??0,w=n(u.totalTax)??0,g=a.some((n=>"string"==typeof n.name&&!!n.name));return{currency:u.currency||"GBP",subtotal:d,fees:l,feeLabel:a.map((n=>n.name)).find((n=>!!n))||t,showFee:e(f??n(u.totalFees),g),tax:w,discount:h,total:n(u.total)??d+l+w-h}}export{r as a,f as b,i as c,u as d,m as e,c as f,h as g,s as h,d as i,o,y as r,l as s,a as t}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The money rows a cart-shaped view renders: subtotal, the booking fee, a
|
|
3
|
-
* discount and the total.
|
|
4
|
-
*
|
|
5
|
-
* Pure: no Stencil, no DOM, no SDK. A core derives these figures and a harness
|
|
6
|
-
* renders what it returns, so the rule for what is shown can be unit tested on
|
|
7
|
-
* its own (the platform plan's headless-core split, AGENTS.md). It lived in
|
|
8
|
-
* `packages/elements/src/utils/cart-totals.ts` until the core split (TKT-68)
|
|
9
|
-
* and is re-exported from there, so every existing import still resolves.
|
|
10
|
-
*
|
|
11
|
-
* The client (`@ticketlayer/live`) already derives these figures from the
|
|
12
|
-
* sales-surface response and publishes `subtotal`, `fees`, `discount`,
|
|
13
|
-
* `total`, `hasFees` and `feeLabel` on the cart it hands us. Cores never
|
|
14
|
-
* import the client, so the same rule is stated here for the case where a
|
|
15
|
-
* host binds an older connector, or a bare sales cart: read what is there,
|
|
16
|
-
* and never invent money that is not.
|
|
17
|
-
*
|
|
18
|
-
* Money is integer minor units (2500 = 25.00) everywhere on this platform.
|
|
19
|
-
* Nothing here divides or multiplies money; the only division is the one
|
|
20
|
-
* `formatPrice` does to render it.
|
|
21
|
-
*/
|
|
22
|
-
/** Shown when the response names no fee of its own. */
|
|
23
|
-
const FEE_LABEL_FALLBACK = 'Booking fee';
|
|
24
|
-
/**
|
|
25
|
-
* Minor units, or null when the value is not minor units. Integers and
|
|
26
|
-
* all-digit strings only: a decimal is not minor units, and treating it as
|
|
27
|
-
* money here would put floating point into a total.
|
|
28
|
-
*/
|
|
29
|
-
function minorUnits(value) {
|
|
30
|
-
if (typeof value === 'number')
|
|
31
|
-
return Number.isInteger(value) ? value : null;
|
|
32
|
-
if (typeof value === 'string' && /^-?\d+$/.test(value))
|
|
33
|
-
return Number(value);
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* THE RULE: a fee of zero is not the same as no fee.
|
|
38
|
-
*
|
|
39
|
-
* Render the fee row when the response EXPRESSES a fee - an amount above
|
|
40
|
-
* zero, or a fee the surface has NAMED (a `type: 'fee'` line or a fee label)
|
|
41
|
-
* even where it computes to zero. A response with no fee figure at all, or a
|
|
42
|
-
* bare zero nothing names, expresses no fee: a channel with no fee profile
|
|
43
|
-
* renders no row, and we never show a "Booking fee 0.00" the surface did not
|
|
44
|
-
* put there.
|
|
45
|
-
*/
|
|
46
|
-
function expressesFee(fees, named) {
|
|
47
|
-
if (fees === null)
|
|
48
|
-
return named;
|
|
49
|
-
return fees > 0 || named;
|
|
50
|
-
}
|
|
51
|
-
const lineType = (line) => line.type || 'ticket';
|
|
52
|
-
function cartTotals(cart) {
|
|
53
|
-
const c = cart || {};
|
|
54
|
-
const lines = Array.isArray(c.items) ? c.items : [];
|
|
55
|
-
const feeLines = lines.filter((l) => lineType(l) === 'fee');
|
|
56
|
-
const discountLines = lines.filter((l) => lineType(l) === 'discount');
|
|
57
|
-
const subtotal = minorUnits(c.itemsSubtotal) ??
|
|
58
|
-
minorUnits(c.subtotal) ??
|
|
59
|
-
lines
|
|
60
|
-
.filter((l) => !['fee', 'tax', 'discount'].includes(lineType(l)))
|
|
61
|
-
.reduce((sum, l) => sum + (minorUnits(l.subtotal) ?? 0), 0);
|
|
62
|
-
const feeFromLines = feeLines.length
|
|
63
|
-
? feeLines.reduce((sum, l) => sum + (minorUnits(l.subtotal) ?? 0), 0)
|
|
64
|
-
: null;
|
|
65
|
-
const fees = minorUnits(c.totalFees) ?? minorUnits(c.fees) ?? feeFromLines;
|
|
66
|
-
const discountFromLines = discountLines.length
|
|
67
|
-
? discountLines.reduce((sum, l) => sum + Math.abs(minorUnits(l.subtotal) ?? 0), 0)
|
|
68
|
-
: null;
|
|
69
|
-
const discount = minorUnits(c.totalDiscounts) ?? minorUnits(c.discount) ?? discountFromLines;
|
|
70
|
-
const tax = minorUnits(c.totalTax) ?? 0;
|
|
71
|
-
const named = (typeof c.feeLabel === 'string' && !!c.feeLabel) ||
|
|
72
|
-
feeLines.some((l) => typeof l.name === 'string' && !!l.name);
|
|
73
|
-
const label = (typeof c.feeLabel === 'string' && c.feeLabel) ||
|
|
74
|
-
feeLines.map((l) => l.name).find((n) => typeof n === 'string' && !!n) ||
|
|
75
|
-
FEE_LABEL_FALLBACK;
|
|
76
|
-
return {
|
|
77
|
-
currency: c.currency || 'GBP',
|
|
78
|
-
subtotal,
|
|
79
|
-
fees: fees ?? 0,
|
|
80
|
-
discount: discount ?? 0,
|
|
81
|
-
// The server's total is what the buyer is charged, so it wins over any sum
|
|
82
|
-
// we could do here. We only add up when the response carries no total.
|
|
83
|
-
total: minorUnits(c.total) ?? subtotal + (fees ?? 0) + tax - (discount ?? 0),
|
|
84
|
-
// The client already applied the rule; honour its answer when it sent one.
|
|
85
|
-
showFee: typeof c.hasFees === 'boolean' ? c.hasFees : expressesFee(fees, named),
|
|
86
|
-
feeLabel: label,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* The totals for a selection that is not yet a cart (tl-ticket-selector).
|
|
91
|
-
*
|
|
92
|
-
* The buyer-facing surface quotes no fee before the cart exists - there is no
|
|
93
|
-
* quote or preview operation, and the channel's fee profile is not exposed to
|
|
94
|
-
* a publishable key - so `quote` is null on every call today and no fee row is
|
|
95
|
-
* rendered. It is a parameter rather than an assumption so that the row lights
|
|
96
|
-
* up from data the moment the surface quotes one, and so the rule stays
|
|
97
|
-
* testable now.
|
|
98
|
-
*/
|
|
99
|
-
function selectionTotals(lines, quote = null) {
|
|
100
|
-
const subtotal = (lines || []).reduce((sum, l) => sum + (minorUnits(l.price) ?? 0) * (Math.max(0, Math.trunc(l.quantity || 0)) || 0), 0);
|
|
101
|
-
const fees = quote ? minorUnits(quote.amount) : null;
|
|
102
|
-
const named = !!quote?.label;
|
|
103
|
-
return {
|
|
104
|
-
subtotal,
|
|
105
|
-
fees: fees ?? 0,
|
|
106
|
-
total: subtotal + (fees ?? 0),
|
|
107
|
-
showFee: quote ? expressesFee(fees, named) : false,
|
|
108
|
-
feeLabel: quote?.label || FEE_LABEL_FALLBACK,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export { FEE_LABEL_FALLBACK as F, cartTotals as c, expressesFee as e, minorUnits as m, selectionTotals as s };
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { m as minorUnits, e as expressesFee, F as FEE_LABEL_FALLBACK } from './money-4ig0-WB6.js';
|
|
2
|
-
|
|
3
|
-
/** Money arrives as minor-unit integers or decimal strings ("50.00"). */
|
|
4
|
-
function formatPrice(value, currency = 'GBP') {
|
|
5
|
-
if (value === null || value === undefined || value === '')
|
|
6
|
-
return '';
|
|
7
|
-
const fmt = new Intl.NumberFormat('en-GB', { style: 'currency', currency });
|
|
8
|
-
if (typeof value === 'number')
|
|
9
|
-
return fmt.format(value / 100);
|
|
10
|
-
const n = Number(value);
|
|
11
|
-
return Number.isNaN(n) ? String(value) : fmt.format(n);
|
|
12
|
-
}
|
|
13
|
-
function formatDateTime(iso) {
|
|
14
|
-
return new Date(iso).toLocaleDateString('en-GB', {
|
|
15
|
-
weekday: 'short',
|
|
16
|
-
day: 'numeric',
|
|
17
|
-
month: 'short',
|
|
18
|
-
year: 'numeric',
|
|
19
|
-
hour: '2-digit',
|
|
20
|
-
minute: '2-digit',
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
function formatDate(iso) {
|
|
24
|
-
return new Date(iso).toLocaleDateString('en-GB', {
|
|
25
|
-
day: 'numeric',
|
|
26
|
-
month: 'short',
|
|
27
|
-
year: 'numeric',
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
/** Line items that are tickets (fees, taxes and discounts have their own type). */
|
|
31
|
-
function ticketItems(order) {
|
|
32
|
-
return (order.items ?? []).filter((i) => !i.type || i.type === 'ticket');
|
|
33
|
-
}
|
|
34
|
-
function ticketCount(order) {
|
|
35
|
-
const fromItems = ticketItems(order).reduce((sum, i) => sum + (Number(i.quantity) || 0), 0);
|
|
36
|
-
return fromItems || order.tickets?.length || 0;
|
|
37
|
-
}
|
|
38
|
-
/** Event name as the order view exposes it: the first ticket line's name. */
|
|
39
|
-
function orderEventName(order) {
|
|
40
|
-
return order.eventName || ticketItems(order)[0]?.name || order.items?.[0]?.name || null;
|
|
41
|
-
}
|
|
42
|
-
function orderCustomerEmail(order, customer) {
|
|
43
|
-
const fromOrder = order?.customerEmail || order?.customer?.email;
|
|
44
|
-
if (fromOrder)
|
|
45
|
-
return fromOrder;
|
|
46
|
-
const c = customer;
|
|
47
|
-
return c?.email || null;
|
|
48
|
-
}
|
|
49
|
-
function statusLabel(status) {
|
|
50
|
-
if (!status)
|
|
51
|
-
return '';
|
|
52
|
-
return status.replace(/_/g, ' ').replace(/^\w/, (m) => m.toUpperCase());
|
|
53
|
-
}
|
|
54
|
-
function statusTone(status) {
|
|
55
|
-
switch (status) {
|
|
56
|
-
case 'confirmed':
|
|
57
|
-
return 'success';
|
|
58
|
-
case 'completed':
|
|
59
|
-
case 'fulfilled':
|
|
60
|
-
return 'info';
|
|
61
|
-
case 'pending':
|
|
62
|
-
case 'processing':
|
|
63
|
-
return 'warning';
|
|
64
|
-
case 'cancelled':
|
|
65
|
-
case 'expired':
|
|
66
|
-
case 'failed':
|
|
67
|
-
return 'error';
|
|
68
|
-
default:
|
|
69
|
-
return 'muted';
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function errorMessage(err, fallback) {
|
|
73
|
-
return err instanceof Error && err.message ? err.message : fallback;
|
|
74
|
-
}
|
|
75
|
-
/** True for the "not signed in" family of API errors (401/403, NO_SESSION, NOT_AUTHENTICATED). */
|
|
76
|
-
function isAuthError(err) {
|
|
77
|
-
const e = err;
|
|
78
|
-
if (!e || typeof e !== 'object')
|
|
79
|
-
return false;
|
|
80
|
-
return e.status === 401 || e.status === 403 || e.code === 'NO_SESSION' || e.code === 'NOT_AUTHENTICATED';
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Find the event and start time for an occurrence id. The order view only
|
|
84
|
-
* carries the occurrence id, so this walks the channel's listings (cached by
|
|
85
|
-
* live-api) until one owns the occurrence. Best effort: null when not found.
|
|
86
|
-
*/
|
|
87
|
-
async function resolveOccurrence(sdk, occurrenceId, maxEvents = 12) {
|
|
88
|
-
const events = sdk.getEventsManager();
|
|
89
|
-
const listing = await events.list({ limit: maxEvents });
|
|
90
|
-
const candidates = listing.items.slice(0, maxEvents);
|
|
91
|
-
for (const candidate of candidates) {
|
|
92
|
-
const detail = (await events.get(candidate.id).catch(() => null));
|
|
93
|
-
const occ = detail?.occurrences?.find((o) => o.id === occurrenceId);
|
|
94
|
-
if (occ) {
|
|
95
|
-
return {
|
|
96
|
-
eventId: detail?.id ?? candidate.id,
|
|
97
|
-
eventName: detail?.name ?? candidate.name ?? '',
|
|
98
|
-
startsAt: occ.startsAt ?? null,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
function orderTotals(order) {
|
|
105
|
-
const o = order || {};
|
|
106
|
-
const items = Array.isArray(o.items) ? o.items : [];
|
|
107
|
-
const feeLines = items.filter((i) => i.type === 'fee');
|
|
108
|
-
const discountLines = items.filter((i) => i.type === 'discount');
|
|
109
|
-
const tickets = ticketItems(o);
|
|
110
|
-
const feeFromLines = feeLines.length
|
|
111
|
-
? feeLines.reduce((sum, i) => sum + (minorUnits(i.subtotal) ?? 0), 0)
|
|
112
|
-
: null;
|
|
113
|
-
const fees = feeFromLines ?? minorUnits(o.totalFees) ?? 0;
|
|
114
|
-
const declaredSubtotal = minorUnits(o.subtotal);
|
|
115
|
-
const subtotal = tickets.length
|
|
116
|
-
? tickets.reduce((sum, i) => sum + (minorUnits(i.subtotal) ?? 0), 0)
|
|
117
|
-
: (declaredSubtotal ?? 0) - fees;
|
|
118
|
-
const discountFromLines = discountLines.length
|
|
119
|
-
? discountLines.reduce((sum, i) => sum + Math.abs(minorUnits(i.subtotal) ?? 0), 0)
|
|
120
|
-
: null;
|
|
121
|
-
const discount = minorUnits(o.totalDiscounts) ?? discountFromLines ?? 0;
|
|
122
|
-
const tax = minorUnits(o.totalTax) ?? 0;
|
|
123
|
-
const named = feeLines.some((i) => typeof i.name === 'string' && !!i.name);
|
|
124
|
-
return {
|
|
125
|
-
currency: o.currency || 'GBP',
|
|
126
|
-
subtotal,
|
|
127
|
-
fees,
|
|
128
|
-
feeLabel: feeLines.map((i) => i.name).find((n) => !!n) || FEE_LABEL_FALLBACK,
|
|
129
|
-
showFee: expressesFee(feeFromLines ?? minorUnits(o.totalFees), named),
|
|
130
|
-
tax,
|
|
131
|
-
discount,
|
|
132
|
-
total: minorUnits(o.total) ?? subtotal + fees + tax - discount,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export { formatPrice as a, statusLabel as b, formatDateTime as c, orderCustomerEmail as d, errorMessage as e, formatDate as f, orderTotals as g, ticketItems as h, isAuthError as i, orderEventName as o, resolveOccurrence as r, statusTone as s, ticketCount as t };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as i,c as t,h as s}from"./p-OoYV1faY.js";import{w as n}from"./p-CqhvfyKV.js";import{e}from"./p-BXpVGW51.js";import"./p-4ig0-WB6.js";const l=class{constructor(s){i(this,s),this.tlAuthChanged=t(this,"tlAuthChanged"),this.tlMagicLinkSent=t(this,"tlMagicLinkSent"),this.tlError=t(this,"tlError"),this.heading="Sign in",this.allowCodeEntry=!0,this.phase="email",this.email="",this.code="",this.busy=!1,this.error=null,this.notice=null,this.customer=null,this.auth=null,this.unsubscribes=[],this.urlCodeUsed=!1,this.handleEmailInput=i=>{this.email=i.target.value,this.error=null},this.handleCodeInput=i=>{this.code=i.target.value,this.error=null},this.handleEmailSubmit=i=>{i.preventDefault(),this.requestLink()},this.handleCodeSubmit=i=>{i.preventDefault(),this.exchange(this.code.trim())}}async componentWillLoad(){const i=await n().catch((()=>null));if(!i)return void(this.error="Sign-in is not available right now");if(this.auth=i.getAuthManager?.()??null,!this.auth)return void(this.error="Sign-in is not available with this SDK");this.syncFromSDK(),this.unsubscribes.push(i.on("auth:changed",(()=>this.syncFromSDK()))),this.unsubscribes.push(i.on("session:changed",(()=>this.syncFromSDK())));const t=this.codeFromUrl();t&&!this.auth.authenticated&&await this.exchange(t)}disconnectedCallback(){this.unsubscribes.forEach((i=>i())),this.unsubscribes=[]}codeFromUrl(){if("undefined"==typeof window||!window.location?.search||this.urlCodeUsed)return null;const i=new URLSearchParams(window.location.search).get("code");return i&&(this.urlCodeUsed=!0),i}syncFromSDK(){this.auth&&(this.auth.authenticated?(this.customer=this.auth.customer??null,this.phase="signed-in"):"signed-in"===this.phase&&(this.customer=null,this.phase="email"))}async requestLink(i=!1){const t=this.email.trim();if(t){if(this.auth){this.busy=!0,this.error=null,this.notice=null;try{await this.auth.requestMagicLink({email:t}),this.phase="sent",this.notice=i?"Sent again. Check your inbox.":null,this.tlMagicLinkSent.emit({email:t})}catch(i){console.error("[tl-login] Magic-link request failed:",i),this.error=e(i,"Could not send your sign-in link"),this.tlError.emit({message:this.error})}finally{this.busy=!1}}}else this.error="Enter your email address"}async exchange(i){if(!i)return void(this.error="Enter the code from your email");if(!this.auth)return;const t=this.phase;this.busy=!0,this.error=null,this.phase="verifying";try{const t=await this.auth.exchange(i);this.customer=this.auth.customer??t?.customer??null,this.phase="signed-in",this.code="",this.tlAuthChanged.emit({customer:this.customer,authenticated:!0})}catch(i){console.error("[tl-login] Code exchange failed:",i),this.phase="verifying"===t||"email"===t?"email":"code",this.error="That code did not work. Check it and try again, or request a new link.",this.tlError.emit({message:this.error})}finally{this.busy=!1}}async signOut(){if(this.auth){this.busy=!0;try{await this.auth.logout()}catch(i){console.error("[tl-login] Sign out failed:",i)}finally{this.busy=!1,this.customer=null,this.phase="email",this.tlAuthChanged.emit({customer:null,authenticated:!1})}}}renderError(){return this.error?s("p",{class:"error",role:"alert"},this.error):null}render(){return"signed-in"===this.phase?s("div",{class:"login signed-in"},s("p",{class:"signed-in-text"},"Signed in as ",s("strong",null,this.customer?.email??"your account")),s("button",{type:"button",class:"secondary",disabled:this.busy,onClick:()=>this.signOut()},"Sign out")):"verifying"===this.phase?s("div",{class:"login"},s("h2",{class:"title"},"Signing you in…"),s("p",{class:"lead"},"Just a moment.")):"sent"===this.phase?s("div",{class:"login"},s("h2",{class:"title"},"Check your inbox"),s("p",{class:"lead"},"We've sent a sign-in link to ",s("strong",null,this.email),". Open it on this device to continue."),this.notice&&s("p",{class:"notice"},this.notice),this.renderError(),s("div",{class:"actions"},s("button",{type:"button",class:"secondary",disabled:this.busy,onClick:()=>this.requestLink(!0)},this.busy?"Sending…":"Resend link"),this.allowCodeEntry&&s("button",{type:"button",class:"link",onClick:()=>this.phase="code"},"Enter the code instead"),s("button",{type:"button",class:"link",onClick:()=>this.phase="email"},"Use a different email"))):"code"===this.phase?s("form",{class:"login",onSubmit:this.handleCodeSubmit},s("h2",{class:"title"},"Enter your code"),s("p",{class:"lead"},"Type the 6-digit code from the email we sent to ",s("strong",null,this.email),"."),s("label",{class:"label",htmlFor:"tl-login-code"},"Code"),s("input",{id:"tl-login-code",class:"input code-input",type:"text",inputmode:"numeric",autocomplete:"one-time-code",placeholder:"123456",value:this.code,disabled:this.busy,onInput:this.handleCodeInput}),this.renderError(),s("button",{type:"submit",class:"primary",disabled:this.busy},this.busy?"Checking…":"Sign in"),s("div",{class:"actions"},s("button",{type:"button",class:"link",onClick:()=>this.requestLink(!0)},"Resend link"),s("button",{type:"button",class:"link",onClick:()=>this.phase="sent"},"Back"))):s("form",{class:"login",onSubmit:this.handleEmailSubmit},s("h2",{class:"title"},this.heading),s("p",{class:"lead"},"Enter your email and we'll send you a secure sign-in link. No password needed."),s("label",{class:"label",htmlFor:"tl-login-email"},"Email address"),s("input",{id:"tl-login-email",class:"input",type:"email",autocomplete:"email",placeholder:"you@example.com",required:!0,value:this.email,disabled:this.busy||!this.auth,onInput:this.handleEmailInput}),this.renderError(),s("button",{type:"submit",class:"primary",disabled:this.busy||!this.auth},this.busy?"Sending link…":"Email me a sign-in link"))}};l.style=":host{display:block;font-family:var(--tl-font-family);color:var(--tl-foreground)}.login{display:flex;flex-direction:column;gap:var(--tl-spacing-3);padding:var(--tl-spacing-6);background:var(--tl-background);border:1px solid var(--tl-border);border-radius:var(--tl-radius-lg)}.title{margin:0;font-size:1.25rem;font-weight:600}.lead{margin:0;font-size:0.875rem;color:var(--tl-muted-foreground)}.label{font-size:0.875rem;font-weight:500}.input{padding:var(--tl-spacing-3);font:inherit;font-size:0.9375rem;color:var(--tl-foreground);background:var(--tl-background);border:1px solid var(--tl-border);border-radius:var(--tl-radius-md)}.input:focus{outline:2px solid var(--tl-primary);outline-offset:1px}.code-input{font-family:var(--tl-font-family-mono);font-size:1.25rem;letter-spacing:0.25em;text-align:center}.primary,.secondary{padding:var(--tl-spacing-3) var(--tl-spacing-4);font:inherit;font-size:0.9375rem;font-weight:600;border-radius:var(--tl-radius-md);cursor:pointer}.primary{color:var(--tl-primary-foreground);background:var(--tl-primary);border:none}.primary:hover:not(:disabled){opacity:0.9}.secondary{color:var(--tl-foreground);background:var(--tl-secondary);border:1px solid var(--tl-border)}.primary:disabled,.secondary:disabled,.input:disabled{opacity:0.6;cursor:not-allowed}.link{padding:0;font:inherit;font-size:0.875rem;color:var(--tl-primary);background:none;border:none;cursor:pointer}.link:hover{text-decoration:underline}.actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--tl-spacing-4)}.error{margin:0;font-size:0.8125rem;color:var(--tl-error)}.notice{margin:0;font-size:0.8125rem;color:var(--tl-success)}.signed-in{flex-direction:row;align-items:center;justify-content:space-between;flex-wrap:wrap}.signed-in-text{margin:0;font-size:0.875rem;overflow-wrap:anywhere}";export{l as tl_login}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as t,c as r,h as s}from"./p-OoYV1faY.js";import{o as e,w as i}from"./p-CqhvfyKV.js";import{e as a,r as o,o as l,c as n,d,g as c,a as h,h as u}from"./p-BXpVGW51.js";import"./p-4ig0-WB6.js";const p=class{constructor(s){t(this,s),this.tlOrderLoaded=r(this,"tlOrderLoaded"),this.tlError=r(this,"tlError"),this.showTickets=!0,this.columns=2,this.order=null,this.resolvedOrderId=null,this.loading=!1,this.error=null,this.paymentFailed=!1,this.occurrence=null,this.signedInCustomer=null}watchOrderId(t){this.resolvedOrderId=t||this.orderIdFromUrl(),this.load()}async componentWillLoad(){const t=this.urlParams(),r=t?.get("redirect_status");this.paymentFailed=!!r&&"succeeded"!==r,this.resolvedOrderId=this.orderId||this.orderIdFromUrl(),this.resolvedOrderId&&!this.paymentFailed&&await this.load()}componentDidLoad(){this.unsubscribe=e("checkout:completed",(t=>{const r=t;r?.id&&(this.paymentFailed=!1,this.order=r,this.resolvedOrderId=r.id,this.tlOrderLoaded.emit({order:r}),this.load())}))}disconnectedCallback(){this.unsubscribe?.()}urlParams(){return"undefined"!=typeof window&&window.location?.search?new URLSearchParams(window.location.search):null}orderIdFromUrl(){return this.urlParams()?.get("orderId")||null}async load(){const t=this.resolvedOrderId;if(t)try{this.loading=!this.order,this.error=null;const r=await i(),s=r.getOrdersManager?.();if(!s)throw new Error("Orders are not available");const e=await s.get(t);if(!e)throw new Error("Order not found");this.order=e,this.signedInCustomer=r.getAuthManager?.()?.customer??null,this.tlOrderLoaded.emit({order:e}),this.resolveEvent(r,e)}catch(t){console.error("[tl-order-confirmation] Failed to load order:",t),this.error=a(t,"Failed to load your order"),this.tlError.emit({message:this.error})}finally{this.loading=!1}}async resolveEvent(t,r){const s=r.tickets?.find((t=>t.eventOccurrenceId))?.eventOccurrenceId;if(s)try{const e=await o(t,s);e&&this.order?.id===r.id&&(this.occurrence=e)}catch{}}renderRows(t){const r=this.customerEmail||d(t,this.signedInCustomer),e=this.occurrence?.eventName||l(t),i=this.occurrence?.startsAt;return s("dl",{class:"rows"},s("div",{class:"row"},s("dt",null,"Order reference"),s("dd",{class:"reference"},t.orderNumber)),r&&s("div",{class:"row"},s("dt",null,"Email"),s("dd",null,r)),e&&s("div",{class:"row"},s("dt",null,"Event"),s("dd",null,e)),i&&s("div",{class:"row"},s("dt",null,"Date"),s("dd",null,n(i))))}renderTotals(t){const r=c(t),e=r.currency;return s("div",{class:"totals"},s("div",{class:"total-row"},s("span",null,"Subtotal"),s("span",null,h(r.subtotal,e))),r.showFee&&s("div",{class:"total-row fee"},s("span",null,r.feeLabel),s("span",null,h(r.fees,e))),r.tax>0&&s("div",{class:"total-row"},s("span",null,"Tax"),s("span",null,h(r.tax,e))),r.discount>0&&s("div",{class:"total-row discount"},s("span",null,"Discount"),s("span",null,"-",h(r.discount,e))),s("div",{class:"total-row total"},s("span",null,"Total"),s("span",null,h(r.total,e))))}render(){if(this.paymentFailed)return s("div",{class:"confirmation"},s("h1",{class:"title"},"Payment not completed"),s("p",{class:"lead"},"Your payment wasn't completed. Your cart is still saved, so you can try again."));if(!this.resolvedOrderId&&!this.order)return null;if(this.loading)return s("div",{class:"confirmation"},s("div",{class:"skeleton-line short"}),s("div",{class:"skeleton-line long"}),s("div",{class:"skeleton-block"}));const t=this.order,r=t?.id||this.resolvedOrderId;return s("div",{class:"confirmation"},s("div",{class:"check","aria-hidden":"true"},s("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor"},s("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M5 13l4 4L19 7"}))),s("h1",{class:"title"},"You're going!"),s("p",{class:"lead"},t?.orderNumber?`Order ${t.orderNumber} is confirmed. Your tickets are on their way to your email.`:"Your order is confirmed. Your tickets are on their way to your email."),this.error&&!t&&s("p",{class:"error"},"We couldn't load your order details yet. ",this.error),t&&Array.isArray(t.items)&&s("div",{class:"summary"},this.renderRows(t),s("ul",{class:"lines"},u(t).map(((r,e)=>s("li",{class:"line",key:e},s("span",{class:"line-name"},r.quantity," x ",r.name),s("span",{class:"line-price"},h(r.subtotal,t.currency)))))),this.renderTotals(t)),this.showTickets&&t&&s("div",{class:"tickets"},s("h2",{class:"subtitle"},"Your tickets"),s("tl-order-tickets",{orderId:r,columns:this.columns}),s("p",{class:"hint"},"Show these QR codes at the door for entry. Use Download PDF on a ticket to save it.")))}static get watchers(){return{orderId:[{watchOrderId:0}]}}};p.style=":host{display:block;font-family:var(--tl-font-family);color:var(--tl-foreground)}.confirmation{text-align:center}.check{width:4rem;height:4rem;margin:0 auto var(--tl-spacing-4);display:flex;align-items:center;justify-content:center;border-radius:9999px;background:var(--tl-success);color:var(--tl-success-foreground)}.check svg{width:2rem;height:2rem}.title{margin:0 0 var(--tl-spacing-2);font-size:1.875rem;font-weight:700;line-height:1.2}.lead{margin:0 0 var(--tl-spacing-6);color:var(--tl-muted-foreground)}.error{margin:0 0 var(--tl-spacing-6);font-size:0.875rem;color:var(--tl-error)}.summary{text-align:left;padding:var(--tl-spacing-6);margin-bottom:var(--tl-spacing-6);background:var(--tl-muted);border:1px solid var(--tl-border);border-radius:var(--tl-radius-lg)}.rows{display:grid;gap:var(--tl-spacing-2);margin:0 0 var(--tl-spacing-4);padding:0 0 var(--tl-spacing-4);border-bottom:1px solid var(--tl-border)}.row{display:flex;justify-content:space-between;gap:var(--tl-spacing-4);font-size:0.875rem}.row dt{color:var(--tl-muted-foreground)}.row dd{margin:0;text-align:right;overflow-wrap:anywhere}.reference{font-family:var(--tl-font-family-mono);font-weight:600}.lines{list-style:none;margin:0;padding:0;display:grid;gap:var(--tl-spacing-2)}.line{display:flex;justify-content:space-between;gap:var(--tl-spacing-4);font-size:0.875rem}.totals{margin-top:var(--tl-spacing-3);padding-top:var(--tl-spacing-3);border-top:1px solid var(--tl-border);display:grid;gap:var(--tl-spacing-1);font-size:0.875rem}.total-row{display:flex;justify-content:space-between;color:var(--tl-muted-foreground)}.total-row.discount{color:var(--tl-success)}.total-row.total{margin-top:var(--tl-spacing-1);font-size:1rem;font-weight:600;color:var(--tl-foreground)}.tickets{text-align:left}.subtitle{margin:0 0 var(--tl-spacing-4);font-size:1.125rem;font-weight:600}.hint{margin:var(--tl-spacing-3) 0 0;font-size:0.75rem;color:var(--tl-muted-foreground)}.skeleton-line,.skeleton-block{background:var(--tl-secondary);border-radius:var(--tl-radius-md);animation:pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;margin:0 auto var(--tl-spacing-3)}.skeleton-line{height:1rem}.skeleton-line.short{width:40%;height:1.75rem}.skeleton-line.long{width:70%}.skeleton-block{height:8rem}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}";export{p as tl_order_confirmation}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e,c as t,h as a,a as s}from"./p-OoYV1faY.js";import{h as i,g as r}from"./p-CqhvfyKV.js";const o=class{constructor(a){e(this,a),this.tlReady=t(this,"tlReady"),this.tlLoad=t(this,"tlLoad"),this.tlError=t(this,"tlError"),this.tlSeatAdded=t(this,"tlSeatAdded"),this.tlSeatRemoved=t(this,"tlSeatRemoved"),this.tlCartChange=t(this,"tlCartChange"),this.hboUrl="https://checkout.ticketlayer.com",this.apiUrl="https://api.ticketlayer.com",this.height="600px",this.width="100%",this.isReady=!1,this.isLoading=!0,this.error=null,this.seatsInCart=[],this.postToIframe=(e,t={})=>{this.iframeRef?.contentWindow&&this.iframeRef.contentWindow.postMessage({type:e,...t},"*")},this.handleMessage=e=>{if(e.data&&e.data.type)switch(e.data.type){case"seatmap:ready":this.isReady=!0,this.isLoading=!1,this.tlReady.emit(),this.postToIframe("seatmap:set-cart-seats",{seatIds:this.seatsInCart});break;case"seatmap:loaded":this.tlLoad.emit({seatMapId:e.data.seatMapId});break;case"seatmap:error":this.error=e.data.error,this.isLoading=!1,this.tlError.emit({error:e.data.error});break;case"seatmap:add-seat":this.handleAddSeat(e.data.seatId,e.data.ticketTypeId);break;case"seatmap:remove-seat":this.handleRemoveSeat(e.data.seatId)}},this.handleAddSeat=async(e,t)=>{if(!i())return console.warn("[tl-seat-map] SDK not available, cannot add seat"),void this.postToIframe("seatmap:add-seat-failed",{seatId:e,error:"SDK not available"});try{const a=r();await a.getCartManager().addSeat(e,t,this.occurrenceId),this.postToIframe("seatmap:add-seat-confirmed",{seatId:e}),this.seatsInCart=[...this.seatsInCart,e],this.tlSeatAdded.emit({seatId:e,ticketTypeId:t}),this.tlCartChange.emit({seatIds:this.seatsInCart})}catch(t){console.error("[tl-seat-map] Failed to add seat:",t),this.postToIframe("seatmap:add-seat-failed",{seatId:e,error:"Failed to add seat"})}},this.handleRemoveSeat=async e=>{if(!i())return console.warn("[tl-seat-map] SDK not available, cannot remove seat"),void this.postToIframe("seatmap:remove-seat-failed",{seatId:e,error:"SDK not available"});try{const t=r();await t.getCartManager().removeSeat(e,this.occurrenceId),this.postToIframe("seatmap:remove-seat-confirmed",{seatId:e}),this.seatsInCart=this.seatsInCart.filter((t=>t!==e)),this.tlSeatRemoved.emit({seatId:e}),this.tlCartChange.emit({seatIds:this.seatsInCart})}catch(t){console.error("[tl-seat-map] Failed to remove seat:",t),this.postToIframe("seatmap:remove-seat-failed",{seatId:e,error:"Failed to remove seat"})}}}componentWillLoad(){window.addEventListener("message",this.handleMessage)}disconnectedCallback(){window.removeEventListener("message",this.handleMessage)}watchOccurrenceId(){this.isReady=!1,this.isLoading=!0,this.error=null}getIframeSrc(){return`${this.hboUrl}/embed/seats?occurrenceId=${encodeURIComponent(this.occurrenceId)}&apiUrl=${encodeURIComponent(this.apiUrl)}`}render(){return a("div",{key:"c9beadc1792d7825ac3f99e6abc8b181e28fd1b6",class:"seat-map-container",style:{width:this.width,height:this.height}},this.isLoading&&a("div",{key:"ad792ea35f433a268c81722ce4e7d0e34780d337",class:"loading"},a("div",{key:"dd3e0657b16c2f265f59fbaa2ac39c559c2093b7",class:"spinner"}),a("p",{key:"2714e3073d0e5cddc50d530aa1cf46a7f73ba96f"},"Loading seat map...")),this.error&&a("div",{key:"3de9d73ab89a1ee963e73b4192d5c93e9667f11b",class:"error"},a("p",{key:"0fea5c828b5b212ffdb45c9c7702d241e2b79cc4",class:"error-title"},"Error"),a("p",{key:"f2c090b982bb1ee6fb7d347d8860b4ce4798a891",class:"error-message"},this.error)),a("iframe",{key:"8023219fdd467ec736f9627190690a6f73df3bb3",ref:e=>this.iframeRef=e,src:this.getIframeSrc(),class:{"seat-map-iframe":!0,hidden:this.isLoading||!!this.error},title:"Ticketlayer Seat Map",allow:"fullscreen"}))}get el(){return s(this)}static get watchers(){return{occurrenceId:[{watchOccurrenceId:0}]}}};o.style=":host{display:block;font-family:var(--tl-font-family)}.seat-map-container{position:relative;overflow:hidden;border-radius:var(--tl-radius-md);background:var(--tl-color-background)}.seat-map-iframe{width:100%;height:100%;border:none}.seat-map-iframe.hidden{display:none}.loading{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--tl-color-background);color:var(--tl-color-foreground);gap:1rem}.loading p{margin:0;font-size:0.875rem;color:var(--tl-color-muted-foreground)}.spinner{width:40px;height:40px;border:3px solid var(--tl-color-border);border-top-color:var(--tl-color-primary);border-radius:50%;animation:tl-seat-map-spin 1s linear infinite}@keyframes tl-seat-map-spin{to{transform:rotate(360deg)}}.error{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--tl-color-background);color:var(--tl-color-error);padding:1.5rem;text-align:center}.error-title{margin:0 0 0.5rem;font-size:1.125rem;font-weight:600}.error-message{margin:0;font-size:0.875rem;opacity:0.9}";export{o as tl_seat_map}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as t,c as e,h as r,H as s,a as i}from"./p-OoYV1faY.js";import{h as o,g as a}from"./p-CqhvfyKV.js";const l=class{constructor(r){t(this,r),this.tlComplete=e(this,"tl-complete"),this.tlError=e(this,"tl-error"),this.tlClose=e(this,"tl-close"),this.disabled=!1,this.handleClick=()=>{if(!this.disabled)return o()?void a().checkout.openModal({onComplete:t=>{this.tlComplete.emit(t)},onError:t=>{this.tlError.emit({message:t.message})},onClose:()=>{this.tlClose.emit()}}):(console.error("[tl-checkout-wrapper] SDK not initialized. Call setSDK(ticketlayer) first."),void this.tlError.emit({message:"SDK not initialized"}))},this.handleKeyDown=t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.handleClick())}}render(){return r(s,{key:"ebaae5dd6710ffc5353ece4327012df0332fdbb7",class:{"tl-checkout-wrapper":!0,"tl-checkout-wrapper--disabled":this.disabled},onClick:this.handleClick,onKeyDown:this.handleKeyDown,role:"button",tabindex:this.disabled?-1:0,"aria-disabled":this.disabled?"true":null},r("slot",{key:"0118d9921df5af1ae2376fd4135bac487aac7ebd"}))}get el(){return i(this)}};l.style="tl-checkout-wrapper,.tl-checkout-wrapper{display:inline-block;cursor:pointer}tl-checkout-wrapper:focus,.tl-checkout-wrapper:focus{outline:2px solid var(--tl-ring);outline-offset:2px;border-radius:var(--tl-radius-sm)}tl-checkout-wrapper[disabled],tl-checkout-wrapper.tl-checkout-wrapper--disabled,.tl-checkout-wrapper--disabled{cursor:not-allowed;opacity:0.5}";export{l as tl_checkout_wrapper}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e,c as t,h as s}from"./p-OoYV1faY.js";import{w as i}from"./p-CqhvfyKV.js";const r=class{constructor(s){e(this,s),this.tlEventClick=t(this,"tlEventClick"),this.limit=12,this.columns=3,this.events=[],this.loading=!0,this.error=null,this.handleEventClick=e=>{console.log("[tl-event-list] Event clicked:",e.detail.eventId),this.tlEventClick.emit(e.detail)}}watchFiltersChange(){this.loadEvents()}async componentWillLoad(){await this.loadEvents()}async loadEvents(){try{console.log("[tl-event-list] Loading events via SDK...",{limit:this.limit,category:this.category}),this.loading=!0,this.error=null;const e=(await i()).getEventsManager(),t=await e.list({limit:this.limit,category:this.category});console.log("[tl-event-list] Events loaded:",t.items.length),this.events=t.items}catch(e){console.error("[tl-event-list] Failed to load events:",e),this.error=e instanceof Error?e.message:"Failed to load events"}finally{this.loading=!1}}render(){const e=`event-grid cols-${Math.min(Math.max(this.columns,1),4)}`;return this.loading?s("div",{class:e},Array.from({length:6}).map(((e,t)=>s("div",{class:"skeleton-card",key:t},s("div",{class:"skeleton-image"}),s("div",{class:"skeleton-content"},s("div",{class:"skeleton-line short"}),s("div",{class:"skeleton-line medium"}),s("div",{class:"skeleton-line long"})))))):this.error?s("div",{class:"error-state"},s("p",{class:"error-title"},"Error loading events"),s("p",{class:"error-message"},this.error)):0===this.events.length?s("div",{class:"empty-state"},s("svg",{class:"empty-icon",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor"},s("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"1.5",d:"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"})),s("p",{class:"empty-title"},"No events available"),s("p",{class:"empty-message"},"Check back later for upcoming events.")):s("div",{class:e},this.events.map((e=>s("tl-event-card",{key:e.id,event:e,onTlClick:this.handleEventClick}))))}static get watchers(){return{limit:[{watchFiltersChange:0}],category:[{watchFiltersChange:0}]}}};r.style=":host{display:block;font-family:var(--tl-font-family)}.event-grid{display:grid;gap:var(--tl-spacing-6)}.cols-1{grid-template-columns:1fr}.cols-2{grid-template-columns:repeat(2, 1fr)}.cols-3{grid-template-columns:repeat(3, 1fr)}.cols-4{grid-template-columns:repeat(4, 1fr)}@media (max-width: 1024px){.cols-4,.cols-3{grid-template-columns:repeat(2, 1fr)}}@media (max-width: 640px){.cols-4,.cols-3,.cols-2{grid-template-columns:1fr}}.skeleton-card{background:var(--tl-secondary);border-radius:var(--tl-radius-lg);overflow:hidden}.skeleton-image{aspect-ratio:16 / 9;background:var(--tl-muted);animation:pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite}.skeleton-content{padding:var(--tl-spacing-4);display:flex;flex-direction:column;gap:0.5rem}.skeleton-line{height:1rem;background:var(--tl-muted);border-radius:var(--tl-radius-sm);animation:pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite}.skeleton-line.short{width:4rem;height:0.75rem}.skeleton-line.medium{width:75%}.skeleton-line.long{width:50%}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}.error-state{background:rgba(239, 68, 68, 0.1);border:1px solid var(--tl-error);border-radius:var(--tl-radius-lg);padding:var(--tl-spacing-4)}.error-title{margin:0;font-weight:500;color:var(--tl-error)}.error-message{margin:0.25rem 0 0;font-size:0.875rem;color:var(--tl-error)}.empty-state{text-align:center;padding:var(--tl-spacing-8) var(--tl-spacing-4)}.empty-icon{width:4rem;height:4rem;margin:0 auto 1rem;color:var(--tl-muted-foreground)}.empty-title{margin:0;font-size:1.25rem;font-weight:600;color:var(--tl-foreground)}.empty-message{margin:0.5rem 0 0;color:var(--tl-muted-foreground)}";export{r as tl_event_list}
|