@shoppexio/storefront-react 0.1.2 → 0.1.4

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.4
4
+
5
+ - Catalog cards are sold out when no option can be ordered, including a
6
+ minimum order above the remaining stock (`isCardSoldOut`), so a card never
7
+ offers a quick add that `add()` refuses.
8
+
9
+ ## 0.1.3
10
+
11
+ - Cart: every add carries the add-ons the merchant marked required
12
+ (`withRequiredAddons`), including adds from cards, bundle dialogs and
13
+ bundle offers, so the quote and the invoice include the mandatory
14
+ surcharge.
15
+
3
16
  ## 0.1.2
4
17
 
5
18
  - Contact form: a message that is longer than the 2,000-character ticket
package/dist/index.d.ts CHANGED
@@ -2278,6 +2278,15 @@ declare function useCart(): CartContextValue;
2278
2278
  * the call site rather than leaving the rejection unhandled — the error is
2279
2279
  * displayed, not swallowed.
2280
2280
  */
2281
+ /**
2282
+ * The add-ons a cart line carries: the caller's choice plus every add-on the
2283
+ * merchant marked required, once each.
2284
+ *
2285
+ * PAYMENT PATH. The buy box preselects and locks required add-ons, but a card,
2286
+ * a bundle dialog or a related tile adds without choosing any. Without this the
2287
+ * line, its quote and the invoice omit a surcharge the merchant made mandatory.
2288
+ */
2289
+ declare function withRequiredAddons(product: StorefrontProduct, chosen: readonly ProductAddon[]): ProductAddon[];
2281
2290
  declare function startCartMutation(mutation: Promise<void>): void;
2282
2291
 
