@shoppexio/storefront-react 0.1.4 → 0.1.5
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 +12 -0
- package/README.md +1 -1
- package/dist/account.js +93 -58
- package/dist/account.js.map +1 -1
- package/dist/index.d.ts +94 -11
- package/dist/index.js +88 -18
- package/dist/index.js.map +1 -1
- package/eject/account/account-page.tsx +8 -2
- package/eject/account/account-warranties.ts +9 -0
- package/eject/account/messages/ar.json +2 -1
- package/eject/account/messages/de.json +2 -1
- package/eject/account/messages/en.json +2 -1
- package/eject/account/messages/es.json +2 -1
- package/eject/account/messages/fi.json +2 -1
- package/eject/account/messages/fr.json +2 -1
- package/eject/account/messages/hi.json +2 -1
- package/eject/account/messages/it.json +2 -1
- package/eject/account/messages/lt.json +2 -1
- package/eject/account/messages/nl.json +2 -1
- package/eject/account/messages/pl.json +2 -1
- package/eject/account/messages/pt.json +2 -1
- package/eject/account/messages/ru.json +2 -1
- package/eject/account/messages/tr.json +2 -1
- package/eject/account/messages/uk.json +2 -1
- package/eject/account/messages/zh.json +2 -1
- package/eject/account/orders.tsx +6 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -826,10 +826,16 @@ interface ShoppexSdk {
|
|
|
826
826
|
data?: SdkPage[];
|
|
827
827
|
message?: string;
|
|
828
828
|
}>;
|
|
829
|
+
/**
|
|
830
|
+
* On a failure, `status` is the HTTP status (404 for a page that does not
|
|
831
|
+
* exist) and is absent when the request never reached a server. SDK 1.0.87
|
|
832
|
+
* and later; earlier builds send no `status` at all.
|
|
833
|
+
*/
|
|
829
834
|
getPage(slug: string): Promise<{
|
|
830
835
|
success: boolean;
|
|
831
836
|
data?: SdkPage;
|
|
832
837
|
message?: string;
|
|
838
|
+
status?: number;
|
|
833
839
|
}>;
|
|
834
840
|
/** Merchant-configured navigation menus, keyed by slot (header/footer/…). */
|
|
835
841
|
getMenus(): Promise<{
|
|
@@ -896,7 +902,9 @@ interface ShoppexSdk {
|
|
|
896
902
|
* One page of the same feed, newest first. `cursor` is the previous page's
|
|
897
903
|
* `pagination.next_cursor`; omit it for the first page.
|
|
898
904
|
*/
|
|
899
|
-
getShopReviewsPage(cursor?: string | null
|
|
905
|
+
getShopReviewsPage(cursor?: string | null, options?: {
|
|
906
|
+
product?: string | null;
|
|
907
|
+
}): Promise<{
|
|
900
908
|
success: boolean;
|
|
901
909
|
data?: {
|
|
902
910
|
feedback: SdkShopReview[];
|
|
@@ -904,7 +912,16 @@ interface ShoppexSdk {
|
|
|
904
912
|
next_cursor: string | null;
|
|
905
913
|
has_more: boolean;
|
|
906
914
|
};
|
|
915
|
+
/** Counts over the whole list, or over one product's reviews when filtered. */
|
|
916
|
+
summary?: SdkShopReviewsSummary;
|
|
917
|
+
/**
|
|
918
|
+
* The product filter the API applied, echoed back. Absent from an API that
|
|
919
|
+
* predates the filter and ignored it; see `loadShopReviewsPage`.
|
|
920
|
+
*/
|
|
921
|
+
product?: string | null;
|
|
907
922
|
};
|
|
923
|
+
message?: string;
|
|
924
|
+
status?: number;
|
|
908
925
|
}>;
|
|
909
926
|
/** Starts an in-page sign-in. Sends the email and nothing else. */
|
|
910
927
|
requestOtp(email: string): Promise<SdkResponse<unknown>>;
|
|
@@ -1054,6 +1071,14 @@ interface ShoppexSdk {
|
|
|
1054
1071
|
/** Lists the buyer's reseller API keys without plaintext secrets. */
|
|
1055
1072
|
resellerApiKeys(): Promise<SdkResponse<unknown>>;
|
|
1056
1073
|
}
|
|
1074
|
+
interface SdkShopReviewsSummary {
|
|
1075
|
+
total: number;
|
|
1076
|
+
positive: number;
|
|
1077
|
+
neutral: number;
|
|
1078
|
+
negative: number;
|
|
1079
|
+
/** 1-5 average of the scores (5/3/1), null for an empty list. */
|
|
1080
|
+
average_score: number | null;
|
|
1081
|
+
}
|
|
1057
1082
|
interface SdkShopReview {
|
|
1058
1083
|
id: string;
|
|
1059
1084
|
/** 1-5, normalized by the SDK from the shop-feedback score (5/3/1). */
|
|
@@ -2888,6 +2913,8 @@ interface ShopReview {
|
|
|
2888
2913
|
productTitle: string | null;
|
|
2889
2914
|
/** True when the review is tied to a real completed purchase. */
|
|
2890
2915
|
verified: boolean;
|
|
2916
|
+
/** Left by the shop's review automation, not written by the buyer. */
|
|
2917
|
+
automated: boolean;
|
|
2891
2918
|
}
|
|
2892
2919
|
type ShopReviewsState = {
|
|
2893
2920
|
status: 'loading';
|
|
@@ -2925,14 +2952,62 @@ declare function toShopReviews(rows: readonly SdkShopReview[], labels: ShopRevie
|
|
|
2925
2952
|
* derive a number from them.
|
|
2926
2953
|
*/
|
|
2927
2954
|
declare function reviewsForProduct(reviews: readonly ShopReview[], productTitle: string): ShopReview[];
|
|
2955
|
+
/** One page of the shop's reviews, newest first. */
|
|
2956
|
+
interface ShopReviewsPageResult {
|
|
2957
|
+
reviews: ShopReview[];
|
|
2958
|
+
/** Pass to the next call; null on the last page. */
|
|
2959
|
+
nextCursor: string | null;
|
|
2960
|
+
/** Counts over the whole list (or the product's reviews), null when the API sent none. */
|
|
2961
|
+
summary: SdkShopReviewsSummary | null;
|
|
2962
|
+
}
|
|
2963
|
+
/**
|
|
2964
|
+
* One page of reviews from the feed, optionally for one product (its catalog
|
|
2965
|
+
* `id`). Throws when the request fails.
|
|
2966
|
+
*
|
|
2967
|
+
* A product page must never show another product's reviews, so a filtered
|
|
2968
|
+
* request also requires the API to echo the filter back: an API that predates
|
|
2969
|
+
* `product` ignores it and would answer with the whole shop's list.
|
|
2970
|
+
*/
|
|
2971
|
+
declare function loadShopReviewsPage(options: {
|
|
2972
|
+
cursor?: string | null;
|
|
2973
|
+
product?: string | null;
|
|
2974
|
+
labels: ShopReviewLabels;
|
|
2975
|
+
}): Promise<ShopReviewsPageResult>;
|
|
2928
2976
|
/**
|
|
2929
2977
|
* The newest WRITTEN reviews, at most `limit`, for a sample such as a home
|
|
2930
|
-
* section. Pages through the feed only until it has
|
|
2931
|
-
*
|
|
2932
|
-
*
|
|
2933
|
-
|
|
2978
|
+
* section or a product's review tab. Pages through the feed only until it has
|
|
2979
|
+
* enough. Automated entries and ratings without words are skipped, since a
|
|
2980
|
+
* sample of quotes needs quotes. Resolves null when a page request fails.
|
|
2981
|
+
*/
|
|
2982
|
+
declare function loadLatestWrittenReviews(limit: number, labels: ShopReviewLabels, options?: {
|
|
2983
|
+
product?: string | null;
|
|
2984
|
+
}): Promise<ShopReview[] | null>;
|
|
2985
|
+
type PagedShopReviewsState = {
|
|
2986
|
+
status: 'loading';
|
|
2987
|
+
} | {
|
|
2988
|
+
status: 'error';
|
|
2989
|
+
} | {
|
|
2990
|
+
status: 'ready';
|
|
2991
|
+
reviews: ShopReview[];
|
|
2992
|
+
summary: SdkShopReviewsSummary | null;
|
|
2993
|
+
hasMore: boolean;
|
|
2994
|
+
/** True while the next page is on its way. */
|
|
2995
|
+
loadingMore: boolean;
|
|
2996
|
+
/** Set when the NEXT page failed; the pages already shown stay. */
|
|
2997
|
+
moreFailed: boolean;
|
|
2998
|
+
};
|
|
2999
|
+
/**
|
|
3000
|
+
* The shop's reviews, one page at a time: the first page on mount (or when
|
|
3001
|
+
* `product` changes), the next only when `loadMore` is called. The summary is
|
|
3002
|
+
* the API's, so the score and breakdown describe the whole list, not the pages
|
|
3003
|
+
* loaded so far.
|
|
2934
3004
|
*/
|
|
2935
|
-
declare function
|
|
3005
|
+
declare function usePagedShopReviews(options: {
|
|
3006
|
+
product?: string | null;
|
|
3007
|
+
labels: ShopReviewLabels;
|
|
3008
|
+
}): PagedShopReviewsState & {
|
|
3009
|
+
loadMore: () => void;
|
|
3010
|
+
};
|
|
2936
3011
|
declare function averageRating(reviews: readonly ShopReview[]): number | null;
|
|
2937
3012
|
declare function useShopReviews(labels: ShopReviewLabels): ShopReviewsState;
|
|
2938
3013
|
|
|
@@ -3033,16 +3108,24 @@ type ShopPageState = {
|
|
|
3033
3108
|
status: 'ready';
|
|
3034
3109
|
page: ShopPageModel;
|
|
3035
3110
|
}
|
|
3036
|
-
/** The
|
|
3111
|
+
/** The API answered that no such page exists (404), or the page has no name. */
|
|
3037
3112
|
| {
|
|
3038
3113
|
status: 'missing';
|
|
3114
|
+
}
|
|
3115
|
+
/**
|
|
3116
|
+
* The page could not be loaded: the API failed or could not be reached, or
|
|
3117
|
+
* the page's body could not be rendered. Not "missing": the page may exist.
|
|
3118
|
+
*/
|
|
3119
|
+
| {
|
|
3120
|
+
status: 'error';
|
|
3039
3121
|
};
|
|
3040
3122
|
/**
|
|
3041
3123
|
* Loads one CMS page by slug.
|
|
3042
3124
|
*
|
|
3043
|
-
*
|
|
3044
|
-
*
|
|
3045
|
-
*
|
|
3125
|
+
* `missing` only when the API says so (404) or the page it returns has no name
|
|
3126
|
+
* to show; inventing a title from the slug would publish a heading the merchant
|
|
3127
|
+
* never wrote. Any other failure is `error`, so an outage never tells a buyer a
|
|
3128
|
+
* real page does not exist.
|
|
3046
3129
|
*/
|
|
3047
3130
|
declare function loadShopPage(slug: string): Promise<ShopPageState>;
|
|
3048
3131
|
|
|
@@ -3123,4 +3206,4 @@ declare function useOnlineUserCount(): number | null;
|
|
|
3123
3206
|
*/
|
|
3124
3207
|
declare function resolveProductVideoEmbedSrc(value: unknown): string | null;
|
|
3125
3208
|
|
|
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 };
|
|
3209
|
+
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 PagedShopReviewsState, 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 SdkShopReviewsSummary, type ShopPageFaqItem, type ShopPageModel, type ShopPageState, type ShopReview, type ShopReviewLabels, type ShopReviewsPageResult, 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, loadShopReviewsPage, 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, usePagedShopReviews, useShopReviews, useStorefront, validateCheckoutFieldValue, validateCheckoutFields, validateContactSubmission, withRequiredAddons };
|
package/dist/index.js
CHANGED
|
@@ -2542,7 +2542,7 @@ function useNavigationLinks(slot, themeLinks, authored) {
|
|
|
2542
2542
|
}
|
|
2543
2543
|
|
|
2544
2544
|
// src/reviews.ts
|
|
2545
|
-
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
2545
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
|
|
2546
2546
|
var SHOP_REVIEW_PAGE_SIZE = 12;
|
|
2547
2547
|
function toTimestamp(value) {
|
|
2548
2548
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -2582,7 +2582,8 @@ function toShopReviews(rows, labels) {
|
|
|
2582
2582
|
dateLabel: formatDateLabel(timestamp),
|
|
2583
2583
|
timestamp,
|
|
2584
2584
|
productTitle: row.product_title?.trim() || null,
|
|
2585
|
-
verified: row.verified === true
|
|
2585
|
+
verified: row.verified === true,
|
|
2586
|
+
automated: row.is_automated === true
|
|
2586
2587
|
};
|
|
2587
2588
|
}).sort((a, b) => b.timestamp - a.timestamp);
|
|
2588
2589
|
}
|
|
@@ -2591,20 +2592,83 @@ function reviewsForProduct(reviews, productTitle) {
|
|
|
2591
2592
|
if (!title) return [];
|
|
2592
2593
|
return reviews.filter((review) => review.productTitle === title);
|
|
2593
2594
|
}
|
|
2594
|
-
async function
|
|
2595
|
+
async function loadShopReviewsPage(options) {
|
|
2596
|
+
const product = options.product?.trim() || null;
|
|
2597
|
+
const result = await getShoppex().getShopReviewsPage(options.cursor ?? null, product ? { product } : void 0);
|
|
2598
|
+
if (!result.success || !result.data) {
|
|
2599
|
+
throw new Error(result.message?.trim() || "Reviews could not be loaded.");
|
|
2600
|
+
}
|
|
2601
|
+
if (product !== null && result.data.product !== product) {
|
|
2602
|
+
throw new Error("This store does not filter reviews by product yet.");
|
|
2603
|
+
}
|
|
2604
|
+
const { pagination } = result.data;
|
|
2605
|
+
return {
|
|
2606
|
+
reviews: toShopReviews(result.data.feedback, options.labels),
|
|
2607
|
+
nextCursor: pagination.has_more ? pagination.next_cursor : null,
|
|
2608
|
+
summary: result.data.summary ?? null
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
async function loadLatestWrittenReviews(limit, labels, options = {}) {
|
|
2595
2612
|
const written = [];
|
|
2596
2613
|
const seen = /* @__PURE__ */ new Set();
|
|
2597
2614
|
let cursor = null;
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2615
|
+
try {
|
|
2616
|
+
while (written.length < limit) {
|
|
2617
|
+
const page = await loadShopReviewsPage({ cursor, product: options.product, labels: { anonymousAuthor: labels.anonymousAuthor, emptyComment: "" } });
|
|
2618
|
+
written.push(...page.reviews.filter((review) => !review.automated && review.comment !== ""));
|
|
2619
|
+
if (!page.nextCursor || seen.has(page.nextCursor)) break;
|
|
2620
|
+
seen.add(page.nextCursor);
|
|
2621
|
+
cursor = page.nextCursor;
|
|
2622
|
+
}
|
|
2623
|
+
} catch {
|
|
2624
|
+
return null;
|
|
2606
2625
|
}
|
|
2607
|
-
return
|
|
2626
|
+
return written.slice(0, limit).map((review) => ({ ...review, comment: review.comment || labels.emptyComment }));
|
|
2627
|
+
}
|
|
2628
|
+
function usePagedShopReviews(options) {
|
|
2629
|
+
const product = options.product?.trim() || null;
|
|
2630
|
+
const { anonymousAuthor, emptyComment } = options.labels;
|
|
2631
|
+
const [state, setState] = useState3({ status: "loading" });
|
|
2632
|
+
const [cursor, setCursor] = useState3(null);
|
|
2633
|
+
const generation = useRef2(0);
|
|
2634
|
+
useEffect3(() => {
|
|
2635
|
+
const current = generation.current += 1;
|
|
2636
|
+
setState({ status: "loading" });
|
|
2637
|
+
setCursor(null);
|
|
2638
|
+
loadShopReviewsPage({ product, labels: { anonymousAuthor, emptyComment } }).then((page) => {
|
|
2639
|
+
if (generation.current !== current) return;
|
|
2640
|
+
setCursor(page.nextCursor);
|
|
2641
|
+
setState({
|
|
2642
|
+
status: "ready",
|
|
2643
|
+
reviews: page.reviews,
|
|
2644
|
+
summary: page.summary,
|
|
2645
|
+
hasMore: page.nextCursor !== null,
|
|
2646
|
+
loadingMore: false,
|
|
2647
|
+
moreFailed: false
|
|
2648
|
+
});
|
|
2649
|
+
}).catch(() => {
|
|
2650
|
+
if (generation.current === current) setState({ status: "error" });
|
|
2651
|
+
});
|
|
2652
|
+
}, [product, anonymousAuthor, emptyComment]);
|
|
2653
|
+
const loadMore = useCallback2(() => {
|
|
2654
|
+
if (state.status !== "ready" || state.loadingMore || cursor === null) return;
|
|
2655
|
+
const current = generation.current;
|
|
2656
|
+
setState({ ...state, loadingMore: true, moreFailed: false });
|
|
2657
|
+
loadShopReviewsPage({ cursor, product, labels: { anonymousAuthor, emptyComment } }).then((page) => {
|
|
2658
|
+
if (generation.current !== current) return;
|
|
2659
|
+
setCursor(page.nextCursor);
|
|
2660
|
+
setState((previous) => previous.status !== "ready" ? previous : {
|
|
2661
|
+
...previous,
|
|
2662
|
+
reviews: [...previous.reviews, ...page.reviews],
|
|
2663
|
+
hasMore: page.nextCursor !== null,
|
|
2664
|
+
loadingMore: false
|
|
2665
|
+
});
|
|
2666
|
+
}).catch(() => {
|
|
2667
|
+
if (generation.current !== current) return;
|
|
2668
|
+
setState((previous) => previous.status !== "ready" ? previous : { ...previous, loadingMore: false, moreFailed: true });
|
|
2669
|
+
});
|
|
2670
|
+
}, [state, cursor, product, anonymousAuthor, emptyComment]);
|
|
2671
|
+
return { ...state, loadMore };
|
|
2608
2672
|
}
|
|
2609
2673
|
function averageRating(reviews) {
|
|
2610
2674
|
if (reviews.length === 0) return null;
|
|
@@ -2663,15 +2727,19 @@ async function buildShopPageModel(page) {
|
|
|
2663
2727
|
};
|
|
2664
2728
|
}
|
|
2665
2729
|
async function loadShopPage(slug) {
|
|
2730
|
+
let result;
|
|
2731
|
+
try {
|
|
2732
|
+
result = await getShoppex().getPage(slug);
|
|
2733
|
+
} catch {
|
|
2734
|
+
return { status: "error" };
|
|
2735
|
+
}
|
|
2736
|
+
if (!result.success) return result.status === 404 ? { status: "missing" } : { status: "error" };
|
|
2737
|
+
const page = result.data;
|
|
2738
|
+
if (!page || typeof page.name !== "string" || !page.name.trim()) return { status: "missing" };
|
|
2666
2739
|
try {
|
|
2667
|
-
const result = await getShoppex().getPage(slug);
|
|
2668
|
-
const page = result.success ? result.data : void 0;
|
|
2669
|
-
if (!page || typeof page.name !== "string" || !page.name.trim()) {
|
|
2670
|
-
return { status: "missing" };
|
|
2671
|
-
}
|
|
2672
2740
|
return { status: "ready", page: await buildShopPageModel(page) };
|
|
2673
2741
|
} catch {
|
|
2674
|
-
return { status: "
|
|
2742
|
+
return { status: "error" };
|
|
2675
2743
|
}
|
|
2676
2744
|
}
|
|
2677
2745
|
|
|
@@ -2781,6 +2849,7 @@ export {
|
|
|
2781
2849
|
isSelectionSoldOut,
|
|
2782
2850
|
loadLatestWrittenReviews,
|
|
2783
2851
|
loadShopPage,
|
|
2852
|
+
loadShopReviewsPage,
|
|
2784
2853
|
missingRequiredCheckoutValues,
|
|
2785
2854
|
optionalBoolean,
|
|
2786
2855
|
optionalString,
|
|
@@ -2829,6 +2898,7 @@ export {
|
|
|
2829
2898
|
useCart,
|
|
2830
2899
|
useNavigationLinks,
|
|
2831
2900
|
useOnlineUserCount,
|
|
2901
|
+
usePagedShopReviews,
|
|
2832
2902
|
useShopReviews,
|
|
2833
2903
|
useStorefront,
|
|
2834
2904
|
validateCheckoutFieldValue,
|