@akinon/pz-theme 2.0.163-rc.0 → 2.0.164-beta.0
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 +15 -50
- package/package.json +4 -4
- package/src/__tests__/commerce-channel-frozen.test.ts +12 -1
- package/src/__tests__/editor-locale-bridge.test.tsx +1 -32
- package/src/__tests__/section-list-identity.test.tsx +113 -0
- package/src/blocks/__tests__/favourites-grid-impression.test.tsx +217 -0
- package/src/blocks/__tests__/group-block-list-click.test.tsx +90 -0
- package/src/blocks/__tests__/text-block.test.tsx +6 -34
- package/src/blocks/favourites-grid-block.tsx +16 -18
- package/src/blocks/group-block.tsx +14 -2
- package/src/blocks/item-template.tsx +1 -0
- package/src/blocks/order-detail-block.tsx +95 -113
- package/src/blocks/product-block-utils.tsx +5 -1
- package/src/blocks/product-recommendations-block.tsx +45 -13
- package/src/blocks/text-block.tsx +2 -6
- package/src/custom/README.md +219 -100
- package/src/custom/__tests__/use-theme-setting.test.tsx +0 -97
- package/src/custom/collect.ts +9 -4
- package/src/custom/property-types.ts +15 -15
- package/src/custom/use-theme-setting.ts +5 -21
- package/src/editor-locale-bridge.tsx +11 -39
- package/src/hooks/__tests__/use-list-impression.test.tsx +228 -0
- package/src/hooks/__tests__/use-section-seen.test.tsx +55 -2
- package/src/hooks/use-list-impression.ts +116 -0
- package/src/hooks/use-section-seen.ts +22 -2
- package/src/sections/__tests__/posts-slider-select-item.test.tsx +205 -0
- package/src/sections/__tests__/section-wrapper-list.test.tsx +148 -0
- package/src/sections/posts-slider-section.tsx +62 -2
- package/src/sections/section-wrapper.tsx +32 -2
- package/src/theme-block.tsx +6 -0
- package/src/theme-placeholder-wrapper.tsx +0 -3
- package/src/theme-section-data-context.tsx +33 -0
- package/src/theme-section.tsx +60 -2
- package/src/utils/__tests__/section-impressions.test.ts +68 -0
- package/src/utils/iterator-price-shapes.test.ts +13 -0
- package/src/utils/iterator-utils.ts +2 -1
- package/src/utils/section-impressions.ts +37 -0
- package/src/blocks/__tests__/order-line-actions.test.tsx +0 -54
- package/src/blocks/order-line-actions.ts +0 -45
- package/src/utils/__tests__/sanitize-rich-text.test.ts +0 -80
- package/src/utils/sanitize-rich-text.ts +0 -215
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
readItemsCurrency
|
|
26
26
|
} from '../utils/analytics';
|
|
27
27
|
import { hasItemTemplate, ItemTemplateList } from './item-template';
|
|
28
|
+
import { useListImpression } from '../hooks/use-list-impression';
|
|
28
29
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
29
30
|
import { DesignerPlaceholder, readToggle } from './product-block-utils';
|
|
30
31
|
|
|
@@ -283,25 +284,21 @@ const FavouritesGridBlock = ({
|
|
|
283
284
|
|
|
284
285
|
// GA4 view_item_list (ZERO-4869), once per distinct wishlist content: the
|
|
285
286
|
// favourites grid IS the list impression on this screen. Keyed by row keys
|
|
286
|
-
// so a remove refires with the new list, a mere re-render does not.
|
|
287
|
-
//
|
|
287
|
+
// so a remove refires with the new list, a mere re-render does not. Sent
|
|
288
|
+
// when the grid is seen, as every other list is (ZERO-5305): a grid kept
|
|
289
|
+
// only for its empty state, its list laid out with `display: none` next to
|
|
290
|
+
// a favourites strip, used to report the favourites a second time.
|
|
288
291
|
const rowsKey = rows.map((row) => row.key).join(',');
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
listName: 'Favourites'
|
|
300
|
-
})
|
|
301
|
-
)
|
|
302
|
-
});
|
|
303
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
304
|
-
}, [rowsKey, isDesigner]);
|
|
292
|
+
const listRef = React.useRef<HTMLDivElement>(null);
|
|
293
|
+
useListImpression({
|
|
294
|
+
ref: listRef,
|
|
295
|
+
products: rows as Array<Record<string, unknown>>,
|
|
296
|
+
listId: 'favourites',
|
|
297
|
+
listName: 'Favourites',
|
|
298
|
+
enabled: !isDesigner,
|
|
299
|
+
refreshKey: rowsKey,
|
|
300
|
+
currency: localeCurrency
|
|
301
|
+
});
|
|
305
302
|
|
|
306
303
|
// A designer who marked a child as the card layout gets that layout repeated
|
|
307
304
|
// per saved product; otherwise the built-in card renders unchanged.
|
|
@@ -402,6 +399,7 @@ const FavouritesGridBlock = ({
|
|
|
402
399
|
|
|
403
400
|
return (
|
|
404
401
|
<div
|
|
402
|
+
ref={listRef}
|
|
405
403
|
data-favourites-grid=""
|
|
406
404
|
data-favourites-grid-id={gridId}
|
|
407
405
|
aria-busy={isBusy}
|
|
@@ -17,6 +17,7 @@ import { DesignerPlaceholder, useThemeItemScope } from './product-block-utils';
|
|
|
17
17
|
import { renderComposedChildren } from './render-composed-children';
|
|
18
18
|
import { CardListSlider, readListGap } from '../components/card-list-slider';
|
|
19
19
|
import { CardListViews } from '../components/card-list-views';
|
|
20
|
+
import { useThemeSectionList } from '../theme-section-data-context';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Composed anchors to the storefront's own routes navigate client-side. A
|
|
@@ -59,17 +60,28 @@ const GroupBlock = ({
|
|
|
59
60
|
const Tag = tag as keyof React.JSX.IntrinsicElements;
|
|
60
61
|
const href = tag === 'a' ? block.properties?.href : undefined;
|
|
61
62
|
const itemScope = useThemeItemScope();
|
|
63
|
+
const sectionList = useThemeSectionList();
|
|
62
64
|
|
|
63
65
|
// GA4 select_item (ZERO-4869): a composed anchor inside a repeated product
|
|
64
66
|
// row IS the product card's click. The row scope carries the product, so no
|
|
65
|
-
// per-card wiring is needed — and outside a row this stays silent.
|
|
67
|
+
// per-card wiring is needed — and outside a row this stays silent. The card
|
|
68
|
+
// reports the list it sits in — the section's — and its place in it
|
|
69
|
+
// (ZERO-5305), the same identity the row's view_item_list carries.
|
|
66
70
|
const handleAnchorAnalytics = () => {
|
|
67
71
|
if (isDesigner) return;
|
|
68
72
|
const scopedProduct = itemScope?.product;
|
|
69
73
|
if (!scopedProduct) return;
|
|
70
74
|
emitCommerceEvent('select_item', {
|
|
71
75
|
currency: readItemsCurrency(scopedProduct as Record<string, unknown>),
|
|
72
|
-
items: [
|
|
76
|
+
items: [
|
|
77
|
+
buildCommerceItem(scopedProduct as Record<string, unknown>, {
|
|
78
|
+
...(typeof itemScope?.index === 'number'
|
|
79
|
+
? { index: itemScope.index }
|
|
80
|
+
: null),
|
|
81
|
+
...(sectionList?.listId ? { listId: sectionList.listId } : null),
|
|
82
|
+
...(sectionList?.listName ? { listName: sectionList.listName } : null)
|
|
83
|
+
})
|
|
84
|
+
]
|
|
73
85
|
});
|
|
74
86
|
};
|
|
75
87
|
|
|
@@ -9,7 +9,6 @@ import { getResponsiveValue, partAttrs } from '../utils';
|
|
|
9
9
|
import { formatDate, formatMoney } from './commerce-format';
|
|
10
10
|
import { readMoneyStyle } from './money-style';
|
|
11
11
|
import { hasItemTemplate, ItemTemplateList } from './item-template';
|
|
12
|
-
import { renderOrderLineActions } from './order-line-actions';
|
|
13
12
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
14
13
|
import {
|
|
15
14
|
DesignerPlaceholder,
|
|
@@ -25,7 +24,7 @@ import {
|
|
|
25
24
|
useOrderActionRules
|
|
26
25
|
} from '../utils/order-action-rules';
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
interface OrderItemLike {
|
|
29
28
|
id?: number;
|
|
30
29
|
price?: string;
|
|
31
30
|
quantity?: string | number;
|
|
@@ -44,7 +43,7 @@ type OrderItemLike = {
|
|
|
44
43
|
absolute_url?: string;
|
|
45
44
|
attributes?: Record<string, unknown>;
|
|
46
45
|
} | null;
|
|
47
|
-
}
|
|
46
|
+
}
|
|
48
47
|
|
|
49
48
|
interface AddressLike {
|
|
50
49
|
first_name?: string;
|
|
@@ -409,7 +408,7 @@ const formatAddress = (address: AddressLike | null | undefined): string[] => {
|
|
|
409
408
|
* currencyText, currencyPosition.
|
|
410
409
|
* Parts: detail, header, number, date, header-total, status,
|
|
411
410
|
* invoice-link, cancel-link, return-link, list, item, image, name, quantity,
|
|
412
|
-
* color, size, item-status, item-tracking, item-return-code,
|
|
411
|
+
* color, size, item-status, item-tracking, item-return-code,
|
|
413
412
|
* item-return-method, item-return-carrier, item-pickup-date, price, shipment,
|
|
414
413
|
* delivery, tracking, addresses, address, address-label, totals, total-row,
|
|
415
414
|
* total-label, total-value, grand-total, payment-info, payment-info-label.
|
|
@@ -956,21 +955,6 @@ const OrderDetailBlock = ({
|
|
|
956
955
|
showPickupDate && returnDetails.pickupDate
|
|
957
956
|
? formatPickupDate(returnDetails.pickupDate, locale)
|
|
958
957
|
: '';
|
|
959
|
-
const lineActions = renderOrderLineActions({
|
|
960
|
-
order,
|
|
961
|
-
line,
|
|
962
|
-
isDesigner
|
|
963
|
-
});
|
|
964
|
-
const showLineMeta =
|
|
965
|
-
showShipmentStatus &&
|
|
966
|
-
Boolean(
|
|
967
|
-
item.status?.label ||
|
|
968
|
-
trackingValue ||
|
|
969
|
-
returnCodeValue ||
|
|
970
|
-
returnMethodValue ||
|
|
971
|
-
returnCarrierValue ||
|
|
972
|
-
pickupDateValue
|
|
973
|
-
);
|
|
974
958
|
|
|
975
959
|
return (
|
|
976
960
|
<li
|
|
@@ -1086,100 +1070,98 @@ const OrderDetailBlock = ({
|
|
|
1086
1070
|
</div>
|
|
1087
1071
|
</div>
|
|
1088
1072
|
|
|
1089
|
-
{
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
</div>
|
|
1182
|
-
)}
|
|
1073
|
+
{showShipmentStatus &&
|
|
1074
|
+
(item.status?.label ||
|
|
1075
|
+
trackingValue ||
|
|
1076
|
+
returnCodeValue ||
|
|
1077
|
+
returnMethodValue ||
|
|
1078
|
+
returnCarrierValue ||
|
|
1079
|
+
pickupDateValue) && (
|
|
1080
|
+
<div
|
|
1081
|
+
style={{
|
|
1082
|
+
display: 'flex',
|
|
1083
|
+
flexDirection: 'column',
|
|
1084
|
+
alignItems: isMobile ? 'flex-start' : 'flex-end',
|
|
1085
|
+
textAlign: isMobile ? 'left' : 'right',
|
|
1086
|
+
gap: '4px',
|
|
1087
|
+
flex: isMobile ? '1 1 100%' : '0 0 auto'
|
|
1088
|
+
}}
|
|
1089
|
+
>
|
|
1090
|
+
{item.status?.label && (
|
|
1091
|
+
<span
|
|
1092
|
+
data-order-detail-item-status=""
|
|
1093
|
+
data-order-status-value={item.status.value}
|
|
1094
|
+
{...partAttrs('item-status')}
|
|
1095
|
+
style={{ display: 'inline-block' }}
|
|
1096
|
+
>
|
|
1097
|
+
{item.status.label}
|
|
1098
|
+
</span>
|
|
1099
|
+
)}
|
|
1100
|
+
{/* Label and value in their own spans, so a
|
|
1101
|
+
composition can colour them apart. */}
|
|
1102
|
+
{returnMethodValue && (
|
|
1103
|
+
<span
|
|
1104
|
+
data-order-detail-item-return-method=""
|
|
1105
|
+
{...partAttrs('item-return-method')}
|
|
1106
|
+
style={{ opacity: 0.8 }}
|
|
1107
|
+
>
|
|
1108
|
+
<span data-label="">{returnMethodLabel}</span>{' '}
|
|
1109
|
+
<span data-value="">{returnMethodValue}</span>
|
|
1110
|
+
</span>
|
|
1111
|
+
)}
|
|
1112
|
+
{returnCarrierValue && (
|
|
1113
|
+
<span
|
|
1114
|
+
data-order-detail-item-return-carrier=""
|
|
1115
|
+
{...partAttrs('item-return-carrier')}
|
|
1116
|
+
style={{ opacity: 0.8 }}
|
|
1117
|
+
>
|
|
1118
|
+
<span data-label="">{returnCarrierLabel}</span>{' '}
|
|
1119
|
+
<span data-value="">{returnCarrierValue}</span>
|
|
1120
|
+
</span>
|
|
1121
|
+
)}
|
|
1122
|
+
{pickupDateValue && (
|
|
1123
|
+
<span
|
|
1124
|
+
data-order-detail-item-pickup-date=""
|
|
1125
|
+
{...partAttrs('item-pickup-date')}
|
|
1126
|
+
style={{ opacity: 0.8 }}
|
|
1127
|
+
>
|
|
1128
|
+
<span data-label="">{pickupDateLabel}</span>{' '}
|
|
1129
|
+
<span data-value="">{pickupDateValue}</span>
|
|
1130
|
+
</span>
|
|
1131
|
+
)}
|
|
1132
|
+
{trackingValue && (
|
|
1133
|
+
<span
|
|
1134
|
+
data-order-detail-item-tracking=""
|
|
1135
|
+
{...partAttrs('item-tracking')}
|
|
1136
|
+
style={{ opacity: 0.8 }}
|
|
1137
|
+
>
|
|
1138
|
+
{lineTrackingLabel}{' '}
|
|
1139
|
+
{item.tracking_url ? (
|
|
1140
|
+
<a
|
|
1141
|
+
href={isDesigner ? '#' : item.tracking_url}
|
|
1142
|
+
onClick={guard}
|
|
1143
|
+
target={isDesigner ? undefined : '_blank'}
|
|
1144
|
+
rel="noreferrer"
|
|
1145
|
+
style={{ color: 'inherit' }}
|
|
1146
|
+
>
|
|
1147
|
+
{item.tracking_number || item.tracking_url}
|
|
1148
|
+
</a>
|
|
1149
|
+
) : (
|
|
1150
|
+
trackingValue
|
|
1151
|
+
)}
|
|
1152
|
+
</span>
|
|
1153
|
+
)}
|
|
1154
|
+
{returnCodeValue && (
|
|
1155
|
+
<span
|
|
1156
|
+
data-order-detail-item-return-code=""
|
|
1157
|
+
{...partAttrs('item-return-code')}
|
|
1158
|
+
style={{ opacity: 0.8 }}
|
|
1159
|
+
>
|
|
1160
|
+
{returnCodeLabel} {returnCodeValue}
|
|
1161
|
+
</span>
|
|
1162
|
+
)}
|
|
1163
|
+
</div>
|
|
1164
|
+
)}
|
|
1183
1165
|
</div>
|
|
1184
1166
|
</li>
|
|
1185
1167
|
);
|
|
@@ -99,6 +99,8 @@ export interface ThemeProduct {
|
|
|
99
99
|
*/
|
|
100
100
|
interface ThemeItemScopeValue {
|
|
101
101
|
product: ThemeProduct | null;
|
|
102
|
+
/** The row's place in its list (0-based), when the repeat knows it. */
|
|
103
|
+
index?: number;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
const ThemeItemScopeContext = React.createContext<ThemeItemScopeValue | null>(
|
|
@@ -107,12 +109,14 @@ const ThemeItemScopeContext = React.createContext<ThemeItemScopeValue | null>(
|
|
|
107
109
|
|
|
108
110
|
export const ThemeItemScopeProvider = ({
|
|
109
111
|
product,
|
|
112
|
+
index,
|
|
110
113
|
children
|
|
111
114
|
}: {
|
|
112
115
|
product: ThemeProduct | null;
|
|
116
|
+
index?: number;
|
|
113
117
|
children: React.ReactNode;
|
|
114
118
|
}) => {
|
|
115
|
-
const value = React.useMemo(() => ({ product }), [product]);
|
|
119
|
+
const value = React.useMemo(() => ({ product, index }), [product, index]);
|
|
116
120
|
|
|
117
121
|
return (
|
|
118
122
|
<ThemeItemScopeContext.Provider value={value}>
|
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
} from '@akinon/next/data/client/product';
|
|
12
12
|
import { useLocalization } from '@akinon/next/hooks';
|
|
13
13
|
import { useOverlay } from '../hooks/use-overlay';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
ThemeSectionListProvider,
|
|
16
|
+
useThemeSectionData,
|
|
17
|
+
useThemeSectionList
|
|
18
|
+
} from '../theme-section-data-context';
|
|
19
|
+
import { useListImpression } from '../hooks/use-list-impression';
|
|
15
20
|
import { getResponsiveValue, partAttrs } from '../utils';
|
|
16
21
|
import {
|
|
17
22
|
buildCommerceItem,
|
|
@@ -285,6 +290,7 @@ const ProductRecommendationsBlock = ({
|
|
|
285
290
|
}: BlockRendererProps) => {
|
|
286
291
|
const { locale, currency: localeCurrency } = useLocalization();
|
|
287
292
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
293
|
+
const sectionList = useThemeSectionList();
|
|
288
294
|
const trackRef = useRef<HTMLDivElement>(null);
|
|
289
295
|
// The ambient product: on a PDP this is what the shopper is looking at, and
|
|
290
296
|
// it is both what gets recorded and what is excluded from its own strip.
|
|
@@ -863,6 +869,25 @@ const ProductRecommendationsBlock = ({
|
|
|
863
869
|
? favouriteCards
|
|
864
870
|
: collectionProducts;
|
|
865
871
|
|
|
872
|
+
// The list this strip is (ZERO-5305): named after its title ("You may also
|
|
873
|
+
// like"), else the section's label; identified by the
|
|
874
|
+
// collection it shows, else the section.
|
|
875
|
+
const listIdentity = {
|
|
876
|
+
listId:
|
|
877
|
+
(!isRecentlyViewed && !isFavourites && !isSectionSource && collectionId) ||
|
|
878
|
+
sectionList?.listId ||
|
|
879
|
+
'product_recommendations',
|
|
880
|
+
listName: title || sectionList?.listName || 'Product Recommendations'
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
useListImpression({
|
|
884
|
+
ref: rootRef,
|
|
885
|
+
products: products as unknown as Record<string, unknown>[],
|
|
886
|
+
listId: listIdentity.listId,
|
|
887
|
+
listName: listIdentity.listName,
|
|
888
|
+
enabled: !isDesigner
|
|
889
|
+
});
|
|
890
|
+
|
|
866
891
|
/**
|
|
867
892
|
* The designer has no browsing history behind the canvas, so a recently
|
|
868
893
|
* viewed strip would collapse to nothing and stop being selectable, sizeable
|
|
@@ -891,17 +916,24 @@ const ProductRecommendationsBlock = ({
|
|
|
891
916
|
|
|
892
917
|
// A designer who marked a child as the card layout gets that layout repeated
|
|
893
918
|
// per product; otherwise the built-in card renders unchanged.
|
|
919
|
+
// The strip's own list identity rides over its cards, so an authored card's
|
|
920
|
+
// click reports this strip — not the section around it — as its list.
|
|
894
921
|
const customCards = hasItemTemplate(block, currentBreakpoint) ? (
|
|
895
|
-
<
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
922
|
+
<ThemeSectionListProvider
|
|
923
|
+
listId={listIdentity.listId}
|
|
924
|
+
listName={listIdentity.listName}
|
|
925
|
+
>
|
|
926
|
+
<ItemTemplateList
|
|
927
|
+
block={block}
|
|
928
|
+
items={products as unknown as Record<string, unknown>[]}
|
|
929
|
+
placeholderId={placeholderId}
|
|
930
|
+
sectionId={sectionId}
|
|
931
|
+
isDesigner={isDesigner}
|
|
932
|
+
selectedBlockId={selectedBlockId}
|
|
933
|
+
currentBreakpoint={currentBreakpoint}
|
|
934
|
+
designerPlaceholderCount={4}
|
|
935
|
+
/>
|
|
936
|
+
</ThemeSectionListProvider>
|
|
905
937
|
) : null;
|
|
906
938
|
|
|
907
939
|
// An empty history is the normal state on a first visit, so the strip
|
|
@@ -1294,8 +1326,8 @@ const ProductRecommendationsBlock = ({
|
|
|
1294
1326
|
buildCommerceItem(
|
|
1295
1327
|
product as unknown as Record<string, unknown>,
|
|
1296
1328
|
{
|
|
1297
|
-
|
|
1298
|
-
|
|
1329
|
+
...listIdentity,
|
|
1330
|
+
index: products.indexOf(product)
|
|
1299
1331
|
}
|
|
1300
1332
|
)
|
|
1301
1333
|
]
|
|
@@ -7,7 +7,6 @@ import { getInnerRootInlineStyles, partAttrs } from '../utils';
|
|
|
7
7
|
import { useThemeSettingsContext } from '../theme-settings-context';
|
|
8
8
|
import { useLocalizeHref } from '../hooks/use-localize-href';
|
|
9
9
|
import { localizeHtmlLinks } from '../utils/localize-href';
|
|
10
|
-
import { useValueLocale } from '../utils/localized-value';
|
|
11
10
|
|
|
12
11
|
const TextBlock = ({
|
|
13
12
|
block,
|
|
@@ -15,7 +14,7 @@ const TextBlock = ({
|
|
|
15
14
|
}: BlockRendererProps) => {
|
|
16
15
|
const { locale } = useLocalization();
|
|
17
16
|
const localize = useLocalizeHref();
|
|
18
|
-
const
|
|
17
|
+
const defaultLocale = process.env.NEXT_PUBLIC_DEFAULT_LOCALE || 'en';
|
|
19
18
|
const themeSettings = useThemeSettingsContext();
|
|
20
19
|
|
|
21
20
|
const getLocalizedContent = (): string => {
|
|
@@ -31,10 +30,7 @@ const TextBlock = ({
|
|
|
31
30
|
|
|
32
31
|
if (typeof value === 'object' && value !== null) {
|
|
33
32
|
return (
|
|
34
|
-
value[locale] ||
|
|
35
|
-
(defaultLocale && value[defaultLocale]) ||
|
|
36
|
-
Object.values(value)[0] ||
|
|
37
|
-
''
|
|
33
|
+
value[locale] || value[defaultLocale] || Object.values(value)[0] || ''
|
|
38
34
|
);
|
|
39
35
|
}
|
|
40
36
|
|