2283
2292
  /**
@@ -2525,6 +2534,14 @@ interface GroupCardModel {
2525
2534
  price: number;
2526
2535
  }
2527
2536
  type CatalogCardModel = ProductCardModel | GroupCardModel;
2537
+ /**
2538
+ * A card is sold out when nothing on it can be ordered: no stock at all, or no
2539
+ * option whose effective quantity range is non-empty (`quantity_min` 2 against
2540
+ * one unit left). PAYMENT PATH: the card's quick add goes through `add()`,
2541
+ * which refuses exactly these selections, so an active button here would be a
2542
+ * control that silently does nothing.
2543
+ */
2544
+ declare function isCardSoldOut(product: StorefrontProduct): boolean;
2528
2545
  interface StorefrontCatalog {
2529
2546
  cards: CatalogCardModel[];
2530
2547
  categories: StorefrontCategory[];
@@ -3106,4 +3123,4 @@ declare function useOnlineUserCount(): number | null;
3106
3123
  */
3107
3124
  declare function resolveProductVideoEmbedSrc(value: unknown): string | null;
3108
3125
 
3109
- export { ACCOUNT_ARTIFACT_CAPABILITIES, ACCOUNT_PATH, ACCOUNT_PATH_ALIAS, ACCOUNT_ROUTE_MESSAGE_KEYS, ACCOUNT_STOREFRONT_ROUTES, ACCOUNT_TABS, type AccountRouteMessageKey, type AccountRouteParts, type AccountTab, type AccountView, type BuyBoxVariantModel, CATALOG_PAGE_SIZE, CATALOG_SORTS, CATALOG_SORT_LABELS, type CartBoundsHeal, CartProvider, type CartQuoteLineBounds, type CartTotals, type CartView, type CartViewLine, type CatalogCardModel, type CatalogPage, type CatalogSort, type CheckoutFieldGroup, type CheckoutFieldValues, type CheckoutFields, type ContactFormValues, type ContactSubmissionContext, DEFAULT_ACCOUNT_TAB, DEFAULT_LOW_STOCK_THRESHOLD, DELIVERY_TIME_UNITS, type DeliveryPromise, type DeliveryTimeUnit, type GroupCardModel, IMPLEMENTED_ACCOUNT_TABS, type ImplementedAccountTab, type LicenseStatement, type LicenseTerm, type LinePricing, MAX_PAY_WHAT_YOU_WANT_PRICE, type MenuNavLink, type MenuSlot, type NavLink, type NavigationLinks, PRODUCT_BADGE_ICON_NAMES, type ProductAddon, type ProductAutomaticDeal, type ProductBadge, type ProductBadgeIconName, type ProductBundle, type ProductBundleItem, type ProductCardModel, type ProductCategoryRef, type ProductContentTab, type ProductCustomField, type ProductDetailModel, type ProductFaq, type ProductRatingModel, type ProductSubscription, type ProductType, QUOTE_UNAVAILABLE_CHECKOUT_ERROR, type RatingStars, type ResellerProgramSummary, type RewardProgramItem, type RewardProgramSummary, SERVING_CONTEXT_HINT, SHOP_REVIEW_PAGE_SIZE, STOREFRONT_SORT_KEYS, type SdkCartAddOptions, type SdkCartAddon, type SdkCartAppliedDiscount, type SdkCartCodeSource, type SdkCartItem, type SdkCartQuote, type SdkCartQuoteLine, type SdkCheckoutResult, type SdkCustomerAffiliateLink, type SdkCustomerAffiliateSummary, type SdkCustomerDashboard, type SdkCustomerDashboardOrder, type SdkCustomerDeliverable, type SdkCustomerDeliveryStatus, type SdkCustomerDeliverySummary, type SdkCustomerLicense, type SdkCustomerLoyalty, type SdkCustomerLoyaltyRedeem, type SdkCustomerLoyaltyTransactionType, type SdkCustomerOrderDetail, type SdkCustomerOrderPage, type SdkCustomerOrderSummary, type SdkCustomerRewardActivity, type SdkCustomerRewards, type SdkCustomerSubscription, type SdkCustomerTicketSummary, type SdkCustomerWarranty, type SdkCustomerWarrantyClaim, type SdkCustomerWarrantyClaimStatus, type SdkCustomerWarrantyList, type SdkCustomerWarrantyStatus, type SdkEligibleCartDeal, type SdkInitOptions, type SdkMenu, type SdkMenuItem, type SdkPage, type SdkRecentSaleEntry, type SdkResponse, type SdkShopReview, type ShopPageFaqItem, type ShopPageModel, type ShopPageState, type ShopReview, type ShopReviewLabels, type ShopReviewsState, type ShoppexSdk, type SocialLink, type SocialNetwork, type StockChip, type StockTone, type StorefrontAddon, type StorefrontCatalog, type StorefrontCategory, type StorefrontData, type StorefrontGroup, type StorefrontListingItem, type StorefrontPriceVariant, type StorefrontProduct, StorefrontProvider, type StorefrontSettings, type StorefrontShop, type StorefrontShopStats, type StorefrontSortKey, type SubscriptionIntervalUnit, type SupportChannel, type VolumeDiscountRule, accountOrderHref, accountRouteMessage, accountTabHref, accountTabLabelKey, averageRating, badgesForCard, badgesForProductPage, buildCartTotals, buildCartView, buildCustomFieldPayload, buildInitialCheckoutFieldValues, buildProductDetail, buildStorefrontCatalog, calculateDisplayLineTotal, calculateLinePricing, canonicalAccountPath, checkoutFieldKey, checkoutFieldWriteRepriced, checkoutNeedsDetails, clampQuantity, clearRecoveredQuoteCheckoutError, filterCatalogCards, findStorefrontProduct, firstOptionalString, flattenMerchantHtmlToText, formatCompactCount, formatDeliveryTime, formatLicenseTerm, formatMoney, formatSubscriptionCadence, formatSubscriptionTrial, getAuthoredContent, getBuyerCurrency, getProductGroups, getProducts, getShoppex, getStorefrontAddons, getStorefrontCategories, getStorefrontListing, getStorefrontSettings, getStorefrontShop, hasInjectedStorefrontData, isAccountTab, isBlankMerchantHtml, isCheckboxValueChecked, isImplementedAccountTab, isProductSoldOut, isRecord, isSelectionSoldOut, loadLatestWrittenReviews, loadShopPage, missingRequiredCheckoutValues, optionalBoolean, optionalString, optionalStringWithDefault, paginateCatalogCards, parseAccountPath, parseCartQuoteLines, parseEnum, parseFiniteNumber, parseProductBadges, parseStorefrontSortKey, readCheckoutNeedsDetails, readStorefrontData, requireArray, requireBoolean, requireNumber, requireRecord, requireString, requireStringFromKeys, requireUnknownRecord, resolveAccountView, resolveBadgeForeground, resolveCartBoundsHeals, resolveCategorySelection, resolveCheckoutFields, resolveDeliveryPromise, resolveDisplayStock, resolveHideStockCounter, resolveLicenseTerm, resolveMenuLinksForSlot, resolvePayWhatYouWantMinimum, resolveProductVideoEmbedSrc, resolveQuantityBounds, resolveSupportChannels, resolveUnsellableLineIds, resolveVariantStock, reviewsForProduct, roundCurrency, sanitizeMerchantHtml, sortCatalogCards, startCartMutation, stripMerchantHtmlImages, submitContactTicket, toShopReviews, toStarCount, useCart, useNavigationLinks, useOnlineUserCount, useShopReviews, useStorefront, validateCheckoutFieldValue, validateCheckoutFields, validateContactSubmission };
3126
+ export { ACCOUNT_ARTIFACT_CAPABILITIES, ACCOUNT_PATH, ACCOUNT_PATH_ALIAS, ACCOUNT_ROUTE_MESSAGE_KEYS, ACCOUNT_STOREFRONT_ROUTES, ACCOUNT_TABS, type AccountRouteMessageKey, type AccountRouteParts, type AccountTab, type AccountView, type BuyBoxVariantModel, CATALOG_PAGE_SIZE, CATALOG_SORTS, CATALOG_SORT_LABELS, type CartBoundsHeal, CartProvider, type CartQuoteLineBounds, type CartTotals, type CartView, type CartViewLine, type CatalogCardModel, type CatalogPage, type CatalogSort, type CheckoutFieldGroup, type CheckoutFieldValues, type CheckoutFields, type ContactFormValues, type ContactSubmissionContext, DEFAULT_ACCOUNT_TAB, DEFAULT_LOW_STOCK_THRESHOLD, DELIVERY_TIME_UNITS, type DeliveryPromise, type DeliveryTimeUnit, type GroupCardModel, IMPLEMENTED_ACCOUNT_TABS, type ImplementedAccountTab, type LicenseStatement, type LicenseTerm, type LinePricing, MAX_PAY_WHAT_YOU_WANT_PRICE, type MenuNavLink, type MenuSlot, type NavLink, type NavigationLinks, PRODUCT_BADGE_ICON_NAMES, type ProductAddon, type ProductAutomaticDeal, type ProductBadge, type ProductBadgeIconName, type ProductBundle, type ProductBundleItem, type ProductCardModel, type ProductCategoryRef, type ProductContentTab, type ProductCustomField, type ProductDetailModel, type ProductFaq, type ProductRatingModel, type ProductSubscription, type ProductType, QUOTE_UNAVAILABLE_CHECKOUT_ERROR, type RatingStars, type ResellerProgramSummary, type RewardProgramItem, type RewardProgramSummary, SERVING_CONTEXT_HINT, SHOP_REVIEW_PAGE_SIZE, STOREFRONT_SORT_KEYS, type SdkCartAddOptions, type SdkCartAddon, type SdkCartAppliedDiscount, type SdkCartCodeSource, type SdkCartItem, type SdkCartQuote, type SdkCartQuoteLine, type SdkCheckoutResult, type SdkCustomerAffiliateLink, type SdkCustomerAffiliateSummary, type SdkCustomerDashboard, type SdkCustomerDashboardOrder, type SdkCustomerDeliverable, type SdkCustomerDeliveryStatus, type SdkCustomerDeliverySummary, type SdkCustomerLicense, type SdkCustomerLoyalty, type SdkCustomerLoyaltyRedeem, type SdkCustomerLoyaltyTransactionType, type SdkCustomerOrderDetail, type SdkCustomerOrderPage, type SdkCustomerOrderSummary, type SdkCustomerRewardActivity, type SdkCustomerRewards, type SdkCustomerSubscription, type SdkCustomerTicketSummary, type SdkCustomerWarranty, type SdkCustomerWarrantyClaim, type SdkCustomerWarrantyClaimStatus, type SdkCustomerWarrantyList, type SdkCustomerWarrantyStatus, type SdkEligibleCartDeal, type SdkInitOptions, type SdkMenu, type SdkMenuItem, type SdkPage, type SdkRecentSaleEntry, type SdkResponse, type SdkShopReview, type ShopPageFaqItem, type ShopPageModel, type ShopPageState, type ShopReview, type ShopReviewLabels, type ShopReviewsState, type ShoppexSdk, type SocialLink, type SocialNetwork, type StockChip, type StockTone, type StorefrontAddon, type StorefrontCatalog, type StorefrontCategory, type StorefrontData, type StorefrontGroup, type StorefrontListingItem, type StorefrontPriceVariant, type StorefrontProduct, StorefrontProvider, type StorefrontSettings, type StorefrontShop, type StorefrontShopStats, type StorefrontSortKey, type SubscriptionIntervalUnit, type SupportChannel, type VolumeDiscountRule, accountOrderHref, accountRouteMessage, accountTabHref, accountTabLabelKey, averageRating, badgesForCard, badgesForProductPage, buildCartTotals, buildCartView, buildCustomFieldPayload, buildInitialCheckoutFieldValues, buildProductDetail, buildStorefrontCatalog, calculateDisplayLineTotal, calculateLinePricing, canonicalAccountPath, checkoutFieldKey, checkoutFieldWriteRepriced, checkoutNeedsDetails, clampQuantity, clearRecoveredQuoteCheckoutError, filterCatalogCards, findStorefrontProduct, firstOptionalString, flattenMerchantHtmlToText, formatCompactCount, formatDeliveryTime, formatLicenseTerm, formatMoney, formatSubscriptionCadence, formatSubscriptionTrial, getAuthoredContent, getBuyerCurrency, getProductGroups, getProducts, getShoppex, getStorefrontAddons, getStorefrontCategories, getStorefrontListing, getStorefrontSettings, getStorefrontShop, hasInjectedStorefrontData, isAccountTab, isBlankMerchantHtml, isCardSoldOut, isCheckboxValueChecked, isImplementedAccountTab, isProductSoldOut, isRecord, isSelectionSoldOut, loadLatestWrittenReviews, loadShopPage, missingRequiredCheckoutValues, optionalBoolean, optionalString, optionalStringWithDefault, paginateCatalogCards, parseAccountPath, parseCartQuoteLines, parseEnum, parseFiniteNumber, parseProductBadges, parseStorefrontSortKey, readCheckoutNeedsDetails, readStorefrontData, requireArray, requireBoolean, requireNumber, requireRecord, requireString, requireStringFromKeys, requireUnknownRecord, resolveAccountView, resolveBadgeForeground, resolveCartBoundsHeals, resolveCategorySelection, resolveCheckoutFields, resolveDeliveryPromise, resolveDisplayStock, resolveHideStockCounter, resolveLicenseTerm, resolveMenuLinksForSlot, resolvePayWhatYouWantMinimum, resolveProductVideoEmbedSrc, resolveQuantityBounds, resolveSupportChannels, resolveUnsellableLineIds, resolveVariantStock, reviewsForProduct, roundCurrency, sanitizeMerchantHtml, sortCatalogCards, startCartMutation, stripMerchantHtmlImages, submitContactTicket, toShopReviews, toStarCount, useCart, useNavigationLinks, useOnlineUserCount, useShopReviews, useStorefront, validateCheckoutFieldValue, validateCheckoutFields, validateContactSubmission, withRequiredAddons };
package/dist/index.js CHANGED
@@ -1473,8 +1473,12 @@ function resolvePriceLabel(product) {
1473
1473
  }
1474
1474
  return formatMoney(product.price, product.currency);
1475
1475
  }
