@fluid-app/portal-sdk 0.1.135 → 0.1.136

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 (31) hide show
  1. package/dist/ProductsScreen-C7cXqLN8.cjs +110 -0
  2. package/dist/ProductsScreen-C7cXqLN8.cjs.map +1 -0
  3. package/dist/{ProductsScreen-CbKT2maZ.mjs → ProductsScreen-CTUejNR0.mjs} +2 -2
  4. package/dist/{ProductsScreen-T1tGuiGy.cjs → ProductsScreen-CcF3f9VD.cjs} +2 -2
  5. package/dist/ProductsScreen-Di6uVQCx.mjs +98 -0
  6. package/dist/ProductsScreen-Di6uVQCx.mjs.map +1 -0
  7. package/dist/ShareablesScreen-B-uZ3B5d.cjs +430 -0
  8. package/dist/ShareablesScreen-B-uZ3B5d.cjs.map +1 -0
  9. package/dist/{ShareablesScreen-DSW36iS7.mjs → ShareablesScreen-BHyxG-oy.mjs} +2 -2
  10. package/dist/{ShareablesScreen-BLbzr0Jb.cjs → ShareablesScreen-DAM01cxf.cjs} +2 -2
  11. package/dist/ShareablesScreen-iBUd6p7M.mjs +412 -0
  12. package/dist/ShareablesScreen-iBUd6p7M.mjs.map +1 -0
  13. package/dist/index.cjs +7 -7
  14. package/dist/index.d.cts.map +1 -1
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +7 -7
  17. package/dist/{src-BbjxT3sc.mjs → portal-tenant-product-media-adapter-Co9Kw-US.mjs} +980 -4
  18. package/dist/portal-tenant-product-media-adapter-Co9Kw-US.mjs.map +1 -0
  19. package/dist/{src-DmzXXBVt.cjs → portal-tenant-product-media-adapter-DM94zJXA.cjs} +1039 -3
  20. package/dist/portal-tenant-product-media-adapter-DM94zJXA.cjs.map +1 -0
  21. package/package.json +16 -16
  22. package/dist/ProductsScreen-B1OAGNQx.cjs +0 -283
  23. package/dist/ProductsScreen-B1OAGNQx.cjs.map +0 -1
  24. package/dist/ProductsScreen-CL71MQNL.mjs +0 -271
  25. package/dist/ProductsScreen-CL71MQNL.mjs.map +0 -1
  26. package/dist/ShareablesScreen-CecBPoFO.mjs +0 -1360
  27. package/dist/ShareablesScreen-CecBPoFO.mjs.map +0 -1
  28. package/dist/ShareablesScreen-DDutXKpW.cjs +0 -1378
  29. package/dist/ShareablesScreen-DDutXKpW.cjs.map +0 -1
  30. package/dist/src-BbjxT3sc.mjs.map +0 -1
  31. package/dist/src-DmzXXBVt.cjs.map +0 -1
