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