1476
+ function isCardSoldOut(product) {
1477
+ if (isProductSoldOut(product)) return true;
1478
+ return product.priceVariants.length > 0 ? product.priceVariants.every((variant) => isSelectionSoldOut(product, variant)) : isSelectionSoldOut(product, null);
1479
+ }
1476
1480
  function buildProductCard(product, settings, sortPriority) {
1477
- const soldOut = isProductSoldOut(product);
1481
+ const soldOut = isCardSoldOut(product);
1478
1482
  const isInfoCard = product.productType === "INFO_CARD";
1479
1483
  const stock = resolveDisplayStock(product);
1480
1484
  const hideCounter = resolveHideStockCounter(product, settings);
@@ -1998,7 +2002,7 @@ function CartProvider({ children }) {
1998
2002
  );
1999
2003
  }
2000
2004
  const { min: minimum, max: maximum } = resolveQuantityBounds(product, variant);
2001
- const addons = options?.addons ?? [];
2005
+ const addons = withRequiredAddons(product, options?.addons ?? []);
2002
2006
  const payWhatYouWantPrice = options?.payWhatYouWantPrice ?? (product.payWhatYouWant ? resolvePayWhatYouWantMinimum(product, variant) : void 0);
2003
2007
  const addonsUnitPrice = addons.reduce((sum, addon) => sum + addon.price, 0);
