@fluid-app/portal-sdk 0.1.246 → 0.1.248

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 (112) hide show
  1. package/dist/{FluidProvider-CNk1Y2k1.mjs → FluidProvider-Bwg1cGSY.mjs} +177 -5
  2. package/dist/FluidProvider-Bwg1cGSY.mjs.map +1 -0
  3. package/dist/{FluidProvider-o1Gu53TN.cjs → FluidProvider-DprqXNu4.cjs} +188 -4
  4. package/dist/FluidProvider-DprqXNu4.cjs.map +1 -0
  5. package/dist/{MessagingScreen-BwI0RShj.cjs → MessagingScreen-BKb4mWGa.cjs} +2 -2
  6. package/dist/{MessagingScreen-WCeHWGlX.cjs → MessagingScreen-CDiLGmMi.cjs} +2 -2
  7. package/dist/{MessagingScreen-WCeHWGlX.cjs.map → MessagingScreen-CDiLGmMi.cjs.map} +1 -1
  8. package/dist/{MessagingScreen-DiSZ7fyd.mjs → MessagingScreen-DGhqsVXi.mjs} +2 -2
  9. package/dist/{MessagingScreen-DiSZ7fyd.mjs.map → MessagingScreen-DGhqsVXi.mjs.map} +1 -1
  10. package/dist/{ProfileScreen-BfvdQa0q.cjs → ProfileScreen-BDLJgcXg.cjs} +2 -2
  11. package/dist/{ProfileScreen-BfvdQa0q.cjs.map → ProfileScreen-BDLJgcXg.cjs.map} +1 -1
  12. package/dist/{ProfileScreen-CRLf8oDe.mjs → ProfileScreen-CmQDKNaP.mjs} +2 -2
  13. package/dist/{ProfileScreen-CRLf8oDe.mjs.map → ProfileScreen-CmQDKNaP.mjs.map} +1 -1
  14. package/dist/{ProfileScreen-Za3ZIWPO.cjs → ProfileScreen-DHv2Cjpz.cjs} +2 -2
  15. package/dist/{ShopScreen-S6rBaoWM.cjs → ShopScreen---dB03HI.cjs} +282 -63
  16. package/dist/ShopScreen---dB03HI.cjs.map +1 -0
  17. package/dist/{ShopScreen-BigHJ5wE.cjs → ShopScreen-B6ygTHDB.cjs} +2 -2
  18. package/dist/{ShopScreen-BG1pxd2D.mjs → ShopScreen-kiVwC38W.mjs} +283 -64
  19. package/dist/ShopScreen-kiVwC38W.mjs.map +1 -0
  20. package/dist/de-CqKH8kwp.cjs +12 -0
  21. package/dist/de-CqKH8kwp.cjs.map +1 -0
  22. package/dist/de-DWONEOZS.mjs +6 -0
  23. package/dist/de-DWONEOZS.mjs.map +1 -0
  24. package/dist/el-CIrAhB-W.cjs +12 -0
  25. package/dist/el-CIrAhB-W.cjs.map +1 -0
  26. package/dist/el-De7Ne7it.mjs +6 -0
  27. package/dist/el-De7Ne7it.mjs.map +1 -0
  28. package/dist/es-4Wsa13tV.cjs +12 -0
  29. package/dist/es-4Wsa13tV.cjs.map +1 -0
  30. package/dist/es-B5_ItPIn.mjs +6 -0
  31. package/dist/es-B5_ItPIn.mjs.map +1 -0
  32. package/dist/fr-BDKPrKKW.cjs +12 -0
  33. package/dist/fr-BDKPrKKW.cjs.map +1 -0
  34. package/dist/fr-jgEDP2og.mjs +6 -0
  35. package/dist/fr-jgEDP2og.mjs.map +1 -0
  36. package/dist/he-5dq6lV2h.cjs +12 -0
  37. package/dist/he-5dq6lV2h.cjs.map +1 -0
  38. package/dist/he-DLQdVr_g.mjs +6 -0
  39. package/dist/he-DLQdVr_g.mjs.map +1 -0
  40. package/dist/hu-CC4QdkPb.mjs +6 -0
  41. package/dist/hu-CC4QdkPb.mjs.map +1 -0
  42. package/dist/hu-Dpgriy5N.cjs +12 -0
  43. package/dist/hu-Dpgriy5N.cjs.map +1 -0
  44. package/dist/id-Ba-0RT7y.cjs +12 -0
  45. package/dist/id-Ba-0RT7y.cjs.map +1 -0
  46. package/dist/id-CwGC2v1d.mjs +6 -0
  47. package/dist/id-CwGC2v1d.mjs.map +1 -0
  48. package/dist/index.cjs +50 -14
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +1 -8
  51. package/dist/index.d.cts.map +1 -1
  52. package/dist/index.d.mts +1 -8
  53. package/dist/index.d.mts.map +1 -1
  54. package/dist/index.mjs +51 -15
  55. package/dist/index.mjs.map +1 -1
  56. package/dist/it-CaxIV-R4.cjs +12 -0
  57. package/dist/it-CaxIV-R4.cjs.map +1 -0
  58. package/dist/it-jUZZ5sjO.mjs +6 -0
  59. package/dist/it-jUZZ5sjO.mjs.map +1 -0
  60. package/dist/ja-Lcg_Qqtj.cjs +12 -0
  61. package/dist/ja-Lcg_Qqtj.cjs.map +1 -0
  62. package/dist/ja-QVQymwAE.mjs +6 -0
  63. package/dist/ja-QVQymwAE.mjs.map +1 -0
  64. package/dist/ko-CFu0TjJO.cjs +12 -0
  65. package/dist/ko-CFu0TjJO.cjs.map +1 -0
  66. package/dist/ko-DfzzTwZI.mjs +6 -0
  67. package/dist/ko-DfzzTwZI.mjs.map +1 -0
  68. package/dist/nl-DR9IRXGT.cjs +12 -0
  69. package/dist/nl-DR9IRXGT.cjs.map +1 -0
  70. package/dist/nl-Dys3mUo2.mjs +6 -0
  71. package/dist/nl-Dys3mUo2.mjs.map +1 -0
  72. package/dist/pl-CBwEisEK.mjs +6 -0
  73. package/dist/pl-CBwEisEK.mjs.map +1 -0
  74. package/dist/pl-DSGSRDM2.cjs +12 -0
  75. package/dist/pl-DSGSRDM2.cjs.map +1 -0
  76. package/dist/pt-D5al7xw3.mjs +6 -0
  77. package/dist/pt-D5al7xw3.mjs.map +1 -0
  78. package/dist/pt-Pz_D1HUz.cjs +12 -0
  79. package/dist/pt-Pz_D1HUz.cjs.map +1 -0
  80. package/dist/ro-B43SoGdE.mjs +6 -0
  81. package/dist/ro-B43SoGdE.mjs.map +1 -0
  82. package/dist/ro-BoGeZTac.cjs +12 -0
  83. package/dist/ro-BoGeZTac.cjs.map +1 -0
  84. package/dist/ru-Cd7LUmcu.cjs +12 -0
  85. package/dist/ru-Cd7LUmcu.cjs.map +1 -0
  86. package/dist/ru-ChwnncDc.mjs +6 -0
  87. package/dist/ru-ChwnncDc.mjs.map +1 -0
  88. package/dist/th-C9S_8Tv6.mjs +6 -0
  89. package/dist/th-C9S_8Tv6.mjs.map +1 -0
  90. package/dist/th-DwLAQd0u.cjs +12 -0
  91. package/dist/th-DwLAQd0u.cjs.map +1 -0
  92. package/dist/tl-CiPbx_5F.mjs +6 -0
  93. package/dist/tl-CiPbx_5F.mjs.map +1 -0
  94. package/dist/tl-DwAVpDyB.cjs +12 -0
  95. package/dist/tl-DwAVpDyB.cjs.map +1 -0
  96. package/dist/tr-BFbCmHQZ.cjs +12 -0
  97. package/dist/tr-BFbCmHQZ.cjs.map +1 -0
  98. package/dist/tr-CUd4dp2u.mjs +6 -0
  99. package/dist/tr-CUd4dp2u.mjs.map +1 -0
  100. package/dist/zh_CN-Cn-k18Y5.cjs +12 -0
  101. package/dist/zh_CN-Cn-k18Y5.cjs.map +1 -0
  102. package/dist/zh_CN-D46-GUTP.mjs +6 -0
  103. package/dist/zh_CN-D46-GUTP.mjs.map +1 -0
  104. package/dist/zh_TW-CIUhIeJP.cjs +12 -0
  105. package/dist/zh_TW-CIUhIeJP.cjs.map +1 -0
  106. package/dist/zh_TW-XqA7UKxt.mjs +6 -0
  107. package/dist/zh_TW-XqA7UKxt.mjs.map +1 -0
  108. package/package.json +15 -13
  109. package/dist/FluidProvider-CNk1Y2k1.mjs.map +0 -1
  110. package/dist/FluidProvider-o1Gu53TN.cjs.map +0 -1
  111. package/dist/ShopScreen-BG1pxd2D.mjs.map +0 -1
  112. package/dist/ShopScreen-S6rBaoWM.cjs.map +0 -1
