1(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([typeof document === "object" ? document.currentScript : undefined, 2488294, ((__turbopack_context__) => { 3"use strict"; 4 5var __TURBOPACK__imported__module__843476__ = __turbopack_context__.i(843476); 6var __TURBOPACK__imported__module__271645__ = __turbopack_context__.i(271645); 7var __TURBOPACK__imported__module__522016__ = __turbopack_context__.i(522016); 8var __TURBOPACK__imported__module__618566__ = __turbopack_context__.i(618566); 9var __TURBOPACK__imported__module__33477__ = __turbopack_context__.i(33477); 10var __TURBOPACK__imported__module__956495__ = __turbopack_context__.i(956495); 11var __TURBOPACK__imported__module__631465__ = __turbopack_context__.i(631465); 12var __TURBOPACK__imported__module__685008__ = __turbopack_context__.i(685008); 13var __TURBOPACK__imported__module__490746__ = __turbopack_context__.i(490746); 14var __TURBOPACK__imported__module__977896__ = __turbopack_context__.i(977896); 15var __TURBOPACK__imported__module__372790__ = __turbopack_context__.i(372790); 16var __TURBOPACK__imported__module__484973__ = __turbopack_context__.i(484973); 17var __TURBOPACK__imported__module__475503__ = __turbopack_context__.i(475503); 18var __TURBOPACK__imported__module__445299__ = __turbopack_context__.i(445299); 19var __TURBOPACK__imported__module__233769__ = __turbopack_context__.i(233769); 20var __TURBOPACK__imported__module__110035__ = __turbopack_context__.i(110035); 21var __TURBOPACK__imported__module__987030__ = __turbopack_context__.i(987030); 22var __TURBOPACK__imported__module__262524__ = __turbopack_context__.i(262524); 23var __TURBOPACK__imported__module__531278__ = __turbopack_context__.i(531278); 24var __TURBOPACK__imported__module__555436__ = __turbopack_context__.i(555436); 25var __TURBOPACK__imported__module__473708__ = __turbopack_context__.i(473708); 26var __TURBOPACK__imported__module__727612__ = __turbopack_context__.i(727612); 27var __TURBOPACK__imported__module__928441__ = __turbopack_context__.i(928441); 28var __TURBOPACK__imported__module__4820__ = __turbopack_context__.i(4820); 29var __TURBOPACK__imported__module__533874__ = __turbopack_context__.i(533874); 30var __TURBOPACK__imported__module__445546__ = __turbopack_context__.i(445546); 31var __TURBOPACK__imported__module__406911__ = __turbopack_context__.i(406911); 32var __TURBOPACK__imported__module__488166__ = __turbopack_context__.i(488166); 33"use client"; 34; 35; 36; 37; 38; 39; 40; 41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57const logger = (0, __TURBOPACK__imported__module__488166__["createLogger"])("sales"); 58const UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/; 59const MAX_LIST_PAGE_SIZE = 100; 60function ChannelOfferForm({ channelId: lockedChannelId, offerId, mode }) { 61 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 62 const router = (0, __TURBOPACK__imported__module__618566__["useRouter"])(); 63 const [initialValues, setInitialValues] = __TURBOPACK__imported__module__271645__["useState"](mode === "create" ? { 64 channelId: lockedChannelId ?? null, 65 productId: null, 66 title: "", 67 description: "", 68 defaultMediaId: null, 69 isActive: true, 70 priceOverrides: [] 71 } : null); 72 const [loading, setLoading] = __TURBOPACK__imported__module__271645__["useState"](mode === "edit"); 73 const [error, setError] = __TURBOPACK__imported__module__271645__["useState"](null); 74 const [isNotFound, setIsNotFound] = __TURBOPACK__imported__module__271645__["useState"](false); 75 const [priceKinds, setPriceKinds] = __TURBOPACK__imported__module__271645__["useState"]([]); 76 const [mediaOptions, setMediaOptions] = __TURBOPACK__imported__module__271645__["useState"]([]); 77 const attachmentCache = __TURBOPACK__imported__module__271645__["useRef"](/* @__PURE__ */ new Map()); 78 const productCache = __TURBOPACK__imported__module__271645__["useRef"](/* @__PURE__ */ new Map()); 79 const [productSummary, setProductSummary] = __TURBOPACK__imported__module__271645__["useState"](null); 80 const [variantPreviews, setVariantPreviews] = __TURBOPACK__imported__module__271645__["useState"]([]); 81 const variantCache = __TURBOPACK__imported__module__271645__["useRef"](/* @__PURE__ */ new Map()); 82 const variantMediaCache = __TURBOPACK__imported__module__271645__["useRef"](/* @__PURE__ */ new Map()); 83 const [selectedChannelId, setSelectedChannelId] = __TURBOPACK__imported__module__271645__["useState"](lockedChannelId ?? null); 84 const manualMediaSelections = __TURBOPACK__imported__module__271645__["useRef"](/* @__PURE__ */ new Set()); 85 const initialPriceVersionsRef = __TURBOPACK__imported__module__271645__["useRef"](/* @__PURE__ */ new Map()); 86 const [currentProductId, setCurrentProductId] = __TURBOPACK__imported__module__271645__["useState"](null); 87 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 88 if (initialValues) { 89 initialPriceVersionsRef.current = collectPriceVersions(initialValues.priceOverrides); 90 } else { 91 initialPriceVersionsRef.current = /* @__PURE__ */ new Map(); 92 } 93 }, [ 94 initialValues 95 ]); 96 const channelOffersHref = __TURBOPACK__imported__module__271645__["useMemo"](()=>buildChannelOffersHref(lockedChannelId), [
97 lockedChannelId 98 ]); 99 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 100 if (lockedChannelId) { 101 setSelectedChannelId(lockedChannelId); 102 } else if (initialValues?.channelId) { 103 setSelectedChannelId(initialValues.channelId); 104 } 105 }, [ 106 initialValues?.channelId, 107 lockedChannelId 108 ]); 109 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 110 if (typeof initialValues?.productId === "string") { 111 setCurrentProductId(initialValues.productId); 112 } 113 }, [ 114 initialValues?.productId 115 ]); 116 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 117 if (typeof initialValues?.productId === "string" && initialValues?.defaultMediaId === null) { 118 manualMediaSelections.current.add(initialValues.productId); 119 } 120 }, [ 121 initialValues?.defaultMediaId, 122 initialValues?.productId 123 ]); 124 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 125 if (mode !== "edit") return; 126 const productId = typeof initialValues?.productId === "string" ? initialValues.productId : null; 127 if (!productId) return; 128 const resolvedProductId = productId; 129 const hydrationChannelId = selectedChannelId ?? lockedChannelId ?? (typeof initialValues?.channelId === "string" ? initialValues.channelId : null); 130 let cancelled = false; 131 async function hydrateExistingProduct() { 132 try { 133 const [summary, attachments, variants] = await Promise.all([ 134 resolveProductSummaryWithCache({ 135 productId: resolvedProductId, 136 channelId: hydrationChannelId ?? null, 137 productCache 138 }), 139 resolveProductMediaOptionsWithCache({ 140 productId: resolvedProductId, 141 attachmentCache 142 }), 143 resolveVariantPreviewsWithCache({ 144 productId: resolvedProductId, 145 variantCache, 146 variantMediaCache 147 }) 148 ]); 149 if (!cancelled) { 150 setProductSummary(summary ?? null); 151 const mergedMedia = buildMediaOptionsFromSources({ 152 attachments, 153 variants, 154 summary 155 }); 156 attachmentCache.current.set(resolvedProductId, mergedMedia); 157 setMediaOptions(mergedMedia); 158 setVariantPreviews(variants); 159 } 160 } catch (err) { 161 logger.error("sales.channels.offer.initialHydrate", { 162 err 163 }); 164 } 165 } 166 void hydrateExistingProduct(); 167 return ()=>{ 168 cancelled = true; 169 }; 170 }, [ 171 attachmentCache, 172 initialValues?.channelId, 173 initialValues?.productId, 174 lockedChannelId, 175 mode, 176 productCache, 177 selectedChannelId, 178 setMediaOptions, 179 setProductSummary, 180 setVariantPreviews, 181 variantCache, 182 variantMediaCache 183 ]); 184 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 185 async function loadKinds() { 186 const mapItems = (items)=>items.map((item)=>{ 187 const displayMode = item.displayMode === "including-tax" || item.display_mode === "including-tax" ? "including-tax" : "excluding-tax"; 188 return { 189 id: typeof item.id === "string" ? item.id : "", 190 code: typeof item.code === "string" ? item.code : null, 191 title: typeof item.title === "string" ? item.title : null, 192 currencyCode: typeof item.currencyCode === "string" ? item.currencyCode : typeof item.currency_code === "string" ? item.currency_code : null, 193 displayMode 194 }; 195 }); 196 const endpoints = [ 197 `/api/sales/price-kinds?pageSize=${MAX_LIST_PAGE_SIZE}`, 198 `/api/catalog/price-kinds?pageSize=${MAX_LIST_PAGE_SIZE}` 199 ]; 200 try { 201 for (const endpoint of endpoints){ 202 try { 203 const payload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(endpoint, void 0, { 204 fallback: { 205 items: [] 206 } 207 }); 208 const items = Array.isArray(payload.items) ? payload.items : []; 209 setPriceKinds(mapItems(items)); 210 return; 211 } catch (err) { 212 logger.error("sales.channels.price-kinds.fetch", { 213 endpoint, 214 err 215 }); 216 } 217 } 218 setPriceKinds([]); 219 } catch (err) { 220 logger.error("catalog.price-kinds.list", { 221 err 222 }); 223 } 224 } 225 void loadKinds(); 226 }, []); 227 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 228 if (mode !== "edit" || !offerId) return; 229 const offerKey = offerId; 230 let cancelled = false;
231 async function loadOffer() { 232 setLoading(true); 233 setError(null); 234 setIsNotFound(false); 235 try { 236 const payload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(`/api/catalog/offers?id=${encodeURIComponent(offerKey)}&pageSize=1`, void 0, { 237 errorMessage: t("sales.channels.offers.errors.loadOffer", "Failed to load offer.") 238 }); 239 const offer = Array.isArray(payload.items) ? payload.items[0] : null; 240 if (!offer) { 241 if (!cancelled) setIsNotFound(true); 242 return; 243 } 244 const values = mapOfferToFormValues(offer, lockedChannelId); 245 const pricePayload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(`/api/catalog/prices?offerId=${encodeURIComponent(offer.id)}&pageSize=${MAX_LIST_PAGE_SIZE}`, void 0, { 246 fallback: { 247 items: [] 248 } 249 }); 250 const priceItems = Array.isArray(pricePayload.items) ? pricePayload.items : []; 251 values.priceOverrides = priceItems.map(mapPriceRow); 252 let preloadedMedia = []; 253 let preloadedVariants = []; 254 let preloadedSummary = null; 255 const productId = typeof values.productId === "string" ? values.productId : null; 256 if (productId) { 257 try { 258 const hydrationChannelId = selectedChannelId ?? lockedChannelId ?? (typeof values.channelId === "string" ? values.channelId : null); 259 const [summary, attachments, variants] = await Promise.all([ 260 resolveProductSummaryWithCache({ 261 productId, 262 channelId: hydrationChannelId ?? null, 263 productCache 264 }), 265 loadProductMedia(productId), 266 resolveVariantPreviewsWithCache({ 267 productId, 268 variantCache, 269 variantMediaCache 270 }) 271 ]); 272 preloadedSummary = summary ?? null; 273 preloadedVariants = variants; 274 preloadedMedia = buildMediaOptionsFromSources({ 275 attachments, 276 variants, 277 summary 278 }); 279 attachmentCache.current.set(productId, preloadedMedia); 280 } catch (err) { 281 logger.error("sales.channels.offer.media.preload", { 282 err 283 }); 284 } 285 } 286 if (!cancelled) { 287 setInitialValues(values); 288 setProductSummary(preloadedSummary); 289 setVariantPreviews(preloadedVariants); 290 setMediaOptions(preloadedMedia); 291 } 292 } catch (err) { 293 logger.error("sales.channels.offer.load", { 294 err 295 }); 296 if (!cancelled) setError(t("sales.channels.offers.errors.loadOffer", "Failed to load offer.")); 297 } finally{ 298 if (!cancelled) setLoading(false); 299 } 300 } 301 void loadOffer(); 302 return ()=>{ 303 cancelled = true; 304 }; 305 }, [ 306 attachmentCache, 307 lockedChannelId, 308 mode, 309 offerId, 310 productCache, 311 selectedChannelId, 312 setMediaOptions, 313 setProductSummary, 314 setVariantPreviews, 315 t, 316 variantCache, 317 variantMediaCache 318 ]); 319 const fields = __TURBOPACK__imported__module__271645__["useMemo"](()=>[ 320 { 321 id: "channelId", 322 label: t("sales.channels.offers.form.channel", "Channel"), 323 type: "custom", 324 required: true, 325 component: ({ value, setValue })=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(ChannelSelectInput, {
326 value: value ?? lockedChannelId ?? null, 327 onChange: (next)=>{ 328 setValue(next ?? null); 329 setSelectedChannelId(next ?? null); 330 }, 331 disabled: !!lockedChannelId, 332 showDetailsLink: true 333 }) 334 }, 335 { 336 id: "productId", 337 label: t("sales.channels.offers.form.product", "Product"), 338 type: "custom", 339 required: true, 340 component: ({ value, setValue })=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(ProductSelectInput, { 341 value: value ?? null, 342 onChange: (next)=>setValue(next), 343 channelId: selectedChannelId, 344 currentOfferId: offerId ?? null 345 }) 346 }, 347 { 348 id: "defaultMediaId", 349 label: t("sales.channels.offers.form.defaultMedia", "Default media"), 350 type: "custom", 351 component: ({ value, setValue })=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(DefaultMediaSelect, { 352 value: value ?? null, 353 onChange: (next)=>{ 354 setValue(next); 355 if (!currentProductId) return; 356 if (next === null || next === void 0) { 357 manualMediaSelections.current.add(currentProductId); 358 } else { 359 manualMediaSelections.current.delete(currentProductId); 360 } 361 }, 362 options: mediaOptions, 363 productThumbnail: productSummary?.defaultMediaUrl ?? null, 364 hasProduct: Boolean(productSummary), 365 productDefaultMediaId: productSummary?.defaultMediaId ?? null 366 }) 367 }, 368 { 369 id: "title", 370 label: t("sales.channels.offers.form.title", "Title"), 371 type: "text", 372 required: true 373 }, 374 { 375 id: "description", 376 label: t("sales.channels.offers.form.description", "Description"), 377 type: "textarea" 378 }, 379 { 380 id: "isActive", 381 label: t("sales.channels.offers.form.active", "Active"), 382 type: "checkbox" 383 } 384 ], [ 385 lockedChannelId, 386 mediaOptions, 387 productSummary, 388 selectedChannelId, 389 t, 390 currentProductId 391 ]); 392 const handleOverrideRemove = __TURBOPACK__imported__module__271645__["useCallback"](async (draft)=>{ 393 const priceId = typeof draft?.priceId === "string" ? draft.priceId : null; 394 if (!priceId) return true; 395 if (mode !== "edit") return true; 396 try { 397 await (0, __TURBOPACK__imported__module__490746__["withScopedApiRequestHeaders"])((0, __TURBOPACK__imported__module__977896__["buildOptimisticLockHeader"])(draft.updatedAt), ()=>(0, __TURBOPACK__imported__module__631465__["deleteCrud"])("catalog/prices", priceId, { 398 errorMessage: t("sales.channels.offers.errors.removePrice", "Failed to remove price override.") 399 })); 400 initialPriceVersionsRef.current.delete(priceId); 401 return true; 402 } catch (err) { 403 if ((0, __TURBOPACK__imported__module__372790__["surfaceRecordConflict"])(err, t)) return false; 404 logger.error("sales.channels.pricing.remove", { 405 err 406 }); 407 (0, __TURBOPACK__imported__module__484973__["flash"])(t("sales.channels.offers.errors.removePrice", "Failed to remove price override."), "error"); 408 return false; 409 } 410 }, [ 411 mode, 412 t 413 ]); 414 const groups = __TURBOPACK__imported__module__271645__["useMemo"](()=>[ 415 { 416 id: "associations", 417 column: 1, 418 title: t("sales.channels.offers.form.groups.associations", "Associations"), 419 fields: [ 420 "channelId" 421 ] 422 }, 423 { 424 id: "product", 425 column: 1, 426 title: t("sales.channels.offers.form.productGroup", "Product"), 427 description: t("sales.channels.offers.form.productGroupHelp", "Search the catalog and pick the product you want to customize for this channel."), 428 fields: [ 429 "productId" 430 ] 431 }, 432 { 433 id: "productSummary", 434 column: 2, 435 title: t("sales.channels.offers.form.productSummaryTitle", "Product summary"), 436 component: ()=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(ProductOverviewCard, { 437 summary: productSummary, 438 variants: variantPreviews 439 }) 440 }, 441 { 442 id: "media", 443 column: 1, 444 title: t("sales.channels.offers.form.mediaGroupTitle", "Default media override"), 445 fields: [ 446 "defaultMediaId" 447 ] 448 }, 449 { 450 id: "content", 451 column: 1, 452 title: t("sales.channels.offers.form.groups.content", "Content"), 453 fields: [ 454 "title", 455 "description", 456 "isActive" 457 ] 458 }, 459 { 460 id: "pricing", 461 column: 1, 462 title: t("sales.channels.offers.form.groups.pricing", "Price overrides"), 463 component: ({ values, setValue })=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(PriceOverridesEditor, { 464 values: Array.isArray(values.priceOverrides) ? values.priceOverrides : [], 465 onChange: (next)=>setValue("priceOverrides", next), 466 priceKinds,
467 basePrice: productSummary?.pricing ?? null, 468 onRemoveDraft: handleOverrideRemove 469 }) 470 }, 471 { 472 id: "customFields", 473 column: 2, 474 title: t("entities.customFields.title", "Custom attributes"), 475 kind: "customFields" 476 }, 477 { 478 id: "watchers", 479 column: 1, 480 bare: true, 481 component: ({ values, setValue, errors })=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(OfferFormWatchers, { 482 values, 483 setValue, 484 errors, 485 productCache, 486 attachmentCache, 487 setMediaOptions, 488 setProductSummary, 489 setVariantPreviews, 490 variantCache, 491 variantMediaCache, 492 channelId: selectedChannelId, 493 manualMediaSelections, 494 setCurrentProductId 495 }) 496 } 497 ], [ 498 attachmentCache, 499 handleOverrideRemove, 500 manualMediaSelections, 501 priceKinds, 502 productCache, 503 productSummary, 504 selectedChannelId, 505 setMediaOptions, 506 setCurrentProductId, 507 t, 508 variantPreviews 509 ]); 510 const handleSubmit = __TURBOPACK__imported__module__271645__["useCallback"](async (values)=>{ 511 const channelId = typeof values.channelId === "string" && values.channelId.length ? values.channelId : selectedChannelId ?? lockedChannelId; 512 const productId = typeof values.productId === "string" ? values.productId : null; 513 if (!channelId || !productId) { 514 throw new Error(t("sales.channels.offers.errors.requiredFields", "Choose a channel and product.")); 515 } 516 const resolvedDefaultMediaId = typeof values.defaultMediaId === "string" && values.defaultMediaId.trim().length ? values.defaultMediaId : values.defaultMediaId === null ? null : void 0; 517 const basePayload = { 518 channelId, 519 productId, 520 title: values.title?.trim() || void 0, 521 description: values.description?.trim() || void 0, 522 isActive: values.isActive !== false 523 }; 524 if (resolvedDefaultMediaId !== void 0) { 525 basePayload.defaultMediaId = resolvedDefaultMediaId; 526 } 527 const attachmentLookup = attachmentCache.current.get(productId) ?? []; 528 const mediaMap = new Map(attachmentLookup.map((entry)=>[ 529 entry.id, 530 entry.fileName 531 ])); 532 if (typeof resolvedDefaultMediaId === "string" && mediaMap.has(resolvedDefaultMediaId)) { 533 const fileName = mediaMap.get(resolvedDefaultMediaId) ?? null; 534 basePayload.defaultMediaUrl = (0, __TURBOPACK__imported__module__445546__["buildAttachmentImageUrl"])(resolvedDefaultMediaId, { 535 slug: (0, __TURBOPACK__imported__module__445546__["slugifyAttachmentFileName"])(fileName) 536 }); 537 } else if (resolvedDefaultMediaId === null) { 538 basePayload.defaultMediaUrl = null; 539 } 540 const customFields = (0, __TURBOPACK__imported__module__956495__["collectCustomFieldValues"])(values); 541 if (Object.keys(customFields).length) basePayload.customFields = customFields; 542 const overrides = Array.isArray(values.priceOverrides) ? values.priceOverrides : []; 543 const priceWithoutKind = overrides.find((entry)=>{ 544 const amount = typeof entry.amount === "string" ? entry.amount.trim() : entry.amount; 545 const hasAmount = typeof amount === "string" ? amount.length > 0 : amount !== void 0 && amount !== null; 546 const hasExistingPrice = typeof entry.priceId === "string" && entry.priceId.length > 0; 547 const hasCurrency = typeof entry.currencyCode === "string" && entry.currencyCode.length > 0;
548 return !entry.priceKindId && (hasAmount || hasExistingPrice || hasCurrency); 549 }); 550 if (priceWithoutKind) { 551 throw (0, __TURBOPACK__imported__module__685008__["createCrudFormError"])(t("sales.channels.offers.errors.priceKindRequired", "Select a price kind for each override."), {}); 552 } 553 const duplicateKind = (()=>{ 554 const seen = /* @__PURE__ */ new Set(); 555 for (const entry of overrides){ 556 const kindId = typeof entry.priceKindId === "string" ? entry.priceKindId : null; 557 if (!kindId) continue; 558 if (seen.has(kindId)) return kindId; 559 seen.add(kindId); 560 } 561 return null; 562 })(); 563 if (duplicateKind) { 564 throw (0, __TURBOPACK__imported__module__685008__["createCrudFormError"])(t("sales.channels.offers.errors.priceKindDuplicate", "Each price kind can only be overridden once."), {}); 565 } 566 const submittedPriceIds = collectPriceIds(overrides); 567 const deletedIdSet = /* @__PURE__ */ new Set(); 568 initialPriceVersionsRef.current.forEach((_version, id)=>{ 569 if (!submittedPriceIds.has(id)) deletedIdSet.add(id); 570 }); 571 const deletedIds = Array.from(deletedIdSet); 572 const deletedVersions = new Map(deletedIds.map((id)=>[ 573 id, 574 initialPriceVersionsRef.current.get(id) ?? null 575 ])); 576 let savedId = offerId ?? null; 577 try { 578 if (mode === "create") { 579 const res = await (0, __TURBOPACK__imported__module__631465__["createCrud"])("catalog/offers", basePayload, { 580 errorMessage: t("sales.channels.offers.errors.save", "Failed to save offer.") 581 }); 582 savedId = res?.result?.offerId ?? res?.result?.id ?? null; 583 } else if (offerId) { 584 await (0, __TURBOPACK__imported__module__631465__["updateCrud"])("catalog/offers", { 585 id: offerId, 586 ...basePayload 587 }, { 588 errorMessage: t("sales.channels.offers.errors.save", "Failed to save offer.") 589 }); 590 savedId = offerId; 591 } 592 } catch (err) { 593 if ((0, __TURBOPACK__imported__module__977896__["extractOptimisticLockConflict"])(err)) { 594 throw err; 595 } 596 const details = err?.details; 597 const rawFieldErrors = err?.fieldErrors; 598 const fieldErrors = rawFieldErrors && typeof rawFieldErrors === "object" ? rawFieldErrors : void 0; 599 const status = err?.status; 600 const message = typeof err.message === "string" && err.message.trim().length ? err.message : t("sales.channels.offers.errors.duplicateProduct", "This product already has an offer in this channel."); 601 throw (0, __TURBOPACK__imported__module__685008__["createCrudFormError"])(message, fieldErrors, { 602 status, 603 details 604 }); 605 } 606 if (savedId) { 607 await syncPriceOverrides({ 608 overrides, 609 deletedIds, 610 deletedVersions, 611 offerId: savedId, 612 channelId, 613 productId 614 }); 615 initialPriceVersionsRef.current = collectPriceVersions(overrides); 616 } 617 (0, __TURBOPACK__imported__module__484973__["flash"])(t("sales.channels.offers.messages.saved", "Offer saved."), "success"); 618 router.push(buildChannelOffersHref(channelId)); 619 }, [ 620 attachmentCache, 621 lockedChannelId, 622 mode, 623 offerId, 624 router, 625 selectedChannelId, 626 t 627 ]); 628 const handleDelete = __TURBOPACK__imported__module__271645__["useCallback"](async ()=>{ 629 if (!offerId) return; 630 await (0, __TURBOPACK__imported__module__631465__["deleteCrud"])("catalog/offers", offerId, { 631 errorMessage: t("sales.channels.offers.errors.delete", "Failed to delete offer.") 632 }); 633 (0, __TURBOPACK__imported__module__484973__["flash"])(t("sales.channels.offers.messages.deleted", "Offer deleted."), "success"); 634 const targetChannel = initialValues?.channelId ?? lockedCh
634annelId ?? ""; 635 router.push(buildChannelOffersHref(targetChannel)); 636 }, [ 637 initialValues?.channelId, 638 lockedChannelId, 639 offerId, 640 router, 641 t 642 ]); 643 if (isNotFound) { 644 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__233769__["RecordNotFoundState"], { 645 label: t("sales.channels.offers.errors.notFound", "Offer not found."), 646 backHref: channelOffersHref, 647 backLabel: t("sales.channels.offers.actions.backToList", "Back to offers") 648 }); 649 } 650 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 651 children: [ 652 error ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__445299__["ErrorMessage"], { 653 label: error, 654 className: "mb-4" 655 }) : null, 656 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__33477__["CrudForm"], { 657 title: mode === "create" ? t("sales.channels.offers.form.createTitle", "Create offer") : t("sales.channels.offers.form.editTitle", "Edit offer"), 658 entityId: __TURBOPACK__imported__module__533874__["E"].catalog.catalog_offer, 659 fields, 660 groups, 661 initialValues: initialValues ?? void 0, 662 optimisticLockUpdatedAt: initialValues?.updatedAt, 663 isLoading: loading, 664 loadingMessage: t("sales.channels.offers.form.loading", "Loading offer\u2026"), 665 submitLabel: mode === "create" ? t("sales.channels.offers.form.createSubmit", "Create offer") : t("sales.channels.offers.form.updateSubmit", "Save changes"), 666 cancelHref: channelOffersHref, 667 backHref: channelOffersHref, 668 onSubmit: handleSubmit, 669 onDelete: mode === "edit" ? handleDelete : void 0, 670 deleteVisible: mode === "edit", 671 deleteRedirect: channelOffersHref 672 }) 673 ] 674 }); 675} 676function mapOfferToFormValues(item, lockedChannelId) { 677 const values = { 678 channelId: typeof item.channelId === "string" ? item.channelId : typeof item.channel_id === "string" ? item.channel_id : lockedChannelId ?? null, 679 productId: typeof item.productId === "string" ? item.productId : typeof item.product_id === "string" ? item.product_id : null, 680 title: typeof item.title === "string" ? item.title : "", 681 description: typeof item.description === "string" ? item.description : "", 682 defaultMediaId: typeof item.defaultMediaId === "string" ? item.defaultMediaId : typeof item.default_media_id === "string" ? item.default_media_id : null, 683 isActive: item.isActive === true || item.is_active === true, 684 priceOverrides: [], 685 updatedAt: typeof item.updatedAt === "string" ? item.updatedAt : typeof item.updated_at === "string" ? item.updated_at : null 686 }; 687 mergeCustomFieldValues(values, item); 688 return values; 689} 690function mapPriceRow(row) { 691 return { 692 tempId: String(row.id ?? crypto.randomUUID?.() ?? Math.random()), 693 priceId: typeof row.id === "string" ? row.id : void 0, 694 priceKindId: typeof row.priceKindId === "string" ? row.priceKindId : typeof row.price_kind_id === "string" ? row.price_kind_id : void 0, 695 priceKindCode: typeof row.priceKindCode === "string" ? row.priceKindCode : typeof row.price_kind_code === "string" ? row.price_kind_code : null, 696 currencyCode: typeof row.currencyCode === "string" ? row.currencyCode : typeof row.currency_code === "string" ? row.currency_code : null, 697 displayMode: row.displayMode === "including-tax" || row.display_mode === "including-tax" ? "including-tax" : "excluding-tax", 698 amount: typeof row.unitPriceNet === "string" ? row.unitPriceNet : typeof row.unit_price_net === "string" ? row.unit_price_net : typeof row.unitPriceGross === "string" ? row.unitPriceGross : typeof row.unit_price_gross === "string" ? row.unit_price_gross : "", 699 updatedAt: typeof row.updatedAt === "string" ? row.updatedAt : typeof row.updated_at === "string" ? row.updated_at : null 700 }; 701} 702function collectPriceIds(source) { 703 if (!Array.isArray(source)) return /* @__PURE__ */ new Set(); 704 const ids = source.map((entry)=>typeof entry?.priceId === "string" ? entry.priceId : null).filter((id)=>Boolean(id)); 705 return new Set(ids); 706} 707function collectPriceVersions(source) { 708 const versions = /* @__PURE__ */ new Map(); 709 if (!Array.isArray(source)) return versions; 710 for (const entry of source){ 711 if (typeof entry?.priceId === "string" && entry.priceId) { 712 versions.set(entry.priceId, typeof entry.updatedAt === "string" ? entry.updatedAt : null); 713 } 714 } 715 return versions; 716} 717function mergeCustomFieldValues(target, source) { 718 Object.assign(target, (0, __TURBOPACK__imported__module__4820__["extractCustomFieldEntries"])(source ?? {})); 719} 720function buildChannelOffersHref(channelId) { 721 return channelId && channelId.length ? `/backend/sales/channels/${channelId}/edit?tab=offers` : "/backend/sales/channels/offers"; 722} 723async function syncPriceOverrides(params) { 724 const { overrides, deletedIds, deletedVersions, offerId, channelId, productId } = params; 725 for (const draft of overrides){
726 if (!draft.priceKindId || !draft.amount) continue; 727 const amount = Number(draft.amount); 728 if (Number.isNaN(amount)) continue; 729 const payload = { 730 offerId, 731 productId, 732 channelId, 733 priceKindId: draft.priceKindId, 734 currencyCode: draft.currencyCode ?? void 0 735 }; 736 if (draft.displayMode === "including-tax") { 737 payload.unitPriceGross = amount; 738 } else { 739 payload.unitPriceNet = amount; 740 } 741 if (draft.priceId) { 742 const priceId = draft.priceId; 743 await (0, __TURBOPACK__imported__module__490746__["withScopedApiRequestHeaders"])((0, __TURBOPACK__imported__module__977896__["buildOptimisticLockHeader"])(draft.updatedAt), ()=>(0, __TURBOPACK__imported__module__631465__["updateCrud"])("catalog/prices", { 744 id: priceId, 745 ...payload 746 })); 747 } else { 748 await (0, __TURBOPACK__imported__module__631465__["createCrud"])("catalog/prices", payload); 749 } 750 } 751 const uniqueDeletedIds = Array.from(new Set(deletedIds.filter((id)=>typeof id === "string" && id.length > 0))); 752 for (const id of uniqueDeletedIds){ 753 if (!id) continue; 754 try { 755 await (0, __TURBOPACK__imported__module__490746__["withScopedApiRequestHeaders"])((0, __TURBOPACK__imported__module__977896__["buildOptimisticLockHeader"])(deletedVersions.get(id) ?? null), ()=>(0, __TURBOPACK__imported__module__631465__["deleteCrud"])("catalog/prices", id)); 756 } catch (err) { 757 logger.error("catalog.prices.delete", { 758 err 759 }); 760 } 761 } 762} 763function ChannelSelectInput({ value, onChange, disabled, showDetailsLink }) { 764 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 765 const [options, setOptions] = __TURBOPACK__imported__module__271645__["useState"]([]); 766 const selectedOption = __TURBOPACK__imported__module__271645__["useMemo"](()=>value ? options.find((opt)=>opt.id === value) ?? null : null, [ 767 options, 768 value 769 ]); 770 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 771 async function load() { 772 try { 773 const payload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(`/api/sales/channels?pageSize=${MAX_LIST_PAGE_SIZE}`, void 0, { 774 fallback: { 775 items: [] 776 } 777 }); 778 const items = Array.isArray(payload.items) ? payload.items : []; 779 setOptions(items.map((item)=>({ 780 id: typeof item.id === "string" ? item.id : "", 781 name: typeof item.name === "string" ? item.name : "", 782 code: typeof item.code === "string" ? item.code : null 783 }))); 784 } catch (err) { 785 logger.error("sales.channels.options", { 786 err 787 }); 788 } 789 } 790 void load(); 791 }, []); 792 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 793 const channelIdToLoad = typeof value === "string" ? value : null; 794 if (!channelIdToLoad || selectedOption) return; 795 const resolvedChannelId = channelIdToLoad; 796 let cancelled = false; 797 async function loadSingle() { 798 try { 799 const payload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(`/api/sales/channels?id=${encodeURIComponent(resolvedChannelId)}&pageSize=1`, void 0, { 800 fallback: { 801 items: [] 802 } 803 }); 804 const item = Array.isArray(payload.items) ? payload.items[0] : null; 805 if (!item || cancelled) return; 806 const entry = { 807 id: typeof item.id === "string" ? item.id : resolvedChannelId, 808 name: typeof item.name === "string" ? item.name : resolvedChannelId, 809 code: typeof item.code === "string" ? item.code : null 810 }; 811 setOptions((prev)=>{ 812 if (prev.some((opt)=>opt.id === entry.id)) return prev; 813 return [ 814 ...prev, 815 entry 816 ]; 817 }); 818 } catch (err) { 819 logger.error("sales.channels.lookup", { 820 err 821 }); 822 } 823 } 824 void loadSingle(); 825 return ()=>{ 826 cancelled = true; 827 }; 828 }, [ 829 selectedOption, 830 value 831 ]); 832 if (disabled && value) { 833 const label = selectedOption?.name ?? value; 834 const detail = selectedOption?.code ?? null; 835 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 836 className: "flex items-center justify-between gap-3 rounded border bg-muted px-3 py-2 text-sm", 837 children: [
838 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 839 className: "min-w-0", 840 children: [ 841 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 842 className: "font-medium truncate", 843 children: label 844 }), 845 detail ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 846 className: "text-xs text-muted-foreground truncate", 847 children: detail 848 }) : null 849 ] 850 }), 851 showDetailsLink ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__522016__["default"], { 852 href: `/backend/sales/channels/${value}/edit`, 853 className: "text-xs font-medium text-primary hover:underline", 854 children: t("sales.channels.offers.form.channelDetails", "Details") 855 }) : null 856 ] 857 }); 858 } 859 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])(__TURBOPACK__imported__module__262524__["Select"], { 860 value: value || void 0, 861 onValueChange: (next)=>onChange(next || null), 862 children: [
863 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectTrigger"], { 864 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectValue"], { 865 placeholder: t("sales.channels.offers.form.channelPlaceholder", "Select channel") 866 }) 867 }), 868 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectContent"], { 869 children: options.map((opt)=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectItem"], { 870 value: opt.id, 871 children: opt.code ? `${opt.name} (${opt.code})` : opt.name 872 }, opt.id)) 873 }) 874 ] 875 }); 876} 877function ProductSelectInput({ value, onChange, channelId, currentOfferId }) { 878 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 879 const [query, setQuery] = __TURBOPACK__imported__module__271645__["useState"](""); 880 const [results, setResults] = __TURBOPACK__imported__module__271645__["useState"]([]); 881 const [isLoading, setLoading] = __TURBOPACK__imported__module__271645__["useState"](false); 882 const [hasTyped, setHasTyped] = __TURBOPACK__imported__module__271645__["useState"](false); 883 const trimmed = query.trim(); 884 const shouldSearch = trimmed.length >= 2 || UUID_REGEX.test(trimmed); 885 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 886 if (!shouldSearch) { 887 setResults([]); 888 return; 889 } 890 let cancelled = false; 891 const controller = new AbortController(); 892 const timeout = setTimeout(async ()=>{ 893 setLoading(true); 894 try { 895 const params = new URLSearchParams({ 896 pageSize: "10" 897 }); 898 if (UUID_REGEX.test(trimmed)) { 899 params.set("id", trimmed); 900 } else if (trimmed.length) { 901 params.set("search", trimmed); 902 } 903 if (channelId) params.set("channelId", channelId); 904 const payload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(`/api/catalog/products?${params.toString()}`, { 905 signal: controller.signal 906 }, { 907 fallback: { 908 items: [] 909 } 910 }); 911 const items = Array.isArray(payload.items) ? payload.items : []; 912 if (!cancelled) { 913 const mapped = items.map((item)=>mapProductSearchResult(item, channelId, currentOfferId)); 914 mapped.sort((a, b)=>{ 915 const aBlocked = Boolean(a.existingOfferId && !a.isCurrentOfferProduct); 916 const bBlocked = Boolean(b.existingOfferId && !b.isCurrentOfferProduct); 917 return Number(aBlocked) - Number(bBlocked); 918 }); 919 setResults(mapped); 920 } 921 } catch (err) { 922 if (err.name === "AbortError") return; 923 logger.error("catalog.products.lookup", { 924 err 925 }); 926 } finally{ 927 if (!cancelled) setLoading(false); 928 } 929 }, 250); 930 return ()=>{ 931 cancelled = true; 932 clearTimeout(timeout); 933 controller.abort(); 934 }; 935 }, [ 936 channelId, 937 currentOfferId, 938 shouldSearch, 939 trimmed 940 ]); 941 const handleKeyDown = __TURBOPACK__imported__module__271645__["useCallback"]((event)=>{ 942 if (event.key === "Enter" && UUID_REGEX.test(trimmed)) { 943 event.preventDefault(); 944 onChange(trimmed); 945 } 946 }, [ 947 onChange, 948 trimmed 949 ]); 950 const selectedHint = value ? t("sales.channels.offers.form.productSelectedHint", "Selected product ID: {{id}}", { 951 id: value 952 }) : null; 953 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 954 className: "space-y-3", 955 children: [
956 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__987030__["Input"], { 957 leftIcon: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__555436__["Search"], {}), 958 value: query, 959 onChange: (event)=>{ 960 setQuery(event.target.value); 961 setHasTyped(true); 962 }, 963 onKeyDown: handleKeyDown, 964 placeholder: t("sales.channels.offers.form.productSearchPlaceholder", "Search by title, SKU, or ID\u2026") 965 }), 966 selectedHint ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 967 className: "rounded border bg-muted px-3 py-2 text-xs text-muted-foreground", 968 children: selectedHint 969 }) : null, 970 value ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__110035__["Button"], { 971 type: "button", 972 variant: "ghost", 973 size: "sm", 974 onClick: ()=>onChange(null), 975 children: t("sales.channels.offers.form.productClear", "Clear selection") 976 }) : null, 977 shouldSearch ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 978 className: "space-y-2", 979 children: [
980 isLoading ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 981 className: "flex items-center gap-2 text-sm text-muted-foreground", 982 children: [ 983 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__531278__["Loader2"], { 984 className: "h-4 w-4 animate-spin" 985 }), 986 t("sales.channels.offers.form.productSearchLoading", "Searching products\u2026") 987 ] 988 }) : null, 989 !isLoading && !results.length ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 990 className: "text-xs text-muted-foreground", 991 children: t("sales.channels.offers.form.productSearchEmpty", "No products match your search.") 992 }) : null, 993 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 994 className: "space-y-2 max-h-80 overflow-y-auto", 995 children: results.map((product)=>{ 996 const isSelected = value === product.id; 997 const hasConflict = Boolean(product.existingOfferId && !product.isCurrentOfferProduct); 998 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 999 className: (0, __TURBOPACK__imported__module__406911__["cn"])("flex gap-3 rounded border bg-card p-3 transition-colors", isSelected ? "border-primary/70 bg-primary/5" : "hover:border-primary/50"), 1000 children: [
1001 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1002 className: "h-12 w-12 overflow-hidden rounded border bg-muted", 1003 children: product.defaultMediaUrl ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("img", { 1004 src: product.defaultMediaUrl, 1005 alt: product.title, 1006 className: "h-full w-full object-cover" 1007 }) : /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1008 className: "flex h-full items-center justify-center text-muted-foreground", 1009 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__473708__["Image"], { 1010 className: "h-5 w-5" 1011 }) 1012 }) 1013 }),
1014 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1015 className: "flex flex-1 flex-col gap-1", 1016 children: [ 1017 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1018 className: "flex items-center justify-between gap-2", 1019 children: [ 1020 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1021 className: "min-w-0", 1022 children: [ 1023 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1024 className: "truncate text-sm font-medium", 1025 children: product.title || t("sales.channels.offers.form.productUntitled", "Untitled product") 1026 }), 1027 product.sku ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1028 className: "text-xs text-muted-foreground", 1029 children: [ 1030 "SKU \xB7 ", 1031 product.sku 1032 ] 1033 }) : null 1034 ] 1035 }),
1036 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1037 className: "text-xs font-medium text-muted-foreground", 1038 children: product.pricing ? formatPriceDisplay(product.pricing) : t("sales.channels.offers.form.productPriceMissing", "No price") 1039 }) 1040 ] 1041 }), 1042 hasConflict ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1043 className: "flex items-center justify-between gap-2 text-xs text-status-warning-text", 1044 children: [ 1045 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("span", { 1046 className: "truncate", 1047 children: t("sales.channels.offers.form.productHasOffer", "Already has an offer for this channel.") 1048 }), 1049 channelId && product.existingOfferId ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__522016__["default"], { 1050 href: `/backend/sales/channels/${encodeURIComponent(String(channelId))}/offers/${encodeURIComponent(String(product.existingOfferId))}/edit`, 1051 className: "shrink-0 font-medium text-primary hover:underline", 1052 children: t("sales.channels.offers.form.productHasOfferLink", "View offer") 1053 }) : null 1054 ] 1055 }) : null,
1056 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1057 className: "flex justify-end", 1058 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__110035__["Button"], { 1059 type: "button", 1060 variant: isSelected ? "secondary" : "outline", 1061 size: "sm", 1062 onClick: ()=>onChange(product.id), 1063 disabled: hasConflict && !isSelected, 1064 children: hasConflict && !isSelected ? t("sales.channels.offers.form.productUnavailable", "Unavailable") : isSelected ? t("sales.channels.offers.form.productSelected", "Selected") : t("sales.channels.offers.form.productSelect", "Select") 1065 }) 1066 }) 1067 ] 1068 }) 1069 ] 1070 }, product.id); 1071 }) 1072 }) 1073 ] 1074 }) : hasTyped ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1075 className: "text-xs text-muted-foreground", 1076 children: t("sales.channels.offers.form.productSearchHint", "Type at least 2 characters or paste a product ID.") 1077 }) : /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1078 className: "text-xs text-muted-foreground", 1079 children: t("sales.channels.offers.form.productSearchIntro", "Search by name or paste the product id to find catalog items.") 1080 }) 1081 ] 1082 }); 1083} 1084function DefaultMediaSelect({ value, options, onChange, productThumbnail, hasProduct, productDefaultMediaId }) { 1085 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 1086 const filteredOptions = __TURBOPACK__imported__module__271645__["useMemo"](()=>{ 1087 if (!productDefaultMediaId) return options; 1088 return options.filter((opt)=>opt.id !== productDefaultMediaId); 1089 }, [ 1090 options, 1091 productDefaultMediaId 1092 ]); 1093 const hasAttachmentOptions = filteredOptions.length > 0; 1094 const showPlaceholder = !hasAttachmentOptions && !productThumbnail && !hasProduct; 1095 if (showPlaceholder) { 1096 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1097 className: "text-xs text-muted-foreground", 1098 children: t("sales.channels.offers.form.mediaSelectProduct", "Select a product to load its media.") 1099 }); 1100 } 1101 const tiles = [ 1102 { 1103 id: "inherit", 1104 label: t("sales.channels.offers.form.mediaInherit", "Use product default"), 1105 thumbnail: productThumbnail, 1106 selected: value == null, 1107 onClick: ()=>onChange(null) 1108 }, 1109 ...filteredOptions.map((opt)=>({ 1110 id: opt.id, 1111 label: opt.label, 1112 thumbnail: opt.thumbnailUrl ?? null, 1113 selected: value === opt.id, 1114 onClick: ()=>onChange(opt.id) 1115 })) 1116 ]; 1117 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1118 className: "space-y-3", 1119 children: [
1120 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1121 className: "text-xs text-muted-foreground", 1122 children: [ 1123 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1124 children: t("sales.channels.offers.form.mediaHelp", "Choose the thumbnail that should represent this offer in the channel.") 1125 }), 1126 !hasAttachmentOptions && hasProduct ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1127 className: "mt-1", 1128 children: t("sales.channels.offers.form.mediaEmpty", "This product has no uploaded media yet; the product default will be used.") 1129 }) : null 1130 ] 1131 }), 1132 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1133 className: "grid gap-3 sm:grid-cols-3", 1134 children: tiles.map((tile)=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("button", { 1135 type: "button", 1136 className: (0, __TURBOPACK__imported__module__406911__["cn"])("flex flex-col rounded border text-left transition-colors", tile.selected ? "border-primary shadow-sm" : "hover:border-primary/60"), 1137 onClick: tile.onClick, 1138 children: [
1139 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1140 className: "relative aspect-square overflow-hidden rounded-t bg-muted", 1141 children: [ 1142 tile.thumbnail ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("img", { 1143 src: tile.thumbnail, 1144 alt: tile.label, 1145 className: "h-full w-full object-cover" 1146 }) : /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1147 className: "flex h-full items-center justify-center text-muted-foreground", 1148 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__473708__["Image"], { 1149 className: "h-6 w-6" 1150 }) 1151 }), 1152 tile.selected ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1153 className: "absolute right-2 top-2 rounded-full bg-primary/90 px-2 py-0.5 text-xs font-semibold text-primary-foreground", 1154 children: t("sales.channels.offers.form.mediaSelected", "Active") 1155 }) : null 1156 ] 1157 }),
1158 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1159 className: "p-2", 1160 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1161 className: "line-clamp-2 text-xs font-medium", 1162 children: tile.label 1163 }) 1164 }) 1165 ] 1166 }, tile.id)) 1167 }) 1168 ] 1169 }); 1170} 1171function OfferFormWatchers({ values, setValue, productCache, attachmentCache, setMediaOptions, setProductSummary, setVariantPreviews, variantCache, variantMediaCache, channelId, manualMediaSelections, setCurrentProductId, errors }) { 1172 const previousProductIdRef = __TURBOPACK__imported__module__271645__["useRef"](null); 1173 const initializedProductRef = __TURBOPACK__imported__module__271645__["useRef"](false); 1174 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 1175 const productId = typeof values.productId === "string" ? values.productId : null; 1176 setCurrentProductId(productId); 1177 if (!productId) { 1178 setMediaOptions([]); 1179 setProductSummary(null); 1180 setVariantPreviews([]); 1181 previousProductIdRef.current = null; 1182 return; 1183 } 1184 const resolvedProductId = productId; 1185 const resolvedChannelId = channelId ?? null; 1186 if (!initializedProductRef.current) { 1187 previousProductIdRef.current = resolvedProductId; 1188 initializedProductRef.current = true; 1189 } else if (previousProductIdRef.current !== resolvedProductId) { 1190 previousProductIdRef.current = resolvedProductId; 1191 setValue("defaultMediaId", void 0); 1192 } 1193 let cancelled = false; 1194 async function load() { 1195 try { 1196 const summary = await resolveProductSummaryWithCache({ 1197 productId: resolvedProductId, 1198 channelId: resolvedChannelId, 1199 productCache 1200 }); 1201 if (!cancelled) { 1202 setProductSummary(summary ?? null); 1203 if (summary) { 1204 const hasTitle = typeof values.title === "string" && values.title.trim().length > 0; 1205 if (!hasTitle && summary.title) { 1206 setValue("title", summary.title); 1207 } 1208 const hasDescription = typeof values.description === "string" && values.description.trim().length > 0; 1209 if (!hasDescription && summary.description) { 1210 setValue("description", summary.description); 1211 } 1212 if (!values.defaultMediaId && summary.defaultMediaId && !manualMediaSelections.current.has(resolvedProductId)) { 1213 setValue("defaultMediaId", summary.defaultMediaId); 1214 } 1215 } 1216 } 1217 const attachments = await resolveProductMediaOptionsWithCache({ 1218 productId: resolvedProductId, 1219 attachmentCache 1220 }); 1221 if (!cancelled) { 1222 const variants = await resolveVariantPreviewsWithCache({ 1223 productId: resolvedProductId, 1224 variantCache, 1225 variantMediaCache 1226 }); 1227 const mergedMedia = buildMediaOptionsFromSources({ 1228 attachments, 1229 variants, 1230 summary 1231 }); 1232 attachmentCache.current.set(resolvedProductId, mergedMedia); 1233 setMediaOptions(mergedMedia); 1234 setVariantPreviews(variants); 1235 } 1236 } catch (err) { 1237 logger.error("sales.channels.offer.watchers", { 1238 err 1239 }); 1240 } 1241 } 1242 void load(); 1243 return ()=>{ 1244 cancelled = true; 1245 }; 1246 }, [ 1247 attachmentCache, 1248 channelId, 1249 manualMediaSelections, 1250 productCache, 1251 setMediaOptions, 1252 setProductSummary, 1253 setValue, 1254 setVariantPreviews, 1255 values.defaultMediaId, 1256 values.description, 1257 values.productId, 1258 values.title, 1259 variantCache, 1260 variantMediaCache, 1261 setCurrentProductId 1262 ]); 1263 return null; 1264} 1265async function resolveProductSummaryWithCache({ productId, channelId, productCache }) { 1266 if (!productId) return null; 1267 const cacheKey = channelId ? `${productId}:${channelId}` : productId; 1268 let summary = productCache.current.get(cacheKey); 1269 if (summary) return summary; 1270 const params = new URLSearchParams({ 1271 id: productId, 1272 pageSize: "1" 1273 }); 1274 if (channelId) params.set("channelId", channelId); 1275 const payload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(`/api/catalog/products?${params.toString()}`, void 0, { 1276 fallback: { 1277 items: [] 1278 } 1279 }); 1280 const product = Array.isArray(payload.items) ? payload.items[0] : null; 1281 summary = product ? mapProductSummary(product) : null; 1282 if (summary) { 1283 productCache.current.set(cacheKey, summary); 1284 } 1285 return summary ?? null; 1286} 1287async function resolveProductMediaOptionsWithCache({ productId, attachmentCache }) { 1288 if (!productId) return []; 1289 const cached = attachmentCache.current.get(productId) ?? []; 1290 if (cached.length) { 1291 const deduped = dedupeMediaOptions(cached); 1292 attachmentCache.current.set(productId, deduped); 1293 return deduped; 1294 } 1295 const attachments = dedupeMediaOptions(await loadProductMedia(productId)); 1296 attachmentCache.current.set(productId, attachments); 1297 return attachments; 1298} 1299async function resolveVariantPreviewsWithCache({ productId, variantCache, variantMediaCache }) { 1300 if (!productId) return []; 1301 const cached = variantCache.current.get(productId); 1302 if (cached) return cached; 1303 const variantPayload = await (0, __TURBOPACK__imported__module__490746__["readApiResultOrThrow"])(`/api/catalog/variants?productId=${encodeURIComponent(productId)}&pageSize=${MAX_LIST_PAGE_SIZE}`, void 0, { 1304 fallback: { 1305 items: [] 1306 } 1307 }); 1308 const items = Array.isArray(variantPayload.items) ? variantPayload.items : []; 1309 const variants = await Promise.all(items.map(async (item)=>{ 1310 const preview = mapVariantPreview(item); 1311 const media = await resolveVariantThumbnail(preview.id, variantMediaCache); 1312 return { 1313 ...preview, 1314 thumbnailId: media?.attachmentId ?? preview.thumbnailId, 1315 thumbnailUrl: media?.thumbnailUrl ?? preview.thumbnailUrl, 1316 thumbnailFileName: media?.fileName ?? preview.thumbnailFileName 1317 }; 1318 })); 1319 variantCache.current.set(productId, variants); 1320 return variants; 1321} 1322function mapProductSummary(item) { 1323 const pricingSource = item.pricing && typeof item.pricing === "object" ? item.pricing : null; 1324 return { 1325 title: typeof item.title === "string" ? item.title : "", 1326 description: typeof item.description === "string" ? item.description : null, 1327 defaultMediaId: typeof item.defaultMediaId === "string" ? item.defaultMediaId : typeof item.default_media_id === "string" ? item.default_media_id : null, 1328 defaultMediaUrl: typeof item.defaultMediaUrl === "string" ? item.defaultMediaUrl : typeof item.default_media_url === "string" ? item.default_media_url : null, 1329 sku: typeof item.sku === "string" ? item.sku : null, 1330 pricing: normalizePricing(pricingSource) 1331 }; 1332} 1333function normalizePricing(source) { 1334 if (!source) return null; 1335 const currencyCode = typeof source.currencyCode === "string" ? source.currencyCode : typeof source.currency_code === "string" ? source.currency_code : null; 1336 const unitPriceNet = typeof source.unitPriceNet === "string" ? source.unitPriceNet : typeof source.unit_price_net === "string" ? source.unit_price_net : null; 1337 const unitPriceGross = typeof source.unitPriceGross === "string" ? source.unitPriceGross : typeof source.unit_price_gross === "string" ? source.unit_price_gross : null; 1338 const displayMode = source.displayMode === "including-tax" || source.display_mode === "including-tax" ? "including-tax" : source.displayMode === "excluding-tax" || source.display_mode === "excluding-tax" ? "excluding-tax" : null; 1339 return { 1340 currencyCode, 1341 unitPriceNet, 1342 unitPriceGross, 1343 displayMode 1344 }; 1345} 1346async function loadProductMedia(productId) { 1347 if (!productId) return []; 1348 const normalize = (items)=>items.filter((item)=>typeof item.id === "string" && typeof item.fileName === "string").map((item)=>({ 1349 id: item.id, 1350 label: item.fileName, 1351 fileName: item.fileName, 1352 thumbnailUrl: typeof item.thumbnailUrl === "string" ? item.thumbnailUrl : (0, __TURBOPACK__imported__module__445546__["buildAttachmentImageUrl"])(item.id, { 1353 width: 360, 1354 height: 360, 1355 slug: (0, __TURBOPACK__imported__module__445546__["slugifyAttachmentFileName"])(item.fileName) 1356 }) 1357 })); 1358 try { 1359 const primary = await (0, __TURBOPACK__imported__module__490746__["apiCall"])(`/api/catalog/product-media?productId=${encodeURIComponent(productId)}`, void 0, { 1360 fallback: { 1361 items: [] 1362 } 1363 }); 1364 if (primary.ok && primary.result?.items) { 1365 return normalize(primary.result.items); 1366 } 1367 } catch (err) { 1368 logger.error("catalog.product-media.lookup", { 1369 err 1370 }); 1371 } 1372 try { 1373 const fallback = await (0, __TURBOPACK__imported__module__490746__["apiCall"])(`/api/attachments?entityId=${encodeURIComponent(__TURBOPACK__imported__module__533874__["E"].catalog.catalog_product)}&recordId=${encodeURIComponent(productId)}`, void 0, { 1374 fallback: { 1375 items: [] 1376 } 1377 }); 1378 if (fallback.ok && fallback.result?.items) { 1379 return normalize(fallback.result.items); 1380 } 1381 } catch (err) { 1382 logger.error("attachments.lookup", { 1383 err 1384 }); 1385 } 1386 return []; 1387} 1388function buildVariantMediaOptions(variants) { 1389 return variants.map((variant)=>{ 1390 if (!variant.thumbnailId || !variant.thumbnailUrl) return null; 1391 const label = variant.name || variant.sku || "Variant"; 1392 const fileName = variant.thumbnailFileName ?? `${variant.thumbnailId}.jpg`; 1393 return { 1394 id: variant.thumbnailId, 1395 label, 1396 fileName, 1397 thumbnailUrl: variant.thumbnailUrl 1398 }; 1399 }).filter((entry)=>Boolean(entry)); 1400} 1401function buildMediaOptionsFromSources({ attachments, variants, summary }) { 1402 const merged = dedupeMediaOptions([ 1403 ...attachments ?? [], 1404 ...buildVariantMediaOptions(variants ?? []) 1405 ]); 1406 const defaultId = summary?.defaultMediaId ?? null; 1407 const defaultUrl = summary?.defaultMediaUrl ?? null; 1408 if (defaultId && defaultUrl && !merged.some((entry)=>entry.id === defaultId)) { 1409 const fileName = inferFileNameFromUrl(defaultUrl, defaultId); 1410 merged.unshift({ 1411 id: defaultId, 1412 label: fileName, 1413 fileName, 1414 thumbnailUrl: defaultUrl 1415 }); 1416 } 1417 return merged; 1418} 1419function dedupeMediaOptions(entries) { 1420 if (!Array.isArray(entries)) return []; 1421 const seen = /* @__PURE__ */ new Set(); 1422 const result = [];
1423 for (const entry of entries){ 1424 if (!entry || typeof entry.id !== "string") continue; 1425 if (seen.has(entry.id)) continue; 1426 seen.add(entry.id); 1427 result.push(entry); 1428 } 1429 return result; 1430} 1431function inferFileNameFromUrl(url, fallbackId) { 1432 if (typeof url === "string" && url.length) { 1433 const cleaned = url.split(/[?#]/)[0]; 1434 const last = cleaned.split("/").pop(); 1435 if (last && last.trim().length) return last; 1436 } 1437 return `${fallbackId}.jpg`; 1438} 1439function mapVariantPreview(item) { 1440 return { 1441 id: typeof item.id === "string" ? item.id : "", 1442 name: typeof item.name === "string" ? item.name : typeof item.sku === "string" ? item.sku : "Variant", 1443 sku: typeof item.sku === "string" ? item.sku : null, 1444 thumbnailUrl: typeof item.defaultMediaUrl === "string" ? item.defaultMediaUrl : typeof item.default_media_url === "string" ? item.default_media_url : null, 1445 thumbnailId: null, 1446 thumbnailFileName: null 1447 }; 1448} 1449async function resolveVariantThumbnail(variantId, cache) { 1450 if (!variantId) return null; 1451 if (cache.current.has(variantId)) { 1452 return cache.current.get(variantId) ?? null; 1453 } 1454 try { 1455 const payload = await (0, __TURBOPACK__imported__module__490746__["apiCall"])(`/api/attachments?entityId=${encodeURIComponent(__TURBOPACK__imported__module__533874__["E"].catalog.catalog_product_variant)}&recordId=${encodeURIComponent(variantId)}`); 1456 const items = payload.ok && payload.result?.items ? payload.result.items : []; 1457 const first = items.find((item)=>typeof item.id === "string"); 1458 if (first?.id) { 1459 const thumbnailUrl = typeof first.thumbnailUrl === "string" ? first.thumbnailUrl : (0, __TURBOPACK__imported__module__445546__["buildAttachmentImageUrl"])(first.id, { 1460 width: 360, 1461 height: 360, 1462 slug: (0, __TURBOPACK__imported__module__445546__["slugifyAttachmentFileName"])(first.fileName ?? first.id) 1463 }); 1464 const info = { 1465 attachmentId: first.id, 1466 thumbnailUrl: thumbnailUrl ?? null, 1467 fileName: typeof first.fileName === "string" ? first.fileName : null 1468 }; 1469 cache.current.set(variantId, info); 1470 return info; 1471 } 1472 } catch (err) { 1473 logger.error("sales.channels.offer.variantMedia", { 1474 err 1475 }); 1476 } 1477 const empty = { 1478 attachmentId: null, 1479 thumbnailUrl: null, 1480 fileName: null 1481 }; 1482 cache.current.set(variantId, empty); 1483 return empty; 1484} 1485function mapProductSearchResult(item, channelId, currentOfferId) { 1486 const offers = Array.isArray(item.offers) ? item.offers : []; 1487 const channelOffer = offers.find((entry)=>{ 1488 if (!entry || typeof entry !== "object") return false; 1489 const offerChannelId = typeof entry.channelId === "string" ? entry.channelId : typeof entry.channel_id === "string" ? entry.channel_id : null; 1490 return channelId ? offerChannelId === channelId : false; 1491 }) ?? null; 1492 const existingOfferId = channelOffer && typeof channelOffer.id === "string" ? channelOffer.id : null; 1493 return { 1494 id: typeof item.id === "string" ? item.id : "", 1495 title: typeof item.title === "string" ? item.title : "", 1496 sku: typeof item.sku === "string" ? item.sku : null, 1497 defaultMediaUrl: typeof item.defaultMediaUrl === "string" ? item.defaultMediaUrl : typeof item.default_media_url === "string" ? item.default_media_url : null, 1498 pricing: item.pricing && typeof item.pricing === "object" ? normalizePricing(item.pricing) : null, 1499 existingOfferId, 1500 existingOfferTitle: channelOffer && typeof channelOffer.title === "string" ? channelOffer.title : null, 1501 isCurrentOfferProduct: Boolean(existingOfferId && currentOfferId && existingOfferId === currentOfferId) 1502 }; 1503} 1504function formatPriceDisplay(pricing) { 1505 if (!pricing) return "\u2014"; 1506 const amount = pricing.displayMode === "including-tax" ? pricing.unitPriceGross ?? pricing.unitPriceNet : pricing.unitPriceNet ?? pricing.unitPriceGross; 1507 if (!amount) return pricing.currencyCode ?? "\u2014"; 1508 return `${pricing.currencyCode ?? ""} ${amount}`; 1509} 1510function PriceOverridesEditor({ values, onChange, priceKinds, basePrice, onRemoveDraft }) { 1511 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 1512 const baseAmount = __TURBOPACK__imported__module__271645__["useMemo"](()=>{ 1513 if (!basePrice) return ""; 1514 const net = basePrice.unitPriceNet ?? null; 1515 const gross = basePrice.unitPriceGross ?? null; 1516 if (basePrice.displayMode === "including-tax") { 1517 return gross ?? net ?? ""; 1518 } 1519 if (basePrice.displayMode === "excluding-tax") { 1520 return net ?? gross ?? ""; 1521 } 1522 return net ?? gross ?? ""; 1523 }, [ 1524 basePrice 1525 ]); 1526 const baseDefaults = __TURBOPACK__imported__module__271645__["useMemo"](()=>({ 1527 amount: baseAmount, 1528 currencyCode: basePrice?.currencyCode ?? null, 1529 displayMode: basePrice?.displayMode ?? null 1530 }), [ 1531 baseAmount, 1532 basePrice?.currencyCode, 1533 basePrice?.displayMode 1534 ]); 1535 const usedKindIdSet = __TURBOPACK__imported__module__271645__["useMemo"](()=>{ 1536 const next = /* @__PURE__ */ new Set();
1537 values.forEach((row)=>{ 1538 if (typeof row.priceKindId === "string" && row.priceKindId.length) { 1539 next.add(row.priceKindId); 1540 } 1541 }); 1542 return next; 1543 }, [ 1544 values 1545 ]); 1546 const availableKindCount = priceKinds.reduce((count, kind)=>usedKindIdSet.has(kind.id) ? count : count + 1, 0); 1547 const canAddRow = availableKindCount > 0; 1548 const addRow = __TURBOPACK__imported__module__271645__["useCallback"](()=>{ 1549 const usedIds = /* @__PURE__ */ new Set(); 1550 values.forEach((row)=>{ 1551 if (typeof row.priceKindId === "string" && row.priceKindId.length) { 1552 usedIds.add(row.priceKindId); 1553 } 1554 }); 1555 const nextKind = priceKinds.find((kind)=>!usedIds.has(kind.id)); 1556 if (!nextKind && priceKinds.length) { 1557 return; 1558 } 1559 onChange([ 1560 ...values, 1561 { 1562 tempId: crypto.randomUUID?.() ?? Math.random().toString(36).slice(2), 1563 amount: baseDefaults.amount, 1564 currencyCode: nextKind?.currencyCode ?? baseDefaults.currencyCode, 1565 displayMode: nextKind?.displayMode ?? baseDefaults.displayMode, 1566 priceKindId: nextKind?.id ?? null, 1567 priceKindCode: nextKind?.code ?? nextKind?.title ?? null 1568 } 1569 ]); 1570 }, [ 1571 baseDefaults, 1572 onChange, 1573 priceKinds, 1574 values 1575 ]); 1576 const updateRow = __TURBOPACK__imported__module__271645__["useCallback"]((tempId, patch)=>{ 1577 onChange(values.map((row)=>row.tempId === tempId ? { 1578 ...row, 1579 ...patch 1580 } : row)); 1581 }, [ 1582 onChange, 1583 values 1584 ]); 1585 const removeRow = __TURBOPACK__imported__module__271645__["useCallback"](async (row)=>{ 1586 const allowRemoval = await onRemoveDraft?.(row); 1587 if (allowRemoval === false) return; 1588 onChange(values.filter((entry)=>entry.tempId !== row.tempId)); 1589 }, [ 1590 onChange, 1591 onRemoveDraft, 1592 values 1593 ]); 1594 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1595 className: "space-y-4", 1596 children: [
1597 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1598 className: "rounded border bg-muted/50 px-3 py-2", 1599 children: [ 1600 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1601 className: "text-xs uppercase text-muted-foreground", 1602 children: t("sales.channels.offers.pricing.basePriceLabel", "Original product price") 1603 }), 1604 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1605 className: "text-base font-semibold", 1606 children: basePrice ? formatPriceDisplay(basePrice) : t("sales.channels.offers.pricing.basePriceMissing", "No price found") 1607 }), 1608 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1609 className: "text-xs text-muted-foreground", 1610 children: t("sales.channels.offers.pricing.basePriceHelp", "Shown to shoppers when no override is configured.") 1611 }) 1612 ] 1613 }),
1614 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1615 className: "space-y-2", 1616 children: [ 1617 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1618 className: "flex items-center justify-between", 1619 children: [ 1620 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1621 className: "text-sm text-muted-foreground", 1622 children: t("sales.channels.offers.pricing.help", "Provide overrides for price kinds when this offer is active.") 1623 }), 1624 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__110035__["Button"], { 1625 type: "button", 1626 variant: "outline", 1627 size: "sm", 1628 onClick: addRow, 1629 disabled: !canAddRow, 1630 children: t("sales.channels.offers.pricing.add", "Add price") 1631 }) 1632 ] 1633 }), 1634 !canAddRow ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1635 className: "text-xs text-muted-foreground", 1636 children: priceKinds.length ? t("sales.channels.offers.pricing.allKindsUsed", "Each price kind already has an override.") : t("sales.channels.offers.pricing.noKindsAvailable", "Define a price kind before adding overrides.") 1637 }) : null 1638 ] 1639 }),
1640 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1641 className: "flex items-center justify-between", 1642 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1643 className: "text-xs text-muted-foreground", 1644 children: t("sales.channels.offers.pricing.overrideHint", "Overrides take precedence over the original product price.") 1645 }) 1646 }), 1647 values.length ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1648 className: "space-y-2", 1649 children: values.map((row)=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1650 className: "grid gap-2 rounded border p-3 md:grid-cols-3", 1651 children: [ 1652 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])(__TURBOPACK__imported__module__262524__["Select"], { 1653 value: row.priceKindId || void 0, 1654 onValueChange: (value)=>{ 1655 const next = priceKinds.find((kind)=>kind.id === value); 1656 updateRow(row.tempId, {
1657 priceKindId: next?.id ?? null, 1658 priceKindCode: next?.code ?? next?.title ?? null, 1659 currencyCode: next?.currencyCode ?? null, 1660 displayMode: next?.displayMode ?? null 1661 }); 1662 }, 1663 children: [ 1664 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectTrigger"], { 1665 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectValue"], { 1666 placeholder: t("sales.channels.offers.pricing.selectKind", "Select price kind") 1667 }) 1668 }), 1669 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectContent"], { 1670 children: priceKinds.map((kind)=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectItem"], { 1671 value: kind.id, 1672 disabled: usedKindIdSet.has(kind.id) && row.priceKindId !== kind.id, 1673 children: kind.title ?? kind.code ?? kind.id 1674 }, kind.id)) 1675 }) 1676 ] 1677 }),
1678 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1679 className: "relative", 1680 children: [ 1681 row.currencyCode ?? basePrice?.currencyCode ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("span", { 1682 className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-xs font-semibold text-muted-foreground", 1683 children: row.currencyCode ?? basePrice?.currencyCode 1684 }) : null, 1685 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__987030__["Input"], { 1686 inputClassName: (0, __TURBOPACK__imported__module__406911__["cn"])(row.currencyCode || basePrice?.currencyCode ? "pl-13" : ""), 1687 type: "number", 1688 placeholder: t("sales.channels.offers.pricing.amount", "Amount"), 1689 value: row.amount ?? "", 1690 onChange: (event)=>updateRow(row.tempId, { 1691 amount: event.target.value 1692 }) 1693 }) 1694 ] 1695 }),
1696 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1697 className: "flex flex-col justify-between gap-2 text-xs text-muted-foreground sm:flex-row sm:items-center", 1698 children: [ 1699 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("span", { 1700 children: row.displayMode === "including-tax" ? t("sales.channels.offers.pricing.includingTax", "Including tax") : t("sales.channels.offers.pricing.excludingTax", "Excluding tax") 1701 }), 1702 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])(__TURBOPACK__imported__module__110035__["Button"], { 1703 type: "button", 1704 variant: "ghost", 1705 size: "sm", 1706 className: "gap-1 px-2 font-normal text-destructive hover:text-destructive focus-visible:text-destructive", 1707 onClick: ()=>{ 1708 void removeRow(row); 1709 }, 1710 children: [
1711 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__727612__["Trash2"], { 1712 className: "h-3.5 w-3.5" 1713 }), 1714 t("sales.channels.offers.pricing.remove", "Remove") 1715 ] 1716 }) 1717 ] 1718 }) 1719 ] 1720 }, row.tempId)) 1721 }) : /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("p", { 1722 className: "text-xs text-muted-foreground", 1723 children: [ 1724 t("sales.channels.offers.pricing.empty", "No overrides yet."), 1725 basePrice ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])(__TURBOPACK__imported__module__843476__["Fragment"], { 1726 children: [ 1727 " ", 1728 t("sales.channels.offers.pricing.emptyFallback", "Using {price} from the product until you add overrides.", { 1729 price: formatPriceDisplay(basePrice) 1730 }) 1731 ] 1732 }) : null 1733 ] 1734 }) 1735 ] 1736 }); 1737} 1738function ProductOverviewCard({ summary, variants }) { 1739 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 1740 if (!summary) { 1741 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1742 className: "text-xs text-muted-foreground", 1743 children: t("sales.channels.offers.form.productSummaryPlaceholder", "Select a product to preview its media, price, and variants.") 1744 }); 1745 } 1746 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1747 className: "space-y-4", 1748 children: [
1749 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1750 className: "flex gap-3", 1751 children: [ 1752 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1753 className: "h-16 w-16 overflow-hidden rounded border bg-muted", 1754 children: summary.defaultMediaUrl ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("img", { 1755 src: summary.defaultMediaUrl, 1756 alt: summary.title, 1757 className: "h-full w-full object-cover" 1758 }) : /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1759 className: "flex h-full items-center justify-center text-muted-foreground", 1760 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__473708__["Image"], { 1761 className: "h-5 w-5" 1762 }) 1763 }) 1764 }),
1765 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1766 className: "flex-1", 1767 children: [ 1768 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1769 className: "text-sm font-semibold", 1770 children: summary.title || t("sales.channels.offers.form.productUntitled", "Untitled product") 1771 }), 1772 summary.sku ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1773 className: "text-xs text-muted-foreground", 1774 children: [ 1775 "SKU \xB7 ", 1776 summary.sku 1777 ] 1778 }) : null, 1779 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1780 className: "text-sm", 1781 children: [
1782 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("span", { 1783 className: "text-muted-foreground", 1784 children: [ 1785 t("sales.channels.offers.form.productPriceLabel", "Base price"), 1786 ":" 1787 ] 1788 }), 1789 " ", 1790 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("span", { 1791 className: "font-semibold", 1792 children: formatPriceDisplay(summary.pricing) 1793 }) 1794 ] 1795 }) 1796 ] 1797 }) 1798 ] 1799 }), 1800 summary.description ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1801 className: "text-sm text-muted-foreground", 1802 children: summary.description 1803 }) : null,
1804 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(ProductVariantsList, { 1805 variants 1806 }) 1807 ] 1808 }); 1809} 1810function ProductVariantsList({ variants }) { 1811 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 1812 if (!variants.length) { 1813 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 1814 className: "text-xs text-muted-foreground", 1815 children: t("sales.channels.offers.form.variantsEmpty", "No variants available for this product.") 1816 }); 1817 } 1818 return /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1819 className: "space-y-2", 1820 children: [ 1821 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1822 className: "text-sm font-medium", 1823 children: t("sales.channels.offers.form.variantsTitle", "Variants") 1824 }), 1825 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1826 className: "space-y-2 max-h-64 overflow-y-auto pr-1", 1827 children: variants.map((variant)=>/* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1828 className: "flex gap-3 rounded border bg-card p-2", 1829 children: [
1830 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1831 className: "h-10 w-10 overflow-hidden rounded border bg-muted", 1832 children: variant.thumbnailUrl ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("img", { 1833 src: variant.thumbnailUrl, 1834 alt: variant.name, 1835 className: "h-full w-full object-cover" 1836 }) : /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1837 className: "flex h-full items-center justify-center text-muted-foreground", 1838 children: /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__473708__["Image"], { 1839 className: "h-4 w-4" 1840 }) 1841 }) 1842 }),
1843 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1844 className: "min-w-0", 1845 children: [ 1846 /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsx"])("div", { 1847 className: "text-xs font-medium", 1848 children: variant.name 1849 }), 1850 variant.sku ? /* @__PURE__ */ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 1851 className: "text-overline text-muted-foreground", 1852 children: [ 1853 "SKU \xB7 ", 1854 variant.sku 1855 ] 1856 }) : null 1857 ] 1858 }) 1859 ] 1860 }, variant.id)) 1861 }) 1862 ] 1863 }); 1864} 1865; 1866__turbopack_context__.s([ 1867 "ChannelOfferForm", 1868 0, 1869 ChannelOfferForm 1870]); 1871}), 1872]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.