@@ -1,1360 +0,0 @@
1
- import { et as USER_TYPES, n as useFluidContext, u as usePortalTenantClient, yt as createFetchClient } from "./FluidProvider-Dd2M4mMV.mjs";
2
- import { t as useFluidAuth } from "./use-fluid-auth-CU2oy-C8.mjs";
3
- import { n as useCurrentUser } from "./use-current-user-DxFplFVa.mjs";
4
- import { n as useAppNavigation } from "./AppNavigationContext-Du3Qq0yc.mjs";
5
- import { i as useSdkClient } from "./use-account-clients-Csy11_yq.mjs";
6
- import { a as ShareablesCoreProvider, i as ShareablesApiProvider, n as ShareablesApp, r as ShareablesUIProvider } from "./src-BbjxT3sc.mjs";
7
- import { t as usePortalProductsClient } from "./use-portal-products-client-BUTk8CR4.mjs";
8
- import { useCallback, useMemo } from "react";
9
- import { jsx } from "react/jsx-runtime";
10
- import { z } from "zod";
11
- //#region src/hooks/use-user-type.ts
12
- /**
13
- * Convenience hook for user-type checks in the portal SDK.
14
- */
15
- function useUserType() {
16
- const { user } = useFluidAuth();
17
- return useMemo(() => {
18
- const userType = user?.user_type ?? null;
19
- return {
20
- userType,
21
- isCustomer: userType === USER_TYPES.customer,
22
- isRep: userType === USER_TYPES.rep,
23
- isAdmin: userType === USER_TYPES.admin || userType === USER_TYPES.root_admin
24
- };
25
- }, [user?.user_type]);
26
- }
27
- //#endregion
28
- //#region ../../file-picker/core/src/schemas/dam.ts
29
- const damVariantSchema = z.object({
30
- id: z.string(),
31
- url: z.string().nullable(),
32
- file_name: z.string(),
33
- mime_type: z.string(),
34
- content: z.any().nullable(),
35
- created_at: z.string(),
36
- updated_at: z.string(),
37
- default: z.boolean(),
38
- is_original: z.boolean(),
39
- is_text: z.boolean(),
40
- media_type: z.string(),
41
- processing_status: z.string(),
42
- tags: z.array(z.string())
43
- });
44
- const damAssetSchema = z.object({
45
- id: z.number(),
46
- canonical_path: z.string(),
47
- category: z.string(),
48
- code: z.string(),
49
- company: z.string(),
50
- created_at: z.string(),
51
- default_variant_id: z.string(),
52
- default_variant_url: z.string().optional(),
53
- description: z.string(),
54
- name: z.string(),
55
- updated_at: z.string(),
56
- variants: z.array(damVariantSchema).optional()
57
- });
58
- const damTreeFolderNodeSchema = z.object({
59
- asset_code: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
60
- name: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
61
- category: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
62
- variants: z.union([z.array(z.unknown()), z.record(z.string(), z.unknown())]).optional()
63
- }).passthrough();
64
- const damTreeSchema = z.record(z.string(), z.union([
65
- z.lazy(() => damTreeSchema),
66
- damAssetSchema,
67
- damTreeFolderNodeSchema
68
- ]));
69
- const damQueryResponseSchema = z.object({
70
- path: z.string(),
71
- tree: damTreeSchema,
72
- meta: z.object({ next_cursor: z.string().optional() }).optional()
73
- });
74
- z.object({ asset: z.object({
75
- file: z.any(),
76
- name: z.string(),
77
- description: z.string().optional(),
78
- tags: z.string().optional()
79
- }) });
80
- z.object({
81
- asset: damAssetSchema,
82
- meta: z.object({
83
- request_id: z.string(),
84
- timestamp: z.string()
85
- })
86
- });
87
- z.object({
88
- placeholder_asset: z.object({
89
- mime_type: z.string(),
90
- name: z.string().optional(),
91
- description: z.string().optional()
92
- }),
93
- skip_autotagging: z.boolean().optional()
94
- });
95
- z.object({
96
- asset: z.object({
97
- file: z.any(),
98
- name: z.string(),
99
- description: z.string().optional(),
100
- tags: z.string().optional()
101
- }).optional(),
102
- text_asset: z.object({
103
- file_name: z.string(),
104
- mime_type: z.string(),
105
- text: z.string(),
106
- name: z.string().optional(),
107
- description: z.string().optional(),
108
- tags: z.string().optional()
109
- }).optional(),
110
- placeholder_asset: z.object({
111
- mime_type: z.string(),
112
- name: z.string().optional(),
113
- description: z.string().optional()
114
- }).optional(),
115
- skip_autotagging: z.boolean().optional()
116
- });
117
- z.object({
118
- asset: z.object({
119
- id: z.number(),
120
- canonical_path: z.string(),
121
- name: z.string()
122
- }),
123
- meta: z.object({
124
- request_id: z.string(),
125
- timestamp: z.string()
126
- })
127
- });
128
- //#endregion
129
- //#region ../../api-clients/portal-tenant-content/src/namespaces/portal_tenant_content.ts
130
- /**
131
- * List media (own uploads and company media)
132
- * Returns a paginated list of the member's own uploads and company-owned media.
133
- *
134
- * @param client - Fetch client instance
135
- * @param [params] - params
136
- */
137
- async function media_list(client, params) {
138
- return client.get(`/api/content/media`, params);
139
- }
140
- /**
141
- * Create a new media item
142
- * Creates a new media item record.
143
- *
144
- * @param client - Fetch client instance
145
- * @param body - body
146
- */
147
- async function media_create(client, body) {
148
- return client.post(`/api/content/media`, body);
149
- }
150
- /**
151
- * Get a specific media item
152
- * Returns a single media item by ID.
153
- *
154
- * @param client - Fetch client instance
155
- * @param id - id
156
- */
157
- async function media_show(client, id) {
158
- return client.get(`/api/content/media/${id}`);
159
- }
160
- /**
161
- * Update a media item (own uploads only)
162
- * Updates a media item's title or description.
163
- *
164
- * @param client - Fetch client instance
165
- * @param id - id
166
- * @param body - body
167
- */
168
- async function media_update(client, id, body) {
169
- return client.patch(`/api/content/media/${id}`, body);
170
- }
171
- /**
172
- * Delete a media item (own uploads only)
173
- * Removes a media item.
174
- *
175
- * @param client - Fetch client instance
176
- * @param id - id
177
- */
178
- async function media_destroy(client, id) {
179
- return client.delete(`/api/content/media/${id}`);
180
- }
181
- /**
182
- * List playlists with cursor pagination
183
- * Returns a paginated list of playlists.
184
- *
185
- * @param client - Fetch client instance
186
- * @param [params] - params
187
- */
188
- async function playlists_list(client, params) {
189
- return client.get(`/api/content/playlists`, params);
190
- }
191
- /**
192
- * Create a new playlist
193
- * Creates a new playlist.
194
- *
195
- * @param client - Fetch client instance
196
- * @param body - body
197
- */
198
- async function playlists_create(client, body) {
199
- return client.post(`/api/content/playlists`, body);
200
- }
201
- /**
202
- * Get a specific playlist
203
- * Returns a single playlist by ID.
204
- *
205
- * @param client - Fetch client instance
206
- * @param id - id
207
- */
208
- async function playlists_show(client, id) {
209
- return client.get(`/api/content/playlists/${id}`);
210
- }
211
- /**
212
- * Update a playlist
213
- * Updates a playlist's title or metadata.
214
- *
215
- * @param client - Fetch client instance
216
- * @param id - id
217
- * @param body - body
218
- */
219
- async function playlists_update(client, id, body) {
220
- return client.patch(`/api/content/playlists/${id}`, body);
221
- }
222
- /**
223
- * Delete a playlist
224
- * Removes a playlist.
225
- *
226
- * @param client - Fetch client instance
227
- * @param id - id
228
- */
229
- async function playlists_destroy(client, id) {
230
- return client.delete(`/api/content/playlists/${id}`);
231
- }
232
- /**
233
- * List items in a playlist
234
- * Returns a paginated list of items in a playlist.
235
- *
236
- * @param client - Fetch client instance
237
- * @param playlist_id - playlist_id
238
- * @param [params] - params
239
- */
240
- async function playlists_items_list(client, playlist_id, params) {
241
- return client.get(`/api/content/playlists/${playlist_id}/items`, params);
242
- }
243
- /**
244
- * Add an item to a playlist
245
- * Adds a media item to a playlist.
246
- *
247
- * @param client - Fetch client instance
248
- * @param playlist_id - playlist_id
249
- * @param body - body
250
- */
251
- async function playlists_items_add(client, playlist_id, body) {
252
- return client.post(`/api/content/playlists/${playlist_id}/items`, body);
253
- }
254
- /**
255
- * Remove an item from a playlist
256
- * Removes a single item from a playlist.
257
- *
258
- * @param client - Fetch client instance
259
- * @param playlist_id - playlist_id
260
- * @param id - id
261
- */
262
- async function playlists_items_remove(client, playlist_id, id) {
263
- return client.delete(`/api/content/playlists/${playlist_id}/items/${id}`);
264
- }
265
- /**
266
- * List share links for the current user
267
- * Returns a paginated list of share links.
268
- *
269
- * @param client - Fetch client instance
270
- * @param [params] - params
271
- */
272
- async function shares_list(client, params) {
273
- return client.get(`/api/shares`, params);
274
- }
275
- /**
276
- * Create a share link
277
- * Creates a new share link for content.
278
- *
279
- * @param client - Fetch client instance
280
- * @param body - body
281
- */
282
- async function shares_create(client, body) {
283
- return client.post(`/api/shares`, body);
284
- }
285
- /**
286
- * List DAM assets
287
- * Returns a paginated list of DAM assets for the company.
288
- *
289
- * @param client - Fetch client instance
290
- * @param [params] - params
291
- */
292
- async function dam_assets_list(client, params) {
293
- return client.get(`/api/content/dam/assets`, params);
294
- }
295
- /**
296
- * Create a DAM asset
297
- * Creates a new DAM asset. Supports two modes:
298
- 1. **JSON placeholder** — send `application/json` with `asset[name]` to
299
- create a placeholder record for later file upload.
300
-
301
- 2. **File upload** — send `multipart/form-data` with `asset[file]`,
302
- `asset[name]`, and optionally `asset[description]` and `asset[tags]`
303
- to upload a file and create the full asset with variants.
304
- *
305
- * @param client - Fetch client instance
306
- * @param body - body
307
- */
308
- async function dam_assets_create(client, body) {
309
- return client.post(`/api/content/dam/assets`, body);
310
- }
311
- /**
312
- * List paths for a DAM asset
313
- * Returns a paginated list of path aliases for a DAM asset.
314
- *
315
- * @param client - Fetch client instance
316
- * @param asset_code - asset_code
317
- * @param [params] - params
318
- */
319
- async function dam_asset_paths_list(client, asset_code, params) {
320
- return client.get(`/api/content/dam/assets/${asset_code}/paths`, params);
321
- }
322
- /**
323
- * Create a path alias for a DAM asset
324
- * Creates a new path alias for an existing DAM asset.
325
- *
326
- * @param client - Fetch client instance
327
- * @param asset_code - asset_code
328
- * @param body - body
329
- */
330
- async function dam_asset_paths_create(client, asset_code, body) {
331
- return client.post(`/api/content/dam/assets/${asset_code}/paths`, body);
332
- }
333
- /**
334
- * Query DAM assets using tree paths and tags
335
- * Searches and retrieves DAM assets using tree path pattern matching, tag-based variant filtering, wildcard name matching, and partial search. Supports cursor pagination for large result sets.
336
- *
337
- * @param client - Fetch client instance
338
- * @param body - body
339
- */
340
- async function dam_query(client, body) {
341
- return client.post(`/api/content/dam/query`, body);
342
- }
343
- /**
344
- * Delete a DAM asset
345
- * Permanently destroys a DAM asset, including its ImageKit storage, variants, and database records.
346
- *
347
- * @param client - Fetch client instance
348
- * @param code - code
349
- */
350
- async function dam_assets_destroy(client, code) {
351
- return client.delete(`/api/content/dam/assets/${code}`);
352
- }
353
- /**
354
- * Discard (soft-delete) a DAM asset
355
- * Soft-deletes a DAM asset. Used to discard an in-progress upload without permanently removing the record.
356
- *
357
- * @param client - Fetch client instance
358
- * @param code - code
359
- */
360
- async function dam_assets_discard(client, code) {
361
- return client.patch(`/api/content/dam/assets/${code}/discard`);
362
- }
363
- //#endregion
364
- //#region ../../shareables/api-client/src/portal-tenant-media-adapter.ts
365
- /**
366
- * Maps a BFF media object to the port's Media shape, providing defaults
367
- * for optional fields returned by the generated client.
368
- */
369
- function mapMedia(raw) {
370
- return {
371
- id: raw.id ?? 0,
372
- title: raw.title ?? "",
373
- description: raw.description ?? null,
374
- media_type: raw.media_type ?? "",
375
- url: raw.url ?? null,
376
- thumbnail_url: raw.thumbnail_url ?? null,
377
- owner_type: raw.owner_type ?? "",
378
- created_at: raw.created_at ?? "",
379
- updated_at: raw.updated_at ?? ""
380
- };
381
- }
382
- /**
383
- * Maps the BFF meta envelope to the port's ApiMeta shape.
384
- */
385
- function mapMeta$3(raw) {
386
- return {
387
- request_id: raw?.request_id ?? null,
388
- timestamp: raw?.timestamp ?? "",
389
- pagination: raw?.pagination ? {
390
- cursor: raw.pagination.cursor ?? null,
391
- limit: raw.pagination.limit,
392
- next_cursor: raw.pagination.next_cursor ?? null,
393
- prev_cursor: raw.pagination.prev_cursor ?? null
394
- } : void 0
395
- };
396
- }
397
- /**
398
- * Creates a ContentMediaApi adapter backed by the portal-tenant content BFF.
399
- *
400
- * Maps the generated portal-tenant-content namespace functions to the abstract
401
- * ContentMediaApi port, closing over the FetchClient so consumers don't need
402
- * to pass it per-call.
403
- */
404
- function createPortalTenantMediaAdapter(client) {
405
- return {
406
- listMedia: async (params) => {
407
- const response = await media_list(client, {
408
- "page[cursor]": params?.cursor,
409
- "page[limit]": params?.limit,
410
- media_type: params?.media_type,
411
- "filter[title]": params?.["filter[title]"],
412
- sort: params?.sort
413
- });
414
- return {
415
- media: (response.media ?? []).map(mapMedia),
416
- meta: mapMeta$3(response.meta)
417
- };
418
- },
419
- createMedia: async (body) => {
420
- const response = await media_create(client, { media: body });
421
- return {
422
- media: mapMedia(response.media ?? {}),
423
- meta: mapMeta$3(response.meta)
424
- };
425
- },
426
- getMedia: async (id) => {
427
- const response = await media_show(client, id);
428
- return {
429
- media: mapMedia(response.media ?? {}),
430
- meta: mapMeta$3(response.meta)
431
- };
432
- },
433
- updateMedia: async (id, body) => {
434
- const response = await media_update(client, id, { media: body });
435
- return {
436
- media: mapMedia(response.media ?? {}),
437
- meta: mapMeta$3(response.meta)
438
- };
439
- },
440
- deleteMedia: async (id) => {
441
- const response = await media_destroy(client, id);
442
- return {
443
- media: { id: response.media?.id ?? 0 },
444
- meta: mapMeta$3(response.meta)
445
- };
446
- }
447
- };
448
- }
449
- function mediaKindFromType$1(mediaType) {
450
- if (mediaType === "video") return "video";
451
- if (mediaType === "image") return "image";
452
- if (mediaType === "document" || mediaType === "pdf") return "pdf";
453
- return null;
454
- }
455
- function toBffMediumResponse(bff) {
456
- const kind = mediaKindFromType$1(bff.media_type);
457
- const isVideo = bff.media_type === "video";
458
- const isPdf = bff.media_type === "pdf" || bff.media_type === "document";
459
- return {
460
- id: bff.id,
461
- user_id: null,
462
- media_type: bff.media_type,
463
- media_format: bff.media_type,
464
- image_url: !isVideo && !isPdf ? bff.url ?? bff.thumbnail_url ?? null : bff.thumbnail_url ?? null,
465
- video_url: isVideo ? bff.url ?? null : null,
466
- pdf_url: isPdf ? bff.url ?? null : null,
467
- title: bff.title,
468
- description: {
469
- id: null,
470
- name: null,
471
- body: bff.description ?? null,
472
- record_type: null,
473
- record_id: null,
474
- created_at: bff.created_at ?? null,
475
- updated_at: bff.updated_at ?? null,
476
- locale: null
477
- },
478
- stripped: bff.description ?? null,
479
- kind,
480
- active: true,
481
- visibility: null,
482
- share_link: null,
483
- views: 0,
484
- leads: 0,
485
- watch: null,
486
- video_status: null,
487
- duration: null,
488
- cta_url: null,
489
- cta_button_text: null,
490
- cta_enabled: false,
491
- cta_action_type: null,
492
- video_shopping_enabled: false,
493
- prompts_enabled: false,
494
- ranks: [],
495
- preview_link: null,
496
- attached_shareables: [],
497
- created_at: bff.created_at
498
- };
499
- }
500
- /**
501
- * Creates a ShareablesApi["media"]-compatible adapter backed by the
502
- * portal-tenant content BFF. Includes cursor-to-page-number caching
503
- * for bridging the legacy UI's page-number pagination.
504
- */
505
- function createPortalTenantMediaShareablesAdapter(client) {
506
- const portAdapter = createPortalTenantMediaAdapter(client);
507
- const cursorByPage = /* @__PURE__ */ new Map();
508
- let lastFilterKey = "";
509
- return {
510
- getMedia: async (options) => {
511
- const pageNumber = options?.page ?? 1;
512
- const filterKey = `${options?.search_query ?? ""}|${options?.sorted_by ?? ""}|${options?.media_type ?? options?.with_type ?? ""}`;
513
- if (filterKey !== lastFilterKey) {
514
- cursorByPage.clear();
515
- lastFilterKey = filterKey;
516
- }
517
- const cursor = pageNumber > 1 ? cursorByPage.get(pageNumber) : void 0;
518
- const rawSort = options?.sorted_by;
519
- let bffSort;
520
- if (rawSort === "title_asc") bffSort = "title_asc";
521
- else if (rawSort === "title_desc") bffSort = "title_desc";
522
- const response = await portAdapter.listMedia({
523
- cursor,
524
- limit: options?.per_page,
525
- media_type: options?.media_type ?? options?.with_type,
526
- "filter[title]": options?.search_query,
527
- sort: bffSort
528
- });
529
- const nextCursor = response.meta.pagination?.next_cursor;
530
- if (nextCursor) cursorByPage.set(pageNumber + 1, nextCursor);
531
- const transformedItems = response.media.map(toBffMediumResponse);
532
- return {
533
- data: transformedItems,
534
- status: "success",
535
- media: transformedItems,
536
- meta: {
537
- total_count: transformedItems.length,
538
- current: pageNumber,
539
- per_page: options?.per_page ?? 24,
540
- pages: nextCursor ? pageNumber + 1 : pageNumber,
541
- next: nextCursor ? pageNumber + 1 : null,
542
- previous: pageNumber > 1 ? pageNumber - 1 : null
543
- }
544
- };
545
- },
546
- getMediaById: async (id) => {
547
- const medium = toBffMediumResponse((await portAdapter.getMedia(id)).media);
548
- return {
549
- data: medium,
550
- status: "success",
551
- media: medium
552
- };
553
- },
554
- createMedia: async (mediaData) => {
555
- return toBffMediumResponse((await portAdapter.createMedia({
556
- title: mediaData.title ?? "",
557
- description: mediaData.description,
558
- media_type: mediaData.media_type ?? "image",
559
- url: mediaData.image_url ?? mediaData.video_url ?? mediaData.pdf_url ?? void 0
560
- })).media);
561
- },
562
- updateMedia: async (id, mediaData) => {
563
- return toBffMediumResponse((await portAdapter.updateMedia(id, {
564
- title: mediaData.title,
565
- description: mediaData.description
566
- })).media);
567
- },
568
- deleteMedia: async (id) => {
569
- await portAdapter.deleteMedia(id);
570
- return { success: true };
571
- }
572
- };
573
- }
574
- //#endregion
575
- //#region ../../shareables/api-client/src/portal-tenant-playlists-adapter.ts
576
- /**
577
- * Maps a BFF playlist object to the port's Playlist shape.
578
- */
579
- function mapPlaylist(raw) {
580
- return {
581
- id: raw.id ?? 0,
582
- title: raw.title ?? "",
583
- description: raw.description ?? null,
584
- items_count: raw.items_count ?? 0,
585
- user_id: raw.user_id,
586
- is_favorited: raw.is_favorited,
587
- image_url: raw.image_url ?? null,
588
- created_at: raw.created_at ?? "",
589
- updated_at: raw.updated_at ?? ""
590
- };
591
- }
592
- /**
593
- * Maps a BFF playlist item to the port's PlaylistItem shape.
594
- */
595
- function mapPlaylistItem(raw) {
596
- return {
597
- id: raw.id ?? 0,
598
- media_id: raw.media_id ?? 0,
599
- position: raw.position ?? null,
600
- title: raw.title,
601
- image_url: raw.image_url ?? null,
602
- media_type: raw.media_type,
603
- video_url: raw.video_url ?? null,
604
- duration: raw.duration ?? null,
605
- created_at: raw.created_at ?? ""
606
- };
607
- }
608
- /**
609
- * Maps the BFF meta envelope to the port's ApiMeta shape.
610
- */
611
- function mapMeta$2(raw) {
612
- return {
613
- request_id: raw?.request_id ?? null,
614
- timestamp: raw?.timestamp ?? "",
615
- pagination: raw?.pagination ? {
616
- cursor: raw.pagination.cursor ?? null,
617
- limit: raw.pagination.limit,
618
- next_cursor: raw.pagination.next_cursor ?? null,
619
- prev_cursor: raw.pagination.prev_cursor ?? null
620
- } : void 0
621
- };
622
- }
623
- /**
624
- * Creates a ContentPlaylistsApi adapter backed by the portal-tenant content BFF.
625
- *
626
- * Maps the generated portal-tenant-content namespace functions to the abstract
627
- * ContentPlaylistsApi port, closing over the FetchClient so consumers don't
628
- * need to pass it per-call.
629
- */
630
- function createPortalTenantPlaylistsAdapter(client) {
631
- return {
632
- listPlaylists: async (params) => {
633
- const response = await playlists_list(client, {
634
- "page[cursor]": params?.cursor,
635
- "page[limit]": params?.limit,
636
- "filter[title]": params?.["filter[title]"],
637
- sort: params?.sort
638
- });
639
- return {
640
- playlists: (response.playlists ?? []).map(mapPlaylist),
641
- meta: mapMeta$2(response.meta)
642
- };
643
- },
644
- createPlaylist: async (body) => {
645
- const response = await playlists_create(client, { playlist: body });
646
- return {
647
- playlist: mapPlaylist(response.playlist ?? {}),
648
- meta: mapMeta$2(response.meta)
649
- };
650
- },
651
- getPlaylist: async (id) => {
652
- const response = await playlists_show(client, id);
653
- return {
654
- playlist: mapPlaylist(response.playlist ?? {}),
655
- meta: mapMeta$2(response.meta)
656
- };
657
- },
658
- updatePlaylist: async (id, body) => {
659
- const response = await playlists_update(client, id, { playlist: body });
660
- return {
661
- playlist: mapPlaylist(response.playlist ?? {}),
662
- meta: mapMeta$2(response.meta)
663
- };
664
- },
665
- deletePlaylist: async (id) => {
666
- const response = await playlists_destroy(client, id);
667
- return {
668
- playlist: { id: response.playlist?.id ?? 0 },
669
- meta: mapMeta$2(response.meta)
670
- };
671
- },
672
- listPlaylistItems: async (playlistId, params) => {
673
- const response = await playlists_items_list(client, playlistId, {
674
- "page[cursor]": params?.cursor,
675
- "page[limit]": params?.limit
676
- });
677
- return {
678
- playlist_items: (response.playlist_items ?? []).map(mapPlaylistItem),
679
- meta: mapMeta$2(response.meta)
680
- };
681
- },
682
- addPlaylistItem: async (playlistId, body) => {
683
- const response = await playlists_items_add(client, playlistId, { item: body });
684
- return {
685
- playlist_item: mapPlaylistItem(response.playlist_item ?? {}),
686
- meta: mapMeta$2(response.meta)
687
- };
688
- },
689
- removePlaylistItem: async (playlistId, itemId) => {
690
- const response = await playlists_items_remove(client, playlistId, itemId);
691
- return {
692
- playlist_item: { id: response.playlist_item?.id ?? 0 },
693
- meta: mapMeta$2(response.meta)
694
- };
695
- }
696
- };
697
- }
698
- function mediaKindFromType(mediaType) {
699
- if (mediaType === "video") return "video";
700
- if (mediaType === "image") return "image";
701
- if (mediaType === "document" || mediaType === "pdf") return "pdf";
702
- return null;
703
- }
704
- function toBffPlaylist(bff, items) {
705
- return {
706
- id: bff.id,
707
- title: bff.title,
708
- description: bff.description ?? null,
709
- image_url: bff.image_url ?? null,
710
- slug: null,
711
- active: true,
712
- user_id: bff.user_id ?? null,
713
- is_favorited: bff.is_favorited ?? false,
714
- items: items ?? [],
715
- items_count: bff.items_count
716
- };
717
- }
718
- /**
719
- * Creates a ShareablesApi["playlists"]-compatible adapter backed by the
720
- * portal-tenant content BFF. Fetches playlist + items in parallel for
721
- * detail views and maps enriched flat fields onto playlist items.
722
- */
723
- function createPortalTenantPlaylistsShareablesAdapter(client) {
724
- const portAdapter = createPortalTenantPlaylistsAdapter(client);
725
- return {
726
- getPlaylists: async (options) => {
727
- const rawSort = options?.sort;
728
- let bffSort;
729
- if (rawSort === "title_asc" || rawSort === "title") bffSort = "title_asc";
730
- else if (rawSort === "title_desc" || rawSort === "-title") bffSort = "title_desc";
731
- else if (rawSort === "created_at_asc" || rawSort === "created_at") bffSort = "created_at_asc";
732
- else if (rawSort === "created_at_desc" || rawSort === "-created_at") bffSort = "created_at_desc";
733
- const response = await portAdapter.listPlaylists({
734
- cursor: options?.["page[cursor]"],
735
- limit: options?.["page[limit]"],
736
- "filter[title]": options?.["filter[title]"],
737
- sort: bffSort
738
- });
739
- return {
740
- playlists: response.playlists.map((p) => toBffPlaylist(p)),
741
- meta: {
742
- request_id: response.meta.request_id ?? "",
743
- timestamp: response.meta.timestamp ?? "",
744
- pagination: {
745
- cursor: response.meta.pagination?.cursor ?? null,
746
- limit: response.meta.pagination?.limit ?? 12,
747
- prev_cursor: response.meta.pagination?.prev_cursor ?? null,
748
- next_cursor: response.meta.pagination?.next_cursor ?? null,
749
- total_count: 0,
750
- total_pages: 0
751
- }
752
- }
753
- };
754
- },
755
- getPlaylistById: async (id) => {
756
- const response = await portAdapter.getPlaylist(id);
757
- const allItems = [];
758
- let cursor;
759
- const MAX_PAGES = 50;
760
- for (let i = 0; i < MAX_PAGES; i++) {
761
- const page = await portAdapter.listPlaylistItems(id, {
762
- cursor,
763
- limit: 100
764
- });
765
- allItems.push(...page.playlist_items);
766
- cursor = page.meta.pagination?.next_cursor ?? void 0;
767
- if (!cursor) break;
768
- }
769
- const items = allItems.map((item) => ({
770
- id: item.id,
771
- order: item.position ?? void 0,
772
- relateable_type: "Medium",
773
- relateable: { id: item.media_id },
774
- title: item.title ?? "Untitled",
775
- image_url: item.image_url ?? null,
776
- kind: mediaKindFromType(item.media_type ?? ""),
777
- video_url: item.video_url ?? null,
778
- duration: item.duration ?? null,
779
- media_format: item.media_type ?? null
780
- }));
781
- return {
782
- playlist: toBffPlaylist(response.playlist, items),
783
- meta: {
784
- request_id: response.meta.request_id ?? "",
785
- timestamp: response.meta.timestamp ?? ""
786
- }
787
- };
788
- },
789
- createPlaylist: async (data) => {
790
- const response = await portAdapter.createPlaylist({
791
- title: data.playlist.title,
792
- description: data.playlist.description
793
- });
794
- return {
795
- playlist: toBffPlaylist(response.playlist),
796
- meta: {
797
- request_id: response.meta.request_id ?? "",
798
- timestamp: response.meta.timestamp ?? ""
799
- }
800
- };
801
- },
802
- updatePlaylist: async (id, data) => {
803
- const response = await portAdapter.updatePlaylist(id, {
804
- title: data.playlist.title,
805
- description: data.playlist.description
806
- });
807
- return {
808
- playlist: toBffPlaylist(response.playlist),
809
- meta: {
810
- request_id: response.meta.request_id ?? "",
811
- timestamp: response.meta.timestamp ?? ""
812
- }
813
- };
814
- },
815
- addItemToPlaylist: async (id, data) => {
816
- await Promise.all(data.items.map((item) => portAdapter.addPlaylistItem(id, {
817
- media_id: item.relateable_id,
818
- position: typeof item.order === "number" ? item.order : Number(item.order)
819
- })));
820
- return toBffPlaylist((await portAdapter.getPlaylist(id)).playlist);
821
- },
822
- removeItemsFromPlaylist: async (playlistId, data) => {
823
- await Promise.all(data.item_ids.map((itemId) => portAdapter.removePlaylistItem(playlistId, itemId)));
824
- return toBffPlaylist((await portAdapter.getPlaylist(playlistId)).playlist);
825
- }
826
- };
827
- }
828
- //#endregion
829
- //#region ../../shareables/api-client/src/portal-tenant-dam-assets-adapter.ts
830
- /**
831
- * Maps a BFF DAM asset to the port's DamAsset shape.
832
- */
833
- function mapDamAsset(raw) {
834
- return {
835
- id: raw.id ?? 0,
836
- code: raw.code ?? "",
837
- name: raw.name ?? "",
838
- description: raw.description ?? null,
839
- category: raw.category ?? null,
840
- company: raw.company ?? null,
841
- default_variant_id: raw.default_variant_id ?? null,
842
- default_variant_url: raw.default_variant_url ?? null,
843
- canonical_path: raw.canonical_path ?? null,
844
- created_at: raw.created_at ?? "",
845
- updated_at: raw.updated_at ?? ""
846
- };
847
- }
848
- /**
849
- * Maps a BFF DAM asset path to the port's DamAssetPath shape.
850
- */
851
- function mapDamAssetPath(raw) {
852
- return {
853
- id: raw.id ?? 0,
854
- asset_code: raw.asset_code ?? "",
855
- path: raw.path ?? "",
856
- created_at: raw.created_at ?? ""
857
- };
858
- }
859
- /**
860
- * Maps the BFF meta envelope to the port's ApiMeta shape.
861
- */
862
- function mapMeta$1(raw) {
863
- return {
864
- request_id: raw?.request_id ?? null,
865
- timestamp: raw?.timestamp ?? "",
866
- pagination: raw?.pagination ? {
867
- cursor: raw.pagination.cursor ?? null,
868
- limit: raw.pagination.limit,
869
- next_cursor: raw.pagination.next_cursor ?? null,
870
- prev_cursor: raw.pagination.prev_cursor ?? null
871
- } : void 0
872
- };
873
- }
874
- /**
875
- * Creates a ContentDamAssetsApi adapter backed by the portal-tenant content BFF.
876
- *
877
- * Maps the generated portal-tenant-content namespace functions to the abstract
878
- * ContentDamAssetsApi port, closing over the FetchClient so consumers don't
879
- * need to pass it per-call.
880
- */
881
- function createPortalTenantDamAssetsAdapter(client) {
882
- return {
883
- listAssets: async (params) => {
884
- const response = await dam_assets_list(client, {
885
- "page[cursor]": params?.cursor,
886
- "page[limit]": params?.limit
887
- });
888
- return {
889
- assets: (response.assets ?? []).map(mapDamAsset),
890
- meta: mapMeta$1(response.meta)
891
- };
892
- },
893
- createAsset: async (body) => {
894
- const response = await dam_assets_create(client, { asset: body });
895
- return {
896
- asset: mapDamAsset(response.asset ?? {}),
897
- meta: mapMeta$1(response.meta)
898
- };
899
- },
900
- listAssetPaths: async (assetCode, params) => {
901
- const response = await dam_asset_paths_list(client, assetCode, {
902
- "page[cursor]": params?.cursor,
903
- "page[limit]": params?.limit
904
- });
905
- return {
906
- asset_paths: (response.asset_paths ?? []).map(mapDamAssetPath),
907
- meta: mapMeta$1(response.meta)
908
- };
909
- },
910
- createAssetPath: async (assetCode, body) => {
911
- const response = await dam_asset_paths_create(client, assetCode, { asset_path: body });
912
- return {
913
- asset_path: mapDamAssetPath(response.asset_path ?? {}),
914
- meta: mapMeta$1(response.meta)
915
- };
916
- }
917
- };
918
- }
919
- /**
920
- * Creates a ShareablesApi["fileResources"]-compatible adapter backed by the
921
- * portal-tenant content BFF. Maps DamAsset to FileResource shape and
922
- * includes cursor-to-page-number caching for legacy UI pagination.
923
- */
924
- function createPortalTenantFilesShareablesAdapter(client) {
925
- const portAdapter = createPortalTenantDamAssetsAdapter(client);
926
- const cursorByPage = /* @__PURE__ */ new Map();
927
- return { getFileResources: async (params) => {
928
- const pageNumber = params?.pageParam ? Number(params.pageParam) : 1;
929
- const pageSize = params?.pageSize ? Number(params.pageSize) : 25;
930
- const cursor = pageNumber > 1 ? cursorByPage.get(pageNumber) : void 0;
931
- const response = await portAdapter.listAssets({
932
- cursor,
933
- limit: pageSize
934
- });
935
- const nextCursor = response.meta.pagination?.next_cursor;
936
- if (nextCursor) cursorByPage.set(pageNumber + 1, nextCursor);
937
- const fileResources = response.assets.map((asset) => ({
938
- id: asset.id,
939
- alt_text: asset.name,
940
- url: asset.default_variant_url ?? "",
941
- filename: asset.name,
942
- content_type: "application/octet-stream",
943
- content_size: 0,
944
- handle: asset.code,
945
- dam_asset_code: asset.code,
946
- preview_image_url: asset.default_variant_url ?? "",
947
- created_at: asset.created_at,
948
- updated_at: asset.updated_at ?? "",
949
- relateable_type: null,
950
- relateable_id: null,
951
- content: null
952
- }));
953
- const hasNextPage = !!nextCursor;
954
- return {
955
- file_resources: fileResources,
956
- meta: {
957
- total_count: fileResources.length,
958
- per_page: pageSize,
959
- current_page: pageNumber,
960
- total_pages: hasNextPage ? pageNumber + 1 : pageNumber
961
- }
962
- };
963
- } };
964
- }
965
- //#endregion
966
- //#region ../../shareables/api-client/src/portal-tenant-shares-adapter.ts
967
- /**
968
- * Narrows an unknown string to a valid ShareableType at runtime.
969
- */
970
- function isShareableType(value) {
971
- return value === "media" || value === "product" || value === "library" || value === "page";
972
- }
973
- /**
974
- * Maps a BFF share to the port's Share shape.
975
- */
976
- function mapShare(raw) {
977
- return {
978
- id: raw.id ?? 0,
979
- url: raw.url ?? "",
980
- shareable_type: isShareableType(raw.shareable_type) ? raw.shareable_type : "media",
981
- shareable_id: raw.shareable_id ?? 0,
982
- created_at: raw.created_at ?? ""
983
- };
984
- }
985
- /**
986
- * Maps the BFF meta envelope to the port's ApiMeta shape.
987
- */
988
- function mapMeta(raw) {
989
- return {
990
- request_id: raw?.request_id ?? null,
991
- timestamp: raw?.timestamp ?? "",
992
- pagination: raw?.pagination ? {
993
- cursor: raw.pagination.cursor ?? null,
994
- limit: raw.pagination.limit,
995
- next_cursor: raw.pagination.next_cursor ?? null,
996
- prev_cursor: raw.pagination.prev_cursor ?? null
997
- } : void 0
998
- };
999
- }
1000
- /**
1001
- * Creates a ContentSharesApi adapter backed by the portal-tenant content BFF.
1002
- *
1003
- * Maps the generated portal-tenant-content namespace functions to the abstract
1004
- * ContentSharesApi port, closing over the FetchClient so consumers don't need
1005
- * to pass it per-call.
1006
- */
1007
- function createPortalTenantSharesAdapter(client) {
1008
- return {
1009
- listShares: async (params) => {
1010
- const response = await shares_list(client, {
1011
- "page[cursor]": params?.cursor,
1012
- "page[limit]": params?.limit
1013
- });
1014
- return {
1015
- shares: (response.shares ?? []).map(mapShare),
1016
- meta: mapMeta(response.meta)
1017
- };
1018
- },
1019
- createShare: async (body) => {
1020
- const response = await shares_create(client, { share: body });
1021
- return {
1022
- share: mapShare(response.share ?? {}),
1023
- meta: mapMeta(response.meta)
1024
- };
1025
- }
1026
- };
1027
- }
1028
- /**
1029
- * Maps legacy Rails model names (used by the UI) to BFF shareable_type values.
1030
- */
1031
- const SHAREABLE_TYPE_MAP = {
1032
- Medium: "media",
1033
- media: "media",
1034
- Product: "product",
1035
- product: "product",
1036
- Library: "library",
1037
- library: "library",
1038
- Page: "page",
1039
- page: "page"
1040
- };
1041
- /**
1042
- * Creates a ShareablesApi["share"]-compatible adapter backed by the
1043
- * portal-tenant content BFF. Maps legacy model names to BFF shareable types.
1044
- */
1045
- function createPortalTenantSharesShareablesAdapter(client) {
1046
- const portAdapter = createPortalTenantSharesAdapter(client);
1047
- return { createShareLink: async (input) => {
1048
- if (!input.relateableId) throw new Error("Cannot create share link without a relateableId");
1049
- const shareableType = SHAREABLE_TYPE_MAP[input.relateableType];
1050
- if (!shareableType) throw new Error(`Unknown shareable type: "${input.relateableType}"`);
1051
- return (await portAdapter.createShare({
1052
- shareable_type: shareableType,
1053
- shareable_id: input.relateableId
1054
- })).share.url;
1055
- } };
1056
- }
1057
- //#endregion
1058
- //#region ../../file-picker/api-client/src/api/url-proxy.ts
1059
- const urlProxyResponseSchema = z.object({
1060
- data: z.string(),
1061
- contentType: z.string(),
1062
- size: z.number()
1063
- });
1064
- /**
1065
- * Proxy a URL fetch through the backend to bypass CORS restrictions.
1066
- * The backend fetches the file and returns it as base64-encoded data.
1067
- *
1068
- * @param url - The URL to fetch
1069
- * @param proxyEndpoint - The proxy endpoint (defaults to "/api/proxy-url")
1070
- */
1071
- async function proxyUrlFetch(url, proxyEndpoint = "/api/proxy-url") {
1072
- const response = await fetch(proxyEndpoint, {
1073
- method: "POST",
1074
- headers: { "Content-Type": "application/json" },
1075
- body: JSON.stringify({ url })
1076
- });
1077
- if (!response.ok) {
1078
- const errorData = await response.json().catch(() => ({ error: "Failed to proxy URL fetch" }));
1079
- throw new Error(errorData.error || `HTTP ${response.status}`);
1080
- }
1081
- const data = await response.json();
1082
- return urlProxyResponseSchema.parse(data);
1083
- }
1084
- //#endregion
1085
- //#region ../../file-picker/api-client/src/portal-tenant-adapter.ts
1086
- /**
1087
- * Maps a BFF DAM asset to the file-picker port's DamAssetCreateResponse shape.
1088
- *
1089
- * The BFF response includes nullable meta.request_id (from Api::Response),
1090
- * while the port schema requires a string. We coalesce to empty string.
1091
- */
1092
- function mapCreateResponse(response) {
1093
- const raw = response.asset ?? {};
1094
- return {
1095
- asset: damAssetSchema.parse({
1096
- ...raw,
1097
- canonical_path: raw.canonical_path ?? "",
1098
- category: raw.category ?? "",
1099
- company: raw.company ?? "",
1100
- description: raw.description ?? "",
1101
- default_variant_id: raw.default_variant_id ?? ""
1102
- }),
1103
- meta: {
1104
- request_id: response.meta?.request_id ?? "",
1105
- timestamp: response.meta?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
1106
- }
1107
- };
1108
- }
1109
- /**
1110
- * Maps a BFF asset path response to the file-picker port's shape.
1111
- */
1112
- function mapAssetPathCreateResponse(response) {
1113
- const assetPath = response.asset_path ?? {};
1114
- return {
1115
- asset: {
1116
- id: assetPath.id ?? 0,
1117
- canonical_path: assetPath.path ?? "",
1118
- name: assetPath.asset_code ?? ""
1119
- },
1120
- meta: {
1121
- request_id: response.meta?.request_id ?? "",
1122
- timestamp: response.meta?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
1123
- }
1124
- };
1125
- }
1126
- /**
1127
- * Creates a FilePickerApi adapter backed by the portal-tenant BFF's
1128
- * `/api/content/dam/*` endpoints, using cookie-based auth via the
1129
- * provided FetchClient.
1130
- *
1131
- * Unsplash search is not available through the BFF — callers that need
1132
- * Unsplash should use the legacy adapter or provide their own
1133
- * implementation.
1134
- *
1135
- * The `onProgress` callback in `createDamAsset` is not supported — the
1136
- * underlying `fetch` API does not expose upload progress events.
1137
- *
1138
- * URL proxy delegates to the same-origin `/api/proxy-url` endpoint
1139
- * (served by the hosting app, not the BFF) for CORS bypass, identical
1140
- * to the legacy adapter behaviour.
1141
- */
1142
- function createPortalTenantFilePickerApiAdapter(client) {
1143
- return {
1144
- createDamAsset: async (params) => {
1145
- const formData = new FormData();
1146
- formData.append("asset[file]", params.file);
1147
- formData.append("asset[name]", params.name);
1148
- if (params.description) formData.append("asset[description]", params.description);
1149
- if (params.tags && params.tags.length > 0) formData.append("asset[tags]", params.tags.join(","));
1150
- return mapCreateResponse(await client.requestWithFormData("/api/content/dam/assets", formData, { method: "POST" }));
1151
- },
1152
- queryDamAssets: async (params) => {
1153
- const response = await dam_query(client, params);
1154
- return damQueryResponseSchema.parse({
1155
- ...response,
1156
- meta: response.meta ? { next_cursor: response.meta.pagination?.next_cursor ?? void 0 } : void 0
1157
- });
1158
- },
1159
- deleteDamAsset: async (code) => {
1160
- return dam_assets_destroy(client, code);
1161
- },
1162
- discardDamAsset: async (code) => {
1163
- return dam_assets_discard(client, code);
1164
- },
1165
- createDamAssetPathForAssets: async (params) => {
1166
- return mapAssetPathCreateResponse(await dam_asset_paths_create(client, params.code, { asset_path: { path: params.asset_paths.join(",") } }));
1167
- },
1168
- searchUnsplash: async (_query, _page, _perPage) => {
1169
- throw new Error("Unsplash search is not available through the portal-tenant BFF. Configure an Unsplash access key and use the standard FilePickerApi adapter instead.");
1170
- },
1171
- proxyUrlFetch: (url) => proxyUrlFetch(url)
1172
- };
1173
- }
1174
- //#endregion
1175
- //#region src/screens/ShareablesScreen.tsx
1176
- /**
1177
- * Parse the current shareables sub-route from the full slug.
1178
- *
1179
- * System nav slugs are "share/products", "share/media", "share/playlists".
1180
- * Detail pages append an ID: "share/products/123", "share/media/456".
1181
- *
1182
- * "share/products" → screen="products", detailId=null
1183
- * "share/products/123" → screen="products", detailId="123"
1184
- * "share/media/456" → screen="media", detailId="456"
1185
- * "share/playlists" → screen="playlists", detailId=null
1186
- * "share/playlists/789" → screen="playlists", detailId="789"
1187
- * "share/files" → screen="files", detailId=null
1188
- * "share" → screen=null (default to products)
1189
- */
1190
- function parseShareablesRoute(currentSlug) {
1191
- const slugWithoutPrefix = currentSlug.replace(/^share\/?/, "");
1192
- if (!slugWithoutPrefix) return {
1193
- screen: null,
1194
- detailId: null,
1195
- action: null
1196
- };
1197
- const parts = slugWithoutPrefix.split("/");
1198
- return {
1199
- screen: parts[0] || null,
1200
- detailId: parts[1] || null,
1201
- action: parts[2] || null
1202
- };
1203
- }
1204
- function ShareablesScreen({ background, textColor, accentColor, padding, borderRadius, ...divProps }) {
1205
- const domainClient = useSdkClient();
1206
- const portalProductsApi = usePortalProductsClient();
1207
- const portalTenantClient = usePortalTenantClient();
1208
- const { config } = useFluidContext();
1209
- const { data: userData } = useCurrentUser();
1210
- const { currentSlug, navigate } = useAppNavigation();
1211
- const { isCustomer } = useUserType();
1212
- const fetchProducts = useCallback(async (search, cursor, limit) => {
1213
- if (search) return portalProductsApi.searchProducts(search, {
1214
- cursor,
1215
- limit
1216
- });
1217
- return portalProductsApi.listProducts({
1218
- cursor,
1219
- limit
1220
- });
1221
- }, [portalProductsApi]);
1222
- const fetchProduct = useCallback(async (id) => portalProductsApi.getProduct(id), [portalProductsApi]);
1223
- const { screen, detailId, action } = parseShareablesRoute(currentSlug);
1224
- const handleNavigate = useCallback((subScreen, id) => {
1225
- navigate(id ? `share/${subScreen}/${id}` : `share/${subScreen}`);
1226
- }, [navigate]);
1227
- const handleBack = useCallback(() => {
1228
- if (detailId && screen) navigate(`share/${screen}`);
1229
- else navigate("share/products");
1230
- }, [
1231
- navigate,
1232
- detailId,
1233
- screen
1234
- ]);
1235
- const coreConfig = useMemo(() => ({
1236
- client: domainClient,
1237
- user: userData ? { id: userData.id } : null,
1238
- repContext: true
1239
- }), [domainClient, userData]);
1240
- const playlistsAdapter = useMemo(() => createPortalTenantPlaylistsAdapter(portalTenantClient), [portalTenantClient]);
1241
- const shareablesApi = useMemo(() => ({
1242
- media: createPortalTenantMediaShareablesAdapter(portalTenantClient),
1243
- playlists: createPortalTenantPlaylistsShareablesAdapter(portalTenantClient),
1244
- fileResources: createPortalTenantFilesShareablesAdapter(portalTenantClient),
1245
- share: createPortalTenantSharesShareablesAdapter(portalTenantClient),
1246
- productMedia: { getProductMedia: async (productId) => {
1247
- return { media: ((await portalProductsApi.getProductMedia(productId)).media ?? []).map((item) => {
1248
- const isVideo = item.media_type === "video";
1249
- const isPdf = item.media_type === "pdf" || item.media_type === "document";
1250
- return {
1251
- id: item.id ?? 0,
1252
- slug: null,
1253
- title: item.title ?? "",
1254
- kind: isVideo ? "video" : isPdf ? "pdf" : "image",
1255
- media_type: item.media_type ?? "image",
1256
- media_format: item.media_type ?? "image",
1257
- image_url: !isVideo && !isPdf ? item.url ?? null : null,
1258
- video_url: isVideo ? item.url ?? null : null,
1259
- pdf_url: isPdf ? item.url ?? null : null,
1260
- powerpoint_url: null,
1261
- duration: 0,
1262
- description: null,
1263
- subtitles: {},
1264
- comments_count: 0
1265
- };
1266
- }) };
1267
- } }
1268
- }), [portalTenantClient, portalProductsApi]);
1269
- const filePickerApi = useMemo(() => {
1270
- const baseUrl = config.baseUrl.replace(/\/+$/, "").replace(/\/api$/, "");
1271
- const csrfToken = typeof document !== "undefined" ? document.querySelector("meta[name=\"csrf-token\"]")?.getAttribute("content") : null;
1272
- return createPortalTenantFilePickerApiAdapter(createFetchClient({
1273
- baseUrl,
1274
- getAuthToken: config.getAuthToken,
1275
- onAuthError: config.onAuthError,
1276
- credentials: "include",
1277
- defaultHeaders: {
1278
- ...config.defaultHeaders,
1279
- ...csrfToken ? { "X-CSRF-Token": csrfToken } : {}
1280
- }
1281
- }));
1282
- }, [
1283
- config.baseUrl,
1284
- config.getAuthToken,
1285
- config.onAuthError,
1286
- config.defaultHeaders
1287
- ]);
1288
- const uiConfig = useMemo(() => ({
1289
- user: userData ? {
1290
- id: userData.id,
1291
- company: userData.company ? { logo_url: userData.company.logo_url } : null
1292
- } : void 0,
1293
- affiliateId: userData?.affiliate_id ?? null,
1294
- basePath: "",
1295
- navigate: (path) => {
1296
- const cleanPath = path.replace(/^\//, "");
1297
- navigate(cleanPath.startsWith("share/") ? cleanPath : `share/${cleanPath}`);
1298
- },
1299
- showToast: (opts) => {
1300
- console.warn(`[Shareables] ${opts.type}: ${opts.title}`);
1301
- },
1302
- filePickerApi,
1303
- onToggleFavorite: async (params) => {
1304
- const affiliateId = userData?.affiliate_id;
1305
- if (!affiliateId) throw new Error("No affiliate ID");
1306
- return domainClient.post(`/user_companies/${affiliateId}/favorites/toggle.json`, {
1307
- favoriteable_id: params.favoriteableId,
1308
- favoriteable_type: params.favoriteableType
1309
- });
1310
- },
1311
- onDeletePlaylist: isCustomer ? void 0 : async (playlistId) => {
1312
- await playlistsAdapter.deletePlaylist(playlistId);
1313
- },
1314
- readOnly: isCustomer
1315
- }), [
1316
- userData,
1317
- navigate,
1318
- filePickerApi,
1319
- domainClient,
1320
- isCustomer,
1321
- playlistsAdapter
1322
- ]);
1323
- return /* @__PURE__ */ jsx("div", {
1324
- ...divProps,
1325
- className: `h-full ${divProps.className ?? ""}`,
1326
- children: /* @__PURE__ */ jsx(ShareablesCoreProvider, {
1327
- config: coreConfig,
1328
- children: /* @__PURE__ */ jsx(ShareablesApiProvider, {
1329
- api: shareablesApi,
1330
- children: /* @__PURE__ */ jsx(ShareablesUIProvider, {
1331
- config: uiConfig,
1332
- children: /* @__PURE__ */ jsx(ShareablesApp, {
1333
- screen,
1334
- detailId,
1335
- action,
1336
- companyLogoUrl: userData?.company?.logo_url,
1337
- countryCode: userData?.country?.iso,
1338
- fetchProducts,
1339
- fetchProduct,
1340
- onNavigate: handleNavigate,
1341
- onBack: handleBack
1342
- })
1343
- })
1344
- })
1345
- })
1346
- });
1347
- }
1348
- const shareablesScreenPropertySchema = {
1349
- widgetType: "ShareablesScreen",
1350
- displayName: "Shareables Screen",
1351
- tabsConfig: [{
1352
- id: "styling",
1353
- label: "Styling"
1354
- }],
1355
- fields: []
1356
- };
1357
- //#endregion
1358
- export { shareablesScreenPropertySchema as n, useUserType as r, ShareablesScreen as t };
1359
-
1360
- //# sourceMappingURL=ShareablesScreen-CecBPoFO.mjs.map