@@ -1,16 +1,36 @@
1
1
  import { r as __exportAll } from "./es-BXxGlAp6.mjs";
2
- import { n as useFluidContext } from "./FluidProvider-CNk1Y2k1.mjs";
2
+ import { l as useActiveLocale, n as useFluidContext } from "./FluidProvider-Bwg1cGSY.mjs";
3
3
  import { $ as DropdownMenuSeparator, A as Select, C as Skeleton, Dn as Button, F as RadioGroup, I as RadioGroupItem, J as DropdownMenuContent, M as SelectItem, N as SelectTrigger, P as SelectValue, Q as DropdownMenuRadioItem, X as DropdownMenuLabel, Z as DropdownMenuRadioGroup, dn as BreadcrumbLink, fn as BreadcrumbList, j as SelectContent, ln as Breadcrumb, mn as BreadcrumbSeparator, pn as BreadcrumbPage, q as DropdownMenu, rt as DropdownMenuTrigger, un as BreadcrumbItem, wt as Card } from "./src-pgBBOcJa.mjs";
4
4
  import { n as useScreenHeaderActions, r as useScreenHeaderBreadcrumbs } from "./ScreenHeaderContext-Cemdo7bM.mjs";
5
5
  import { t as useStore } from "./use-store-C2KBIS41.mjs";
6
6
  import { n as useAppNavigation } from "./AppNavigationContext-DNod9mf6.mjs";
7
7
  import { t as SearchSort } from "./SearchSort-CokMCrhy.mjs";
