@fluid-app/portal-sdk 0.1.162 → 0.1.164

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 (69) hide show
  1. package/dist/{MySiteScreen-g8Esyofu.mjs → MySiteScreen-CG2DnzQH.mjs} +2 -2
  2. package/dist/{MySiteScreen-g8Esyofu.mjs.map → MySiteScreen-CG2DnzQH.mjs.map} +1 -1
  3. package/dist/{MySiteScreen-Cos0jTa_.cjs → MySiteScreen-DRMrEMEI.cjs} +2 -2
  4. package/dist/{MySiteScreen-Xcg07a3M.cjs → MySiteScreen-Lr2SbrXz.cjs} +2 -2
  5. package/dist/{MySiteScreen-Xcg07a3M.cjs.map → MySiteScreen-Lr2SbrXz.cjs.map} +1 -1
  6. package/dist/{OrdersScreen-DZyOBKmU.cjs → OrdersScreen-B6n41CbG.cjs} +1 -1
  7. package/dist/{OrdersScreen-ZGUm8buk.cjs → OrdersScreen-BKCQdz5A.cjs} +55 -56
  8. package/dist/OrdersScreen-BKCQdz5A.cjs.map +1 -0
  9. package/dist/{OrdersScreen-DeLoyVGI.mjs → OrdersScreen-CFRVfzez.mjs} +55 -56
  10. package/dist/OrdersScreen-CFRVfzez.mjs.map +1 -0
  11. package/dist/{use-portal-shareables-api-DRK9Y5dp.mjs → PortalContentApiProvider-CW0ADhPi.mjs} +285 -94
  12. package/dist/PortalContentApiProvider-CW0ADhPi.mjs.map +1 -0
  13. package/dist/{use-portal-shareables-api-DcjYlAOy.cjs → PortalContentApiProvider-Di5emtYd.cjs} +290 -129
  14. package/dist/PortalContentApiProvider-Di5emtYd.cjs.map +1 -0
  15. package/dist/PortalProductsApiProvider-BCXX9NGK.mjs +780 -0
  16. package/dist/PortalProductsApiProvider-BCXX9NGK.mjs.map +1 -0
  17. package/dist/PortalProductsApiProvider-BquMHwvt.cjs +816 -0
  18. package/dist/PortalProductsApiProvider-BquMHwvt.cjs.map +1 -0
  19. package/dist/{ProductsScreen-B2SKzTE4.cjs → ProductsScreen-C6eNgxjP.cjs} +4 -3
  20. package/dist/{ProductsScreen-D6eoU86k.mjs → ProductsScreen-CVNJudq9.mjs} +39 -44
  21. package/dist/ProductsScreen-CVNJudq9.mjs.map +1 -0
  22. package/dist/{ProductsScreen-DbwSCY7G.cjs → ProductsScreen-KjjhlDGo.cjs} +39 -44
  23. package/dist/ProductsScreen-KjjhlDGo.cjs.map +1 -0
  24. package/dist/{ProductsScreen-BGah2tcD.mjs → ProductsScreen-nHmUftQn.mjs} +4 -3
  25. package/dist/{ShareablesScreen-DRUT-yoi.mjs → ShareablesScreen-CdTyyDRO.mjs} +4 -3
  26. package/dist/{ShareablesScreen-Dy04EXe5.cjs → ShareablesScreen-DUzo8kRi.cjs} +4 -3
  27. package/dist/ShareablesScreen-DpEP_6u0.mjs +132 -0
  28. package/dist/ShareablesScreen-DpEP_6u0.mjs.map +1 -0
  29. package/dist/ShareablesScreen-Dz8w2l3e.cjs +144 -0
  30. package/dist/ShareablesScreen-Dz8w2l3e.cjs.map +1 -0
  31. package/dist/{ShopScreen-CQ48b1c8.mjs → ShopScreen-BH6zQndJ.mjs} +10 -724
  32. package/dist/ShopScreen-BH6zQndJ.mjs.map +1 -0
  33. package/dist/{ShopScreen-CFqoT4IC.cjs → ShopScreen-BUXUtEuj.cjs} +13 -727
  34. package/dist/ShopScreen-BUXUtEuj.cjs.map +1 -0
  35. package/dist/{ShopScreen-B7faQx84.cjs → ShopScreen-BbucUNI7.cjs} +2 -1
  36. package/dist/{SubscriptionsScreen-C2iORyT_.cjs → SubscriptionsScreen-BdGF5OLE.cjs} +408 -409
  37. package/dist/SubscriptionsScreen-BdGF5OLE.cjs.map +1 -0
  38. package/dist/{SubscriptionsScreen-ClWrrqPK.cjs → SubscriptionsScreen-Cwa2lR1D.cjs} +1 -1
  39. package/dist/{SubscriptionsScreen-BfdK8067.mjs → SubscriptionsScreen-Dn3AEUJi.mjs} +408 -409
  40. package/dist/SubscriptionsScreen-Dn3AEUJi.mjs.map +1 -0
  41. package/dist/{dist-lO2OG0T5.cjs → dist-BF_4vk1z.cjs} +1 -1
  42. package/dist/{dist-lO2OG0T5.cjs.map → dist-BF_4vk1z.cjs.map} +1 -1
  43. package/dist/index.cjs +21 -20
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.cts.map +1 -1
  46. package/dist/index.d.mts.map +1 -1
  47. package/dist/index.mjs +21 -20
  48. package/dist/index.mjs.map +1 -1
  49. package/dist/{sortable.esm-DSrWP4x9.mjs → sortable.esm-E6JdQn7I.mjs} +1 -1
  50. package/dist/{sortable.esm-DSrWP4x9.mjs.map → sortable.esm-E6JdQn7I.mjs.map} +1 -1
  51. package/package.json +17 -17
  52. package/dist/OrdersScreen-DeLoyVGI.mjs.map +0 -1
  53. package/dist/OrdersScreen-ZGUm8buk.cjs.map +0 -1
  54. package/dist/ProductsScreen-D6eoU86k.mjs.map +0 -1
  55. package/dist/ProductsScreen-DbwSCY7G.cjs.map +0 -1
  56. package/dist/ShareablesScreen-DPHZMh-V.cjs +0 -391
  57. package/dist/ShareablesScreen-DPHZMh-V.cjs.map +0 -1
  58. package/dist/ShareablesScreen-DrQDQ1-U.mjs +0 -379
  59. package/dist/ShareablesScreen-DrQDQ1-U.mjs.map +0 -1
  60. package/dist/ShopScreen-CFqoT4IC.cjs.map +0 -1
  61. package/dist/ShopScreen-CQ48b1c8.mjs.map +0 -1
  62. package/dist/SubscriptionsScreen-BfdK8067.mjs.map +0 -1
  63. package/dist/SubscriptionsScreen-C2iORyT_.cjs.map +0 -1
  64. package/dist/use-portal-products-client-BUFD20ZY.mjs +0 -65
  65. package/dist/use-portal-products-client-BUFD20ZY.mjs.map +0 -1
  66. package/dist/use-portal-products-client-DTkFvOal.cjs +0 -71
  67. package/dist/use-portal-products-client-DTkFvOal.cjs.map +0 -1
  68. package/dist/use-portal-shareables-api-DRK9Y5dp.mjs.map +0 -1
  69. package/dist/use-portal-shareables-api-DcjYlAOy.cjs.map +0 -1
