@nuskin/react-search-sdk 1.0.0-trying-again.2 → 1.0.0-trying-again.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/README.md +26 -3
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +154 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +154 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { lazy, useState, useEffect, useRef, useMemo, useCallback,
|
|
1
|
+
import { lazy, useState, useEffect, useRef, useMemo, useCallback, Component, Suspense } from 'react';
|
|
2
2
|
import configurationSdk from '@nuskin/configuration-sdk';
|
|
3
3
|
import { SearchModal } from '@nuskin/react-search-components';
|
|
4
|
+
import { createProductClient, ProductProvider, useProductById, ProductCard } from '@nuskin/react-product-sdk';
|
|
5
|
+
import styled from '@emotion/styled';
|
|
4
6
|
import { jsx } from 'react/jsx-runtime';
|
|
5
7
|
|
|
6
8
|
// src/components/CommerceSearch/CommerceSearch.tsx
|
|
@@ -28,7 +30,10 @@ var TEST_ENVIRONMENT_VALUES = {
|
|
|
28
30
|
agent: {
|
|
29
31
|
appKey: "pk_commerce_product_advisor_624aea4305b09240e8c8f41d0f6527b2",
|
|
30
32
|
apiBaseUrl: "https://nui.tst.nuskin.ai/"
|
|
31
|
-
}
|
|
33
|
+
},
|
|
34
|
+
// Open to visitors who are not signed in, so the handoff can be tried where signing in is not
|
|
35
|
+
// possible (for example local development). Sign-in stays required everywhere else.
|
|
36
|
+
allowGuestAgent: true
|
|
32
37
|
};
|
|
33
38
|
function nonEmptyString(value) {
|
|
34
39
|
return typeof value === "string" ? value.trim() : "";
|
|
@@ -45,7 +50,8 @@ function normalizeCommerceSearchConfig(raw, { language } = {}) {
|
|
|
45
50
|
apiBaseUrl,
|
|
46
51
|
...language ? { language } : {}
|
|
47
52
|
}
|
|
48
|
-
} : {}
|
|
53
|
+
} : {},
|
|
54
|
+
...raw?.allowGuestAgent === true ? { allowGuestAgent: true } : {}
|
|
49
55
|
};
|
|
50
56
|
}
|
|
51
57
|
async function fetchCommerceSearchConfig({
|
|
@@ -299,6 +305,16 @@ function resolveCustomerTypeHeaders(getCustomerType) {
|
|
|
299
305
|
const customerType = getCustomerType?.()?.trim();
|
|
300
306
|
return customerType ? { "X-Customer-Type": customerType } : void 0;
|
|
301
307
|
}
|
|
308
|
+
var NO_RESULTS_ERROR_CODE = "SFOSER002";
|
|
309
|
+
async function isNoResultsResponse(response) {
|
|
310
|
+
if (response.status !== 404) return false;
|
|
311
|
+
try {
|
|
312
|
+
const body = await response.json();
|
|
313
|
+
return body?.code === NO_RESULTS_ERROR_CODE;
|
|
314
|
+
} catch {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
302
318
|
async function fetchJsonFromCandidates(fetchImpl, requestUrls, requestHeaders = {}) {
|
|
303
319
|
let lastError;
|
|
304
320
|
for (const requestUrl of requestUrls) {
|
|
@@ -309,6 +325,7 @@ async function fetchJsonFromCandidates(fetchImpl, requestUrls, requestHeaders =
|
|
|
309
325
|
headers: { Accept: "application/json", ...requestHeaders }
|
|
310
326
|
});
|
|
311
327
|
if (!response.ok) {
|
|
328
|
+
if (await isNoResultsResponse(response)) return null;
|
|
312
329
|
lastError = new Error(
|
|
313
330
|
`Request failed with status ${response.status}`
|
|
314
331
|
);
|
|
@@ -348,6 +365,13 @@ function createSearchService(options = {}) {
|
|
|
348
365
|
locationLike,
|
|
349
366
|
country: localeParts.country,
|
|
350
367
|
getMarketConfig
|
|
368
|
+
}).catch((error) => {
|
|
369
|
+
catalogRequestConfigPromise = null;
|
|
370
|
+
console.warn(
|
|
371
|
+
"[search] Could not load the market configuration for the suggestions:",
|
|
372
|
+
error
|
|
373
|
+
);
|
|
374
|
+
throw error;
|
|
351
375
|
});
|
|
352
376
|
}
|
|
353
377
|
return catalogRequestConfigPromise;
|
|
@@ -468,6 +492,19 @@ function toNavigationTarget(path) {
|
|
|
468
492
|
return /^https?:\/\//i.test(path) ? { type: "external", url: path } : { type: "internal", path };
|
|
469
493
|
}
|
|
470
494
|
|
|
495
|
+
// src/utils/productEnvironment.ts
|
|
496
|
+
var PRODUCT_ENVIRONMENTS = ["dev", "test", "prod"];
|
|
497
|
+
function toProductEnvironment(environmentCode) {
|
|
498
|
+
return environmentCode && PRODUCT_ENVIRONMENTS.includes(environmentCode) ? environmentCode : void 0;
|
|
499
|
+
}
|
|
500
|
+
function getProductEnvironment() {
|
|
501
|
+
try {
|
|
502
|
+
return toProductEnvironment(getEnvironmentCode());
|
|
503
|
+
} catch {
|
|
504
|
+
return void 0;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
471
508
|
// src/utils/catalogHelpers.ts
|
|
472
509
|
var CART_DISABLED_PRODUCT_STATUSES = /* @__PURE__ */ new Set([
|
|
473
510
|
"discontinued",
|
|
@@ -997,9 +1034,10 @@ function resolveNuiSearchFlag(env = {}) {
|
|
|
997
1034
|
}
|
|
998
1035
|
function isNuiSearchEnabled({
|
|
999
1036
|
isAuthenticated,
|
|
1000
|
-
flag
|
|
1037
|
+
flag,
|
|
1038
|
+
allowGuests = false
|
|
1001
1039
|
}) {
|
|
1002
|
-
return
|
|
1040
|
+
return flag === true && (isAuthenticated === true || allowGuests);
|
|
1003
1041
|
}
|
|
1004
1042
|
|
|
1005
1043
|
// src/utils/searchRouting.ts
|
|
@@ -1013,15 +1051,69 @@ function decideSearchRoute({
|
|
|
1013
1051
|
if (snapshot.suggestionFetchFailed) return "search";
|
|
1014
1052
|
return snapshot.suggestions.length > 0 ? "search" : "handoff";
|
|
1015
1053
|
}
|
|
1054
|
+
|
|
1055
|
+
// src/utils/cachedProductClient.ts
|
|
1056
|
+
function withProductCache(client) {
|
|
1057
|
+
const lookups = /* @__PURE__ */ new Map();
|
|
1058
|
+
return {
|
|
1059
|
+
getProductById(productId) {
|
|
1060
|
+
let lookup = lookups.get(productId);
|
|
1061
|
+
if (!lookup) {
|
|
1062
|
+
lookup = client.getProductById(productId);
|
|
1063
|
+
lookups.set(productId, lookup);
|
|
1064
|
+
}
|
|
1065
|
+
return lookup;
|
|
1066
|
+
},
|
|
1067
|
+
getProductsByIds: (productIds) => client.getProductsByIds(productIds)
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
var AgentProductSlot = styled.div`
|
|
1071
|
+
&& {
|
|
1072
|
+
flex: 0 0 240px;
|
|
1073
|
+
overflow: hidden;
|
|
1074
|
+
width: 240px;
|
|
1075
|
+
}
|
|
1076
|
+
`;
|
|
1077
|
+
var SalesAIChatWidget = lazy(
|
|
1078
|
+
() => Promise.all([
|
|
1079
|
+
import('@nu-skin-enterprises/chat-widget'),
|
|
1080
|
+
import('@nu-skin-enterprises/chat-widget/styles.css')
|
|
1081
|
+
]).then(([mod]) => ({ default: mod.SalesAIChatWidget }))
|
|
1082
|
+
);
|
|
1016
1083
|
var HANDLE_POLL_MS = 50;
|
|
1017
1084
|
var HANDLE_TIMEOUT_MS = 15e3;
|
|
1018
|
-
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
return {
|
|
1024
|
-
}
|
|
1085
|
+
function AgentProductCard({ sku }) {
|
|
1086
|
+
const { product, isLoading, error } = useProductById(sku);
|
|
1087
|
+
if (!isLoading && (error || !product?.seoInformation?.canonicalURL)) {
|
|
1088
|
+
return null;
|
|
1089
|
+
}
|
|
1090
|
+
return /* @__PURE__ */ jsx(AgentProductSlot, { children: /* @__PURE__ */ jsx(ProductCard, { productId: sku }) });
|
|
1091
|
+
}
|
|
1092
|
+
var renderAgentProduct = (product) => /* @__PURE__ */ jsx(AgentProductCard, { sku: product.sku });
|
|
1093
|
+
function AgentWidget({
|
|
1094
|
+
widgetProps,
|
|
1095
|
+
products
|
|
1096
|
+
}) {
|
|
1097
|
+
const environment = products?.environment;
|
|
1098
|
+
const market = products?.market;
|
|
1099
|
+
const language = products?.language;
|
|
1100
|
+
const client = useMemo(
|
|
1101
|
+
() => environment && market && language ? withProductCache(
|
|
1102
|
+
createProductClient({ environment, market, language })
|
|
1103
|
+
) : void 0,
|
|
1104
|
+
[environment, market, language]
|
|
1105
|
+
);
|
|
1106
|
+
if (!client) {
|
|
1107
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(SalesAIChatWidget, { ...widgetProps }) });
|
|
1108
|
+
}
|
|
1109
|
+
return /* @__PURE__ */ jsx(ProductProvider, { client, children: /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
1110
|
+
SalesAIChatWidget,
|
|
1111
|
+
{
|
|
1112
|
+
renderProduct: renderAgentProduct,
|
|
1113
|
+
...widgetProps
|
|
1114
|
+
}
|
|
1115
|
+
) }) });
|
|
1116
|
+
}
|
|
1025
1117
|
function getSalesAIHandle() {
|
|
1026
1118
|
return window.SalesAI;
|
|
1027
1119
|
}
|
|
@@ -1077,6 +1169,7 @@ function NuiAgentPanel({
|
|
|
1077
1169
|
agent,
|
|
1078
1170
|
query,
|
|
1079
1171
|
handoffContext,
|
|
1172
|
+
products,
|
|
1080
1173
|
onUnavailable
|
|
1081
1174
|
}) {
|
|
1082
1175
|
useHandoff({
|
|
@@ -1085,19 +1178,22 @@ function NuiAgentPanel({
|
|
|
1085
1178
|
agentContext: agent.context,
|
|
1086
1179
|
onUnavailable
|
|
1087
1180
|
});
|
|
1088
|
-
|
|
1089
|
-
|
|
1181
|
+
const widgetProps = {
|
|
1182
|
+
appKey: agent.appKey,
|
|
1183
|
+
apiBaseUrl: agent.apiBaseUrl,
|
|
1184
|
+
theme: agent.theme ?? "nui-light",
|
|
1185
|
+
defaultOpen: true,
|
|
1186
|
+
hideFab: true,
|
|
1187
|
+
placement: "host",
|
|
1188
|
+
...agent.language === void 0 ? {} : { language: agent.language }
|
|
1189
|
+
};
|
|
1190
|
+
return /* @__PURE__ */ jsx(AgentErrorBoundary, { onError: onUnavailable, children: /* @__PURE__ */ jsx(
|
|
1191
|
+
AgentWidget,
|
|
1090
1192
|
{
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
theme: agent.theme ?? "nui-light",
|
|
1094
|
-
defaultOpen: true,
|
|
1095
|
-
hideFab: true,
|
|
1096
|
-
placement: "host",
|
|
1097
|
-
...agent.language === void 0 ? {} : { language: agent.language },
|
|
1098
|
-
...agent.renderProduct === void 0 ? {} : { renderProduct: agent.renderProduct }
|
|
1193
|
+
widgetProps,
|
|
1194
|
+
...products ? { products } : {}
|
|
1099
1195
|
}
|
|
1100
|
-
) })
|
|
1196
|
+
) });
|
|
1101
1197
|
}
|
|
1102
1198
|
var SUBMIT_WAIT_TIMEOUT_MS = 2e3;
|
|
1103
1199
|
function uniqueRecentSearches(queries) {
|
|
@@ -1116,6 +1212,8 @@ function CommerceSearchView({
|
|
|
1116
1212
|
navigate,
|
|
1117
1213
|
isAuthenticated,
|
|
1118
1214
|
agent,
|
|
1215
|
+
allowGuestAgent = false,
|
|
1216
|
+
agentProducts,
|
|
1119
1217
|
logo,
|
|
1120
1218
|
minimumSearchLength = MINIMUM_SEARCH_CHAR_LENGTH,
|
|
1121
1219
|
gtmContext
|
|
@@ -1141,7 +1239,11 @@ function CommerceSearchView({
|
|
|
1141
1239
|
suggestions,
|
|
1142
1240
|
updateQuery
|
|
1143
1241
|
} = search;
|
|
1144
|
-
const enabled = agent !== void 0 && isNuiSearchEnabled({
|
|
1242
|
+
const enabled = agent !== void 0 && isNuiSearchEnabled({
|
|
1243
|
+
isAuthenticated,
|
|
1244
|
+
flag,
|
|
1245
|
+
allowGuests: allowGuestAgent
|
|
1246
|
+
});
|
|
1145
1247
|
const items = getVisibleSuggestions({
|
|
1146
1248
|
didYouMean,
|
|
1147
1249
|
suggestions
|
|
@@ -1311,6 +1413,22 @@ function CommerceSearchView({
|
|
|
1311
1413
|
if (agentQuery !== null)
|
|
1312
1414
|
navigateTo(service.submitProductSearch(agentQuery));
|
|
1313
1415
|
}, [agentQuery, navigateTo, service]);
|
|
1416
|
+
const agentProductsProps = agentProducts ? { products: agentProducts } : {};
|
|
1417
|
+
const agentPanel = handoff === null || agent === void 0 ? void 0 : /* @__PURE__ */ jsx(
|
|
1418
|
+
NuiAgentPanel,
|
|
1419
|
+
{
|
|
1420
|
+
agent,
|
|
1421
|
+
query: handoff.query,
|
|
1422
|
+
handoffContext: {
|
|
1423
|
+
source: "storefront_search",
|
|
1424
|
+
trigger: "zero_results",
|
|
1425
|
+
query: handoff.query,
|
|
1426
|
+
did_you_mean: handoff.didYouMean
|
|
1427
|
+
},
|
|
1428
|
+
...agentProductsProps,
|
|
1429
|
+
onUnavailable: handleAgentUnavailable
|
|
1430
|
+
}
|
|
1431
|
+
);
|
|
1314
1432
|
return /* @__PURE__ */ jsx(
|
|
1315
1433
|
SearchModal,
|
|
1316
1434
|
{
|
|
@@ -1338,20 +1456,7 @@ function CommerceSearchView({
|
|
|
1338
1456
|
onSelect: handleRecentSelect,
|
|
1339
1457
|
onClear: handleClearRecent
|
|
1340
1458
|
},
|
|
1341
|
-
agentPanel
|
|
1342
|
-
NuiAgentPanel,
|
|
1343
|
-
{
|
|
1344
|
-
agent,
|
|
1345
|
-
query: handoff.query,
|
|
1346
|
-
handoffContext: {
|
|
1347
|
-
source: "storefront_search",
|
|
1348
|
-
trigger: "zero_results",
|
|
1349
|
-
query: handoff.query,
|
|
1350
|
-
did_you_mean: handoff.didYouMean
|
|
1351
|
-
},
|
|
1352
|
-
onUnavailable: handleAgentUnavailable
|
|
1353
|
-
}
|
|
1354
|
-
)
|
|
1459
|
+
agentPanel
|
|
1355
1460
|
}
|
|
1356
1461
|
);
|
|
1357
1462
|
}
|
|
@@ -1369,7 +1474,7 @@ function CommerceSearch({
|
|
|
1369
1474
|
useEffect(() => {
|
|
1370
1475
|
if (isOpen) setHasOpened(true);
|
|
1371
1476
|
}, [isOpen]);
|
|
1372
|
-
const { minimumSearchLength, agent } = useCommerceSearchConfig({
|
|
1477
|
+
const { minimumSearchLength, agent, allowGuestAgent } = useCommerceSearchConfig({
|
|
1373
1478
|
country,
|
|
1374
1479
|
language,
|
|
1375
1480
|
enabled: hasOpened
|
|
@@ -1402,6 +1507,14 @@ function CommerceSearch({
|
|
|
1402
1507
|
}),
|
|
1403
1508
|
[country, language, isAuthenticated, accountType, userId]
|
|
1404
1509
|
);
|
|
1510
|
+
const agentProducts = useMemo(() => {
|
|
1511
|
+
const environment = getProductEnvironment();
|
|
1512
|
+
return environment ? {
|
|
1513
|
+
environment,
|
|
1514
|
+
market: country.toUpperCase(),
|
|
1515
|
+
language: language.toLowerCase()
|
|
1516
|
+
} : void 0;
|
|
1517
|
+
}, [country, language]);
|
|
1405
1518
|
return /* @__PURE__ */ jsx(
|
|
1406
1519
|
CommerceSearchView,
|
|
1407
1520
|
{
|
|
@@ -1411,6 +1524,8 @@ function CommerceSearch({
|
|
|
1411
1524
|
navigate: navigateToPath,
|
|
1412
1525
|
isAuthenticated,
|
|
1413
1526
|
...agent ? { agent } : {},
|
|
1527
|
+
...allowGuestAgent ? { allowGuestAgent } : {},
|
|
1528
|
+
...agentProducts ? { agentProducts } : {},
|
|
1414
1529
|
logo,
|
|
1415
1530
|
minimumSearchLength,
|
|
1416
1531
|
gtmContext
|