8
8
  import { a as usePortalProductCatalog, i as usePortalProductDetail, n as determineProductPrice, r as getProductImageUrl, t as PortalProductsApiProvider } from "./PortalProductsApiProvider-BFdHFvog.mjs";
9
- import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
9
+ import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
10
10
  import { useInfiniteQuery } from "@tanstack/react-query";
11
11
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
12
  import { ArrowUpDown, ChevronLeft, ChevronRight, CirclePlay, ShoppingCart } from "lucide-react";
13
13
  import { createPortal } from "react-dom";
14
+ //#region ../../platform/i18n/src/translation-api-context-factory.ts
15
+ function createTranslationContext(domainName) {
16
+ const Ctx = createContext(null);
17
+ function useTranslation() {
18
+ const api = useContext(Ctx);
19
+ if (!api) throw new Error(`use${domainName}Translation must be used within a ${domainName}TranslationProvider`);
20
+ return api;
21
+ }
22
+ return {
23
+ Context: Ctx,
24
+ Provider: Ctx.Provider,
25
+ useTranslation
26
+ };
27
+ }
28
+ //#endregion
29
+ //#region ../../shop/core/src/translation-api-context.ts
30
+ const { Provider, useTranslation } = createTranslationContext("Shop");
31
+ const ShopTranslationProvider = Provider;
32
+ const useShopTranslation = useTranslation;
33
+ //#endregion
14
34
  //#region ../../shop/ui/src/utils/media-helpers.ts
15
35
  const VIDEO_EXTENSIONS = [
16
36
  ".mp4",
@@ -72,10 +92,11 @@ function formatPortalPrice(price, currency) {
72
92
  }
73
93
  function ProductCardContent({ product, countryIso, companyLogoUrl, renderImage = defaultRenderImage$1 }) {
74
94
  const [isHovered, setIsHovered] = useState(false);
95
+ const { t } = useShopTranslation();
75
96
  const isPortal = isPortalProduct(product);
76
97
  const coverImage = isPortal ? getPortalProductCoverImage(product) : getProductImageUrl(product);
77
98
  const isVideo = isVideoUrl(coverImage);
78
- const productName = isPortal ? product.name || "No title available" : product.title || "No title available";
99
+ const productName = isPortal ? product.name || t("no_title") : product.title || t("no_title");
79
100
  let repPrice = null;
80
101
  let price = null;
81
102
  if (isPortal) if (product.wholesale_price) {
@@ -143,6 +164,15 @@ function ProductCardContent({ product, countryIso, companyLogoUrl, renderImage =
143
164
  " ",
144
165
  getVariantCountryValue(getSelectedVariant(product), countryIso, "qv") || "-"
145
166
  ]
167
+ }),
168
+ isPortal && product.wholesale_price != null && /* @__PURE__ */ jsxs("div", {
169
+ className: "text-muted-foreground text-sm",
170
+ children: [
171
+ "CV ",
172
+ product.cv ?? "-",
173
+ " | QV ",
174
+ product.qv ?? "-"
175
+ ]
146
176
  })
147
177
  ]
148
178
  })] });