@@ -0,0 +1,780 @@
1
+ import { c as products_search, l as products_show, o as products_list, s as products_media_list } from "./portal_tenant-iAeJ-HB1.mjs";
2
+ import { n as usePortalTenantClient } from "./PortalTenantClientProvider-_VXOs0t4.mjs";
3
+ import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
4
+ import { useQuery } from "@tanstack/react-query";
5
+ import { jsx } from "react/jsx-runtime";
6
+ import { create } from "zustand";
7
+ import "zustand/middleware";
8
+ createContext(null);
9
+ //#endregion
10
+ //#region ../../products/core/src/portal-products-api-context.tsx
11
+ const PortalProductsCoreContext = createContext(null);
12
+ function PortalProductsCoreProvider({ api, children }) {
13
+ return /* @__PURE__ */ jsx(PortalProductsCoreContext.Provider, {
14
+ value: { api },
15
+ children
16
+ });
17
+ }
18
+ function usePortalProductsApi() {
19
+ const ctx = useContext(PortalProductsCoreContext);
20
+ if (!ctx) throw new Error("usePortalProductsApi must be used within a <PortalProductsCoreProvider>");
21
+ return ctx.api;
22
+ }
23
+ //#endregion
24
+ //#region ../../products/core/src/hooks/use-debounce.ts
25
+ function useDebounce(value, delay) {
26
+ const [debouncedValue, setDebouncedValue] = useState(value);
27
+ useEffect(() => {
28
+ const timer = setTimeout(() => {
29
+ setDebouncedValue(value);
30
+ }, delay);
31
+ return () => {
32
+ clearTimeout(timer);
33
+ };
34
+ }, [value, delay]);
35
+ return debouncedValue;
36
+ }
37
+ //#endregion
38
+ //#region ../../products/core/src/hooks/use-portal-products.ts
39
+ const portalProductKeys = {
40
+ all: ["portal-products"],
41
+ list: (params) => [
42
+ ...portalProductKeys.all,
43
+ "list",
44
+ params
45
+ ],
46
+ detail: (id) => [
47
+ ...portalProductKeys.all,
48
+ "detail",
49
+ String(id)
50
+ ],
51
+ search: (query, params) => [
52
+ ...portalProductKeys.all,
53
+ "search",
54
+ query,
55
+ params
56
+ ],
57
+ media: (productId) => [
58
+ ...portalProductKeys.all,
59
+ "media",
60
+ String(productId)
61
+ ]
62
+ };
63
+ function usePortalProduct(id, options) {
64
+ const api = usePortalProductsApi();
65
+ return useQuery({
66
+ queryKey: portalProductKeys.detail(id),
67
+ queryFn: () => api.getProduct(id),
68
+ enabled: options?.enabled
69
+ });
70
+ }
71
+ //#endregion
72
+ //#region ../../products/core/src/hooks/use-portal-product-catalog.ts
73
+ function usePortalProductCatalog({ perPage = 25 } = {}) {
74
+ const api = usePortalProductsApi();
75
+ const [searchTerm, setSearchTerm] = useState("");
76
+ const debouncedSearchTerm = useDebounce(searchTerm, 300);
77
+ const [currentSort, setCurrentSort] = useState("created_at_desc");
78
+ return {
79
+ searchTerm,
80
+ setSearchTerm,
81
+ debouncedSearchTerm,
82
+ currentSort,
83
+ setCurrentSort,
84
+ fetchProducts: useCallback(async (pageParam) => {
85
+ const cursor = pageParam;
86
+ if (debouncedSearchTerm) return api.searchProducts(debouncedSearchTerm, {
87
+ cursor,
88
+ limit: perPage,
89
+ sort: currentSort
90
+ });
91
+ return api.listProducts({
92
+ cursor,
93
+ limit: perPage,
94
+ sort: currentSort
95
+ });
96
+ }, [
97
+ api,
98
+ debouncedSearchTerm,
99
+ perPage,
100
+ currentSort
101
+ ]),
102
+ getNextPageParam: useCallback((lastPage, _allPages, lastPageParam) => {
103
+ const nextCursor = lastPage.meta?.pagination?.next_cursor ?? void 0;
104
+ if (nextCursor != null && nextCursor === lastPageParam) return;
105
+ return nextCursor;
106
+ }, []),
107
+ queryKey: useMemo(() => [
108
+ "portal-product-catalog",
109
+ debouncedSearchTerm || "",
110
+ perPage,
111
+ currentSort
112
+ ], [
113
+ debouncedSearchTerm,
114
+ perPage,
115
+ currentSort
116
+ ]),
117
+ perPage
118
+ };
119
+ }
120
+ //#endregion
121
+ //#region ../../products/core/src/hooks/use-portal-product-detail.ts
122
+ function usePortalProductDetail({ productId }) {
123
+ const { data: productResponse, isLoading, error } = usePortalProduct(productId);
124
+ const product = productResponse?.product;
125
+ return {
126
+ product,
127
+ isLoading,
128
+ error,
129
+ images: useMemo(() => {
130
+ if (!product?.images) return [];
131
+ return product.images.map((img, idx) => ({
132
+ id: idx,
133
+ url: img.url ?? "",
134
+ alt: img.alt ?? null
135
+ }));
136
+ }, [product?.images])
137
+ };
138
+ }
139
+ //#endregion
140
+ //#region ../../products/core/src/utils/subscription-plans.ts
141
+ function ensureDefaultSubscriptionPlan(plans) {
142
+ const activePlans = plans.filter((plan) => plan.active !== false);
143
+ if (activePlans.length === 0) return plans.map((plan) => ({
144
+ ...plan,
145
+ default: false
146
+ }));
147
+ if (!activePlans.some((plan) => plan.default === true)) {
148
+ const planWithLowestId = activePlans.reduce((lowest, current) => {
149
+ const lowestId = lowest.subscription_plan?.id || Infinity;
150
+ return (current.subscription_plan?.id || Infinity) < lowestId ? current : lowest;
151
+ });
152
+ return plans.map((plan) => ({
153
+ ...plan,
154
+ default: plan.subscription_plan?.id === planWithLowestId.subscription_plan?.id && plan.active !== false
155
+ }));
156
+ }
157
+ return plans.map((plan) => ({
158
+ ...plan,
159
+ default: plan.active !== false ? plan.default : false
160
+ }));
161
+ }
162
+ function plansToAttributes(plans) {
163
+ return plans.map((plan) => ({
164
+ id: plan.id ?? void 0,
165
+ subscription_plan_id: plan.subscription_plan.id,
166
+ default: plan.default || false,
167
+ active: plan.active !== false
168
+ }));
169
+ }
170
+ //#endregion
171
+ //#region ../../products/core/src/stores/use-product-store.ts
172
+ const defaultState = {
173
+ id: void 0,
174
+ title: "",
175
+ description: "",
176
+ introduction: "",
177
+ stripped: "",
178
+ feature_text: "",
179
+ sku: "",
180
+ slug: "",
181
+ canonical_url: null,
182
+ image_url: "",
183
+ image_path: void 0,
184
+ status: "draft",
185
+ publish_at: null,
186
+ price: "0",
187
+ commission: 0,
188
+ public: true,
189
+ no_index: false,
190
+ show_reviews: true,
191
+ publish_to_retail_store: true,
192
+ publish_to_rep_store: true,
193
+ publish_to_share_tab: true,
194
+ collection_ids: [],
195
+ tag_ids: [],
196
+ images_attributes: [],
197
+ product_subscription_plans_attributes: [],
198
+ product_subscription_plans: [],
199
+ variants_attributes: [],
200
+ bundle: false,
201
+ track_inventory_on_bundle_items: false,
202
+ product_bundles_attributes: [],
203
+ option_attrs: [],
204
+ options: [],
205
+ metafields_attributes: [],
206
+ metadata: {},
207
+ search_engine_optimizer_attributes: {
208
+ title: "",
209
+ description: "",
210
+ image_url: "",
211
+ image_path: "",
212
+ block_crawler: false
213
+ }
214
+ };
215
+ function syncSubscriptionPlans(plans) {
216
+ const plansWithDefault = plans.filter((plan) => plan.active !== false).length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans;
217
+ return {
218
+ product_subscription_plans: plansWithDefault,
219
+ product_subscription_plans_attributes: plansToAttributes(plansWithDefault)
220
+ };
221
+ }
222
+ const extractFilenameFromUrl = (imageUrl) => {
223
+ try {
224
+ return new URL(imageUrl).pathname.split("/").pop() || "";
225
+ } catch {
226
+ return imageUrl.split("/").pop()?.split("?")[0] || "";
227
+ }
228
+ };
229
+ const createProductStore = (set, get) => ({
230
+ ...defaultState,
231
+ track_inventory_on_bundle_items: false,
232
+ translations: {},
233
+ editedTranslations: {},
234
+ translationErrors: {},
235
+ translationLoading: {},
236
+ translationsFetched: false,
237
+ errors: {},
238
+ isValid: false,
239
+ isDirty: false,
240
+ setProduct: (productData) => {
241
+ set({
242
+ id: productData.id || void 0,
243
+ title: productData.title || "",
244
+ description: productData.description || "",
245
+ introduction: productData.introduction || "",
246
+ stripped: productData.stripped || "",
247
+ feature_text: productData.feature_text || "",
248
+ sku: productData.sku || "",
249
+ slug: productData.slug || "",
250
+ canonical_url: productData.canonical_url || null,
251
+ custom_slug: productData.custom_slug || false,
252
+ image_url: productData.image_url || "",
253
+ image_path: productData.image_path && !productData.image_path.includes("undefined") ? productData.image_path : productData.image_url ? extractFilenameFromUrl(productData.image_url) : void 0,
254
+ status: productData.status || "draft",
255
+ publish_at: productData.publish_at || null,
256
+ commission: typeof productData.commission === "string" ? parseFloat(productData.commission) : productData.commission || 0,
257
+ public: productData.public ?? true,
258
+ no_index: productData.no_index ?? false,
259
+ show_reviews: productData.show_reviews ?? true,
260
+ publish_to_retail_store: productData.publish_to_retail_store,
261
+ publish_to_rep_store: productData.publish_to_rep_store,
262
+ publish_to_share_tab: productData.publish_to_share_tab,
263
+ ...productData.tax_category_id && { tax_category_id: productData.tax_category_id },
264
+ international_tax_type: productData.international_tax_type || void 0,
265
+ category_id: productData.category_id ? parseInt(productData.category_id) : productData.category?.id ? productData.category.id : void 0,
266
+ application_theme_template_id: productData.application_theme_template_id || void 0,
267
+ collection_ids: productData.collections?.map((collection) => collection.id),
268
+ tag_ids: Array.isArray(productData.tags) ? productData.tags.map((tag) => typeof tag === "number" ? tag : tag?.id).filter(Boolean) : [],
269
+ search_engine_optimizer_attributes: {
270
+ id: productData.search_engine_optimizer?.id,
271
+ title: productData.search_engine_optimizer?.title || productData.title || void 0,
272
+ description: productData.search_engine_optimizer?.description || "",
273
+ image_url: productData.search_engine_optimizer?.image_url || productData.image_url || "",
274
+ image_path: productData.search_engine_optimizer?.image_path || productData.image_path || "",
275
+ block_crawler: productData.search_engine_optimizer?.block_crawler ?? false
276
+ },
277
+ images_attributes: productData.images?.map((img) => ({
278
+ id: img.id,
279
+ position: img.position || 0,
280
+ image_url: img.image_url,
281
+ image_path: img.image_path && !img.image_path.includes("undefined") ? img.image_path : img.image_url ? extractFilenameFromUrl(img.image_url) : void 0,
282
+ _destroy: false
283
+ })) || [],
284
+ ...productData.images && productData.images.length > 0 && { image_path: (() => {
285
+ if (productData.image_path && typeof productData.image_path === "string" && !productData.image_path.includes("undefined")) return productData.image_path;
286
+ const firstImage = productData.images.find((img) => img.position === 0);
287
+ if (firstImage?.image_path && typeof firstImage.image_path === "string" && !firstImage.image_path.includes("undefined")) return firstImage.image_path;
288
+ return productData.image_url ? extractFilenameFromUrl(productData.image_url) : void 0;
289
+ })() },
290
+ product_subscription_plans: (() => {
291
+ const plans = productData?.product_subscription_plans?.map((plan) => ({
292
+ ...plan,
293
+ active: plan?.active
294
+ })) || [];
295
+ return plans.length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans;
296
+ })(),
297
+ product_subscription_plans_attributes: (() => {
298
+ const plans = productData?.product_subscription_plans?.map((plan) => ({
299
+ ...plan,
300
+ active: plan?.active
301
+ })) || [];
302
+ return plansToAttributes(plans.length > 0 ? ensureDefaultSubscriptionPlan(plans) : plans);
303
+ })(),
304
+ variants_attributes: productData?.variants?.filter((variant) => variant.id !== null && variant.id !== void 0).map((variant) => ({
305
+ id: variant.id,
306
+ title: variant.title ?? productData?.title ?? "Untitled Variant",
307
+ option_attrs: variant.option_attrs || [],
308
+ sku: variant.sku || void 0,
309
+ price: variant.price,
310
+ track_quantity: variant.track_quantity ?? false,
311
+ keep_selling: variant.keep_selling ?? false,
312
+ bar_code: variant.bar_code ?? "",
313
+ limit_subscription: variant.limit_subscription,
314
+ subscription_max_qty: variant.subscription_max_qty ?? 0,
315
+ customer_limit: variant.customer_limit ?? 0,
316
+ is_master: variant.is_master,
317
+ _destroy: false,
318
+ images_attributes: variant?.images?.map((image) => ({
319
+ id: image.id,
320
+ position: image.position || 0,
321
+ image_url: image.image_url,
322
+ _destroy: false
323
+ })),
324
+ inventory_levels_attributes: variant?.inventory_levels?.filter((level) => (level.warehouse_id ?? level.warehouse?.id) != null).map((level) => ({
325
+ id: level.id,
326
+ available: level.available,
327
+ committed: level.committed,
328
+ on_hand: level.on_hand,
329
+ unavailable: level.unavailable,
330
+ warehouse_id: level.warehouse?.id || 0,
331
+ _destroy: false
332
+ })),
333
+ variant_countries_attributes: variant?.variant_countries ? Object.entries(variant.variant_countries).map(([iso, country]) => ({
334
+ id: country.id ?? 0,
335
+ active: country.active ?? true,
336
+ country_id: country.country_id,
337
+ country_name: country.country_name ?? "",
338
+ country_iso: iso,
339
+ price: Number(country.price) || 0,
340
+ subscription_price: Number(country.subscription_price) || 0,
341
+ wholesale: Number(country.wholesale) || 0,
342
+ wholesale_subscription_price: Number(country.wholesale_subscription_price) || 0,
343
+ compare_price: Number(country.compare_price) || 0,
344
+ cv: Number(country.cv) || 0,
345
+ qv: Number(country.qv) || 0,
346
+ pc_cv: Number(country.pc_cv) || 0,
347
+ pc_qv: Number(country.pc_qv) || 0,
348
+ cost_of_goods_sold: Number(country.cost_of_goods_sold) || 0,
349
+ currency_code: country.currency_code || null,
350
+ shipping: Number(country.shipping) || 0,
351
+ points: country.points
352
+ })) : []
353
+ })),
354
+ bundle: productData.product_bundles && productData.product_bundles.length > 0,
355
+ track_inventory_on_bundle_items: productData.track_inventory_on_bundle_items ?? false,
356
+ product_bundles_attributes: (productData.product_bundles || []).map((bundle) => ({
357
+ id: bundle.id,
358
+ bundled_variant_id: bundle.bundled_variant?.id || 0,
359
+ bundled_variant: {
360
+ title: bundle.bundled_variant?.title || "",
361
+ sku: bundle.bundled_variant?.sku || null,
362
+ price: String(bundle.bundled_variant?.price || "0"),
363
+ price_in_currency: bundle.bundled_variant?.price_in_currency || "",
364
+ currency_code: bundle.bundled_variant?.currency_code,
365
+ product: {
366
+ id: bundle.bundled_variant?.product.id || 0,
367
+ title: bundle.bundled_variant?.product.title || "",
368
+ image_url: bundle.bundled_variant?.product.image_url || "",
369
+ price: bundle.bundled_variant?.product.price || "0",
370
+ price_in_currency: bundle.bundled_variant?.product.price_in_currency || "",
371
+ cv: bundle.bundled_variant?.product.cv || 0,
372
+ qv: bundle.bundled_variant?.product.qv || 0
373
+ }
374
+ },
375
+ cv: bundle.cv || 0,
376
+ qv: bundle.qv || 0,
377
+ quantity: bundle.quantity,
378
+ display_externally: bundle.display_externally ?? true,
379
+ _destroy: false
380
+ })),
381
+ option_attrs: productData.option_attrs || [],
382
+ options: productData.options || [],
383
+ metafields_attributes: (productData.metafields || []).map((metafield) => ({
384
+ id: metafield.id,
385
+ namespace: metafield.namespace,
386
+ key: metafield.key,
387
+ value: metafield.value,
388
+ value_type: metafield.value_type,
389
+ _destroy: false
390
+ })),
391
+ metadata: productData.metadata || {},
392
+ errors: {},
393
+ isValid: false,
394
+ isDirty: false
395
+ });
396
+ },
397
+ updateSlug: (slug, isManual = true) => {
398
+ set((state) => ({
399
+ slug,
400
+ custom_slug: isManual,
401
+ search_engine_optimizer_attributes: {
402
+ ...state.search_engine_optimizer_attributes,
403
+ title: state.search_engine_optimizer_attributes?.title || "",
404
+ description: state.search_engine_optimizer_attributes?.description || "",
405
+ image_url: state.search_engine_optimizer_attributes?.image_url || "",
406
+ image_path: state.search_engine_optimizer_attributes?.image_path || "",
407
+ block_crawler: state.search_engine_optimizer_attributes?.block_crawler ?? false
408
+ },
409
+ isDirty: true
410
+ }));
411
+ },
412
+ updateSEO: (seo) => {
413
+ set((state) => ({
414
+ search_engine_optimizer_attributes: {
415
+ ...state.search_engine_optimizer_attributes,
416
+ title: seo.title !== void 0 ? seo.title : state.search_engine_optimizer_attributes?.title || "",
417
+ description: seo.description !== void 0 ? seo.description : state.search_engine_optimizer_attributes?.description || "",
418
+ image_url: seo.image_url !== void 0 ? seo.image_url : state.search_engine_optimizer_attributes?.image_url || "",
419
+ image_path: seo.image_path !== void 0 ? seo.image_path : state.search_engine_optimizer_attributes?.image_path || "",
420
+ block_crawler: seo.block_crawler !== void 0 ? seo.block_crawler : state.search_engine_optimizer_attributes?.block_crawler ?? false
421
+ },
422
+ isDirty: true
423
+ }));
424
+ },
425
+ updateField: (key, value, options) => {
426
+ const { shouldValidate = false, shouldClearError = true, markDirty = true } = options || {};
427
+ set((state) => {
428
+ if (key === "product_subscription_plans") return {
429
+ ...state,
430
+ ...syncSubscriptionPlans(value),
431
+ errors: shouldClearError ? {
432
+ ...state.errors,
433
+ [key]: void 0
434
+ } : state.errors,
435
+ isDirty: markDirty ? true : state.isDirty
436
+ };
437
+ return {
438
+ ...state,
439
+ [key]: value,
440
+ errors: shouldClearError ? {
441
+ ...state.errors,
442
+ [key]: void 0
443
+ } : state.errors,
444
+ isDirty: markDirty ? true : state.isDirty
445
+ };
446
+ });
447
+ if (shouldValidate) get().validateField(key);
448
+ },
449
+ updatePartial: (updates) => {
450
+ set((state) => {
451
+ if (updates.product_subscription_plans) return {
452
+ ...state,
453
+ ...updates,
454
+ ...syncSubscriptionPlans(updates.product_subscription_plans),
455
+ errors: {
456
+ ...state.errors,
457
+ ...Object.keys(updates).reduce((acc, key) => {
458
+ acc[key] = void 0;
459
+ return acc;
460
+ }, {})
461
+ },
462
+ isDirty: true
463
+ };
464
+ return {
465
+ ...state,
466
+ ...updates,
467
+ errors: {
468
+ ...state.errors,
469
+ ...Object.keys(updates).reduce((acc, key) => {
470
+ acc[key] = void 0;
471
+ return acc;
472
+ }, {})
473
+ },
474
+ isDirty: true
475
+ };
476
+ });
477
+ },
478
+ updateArrayItem: (arrayKey, itemId, updatedItem, idField = "id") => {
479
+ set((state) => {
480
+ const updatedArray = (Array.isArray(state[arrayKey]) ? state[arrayKey] : []).map((item) => {
481
+ if (typeof item === "object" && item !== null && idField in item && item[idField] === itemId) return updatedItem;
482
+ return item;
483
+ });
484
+ if (arrayKey === "product_subscription_plans") return {
485
+ ...state,
486
+ ...syncSubscriptionPlans(updatedArray),
487
+ errors: {
488
+ ...state.errors,
489
+ [arrayKey]: void 0
490
+ },
491
+ isDirty: true
492
+ };
493
+ return {
494
+ ...state,
495
+ [arrayKey]: updatedArray,
496
+ errors: {
497
+ ...state.errors,
498
+ [arrayKey]: void 0
499
+ },
500
+ isDirty: true
501
+ };
502
+ });
503
+ },
504
+ reset: () => {
505
+ set({
506
+ ...defaultState,
507
+ track_inventory_on_bundle_items: false,
508
+ custom_slug: false,
509
+ errors: {},
510
+ isValid: false,
511
+ isDirty: false
512
+ });
513
+ },
514
+ validateField: (field) => {
515
+ const fieldValue = get()[field];
516
+ const hasValue = fieldValue !== void 0 && fieldValue !== null && fieldValue !== "";
517
+ set((state) => ({
518
+ errors: {
519
+ ...state.errors,
520
+ [field]: hasValue ? void 0 : `${field} is required`
521
+ },
522
+ isValid: hasValue && Object.keys(state.errors).every((key) => key === field || !state.errors[key])
523
+ }));
524
+ },
525
+ validateRequired: () => {
526
+ const state = get();
527
+ const errors = {};
528
+ if (!state.title) errors.title = "Title is required";
529
+ if (Object.keys(errors).length > 0) {
530
+ set({
531
+ errors,
532
+ isValid: false
533
+ });
534
+ return false;
535
+ }
536
+ set({
537
+ errors: {},
538
+ isValid: true
539
+ });
540
+ return true;
541
+ },
542
+ clearErrors: () => {
543
+ set({
544
+ errors: {},
545
+ isValid: false
546
+ });
547
+ },
548
+ clearFieldError: (field) => {
549
+ set((state) => ({ errors: {
550
+ ...state.errors,
551
+ [field]: void 0
552
+ } }));
553
+ },
554
+ markClean: () => {
555
+ set({ isDirty: false });
556
+ },
557
+ setTranslationLoading: (languageIso, loading) => {
558
+ set((state) => ({ translationLoading: {
559
+ ...state.translationLoading,
560
+ [languageIso]: loading
561
+ } }));
562
+ },
563
+ setTranslationData: (languageIso, data) => {
564
+ set((state) => ({
565
+ translations: {
566
+ ...state.translations,
567
+ [languageIso]: data
568
+ },
569
+ translationLoading: {
570
+ ...state.translationLoading,
571
+ [languageIso]: false
572
+ }
573
+ }));
574
+ },
575
+ updateTranslationField: (languageIso, field, value) => {
576
+ set((state) => {
577
+ const originalValue = state.translations[languageIso]?.[field];
578
+ let error;
579
+ if (field === "title" && value === "" && originalValue && originalValue.trim() !== "") error = "Title is required";
580
+ return {
581
+ editedTranslations: {
582
+ ...state.editedTranslations,
583
+ [languageIso]: {
584
+ ...state.editedTranslations[languageIso],
585
+ [field]: value
586
+ }
587
+ },
588
+ translationErrors: {
589
+ ...state.translationErrors,
590
+ [languageIso]: {
591
+ ...state.translationErrors[languageIso],
592
+ [field]: error
593
+ }
594
+ }
595
+ };
596
+ });
597
+ },
598
+ getTranslation: (languageIso, field) => {
599
+ const state = get();
600
+ return state.editedTranslations[languageIso]?.[field] ?? state.translations[languageIso]?.[field];
601
+ },
602
+ getOriginalTranslation: (languageIso, field) => {
603
+ return get().translations[languageIso]?.[field];
604
+ },
605
+ getEditedTranslation: (languageIso, field) => {
606
+ return get().editedTranslations[languageIso]?.[field];
607
+ },
608
+ setTranslationError: (languageIso, field, error) => {
609
+ set((state) => ({ translationErrors: {
610
+ ...state.translationErrors,
611
+ [languageIso]: {
612
+ ...state.translationErrors[languageIso],
613
+ [field]: error
614
+ }
615
+ } }));
616
+ },
617
+ getTranslationError: (languageIso, field) => {
618
+ return get().translationErrors[languageIso]?.[field];
619
+ },
620
+ isTranslationLoading: (languageIso) => {
621
+ return get().translationLoading[languageIso] ?? false;
622
+ },
623
+ resetTranslations: () => {
624
+ set({
625
+ translations: {},
626
+ editedTranslations: {},
627
+ translationErrors: {},
628
+ translationLoading: {},
629
+ translationsFetched: false
630
+ });
631
+ },
632
+ setTranslationsFetched: (fetched) => {
633
+ set({ translationsFetched: fetched });
634
+ }
635
+ });
636
+ create()(createProductStore);
637
+ create()((set, get) => ({
638
+ draftData: null,
639
+ isFromSettings: false,
640
+ navigationTarget: null,
641
+ saveDraft: (data) => {
642
+ const formData = data;
643
+ if (formData?.title || formData?.description || formData?.sku || formData?.product_subscription_plans && formData.product_subscription_plans.length > 0) set({ draftData: data });
644
+ },
645
+ getDraft: () => {
646
+ const { draftData, isFromSettings, navigationTarget } = get();
647
+ if (!draftData) return null;
648
+ if (isFromSettings && navigationTarget) return draftData;
649
+ set({ draftData: null });
650
+ return null;
651
+ },
652
+ clearDraft: () => {
653
+ const { draftData } = get();
654
+ if (draftData) set({ draftData: null });
655
+ },
656
+ setFromSettings: (value) => {
657
+ set({ isFromSettings: value });
658
+ },
659
+ setNavigationTarget: (target) => {
660
+ set({ navigationTarget: target });
661
+ },
662
+ reset: () => {
663
+ set({
664
+ draftData: null,
665
+ isFromSettings: false,
666
+ navigationTarget: null
667
+ });
668
+ }
669
+ }));
670
+ //#endregion
671
+ //#region ../../products/core/src/utils/product-helpers.ts
672
+ function getProductImageUrl(product) {
673
+ if (!product) return null;
674
+ if (Array.isArray(product.images) && product.images.length > 0) {
675
+ const primaryImage = [...product.images].sort((a, b) => (a.position ?? 0) - (b.position ?? 0))[0];
676
+ if (primaryImage?.image_url) return primaryImage.image_url;
677
+ }
678
+ return product.image_url ?? null;
679
+ }
680
+ //#endregion
681
+ //#region ../../products/core/src/utils/product-price.ts
682
+ function stripParentheticalText(text) {
683
+ if (!text) return null;
684
+ return text.replace(/\s*\([^)]*\)/g, "").trim();
685
+ }
686
+ function isShopVariantCountry(vc) {
687
+ return vc !== void 0 && "display_wholesale_subscription_price" in vc;
688
+ }
689
+ function isAdminProduct(product) {
690
+ return "display_price" in product;
691
+ }
692
+ function isVariantCountriesRecord(vc) {
693
+ return vc !== null && typeof vc === "object" && !Array.isArray(vc);
694
+ }
695
+ function determineProductPrice(product, countryIso) {
696
+ const { variants } = product;
697
+ const selectedVariant = variants?.find((v) => {
698
+ if (isVariantCountriesRecord(v.variant_countries)) return v.variant_countries[countryIso]?.active;
699
+ return false;
700
+ }) || variants?.[0] || null;
701
+ let variantCountry;
702
+ if (countryIso && selectedVariant?.variant_countries) {
703
+ const variantCountries = selectedVariant.variant_countries;
704
+ if (Array.isArray(variantCountries)) variantCountry = variantCountries.find((v) => v?.country?.iso === countryIso);
705
+ else if (isVariantCountriesRecord(variantCountries)) variantCountry = variantCountries[countryIso];
706
+ }
707
+ if (selectedVariant?.subscription_only) return { repPrice: isShopVariantCountry(variantCountry) ? variantCountry.display_wholesale_subscription_price : void 0 };
708
+ const price = isShopVariantCountry(variantCountry) ? variantCountry.display_price : isAdminProduct(product) ? product.display_price : void 0;
709
+ const repPrice = isShopVariantCountry(variantCountry) ? variantCountry.display_wholesale : void 0;
710
+ return {
711
+ repPrice: stripParentheticalText(repPrice),
712
+ price: price === repPrice ? null : stripParentheticalText(price)
713
+ };
714
+ }
715
+ //#endregion
716
+ //#region src/adapters/products-api-adapter.ts
717
+ /**
718
+ * Creates a PortalProductsApi-compatible adapter from a portal-tenant FetchClient.
719
+ *
720
+ * This bridges the auto-generated portal-tenant API client to the abstract
721
+ * PortalProductsApi interface defined in @fluid-app/products-core, closing
722
+ * over the FetchClient so consumers don't need to pass it per-call.
723
+ *
724
+ * Each method maps the BFF response to the port type at runtime rather than
725
+ * using type assertions, so TypeScript catches schema drift between the
726
+ * generated client and the hand-authored port types at compile time.
727
+ */
728
+ function createPortalProductsApiAdapter(client) {
729
+ return {
730
+ listProducts: async (params) => {
731
+ const response = await products_list(client, {
732
+ "page[cursor]": params?.cursor,
733
+ "page[limit]": params?.limit,
734
+ sort: params?.sort
735
+ });
736
+ return {
737
+ products: response.products ?? [],
738
+ meta: response.meta
739
+ };
740
+ },
741
+ getProduct: async (id) => {
742
+ const response = await products_show(client, id);
743
+ return {
744
+ product: response.product ?? {},
745
+ meta: response.meta
746
+ };
747
+ },
748
+ searchProducts: async (query, params) => {
749
+ const response = await products_search(client, {
750
+ q: query,
751
+ "page[cursor]": params?.cursor,
752
+ "page[limit]": params?.limit
753
+ });
754
+ return {
755
+ products: response.products ?? [],
756
+ meta: response.meta
757
+ };
758
+ },
759
+ getProductMedia: async (productId) => {
760
+ const response = await products_media_list(client, productId);
761
+ return {
762
+ media: response.media ?? [],
763
+ meta: response.meta
764
+ };
765
+ }
766
+ };
767
+ }
768
+ //#endregion
769
+ //#region src/products/PortalProductsApiProvider.tsx
770
+ function PortalProductsApiProvider({ children }) {
771
+ const client = usePortalTenantClient();
772
+ return /* @__PURE__ */ jsx(PortalProductsCoreProvider, {
773
+ api: useMemo(() => createPortalProductsApiAdapter(client), [client]),
774
+ children
775
+ });
776
+ }
777
+ //#endregion
778
+ export { usePortalProductCatalog as a, usePortalProductDetail as i, determineProductPrice as n, usePortalProductsApi as o, getProductImageUrl as r, PortalProductsApiProvider as t };
779
+
780
+ //# sourceMappingURL=PortalProductsApiProvider-BCXX9NGK.mjs.map