@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.
Files changed (62) hide show
  1. package/README.md +141 -4
  2. package/dist/cjs/cores/buy-tickets-button.js +213 -0
  3. package/dist/cjs/cores/buy-tickets-wrapper.js +106 -0
  4. package/dist/cjs/cores/cart-badge.js +150 -0
  5. package/dist/cjs/cores/cart-drawer.js +122 -0
  6. package/dist/cjs/cores/cart.js +247 -0
  7. package/dist/cjs/cores/checkout-wrapper.js +75 -0
  8. package/dist/cjs/cores/event-card.js +209 -0
  9. package/dist/cjs/cores/event-list.js +109 -0
  10. package/dist/cjs/cores/index.js +64 -1
  11. package/dist/cjs/cores/login.js +309 -0
  12. package/dist/cjs/cores/my-orders.js +221 -0
  13. package/dist/cjs/cores/occurrence-selector.js +528 -0
  14. package/dist/cjs/cores/order-confirmation.js +301 -0
  15. package/dist/cjs/cores/order-tickets.js +172 -0
  16. package/dist/cjs/cores/promo-code.js +136 -0
  17. package/dist/cjs/cores/ticket-selector.js +30 -0
  18. package/dist/cjs/define.js +76 -0
  19. package/dist/cjs/index.js +17 -1
  20. package/dist/cjs/manifest.js +5 -0
  21. package/dist/cjs/orders.js +169 -0
  22. package/dist/esm/client.d.ts +106 -0
  23. package/dist/esm/cores/buy-tickets-button.d.ts +55 -0
  24. package/dist/esm/cores/buy-tickets-button.js +210 -0
  25. package/dist/esm/cores/buy-tickets-wrapper.d.ts +27 -0
  26. package/dist/esm/cores/buy-tickets-wrapper.js +103 -0
  27. package/dist/esm/cores/cart-badge.d.ts +48 -0
  28. package/dist/esm/cores/cart-badge.js +147 -0
  29. package/dist/esm/cores/cart-drawer.d.ts +44 -0
  30. package/dist/esm/cores/cart-drawer.js +119 -0
  31. package/dist/esm/cores/cart.d.ts +105 -0
  32. package/dist/esm/cores/cart.js +244 -0
  33. package/dist/esm/cores/checkout-wrapper.d.ts +22 -0
  34. package/dist/esm/cores/checkout-wrapper.js +72 -0
  35. package/dist/esm/cores/event-card.d.ts +80 -0
  36. package/dist/esm/cores/event-card.js +205 -0
  37. package/dist/esm/cores/event-list.d.ts +35 -0
  38. package/dist/esm/cores/event-list.js +106 -0
  39. package/dist/esm/cores/index.d.ts +28 -0
  40. package/dist/esm/cores/index.js +42 -0
  41. package/dist/esm/cores/login.d.ts +125 -0
  42. package/dist/esm/cores/login.js +306 -0
  43. package/dist/esm/cores/my-orders.d.ts +63 -0
  44. package/dist/esm/cores/my-orders.js +218 -0
  45. package/dist/esm/cores/occurrence-selector.d.ts +170 -0
  46. package/dist/esm/cores/occurrence-selector.js +525 -0
  47. package/dist/esm/cores/order-confirmation.d.ts +99 -0
  48. package/dist/esm/cores/order-confirmation.js +298 -0
  49. package/dist/esm/cores/order-tickets.d.ts +46 -0
  50. package/dist/esm/cores/order-tickets.js +169 -0
  51. package/dist/esm/cores/promo-code.d.ts +56 -0
  52. package/dist/esm/cores/promo-code.js +132 -0
  53. package/dist/esm/cores/ticket-selector.js +30 -0
  54. package/dist/esm/define.d.ts +146 -0
  55. package/dist/esm/define.js +75 -0
  56. package/dist/esm/index.d.ts +5 -3
  57. package/dist/esm/index.js +2 -1
  58. package/dist/esm/manifest.d.ts +12 -0
  59. package/dist/esm/manifest.js +5 -0
  60. package/dist/esm/orders.d.ts +110 -0
  61. package/dist/esm/orders.js +154 -0
  62. 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
+ });