@tiledev/sdk-apptile-live-selling 0.13.0 → 0.15.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 (131) hide show
  1. package/README.md +116 -12
  2. package/dist/clipsPage.d.ts +29 -0
  3. package/dist/clipsPage.d.ts.map +1 -0
  4. package/dist/clipsPage.js +49 -0
  5. package/dist/clipsPage.js.map +1 -0
  6. package/dist/giveawayPrizeLines.d.ts +10 -0
  7. package/dist/giveawayPrizeLines.d.ts.map +1 -1
  8. package/dist/giveawayPrizeLines.js +11 -1
  9. package/dist/giveawayPrizeLines.js.map +1 -1
  10. package/dist/hiddenShows.d.ts +10 -0
  11. package/dist/hiddenShows.d.ts.map +1 -1
  12. package/dist/hiddenShows.js +11 -0
  13. package/dist/hiddenShows.js.map +1 -1
  14. package/dist/index.d.ts +10 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +53 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/linkLots.d.ts +64 -0
  19. package/dist/linkLots.d.ts.map +1 -0
  20. package/dist/linkLots.js +84 -0
  21. package/dist/linkLots.js.map +1 -0
  22. package/dist/livePages.d.ts +166 -0
  23. package/dist/livePages.d.ts.map +1 -0
  24. package/dist/livePages.js +187 -0
  25. package/dist/livePages.js.map +1 -0
  26. package/dist/liveRoom.d.ts +21 -0
  27. package/dist/liveRoom.d.ts.map +1 -0
  28. package/dist/liveRoom.js +28 -0
  29. package/dist/liveRoom.js.map +1 -0
  30. package/dist/pageOptions.d.ts +118 -0
  31. package/dist/pageOptions.d.ts.map +1 -0
  32. package/dist/pageOptions.js +99 -0
  33. package/dist/pageOptions.js.map +1 -0
  34. package/dist/pageTypes.d.ts +185 -0
  35. package/dist/pageTypes.d.ts.map +1 -0
  36. package/dist/pageTypes.js +3 -0
  37. package/dist/pageTypes.js.map +1 -0
  38. package/dist/react/LiveSellingProvider.d.ts +31 -1
  39. package/dist/react/LiveSellingProvider.d.ts.map +1 -1
  40. package/dist/react/LiveSellingProvider.js +44 -2
  41. package/dist/react/LiveSellingProvider.js.map +1 -1
  42. package/dist/react/index.d.ts +12 -0
  43. package/dist/react/index.d.ts.map +1 -1
  44. package/dist/react/index.js +34 -1
  45. package/dist/react/index.js.map +1 -1
  46. package/dist/react/index.web.d.ts +13 -32
  47. package/dist/react/index.web.d.ts.map +1 -1
  48. package/dist/react/index.web.js +52 -139
  49. package/dist/react/index.web.js.map +1 -1
  50. package/dist/react/navigation.d.ts +13 -0
  51. package/dist/react/navigation.d.ts.map +1 -0
  52. package/dist/react/navigation.js +7 -0
  53. package/dist/react/navigation.js.map +1 -0
  54. package/dist/react/platformSession.d.ts +16 -0
  55. package/dist/react/platformSession.d.ts.map +1 -0
  56. package/dist/react/platformSession.js +28 -0
  57. package/dist/react/platformSession.js.map +1 -0
  58. package/dist/react/platformSession.web.d.ts +35 -0
  59. package/dist/react/platformSession.web.d.ts.map +1 -0
  60. package/dist/react/platformSession.web.js +148 -0
  61. package/dist/react/platformSession.web.js.map +1 -0
  62. package/dist/react/replayPlayer.d.ts +74 -0
  63. package/dist/react/replayPlayer.d.ts.map +1 -0
  64. package/dist/react/replayPlayer.js +279 -0
  65. package/dist/react/replayPlayer.js.map +1 -0
  66. package/dist/react/shopifyProviders.d.ts +69 -0
  67. package/dist/react/shopifyProviders.d.ts.map +1 -0
  68. package/dist/react/shopifyProviders.js +100 -0
  69. package/dist/react/shopifyProviders.js.map +1 -0
  70. package/dist/react/useAccountName.d.ts +8 -0
  71. package/dist/react/useAccountName.d.ts.map +1 -0
  72. package/dist/react/useAccountName.js +49 -0
  73. package/dist/react/useAccountName.js.map +1 -0
  74. package/dist/react/useClipsPage.d.ts +47 -0
  75. package/dist/react/useClipsPage.d.ts.map +1 -0
  76. package/dist/react/useClipsPage.js +130 -0
  77. package/dist/react/useClipsPage.js.map +1 -0
  78. package/dist/react/useKeepScreenAwake.d.ts +2 -0
  79. package/dist/react/useKeepScreenAwake.d.ts.map +1 -0
  80. package/dist/react/useKeepScreenAwake.js +34 -0
  81. package/dist/react/useKeepScreenAwake.js.map +1 -0
  82. package/dist/react/useLiveAuction.d.ts +106 -0
  83. package/dist/react/useLiveAuction.d.ts.map +1 -0
  84. package/dist/react/useLiveAuction.js +249 -0
  85. package/dist/react/useLiveAuction.js.map +1 -0
  86. package/dist/react/useLiveChat.d.ts +110 -0
  87. package/dist/react/useLiveChat.d.ts.map +1 -0
  88. package/dist/react/useLiveChat.js +209 -0
  89. package/dist/react/useLiveChat.js.map +1 -0
  90. package/dist/react/useLiveGiveawaysAndPolls.d.ts +95 -0
  91. package/dist/react/useLiveGiveawaysAndPolls.d.ts.map +1 -0
  92. package/dist/react/useLiveGiveawaysAndPolls.js +225 -0
  93. package/dist/react/useLiveGiveawaysAndPolls.js.map +1 -0
  94. package/dist/react/useLivePage.d.ts +134 -0
  95. package/dist/react/useLivePage.d.ts.map +1 -0
  96. package/dist/react/useLivePage.js +304 -0
  97. package/dist/react/useLivePage.js.map +1 -0
  98. package/dist/react/useLiveShop.d.ts +103 -0
  99. package/dist/react/useLiveShop.d.ts.map +1 -0
  100. package/dist/react/useLiveShop.js +211 -0
  101. package/dist/react/useLiveShop.js.map +1 -0
  102. package/dist/react/useReplayPage.d.ts +133 -0
  103. package/dist/react/useReplayPage.d.ts.map +1 -0
  104. package/dist/react/useReplayPage.js +565 -0
  105. package/dist/react/useReplayPage.js.map +1 -0
  106. package/dist/showCredit.d.ts +87 -0
  107. package/dist/showCredit.d.ts.map +1 -0
  108. package/dist/showCredit.js +120 -0
  109. package/dist/showCredit.js.map +1 -0
  110. package/dist/showNames.d.ts +11 -0
  111. package/dist/showNames.d.ts.map +1 -1
  112. package/dist/showNames.js +23 -1
  113. package/dist/showNames.js.map +1 -1
  114. package/dist/ui/BubbleFrame.d.ts +38 -0
  115. package/dist/ui/BubbleFrame.d.ts.map +1 -0
  116. package/dist/ui/BubbleFrame.js +181 -0
  117. package/dist/ui/BubbleFrame.js.map +1 -0
  118. package/dist/ui/LiveBubble.d.ts +37 -0
  119. package/dist/ui/LiveBubble.d.ts.map +1 -0
  120. package/dist/ui/LiveBubble.js +101 -0
  121. package/dist/ui/LiveBubble.js.map +1 -0
  122. package/dist/ui/ReplayBubble.d.ts +23 -0
  123. package/dist/ui/ReplayBubble.d.ts.map +1 -0
  124. package/dist/ui/ReplayBubble.js +65 -0
  125. package/dist/ui/ReplayBubble.js.map +1 -0
  126. package/dist/ui.d.ts +27 -0
  127. package/dist/ui.d.ts.map +1 -0
  128. package/dist/ui.js +34 -0
  129. package/dist/ui.js.map +1 -0
  130. package/package.json +36 -5
  131. package/ui/package.json +6 -0
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useLivePage = useLivePage;
4
+ /**
5
+ * The Live screen's page model (0.14.0, moved from amore-v2's `src/core/hooks/useLivePage.ts`:
6
+ * Freckled Poppy's Live, phase 1, watching and the in-app bubble; 0.15.0 adds its links and the cart
7
+ * hold's timer, from amore-v2's `eng928/integration`). The routes are the app's (`LiveSellingProvider`'s
8
+ * `routes`); the route's `streamId` param is read here.
9
+ */
10
+ const sdk_analytics_core_1 = require("@tiledev/sdk-analytics-core");
11
+ const sdk_shopify_1 = require("@tiledev/sdk-shopify");
12
+ const react_1 = require("react");
13
+ const react_native_1 = require("react-native");
14
+ const client_1 = require("../client");
15
+ const hiddenShows_1 = require("../hiddenShows");
16
+ const liveSelling_1 = require("../liveSelling");
17
+ const linkLots_1 = require("../linkLots");
18
+ const livePages_1 = require("../livePages");
19
+ const pageOptions_1 = require("../pageOptions");
20
+ const sessionTypes_1 = require("../sessionTypes");
21
+ const LiveSellingProvider_1 = require("./LiveSellingProvider");
22
+ const platformSession_1 = require("./platformSession");
23
+ const replayPlayer_1 = require("./replayPlayer");
24
+ const useKeepScreenAwake_1 = require("./useKeepScreenAwake");
25
+ const useLiveChat_1 = require("./useLiveChat");
26
+ const useStreamInfo_1 = require("./useStreamInfo");
27
+ const navigation_1 = require("./navigation");
28
+ /**
29
+ * Shows already reported as joined (`liveJoin`) in this run of the app: once per show per run, so a
30
+ * trip through the bubble, the Cart or another screen and back isn't a second join (amore-v2's audit,
31
+ * L5: production reported on every viewer-count tick).
32
+ */
33
+ const joinedThisRun = new Set();
34
+ /**
35
+ * Everything the Live screen wires, so the screen stays plain tiles. Call it from the Live screen and
36
+ * from each of its tiles' wiring: every call reads the same session.
37
+ *
38
+ * - **The session is the app's** (`ShopifyLiveSessionProvider`), joined above the navigator; this
39
+ * screen binds to its picture (the player tile's `LiveVideoTarget`) and never owns the room.
40
+ * - **Pinned to the route's show** while watching (`holdStream(streamId)`, at every arrival), so a host
41
+ * restarting the broadcast can't swap the room underneath; released when the shopper closes the show
42
+ * (back on a show that has ended or is still joining, ✕ on the bubble, or leaving any other way
43
+ * without the bubble), and kept when the bubble takes the show.
44
+ * - **Which show** (`useLiveShow`): the session's record once it is this show's (just after the pin it
45
+ * can still hold the last show's), where it stands, and whether it is on air.
46
+ * - **Where the link lands** (`streams.destinationFor`, one read of the show's record on arrival): a
47
+ * show on air stays; an ended show with a recording is replaced by its Replay
48
+ * (`routes.replaceWithReplay`); anything else (a rehearsal this shopper can't see included) by the
49
+ * Live tab (`routes.backToLiveTab`). Not on the web, where nothing can play: the Tile preview stays on
50
+ * this page to show its tiles, with the record's poster and the ended words.
51
+ * - **Every arrival** reads the record again (`refreshStreamRecords`, which restarts the session's
52
+ * off-air wait, so a push tapped in the foreground can't be declared over on a stale record) and ends
53
+ * the bubble: this screen shows the picture again.
54
+ * - **Back, every kind** (the header's arrow, the iOS swipe, Android's back; decided 2026-10-05,
55
+ * amore-v2's Head of Engineering) shrinks a show that is playing or waiting for its host into the
56
+ * bubble as the screen leaves, and closes one that has ended. One path: the screen's `beforeRemove`,
57
+ * for the navigation's back actions (`BACK_ACTIONS`). Picture-in-picture is a back that always
58
+ * shrinks; the cart shrinks the show and opens the Cart over this screen (Items You Won on an auction
59
+ * show: `routes.openCart`). Android's back with nothing behind this screen (a link on a cold start)
60
+ * does what the arrow does: back to the Live tab.
61
+ * - **A link from the show** (`openLink`, 0.15.0; decided 2026-10-19 by amore-v2's Head of Engineering)
62
+ * opens inside the app, never the phone's browser: the show goes into the bubble, as for the cart, and
63
+ * the app's `routes.openLink` opens the page (amore-v2: the store's product or collection on its
64
+ * screen, any other page in its web page). Leaving the app for the phone's browser is what left the
65
+ * player dark on the way back (ENG-629) and the phone's window blank (ENG-580). A link that isn't https
66
+ * (`opensInApp`), or an app without `routes.openLink`, opens nothing, and the show stays.
67
+ * - **The cart's holds** (0.15.0, amore-v2's ENG-691): the header shows a timer under the cart button in
68
+ * the soonest hold's last minutes; this hands it when each hold ends (`header.holdEndTimes`,
69
+ * `holdEndTimesOf` over sdk-shopify's cart and its `cartExtensions`), and the header counts.
70
+ * - **One shrunk show at a time:** arriving here stops a replay's bubble (and the Replay screen stops
71
+ * this show's bubble).
72
+ * - **The screen stays on** while it shows the show playing or waiting for its host.
73
+ * - **Under a sheet** (`routes.sheets`: the variant page, opened from the shop; the Sign In page) the
74
+ * show plays on here, with the screen on and the light status bar, as Replay's does.
75
+ * - **Put away** while the show plays here (a sheet over it included), it goes on in the phone's own
76
+ * floating window (`systemWindowWhenAway`); coming back finds it here again.
77
+ * - **`liveJoin`** (`track`) once per show per app run; never for a rehearsal, a show the config's
78
+ * `hiddenShows` names, whoever watches it.
79
+ * - **Hidden shows** (`hiddenShows`): for a shopper who isn't on the team the session never holds one,
80
+ * so it is never on air here (the link goes to the Live tab).
81
+ * - **Chat and reactions** are `useLiveChat`'s, shown only while the show is on air; a host's or
82
+ * moderator's link in the chat opens through `openLink`.
83
+ */
84
+ function useLivePage() {
85
+ var _a, _b, _c, _d;
86
+ const nav = (0, navigation_1.useNavigation)();
87
+ const route = (0, navigation_1.useRoute)();
88
+ const streamId = (_b = (_a = route.params) === null || _a === void 0 ? void 0 : _a.streamId) !== null && _b !== void 0 ? _b : '';
89
+ const isFocused = (0, navigation_1.useIsFocused)();
90
+ const { routes, track, canOpenLinks } = (0, LiveSellingProvider_1.useLivePageOptions)();
91
+ // The session changes only on the room's events, never on a clock: the header and the auction tiles keep their own.
92
+ const session = (0, platformSession_1.useLiveSession)();
93
+ const { holdStream, releaseStream, enterPip, exitPip, setMuted } = session.actions;
94
+ const { viewerEmail: email } = (0, LiveSellingProvider_1.useLiveSelling)();
95
+ const { show: sessionShow, status, onAir } = (0, platformSession_1.useLiveShow)(streamId);
96
+ const { cart: { cart, itemCount }, cartPage: { extensions: cartExtensions }, } = (0, sdk_shopify_1.useShopify)();
97
+ const holdEndTimes = (0, react_1.useMemo)(() => (0, livePages_1.holdEndTimesOf)(cart, cartExtensions), [cart, cartExtensions]);
98
+ const { bubbleShown: replayInBubble, stop: stopReplay } = (0, replayPlayer_1.useReplayPlayer)();
99
+ // ─── Which show ────────────────────────────────────────────────────────────────────────────────
100
+ // `sessionShow` (above) is the session's record once it is this show's. The record the link's answer
101
+ // was read from stands in for its poster until then, and on the web.
102
+ const [linkedShow, setLinkedShow] = (0, react_1.useState)(null);
103
+ const show = sessionShow !== null && sessionShow !== void 0 ? sessionShow : (linkedShow && linkedShow.streamingId === streamId ? linkedShow : null);
104
+ /** The screen is leaving for good (closed, or sent on by the link's answer): going doesn't shrink the show. */
105
+ const leavingForGood = (0, react_1.useRef)(false);
106
+ // ─── Where the link lands ──────────────────────────────────────────────────────────────────────
107
+ (0, react_1.useEffect)(() => {
108
+ if (!streamId)
109
+ return;
110
+ let stillHere = true;
111
+ void liveSelling_1.liveSelling.streams.destinationFor(streamId, { viewerEmail: email }).then(({ destination, show: record, readError }) => {
112
+ if (readError)
113
+ (0, pageOptions_1.reportLiveWarning)(readError, { at: 'live.destinationFor', streamId });
114
+ if (!stillHere)
115
+ return;
116
+ setLinkedShow(record);
117
+ if (react_native_1.Platform.OS === 'web' || destination.to === 'livePlayer')
118
+ return;
119
+ leavingForGood.current = true;
120
+ if (destination.to === 'replay')
121
+ routes.replaceWithReplay(destination.feedId, nav);
122
+ // Back to the tabs already in the stack, or in this screen's place when it opened alone (a link on a cold start).
123
+ else
124
+ routes.backToLiveTab(nav);
125
+ });
126
+ return () => {
127
+ stillHere = false;
128
+ };
129
+ }, [streamId, email, nav, routes]);
130
+ // ─── Arriving ──────────────────────────────────────────────────────────────────────────────────
131
+ (0, navigation_1.useFocusEffect)((0, react_1.useCallback)(() => {
132
+ holdStream(streamId || undefined);
133
+ (0, useStreamInfo_1.refreshStreamRecords)();
134
+ exitPip();
135
+ }, [streamId, holdStream, exitPip]));
136
+ (0, react_1.useEffect)(() => {
137
+ if (isFocused && replayInBubble)
138
+ stopReplay();
139
+ }, [isFocused, replayInBubble, stopReplay]);
140
+ // ─── Leaving ───────────────────────────────────────────────────────────────────────────────────
141
+ /** The show went into the bubble on the way out: leaving keeps it playing there, pinned. */
142
+ const shrunk = (0, react_1.useRef)(false);
143
+ (0, react_1.useEffect)(() => {
144
+ if (!isFocused)
145
+ return;
146
+ shrunk.current = false;
147
+ leavingForGood.current = false;
148
+ }, [isFocused]);
149
+ const pipModeNow = (0, react_1.useRef)(session.pipMode);
150
+ pipModeNow.current = session.pipMode;
151
+ // Gone without the bubble (back on an ended show, replaced by the Replay or the Live tab): the show
152
+ // stops and the pin goes. Not when the bubble took it.
153
+ (0, react_1.useEffect)(() => () => {
154
+ if (shrunk.current || pipModeNow.current !== 'none')
155
+ return;
156
+ exitPip({ stopVideo: true });
157
+ releaseStream();
158
+ }, [exitPip, releaseStream]);
159
+ // ─── Where the show stands ─────────────────────────────────────────────────────────────────────
160
+ // `status` and `onAir` are `useLiveShow`'s: joining until the session holds this show's record. The
161
+ // controls follow the link's record until then (an auction's cart is Items You Won from the start).
162
+ const capabilities = (0, sessionTypes_1.capabilitiesFor)(show);
163
+ const canShrink = capabilities.canPip && onAir;
164
+ // On show, or covered only by a page drawn as a sheet (the variant page, from the shop): the picture
165
+ // stays here, playing behind it, and the screen stays on.
166
+ const coveredOnlyBySheet = (0, navigation_1.useNavigationState)((state) => (0, livePages_1.isCoveredOnlyBySheet)(state, route.key, routes.sheets));
167
+ const onScreen = isFocused || coveredOnlyBySheet;
168
+ const showing = onScreen && session.pipMode === 'none';
169
+ // ─── Leaving for another page, the show playing on in the bubble ───────────────────────────────
170
+ /**
171
+ * The show goes into the app's own bubble (the session's `enterPip`: `pipMode` `inapp`, `LiveBubble`;
172
+ * never the phone's window, which only the phone opens as the app is put away) before a page opens over
173
+ * this screen, so it plays on there; not while it is joining or has ended. Coming back here (back, the
174
+ * bubble's tap, Android's back) ends the bubble as the screen focuses (above).
175
+ */
176
+ const shrinkForAnotherPage = (0, react_1.useCallback)(() => {
177
+ if (!canShrink)
178
+ return;
179
+ shrunk.current = true;
180
+ enterPip();
181
+ }, [canShrink, enterPip]);
182
+ /** A link from the show: its page inside the app, the show in the bubble. Nothing for one that can't open. */
183
+ const openLink = (0, react_1.useCallback)((url, title) => {
184
+ if (!canOpenLinks || !(0, linkLots_1.opensInApp)(url))
185
+ return;
186
+ shrinkForAnotherPage();
187
+ routes.openLink(url.trim(), title, nav);
188
+ }, [canOpenLinks, shrinkForAnotherPage, routes, nav]);
189
+ // Chat and reactions: only while this show is on air. Its own hook (`useLiveChat`).
190
+ const chat = (0, useLiveChat_1.useLiveChat)({
191
+ onAir,
192
+ canComment: capabilities.canComment,
193
+ canReact: capabilities.canReact,
194
+ openLink,
195
+ auction: capabilities.canBid,
196
+ });
197
+ // Every back press (`BACK_ACTIONS`) passes here as the screen goes: a show on air enters the bubble,
198
+ // then the screen is let go. Nothing is prevented.
199
+ const canShrinkNow = (0, react_1.useRef)(canShrink);
200
+ canShrinkNow.current = canShrink;
201
+ (0, react_1.useEffect)(() => nav.addListener('beforeRemove', (event) => {
202
+ if (!livePages_1.BACK_ACTIONS.has(event.data.action.type))
203
+ return;
204
+ if (leavingForGood.current || !canShrinkNow.current || pipModeNow.current !== 'none')
205
+ return;
206
+ shrunk.current = true;
207
+ enterPip();
208
+ }), [nav, enterPip]);
209
+ (0, useKeepScreenAwake_1.useKeepScreenAwake)(showing && onAir, 'live');
210
+ // ─── liveJoin, once per show per app run ───────────────────────────────────────────────────────
211
+ const viewerCount = session.viewerCount;
212
+ (0, react_1.useEffect)(() => {
213
+ if (!isFocused || !sessionShow || sessionShow.status !== 'live' || (0, hiddenShows_1.isHiddenShow)(sessionShow, (0, client_1.hiddenShowsRule)()))
214
+ return;
215
+ if (joinedThisRun.has(sessionShow.streamingId))
216
+ return;
217
+ joinedThisRun.add(sessionShow.streamingId);
218
+ track(sdk_analytics_core_1.DefaultEvents.LIVE_JOIN, (0, sdk_analytics_core_1.liveJoinParams)(sessionShow.streamingId, viewerCount));
219
+ }, [isFocused, sessionShow, viewerCount, track]);
220
+ // ─── The header's buttons ──────────────────────────────────────────────────────────────────────
221
+ /** Back: to the screen behind, or to the Live tab when this one opened alone. A show on air shrinks on the way (above). */
222
+ const goBack = (0, react_1.useCallback)(() => {
223
+ if (nav.canGoBack())
224
+ nav.goBack();
225
+ else
226
+ routes.backToLiveTab(nav);
227
+ }, [nav, routes]);
228
+ const close = (0, react_1.useCallback)(() => {
229
+ leavingForGood.current = true;
230
+ // Stopped outright: without `stopVideo` the room plays on with no surface.
231
+ exitPip({ stopVideo: true });
232
+ releaseStream();
233
+ goBack();
234
+ }, [exitPip, releaseStream, goBack]);
235
+ const back = canShrink ? goBack : close;
236
+ // Android's back with nothing behind this screen (a link on a cold start) would close the app: it does
237
+ // what the arrow does instead. With a screen behind, the navigator goes back, through `beforeRemove`.
238
+ const backNow = (0, react_1.useRef)(back);
239
+ backNow.current = back;
240
+ (0, navigation_1.useFocusEffect)((0, react_1.useCallback)(() => {
241
+ const subscription = react_native_1.BackHandler.addEventListener('hardwareBackPress', () => {
242
+ if (nav.canGoBack())
243
+ return false;
244
+ backNow.current();
245
+ return true;
246
+ });
247
+ return () => subscription.remove();
248
+ }, [nav]));
249
+ const isAuction = capabilities.canBid;
250
+ const openCart = (0, react_1.useCallback)(() => {
251
+ shrinkForAnotherPage();
252
+ // A bidder's cart is what they've won: their bids never land in the shopping cart (Freckled Poppy's).
253
+ routes.openCart({ itemsYouWon: isAuction }, nav);
254
+ }, [shrinkForAnotherPage, isAuction, nav, routes]);
255
+ // One surface at a time: not while the bubble or the phone's own window has it, or another screen is over this one.
256
+ const videoActive = showing && !!sessionShow;
257
+ return {
258
+ /**
259
+ * Android's own picture-in-picture window is up. It shrinks the whole app, and every sheet on the
260
+ * Live screen (poll, giveaway, shop, custom bid, name, reactions) is a window of its own above the
261
+ * app, so it rode the shrink and covered the video (fixed 2026-10-08; Freckled Poppy hides its
262
+ * sheets the same way). The screen then draws only the player; the sheets' open state is the
263
+ * hooks', so they come back. iOS's window shows the video alone.
264
+ */
265
+ inSystemWindow: react_native_1.Platform.OS === 'android' && session.pipMode === 'system',
266
+ /** The screen is on show (or under a sheet), over the dark video: light status bar text. */
267
+ lightStatusBar: onScreen,
268
+ player: {
269
+ status,
270
+ posterUrl: (_c = show === null || show === void 0 ? void 0 : show.thumbnailUrl) !== null && _c !== void 0 ? _c : null,
271
+ isAuction: !!(show === null || show === void 0 ? void 0 : show.isAuction),
272
+ videoActive,
273
+ // Put away while the show plays here, it goes on in the phone's own floating window. Not while
274
+ // joining, waiting for the host or ended: there is no picture.
275
+ systemWindowWhenAway: videoActive && status === 'playing' && capabilities.canPip,
276
+ },
277
+ header: {
278
+ ended: status === 'ended',
279
+ // An auction show: the header's own LIVE words for one (sparkl-v2's and k-marie-v2's LiveHeader01 `auctionLiveLabel`).
280
+ isAuction: !!(show === null || show === void 0 ? void 0 : show.isAuction),
281
+ // The header counts its clock up from it on its own (`useShowClock`), so the screen isn't drawn each second.
282
+ startedAt: (_d = sessionShow === null || sessionShow === void 0 ? void 0 : sessionShow.startedAtMs) !== null && _d !== void 0 ? _d : null,
283
+ // Known once the room has said: 0 means it hasn't yet.
284
+ viewerCount: onAir && capabilities.showViewerCount && viewerCount > 0 ? viewerCount : null,
285
+ muted: session.muted,
286
+ canMute: status !== 'ended' && status !== 'error',
287
+ canPip: canShrink,
288
+ backShrinks: canShrink,
289
+ cartCount: itemCount,
290
+ // The hold timer under the cart button counts down to the soonest of these on its own (0.15.0).
291
+ holdEndTimes,
292
+ onBack: back,
293
+ onToggleMute: () => setMuted(!session.muted),
294
+ // Shown only while the show can shrink: a back press, which shrinks it on the way.
295
+ onPip: goBack,
296
+ onCart: openCart,
297
+ },
298
+ /** The chat, the comment box, reactions and the pinned comment: one set of props per tile (`useLiveChat`). */
299
+ chat,
300
+ /** A link from the show (0.15.0): its page inside the app, the show in the bubble. `useLiveShop` takes it. */
301
+ openLink,
302
+ };
303
+ }
304
+ //# sourceMappingURL=useLivePage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLivePage.js","sourceRoot":"","sources":["../../src/react/useLivePage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The Live screen's shopping (0.14.0, moved from amore-v2's `src/core/hooks/useLiveShop.ts`: phase 3 of
3
+ * its "Live player plan", shop and cart; 0.15.0 adds its link lots, from amore-v2's `eng928/integration`).
4
+ * The routes are the app's (`LiveSellingProvider`'s `routes`); the route's `streamId` param is read here.
5
+ */
6
+ import { type Product } from '@tiledev/sdk-shopify';
7
+ import { type ShowLink } from '../linkLots';
8
+ import type { LiveCartChip, LiveFeaturedProduct, LiveShopLink, LiveSoldChip } from '../pageTypes';
9
+ /** What the Live screen hands the shop (0.15.0). */
10
+ export interface LiveShopScreen {
11
+ /**
12
+ * Opens a link the host added inside the app, the show in the bubble: `useLivePage`'s `openLink`, as
13
+ * amore-v2's wiring passes it (`useLiveShop({ openLink: page.openLink })`). Unset: the link opens
14
+ * through `routes.openLink` with the show left where it is.
15
+ */
16
+ openLink?: (url: string, title?: string | null) => void;
17
+ }
18
+ /**
19
+ * The phone's share sheet with an address (a product's page): iOS takes the link as `url`, Android as
20
+ * text. Nothing without one; a dismissed sheet, or none (the web preview without the browser's share),
21
+ * is nothing to report.
22
+ */
23
+ export declare function shareAddress(url: string | null | undefined): Promise<void>;
24
+ /** The phone's share sheet with a product's link (the Live card's and Replay's share): its page on the store (`productShareUrl`). */
25
+ export declare function shareProduct(product: Product): Promise<void>;
26
+ /**
27
+ * The Live screen's shopping, so the screen stays plain tiles. Reads the app's live session, as
28
+ * `useLivePage` does, for the show the route names.
29
+ *
30
+ * - **The featured product** (`productCard`): the session's `activeProduct`, with its lot number
31
+ * (`sellId`; the session re-reads the record when the host features a lot, so a number issued at
32
+ * show time arrives; the card shows it only when its own setting turns it on). A tap on the card
33
+ * opens the product (`openProduct`, below); share opens the phone's share sheet with the product's
34
+ * link (`shareProduct`, old Amore's). On an auction show: where bidding starts, no Buy and no lot
35
+ * badge, no share (decided 2026-10-05, amore-v2's Head of Engineering: "Share icon should be hidden
36
+ * for live auctions"), and "Waiting for the next lot…" while nothing is featured; the round's bid,
37
+ * state and leader are `useLiveAuction`'s.
38
+ * - **The Shop button** (`shopButton`) and its sheet: every product on the show, the featured one first
39
+ * and marked (`featuredFirst`), each with its lot number. A pick opens the product (`openProduct`);
40
+ * quick add as everywhere. On an auction show too: there its sheet lists the lots instead
41
+ * (`useLiveAuction`), and a pick opens the lot.
42
+ * - **What a tap on a product opens** (`openProduct`; decided 2026-10-05: "Size sheet over show"): the
43
+ * variant page over the playing show (`routes.openVariantPage`). On a live show it is for buying, with
44
+ * the live credit (`liveShowCredit`). On an auction show it is the lot's details in auction mode
45
+ * (`auctionLotPageParams`): the product page's auction notice, no Add to Cart, no credit and no
46
+ * announcement; the shopper bids from the show.
47
+ * - **Buying goes through the variant page**, over the playing show, as Replay's products do. Every add
48
+ * from here carries the live credit and, once it lands, is announced to the room
49
+ * (`announceToLiveRoom`, which the app's variant page hands `reportShowAdd`; quick add does it
50
+ * itself). Signed out, shopping is open, as Freckled Poppy's.
51
+ * - **Links the host added** (0.15.0; amore-v2, 2026-10-19: lots that are web addresses, mostly affiliate
52
+ * links, `showLinkOf`). The session hands them over among the products, in the host's order, with a
53
+ * title, a price (in the shop's currency: the session gives none), a photo and the address, and no
54
+ * product (`raw`). Featured, the card shows it with Open in place of Buy (`isLink`), the price, no
55
+ * star, on any show (never "Waiting for the next lot…"); in the Shop sheet it is a card among the
56
+ * products (`LiveShopLink`: no star, no Add to Cart). A tap opens it inside the app with the show in the
57
+ * bubble (the screen's `openLink`); share shares its address. A link that isn't https, or an app with no
58
+ * `routes.openLink`, is shown but opens nothing (`url` null, `canOpen` false).
59
+ * - **The room's chips:** "just sold" (`session.sold`) and "added to cart" (`session.cartAnnouncements`,
60
+ * not on an auction show, as Freckled Poppy's). A name the room sent is shown by its first word
61
+ * (`firstNameOf`); the session hands out no name as an email.
62
+ * - **Nothing shows** until the session holds this show's record (`useLiveShow`). It never holds a
63
+ * hidden show the shopper can't see (`hiddenShows`). The web's session is always "ended" with no
64
+ * show, so none of these tiles draw there.
65
+ */
66
+ export declare function useLiveShop(screen?: LiveShopScreen): {
67
+ productCard: {
68
+ visible: boolean;
69
+ product: LiveFeaturedProduct | null;
70
+ betweenLots: boolean;
71
+ canBuy: boolean;
72
+ canShare: boolean;
73
+ favorite: boolean;
74
+ onOpenProduct: () => void;
75
+ onToggleFavorite: () => void;
76
+ onShare: () => void;
77
+ };
78
+ shopButton: {
79
+ visible: boolean;
80
+ /** The products and the links the host added (`LiveShopLink`), in the host's order, the featured one first. */
81
+ products: (Product | ShowLink)[];
82
+ onScreenProductId: string | null;
83
+ lotNumbers: Record<string, string>;
84
+ favoriteIds: string[];
85
+ auctionProductIds: string[];
86
+ onPressProduct: (product: Product) => void;
87
+ onOpenLink: (link: Pick<LiveShopLink, "url" | "title">) => void;
88
+ onToggleFavorite: (product: Product) => undefined;
89
+ onQuickAdd: (product: Product) => void;
90
+ addingProductIds: string[];
91
+ };
92
+ soldChips: {
93
+ visible: boolean;
94
+ chips: LiveSoldChip[];
95
+ };
96
+ cartChips: {
97
+ visible: boolean;
98
+ chips: LiveCartChip[];
99
+ };
100
+ };
101
+ /** What `useLiveShop` hands the Live screen's shop tiles. */
102
+ export type LiveShop = ReturnType<typeof useLiveShop>;
103
+ //# sourceMappingURL=useLiveShop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveShop.d.ts","sourceRoot":"","sources":["../../src/react/useLiveShop.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAuE,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAIzH,OAAO,EAA0B,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAWlG,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhF;AAED,qIAAqI;AACrI,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAElE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,WAAW,CAAC,MAAM,GAAE,cAAmB;;;;;;;;;;;;;;QA+IjD,+GAA+G;;;;;;kCAxFvG,OAAO;2BAQV,IAAI,CAAC,YAAY,EAAE,KAAK,GAAG,OAAO,CAAC;oCAwFZ,OAAO;;;;;;;;;;;;EAQxC;AAED,6DAA6D;AAC7D,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC"}
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shareAddress = shareAddress;
4
+ exports.shareProduct = shareProduct;
5
+ exports.useLiveShop = useLiveShop;
6
+ /**
7
+ * The Live screen's shopping (0.14.0, moved from amore-v2's `src/core/hooks/useLiveShop.ts`: phase 3 of
8
+ * its "Live player plan", shop and cart; 0.15.0 adds its link lots, from amore-v2's `eng928/integration`).
9
+ * The routes are the app's (`LiveSellingProvider`'s `routes`); the route's `streamId` param is read here.
10
+ */
11
+ const sdk_shopify_1 = require("@tiledev/sdk-shopify");
12
+ const react_1 = require("react");
13
+ const react_native_1 = require("react-native");
14
+ const linkLots_1 = require("../linkLots");
15
+ const showCredit_1 = require("../showCredit");
16
+ const showNames_1 = require("../showNames");
17
+ const showLots_1 = require("../showLots");
18
+ const LiveSellingProvider_1 = require("./LiveSellingProvider");
19
+ const platformSession_1 = require("./platformSession");
20
+ const navigation_1 = require("./navigation");
21
+ /**
22
+ * The phone's share sheet with an address (a product's page): iOS takes the link as `url`, Android as
23
+ * text. Nothing without one; a dismissed sheet, or none (the web preview without the browser's share),
24
+ * is nothing to report.
25
+ */
26
+ async function shareAddress(url) {
27
+ if (!url)
28
+ return;
29
+ try {
30
+ await react_native_1.Share.share(react_native_1.Platform.OS === 'ios' ? { url } : { message: url });
31
+ }
32
+ catch {
33
+ // Dismissed, or no share sheet.
34
+ }
35
+ }
36
+ /** The phone's share sheet with a product's link (the Live card's and Replay's share): its page on the store (`productShareUrl`). */
37
+ async function shareProduct(product) {
38
+ await shareAddress((0, sdk_shopify_1.productShareUrl)(product));
39
+ }
40
+ /**
41
+ * The Live screen's shopping, so the screen stays plain tiles. Reads the app's live session, as
42
+ * `useLivePage` does, for the show the route names.
43
+ *
44
+ * - **The featured product** (`productCard`): the session's `activeProduct`, with its lot number
45
+ * (`sellId`; the session re-reads the record when the host features a lot, so a number issued at
46
+ * show time arrives; the card shows it only when its own setting turns it on). A tap on the card
47
+ * opens the product (`openProduct`, below); share opens the phone's share sheet with the product's
48
+ * link (`shareProduct`, old Amore's). On an auction show: where bidding starts, no Buy and no lot
49
+ * badge, no share (decided 2026-10-05, amore-v2's Head of Engineering: "Share icon should be hidden
50
+ * for live auctions"), and "Waiting for the next lot…" while nothing is featured; the round's bid,
51
+ * state and leader are `useLiveAuction`'s.
52
+ * - **The Shop button** (`shopButton`) and its sheet: every product on the show, the featured one first
53
+ * and marked (`featuredFirst`), each with its lot number. A pick opens the product (`openProduct`);
54
+ * quick add as everywhere. On an auction show too: there its sheet lists the lots instead
55
+ * (`useLiveAuction`), and a pick opens the lot.
56
+ * - **What a tap on a product opens** (`openProduct`; decided 2026-10-05: "Size sheet over show"): the
57
+ * variant page over the playing show (`routes.openVariantPage`). On a live show it is for buying, with
58
+ * the live credit (`liveShowCredit`). On an auction show it is the lot's details in auction mode
59
+ * (`auctionLotPageParams`): the product page's auction notice, no Add to Cart, no credit and no
60
+ * announcement; the shopper bids from the show.
61
+ * - **Buying goes through the variant page**, over the playing show, as Replay's products do. Every add
62
+ * from here carries the live credit and, once it lands, is announced to the room
63
+ * (`announceToLiveRoom`, which the app's variant page hands `reportShowAdd`; quick add does it
64
+ * itself). Signed out, shopping is open, as Freckled Poppy's.
65
+ * - **Links the host added** (0.15.0; amore-v2, 2026-10-19: lots that are web addresses, mostly affiliate
66
+ * links, `showLinkOf`). The session hands them over among the products, in the host's order, with a
67
+ * title, a price (in the shop's currency: the session gives none), a photo and the address, and no
68
+ * product (`raw`). Featured, the card shows it with Open in place of Buy (`isLink`), the price, no
69
+ * star, on any show (never "Waiting for the next lot…"); in the Shop sheet it is a card among the
70
+ * products (`LiveShopLink`: no star, no Add to Cart). A tap opens it inside the app with the show in the
71
+ * bubble (the screen's `openLink`); share shares its address. A link that isn't https, or an app with no
72
+ * `routes.openLink`, is shown but opens nothing (`url` null, `canOpen` false).
73
+ * - **The room's chips:** "just sold" (`session.sold`) and "added to cart" (`session.cartAnnouncements`,
74
+ * not on an auction show, as Freckled Poppy's). A name the room sent is shown by its first word
75
+ * (`firstNameOf`); the session hands out no name as an email.
76
+ * - **Nothing shows** until the session holds this show's record (`useLiveShow`). It never holds a
77
+ * hidden show the shopper can't see (`hiddenShows`). The web's session is always "ended" with no
78
+ * show, so none of these tiles draw there.
79
+ */
80
+ function useLiveShop(screen = {}) {
81
+ var _a, _b, _c, _d, _e, _f;
82
+ const nav = (0, navigation_1.useNavigation)();
83
+ const streamId = (_b = (_a = (0, navigation_1.useRoute)().params) === null || _a === void 0 ? void 0 : _a.streamId) !== null && _b !== void 0 ? _b : '';
84
+ const { routes, track, canOpenLinks } = (0, LiveSellingProvider_1.useLivePageOptions)();
85
+ const screenOpenLink = screen.openLink;
86
+ // The session changes only on the room's events, never on a clock.
87
+ const session = (0, platformSession_1.useLiveSession)();
88
+ const wishlist = (0, sdk_shopify_1.useWishlist)();
89
+ // The session's record once it is this show's: right after the pin it can still hold the last show's.
90
+ const { show, onAir, capabilities } = (0, platformSession_1.useLiveShow)(streamId);
91
+ const hidden = !show;
92
+ const isAuction = capabilities.canBid;
93
+ // ─── The products and links ────────────────────────────────────────────────────────────────────
94
+ const featured = show ? session.activeProduct : null;
95
+ const featuredProduct = (_c = featured === null || featured === void 0 ? void 0 : featured.raw) !== null && _c !== void 0 ? _c : null;
96
+ // A link the host featured: a web address, no product of the store.
97
+ const featuredLink = (0, react_1.useMemo)(() => (featured && !featured.raw && featured.externalUrl ? (0, linkLots_1.showLinkOf)(featured, { canOpen: canOpenLinks }) : null), [featured, canOpenLinks]);
98
+ const featuredId = (_e = (_d = featuredProduct === null || featuredProduct === void 0 ? void 0 : featuredProduct.id) !== null && _d !== void 0 ? _d : featuredLink === null || featuredLink === void 0 ? void 0 : featuredLink.id) !== null && _e !== void 0 ? _e : null;
99
+ /**
100
+ * The show's Shopify products and the links the host added, in the host's order, the featured one
101
+ * first: the shopper who taps Shop wants what the host holds up.
102
+ */
103
+ const shopItems = (0, react_1.useMemo)(() => (0, showLots_1.featuredFirst)(session.products.flatMap((lot) => lot.raw ? [lot.raw] : lot.externalUrl ? [(0, linkLots_1.showLinkOf)(lot, { canOpen: canOpenLinks })] : []), featuredId), [session.products, featuredId, canOpenLinks]);
104
+ const products = (0, react_1.useMemo)(() => shopItems.filter((item) => !(0, linkLots_1.isShowLink)(item)), [shopItems]);
105
+ /** Each lot's number, by product id (a link's own id): the number the host reads out. */
106
+ const lotNumbers = (0, react_1.useMemo)(() => Object.fromEntries(session.products.flatMap((lot) => {
107
+ var _a, _b;
108
+ const id = (_b = (_a = lot.raw) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : (lot.externalUrl ? lot.id : null);
109
+ return id && lot.sellId ? [[id, lot.sellId]] : [];
110
+ })), [session.products]);
111
+ const auctionProductIds = (0, react_1.useMemo)(() => products.filter(sdk_shopify_1.isAuctioned).map((product) => product.id), [products]);
112
+ // ─── Buying ────────────────────────────────────────────────────────────────────────────────────
113
+ const creditFor = (0, react_1.useCallback)((product) => { var _a; return (0, showCredit_1.liveShowCredit)(show, (_a = lotNumbers[product.id]) !== null && _a !== void 0 ? _a : null); }, [show, lotNumbers]);
114
+ const quickAdd = (0, sdk_shopify_1.useQuickAdd)((0, showCredit_1.showQuickAddOptions)((params) => routes.openVariantPage(params, nav), { credit: creditFor, track }));
115
+ const openVariantPage = (0, react_1.useCallback)((product) => routes.openVariantPage((0, showCredit_1.variantPageParams)(product, creditFor(product)), nav), [routes, nav, creditFor]);
116
+ const openLotPage = (0, react_1.useCallback)((product) => routes.openVariantPage((0, showCredit_1.auctionLotPageParams)(product), nav), [routes, nav]);
117
+ /** A tap on a product, on the card or in the Shop sheet: a lot's details on an auction show, else the variant page to buy it. */
118
+ const openProduct = isAuction ? openLotPage : openVariantPage;
119
+ /** A tap on a link the host added: its page inside the app, the show in the bubble. Nothing for one that can't open. */
120
+ const openShowLink = (0, react_1.useCallback)((link) => {
121
+ if (!link.url)
122
+ return;
123
+ if (screenOpenLink)
124
+ screenOpenLink(link.url, link.title);
125
+ else
126
+ routes.openLink(link.url, link.title, nav);
127
+ }, [screenOpenLink, routes, nav]);
128
+ // ─── The featured card ─────────────────────────────────────────────────────────────────────────
129
+ // The lot's opening bid, joined onto the product from the record by the session.
130
+ const startingBid = isAuction && featured ? ((_f = featured.baseBidPrice) !== null && _f !== void 0 ? _f : null) : null;
131
+ const featuredCard = (0, react_1.useMemo)(() => {
132
+ var _a, _b, _c, _d, _e, _f;
133
+ return featuredProduct
134
+ ? {
135
+ id: featuredProduct.id,
136
+ title: featuredProduct.title,
137
+ price: (0, sdk_shopify_1.formatMoney)(featuredProduct.priceRange.min),
138
+ imageUrl: (_d = (_b = (_a = featuredProduct.featuredImage) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : (_c = featuredProduct.images[0]) === null || _c === void 0 ? void 0 : _c.url) !== null && _d !== void 0 ? _d : null,
139
+ // No lot badge on an auction lot: a bidder bids, they don't buy by the number (Freckled Poppy's).
140
+ lotNumber: isAuction ? null : ((_e = featured === null || featured === void 0 ? void 0 : featured.sellId) !== null && _e !== void 0 ? _e : null),
141
+ startingBid: startingBid != null ? (0, sdk_shopify_1.formatMoney)({ amount: String(startingBid), currencyCode: featuredProduct.priceRange.min.currencyCode }) : null,
142
+ }
143
+ : featuredLink
144
+ ? {
145
+ id: featuredLink.id,
146
+ title: featuredLink.title,
147
+ price: featuredLink.price,
148
+ imageUrl: featuredLink.imageUrl,
149
+ lotNumber: isAuction ? null : ((_f = featured === null || featured === void 0 ? void 0 : featured.sellId) !== null && _f !== void 0 ? _f : null),
150
+ startingBid: null,
151
+ isLink: true,
152
+ canOpen: !!featuredLink.url,
153
+ }
154
+ : null;
155
+ }, [featuredProduct, featuredLink, featured === null || featured === void 0 ? void 0 : featured.sellId, isAuction, startingBid]);
156
+ // ─── The room's chips ──────────────────────────────────────────────────────────────────────────
157
+ const soldChips = (0, react_1.useMemo)(() => session.sold.map((card) => ({ id: card.id, quantity: card.quantity, productName: card.productName, lotNumber: card.sellId })), [session.sold]);
158
+ const cartChips = (0, react_1.useMemo)(() => session.cartAnnouncements.map((card) => ({
159
+ id: card.id,
160
+ name: (0, showNames_1.firstNameOf)(card.userName),
161
+ productTitle: card.productTitle,
162
+ lotNumber: card.sellId,
163
+ })), [session.cartAnnouncements]);
164
+ return {
165
+ productCard: {
166
+ visible: !hidden,
167
+ product: featuredCard,
168
+ // An auction has gaps between lots: the slot keeps its place rather than leave the frame empty.
169
+ betweenLots: isAuction && !featuredCard && onAir,
170
+ canBuy: !isAuction,
171
+ // No share on an auction show (decided 2026-10-05, amore-v2's Head of Engineering), nor for a link that opens nothing.
172
+ canShare: !isAuction && (!featuredLink || !!featuredLink.url),
173
+ favorite: !!featuredProduct && wishlist.has(featuredProduct.id),
174
+ onOpenProduct: () => {
175
+ if (featuredProduct)
176
+ openProduct(featuredProduct);
177
+ else if (featuredLink)
178
+ openShowLink(featuredLink);
179
+ },
180
+ onToggleFavorite: () => {
181
+ if (featuredProduct)
182
+ void wishlist.toggle(featuredProduct);
183
+ },
184
+ onShare: () => {
185
+ if (featuredProduct)
186
+ void shareProduct(featuredProduct);
187
+ else if (featuredLink)
188
+ void shareAddress(featuredLink.url);
189
+ },
190
+ },
191
+ shopButton: {
192
+ // On an auction show too: there its sheet lists the lots (`useLiveAuction`'s `shopButton.lots`).
193
+ visible: !hidden,
194
+ /** The products and the links the host added (`LiveShopLink`), in the host's order, the featured one first. */
195
+ products: shopItems,
196
+ onScreenProductId: featuredId,
197
+ lotNumbers,
198
+ favoriteIds: wishlist.ids,
199
+ auctionProductIds,
200
+ onPressProduct: openProduct,
201
+ onOpenLink: openShowLink,
202
+ onToggleFavorite: (product) => void wishlist.toggle(product),
203
+ onQuickAdd: quickAdd.add,
204
+ addingProductIds: quickAdd.addingProductIds,
205
+ },
206
+ soldChips: { visible: !hidden, chips: soldChips },
207
+ // An auction sells by bidding: its room has no carts to announce (Freckled Poppy's).
208
+ cartChips: { visible: !hidden && !isAuction, chips: cartChips },
209
+ };
210
+ }
211
+ //# sourceMappingURL=useLiveShop.js.map