2004
2008
  const unitPriceSnapshot = payWhatYouWantPrice !== void 0 ? payWhatYouWantPrice + addonsUnitPrice : calculateLinePricing(product, variant, addons, quantity).effectiveUnitPrice;
@@ -2039,12 +2043,18 @@ function CartProvider({ children }) {
2039
2043
  }
2040
2044
  const { bounds } = member;
2041
2045
  const payWhatYouWantPrice = member.product.payWhatYouWant ? resolvePayWhatYouWantMinimum(member.product, member.variant) : void 0;
2046
+ const requiredAddons = withRequiredAddons(member.product, []);
2047
+ const addonsUnitPrice = requiredAddons.reduce((sum, addon) => sum + addon.price, 0);
2042
2048
  const addOptions = {
2043
2049
  ...item.variantId !== "default" ? { price_variant_id: item.variantId } : {},
2044
2050
  // The offer states each member's unit price; a line without that
2045
2051
  // snapshot shows no money in the cart until the quote answers. A named
2046
2052
  // price overrides it, because that is the amount the backend charges.
2047
- ...payWhatYouWantPrice !== void 0 ? { price_data: { unit_price: payWhatYouWantPrice }, pay_what_you_want_price: payWhatYouWantPrice } : item.unitPrice > 0 ? { price_data: { unit_price: item.unitPrice } } : {},
2053
+ ...payWhatYouWantPrice !== void 0 ? { price_data: { unit_price: payWhatYouWantPrice + addonsUnitPrice }, pay_what_you_want_price: payWhatYouWantPrice } : item.unitPrice > 0 ? { price_data: { unit_price: item.unitPrice + addonsUnitPrice } } : {},
2054
+ ...requiredAddons.length > 0 ? {
2055
+ addons: requiredAddons.map((addon) => ({ id: addon.id })),
2056
+ addon_labels: requiredAddons.map((addon) => addon.title)
2057
+ } : {},
2048
2058
  title: item.title,
2049
2059
  ...item.variantTitle ? { variant_title: item.variantTitle } : {},
2050
2060
  ...item.imageUrl ? { image_url: item.imageUrl } : {},
@@ -2327,6 +2337,10 @@ function useCart() {
2327
2337
  if (!context) throw new Error("useCart must be used inside CartProvider.");
2328
2338
  return context;
2329
2339
  }
2340
+ function withRequiredAddons(product, chosen) {
2341
+ const ids = new Set(chosen.map((addon) => addon.id));
2342
+ return [...chosen, ...product.addons.filter((addon) => addon.required && !ids.has(addon.id))];
2343
+ }
2330
2344
  function startCartMutation(mutation) {
2331
2345
  void mutation.catch(() => void 0);
2332
2346
  }
@@ -2759,6 +2773,7 @@ export {
2759
2773
  hasInjectedStorefrontData,
2760
2774
  isAccountTab,
2761
2775
  isBlankMerchantHtml,
2776
+ isCardSoldOut,
2762
2777
  isCheckboxValueChecked,
2763
2778
  isImplementedAccountTab,
2764
2779
  isProductSoldOut,
@@ -2818,6 +2833,7 @@ export {
2818
2833
  useStorefront,
2819
2834
  validateCheckoutFieldValue,
2820
2835
  validateCheckoutFields,
2821
- validateContactSubmission
2836
+ validateContactSubmission,
2837
+ withRequiredAddons
2822
2838
  };
2823
2839
  //# sourceMappingURL=index.js.map