@neurodyn/react-ai-try-on 0.0.5 → 0.1.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/dist/index.d.ts +280 -10
- package/dist/index.js +709 -142
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -2045,6 +2045,10 @@ var __webpack_modules__ = {
|
|
|
2045
2045
|
padding-bottom: 5px;
|
|
2046
2046
|
}
|
|
2047
2047
|
|
|
2048
|
+
.pl-2 {
|
|
2049
|
+
padding-left: calc(var(--spacing) * 2);
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2048
2052
|
.pl-3 {
|
|
2049
2053
|
padding-left: calc(var(--spacing) * 3);
|
|
2050
2054
|
}
|
|
@@ -2707,6 +2711,10 @@ var __webpack_modules__ = {
|
|
|
2707
2711
|
-webkit-mask-size: 18% 18%;
|
|
2708
2712
|
}
|
|
2709
2713
|
|
|
2714
|
+
.paused {
|
|
2715
|
+
animation-play-state: paused;
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2710
2718
|
.running {
|
|
2711
2719
|
animation-play-state: running;
|
|
2712
2720
|
}
|
|
@@ -4479,6 +4487,10 @@ var __webpack_modules__ = {
|
|
|
4479
4487
|
color: var(--v-text-dark);
|
|
4480
4488
|
}
|
|
4481
4489
|
|
|
4490
|
+
.data-\\[variant\\=destructive\\]\\:\\[\\&_svg\\:not\\(\\[class\\*\\=text-\\]\\)\\]\\:text-inherit[data-variant="destructive"] svg:not([class*="text-"]) {
|
|
4491
|
+
color: inherit;
|
|
4492
|
+
}
|
|
4493
|
+
|
|
4482
4494
|
.\\[\\&_tr\\]\\:border-b tr {
|
|
4483
4495
|
border-bottom-style: var(--tw-border-style);
|
|
4484
4496
|
border-bottom-width: 1px;
|
|
@@ -9462,6 +9474,15 @@ function ThemeProvider({ children, defaultTheme = 'system', storageKey = 'v-them
|
|
|
9462
9474
|
});
|
|
9463
9475
|
}
|
|
9464
9476
|
var fontsinline = __webpack_require__("../ui/src/styles/fonts.css?inline");
|
|
9477
|
+
const externalTryOnClient = {
|
|
9478
|
+
requestUploadUrls: async ()=>{
|
|
9479
|
+
throw new Error('External generation handles its own uploads');
|
|
9480
|
+
},
|
|
9481
|
+
generateTryOn: async ()=>{
|
|
9482
|
+
throw new Error('External generation handler is required');
|
|
9483
|
+
},
|
|
9484
|
+
sendWidgetEvent: ()=>{}
|
|
9485
|
+
};
|
|
9465
9486
|
const DEFAULT_API_TIMEOUT = 30000;
|
|
9466
9487
|
function createDefaultClient(defaultBaseURL) {
|
|
9467
9488
|
return axios.create({
|
|
@@ -9859,6 +9880,17 @@ async function tryOnControllerCreateUploadUrls(params, config = {}) {
|
|
|
9859
9880
|
});
|
|
9860
9881
|
return res.data;
|
|
9861
9882
|
}
|
|
9883
|
+
async function tryOnControllerGenerateShopifyTryOn(data, config = {}) {
|
|
9884
|
+
const { client: request = node_client_node_client, ...requestConfig } = config;
|
|
9885
|
+
const requestData = data;
|
|
9886
|
+
const res = await request({
|
|
9887
|
+
method: "POST",
|
|
9888
|
+
url: "/public/try-on/shopify/generate",
|
|
9889
|
+
data: requestData,
|
|
9890
|
+
...requestConfig
|
|
9891
|
+
});
|
|
9892
|
+
return res.data;
|
|
9893
|
+
}
|
|
9862
9894
|
async function tryOnControllerGenerateTryOn(data, config = {}) {
|
|
9863
9895
|
const { client: request = node_client_node_client, ...requestConfig } = config;
|
|
9864
9896
|
const requestData = data;
|
|
@@ -10146,6 +10178,16 @@ function createTryOnClient({ apiKey } = {}) {
|
|
|
10146
10178
|
}) : createInternalTryOnClient();
|
|
10147
10179
|
}
|
|
10148
10180
|
const ns1 = {
|
|
10181
|
+
activationLoading: 'Checking this product…',
|
|
10182
|
+
activationLoadingSubtitle: 'One moment while the store confirms try-on for this item.',
|
|
10183
|
+
activationTemporarilyUnavailable: 'Try-on is paused for this store right now. Please check back later.',
|
|
10184
|
+
activationUnavailableTitle: 'Try-on is unavailable',
|
|
10185
|
+
externalPhotoRequired: 'Please upload your photo again.',
|
|
10186
|
+
externalNoTokens: 'The store has no tokens remaining.',
|
|
10187
|
+
externalProductUnavailable: 'Try-on is unavailable for this product.',
|
|
10188
|
+
externalServiceUnavailable: 'Try-on is unavailable. Please try again later.',
|
|
10189
|
+
externalTimeout: 'The request timed out. Please try again.',
|
|
10190
|
+
externalPhotoHint: 'Upload a clear photo of yourself. The store chooses the item used for your try-on.',
|
|
10149
10191
|
back: 'Back',
|
|
10150
10192
|
badge: 'Try it on',
|
|
10151
10193
|
confirmBadge: 'Almost there',
|
|
@@ -10235,7 +10277,7 @@ const ns1 = {
|
|
|
10235
10277
|
startUpload: 'Choose your photo',
|
|
10236
10278
|
termsJoiner: '&',
|
|
10237
10279
|
termsLink: 'Terms',
|
|
10238
|
-
termsPrefix: 'By using this service,
|
|
10280
|
+
termsPrefix: 'By using this service, you agree to',
|
|
10239
10281
|
privacyLink: 'privacy Policy',
|
|
10240
10282
|
upperBodyIntroBadArmsCrossed: 'Arms crossed hide the fit',
|
|
10241
10283
|
upperBodyIntroBadObjectBlockingTorso: 'Object blocks the torso',
|
|
@@ -10257,6 +10299,16 @@ const ns1 = {
|
|
|
10257
10299
|
wristIntroTitle: 'Give us a hand'
|
|
10258
10300
|
};
|
|
10259
10301
|
const ru_ns1 = {
|
|
10302
|
+
activationLoading: 'Проверяем товар…',
|
|
10303
|
+
activationLoadingSubtitle: 'Магазин подтверждает примерку для этого товара.',
|
|
10304
|
+
activationTemporarilyUnavailable: 'Примерка в этом магазине сейчас приостановлена. Загляните позже.',
|
|
10305
|
+
activationUnavailableTitle: 'Примерка недоступна',
|
|
10306
|
+
externalPhotoRequired: 'Загрузите фото заново.',
|
|
10307
|
+
externalNoTokens: 'У магазина закончились токены.',
|
|
10308
|
+
externalProductUnavailable: 'Примерка для этого товара недоступна.',
|
|
10309
|
+
externalServiceUnavailable: 'Примерка недоступна. Попробуйте позже.',
|
|
10310
|
+
externalTimeout: 'Время ожидания истекло. Попробуйте снова.',
|
|
10311
|
+
externalPhotoHint: 'Загрузите чёткое фото себя. Изображение товара для примерки определяется настройками магазина.',
|
|
10260
10312
|
back: 'Назад',
|
|
10261
10313
|
badge: 'Примерить',
|
|
10262
10314
|
confirmBadge: 'Почти готово',
|
|
@@ -10313,7 +10365,7 @@ const ru_ns1 = {
|
|
|
10313
10365
|
headwearIntroTitle: 'Загрузите фото головы и плеч',
|
|
10314
10366
|
introCta: 'Продолжить',
|
|
10315
10367
|
introBadge: 'Совет',
|
|
10316
|
-
myFits: '
|
|
10368
|
+
myFits: 'Мои образы',
|
|
10317
10369
|
lowerBodyIntroBadCoveredWaist: 'Свободная одежда скрывает линию талии',
|
|
10318
10370
|
lowerBodyIntroBadSitting: 'В сидячей позе ноги согнуты',
|
|
10319
10371
|
lowerBodyIntroGoodFullBody: 'Фото в полный рост',
|
|
@@ -10338,8 +10390,8 @@ const ru_ns1 = {
|
|
|
10338
10390
|
resultReset: 'Сохранить',
|
|
10339
10391
|
resultShare: 'Поделиться',
|
|
10340
10392
|
resultTitle: 'Вот как это выглядит на вас',
|
|
10341
|
-
resultTryAnother: '
|
|
10342
|
-
resultTryAnotherWithPrice: '
|
|
10393
|
+
resultTryAnother: 'Добавить в корзину',
|
|
10394
|
+
resultTryAnotherWithPrice: 'Добавить в корзину – {{price}}',
|
|
10343
10395
|
share: 'Поделиться',
|
|
10344
10396
|
startHistory: 'Смотреть прошлые результаты',
|
|
10345
10397
|
startTitle: 'Хотите увидеть это на себе?',
|
|
@@ -10392,6 +10444,7 @@ const PROPERTY_BLOCK_RE = /@property\s+(--[^{\s]+)\s*\{([^}]*)\}/g;
|
|
|
10392
10444
|
const INITIAL_VALUE_RE = /initial-value:([^;}]+)/i;
|
|
10393
10445
|
const NON_INHERITING_RE = /inherits:\s*false(?:\s*;|\s*$)/i;
|
|
10394
10446
|
const ROOT_TO_HOST_SELECTOR_RE = /:root\s*,\s*:host|:root/g;
|
|
10447
|
+
const SHADOW_HOST_VISIBILITY_CSS = ':host{display:block!important;visibility:visible!important}';
|
|
10395
10448
|
function createShadowRootCssText(cssText) {
|
|
10396
10449
|
const cssForHost = cssText.replace(ROOT_TO_HOST_SELECTOR_RE, ':host');
|
|
10397
10450
|
const propertyBlocks = Array.from(cssText.matchAll(PROPERTY_BLOCK_RE));
|
|
@@ -18193,7 +18246,7 @@ function ResultImagePanel({ className, onOpenComparison, productLabel, productUr
|
|
|
18193
18246
|
});
|
|
18194
18247
|
}
|
|
18195
18248
|
const COMPARISON_DIALOG_BACKGROUND_CLASS_NAME = 'bg-[#212124E5]';
|
|
18196
|
-
function ComparisonDialog({ onAddToCart, onClose, onDeleteResult, onSaveResult, onShareResult, portalContainer, productName, productPrice, productUrl, result }) {
|
|
18249
|
+
function ComparisonDialog({ addToCartError, addToCartPending = false, onAddToCart, onClose, onDeleteResult, onSaveResult, onShareResult, portalContainer, productName, productPrice, productUrl, result }) {
|
|
18197
18250
|
const { t } = useTranslation();
|
|
18198
18251
|
const productLabel = productName ?? t('resultProductLink');
|
|
18199
18252
|
const normalizedProductPrice = normalizeProductPrice(productPrice);
|
|
@@ -18307,59 +18360,67 @@ function ComparisonDialog({ onAddToCart, onClose, onDeleteResult, onSaveResult,
|
|
|
18307
18360
|
]
|
|
18308
18361
|
})
|
|
18309
18362
|
}),
|
|
18310
|
-
/*#__PURE__*/
|
|
18311
|
-
className: "flex
|
|
18312
|
-
children:
|
|
18313
|
-
|
|
18314
|
-
|
|
18315
|
-
|
|
18316
|
-
|
|
18317
|
-
|
|
18318
|
-
|
|
18319
|
-
|
|
18320
|
-
|
|
18321
|
-
|
|
18322
|
-
|
|
18363
|
+
/*#__PURE__*/ jsxs("div", {
|
|
18364
|
+
className: "flex shrink-0 flex-col items-center gap-1 px-8 pb-6 pt-3",
|
|
18365
|
+
children: [
|
|
18366
|
+
addToCartError && /*#__PURE__*/ jsx_runtime_jsx("p", {
|
|
18367
|
+
className: "text-xs text-text-sub",
|
|
18368
|
+
role: "alert",
|
|
18369
|
+
children: addToCartError
|
|
18370
|
+
}),
|
|
18371
|
+
/*#__PURE__*/ jsxs("div", {
|
|
18372
|
+
className: "flex h-23 w-full max-w-104 items-start gap-2",
|
|
18373
|
+
children: [
|
|
18374
|
+
onAddToCart && /*#__PURE__*/ jsxs(button_Button, {
|
|
18375
|
+
className: "min-w-0 flex-1",
|
|
18376
|
+
disabled: addToCartPending,
|
|
18377
|
+
size: "lg",
|
|
18378
|
+
type: "button",
|
|
18379
|
+
variant: "contrast",
|
|
18380
|
+
onClick: onAddToCart,
|
|
18381
|
+
children: [
|
|
18382
|
+
/*#__PURE__*/ jsx_runtime_jsx(Cart, {
|
|
18383
|
+
"data-icon": "inline-start"
|
|
18384
|
+
}),
|
|
18385
|
+
/*#__PURE__*/ jsx_runtime_jsx("span", {
|
|
18386
|
+
className: "truncate",
|
|
18387
|
+
children: addToCartLabel
|
|
18388
|
+
})
|
|
18389
|
+
]
|
|
18390
|
+
}),
|
|
18391
|
+
/*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
18392
|
+
"aria-label": t('share'),
|
|
18393
|
+
size: "icon-lg",
|
|
18394
|
+
type: "button",
|
|
18395
|
+
variant: "outline",
|
|
18396
|
+
onClick: onShareResult,
|
|
18397
|
+
children: /*#__PURE__*/ jsx_runtime_jsx(Share, {
|
|
18398
|
+
"data-icon": "inline-start"
|
|
18399
|
+
})
|
|
18400
|
+
}),
|
|
18401
|
+
/*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
18402
|
+
"aria-label": t('download'),
|
|
18403
|
+
size: "icon-lg",
|
|
18404
|
+
type: "button",
|
|
18405
|
+
variant: "outline",
|
|
18406
|
+
onClick: onSaveResult,
|
|
18407
|
+
children: /*#__PURE__*/ jsx_runtime_jsx(Download, {
|
|
18408
|
+
"data-icon": "inline-start"
|
|
18409
|
+
})
|
|
18410
|
+
}),
|
|
18411
|
+
/*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
18412
|
+
"aria-label": t('reset'),
|
|
18413
|
+
size: "icon-lg",
|
|
18414
|
+
type: "button",
|
|
18415
|
+
variant: "outline",
|
|
18416
|
+
onClick: handleDelete,
|
|
18417
|
+
children: /*#__PURE__*/ jsx_runtime_jsx(EditorTrash, {
|
|
18323
18418
|
"data-icon": "inline-start"
|
|
18324
|
-
}),
|
|
18325
|
-
/*#__PURE__*/ jsx_runtime_jsx("span", {
|
|
18326
|
-
className: "truncate",
|
|
18327
|
-
children: addToCartLabel
|
|
18328
18419
|
})
|
|
18329
|
-
]
|
|
18330
|
-
}),
|
|
18331
|
-
/*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
18332
|
-
"aria-label": t('share'),
|
|
18333
|
-
size: "icon-lg",
|
|
18334
|
-
type: "button",
|
|
18335
|
-
variant: "outline",
|
|
18336
|
-
onClick: onShareResult,
|
|
18337
|
-
children: /*#__PURE__*/ jsx_runtime_jsx(Share, {
|
|
18338
|
-
"data-icon": "inline-start"
|
|
18339
|
-
})
|
|
18340
|
-
}),
|
|
18341
|
-
/*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
18342
|
-
"aria-label": t('download'),
|
|
18343
|
-
size: "icon-lg",
|
|
18344
|
-
type: "button",
|
|
18345
|
-
variant: "outline",
|
|
18346
|
-
onClick: onSaveResult,
|
|
18347
|
-
children: /*#__PURE__*/ jsx_runtime_jsx(Download, {
|
|
18348
|
-
"data-icon": "inline-start"
|
|
18349
|
-
})
|
|
18350
|
-
}),
|
|
18351
|
-
/*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
18352
|
-
"aria-label": t('reset'),
|
|
18353
|
-
size: "icon-lg",
|
|
18354
|
-
type: "button",
|
|
18355
|
-
variant: "outline",
|
|
18356
|
-
onClick: handleDelete,
|
|
18357
|
-
children: /*#__PURE__*/ jsx_runtime_jsx(EditorTrash, {
|
|
18358
|
-
"data-icon": "inline-start"
|
|
18359
18420
|
})
|
|
18360
|
-
|
|
18361
|
-
|
|
18362
|
-
|
|
18421
|
+
]
|
|
18422
|
+
})
|
|
18423
|
+
]
|
|
18363
18424
|
})
|
|
18364
18425
|
]
|
|
18365
18426
|
})
|
|
@@ -18881,10 +18942,10 @@ function getAiTryOnGuidance(productType) {
|
|
|
18881
18942
|
}
|
|
18882
18943
|
function StartScreen({ view }) {
|
|
18883
18944
|
const { t } = useTranslation();
|
|
18884
|
-
const guidance = getAiTryOnGuidance(view.productType);
|
|
18945
|
+
const guidance = view.productType ? getAiTryOnGuidance(view.productType) : null;
|
|
18885
18946
|
return /*#__PURE__*/ jsxs(ScreenLayout, {
|
|
18886
18947
|
title: t('startTitle'),
|
|
18887
|
-
subtitle: t(guidance
|
|
18948
|
+
subtitle: t(guidance?.titleKey ?? 'externalPhotoHint'),
|
|
18888
18949
|
children: [
|
|
18889
18950
|
/*#__PURE__*/ jsxs(TryOnImagePanel, {
|
|
18890
18951
|
className: "mt-3",
|
|
@@ -18935,7 +18996,8 @@ function StartScreen({ view }) {
|
|
|
18935
18996
|
}
|
|
18936
18997
|
function IntroScreen({ view }) {
|
|
18937
18998
|
const { t } = useTranslation();
|
|
18938
|
-
const guidance = getAiTryOnGuidance(view.productType);
|
|
18999
|
+
const guidance = view.productType ? getAiTryOnGuidance(view.productType) : null;
|
|
19000
|
+
if (!guidance) return null;
|
|
18939
19001
|
return /*#__PURE__*/ jsxs(ScreenLayout, {
|
|
18940
19002
|
title: t(guidance.titleKey),
|
|
18941
19003
|
subtitle: t(guidance.subtitleKey),
|
|
@@ -19053,6 +19115,79 @@ function ConfirmScreen({ view }) {
|
|
|
19053
19115
|
]
|
|
19054
19116
|
});
|
|
19055
19117
|
}
|
|
19118
|
+
function ActivationLoadingScreen() {
|
|
19119
|
+
const { t } = useTranslation();
|
|
19120
|
+
return /*#__PURE__*/ jsx_runtime_jsx(ScreenLayout, {
|
|
19121
|
+
title: t('activationLoading'),
|
|
19122
|
+
subtitle: t('activationLoadingSubtitle'),
|
|
19123
|
+
children: /*#__PURE__*/ jsx_runtime_jsx(TryOnImagePanel, {
|
|
19124
|
+
className: "mt-3",
|
|
19125
|
+
children: /*#__PURE__*/ jsx_runtime_jsx(LoadingTexture, {
|
|
19126
|
+
animated: true,
|
|
19127
|
+
className: "left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
|
|
19128
|
+
})
|
|
19129
|
+
})
|
|
19130
|
+
});
|
|
19131
|
+
}
|
|
19132
|
+
function ActivationUnavailableScreen({ onClose, temporary }) {
|
|
19133
|
+
const { t } = useTranslation();
|
|
19134
|
+
return /*#__PURE__*/ jsx_runtime_jsx(ScreenLayout, {
|
|
19135
|
+
title: t('activationUnavailableTitle'),
|
|
19136
|
+
subtitle: t(temporary ? 'activationTemporarilyUnavailable' : 'externalProductUnavailable'),
|
|
19137
|
+
children: /*#__PURE__*/ jsxs(ActionStack, {
|
|
19138
|
+
className: "mt-4",
|
|
19139
|
+
children: [
|
|
19140
|
+
onClose && /*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
19141
|
+
className: "w-full",
|
|
19142
|
+
size: "lg",
|
|
19143
|
+
type: "button",
|
|
19144
|
+
variant: "contrast",
|
|
19145
|
+
onClick: onClose,
|
|
19146
|
+
children: t('close')
|
|
19147
|
+
}),
|
|
19148
|
+
/*#__PURE__*/ jsx_runtime_jsx(TermsCopy, {
|
|
19149
|
+
className: "text-text-sub"
|
|
19150
|
+
})
|
|
19151
|
+
]
|
|
19152
|
+
})
|
|
19153
|
+
});
|
|
19154
|
+
}
|
|
19155
|
+
function ActivationErrorScreen({ onClose, onRetry }) {
|
|
19156
|
+
const { t } = useTranslation();
|
|
19157
|
+
return /*#__PURE__*/ jsx_runtime_jsx(ScreenLayout, {
|
|
19158
|
+
title: t('errorTitle'),
|
|
19159
|
+
subtitle: t('externalServiceUnavailable'),
|
|
19160
|
+
children: /*#__PURE__*/ jsxs(ActionStack, {
|
|
19161
|
+
className: "mt-4",
|
|
19162
|
+
children: [
|
|
19163
|
+
onRetry && /*#__PURE__*/ jsxs(button_Button, {
|
|
19164
|
+
className: "w-full",
|
|
19165
|
+
size: "lg",
|
|
19166
|
+
type: "button",
|
|
19167
|
+
variant: "contrast",
|
|
19168
|
+
onClick: onRetry,
|
|
19169
|
+
children: [
|
|
19170
|
+
/*#__PURE__*/ jsx_runtime_jsx(Vizbl, {
|
|
19171
|
+
"data-icon": "inline-start"
|
|
19172
|
+
}),
|
|
19173
|
+
t('errorRetry')
|
|
19174
|
+
]
|
|
19175
|
+
}),
|
|
19176
|
+
onClose && /*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
19177
|
+
className: "w-full",
|
|
19178
|
+
size: "lg",
|
|
19179
|
+
type: "button",
|
|
19180
|
+
variant: "outline",
|
|
19181
|
+
onClick: onClose,
|
|
19182
|
+
children: t('close')
|
|
19183
|
+
}),
|
|
19184
|
+
/*#__PURE__*/ jsx_runtime_jsx(TermsCopy, {
|
|
19185
|
+
className: "text-text-sub"
|
|
19186
|
+
})
|
|
19187
|
+
]
|
|
19188
|
+
})
|
|
19189
|
+
});
|
|
19190
|
+
}
|
|
19056
19191
|
function ProcessingScreen({ view }) {
|
|
19057
19192
|
const { t } = useTranslation();
|
|
19058
19193
|
return /*#__PURE__*/ jsxs(ScreenLayout, {
|
|
@@ -19101,14 +19236,25 @@ function ProcessingScreen({ view }) {
|
|
|
19101
19236
|
]
|
|
19102
19237
|
});
|
|
19103
19238
|
}
|
|
19104
|
-
function ErrorScreen({ view }) {
|
|
19239
|
+
function ErrorScreen({ view, onClose }) {
|
|
19105
19240
|
const { t } = useTranslation();
|
|
19106
19241
|
const isFileTooLarge = 'upload-validation' === view.error.kind && 'file-too-large' === view.error.code;
|
|
19242
|
+
const externalErrors = {
|
|
19243
|
+
tokens: 'externalNoTokens',
|
|
19244
|
+
product: 'externalProductUnavailable',
|
|
19245
|
+
service: 'externalServiceUnavailable',
|
|
19246
|
+
timeout: 'externalTimeout',
|
|
19247
|
+
'photo-required': 'externalPhotoRequired'
|
|
19248
|
+
};
|
|
19249
|
+
const code = 'generation' === view.error.kind ? view.error.code : void 0;
|
|
19250
|
+
const externalKey = code ? externalErrors[code] : void 0;
|
|
19251
|
+
const canRetry = !code || 'service' === code || 'timeout' === code;
|
|
19252
|
+
const canChangePhoto = !code || 'photo-required' === code;
|
|
19107
19253
|
return /*#__PURE__*/ jsxs(ScreenLayout, {
|
|
19108
19254
|
title: t(isFileTooLarge ? 'errorFileTooLarge' : 'errorTitle'),
|
|
19109
|
-
subtitle: isFileTooLarge ? void 0 : t('errorSubtitle'),
|
|
19255
|
+
subtitle: isFileTooLarge ? void 0 : t(externalKey ?? 'errorSubtitle'),
|
|
19110
19256
|
children: [
|
|
19111
|
-
!isFileTooLarge && /*#__PURE__*/ jsxs(TryOnImagePanel, {
|
|
19257
|
+
!isFileTooLarge && !code && /*#__PURE__*/ jsxs(TryOnImagePanel, {
|
|
19112
19258
|
className: "mt-3",
|
|
19113
19259
|
children: [
|
|
19114
19260
|
/*#__PURE__*/ jsx_runtime_jsx(BlurredPhotoBackdrop, {
|
|
@@ -19156,7 +19302,7 @@ function ErrorScreen({ view }) {
|
|
|
19156
19302
|
/*#__PURE__*/ jsxs(ActionStack, {
|
|
19157
19303
|
className: "mt-4",
|
|
19158
19304
|
children: [
|
|
19159
|
-
/*#__PURE__*/ jsxs(button_Button, {
|
|
19305
|
+
canRetry && /*#__PURE__*/ jsxs(button_Button, {
|
|
19160
19306
|
className: "w-full",
|
|
19161
19307
|
size: "lg",
|
|
19162
19308
|
type: "button",
|
|
@@ -19169,7 +19315,7 @@ function ErrorScreen({ view }) {
|
|
|
19169
19315
|
t('errorRetry')
|
|
19170
19316
|
]
|
|
19171
19317
|
}),
|
|
19172
|
-
/*#__PURE__*/ jsxs(button_Button, {
|
|
19318
|
+
canChangePhoto && /*#__PURE__*/ jsxs(button_Button, {
|
|
19173
19319
|
className: "w-full",
|
|
19174
19320
|
size: "lg",
|
|
19175
19321
|
type: "button",
|
|
@@ -19182,6 +19328,14 @@ function ErrorScreen({ view }) {
|
|
|
19182
19328
|
t('errorDifferentPhoto')
|
|
19183
19329
|
]
|
|
19184
19330
|
}),
|
|
19331
|
+
code && onClose && /*#__PURE__*/ jsx_runtime_jsx(button_Button, {
|
|
19332
|
+
className: "w-full",
|
|
19333
|
+
size: "lg",
|
|
19334
|
+
type: "button",
|
|
19335
|
+
variant: "outline",
|
|
19336
|
+
onClick: onClose,
|
|
19337
|
+
children: t('close')
|
|
19338
|
+
}),
|
|
19185
19339
|
/*#__PURE__*/ jsx_runtime_jsx(TermsCopy, {
|
|
19186
19340
|
className: "text-text-sub"
|
|
19187
19341
|
})
|
|
@@ -19190,8 +19344,9 @@ function ErrorScreen({ view }) {
|
|
|
19190
19344
|
]
|
|
19191
19345
|
});
|
|
19192
19346
|
}
|
|
19193
|
-
function ResultScreen({ view }) {
|
|
19347
|
+
function ResultScreen({ view, showAddToCart = true, onAddToCart, addToCartPending = false, addToCartError }) {
|
|
19194
19348
|
const { t } = useTranslation();
|
|
19349
|
+
const addToCart = onAddToCart ?? view.addToCart;
|
|
19195
19350
|
const normalizedProductPrice = try_on_screens_normalizeProductPrice(view.productPrice);
|
|
19196
19351
|
const addToCartLabel = normalizedProductPrice ? t('resultTryAnotherWithPrice', {
|
|
19197
19352
|
price: normalizedProductPrice
|
|
@@ -19202,7 +19357,8 @@ function ResultScreen({ view }) {
|
|
|
19202
19357
|
className: "flex flex-col gap-4 px-6 pb-2 pt-4 sm:px-8",
|
|
19203
19358
|
children: view.resultHistory.map((historyItem, index)=>/*#__PURE__*/ jsx_runtime_jsx(ResultFitCard, {
|
|
19204
19359
|
compact: index > 0,
|
|
19205
|
-
onAddToCart:
|
|
19360
|
+
onAddToCart: showAddToCart ? addToCart : void 0,
|
|
19361
|
+
addToCartPending: addToCartPending,
|
|
19206
19362
|
productName: historyItem.productName ?? view.productName,
|
|
19207
19363
|
productPrice: historyItem.productPrice,
|
|
19208
19364
|
productUrl: historyItem.productUrl ?? view.productUrl,
|
|
@@ -19230,12 +19386,13 @@ function ResultScreen({ view }) {
|
|
|
19230
19386
|
/*#__PURE__*/ jsxs(ActionStack, {
|
|
19231
19387
|
className: "mt-4",
|
|
19232
19388
|
children: [
|
|
19233
|
-
/*#__PURE__*/ jsxs(button_Button, {
|
|
19389
|
+
showAddToCart && /*#__PURE__*/ jsxs(button_Button, {
|
|
19234
19390
|
className: "w-full",
|
|
19391
|
+
disabled: addToCartPending,
|
|
19235
19392
|
size: "lg",
|
|
19236
19393
|
type: "button",
|
|
19237
19394
|
variant: "contrast",
|
|
19238
|
-
onClick:
|
|
19395
|
+
onClick: addToCart,
|
|
19239
19396
|
children: [
|
|
19240
19397
|
/*#__PURE__*/ jsx_runtime_jsx(Cart, {
|
|
19241
19398
|
"data-icon": "inline-start"
|
|
@@ -19243,6 +19400,11 @@ function ResultScreen({ view }) {
|
|
|
19243
19400
|
addToCartLabel
|
|
19244
19401
|
]
|
|
19245
19402
|
}),
|
|
19403
|
+
addToCartError && /*#__PURE__*/ jsx_runtime_jsx("p", {
|
|
19404
|
+
className: "text-center text-xs text-text-sub",
|
|
19405
|
+
role: "alert",
|
|
19406
|
+
children: addToCartError
|
|
19407
|
+
}),
|
|
19246
19408
|
/*#__PURE__*/ jsxs("div", {
|
|
19247
19409
|
className: "grid grid-cols-3 gap-2",
|
|
19248
19410
|
children: [
|
|
@@ -19286,7 +19448,7 @@ function ResultScreen({ view }) {
|
|
|
19286
19448
|
]
|
|
19287
19449
|
});
|
|
19288
19450
|
}
|
|
19289
|
-
function ResultFitCard({ compact = false, onAddToCart, onDeleteResult, onOpenComparison, onSaveResult, onShareResult, productName, productPrice, productUrl, result }) {
|
|
19451
|
+
function ResultFitCard({ compact = false, onAddToCart, addToCartPending = false, onDeleteResult, onOpenComparison, onSaveResult, onShareResult, productName, productPrice, productUrl, result }) {
|
|
19290
19452
|
const { t } = useTranslation();
|
|
19291
19453
|
const productLabel = productName ?? t('resultProductLink');
|
|
19292
19454
|
const normalizedProductPrice = try_on_screens_normalizeProductPrice(productPrice);
|
|
@@ -19306,8 +19468,9 @@ function ResultFitCard({ compact = false, onAddToCart, onDeleteResult, onOpenCom
|
|
|
19306
19468
|
/*#__PURE__*/ jsxs("div", {
|
|
19307
19469
|
className: "flex gap-2",
|
|
19308
19470
|
children: [
|
|
19309
|
-
/*#__PURE__*/ jsxs(button_Button, {
|
|
19471
|
+
onAddToCart && /*#__PURE__*/ jsxs(button_Button, {
|
|
19310
19472
|
className: "min-w-0 flex-1",
|
|
19473
|
+
disabled: addToCartPending,
|
|
19311
19474
|
size: "default",
|
|
19312
19475
|
type: "button",
|
|
19313
19476
|
variant: "contrast",
|
|
@@ -19429,6 +19592,55 @@ function try_on_screens_normalizeProductPrice(value) {
|
|
|
19429
19592
|
const normalized = value?.trim();
|
|
19430
19593
|
return normalized || void 0;
|
|
19431
19594
|
}
|
|
19595
|
+
const IMAGE_SNIFF_BYTES = 16;
|
|
19596
|
+
const IMAGE_BRANDS = new Set([
|
|
19597
|
+
'avif',
|
|
19598
|
+
'avis',
|
|
19599
|
+
'heic',
|
|
19600
|
+
'heix',
|
|
19601
|
+
'heim',
|
|
19602
|
+
'heis',
|
|
19603
|
+
'hevc',
|
|
19604
|
+
'hevx',
|
|
19605
|
+
'mif1',
|
|
19606
|
+
'msf1'
|
|
19607
|
+
]);
|
|
19608
|
+
async function readGeneratedImage(response) {
|
|
19609
|
+
const blob = toBlob(response);
|
|
19610
|
+
if (!blob || blob.size <= 0) return {
|
|
19611
|
+
blob: null,
|
|
19612
|
+
errorText: null
|
|
19613
|
+
};
|
|
19614
|
+
const header = new Uint8Array(await blob.slice(0, IMAGE_SNIFF_BYTES).arrayBuffer());
|
|
19615
|
+
if (!isImageHeader(header)) return {
|
|
19616
|
+
blob: null,
|
|
19617
|
+
errorText: (await blob.text().catch(()=>'')).slice(0, 2000)
|
|
19618
|
+
};
|
|
19619
|
+
return {
|
|
19620
|
+
blob,
|
|
19621
|
+
errorText: null
|
|
19622
|
+
};
|
|
19623
|
+
}
|
|
19624
|
+
function toBlob(response) {
|
|
19625
|
+
if (response instanceof Blob) return response;
|
|
19626
|
+
if (response instanceof ArrayBuffer) return new Blob([
|
|
19627
|
+
response
|
|
19628
|
+
]);
|
|
19629
|
+
if (ArrayBuffer.isView(response)) return new Blob([
|
|
19630
|
+
new Uint8Array(response.buffer, response.byteOffset, response.byteLength)
|
|
19631
|
+
]);
|
|
19632
|
+
return null;
|
|
19633
|
+
}
|
|
19634
|
+
function isImageHeader(header) {
|
|
19635
|
+
const startsWith = (...bytes)=>bytes.every((byte, index)=>header[index] === byte);
|
|
19636
|
+
const at = (offset, ...bytes)=>bytes.every((byte, index)=>header[offset + index] === byte);
|
|
19637
|
+
return startsWith(0xFF, 0xD8, 0xFF) || startsWith(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A) || startsWith(0x47, 0x49, 0x46, 0x38) || startsWith(0x42, 0x4D) || startsWith(0x52, 0x49, 0x46, 0x46) && at(8, 0x57, 0x45, 0x42, 0x50) || at(4, 0x66, 0x74, 0x79, 0x70) && IMAGE_BRANDS.has(brand(header));
|
|
19638
|
+
}
|
|
19639
|
+
function brand(header) {
|
|
19640
|
+
let value = '';
|
|
19641
|
+
for(let index = 8; index < 12; index++)value += String.fromCharCode(header[index] ?? 0);
|
|
19642
|
+
return value;
|
|
19643
|
+
}
|
|
19432
19644
|
const REQUIRED_UPLOAD_COUNT = 2;
|
|
19433
19645
|
function createNanoBananaAiTryOnProcessor({ createObjectUrl = defaultCreateObjectUrl, fetch: fetchImpl, productImageSrc, productType, tryOnClient, apiKey }) {
|
|
19434
19646
|
assertProductType(productType);
|
|
@@ -19447,8 +19659,12 @@ function createNanoBananaAiTryOnProcessor({ createObjectUrl = defaultCreateObjec
|
|
|
19447
19659
|
const [personUpload, productUpload] = resolveUploads(await client.requestUploadUrls(REQUIRED_UPLOAD_COUNT), REQUIRED_UPLOAD_COUNT);
|
|
19448
19660
|
context?.reportProgress(44);
|
|
19449
19661
|
await Promise.all([
|
|
19450
|
-
uploadImageToPresignedUrl(personUpload.uploadUrl, personImageBlob,
|
|
19451
|
-
|
|
19662
|
+
uploadImageToPresignedUrl(personUpload.uploadUrl, personImageBlob, {
|
|
19663
|
+
fetch: fetchImpl
|
|
19664
|
+
}),
|
|
19665
|
+
uploadImageToPresignedUrl(productUpload.uploadUrl, productImageBlob, {
|
|
19666
|
+
fetch: fetchImpl
|
|
19667
|
+
})
|
|
19452
19668
|
]);
|
|
19453
19669
|
context?.reportProgress(62);
|
|
19454
19670
|
const stopGenerationProgress = startGenerationProgress(context?.reportProgress);
|
|
@@ -19467,8 +19683,8 @@ function createNanoBananaAiTryOnProcessor({ createObjectUrl = defaultCreateObjec
|
|
|
19467
19683
|
stopGenerationProgress();
|
|
19468
19684
|
}
|
|
19469
19685
|
context?.reportProgress(96);
|
|
19470
|
-
const generatedImageBlob = await
|
|
19471
|
-
if (generatedImageBlob
|
|
19686
|
+
const { blob: generatedImageBlob } = await readGeneratedImage(response);
|
|
19687
|
+
if (!generatedImageBlob) throw new Error('AI try-on generation did not return an image');
|
|
19472
19688
|
context?.reportProgress(98);
|
|
19473
19689
|
const generatedImageSrc = createObjectUrl(generatedImageBlob);
|
|
19474
19690
|
if (!generatedImageSrc) throw new Error('AI try-on result image URL cannot be created');
|
|
@@ -19510,14 +19726,28 @@ function resolveFetch(fetchImpl) {
|
|
|
19510
19726
|
if ('function' == typeof fetch) return fetch;
|
|
19511
19727
|
throw new Error('Fetch API is not available for AI try-on image upload');
|
|
19512
19728
|
}
|
|
19513
|
-
async function uploadImageToPresignedUrl(uploadUrl, imageBlob,
|
|
19514
|
-
const
|
|
19515
|
-
|
|
19516
|
-
|
|
19729
|
+
async function uploadImageToPresignedUrl(uploadUrl, imageBlob, options = {}) {
|
|
19730
|
+
const { fetch: fetchImpl, signal, timeoutMs } = options;
|
|
19731
|
+
const controller = new AbortController();
|
|
19732
|
+
const abort = ()=>controller.abort(signal?.reason);
|
|
19733
|
+
const timer = void 0 === timeoutMs ? void 0 : setTimeout(()=>controller.abort(new DOMException('AI try-on image upload timed out', 'TimeoutError')), timeoutMs);
|
|
19734
|
+
if (signal?.aborted) abort();
|
|
19735
|
+
else signal?.addEventListener('abort', abort, {
|
|
19736
|
+
once: true
|
|
19517
19737
|
});
|
|
19518
|
-
|
|
19519
|
-
const
|
|
19520
|
-
|
|
19738
|
+
try {
|
|
19739
|
+
const response = await resolveFetch(fetchImpl)(uploadUrl, {
|
|
19740
|
+
body: imageBlob,
|
|
19741
|
+
method: 'PUT',
|
|
19742
|
+
signal: controller.signal
|
|
19743
|
+
});
|
|
19744
|
+
if (!response.ok) {
|
|
19745
|
+
const details = await response.text().catch(()=>'');
|
|
19746
|
+
throw new Error(`Nano Banana image upload failed with status ${response.status}${details ? `: ${details}` : ''}`);
|
|
19747
|
+
}
|
|
19748
|
+
} finally{
|
|
19749
|
+
clearTimeout(timer);
|
|
19750
|
+
signal?.removeEventListener('abort', abort);
|
|
19521
19751
|
}
|
|
19522
19752
|
}
|
|
19523
19753
|
async function resolveProductImageBlob(productImageSrc, fetchImpl) {
|
|
@@ -19539,24 +19769,6 @@ async function resolveBlobFromUrl(src, fetchImpl, message) {
|
|
|
19539
19769
|
}
|
|
19540
19770
|
return response.blob();
|
|
19541
19771
|
}
|
|
19542
|
-
async function resolveGeneratedImageBlob(response) {
|
|
19543
|
-
if (response instanceof Blob) return response.type ? response : new Blob([
|
|
19544
|
-
response
|
|
19545
|
-
], {
|
|
19546
|
-
type: 'image/jpeg'
|
|
19547
|
-
});
|
|
19548
|
-
if (response instanceof ArrayBuffer) return new Blob([
|
|
19549
|
-
response
|
|
19550
|
-
], {
|
|
19551
|
-
type: 'image/jpeg'
|
|
19552
|
-
});
|
|
19553
|
-
if ('string' == typeof response) return new Blob([
|
|
19554
|
-
response
|
|
19555
|
-
], {
|
|
19556
|
-
type: 'image/jpeg'
|
|
19557
|
-
});
|
|
19558
|
-
throw new Error('AI try-on generation did not return an image');
|
|
19559
|
-
}
|
|
19560
19772
|
function startGenerationProgress(reportProgress) {
|
|
19561
19773
|
if (!reportProgress) return ()=>{};
|
|
19562
19774
|
reportProgress(70);
|
|
@@ -19965,7 +20177,7 @@ class AiTryOnSession {
|
|
|
19965
20177
|
};
|
|
19966
20178
|
}
|
|
19967
20179
|
choosePhoto() {
|
|
19968
|
-
if (this.tipStore.consumeFirstView(this.state.productType)) {
|
|
20180
|
+
if (this.state.productType && this.tipStore.consumeFirstView(this.state.productType)) {
|
|
19969
20181
|
this.state = {
|
|
19970
20182
|
...this.state,
|
|
19971
20183
|
stage: 'intro'
|
|
@@ -19977,14 +20189,14 @@ class AiTryOnSession {
|
|
|
19977
20189
|
};
|
|
19978
20190
|
}
|
|
19979
20191
|
continueIntro() {
|
|
19980
|
-
this.tipStore.markSeen(this.state.productType);
|
|
20192
|
+
if (this.state.productType) this.tipStore.markSeen(this.state.productType);
|
|
19981
20193
|
return {
|
|
19982
20194
|
type: 'request-file-input'
|
|
19983
20195
|
};
|
|
19984
20196
|
}
|
|
19985
20197
|
requestClose() {
|
|
19986
20198
|
if ('intro' === this.state.stage) {
|
|
19987
|
-
this.tipStore.markSeen(this.state.productType);
|
|
20199
|
+
if (this.state.productType) this.tipStore.markSeen(this.state.productType);
|
|
19988
20200
|
this.goBack();
|
|
19989
20201
|
return null;
|
|
19990
20202
|
}
|
|
@@ -20128,12 +20340,15 @@ class AiTryOnSession {
|
|
|
20128
20340
|
};
|
|
20129
20341
|
return historyItem;
|
|
20130
20342
|
}
|
|
20131
|
-
failGeneration(message) {
|
|
20343
|
+
failGeneration(message, code) {
|
|
20132
20344
|
this.state = {
|
|
20133
20345
|
...this.state,
|
|
20134
20346
|
error: {
|
|
20135
20347
|
kind: 'generation',
|
|
20136
|
-
message
|
|
20348
|
+
message,
|
|
20349
|
+
...code ? {
|
|
20350
|
+
code
|
|
20351
|
+
} : {}
|
|
20137
20352
|
},
|
|
20138
20353
|
generationProduct: null,
|
|
20139
20354
|
stage: 'error'
|
|
@@ -20304,6 +20519,13 @@ function clampProgress(progress) {
|
|
|
20304
20519
|
function createPhotoId(file) {
|
|
20305
20520
|
return `${file.name}-${file.size}-${file.lastModified}`;
|
|
20306
20521
|
}
|
|
20522
|
+
class AiTryOnGenerationError extends Error {
|
|
20523
|
+
code;
|
|
20524
|
+
constructor(code){
|
|
20525
|
+
super(code), this.code = code;
|
|
20526
|
+
this.name = 'AiTryOnGenerationError';
|
|
20527
|
+
}
|
|
20528
|
+
}
|
|
20307
20529
|
function createAiTryOnInteractiveView(session, { addToCart, choosePhoto, deleteResult, generate, runSessionCommand, saveResult, shareResult, sync }) {
|
|
20308
20530
|
const currentView = session.view;
|
|
20309
20531
|
switch(currentView.stage){
|
|
@@ -20440,6 +20662,13 @@ function collectPhotoObjectUrl(photo) {
|
|
|
20440
20662
|
function useAiTryOnSession({ historyStore = indexedDbAiTryOnHistoryStore, objectUrls = browserAiTryOnObjectUrls, onRequestClose, onRequestFileInput, processPhoto, productImageSrc, productName, productPrice, productType, productUrl, tryOnClient, resultActions = browserAiTryOnResultActions, tipStore = browserAiTryOnTipStore }) {
|
|
20441
20663
|
const [, rerender] = (0, __rspack_external_react.useReducer)((value)=>value + 1, 0);
|
|
20442
20664
|
const trackedObjectUrls = (0, __rspack_external_react.useRef)(new Set());
|
|
20665
|
+
const mounted = (0, __rspack_external_react.useRef)(true);
|
|
20666
|
+
(0, __rspack_external_react.useEffect)(()=>{
|
|
20667
|
+
mounted.current = true;
|
|
20668
|
+
return ()=>{
|
|
20669
|
+
mounted.current = false;
|
|
20670
|
+
};
|
|
20671
|
+
}, []);
|
|
20443
20672
|
const createTrackedObjectUrl = (0, __rspack_external_react.useCallback)((blob)=>{
|
|
20444
20673
|
const src = objectUrls.createObjectUrl(blob);
|
|
20445
20674
|
if (src) trackedObjectUrls.current.add(src);
|
|
@@ -20465,12 +20694,16 @@ function useAiTryOnSession({ historyStore = indexedDbAiTryOnHistoryStore, object
|
|
|
20465
20694
|
productType,
|
|
20466
20695
|
productUrl
|
|
20467
20696
|
});
|
|
20468
|
-
const processSelectedPhoto = (0, __rspack_external_react.useMemo)(()=>
|
|
20697
|
+
const processSelectedPhoto = (0, __rspack_external_react.useMemo)(()=>{
|
|
20698
|
+
if (processPhoto) return processPhoto;
|
|
20699
|
+
assertProductType(productType);
|
|
20700
|
+
return createNanoBananaAiTryOnProcessor({
|
|
20469
20701
|
createObjectUrl: createTrackedObjectUrl,
|
|
20470
20702
|
productImageSrc,
|
|
20471
20703
|
productType,
|
|
20472
20704
|
tryOnClient
|
|
20473
|
-
})
|
|
20705
|
+
});
|
|
20706
|
+
}, [
|
|
20474
20707
|
createTrackedObjectUrl,
|
|
20475
20708
|
processPhoto,
|
|
20476
20709
|
productImageSrc,
|
|
@@ -20531,21 +20764,29 @@ function useAiTryOnSession({ historyStore = indexedDbAiTryOnHistoryStore, object
|
|
|
20531
20764
|
try {
|
|
20532
20765
|
const result = await processSelectedPhoto(photo, {
|
|
20533
20766
|
reportProgress: (progress)=>{
|
|
20767
|
+
if (!mounted.current) return;
|
|
20534
20768
|
session.reportGenerationProgress(progress);
|
|
20535
20769
|
sync();
|
|
20536
20770
|
}
|
|
20537
20771
|
});
|
|
20538
20772
|
await waitForRemainingProcessingDuration(processingStartedAt);
|
|
20773
|
+
if (!mounted.current) {
|
|
20774
|
+
persistHistoryItem(session.completeGeneration(result));
|
|
20775
|
+
if (result.after.src.startsWith('blob:')) objectUrls.revokeObjectUrl(result.after.src);
|
|
20776
|
+
return;
|
|
20777
|
+
}
|
|
20539
20778
|
const historyItem = session.completeGeneration(result);
|
|
20540
20779
|
trackResultObjectUrls(historyItem, trackedObjectUrls.current);
|
|
20541
20780
|
persistHistoryItem(historyItem);
|
|
20542
20781
|
sync();
|
|
20543
20782
|
} catch (error) {
|
|
20544
20783
|
await waitForRemainingProcessingDuration(processingStartedAt);
|
|
20545
|
-
|
|
20784
|
+
if (!mounted.current) return;
|
|
20785
|
+
session.failGeneration(error instanceof Error ? error.message : void 0, error instanceof AiTryOnGenerationError ? error.code : void 0);
|
|
20546
20786
|
sync();
|
|
20547
20787
|
}
|
|
20548
20788
|
}, [
|
|
20789
|
+
objectUrls,
|
|
20549
20790
|
persistHistoryItem,
|
|
20550
20791
|
processSelectedPhoto,
|
|
20551
20792
|
session,
|
|
@@ -20653,8 +20894,11 @@ function useAiTryOnSession({ historyStore = indexedDbAiTryOnHistoryStore, object
|
|
|
20653
20894
|
function waitForRemainingProcessingDuration(startedAt) {
|
|
20654
20895
|
return waitForProcessingDuration(getRemainingProcessingDuration(startedAt));
|
|
20655
20896
|
}
|
|
20656
|
-
|
|
20657
|
-
|
|
20897
|
+
const READY_ACTIVATION = {
|
|
20898
|
+
status: 'ready'
|
|
20899
|
+
};
|
|
20900
|
+
function AiTryOnRoot({ dialogPortalContainer, language, onClose, onAddToCart, processPhoto, productImageSrc, productName, productPrice, productType, productUrl, tryOnClient: providedTryOnClient, apiKey, showDialogCloseButton = false, showAddToCart = true, activation = READY_ACTIVATION, onRetryActivation }) {
|
|
20901
|
+
if (!processPhoto) assertProductType(productType);
|
|
20658
20902
|
const { i18n, t } = useTranslation();
|
|
20659
20903
|
const fileInputRef = (0, __rspack_external_react.useRef)(null);
|
|
20660
20904
|
const normalizedApiKey = normalizeApiKey(apiKey);
|
|
@@ -20682,7 +20926,22 @@ function AiTryOnRoot({ dialogPortalContainer, language, onClose, processPhoto, p
|
|
|
20682
20926
|
tryOnClient
|
|
20683
20927
|
});
|
|
20684
20928
|
const stage = session.view.stage;
|
|
20929
|
+
const closeDialog = onClose ?? session.requestClose;
|
|
20685
20930
|
const isMyFitsActive = 'result' === session.view.stage && session.view.myFitsOpen;
|
|
20931
|
+
const [cartPending, setCartPending] = (0, __rspack_external_react.useState)(false);
|
|
20932
|
+
const [cartError, setCartError] = (0, __rspack_external_react.useState)(void 0);
|
|
20933
|
+
const addToCart = (0, __rspack_external_react.useCallback)(()=>{
|
|
20934
|
+
if ('result' !== session.view.stage) return;
|
|
20935
|
+
session.view.addToCart();
|
|
20936
|
+
if (!onAddToCart) return;
|
|
20937
|
+
setCartPending(true);
|
|
20938
|
+
setCartError(void 0);
|
|
20939
|
+
Promise.resolve(onAddToCart()).catch((error)=>setCartError(error instanceof Error && error.message ? error.message : t('externalServiceUnavailable'))).finally(()=>setCartPending(false));
|
|
20940
|
+
}, [
|
|
20941
|
+
onAddToCart,
|
|
20942
|
+
session.view,
|
|
20943
|
+
t
|
|
20944
|
+
]);
|
|
20686
20945
|
function handleFileChange(event) {
|
|
20687
20946
|
const file = event.currentTarget.files?.[0];
|
|
20688
20947
|
if (file) session.selectFile(file);
|
|
@@ -20711,14 +20970,14 @@ function AiTryOnRoot({ dialogPortalContainer, language, onClose, processPhoto, p
|
|
|
20711
20970
|
"data-ai-try-on-stage": stage,
|
|
20712
20971
|
children: [
|
|
20713
20972
|
/*#__PURE__*/ jsx_runtime_jsx(TryOnHeader, {
|
|
20714
|
-
badge: 'history' === stage ? null : t(getBadgeKey(stage)),
|
|
20973
|
+
badge: 'history' === stage || 'ready' !== activation.status ? null : t(getBadgeKey(stage)),
|
|
20715
20974
|
badgeTone: getBadgeTone(stage),
|
|
20716
20975
|
closeLabel: t('close'),
|
|
20717
|
-
leftSlot: leftSlot,
|
|
20718
|
-
middleSlot: middleSlot,
|
|
20976
|
+
leftSlot: 'ready' === activation.status ? leftSlot : null,
|
|
20977
|
+
middleSlot: 'ready' === activation.status ? middleSlot : null,
|
|
20719
20978
|
preferMiddleSlotFirst: 'result' === stage,
|
|
20720
20979
|
showCloseButton: showDialogCloseButton,
|
|
20721
|
-
onClose: session.requestClose
|
|
20980
|
+
onClose: 'ready' === activation.status ? session.requestClose : closeDialog
|
|
20722
20981
|
}),
|
|
20723
20982
|
/*#__PURE__*/ jsx_runtime_jsx("input", {
|
|
20724
20983
|
ref: fileInputRef,
|
|
@@ -20729,36 +20988,56 @@ function AiTryOnRoot({ dialogPortalContainer, language, onClose, processPhoto, p
|
|
|
20729
20988
|
}),
|
|
20730
20989
|
/*#__PURE__*/ jsxs(TryOnScreenTransition, {
|
|
20731
20990
|
children: [
|
|
20732
|
-
'
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
view: session.view
|
|
20737
|
-
}) : null,
|
|
20738
|
-
'history' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(HistoryScreen, {
|
|
20739
|
-
view: session.view
|
|
20991
|
+
'loading' === activation.status ? /*#__PURE__*/ jsx_runtime_jsx(ActivationLoadingScreen, {}) : null,
|
|
20992
|
+
'unavailable' === activation.status ? /*#__PURE__*/ jsx_runtime_jsx(ActivationUnavailableScreen, {
|
|
20993
|
+
temporary: activation.temporary,
|
|
20994
|
+
onClose: closeDialog
|
|
20740
20995
|
}) : null,
|
|
20741
|
-
'
|
|
20742
|
-
|
|
20996
|
+
'error' === activation.status ? /*#__PURE__*/ jsx_runtime_jsx(ActivationErrorScreen, {
|
|
20997
|
+
onClose: closeDialog,
|
|
20998
|
+
onRetry: onRetryActivation
|
|
20743
20999
|
}) : null,
|
|
20744
|
-
'
|
|
20745
|
-
|
|
20746
|
-
|
|
20747
|
-
|
|
20748
|
-
|
|
20749
|
-
|
|
20750
|
-
|
|
20751
|
-
|
|
20752
|
-
|
|
21000
|
+
'ready' !== activation.status ? null : /*#__PURE__*/ jsxs(Fragment, {
|
|
21001
|
+
children: [
|
|
21002
|
+
'start' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(StartScreen, {
|
|
21003
|
+
view: session.view
|
|
21004
|
+
}) : null,
|
|
21005
|
+
'intro' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(IntroScreen, {
|
|
21006
|
+
view: session.view
|
|
21007
|
+
}) : null,
|
|
21008
|
+
'history' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(HistoryScreen, {
|
|
21009
|
+
view: session.view
|
|
21010
|
+
}) : null,
|
|
21011
|
+
'confirm' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(ConfirmScreen, {
|
|
21012
|
+
view: session.view
|
|
21013
|
+
}) : null,
|
|
21014
|
+
'processing' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(ProcessingScreen, {
|
|
21015
|
+
view: session.view
|
|
21016
|
+
}) : null,
|
|
21017
|
+
'error' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(ErrorScreen, {
|
|
21018
|
+
view: session.view,
|
|
21019
|
+
onClose: session.requestClose
|
|
21020
|
+
}) : null,
|
|
21021
|
+
'result' === session.view.stage ? /*#__PURE__*/ jsx_runtime_jsx(ResultScreen, {
|
|
21022
|
+
view: session.view,
|
|
21023
|
+
showAddToCart: showAddToCart,
|
|
21024
|
+
onAddToCart: onAddToCart ? addToCart : void 0,
|
|
21025
|
+
addToCartPending: cartPending,
|
|
21026
|
+
addToCartError: cartError
|
|
21027
|
+
}) : null
|
|
21028
|
+
]
|
|
21029
|
+
})
|
|
20753
21030
|
]
|
|
20754
|
-
}, stage),
|
|
21031
|
+
}, 'ready' === activation.status ? stage : `activation-${activation.status}`),
|
|
20755
21032
|
session.comparison.open && /*#__PURE__*/ jsx_runtime_jsx(ComparisonDialog, {
|
|
20756
21033
|
productName: session.comparison.productName,
|
|
20757
21034
|
productPrice: session.comparison.productPrice,
|
|
20758
21035
|
productUrl: session.comparison.productUrl,
|
|
20759
21036
|
portalContainer: dialogPortalContainer ?? void 0,
|
|
20760
21037
|
result: session.comparison.result,
|
|
20761
|
-
|
|
21038
|
+
addToCartPending: cartPending,
|
|
21039
|
+
addToCartError: cartError,
|
|
21040
|
+
onAddToCart: showAddToCart ? onAddToCart ? addToCart : session.comparison.addToCart : void 0,
|
|
20762
21041
|
onClose: session.comparison.close,
|
|
20763
21042
|
onDeleteResult: session.comparison.deleteResult,
|
|
20764
21043
|
onSaveResult: session.comparison.saveResult,
|
|
@@ -20798,8 +21077,246 @@ function getBadgeTone(stage) {
|
|
|
20798
21077
|
configureNodeApiClient({
|
|
20799
21078
|
baseURL: "https://api.neurodyn.ai/"
|
|
20800
21079
|
});
|
|
20801
|
-
|
|
20802
|
-
|
|
21080
|
+
const SHOPIFY_REQUEST_TIMEOUT_MS = 30000;
|
|
21081
|
+
const SHOPIFY_UPLOAD_TIMEOUT_MS = 300000;
|
|
21082
|
+
const SHOPPER_UPLOAD_COUNT = 1;
|
|
21083
|
+
const MAX_ERROR_BODY = 2000;
|
|
21084
|
+
class ShopifyTryOnClient {
|
|
21085
|
+
createObjectUrl;
|
|
21086
|
+
operations;
|
|
21087
|
+
signal;
|
|
21088
|
+
session = null;
|
|
21089
|
+
constructor({ createObjectUrl = shopify_try_on_client_defaultCreateObjectUrl, operations, signal }){
|
|
21090
|
+
this.createObjectUrl = createObjectUrl;
|
|
21091
|
+
this.operations = operations;
|
|
21092
|
+
this.signal = signal;
|
|
21093
|
+
}
|
|
21094
|
+
async activate(target) {
|
|
21095
|
+
const response = await this.run(()=>this.operations.activate(target, this.baseConfig()));
|
|
21096
|
+
const { activation, session } = normalizeShopifyActivation(response);
|
|
21097
|
+
if (session) this.session = createWidgetSessionClient(session, {
|
|
21098
|
+
apiConfig: this.baseConfig(),
|
|
21099
|
+
issueWidgetToken: this.operations.issueWidgetToken
|
|
21100
|
+
});
|
|
21101
|
+
return activation;
|
|
21102
|
+
}
|
|
21103
|
+
createProcessPhoto(target) {
|
|
21104
|
+
return async (photo, context)=>{
|
|
21105
|
+
context?.reportProgress(4);
|
|
21106
|
+
const source = await resolveAiTryOnSourceBlob(photo);
|
|
21107
|
+
if (!source || source.size <= 0) throw new AiTryOnGenerationError('photo-required');
|
|
21108
|
+
context?.reportProgress(18);
|
|
21109
|
+
const [upload] = resolveUploads(await this.run(async ()=>this.operations.requestUploadUrls(SHOPPER_UPLOAD_COUNT, await this.requestConfig())), SHOPPER_UPLOAD_COUNT);
|
|
21110
|
+
context?.reportProgress(38);
|
|
21111
|
+
const uploadOptions = {
|
|
21112
|
+
signal: this.signal,
|
|
21113
|
+
timeoutMs: SHOPIFY_UPLOAD_TIMEOUT_MS
|
|
21114
|
+
};
|
|
21115
|
+
await this.run(()=>this.operations.uploadPhoto ? this.operations.uploadPhoto(upload.uploadUrl, source, uploadOptions) : uploadImageToPresignedUrl(upload.uploadUrl, source, uploadOptions));
|
|
21116
|
+
context?.reportProgress(58);
|
|
21117
|
+
const stopGenerationProgress = startGenerationProgress(context?.reportProgress);
|
|
21118
|
+
let response;
|
|
21119
|
+
try {
|
|
21120
|
+
response = await this.run(async ()=>this.operations.generate({
|
|
21121
|
+
...target,
|
|
21122
|
+
personImageKey: upload.key
|
|
21123
|
+
}, await this.requestConfig({
|
|
21124
|
+
responseType: 'blob',
|
|
21125
|
+
timeout: 90000
|
|
21126
|
+
})));
|
|
21127
|
+
} finally{
|
|
21128
|
+
stopGenerationProgress();
|
|
21129
|
+
}
|
|
21130
|
+
const { blob, errorText } = await readGeneratedImage(response);
|
|
21131
|
+
if (!blob) throw toGenerationError(errorText);
|
|
21132
|
+
context?.reportProgress(98);
|
|
21133
|
+
const src = this.createObjectUrl(blob);
|
|
21134
|
+
if (!src) throw new AiTryOnGenerationError('service');
|
|
21135
|
+
return {
|
|
21136
|
+
before: photo,
|
|
21137
|
+
after: {
|
|
21138
|
+
blob,
|
|
21139
|
+
id: `${photo.id}-shopify-result`,
|
|
21140
|
+
name: photo.name ? `${photo.name} result` : 'AI try-on result',
|
|
21141
|
+
size: blob.size,
|
|
21142
|
+
src,
|
|
21143
|
+
type: blob.type || 'image/jpeg'
|
|
21144
|
+
}
|
|
21145
|
+
};
|
|
21146
|
+
};
|
|
21147
|
+
}
|
|
21148
|
+
async run(operation) {
|
|
21149
|
+
try {
|
|
21150
|
+
return await operation();
|
|
21151
|
+
} catch (error) {
|
|
21152
|
+
if (error instanceof AiTryOnGenerationError || isCanceled(error, this.signal)) throw error;
|
|
21153
|
+
throw isTimeout(error) ? new AiTryOnGenerationError('timeout') : toGenerationError(await readRejectionBody(error));
|
|
21154
|
+
}
|
|
21155
|
+
}
|
|
21156
|
+
sendWidgetEvent(event) {
|
|
21157
|
+
const send = this.operations.sendWidgetEvent;
|
|
21158
|
+
if (!send) return;
|
|
21159
|
+
this.requestConfig().then((config)=>send({
|
|
21160
|
+
event,
|
|
21161
|
+
timestamp: new Date().toISOString()
|
|
21162
|
+
}, config)).catch(()=>{});
|
|
21163
|
+
}
|
|
21164
|
+
async requestUploadUrls() {
|
|
21165
|
+
throw new Error('Shopify generation handles its own uploads');
|
|
21166
|
+
}
|
|
21167
|
+
async generateTryOn() {
|
|
21168
|
+
throw new Error('Shopify generation runs through its own processor');
|
|
21169
|
+
}
|
|
21170
|
+
baseConfig() {
|
|
21171
|
+
return {
|
|
21172
|
+
signal: this.signal,
|
|
21173
|
+
timeout: SHOPIFY_REQUEST_TIMEOUT_MS
|
|
21174
|
+
};
|
|
21175
|
+
}
|
|
21176
|
+
async requestConfig(config = {}) {
|
|
21177
|
+
const merged = {
|
|
21178
|
+
...this.baseConfig(),
|
|
21179
|
+
...config
|
|
21180
|
+
};
|
|
21181
|
+
return this.session ? this.session.getApiConfigForRequest(merged) : merged;
|
|
21182
|
+
}
|
|
21183
|
+
}
|
|
21184
|
+
function createShopifyTryOnClient(options) {
|
|
21185
|
+
return new ShopifyTryOnClient(options);
|
|
21186
|
+
}
|
|
21187
|
+
function normalizeShopifyActivation(response) {
|
|
21188
|
+
const body = shopify_try_on_client_isRecord(response) ? response : {};
|
|
21189
|
+
const zoneType = 'string' == typeof body.zoneType ? body.zoneType : void 0;
|
|
21190
|
+
const photoUrl = shopify_try_on_client_normalizeString(body.photoUrl) || void 0;
|
|
21191
|
+
const session = normalizeWidgetSession(body.widgetSession);
|
|
21192
|
+
const hasSource = void 0 !== photoUrl;
|
|
21193
|
+
const available = true === body.available && null !== session && hasSource;
|
|
21194
|
+
const reason = available ? void 0 : readReason(body.unavailableReason) ?? (true !== body.available || hasSource ? void 0 : 'no_product_photo');
|
|
21195
|
+
return {
|
|
21196
|
+
activation: {
|
|
21197
|
+
available,
|
|
21198
|
+
photoUrl,
|
|
21199
|
+
reason,
|
|
21200
|
+
zoneType: isProductType(zoneType) ? zoneType : void 0
|
|
21201
|
+
},
|
|
21202
|
+
session: available ? session : null
|
|
21203
|
+
};
|
|
21204
|
+
}
|
|
21205
|
+
const UNAVAILABLE_REASONS = new Set([
|
|
21206
|
+
'not_enabled',
|
|
21207
|
+
'zone_not_configured',
|
|
21208
|
+
'no_product_photo',
|
|
21209
|
+
'tokens_exhausted'
|
|
21210
|
+
]);
|
|
21211
|
+
function readReason(value) {
|
|
21212
|
+
return 'string' == typeof value && UNAVAILABLE_REASONS.has(value) ? value : void 0;
|
|
21213
|
+
}
|
|
21214
|
+
function toGenerationError(errorText) {
|
|
21215
|
+
if (!errorText) return new AiTryOnGenerationError('service');
|
|
21216
|
+
try {
|
|
21217
|
+
const body = JSON.parse(errorText);
|
|
21218
|
+
const code = shopify_try_on_client_isRecord(body) ? body.code : void 0;
|
|
21219
|
+
if ('tokens' === code || 'product' === code || 'timeout' === code || 'service' === code) return new AiTryOnGenerationError(code);
|
|
21220
|
+
} catch {}
|
|
21221
|
+
return new AiTryOnGenerationError('service');
|
|
21222
|
+
}
|
|
21223
|
+
function normalizeWidgetSession(value) {
|
|
21224
|
+
if (!shopify_try_on_client_isRecord(value)) return null;
|
|
21225
|
+
const token = shopify_try_on_client_normalizeString(value.token);
|
|
21226
|
+
const sid = shopify_try_on_client_normalizeString(value.sid);
|
|
21227
|
+
const expiresIn = 'number' == typeof value.expiresIn ? value.expiresIn : NaN;
|
|
21228
|
+
return token && sid && Number.isFinite(expiresIn) && expiresIn > 0 ? {
|
|
21229
|
+
expiresIn,
|
|
21230
|
+
sid,
|
|
21231
|
+
token
|
|
21232
|
+
} : null;
|
|
21233
|
+
}
|
|
21234
|
+
function isCanceled(error, signal) {
|
|
21235
|
+
return signal?.aborted === true || 'AbortError' === errorName(error) || 'ERR_CANCELED' === shopify_try_on_client_errorCode(error);
|
|
21236
|
+
}
|
|
21237
|
+
function isTimeout(error) {
|
|
21238
|
+
return 'TimeoutError' === errorName(error) || 'ECONNABORTED' === shopify_try_on_client_errorCode(error) || 'ETIMEDOUT' === shopify_try_on_client_errorCode(error);
|
|
21239
|
+
}
|
|
21240
|
+
function errorName(error) {
|
|
21241
|
+
return shopify_try_on_client_isRecord(error) && 'string' == typeof error.name ? error.name : '';
|
|
21242
|
+
}
|
|
21243
|
+
function shopify_try_on_client_errorCode(error) {
|
|
21244
|
+
return shopify_try_on_client_isRecord(error) && 'string' == typeof error.code ? error.code : '';
|
|
21245
|
+
}
|
|
21246
|
+
async function readRejectionBody(error) {
|
|
21247
|
+
const response = shopify_try_on_client_isRecord(error) ? error.response : void 0;
|
|
21248
|
+
const data = shopify_try_on_client_isRecord(response) ? response.data : void 0;
|
|
21249
|
+
if (data instanceof Blob) return (await data.text().catch(()=>'')).slice(0, MAX_ERROR_BODY) || null;
|
|
21250
|
+
if ('string' == typeof data) return data.slice(0, MAX_ERROR_BODY) || null;
|
|
21251
|
+
if (shopify_try_on_client_isRecord(data)) return JSON.stringify(data).slice(0, MAX_ERROR_BODY);
|
|
21252
|
+
return null;
|
|
21253
|
+
}
|
|
21254
|
+
function shopify_try_on_client_isRecord(value) {
|
|
21255
|
+
return null !== value && 'object' == typeof value;
|
|
21256
|
+
}
|
|
21257
|
+
function shopify_try_on_client_normalizeString(value) {
|
|
21258
|
+
return 'string' == typeof value ? value.trim() : '';
|
|
21259
|
+
}
|
|
21260
|
+
function shopify_try_on_client_defaultCreateObjectUrl(blob) {
|
|
21261
|
+
return 'function' == typeof URL.createObjectURL ? URL.createObjectURL(blob) : '';
|
|
21262
|
+
}
|
|
21263
|
+
const SHOPIFY_PRODUCT_TYPE = 'ai-try-on-shopify';
|
|
21264
|
+
function createProxyRequest(baseURL) {
|
|
21265
|
+
const instance = axios.create({
|
|
21266
|
+
baseURL,
|
|
21267
|
+
timeout: SHOPIFY_REQUEST_TIMEOUT_MS
|
|
21268
|
+
});
|
|
21269
|
+
return async function(config) {
|
|
21270
|
+
const response = await instance.request(config);
|
|
21271
|
+
return {
|
|
21272
|
+
data: response.data,
|
|
21273
|
+
headers: response.headers,
|
|
21274
|
+
status: response.status,
|
|
21275
|
+
statusText: response.statusText
|
|
21276
|
+
};
|
|
21277
|
+
};
|
|
21278
|
+
}
|
|
21279
|
+
function createAppProxyOperations(basePath) {
|
|
21280
|
+
const mount = basePath.trim().replace(/\/+$/, '');
|
|
21281
|
+
if (!mount) return;
|
|
21282
|
+
const client = createProxyRequest(mount);
|
|
21283
|
+
return {
|
|
21284
|
+
activate: ({ productId, variantId }, config)=>tryOnControllerActivateTryOn({
|
|
21285
|
+
product_id: productId,
|
|
21286
|
+
variant_id: variantId,
|
|
21287
|
+
productType: SHOPIFY_PRODUCT_TYPE
|
|
21288
|
+
}, {
|
|
21289
|
+
...config,
|
|
21290
|
+
client
|
|
21291
|
+
}),
|
|
21292
|
+
generate: (data, config)=>tryOnControllerGenerateShopifyTryOn(data, {
|
|
21293
|
+
...config,
|
|
21294
|
+
client
|
|
21295
|
+
}),
|
|
21296
|
+
issueWidgetToken: (data, config)=>publicApiControllerIssueWidgetToken(data, {
|
|
21297
|
+
...config,
|
|
21298
|
+
client
|
|
21299
|
+
}),
|
|
21300
|
+
requestUploadUrls: (count, config)=>tryOnControllerCreateUploadUrls({
|
|
21301
|
+
count
|
|
21302
|
+
}, {
|
|
21303
|
+
...config,
|
|
21304
|
+
client
|
|
21305
|
+
}),
|
|
21306
|
+
sendWidgetEvent: (data, config)=>widgetEventsControllerCreateWidgetEvent(data, {
|
|
21307
|
+
...config,
|
|
21308
|
+
client
|
|
21309
|
+
})
|
|
21310
|
+
};
|
|
21311
|
+
}
|
|
21312
|
+
const LOADING_ACTIVATION = {
|
|
21313
|
+
status: 'loading'
|
|
21314
|
+
};
|
|
21315
|
+
const src_READY_ACTIVATION = {
|
|
21316
|
+
status: 'ready'
|
|
21317
|
+
};
|
|
21318
|
+
function AiTryOnDialog({ defaultOpen = false, language, onOpenChange, open, productImageSrc, productName, productPrice, productType, productUrl, apiKey, externalGeneration, externalActivation, externalAddToCart, externalClient, ...props }) {
|
|
21319
|
+
if (!externalGeneration) assertProductType(productType);
|
|
20803
21320
|
const i18n = (0, __rspack_external_react.useMemo)(()=>createAiTryOnI18n(language), [
|
|
20804
21321
|
language
|
|
20805
21322
|
]);
|
|
@@ -20809,20 +21326,58 @@ function AiTryOnDialog({ defaultOpen = false, language, onOpenChange, open, prod
|
|
|
20809
21326
|
const isControlled = void 0 !== open;
|
|
20810
21327
|
const currentOpen = isControlled ? open : internalOpen;
|
|
20811
21328
|
const normalizedApiKey = normalizeApiKey(apiKey);
|
|
20812
|
-
const tryOnClient = (0, __rspack_external_react.useMemo)(()=>createTryOnClient({
|
|
21329
|
+
const tryOnClient = (0, __rspack_external_react.useMemo)(()=>externalGeneration ? externalClient ?? externalTryOnClient : createTryOnClient({
|
|
20813
21330
|
apiKey: normalizedApiKey
|
|
20814
21331
|
}), [
|
|
20815
|
-
normalizedApiKey
|
|
21332
|
+
normalizedApiKey,
|
|
21333
|
+
externalGeneration,
|
|
21334
|
+
externalClient
|
|
21335
|
+
]);
|
|
21336
|
+
const [externalActivationState, setExternalActivationState] = (0, __rspack_external_react.useState)(LOADING_ACTIVATION);
|
|
21337
|
+
const [activationAttempt, setActivationAttempt] = (0, __rspack_external_react.useState)(0);
|
|
21338
|
+
const activation = externalActivation ? externalActivationState : src_READY_ACTIVATION;
|
|
21339
|
+
const activationRef = (0, __rspack_external_react.useRef)(externalActivation);
|
|
21340
|
+
const hasActivation = Boolean(externalActivation);
|
|
21341
|
+
(0, __rspack_external_react.useEffect)(()=>{
|
|
21342
|
+
activationRef.current = externalActivation;
|
|
21343
|
+
});
|
|
21344
|
+
(0, __rspack_external_react.useEffect)(()=>{
|
|
21345
|
+
const activate = activationRef.current;
|
|
21346
|
+
if (!activate) return;
|
|
21347
|
+
setExternalActivationState(LOADING_ACTIVATION);
|
|
21348
|
+
if (!currentOpen) return;
|
|
21349
|
+
let cancelled = false;
|
|
21350
|
+
activate().then((result)=>{
|
|
21351
|
+
if (!cancelled) setExternalActivationState(result.enabled ? {
|
|
21352
|
+
...result,
|
|
21353
|
+
status: 'ready'
|
|
21354
|
+
} : {
|
|
21355
|
+
status: 'unavailable',
|
|
21356
|
+
temporary: result.temporarilyUnavailable
|
|
21357
|
+
});
|
|
21358
|
+
}).catch(()=>{
|
|
21359
|
+
if (!cancelled) setExternalActivationState({
|
|
21360
|
+
status: 'error'
|
|
21361
|
+
});
|
|
21362
|
+
});
|
|
21363
|
+
return ()=>{
|
|
21364
|
+
cancelled = true;
|
|
21365
|
+
};
|
|
21366
|
+
}, [
|
|
21367
|
+
activationAttempt,
|
|
21368
|
+
currentOpen,
|
|
21369
|
+
hasActivation
|
|
20816
21370
|
]);
|
|
20817
21371
|
(0, __rspack_external_react.useEffect)(()=>{
|
|
20818
21372
|
if (!currentOpen) {
|
|
20819
21373
|
hasTrackedOpen.current = false;
|
|
20820
21374
|
return;
|
|
20821
21375
|
}
|
|
20822
|
-
if (hasTrackedOpen.current) return;
|
|
21376
|
+
if ('ready' !== activation.status || hasTrackedOpen.current) return;
|
|
20823
21377
|
hasTrackedOpen.current = true;
|
|
20824
21378
|
tryOnClient.sendWidgetEvent('widget_opened');
|
|
20825
21379
|
}, [
|
|
21380
|
+
activation.status,
|
|
20826
21381
|
currentOpen,
|
|
20827
21382
|
tryOnClient
|
|
20828
21383
|
]);
|
|
@@ -20841,6 +21396,9 @@ function AiTryOnDialog({ defaultOpen = false, language, onOpenChange, open, prod
|
|
|
20841
21396
|
zIndex: 2147483647
|
|
20842
21397
|
},
|
|
20843
21398
|
children: [
|
|
21399
|
+
/*#__PURE__*/ jsx_runtime_jsx("style", {
|
|
21400
|
+
children: SHADOW_HOST_VISIBILITY_CSS
|
|
21401
|
+
}),
|
|
20844
21402
|
/*#__PURE__*/ jsx_runtime_jsx("style", {
|
|
20845
21403
|
children: shadowRootCssText
|
|
20846
21404
|
}),
|
|
@@ -20863,6 +21421,10 @@ function AiTryOnDialog({ defaultOpen = false, language, onOpenChange, open, prod
|
|
|
20863
21421
|
productType: productType,
|
|
20864
21422
|
productUrl: productUrl,
|
|
20865
21423
|
tryOnClient: tryOnClient,
|
|
21424
|
+
externalGeneration: externalGeneration,
|
|
21425
|
+
externalAddToCart: externalAddToCart,
|
|
21426
|
+
activation: activation,
|
|
21427
|
+
onRetryActivation: ()=>setActivationAttempt((attempt)=>attempt + 1),
|
|
20866
21428
|
onRequestClose: ()=>handleOpenChange(false),
|
|
20867
21429
|
onOpenChange: handleOpenChange,
|
|
20868
21430
|
...props
|
|
@@ -20874,7 +21436,7 @@ function AiTryOnDialog({ defaultOpen = false, language, onOpenChange, open, prod
|
|
|
20874
21436
|
]
|
|
20875
21437
|
});
|
|
20876
21438
|
}
|
|
20877
|
-
function AiTryOnDialogContent({ language, onRequestClose, portalContainer, productImageSrc, productName, productPrice, productType, productUrl, tryOnClient, ...props }) {
|
|
21439
|
+
function AiTryOnDialogContent({ language, onRequestClose, portalContainer, productImageSrc, productName, productPrice, productType, productUrl, tryOnClient, externalGeneration, externalAddToCart, activation, onRetryActivation, ...props }) {
|
|
20878
21440
|
const { t } = useTranslation();
|
|
20879
21441
|
return /*#__PURE__*/ jsx_runtime_jsx(Dialog, {
|
|
20880
21442
|
...props,
|
|
@@ -20901,12 +21463,17 @@ function AiTryOnDialogContent({ language, onRequestClose, portalContainer, produ
|
|
|
20901
21463
|
/*#__PURE__*/ jsx_runtime_jsx(AiTryOnRoot, {
|
|
20902
21464
|
dialogPortalContainer: portalContainer,
|
|
20903
21465
|
language: language,
|
|
20904
|
-
productImageSrc: productImageSrc,
|
|
21466
|
+
productImageSrc: 'ready' === activation.status && activation.productImageSrc || productImageSrc,
|
|
20905
21467
|
productName: productName,
|
|
20906
21468
|
productPrice: productPrice,
|
|
20907
|
-
productType: productType,
|
|
21469
|
+
productType: 'ready' === activation.status ? activation.productType ?? productType : productType,
|
|
20908
21470
|
productUrl: productUrl,
|
|
20909
21471
|
tryOnClient: tryOnClient,
|
|
21472
|
+
processPhoto: externalGeneration,
|
|
21473
|
+
activation: activation,
|
|
21474
|
+
onRetryActivation: onRetryActivation,
|
|
21475
|
+
onAddToCart: externalAddToCart,
|
|
21476
|
+
showAddToCart: !externalGeneration || Boolean(externalAddToCart),
|
|
20910
21477
|
showDialogCloseButton: true,
|
|
20911
21478
|
onClose: onRequestClose
|
|
20912
21479
|
})
|
|
@@ -20914,4 +21481,4 @@ function AiTryOnDialogContent({ language, onRequestClose, portalContainer, produ
|
|
|
20914
21481
|
})
|
|
20915
21482
|
});
|
|
20916
21483
|
}
|
|
20917
|
-
export { AiTryOnDialog, PRODUCT_TYPES, isProductType };
|
|
21484
|
+
export { AiTryOnDialog, AiTryOnGenerationError, PRODUCT_TYPES, SHOPIFY_REQUEST_TIMEOUT_MS, createAppProxyOperations, createShopifyTryOnClient, isProductType, uploadImageToPresignedUrl };
|