@@ -319,18 +349,18 @@ function QuantitySelector({ quantity, setQuantity }) {
319
349
  //#endregion
320
350
  //#region ../../shop/ui/src/components/purchase-options.tsx
321
351
  function PurchaseOptions({ showBuyOnce, showSubscribe, isSubscribe, onSubscribeChange, product_subscription_plans, selectedSubscriptionPlan, onSubscriptionPlanChange, userSelectedSubscribe, wholesalePrice, wholesaleSubscriptionPrice }) {
352
+ const { t } = useShopTranslation();
322
353
  const defaultSubscriptionPlan = useMemo(() => {
323
354
  if (!product_subscription_plans?.length) return null;
324
355
  return product_subscription_plans.find((plan) => plan.default) || product_subscription_plans[0];
325
356
  }, [product_subscription_plans]);
326
357
  const currentSubscriptionPlan = selectedSubscriptionPlan || defaultSubscriptionPlan;
327
- const savingsText = useMemo(() => {
358
+ const savingsPercentage = useMemo(() => {
328
359
  if (wholesalePrice === void 0 || wholesaleSubscriptionPrice === void 0 || wholesalePrice <= 0) return null;
329
360
  const savings = wholesalePrice - wholesaleSubscriptionPrice;
330
361
  if (savings <= 0) return null;
331
- const savingsPercentage = Math.round(savings / wholesalePrice * 100);
332
- if (savingsPercentage <= 0) return null;
333
- return `Save ${savingsPercentage}%`;
362
+ const pct = Math.round(savings / wholesalePrice * 100);
363
+ return pct > 0 ? pct : null;
334
364
  }, [wholesalePrice, wholesaleSubscriptionPrice]);
335
365
  const formatSubscriptionPlan = (plan) => {
336
366
  return `${plan.subscription_plan.billing_interval} ${plan.subscription_plan.billing_interval_unit} (${plan.subscription_plan.name})`;
@@ -364,22 +394,22 @@ function PurchaseOptions({ showBuyOnce, showSubscribe, isSubscribe, onSubscribeC
364
394
  className: `flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${isSubscribe ? "border-contrast bg-contrast text-foreground" : "border-border bg-background text-muted-foreground"}`
365
395
  }), /* @__PURE__ */ jsxs("div", {
366
396
  className: "flex-1",
367
- children: [/* @__PURE__ */ jsxs("div", {
397
+ children: [/* @__PURE__ */ jsx("div", {
368
398
  className: "text-foreground mb-1 text-sm leading-tight font-medium",
369
- children: ["Subscribe", savingsText ? ` & ${savingsText}` : ""]
399
+ children: savingsPercentage ? t("subscribe_and_save", { percentage: savingsPercentage }) : t("subscribe")
370
400
  }), product_subscription_plans?.length > 0 && /* @__PURE__ */ jsxs("div", {
371
401
  className: "bg-muted mt-3 rounded-lg p-2",
372
402
  onClick: (e) => e.stopPropagation(),
373
403
  children: [/* @__PURE__ */ jsx("div", {
374
404
  className: "text-foreground mb-1 text-xs font-medium",
375
- children: "Delivery Frequency:"
405
+ children: t("delivery_frequency")
376
406
  }), /* @__PURE__ */ jsxs(Select, {
377
407
  value: currentSubscriptionPlan?.subscription_plan.id.toString() || "",
378
408
  onValueChange: handleSubscriptionPlanChange,
379
409
  disabled: product_subscription_plans?.length === 1,
380
410
  children: [/* @__PURE__ */ jsx(SelectTrigger, {
381
411
  className: "bg-background text-foreground! w-full text-xs",
382
- children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select delivery schedule" })
412
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("select_delivery_schedule") })
383
413
  }), /* @__PURE__ */ jsx(SelectContent, { children: subscriptionPlanOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, {
384
414
  value: option.value,
385
415
  children: option.label
@@ -399,7 +429,7 @@ function PurchaseOptions({ showBuyOnce, showSubscribe, isSubscribe, onSubscribeC
399
429
  className: `flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${!isSubscribe ? "border-contrast bg-contrast text-foreground" : "border-border bg-background text-muted-foreground"}`
400
430
  }), /* @__PURE__ */ jsx("div", {
401
431
  className: "text-foreground mb-1 text-sm leading-tight font-medium",
402
- children: "One-Time Purchase"
432
+ children: t("one_time_purchase")
403
433
  })]
404
434
  })
405
435
  })]
@@ -415,32 +445,6 @@ function sanitizeHtml(html) {
415
445
  for (const el of doc.querySelectorAll("*")) for (const attr of [...el.attributes]) if (attr.name.toLowerCase().startsWith("on") || attr.value.toLowerCase().trim().startsWith("javascript:")) el.removeAttribute(attr.name);
416
446
  return doc.body.innerHTML;
417
447
  }
418
- const SORT_OPTIONS = [
419
- {
420
- id: "title_asc",
421
- label: "Title (A-Z)"
422
- },
423
- {
424
- id: "title_desc",
425
- label: "Title (Z-A)"
426
- },
427
- {
428
- id: "price_asc",
429
- label: "Price (Low to High)"
430
- },
431
- {
432
- id: "price_desc",
433
- label: "Price (High to Low)"
434
- },
435
- {
436
- id: "created_at_desc",
437
- label: "Recently Updated"
438
- },
439
- {
440
- id: "created_at_asc",
441
- label: "Oldest Updated"
442
- }
443
- ];
444
448
  const GRID_CLASS = "grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4";
445
449
  function SkeletonGrid({ count = 8 }) {
446
450
  return /* @__PURE__ */ jsx("div", {
@@ -458,6 +462,7 @@ function SkeletonGrid({ count = 8 }) {
458
462
  }
459
463
  function ProductListing({ companyLogoUrl, renderImage, onSelectProduct, cartButton }) {
460
464
  const observerTarget = useRef(null);
465
+ const { t } = useShopTranslation();
461
466
  const catalog = usePortalProductCatalog({ perPage: PAGE_SIZE });
462
467
  const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage, error, isFetched } = useInfiniteQuery({
463
468
  queryKey: catalog.queryKey,
@@ -483,6 +488,32 @@ function ProductListing({ companyLogoUrl, renderImage, onSelectProduct, cartButt
483
488
  return () => observer.disconnect();
484
489
  }, [handleIntersect]);
485
490
  const allProducts = data?.pages.flatMap((page) => page.products) ?? [];
491
+ const sortOptions = useMemo(() => [
492
+ {
493
+ id: "title_asc",
494
+ label: t("sort_title_asc")
495
+ },
496
+ {
497
+ id: "title_desc",
498
+ label: t("sort_title_desc")
499
+ },
500
+ {
501
+ id: "price_asc",
502
+ label: t("sort_price_asc")
503
+ },
504
+ {
505
+ id: "price_desc",
506
+ label: t("sort_price_desc")
507
+ },
508
+ {
509
+ id: "created_at_desc",
510
+ label: t("sort_recent")
511
+ },
512
+ {
513
+ id: "created_at_asc",
514
+ label: t("sort_oldest")
515
+ }
516
+ ], [t]);
486
517
  return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
487
518
  className: "mx-auto px-2 md:px-10",
488
519
  children: /* @__PURE__ */ jsxs("div", {
@@ -493,7 +524,7 @@ function ProductListing({ companyLogoUrl, renderImage, onSelectProduct, cartButt
493
524
  children: /* @__PURE__ */ jsx(SearchSort, {
494
525
  searchValue: catalog.searchTerm,
495
526
  onSearchChange: catalog.setSearchTerm,
496
- placeholder: "Search products..."
527
+ placeholder: t("search_placeholder")
497
528
  })
498
529
  }),
499
530
  /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
@@ -508,12 +539,12 @@ function ProductListing({ companyLogoUrl, renderImage, onSelectProduct, cartButt
508
539
  align: "end",
509
540
  className: "w-60",
510
541
  children: [
511
- /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Sort By" }),
542
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: t("sort_by") }),
512
543
  /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
513
544
  /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
514
545
  value: catalog.currentSort,
515
546
  onValueChange: catalog.setCurrentSort,
516
- children: SORT_OPTIONS.map((opt) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
547
+ children: sortOptions.map((opt) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
517
548
  value: opt.id,
518
549
  children: opt.label
519
550
  }, opt.id))
@@ -528,14 +559,14 @@ function ProductListing({ companyLogoUrl, renderImage, onSelectProduct, cartButt
528
559
  })
529
560
  }), /* @__PURE__ */ jsx("div", {
530
561
  className: "mx-auto space-y-8 px-2 md:px-10 md:py-8",
531
- children: isLoading ? /* @__PURE__ */ jsx(SkeletonGrid, {}) : error ? /* @__PURE__ */ jsxs("p", {
562
+ children: isLoading ? /* @__PURE__ */ jsx(SkeletonGrid, {}) : error ? /* @__PURE__ */ jsx("p", {
532
563
  className: "mx-auto my-6 rounded-lg bg-red-100 px-3 py-2 text-red-500",
533
- children: ["Error: ", error.message]
564
+ children: t("error_generic")
534
565
  }) : isFetched && allProducts.length === 0 ? /* @__PURE__ */ jsx("div", {
535
566
  className: "flex flex-col items-center justify-center py-8 text-center",
536
567
  children: /* @__PURE__ */ jsx("p", {
537
568
  className: "text-muted-foreground text-sm",
538
- children: catalog.searchTerm ? `No products match "${catalog.searchTerm}". Try a different search term.` : "There are no products available at the moment."
569
+ children: catalog.searchTerm ? t("no_search_results", { term: catalog.searchTerm }) : t("no_products")
539
570
  })
540
571
  }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
541
572
  /* @__PURE__ */ jsx("div", {
@@ -628,11 +659,14 @@ function ProductDetail({ productId, renderImage }) {
628
659
  const [selections, setSelections] = useState({});
629
660
  const [userSelectedSubscribe, setUserSelectedSubscribe] = useState(false);
630
661
  const [selectedSubscriptionPlan, setSelectedSubscriptionPlan] = useState(void 0);
662
+ const { t } = useShopTranslation();
631
663
  const { product, isLoading, error, images } = usePortalProductDetail({ productId });
632
664
  const variants = useMemo(() => product?.variants ?? [], [product?.variants]);
633
665
  const subscriptionPlans = useMemo(() => product?.subscription_plans ?? [], [product?.subscription_plans]);
634
666
  const masterVariant = useMemo(() => variants.find((v) => v.is_master) ?? variants[0], [variants]);
635
667
  const optionGroups = useMemo(() => buildOptionGroups(variants), [variants]);
668
+ const showVariantChoices = optionGroups.length === 0 && variants.length > 1;
669
+ const [selectedVariantId, setSelectedVariantId] = useState(null);
636
670
  useEffect(() => {
637
671
  if (optionGroups.length === 0) return;
638
672
  const source = variants.find((v) => !v.is_master) ?? masterVariant;
@@ -645,14 +679,27 @@ function ProductDetail({ productId, renderImage }) {
645
679
  variants,
646
680
  masterVariant
647
681
  ]);
682
+ useEffect(() => {
683
+ if (!showVariantChoices) return;
684
+ if (selectedVariantId != null) return;
685
+ if (masterVariant?.id == null) return;
686
+ setSelectedVariantId(masterVariant.id);
687
+ }, [
688
+ showVariantChoices,
689
+ selectedVariantId,
690
+ masterVariant?.id
691
+ ]);
648
692
  const selectedVariant = useMemo(() => {
693
+ if (showVariantChoices) return variants.find((v) => v.id === selectedVariantId) ?? masterVariant;
649
694
  if (optionGroups.length === 0) return masterVariant;
650
695
  return findVariantBySelections(variants, selections) ?? masterVariant;
651
696
  }, [
652
697
  variants,
653
698
  optionGroups,
654
699
  selections,
655
- masterVariant
700
+ masterVariant,
701
+ showVariantChoices,
702
+ selectedVariantId
656
703
  ]);
657
704
  const legacySubscriptionPlans = useMemo(() => mapToLegacySubscriptionPlans(subscriptionPlans), [subscriptionPlans]);
658
705
  const isSubscribe = selectedVariant?.subscription_only === true || userSelectedSubscribe;
@@ -708,10 +755,10 @@ function ProductDetail({ productId, renderImage }) {
708
755
  className: "text-center",
709
756
  children: [/* @__PURE__ */ jsx("h3", {
710
757
  className: "text-foreground mb-2 text-lg font-medium",
711
- children: "Unable to load product"
758
+ children: t("error_loading")
712
759
  }), /* @__PURE__ */ jsx("p", {
713
760
  className: "text-muted-foreground",
714
- children: "Something went wrong. Please try again later."
761
+ children: t("error_generic")
715
762
  })]
716
763
  })
717
764
  });
@@ -721,14 +768,14 @@ function ProductDetail({ productId, renderImage }) {
721
768
  className: "text-center",
722
769
  children: [/* @__PURE__ */ jsx("h3", {
723
770
  className: "text-foreground mb-2 text-lg font-medium",
724
- children: "Product not found"
771
+ children: t("product_not_found")
725
772
  }), /* @__PURE__ */ jsx("p", {
726
773
  className: "text-muted-foreground",
727
- children: "The product you're looking for doesn't exist."
774
+ children: t("product_not_found_description")
728
775
  })]
729
776
  })
730
777
  });
731
- const title = product.name || "Product";
778
+ const title = product.name || t("product_fallback_name");
732
779
  const isBundle = product.bundle === true;
733
780
  const bundleUrl = isBundle && product.canonical_url ? product.canonical_url : null;
734
781
  return /* @__PURE__ */ jsx("div", {
@@ -763,12 +810,22 @@ function ProductDetail({ productId, renderImage }) {
763
810
  className: "pt-2",
764
811
  children: [/* @__PURE__ */ jsx("h3", {
765
812
  className: "text-foreground mb-1 text-sm font-medium",
766
- children: "Product Description"
813
+ children: t("product_description")
767
814
  }), /* @__PURE__ */ jsx("div", {
768
815
  className: "text-foreground mb-3 text-[12px]",
769
816
  dangerouslySetInnerHTML: { __html: sanitizeHtml(product.description ?? "") }
770
817
  })]
771
818
  }),
819
+ product.wholesale_price != null && /* @__PURE__ */ jsxs("div", {
820
+ className: "text-muted-foreground mb-3 text-sm",
821
+ children: [
822
+ "CV ",
823
+ selectedVariant?.cv ?? "-",
824
+ " | QV",
825
+ " ",
826
+ selectedVariant?.qv ?? "-"
827
+ ]
828
+ }),
772
829
  isBundle ? /* @__PURE__ */ jsxs("div", {
773
830
  className: "pt-4",
774
831
  children: [/* @__PURE__ */ jsx(Button, {
@@ -778,10 +835,10 @@ function ProductDetail({ productId, renderImage }) {
778
835
  onClick: () => {
779
836
  if (bundleUrl) window.open(bundleUrl, "_blank", "noopener,noreferrer");
780
837
  },
781
- children: "Purchase Bundle"
838
+ children: t("purchase_bundle")
782
839
  }), !bundleUrl && /* @__PURE__ */ jsx("p", {
783
840
  className: "text-muted-foreground mt-2 text-center text-xs",
784
- children: "Bundle configuration is unavailable. Please contact support."
841
+ children: t("bundle_unavailable")
785
842
  })]
786
843
  }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
787
844
  /* @__PURE__ */ jsx(PurchaseOptions, {
@@ -811,7 +868,7 @@ function ProductDetail({ productId, renderImage }) {
811
868
  })),
812
869
  children: [/* @__PURE__ */ jsx(SelectTrigger, {
813
870
  className: "w-48 max-w-full",
814
- children: /* @__PURE__ */ jsx(SelectValue, { placeholder: `Select ${group.name}` })
871
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("select_option", { name: group.name }) })
815
872
  }), /* @__PURE__ */ jsx(SelectContent, {
816
873
  position: "popper",
817
874
  className: "max-h-60",
@@ -823,9 +880,33 @@ function ProductDetail({ productId, renderImage }) {
823
880
  })]
824
881
  }, group.optionId))
825
882
  }),
883
+ showVariantChoices && /* @__PURE__ */ jsx("div", {
884
+ className: "mb-4 pt-4",
885
+ children: /* @__PURE__ */ jsxs("div", {
886
+ className: "mb-3 flex items-center",
887
+ children: [/* @__PURE__ */ jsx("h3", {
888
+ className: "text-md text-foreground w-24 font-bold",
889
+ children: "Variant"
890
+ }), /* @__PURE__ */ jsxs(Select, {
891
+ value: selectedVariantId != null ? String(selectedVariantId) : "",
892
+ onValueChange: (value) => setSelectedVariantId(Number(value)),
893
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
894
+ className: "w-48 max-w-full",
895
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select variant" })
896
+ }), /* @__PURE__ */ jsx(SelectContent, {
897
+ position: "popper",
898
+ className: "max-h-60",
899
+ children: variants.map((v, idx) => v.id == null ? null : /* @__PURE__ */ jsx(SelectItem, {
900
+ value: String(v.id),
901
+ children: v.title || `Variant ${idx + 1}`
902
+ }, v.id))
903
+ })]
904
+ })]
905
+ })
906
+ }),
826
907
  selectedVariant?.subscription_only && !selectedVariant?.allow_subscription && /* @__PURE__ */ jsx("div", {
827
908
  className: "text-muted-foreground text-sm",
828
- children: "This product is unavailable for purchase."
909
+ children: t("product_unavailable")
829
910
  }),
830
911
  /* @__PURE__ */ jsx("div", { className: "mt-4 mb-3" }),
831
912
  /* @__PURE__ */ jsxs("div", {
@@ -842,7 +923,7 @@ function ProductDetail({ productId, renderImage }) {
842
923
  "data-fluid-subscribe": isSubscribe,
843
924
  "data-fluid-subscription-plan-id": isSubscribe ? String(resolvedPlanId ?? "") : "",
844
925
  "data-fluid-open-cart-after-add": "false",
845
- children: [/* @__PURE__ */ jsx(ShoppingCart, { className: "h-4 w-4" }), isSubscribe ? "Subscribe" : "Add to Cart"]
926
+ children: [/* @__PURE__ */ jsx(ShoppingCart, { className: "h-4 w-4" }), isSubscribe ? t("subscribe") : t("add_to_cart")]
846
927
  })]
847
928
  })
848
929
  ] })
@@ -1027,13 +1108,142 @@ function ShopContainer({ children, className = "", cartScript, cartWidget }) {
1027
1108
  }) });
1028
1109
  }
1029
1110
  //#endregion
1111
+ //#region ../../platform/i18n/src/use-domain-dict.ts
1112
+ function useDomainDict(domain, locale) {
1113
+ const [dict, setDict] = useState(domain.fallback);
1114
+ useEffect(() => {
1115
+ let cancelled = false;
1116
+ if (locale === domain.fallbackLocale) {
1117
+ setDict(domain.fallback);
1118
+ return;
1119
+ }
1120
+ setDict(domain.fallback);
1121
+ domain.load(locale).then((next) => {
1122
+ if (!cancelled) setDict(next);
1123
+ }).catch(() => {
1124
+ if (!cancelled) setDict(domain.fallback);
1125
+ });
1126
+ return () => {
1127
+ cancelled = true;
1128
+ };
1129
+ }, [domain, locale]);
1130
+ return dict;
1131
+ }
1132
+ //#endregion
1133
+ //#region ../../platform/i18n/src/translations.ts
1134
+ function createDomainTranslations(config) {
1135
+ const fallbackLocale = config.fallbackLocale ?? "en";
1136
+ return {
1137
+ fallback: config.fallback,
1138
+ fallbackLocale,
1139
+ async load(locale) {
1140
+ if (locale === fallbackLocale) return config.fallback;
1141
+ const loader = config.loaders?.[locale];
1142
+ if (!loader) return config.fallback;
1143
+ const target = await loader();
1144
+ return {
1145
+ ...config.fallback,
1146
+ ...target
1147
+ };
1148
+ }
1149
+ };
1150
+ }
1151
+ //#endregion
1152
+ //#region ../../platform/i18n/src/static-dict-adapter.ts
1153
+ function createStaticDictAdapter(locale, dict) {
1154
+ return {
1155
+ locale,
1156
+ t(key, ...args) {
1157
+ const template = dict[key] ?? key;
1158
+ const params = args[0];
1159
+ if (!params) return template;
1160
+ return template.replace(/\{\{(\w+)\}\}/g, (match, name) => name in params ? String(params[name]) : match);
1161
+ }
1162
+ };
1163
+ }
1164
+ //#endregion
1165
+ //#region ../../shop/core/src/translation-adapter.ts
1166
+ const shopDomain = createDomainTranslations({
1167
+ fallback: {
1168
+ breadcrumb: "Shop",
1169
+ product_fallback_name: "Product",
1170
+ search_placeholder: "Search products...",
1171
+ sort_by: "Sort By",
1172
+ sort_title_asc: "Title (A-Z)",
1173
+ sort_title_desc: "Title (Z-A)",
1174
+ sort_price_asc: "Price (Low to High)",
1175
+ sort_price_desc: "Price (High to Low)",
1176
+ sort_recent: "Recently Updated",
1177
+ sort_oldest: "Oldest Updated",
1178
+ no_products: "There are no products available at the moment.",
1179
+ no_search_results: "No products match \"{{term}}\". Try a different search term.",
1180
+ error_loading: "Unable to load product",
1181
+ error_generic: "Something went wrong. Please try again later.",
1182
+ product_not_found: "Product not found",
1183
+ product_not_found_description: "The product you're looking for doesn't exist.",
1184
+ product_description: "Product Description",
1185
+ no_title: "No title available",
1186
+ add_to_cart: "Add to Cart",
1187
+ subscribe: "Subscribe",
1188
+ subscribe_and_save: "Subscribe & Save {{percentage}}%",
1189
+ one_time_purchase: "One-Time Purchase",
1190
+ delivery_frequency: "Delivery Frequency:",
1191
+ select_delivery_schedule: "Select delivery schedule",
1192
+ purchase_bundle: "Purchase Bundle",
1193
+ bundle_unavailable: "Bundle configuration is unavailable. Please contact support.",
1194
+ product_unavailable: "This product is unavailable for purchase.",
1195
+ ratings_and_reviews: "Ratings and reviews",
1196
+ ratings_count: "{{count}} ratings",
1197
+ select_option: "Select {{name}}"
1198
+ },
1199
+ loaders: {
1200
+ de: () => import("./de-DWONEOZS.mjs").then((m) => m.default),
1201
+ el: () => import("./el-De7Ne7it.mjs").then((m) => m.default),
1202
+ es: () => import("./es-B5_ItPIn.mjs").then((m) => m.default),
1203
+ fr: () => import("./fr-jgEDP2og.mjs").then((m) => m.default),
1204
+ he: () => import("./he-DLQdVr_g.mjs").then((m) => m.default),
1205
+ hu: () => import("./hu-CC4QdkPb.mjs").then((m) => m.default),
1206
+ id: () => import("./id-CwGC2v1d.mjs").then((m) => m.default),
1207
+ it: () => import("./it-jUZZ5sjO.mjs").then((m) => m.default),
1208
+ ja: () => import("./ja-QVQymwAE.mjs").then((m) => m.default),
1209
+ ko: () => import("./ko-DfzzTwZI.mjs").then((m) => m.default),
1210
+ nl: () => import("./nl-Dys3mUo2.mjs").then((m) => m.default),
1211
+ pl: () => import("./pl-CBwEisEK.mjs").then((m) => m.default),
1212
+ pt: () => import("./pt-D5al7xw3.mjs").then((m) => m.default),
1213
+ ro: () => import("./ro-B43SoGdE.mjs").then((m) => m.default),
1214
+ ru: () => import("./ru-ChwnncDc.mjs").then((m) => m.default),
1215
+ th: () => import("./th-C9S_8Tv6.mjs").then((m) => m.default),
1216
+ tl: () => import("./tl-CiPbx_5F.mjs").then((m) => m.default),
1217
+ tr: () => import("./tr-CUd4dp2u.mjs").then((m) => m.default),
1218
+ zh_CN: () => import("./zh_CN-D46-GUTP.mjs").then((m) => m.default),
1219
+ zh_TW: () => import("./zh_TW-XqA7UKxt.mjs").then((m) => m.default)
1220
+ }
1221
+ });
1222
+ function createShopTranslationAdapter(locale, dict) {
1223
+ return createStaticDictAdapter(locale, dict);
1224
+ }
1225
+ //#endregion
1226
+ //#region src/providers/ShopTranslationBridge.tsx
1227
+ function ShopTranslationBridge({ children }) {
1228
+ const { locale } = useActiveLocale();
1229
+ const dict = useDomainDict(shopDomain, locale);
1230
+ return /* @__PURE__ */ jsx(ShopTranslationProvider, {
1231
+ value: useMemo(() => createShopTranslationAdapter(locale, dict), [locale, dict]),
1232
+ children
1233
+ });
1234
+ }
1235
+ //#endregion
1030
1236
  //#region src/screens/ShopScreen.tsx
1031
1237
  var ShopScreen_exports = /* @__PURE__ */ __exportAll({
1032
1238
  ShopScreen: () => ShopScreen,
1033
1239
  shopScreenPropertySchema: () => shopScreenPropertySchema
1034
1240
  });
1035
- function ShopScreen({ background, textColor, accentColor, padding, borderRadius, ...divProps }) {
1241
+ function ShopScreen(props) {
1242
+ return /* @__PURE__ */ jsx(ShopTranslationBridge, { children: /* @__PURE__ */ jsx(ShopScreenContent, { ...props }) });
1243
+ }
1244
+ function ShopScreenContent({ background, textColor, accentColor, padding, borderRadius, ...divProps }) {
1036
1245
  const { config } = useFluidContext();
1246
+ const { t } = useShopTranslation();
1037
1247
  const { data: store } = useStore();
1038
1248
  const { currentSlug, navigate } = useAppNavigation();
1039
1249
  const countryCode = config.countryIso ?? "US";
@@ -1044,12 +1254,16 @@ function ShopScreen({ background, textColor, accentColor, padding, borderRadius,
1044
1254
  children: /* @__PURE__ */ jsx(BreadcrumbItem, { children: productId ? /* @__PURE__ */ jsx(BreadcrumbLink, {
1045
1255
  onClick: () => navigate("shop"),
1046
1256
  className: "cursor-pointer font-semibold",
1047
- children: "Shop"
1257
+ children: t("breadcrumb")
1048
1258
  }) : /* @__PURE__ */ jsx(BreadcrumbPage, {
1049
1259
  className: "font-semibold",
1050
- children: "Shop"
1260
+ children: t("breadcrumb")
1051
1261
  }) })
1052
- }) }), [productId, navigate]));
1262
+ }) }), [
1263
+ productId,
1264
+ navigate,
1265
+ t
1266
+ ]));
1053
1267
  useScreenHeaderActions(useMemo(() => /* @__PURE__ */ jsx("div", {
1054
1268
  className: "flex items-center gap-4",
1055
1269
  children: /* @__PURE__ */ jsx(CartButton, {})
@@ -1123,15 +1337,16 @@ const shopScreenPropertySchema = {
1123
1337
  */
1124
1338
  function ProductBreadcrumb({ productId }) {
1125
1339
  const { navigate } = useAppNavigation();
1340
+ const { t } = useShopTranslation();
1126
1341
  const { product } = usePortalProductDetail({ productId });
1127
- const productName = product?.name ?? "Product";
1342
+ const productName = product?.name ?? t("product_fallback_name");
1128
1343
  useScreenHeaderBreadcrumbs(useMemo(() => /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsxs(BreadcrumbList, {
1129
1344
  className: "text-lg",
1130
1345
  children: [
1131
1346
  /* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsx(BreadcrumbLink, {
1132
1347
  onClick: () => navigate("shop"),
1133
1348
  className: "cursor-pointer font-semibold",
1134
- children: "Shop"
1349
+ children: t("breadcrumb")
1135
1350
  }) }),
1136
1351
  /* @__PURE__ */ jsx(BreadcrumbSeparator, {}),
1137
1352
  /* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsx(BreadcrumbPage, {
@@ -1139,10 +1354,14 @@ function ProductBreadcrumb({ productId }) {
1139
1354
  children: productName
1140
1355
  }) })
1141
1356
  ]
1142
- }) }), [productName, navigate]));
1357
+ }) }), [
1358
+ productName,
1359
+ navigate,
1360
+ t
1361
+ ]));
1143
1362
  return null;
1144
1363
  }
1145
1364
  //#endregion
1146
1365
  export { ShopScreen_exports as n, shopScreenPropertySchema as r, ShopScreen as t };
1147
1366
 
1148
- //# sourceMappingURL=ShopScreen-BG1pxd2D.mjs.map
1367
+ //# sourceMappingURL=ShopScreen-kiVwC38W.mjs.map