@ticketlayer/elements-core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -4
- package/dist/cjs/cores/buy-tickets-button.js +213 -0
- package/dist/cjs/cores/buy-tickets-wrapper.js +106 -0
- package/dist/cjs/cores/cart-badge.js +150 -0
- package/dist/cjs/cores/cart-drawer.js +122 -0
- package/dist/cjs/cores/cart.js +247 -0
- package/dist/cjs/cores/checkout-wrapper.js +75 -0
- package/dist/cjs/cores/event-card.js +209 -0
- package/dist/cjs/cores/event-list.js +109 -0
- package/dist/cjs/cores/index.js +64 -1
- package/dist/cjs/cores/login.js +309 -0
- package/dist/cjs/cores/my-orders.js +221 -0
- package/dist/cjs/cores/occurrence-selector.js +528 -0
- package/dist/cjs/cores/order-confirmation.js +301 -0
- package/dist/cjs/cores/order-tickets.js +172 -0
- package/dist/cjs/cores/promo-code.js +136 -0
- package/dist/cjs/cores/ticket-selector.js +30 -0
- package/dist/cjs/define.js +76 -0
- package/dist/cjs/index.js +17 -1
- package/dist/cjs/manifest.js +5 -0
- package/dist/cjs/orders.js +169 -0
- package/dist/esm/client.d.ts +106 -0
- package/dist/esm/cores/buy-tickets-button.d.ts +55 -0
- package/dist/esm/cores/buy-tickets-button.js +210 -0
- package/dist/esm/cores/buy-tickets-wrapper.d.ts +27 -0
- package/dist/esm/cores/buy-tickets-wrapper.js +103 -0
- package/dist/esm/cores/cart-badge.d.ts +48 -0
- package/dist/esm/cores/cart-badge.js +147 -0
- package/dist/esm/cores/cart-drawer.d.ts +44 -0
- package/dist/esm/cores/cart-drawer.js +119 -0
- package/dist/esm/cores/cart.d.ts +105 -0
- package/dist/esm/cores/cart.js +244 -0
- package/dist/esm/cores/checkout-wrapper.d.ts +22 -0
- package/dist/esm/cores/checkout-wrapper.js +72 -0
- package/dist/esm/cores/event-card.d.ts +80 -0
- package/dist/esm/cores/event-card.js +205 -0
- package/dist/esm/cores/event-list.d.ts +35 -0
- package/dist/esm/cores/event-list.js +106 -0
- package/dist/esm/cores/index.d.ts +28 -0
- package/dist/esm/cores/index.js +42 -0
- package/dist/esm/cores/login.d.ts +125 -0
- package/dist/esm/cores/login.js +306 -0
- package/dist/esm/cores/my-orders.d.ts +63 -0
- package/dist/esm/cores/my-orders.js +218 -0
- package/dist/esm/cores/occurrence-selector.d.ts +170 -0
- package/dist/esm/cores/occurrence-selector.js +525 -0
- package/dist/esm/cores/order-confirmation.d.ts +99 -0
- package/dist/esm/cores/order-confirmation.js +298 -0
- package/dist/esm/cores/order-tickets.d.ts +46 -0
- package/dist/esm/cores/order-tickets.js +169 -0
- package/dist/esm/cores/promo-code.d.ts +56 -0
- package/dist/esm/cores/promo-code.js +132 -0
- package/dist/esm/cores/ticket-selector.js +30 -0
- package/dist/esm/define.d.ts +146 -0
- package/dist/esm/define.js +75 -0
- package/dist/esm/index.d.ts +5 -3
- package/dist/esm/index.js +2 -1
- package/dist/esm/manifest.d.ts +12 -0
- package/dist/esm/manifest.js +5 -0
- package/dist/esm/orders.d.ts +110 -0
- package/dist/esm/orders.js +154 -0
- package/package.json +2 -2
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.myOrdersCore = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `tl-my-orders`: the signed-in customer's orders, one expandable row each.
|
|
6
|
+
*
|
|
7
|
+
* The first core whose whole shape is decided by whether somebody is signed
|
|
8
|
+
* in. It reads the client's auth manager once, follows `auth:changed` and
|
|
9
|
+
* `session:changed` from there, and lists the orders whenever the answer turns
|
|
10
|
+
* from signed out to signed in. Both subscriptions are bound in its own
|
|
11
|
+
* `mount` and handed to `ctx.onTeardown` (TKT-197), so a remount cannot leave
|
|
12
|
+
* four listeners on the bus.
|
|
13
|
+
*
|
|
14
|
+
* Behaviour is what the Stencil component did, to the letter, including the
|
|
15
|
+
* three things that read like accidents and are not:
|
|
16
|
+
*
|
|
17
|
+
* - a connector with no auth accessor is treated as SIGNED IN, and a 401 from
|
|
18
|
+
* the listing is what decides otherwise. That is deliberate: an older
|
|
19
|
+
* connector has no way to answer the question, and showing the sign-in form
|
|
20
|
+
* to someone who is signed in is the worse failure.
|
|
21
|
+
* - a 401 or 403 from the listing is not an error. It drops back to the
|
|
22
|
+
* signed-out view, which renders the inline sign-in, and emits nothing.
|
|
23
|
+
* - the element does NOT announce that the host never started Live. It shows
|
|
24
|
+
* "Orders are not available right now" and stays quiet, where `tl-cart`
|
|
25
|
+
* emits `tlError` for the same condition, because the component's wait and
|
|
26
|
+
* its read were in different places. Kept rather than made consistent.
|
|
27
|
+
*
|
|
28
|
+
* What did not come across is the `console.error` tracing, which a library
|
|
29
|
+
* should not do for its host (`tl-cart` dropped its own for the same reason).
|
|
30
|
+
*/
|
|
31
|
+
const define_js_1 = require("../define.js");
|
|
32
|
+
const orders_js_1 = require("../orders.js");
|
|
33
|
+
const promo_code_js_1 = require("./promo-code.js");
|
|
34
|
+
const STRINGS = {
|
|
35
|
+
signInTitle: 'Sign in to see your orders',
|
|
36
|
+
signInText: 'Your tickets and order history live in your account.',
|
|
37
|
+
errorTitle: 'Could not load your orders',
|
|
38
|
+
emptyTitle: 'No orders yet',
|
|
39
|
+
orderPrefix: 'Order ',
|
|
40
|
+
unnamedEvent: 'Order',
|
|
41
|
+
ticketSingular: 'ticket',
|
|
42
|
+
ticketPlural: 'tickets',
|
|
43
|
+
unavailable: 'Orders are not available right now',
|
|
44
|
+
noOrdersManager: 'Orders are not available',
|
|
45
|
+
loadFailed: 'Failed to load your orders',
|
|
46
|
+
};
|
|
47
|
+
exports.myOrdersCore = (0, define_js_1.defineElement)({
|
|
48
|
+
tag: 'tl-my-orders',
|
|
49
|
+
docs: "The signed-in customer's orders: event, date, ticket count, total and status, each row expanding to its tickets.",
|
|
50
|
+
category: 'account',
|
|
51
|
+
runtimes: ['web', 'native'],
|
|
52
|
+
tokens: [
|
|
53
|
+
'background',
|
|
54
|
+
'border',
|
|
55
|
+
'error',
|
|
56
|
+
'error-foreground',
|
|
57
|
+
'font-family',
|
|
58
|
+
'foreground',
|
|
59
|
+
'muted-foreground',
|
|
60
|
+
'primary',
|
|
61
|
+
'primary-foreground',
|
|
62
|
+
'radius-lg',
|
|
63
|
+
'secondary',
|
|
64
|
+
'secondary-foreground',
|
|
65
|
+
'spacing-1',
|
|
66
|
+
'spacing-3',
|
|
67
|
+
'spacing-4',
|
|
68
|
+
'spacing-8',
|
|
69
|
+
'success',
|
|
70
|
+
'success-foreground',
|
|
71
|
+
'warning',
|
|
72
|
+
'warning-foreground',
|
|
73
|
+
],
|
|
74
|
+
sdkMethods: ['orders.mine', 'auth.authenticated', 'on'],
|
|
75
|
+
props: {
|
|
76
|
+
emptyMessage: {
|
|
77
|
+
type: 'string',
|
|
78
|
+
attr: 'empty-message',
|
|
79
|
+
default: "When you buy tickets they'll show up here, ready to view and download.",
|
|
80
|
+
docs: 'Copy for the empty state.',
|
|
81
|
+
},
|
|
82
|
+
columns: { type: 'number', attr: 'columns', default: 2, docs: 'Columns for the expanded ticket grid.' },
|
|
83
|
+
},
|
|
84
|
+
events: {
|
|
85
|
+
tlOrderSelect: { detail: '{ orderId: string; }', docs: 'a row was expanded ({ orderId })' },
|
|
86
|
+
tlError: { detail: '{ message: string; }', docs: 'the orders could not be loaded' },
|
|
87
|
+
},
|
|
88
|
+
strings: STRINGS,
|
|
89
|
+
statuses: ['loading', 'signed-out', 'error', 'empty', 'ready'],
|
|
90
|
+
state: () => ({ orders: [], authenticated: false, loading: true, error: null, expandedId: null }),
|
|
91
|
+
/**
|
|
92
|
+
* On screen: wait for the client, read who is signed in, follow both auth
|
|
93
|
+
* signals, then list the orders if there is somebody to list them for.
|
|
94
|
+
*
|
|
95
|
+
* The session hydrates after the client publishes, so `auth:changed` and
|
|
96
|
+
* `session:changed` are both followed: the connector raises one or the other
|
|
97
|
+
* depending on whether the customer signed in here or arrived with a session
|
|
98
|
+
* already warm.
|
|
99
|
+
*/
|
|
100
|
+
mount: (ctx) => {
|
|
101
|
+
void (async () => {
|
|
102
|
+
let client;
|
|
103
|
+
try {
|
|
104
|
+
client = await ctx.whenClient();
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
if (!ctx.active())
|
|
108
|
+
return;
|
|
109
|
+
ctx.actions.connectFailed();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!ctx.active())
|
|
113
|
+
return;
|
|
114
|
+
// An older connector has no auth accessor and cannot answer, so assume
|
|
115
|
+
// signed in and let a 401 from the listing decide.
|
|
116
|
+
const auth = client.getAuthManager?.();
|
|
117
|
+
ctx.setState({ authenticated: auth ? auth.authenticated : true });
|
|
118
|
+
for (const event of ['auth:changed', 'session:changed']) {
|
|
119
|
+
const off = client.on?.(event, () => ctx.actions.syncAuth());
|
|
120
|
+
if (typeof off === 'function')
|
|
121
|
+
ctx.onTeardown(off);
|
|
122
|
+
}
|
|
123
|
+
if (ctx.state.authenticated)
|
|
124
|
+
await ctx.actions.load();
|
|
125
|
+
else
|
|
126
|
+
ctx.setState({ loading: false });
|
|
127
|
+
})();
|
|
128
|
+
},
|
|
129
|
+
status: ({ state }) => state.loading
|
|
130
|
+
? 'loading'
|
|
131
|
+
: !state.authenticated
|
|
132
|
+
? 'signed-out'
|
|
133
|
+
: state.error
|
|
134
|
+
? 'error'
|
|
135
|
+
: state.orders.length === 0
|
|
136
|
+
? 'empty'
|
|
137
|
+
: 'ready',
|
|
138
|
+
derive: ({ state, strings }) => ({
|
|
139
|
+
rows: state.orders.map((order) => {
|
|
140
|
+
const count = (0, orders_js_1.ticketCount)(order);
|
|
141
|
+
return {
|
|
142
|
+
id: order.id,
|
|
143
|
+
numberLabel: `${strings.orderPrefix}${order.orderNumber}`,
|
|
144
|
+
eventName: (0, orders_js_1.orderEventName)(order) ?? strings.unnamedEvent,
|
|
145
|
+
dateLabel: order.createdAt ? (0, orders_js_1.formatDate)(order.createdAt) : null,
|
|
146
|
+
countLabel: `${count} ${count === 1 ? strings.ticketSingular : strings.ticketPlural}`,
|
|
147
|
+
totalLabel: (0, orders_js_1.formatPrice)(order.total, order.currency),
|
|
148
|
+
statusLabel: (0, orders_js_1.statusLabel)(order.status),
|
|
149
|
+
statusTone: (0, orders_js_1.statusTone)(order.status),
|
|
150
|
+
expanded: state.expandedId === order.id,
|
|
151
|
+
};
|
|
152
|
+
}),
|
|
153
|
+
}),
|
|
154
|
+
// The action map is named so `syncAuth` can call `load`: the action context
|
|
155
|
+
// does not carry the actions (only a mount's does), and listing the orders
|
|
156
|
+
// when the session turns warm is the same work the mount does.
|
|
157
|
+
actions: (ctx) => {
|
|
158
|
+
const self = {
|
|
159
|
+
/** List the orders. A 401 means signed out, which is not an error. */
|
|
160
|
+
async load() {
|
|
161
|
+
const client = ctx.optionalClient();
|
|
162
|
+
if (!client)
|
|
163
|
+
return;
|
|
164
|
+
try {
|
|
165
|
+
ctx.setState({ loading: true, error: null });
|
|
166
|
+
const orders = client.getOrdersManager?.();
|
|
167
|
+
if (!orders)
|
|
168
|
+
throw new Error(ctx.strings.noOrdersManager);
|
|
169
|
+
const list = (await orders.mine());
|
|
170
|
+
ctx.setState({ orders: list ?? [], authenticated: true });
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
if ((0, promo_code_js_1.isAuthError)(err)) {
|
|
174
|
+
// Not signed in: fall through to the inline sign-in rather than an error.
|
|
175
|
+
ctx.setState({ authenticated: false, orders: [] });
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const message = (0, orders_js_1.errorMessage)(err, ctx.strings.loadFailed);
|
|
179
|
+
ctx.setState({ error: message });
|
|
180
|
+
ctx.emit('tlError', { message });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
ctx.setState({ loading: false });
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
/**
|
|
188
|
+
* The client says the session changed. Listing on the way in and clearing
|
|
189
|
+
* on the way out; an unchanged answer does nothing, which is what keeps a
|
|
190
|
+
* burst of `session:changed` from listing the orders four times.
|
|
191
|
+
*/
|
|
192
|
+
syncAuth() {
|
|
193
|
+
const auth = ctx.optionalClient()?.getAuthManager?.();
|
|
194
|
+
if (!auth)
|
|
195
|
+
return;
|
|
196
|
+
const was = ctx.state.authenticated;
|
|
197
|
+
ctx.setState({ authenticated: auth.authenticated });
|
|
198
|
+
if (auth.authenticated && !was)
|
|
199
|
+
void self.load();
|
|
200
|
+
else if (!auth.authenticated && was)
|
|
201
|
+
ctx.setState({ orders: [], expandedId: null });
|
|
202
|
+
},
|
|
203
|
+
/** Open a row, or close the open one. Only opening is announced. */
|
|
204
|
+
toggle(orderId) {
|
|
205
|
+
const opening = ctx.state.expandedId !== orderId;
|
|
206
|
+
ctx.setState({ expandedId: opening ? orderId : null });
|
|
207
|
+
if (opening)
|
|
208
|
+
ctx.emit('tlOrderSelect', { orderId });
|
|
209
|
+
},
|
|
210
|
+
/**
|
|
211
|
+
* The host never produced a client. Said on screen and nowhere else: the
|
|
212
|
+
* component did not emit `tlError` here, because its wait for the client
|
|
213
|
+
* was outside the try block that announces a failure.
|
|
214
|
+
*/
|
|
215
|
+
connectFailed() {
|
|
216
|
+
ctx.setState({ loading: false, error: ctx.strings.unavailable });
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
return self;
|
|
220
|
+
},
|
|
221
|
+
});
|