@vio-live/web-sdk 0.32.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +123 -0
- package/README.md +156 -17
- package/dist/chunk-3YFJFDSN.js +3 -0
- package/dist/{chunk-QGJUBVH3.js.map → chunk-3YFJFDSN.js.map} +1 -1
- package/dist/{chunk-C5Q6W4B2.js → chunk-F7LE5AZY.js} +358 -56
- package/dist/chunk-F7LE5AZY.js.map +1 -0
- package/dist/{chunk-IR4XYTZL.js → chunk-QA5R4VYF.js} +943 -134
- package/dist/chunk-QA5R4VYF.js.map +1 -0
- package/dist/core/index.d.ts +819 -567
- package/dist/core/index.js +2 -2
- package/dist/detail-layout-BI556w8p.d.ts +76 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/react/index.d.ts +4 -2
- package/dist/react/index.js +5 -4
- package/dist/react/index.js.map +1 -1
- package/dist/{tokens-D1DCVzOf.d.ts → tokens-C-LsqKQH.d.ts} +130 -11
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-C5Q6W4B2.js.map +0 -1
- package/dist/chunk-IR4XYTZL.js.map +0 -1
- package/dist/chunk-QGJUBVH3.js +0 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vio, __decorateClass, primaryImageUrl, displayPrice, toCampaignId, getGlobalCurrency, ensureVippsButton, formatPrice, buyerRefOf, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, storageGet, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, getGlobalCountryCode, isValidPhone, gatewayHasBuyerRef, rememberedCheckoutSponsor, checkoutSponsorOf, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, sponsorIdentityFrom, Configuration, normalizeScope, campaignCandidates } from './chunk-
|
|
1
|
+
import { Vio, __decorateClass, primaryImageUrl, displayPrice, resolveDetailLayout, toCampaignId, getGlobalCurrency, copyAppliedLayout, onGlobalDetailLayoutChange, layoutSignature, layoutOriginOf, ensureVippsButton, formatPrice, shippingDescriptionOf, buyerRefOf, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, storageGet, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, getGlobalCountryCode, isValidPhone, gatewayHasBuyerRef, rememberedCheckoutSponsor, checkoutSponsorOf, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, sponsorIdentityFrom, Configuration, normalizeScope, campaignCandidates } from './chunk-QA5R4VYF.js';
|
|
2
2
|
import { LitElement, css, html, nothing } from 'lit';
|
|
3
3
|
import { property, state, query } from 'lit/decorators.js';
|
|
4
4
|
|
|
@@ -201,7 +201,8 @@ var THEME_KEY_TO_CSS_VAR = {
|
|
|
201
201
|
confirmTitleSize: "--vio-confirm-title-size",
|
|
202
202
|
confirmCheckBg: "--vio-confirm-check-bg",
|
|
203
203
|
redirectBg: "--vio-redirect-bg",
|
|
204
|
-
redirectSpinner: "--vio-redirect-spinner"
|
|
204
|
+
redirectSpinner: "--vio-redirect-spinner",
|
|
205
|
+
vippsCartPayment: "--vio-vipps-cart-payment"
|
|
205
206
|
};
|
|
206
207
|
function applyVioTheme(overrides, target = typeof document !== "undefined" ? document.documentElement : null) {
|
|
207
208
|
if (!target) return;
|
|
@@ -1151,6 +1152,21 @@ var VioProductCarousel = class extends LitElement {
|
|
|
1151
1152
|
* sponsor of the campaign the slot shows (ADR-0034 — "the campaign of the
|
|
1152
1153
|
* block is its sponsor"), else 0 (unknown).
|
|
1153
1154
|
*/
|
|
1155
|
+
/**
|
|
1156
|
+
* The campaign whose channel sells a sponsor's products here (one article =
|
|
1157
|
+
* one campaign = one channel): the campaign this slot credits for that
|
|
1158
|
+
* sponsor (`Vio.attribution`), then the element's own (`vio-campaign`, an
|
|
1159
|
+
* ancestor's `data-vio-campaign`).
|
|
1160
|
+
*/
|
|
1161
|
+
commerceCampaigns(sponsorId) {
|
|
1162
|
+
const own = this.slotRegistration.campaignHint;
|
|
1163
|
+
try {
|
|
1164
|
+
const resolved = typeof Vio.attribution === "function" ? Vio.attribution(this.effectiveSlot || null, { sponsorId, campaignId: own }).campaignId : void 0;
|
|
1165
|
+
return resolved !== void 0 ? [resolved, ...own] : own;
|
|
1166
|
+
} catch {
|
|
1167
|
+
return own;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1154
1170
|
effectiveSponsorId() {
|
|
1155
1171
|
if (this.sponsorId > 0) return this.sponsorId;
|
|
1156
1172
|
const fromSlot = typeof Vio.campaignForSlot === "function" ? Number(Vio.campaignForSlot(this.effectiveSlot || null, { campaignId: this.slotRegistration.campaignHint })?.primarySponsor?.id) : NaN;
|
|
@@ -1188,7 +1204,7 @@ var VioProductCarousel = class extends LitElement {
|
|
|
1188
1204
|
}
|
|
1189
1205
|
const fetched = await Promise.all(
|
|
1190
1206
|
Array.from(bySponsor.entries()).map(async ([sponsorId2, ids]) => {
|
|
1191
|
-
const commerce = this.commerceKey && this.productRefs.trim() === "" ? Vio.commerceWithKey(this.commerceKey) : Vio.commerceFor(sponsorId2);
|
|
1207
|
+
const commerce = this.commerceKey && this.productRefs.trim() === "" ? Vio.commerceWithKey(this.commerceKey) : Vio.commerceFor(sponsorId2, { campaignId: this.commerceCampaigns(sponsorId2) });
|
|
1192
1208
|
const products = await commerce.channel.product.getByIds({
|
|
1193
1209
|
product_ids: ids,
|
|
1194
1210
|
currency: this.currency,
|
|
@@ -1541,6 +1557,21 @@ function returnCancelled(detail) {
|
|
|
1541
1557
|
emit("vio:payment-redirect-cancel", { ...detail, reason: "cancelled" });
|
|
1542
1558
|
}
|
|
1543
1559
|
|
|
1560
|
+
// src/ui/vipps-cart-payment.ts
|
|
1561
|
+
var VIPPS_CART_PAYMENT_VAR = "--vio-vipps-cart-payment";
|
|
1562
|
+
function resolveVippsCartPayment(el, own) {
|
|
1563
|
+
let fromTheme = "";
|
|
1564
|
+
if (!own) {
|
|
1565
|
+
try {
|
|
1566
|
+
fromTheme = typeof getComputedStyle === "function" ? getComputedStyle(el).getPropertyValue(VIPPS_CART_PAYMENT_VAR) : "";
|
|
1567
|
+
} catch {
|
|
1568
|
+
fromTheme = "";
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
const value = String(own || fromTheme || "").trim().replace(/^["']|["']$/g, "").toLowerCase();
|
|
1572
|
+
return value === "checkout" ? "checkout" : "express";
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1544
1575
|
// src/core/checkout/method-taxonomy.ts
|
|
1545
1576
|
function normalizeMethodName(name) {
|
|
1546
1577
|
return String(name ?? "").toLowerCase().replace(/[^a-z]/g, "");
|
|
@@ -2022,6 +2053,19 @@ function unlockPageScroll() {
|
|
|
2022
2053
|
}
|
|
2023
2054
|
|
|
2024
2055
|
// src/ui/components/vio-product-detail.ts
|
|
2056
|
+
var layoutAttribute = {
|
|
2057
|
+
fromAttribute(value) {
|
|
2058
|
+
if (value === null || value.trim() === "") return null;
|
|
2059
|
+
try {
|
|
2060
|
+
return JSON.parse(value);
|
|
2061
|
+
} catch {
|
|
2062
|
+
return value;
|
|
2063
|
+
}
|
|
2064
|
+
},
|
|
2065
|
+
toAttribute(value) {
|
|
2066
|
+
return value === null || value === void 0 ? null : JSON.stringify(value);
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
2025
2069
|
var ADDED_TOAST_MS = 8e3;
|
|
2026
2070
|
var STRIPE_LOGO_SRC = "data:image/svg+xml;utf8," + encodeURIComponent(
|
|
2027
2071
|
'<svg width="360" height="150" viewBox="0 0 360 150" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M360 77.4001C360 51.8001 347.6 31.6001 323.9 31.6001C300.1 31.6001 285.7 51.8001 285.7 77.2001C285.7 107.3 302.7 122.5 327.1 122.5C339 122.5 348 119.8 354.8 116V96.0001C348 99.4001 340.2 101.5 330.3 101.5C320.6 101.5 312 98.1001 310.9 86.3001H359.8C359.8 85.0001 360 79.8001 360 77.4001ZM310.6 67.9001C310.6 56.6001 317.5 51.9001 323.8 51.9001C329.9 51.9001 336.4 56.6001 336.4 67.9001H310.6Z" fill="#533AFD"/><path fill-rule="evenodd" clip-rule="evenodd" d="M247.1 31.6001C237.3 31.6001 231 36.2001 227.5 39.4001L226.2 33.2001H204.2V149.8L229.2 144.5L229.3 116.2C232.9 118.8 238.2 122.5 247 122.5C264.9 122.5 281.2 108.1 281.2 76.4001C281.1 47.4001 264.6 31.6001 247.1 31.6001ZM241.1 100.5C235.2 100.5 231.7 98.4001 229.3 95.8001L229.2 58.7001C231.8 55.8001 235.4 53.8001 241.1 53.8001C250.2 53.8001 256.5 64.0001 256.5 77.1001C256.5 90.5001 250.3 100.5 241.1 100.5Z" fill="#533AFD"/><path fill-rule="evenodd" clip-rule="evenodd" d="M169.8 25.7L194.9 20.3V0L169.8 5.3V25.7Z" fill="#533AFD"/><path d="M194.9 33.3H169.8V120.8H194.9V33.3Z" fill="#533AFD"/><path fill-rule="evenodd" clip-rule="evenodd" d="M142.9 40.7L141.3 33.3H119.7V120.8H144.7V61.5C150.6 53.8 160.6 55.2 163.7 56.3V33.3C160.5 32.1 148.8 29.9 142.9 40.7Z" fill="#533AFD"/><path fill-rule="evenodd" clip-rule="evenodd" d="M92.8999 11.6001L68.4999 16.8001L68.3999 96.9001C68.3999 111.7 79.4999 122.6 94.2999 122.6C102.5 122.6 108.5 121.1 111.8 119.3V99.0001C108.6 100.3 92.7999 104.9 92.7999 90.1001V54.6001H111.8V33.3001H92.7999L92.8999 11.6001Z" fill="#533AFD"/><path fill-rule="evenodd" clip-rule="evenodd" d="M25.3 58.7001C25.3 54.8001 28.5 53.3001 33.8 53.3001C41.4 53.3001 51 55.6001 58.6 59.7001V36.2001C50.3 32.9001 42.1 31.6001 33.8 31.6001C13.5 31.6001 0 42.2001 0 59.9001C0 87.5001 38 83.1001 38 95.0001C38 99.6001 34 101.1 28.4 101.1C20.1 101.1 9.5 97.7001 1.1 93.1001V116.9C10.4 120.9 19.8 122.6 28.4 122.6C49.2 122.6 63.5 112.3 63.5 94.4001C63.4 64.6001 25.3 69.9001 25.3 58.7001Z" fill="#533AFD"/></svg>'
|
|
@@ -2072,11 +2116,18 @@ var VioProductDetail = class extends LitElement {
|
|
|
2072
2116
|
this.vioContentId = "";
|
|
2073
2117
|
this.vioContentTitle = "";
|
|
2074
2118
|
this.noAddedToast = false;
|
|
2119
|
+
this.vippsCartPayment = "";
|
|
2075
2120
|
this.gallery = "";
|
|
2076
2121
|
this.descriptionMode = "";
|
|
2077
2122
|
this.highlights = [];
|
|
2078
2123
|
this.deliveryTime = "";
|
|
2079
2124
|
this.carrierLogos = {};
|
|
2125
|
+
this.layout = null;
|
|
2126
|
+
/** The layout the detail renders with now (resolved before each render). */
|
|
2127
|
+
this.layoutNow = resolveDetailLayout(null);
|
|
2128
|
+
/** The product and layout `vio:detail-layout-applied` was last said for. */
|
|
2129
|
+
this.appliedFor = null;
|
|
2130
|
+
this.unsubscribeLayout = null;
|
|
2080
2131
|
this.slotRegistration = new SlotRegistration(this, "detail");
|
|
2081
2132
|
/** What the click that opened the detail carried ('' when nothing), and for which product. */
|
|
2082
2133
|
this.eventSlot = "";
|
|
@@ -2165,6 +2216,10 @@ var VioProductDetail = class extends LitElement {
|
|
|
2165
2216
|
this.show();
|
|
2166
2217
|
void this.fetchProduct();
|
|
2167
2218
|
};
|
|
2219
|
+
/** The cart changed (another tab, the drawer): the line under Vipps counts it again. */
|
|
2220
|
+
this.boundCartChange = () => {
|
|
2221
|
+
if (this.open) this.requestUpdate();
|
|
2222
|
+
};
|
|
2168
2223
|
/** The photo in view is the active one (dots, Apple Pay sheet, events). */
|
|
2169
2224
|
this.onCarouselScroll = () => {
|
|
2170
2225
|
const track = this.carouselTrack();
|
|
@@ -2183,6 +2238,14 @@ var VioProductDetail = class extends LitElement {
|
|
|
2183
2238
|
if (atEnd !== this.thumbsAtEnd) this.thumbsAtEnd = atEnd;
|
|
2184
2239
|
};
|
|
2185
2240
|
}
|
|
2241
|
+
/**
|
|
2242
|
+
* The layout this detail applies (0.34): `{ id, revision, experimentId?,
|
|
2243
|
+
* variantId?, sections, adjusted, source }` — `source` is `element` (its own
|
|
2244
|
+
* `layout`), `global` (`Vio.configureDetail`) or `default`. A copy.
|
|
2245
|
+
*/
|
|
2246
|
+
get appliedLayout() {
|
|
2247
|
+
return copyAppliedLayout(resolveDetailLayout(this.layout));
|
|
2248
|
+
}
|
|
2186
2249
|
/** The card's context applies to the product it opened — not to one the host opened by hand later. */
|
|
2187
2250
|
get fromCard() {
|
|
2188
2251
|
return this.eventProductId !== "" && this.eventProductId === String(this.productId);
|
|
@@ -2204,6 +2267,21 @@ var VioProductDetail = class extends LitElement {
|
|
|
2204
2267
|
const own = this.slotRegistration.campaignHint;
|
|
2205
2268
|
return this.fromCard && this.eventCampaignId !== void 0 ? [this.eventCampaignId, ...own] : own;
|
|
2206
2269
|
}
|
|
2270
|
+
/**
|
|
2271
|
+
* The campaign whose channel sells the open product (one article = one
|
|
2272
|
+
* campaign = one channel): the campaign its events credit, then the opening
|
|
2273
|
+
* click's and this element's own — so the product, its rates and its
|
|
2274
|
+
* seller are read with that channel's key, the one the cart is created on.
|
|
2275
|
+
*/
|
|
2276
|
+
commerceCampaigns() {
|
|
2277
|
+
const hint = this.activeCampaignHint;
|
|
2278
|
+
try {
|
|
2279
|
+
const resolved = this.attribution().campaignId;
|
|
2280
|
+
return typeof resolved === "number" ? [resolved, ...hint] : hint;
|
|
2281
|
+
} catch {
|
|
2282
|
+
return hint;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2207
2285
|
slotAttributes() {
|
|
2208
2286
|
return {
|
|
2209
2287
|
vioSlot: this.vioSlot,
|
|
@@ -2684,6 +2762,10 @@ var VioProductDetail = class extends LitElement {
|
|
|
2684
2762
|
}
|
|
2685
2763
|
/* The sizes follow the price closely: they are the next thing to do. */
|
|
2686
2764
|
.headline + .purchase { margin-top: calc(var(--vio-detail-sizes-gap, 2px) - var(--vio-detail-info-gap, 20px)); }
|
|
2765
|
+
/* A layout with the sizes apart from the buy zone (0.34): they follow the
|
|
2766
|
+
price closely instead, and the buy zone keeps the normal gap. */
|
|
2767
|
+
.headline + .buy-options.options-apart { margin-top: calc(var(--vio-detail-sizes-gap, 2px) - var(--vio-detail-info-gap, 20px)); }
|
|
2768
|
+
.headline + .purchase.options-apart { margin-top: 0; }
|
|
2687
2769
|
.price {
|
|
2688
2770
|
font-size: var(--vio-detail-price-size, 24px);
|
|
2689
2771
|
font-weight: var(--vio-detail-price-weight, 700);
|
|
@@ -3175,6 +3257,9 @@ var VioProductDetail = class extends LitElement {
|
|
|
3175
3257
|
}
|
|
3176
3258
|
connectedCallback() {
|
|
3177
3259
|
super.connectedCallback();
|
|
3260
|
+
Vio.cart.addEventListener("change", this.boundCartChange);
|
|
3261
|
+
this.unsubscribeLayout?.();
|
|
3262
|
+
this.unsubscribeLayout = onGlobalDetailLayoutChange(() => this.requestUpdate());
|
|
3178
3263
|
this.slotRegistration.connect(this.slotAttributes());
|
|
3179
3264
|
void this.loadVippsButton();
|
|
3180
3265
|
document.addEventListener("vio:product-click", this.boundProductClick);
|
|
@@ -3183,8 +3268,11 @@ var VioProductDetail = class extends LitElement {
|
|
|
3183
3268
|
if (this.addedToastTimer) clearTimeout(this.addedToastTimer);
|
|
3184
3269
|
this.addedToastTimer = null;
|
|
3185
3270
|
document.removeEventListener("vio:product-click", this.boundProductClick);
|
|
3271
|
+
Vio.cart.removeEventListener("change", this.boundCartChange);
|
|
3186
3272
|
this.slotRegistration.clear();
|
|
3187
3273
|
this.bottomSheet.disconnect();
|
|
3274
|
+
this.unsubscribeLayout?.();
|
|
3275
|
+
this.unsubscribeLayout = null;
|
|
3188
3276
|
super.disconnectedCallback();
|
|
3189
3277
|
}
|
|
3190
3278
|
updated(changed) {
|
|
@@ -3208,17 +3296,38 @@ var VioProductDetail = class extends LitElement {
|
|
|
3208
3296
|
else this.revealActiveSlide();
|
|
3209
3297
|
}
|
|
3210
3298
|
this.measureLogo();
|
|
3299
|
+
this.announceLayout();
|
|
3211
3300
|
if (changed.has("vioSlot") || changed.has("vioSlotName") || changed.has("vioScope") || changed.has("vioScopeName") || changed.has("vioCampaign")) {
|
|
3212
3301
|
this.slotRegistration.sync(this.slotAttributes());
|
|
3213
3302
|
}
|
|
3214
3303
|
}
|
|
3215
3304
|
willUpdate(changed) {
|
|
3305
|
+
this.layoutNow = resolveDetailLayout(this.layout);
|
|
3216
3306
|
if (changed.has("gallery") || changed.has("open") && this.open) this.galleryMode = this.resolveGalleryMode();
|
|
3217
3307
|
if (changed.has("descriptionMode") || changed.has("open") && this.open) {
|
|
3218
3308
|
const value = this.themeChoice(this.descriptionMode, "--vio-detail-description-mode");
|
|
3219
3309
|
this.resolvedDescriptionMode = value === "folded" || value === "open" ? value : "preview";
|
|
3220
3310
|
}
|
|
3221
3311
|
}
|
|
3312
|
+
/**
|
|
3313
|
+
* `vio:detail-layout-applied` (bubbles, composed), with the applied layout,
|
|
3314
|
+
* each time a product renders with a layout it has not been shown with yet:
|
|
3315
|
+
* every open of a product, and every change of layout while it is open.
|
|
3316
|
+
*/
|
|
3317
|
+
announceLayout() {
|
|
3318
|
+
const product = this.product;
|
|
3319
|
+
if (!product || this.fetchError) return;
|
|
3320
|
+
const signature = layoutSignature(this.layoutNow);
|
|
3321
|
+
if (this.appliedFor && this.appliedFor.product === product && this.appliedFor.signature === signature) return;
|
|
3322
|
+
this.appliedFor = { product, signature };
|
|
3323
|
+
this.dispatchEvent(
|
|
3324
|
+
new CustomEvent("vio:detail-layout-applied", {
|
|
3325
|
+
bubbles: true,
|
|
3326
|
+
composed: true,
|
|
3327
|
+
detail: { ...copyAppliedLayout(this.layoutNow), productId: product.id, sponsorId: this.sponsorId }
|
|
3328
|
+
})
|
|
3329
|
+
);
|
|
3330
|
+
}
|
|
3222
3331
|
/** An option as the element says it, else as the theme's custom property says it (lower case, unquoted). */
|
|
3223
3332
|
themeChoice(own, cssVar) {
|
|
3224
3333
|
const fromTheme = typeof getComputedStyle === "function" ? getComputedStyle(this).getPropertyValue(cssVar) : "";
|
|
@@ -3319,7 +3428,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
3319
3428
|
try {
|
|
3320
3429
|
const activeCurrency = getGlobalCurrency() || this.currency;
|
|
3321
3430
|
this.currency = activeCurrency;
|
|
3322
|
-
const commerce = Vio.commerceFor(this.sponsorId);
|
|
3431
|
+
const commerce = Vio.commerceFor(this.sponsorId, { campaignId: this.commerceCampaigns() });
|
|
3323
3432
|
products = await commerce.channel.product.getByIds({
|
|
3324
3433
|
product_ids: [productIdNum],
|
|
3325
3434
|
currency: activeCurrency,
|
|
@@ -3348,10 +3457,17 @@ var VioProductDetail = class extends LitElement {
|
|
|
3348
3457
|
const price = Number(
|
|
3349
3458
|
this.product.price?.amount_incl_taxes ?? this.product.price?.amount
|
|
3350
3459
|
);
|
|
3460
|
+
const shown = layoutOriginOf(resolveDetailLayout(this.layout));
|
|
3351
3461
|
Vio.analytics.track("view_item", {
|
|
3352
3462
|
context: {
|
|
3353
3463
|
sponsorId: this.sponsorId > 0 ? Number(this.sponsorId) : void 0,
|
|
3354
|
-
...this.attribution()
|
|
3464
|
+
...this.attribution(),
|
|
3465
|
+
...shown.layoutId ? {
|
|
3466
|
+
layoutId: shown.layoutId,
|
|
3467
|
+
layoutRevision: shown.layoutRevision ?? "",
|
|
3468
|
+
experimentId: shown.experimentId,
|
|
3469
|
+
variantId: shown.variantId
|
|
3470
|
+
} : {}
|
|
3355
3471
|
},
|
|
3356
3472
|
commerce: {
|
|
3357
3473
|
items: [
|
|
@@ -3682,7 +3798,8 @@ var VioProductDetail = class extends LitElement {
|
|
|
3682
3798
|
this.selectionPrompt = missing.name;
|
|
3683
3799
|
void this.updateComplete.then(() => {
|
|
3684
3800
|
const group = this.renderRoot.querySelector(".option-group.needs-choice");
|
|
3685
|
-
group?.
|
|
3801
|
+
const apart = !!group?.closest(".options-apart");
|
|
3802
|
+
group?.scrollIntoView?.({ behavior: "smooth", block: apart ? "center" : "nearest" });
|
|
3686
3803
|
});
|
|
3687
3804
|
return false;
|
|
3688
3805
|
}
|
|
@@ -3752,13 +3869,14 @@ var VioProductDetail = class extends LitElement {
|
|
|
3752
3869
|
const variant = this.selectedVariant();
|
|
3753
3870
|
const sponsorName = resolveSponsorIdentity(this.sponsorId)?.name || void 0;
|
|
3754
3871
|
const { campaignId, slot, contentId, componentTemplateId, contentUrl, contentTitle } = this.attribution();
|
|
3872
|
+
const layout = layoutOriginOf(this.layoutNow);
|
|
3755
3873
|
Vio.cart.addProduct({
|
|
3756
3874
|
product: this.product,
|
|
3757
3875
|
sponsorId: this.sponsorId,
|
|
3758
3876
|
sponsorName,
|
|
3759
3877
|
quantity: this.quantity,
|
|
3760
3878
|
variantId: variant?.id,
|
|
3761
|
-
origin: { campaignId, slot, contentId, componentKind: componentTemplateId, contentUrl, contentTitle }
|
|
3879
|
+
origin: { campaignId, slot, contentId, componentKind: componentTemplateId, contentUrl, contentTitle, ...layout }
|
|
3762
3880
|
});
|
|
3763
3881
|
return variant?.id;
|
|
3764
3882
|
}
|
|
@@ -3777,7 +3895,9 @@ var VioProductDetail = class extends LitElement {
|
|
|
3777
3895
|
sponsorId: this.sponsorId,
|
|
3778
3896
|
quantity: this.quantity,
|
|
3779
3897
|
variantId,
|
|
3780
|
-
...this.attribution()
|
|
3898
|
+
...this.attribution(),
|
|
3899
|
+
// The detail layout of the add (0.34) — `variantId` above is the product's.
|
|
3900
|
+
...this.layoutNow.source !== "default" ? { layout: layoutOriginOf(this.layoutNow) } : {}
|
|
3781
3901
|
}
|
|
3782
3902
|
})
|
|
3783
3903
|
);
|
|
@@ -3890,7 +4010,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
3890
4010
|
if (!this.product || this.availableQuantity <= 0 || this.adding) return;
|
|
3891
4011
|
if (!this.requireSelection()) return;
|
|
3892
4012
|
if (!(this.unitPrice > 0)) return;
|
|
3893
|
-
if (
|
|
4013
|
+
if (this.cartHasLines() && this.vippsCartMode() === "checkout") {
|
|
3894
4014
|
this.addCurrentToCart();
|
|
3895
4015
|
this.close();
|
|
3896
4016
|
this.openCheckoutWithVipps();
|
|
@@ -3902,12 +4022,46 @@ var VioProductDetail = class extends LitElement {
|
|
|
3902
4022
|
void this.startVippsExpressOrCheckout(redirect);
|
|
3903
4023
|
}
|
|
3904
4024
|
/**
|
|
3905
|
-
* The Vipps button will open the app with Express
|
|
3906
|
-
* brand has Express on, and this brand's cart is
|
|
3907
|
-
*
|
|
4025
|
+
* The Vipps button will open the app with Express for this product alone
|
|
4026
|
+
* (see buyWithVipps): the brand has Express on, and this brand's cart is
|
|
4027
|
+
* empty.
|
|
3908
4028
|
*/
|
|
3909
4029
|
vippsGoesStraightToApp() {
|
|
3910
|
-
return this.vippsExpress &&
|
|
4030
|
+
return this.vippsExpress && !this.cartHasLines();
|
|
4031
|
+
}
|
|
4032
|
+
/** This brand's cart already has lines. */
|
|
4033
|
+
cartHasLines() {
|
|
4034
|
+
return (Vio.cart.getCart(this.sponsorId)?.items.length ?? 0) > 0;
|
|
4035
|
+
}
|
|
4036
|
+
/** `vipps-cart-payment`, else the theme's, else `express`. */
|
|
4037
|
+
vippsCartMode() {
|
|
4038
|
+
return resolveVippsCartPayment(this, this.vippsCartPayment);
|
|
4039
|
+
}
|
|
4040
|
+
/**
|
|
4041
|
+
* What the Vipps button will pay when the brand's cart already has lines
|
|
4042
|
+
* (`express` mode): every unit in the cart plus this product at the chosen
|
|
4043
|
+
* quantity, and their total, as the cart sums it (shipping is chosen in
|
|
4044
|
+
* Vipps). null with an empty cart, or in `checkout` mode.
|
|
4045
|
+
*/
|
|
4046
|
+
wholeCartToPay() {
|
|
4047
|
+
if (this.vippsCartMode() !== "express") return null;
|
|
4048
|
+
const cart = Vio.cart.getCart(this.sponsorId);
|
|
4049
|
+
const items = cart?.items ?? [];
|
|
4050
|
+
if (items.length === 0) return null;
|
|
4051
|
+
const units = items.reduce((n, i) => n + (Number(i.quantity) || 0), 0) + this.quantity;
|
|
4052
|
+
const total = items.reduce((sum, i) => sum + (Number(i.unitPrice) || 0) * (Number(i.quantity) || 0), 0) + this.unitPrice * this.quantity;
|
|
4053
|
+
return { units, total, currency: cart?.currency || this.currency };
|
|
4054
|
+
}
|
|
4055
|
+
/** The line under the Vipps button: what is paid (a cart with lines) or what happens in the app (Express, empty cart). */
|
|
4056
|
+
renderVippsNote() {
|
|
4057
|
+
const whole = this.wholeCartToPay();
|
|
4058
|
+
if (whole) {
|
|
4059
|
+
return html`<p class="vipps-note vipps-note-cart" part="vipps-note">Betaler hele handlekurven · ${whole.units} varer · ${formatPrice(whole.total, whole.currency)}</p>`;
|
|
4060
|
+
}
|
|
4061
|
+
if (this.vippsGoesStraightToApp()) {
|
|
4062
|
+
return html`<p class="vipps-note" part="vipps-note">Vipps fyller inn navn og adresse – du godkjenner og betaler i appen</p>`;
|
|
4063
|
+
}
|
|
4064
|
+
return "";
|
|
3911
4065
|
}
|
|
3912
4066
|
async startVippsExpressOrCheckout(redirect) {
|
|
3913
4067
|
let fallback = true;
|
|
@@ -3982,8 +4136,8 @@ var VioProductDetail = class extends LitElement {
|
|
|
3982
4136
|
* after an await, so it cannot wait for the server's cart), while the
|
|
3983
4137
|
* charge is the sponsor's WHOLE cart. So the sheet opens only when it shows
|
|
3984
4138
|
* what will be charged: an empty cart, and a sheet prepared for this
|
|
3985
|
-
* product × quantity. Otherwise — lines already in the cart
|
|
3986
|
-
*
|
|
4139
|
+
* product × quantity. Otherwise — lines already in the cart, or a quantity
|
|
4140
|
+
* whose sheet is still being prepared —
|
|
3987
4141
|
* the product is added and the checkout opens with Apple Pay preselected:
|
|
3988
4142
|
* every line and the total on screen, and its own Apple Pay button pays
|
|
3989
4143
|
* that total.
|
|
@@ -4019,7 +4173,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
4019
4173
|
async loadShippingFrom(productId, seq) {
|
|
4020
4174
|
let rates = null;
|
|
4021
4175
|
try {
|
|
4022
|
-
const product = Vio.commerceFor(this.sponsorId).channel.product;
|
|
4176
|
+
const product = Vio.commerceFor(this.sponsorId, { campaignId: this.commerceCampaigns() }).channel.product;
|
|
4023
4177
|
rates = typeof product.getShippingRates === "function" ? await product.getShippingRates(productId, { currency: this.currency }) : null;
|
|
4024
4178
|
} catch {
|
|
4025
4179
|
rates = null;
|
|
@@ -4135,7 +4289,12 @@ var VioProductDetail = class extends LitElement {
|
|
|
4135
4289
|
*/
|
|
4136
4290
|
renderShippingReturns() {
|
|
4137
4291
|
const identity = resolveSponsorIdentity(this.sponsorId);
|
|
4138
|
-
const rates = this.shippingRates
|
|
4292
|
+
const rates = shippingRatesShown(this.shippingRates, [
|
|
4293
|
+
this.product?.title,
|
|
4294
|
+
this.product?.brand,
|
|
4295
|
+
this.sellerName,
|
|
4296
|
+
identity?.name
|
|
4297
|
+
]);
|
|
4139
4298
|
const times = [...new Set(rates.map((r) => r.description).filter(Boolean))];
|
|
4140
4299
|
const perRateTime = times.length > 1;
|
|
4141
4300
|
const sharedTime = times.length === 1 ? times[0] : times.length === 0 && this.deliveryTime.trim() ? `Leveringstid: ${this.deliveryTime.trim()}` : "";
|
|
@@ -4188,7 +4347,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
4188
4347
|
async loadSeller(productId, seq) {
|
|
4189
4348
|
let name = null;
|
|
4190
4349
|
try {
|
|
4191
|
-
name = await Vio.commerceFor(this.sponsorId).channel.product.getSellerCompany(productId);
|
|
4350
|
+
name = await Vio.commerceFor(this.sponsorId, { campaignId: this.commerceCampaigns() }).channel.product.getSellerCompany(productId);
|
|
4192
4351
|
} catch {
|
|
4193
4352
|
name = null;
|
|
4194
4353
|
}
|
|
@@ -4283,9 +4442,6 @@ var VioProductDetail = class extends LitElement {
|
|
|
4283
4442
|
}
|
|
4284
4443
|
if (!this.product) return html``;
|
|
4285
4444
|
const p = this.product;
|
|
4286
|
-
const stock = this.stockLabel();
|
|
4287
|
-
const compare = this.compareAt;
|
|
4288
|
-
const showCompare = compare !== null && compare > this.unitPrice;
|
|
4289
4445
|
const images = this.allImages();
|
|
4290
4446
|
const activeImage = this.activeImage;
|
|
4291
4447
|
return html`
|
|
@@ -4330,24 +4486,110 @@ var VioProductDetail = class extends LitElement {
|
|
|
4330
4486
|
</div>`}
|
|
4331
4487
|
|
|
4332
4488
|
<div class="info" part="info">
|
|
4333
|
-
${
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4489
|
+
${this.renderSections(this.layoutNow.sections)}
|
|
4490
|
+
</div>
|
|
4491
|
+
</div>
|
|
4492
|
+
`;
|
|
4493
|
+
}
|
|
4494
|
+
/**
|
|
4495
|
+
* The info column in the applied layout's order (0.34) — the real DOM in
|
|
4496
|
+
* that order, never CSS `order`, the same on every screen. The default
|
|
4497
|
+
* order renders exactly the column before 0.34: brand, `.headline` (the
|
|
4498
|
+
* title row with the stock, the price row), then `.purchase` — `.buy` with
|
|
4499
|
+
* the options first — and highlights, description, «Frakt & retur» in it.
|
|
4500
|
+
*
|
|
4501
|
+
* A run of `title` / `stock` / `price` is one `.headline`; `title`
|
|
4502
|
+
* right before `stock` share the title row. `options` right before
|
|
4503
|
+
* `purchase` live in `.buy` (a pinned buy zone keeps them); elsewhere they
|
|
4504
|
+
* are a block of their own. Everything after `purchase` goes in
|
|
4505
|
+
* `.purchase`, as the description does by default: a pinned buy zone may
|
|
4506
|
+
* slide over it, never over what comes before.
|
|
4507
|
+
*/
|
|
4508
|
+
renderSections(sections) {
|
|
4509
|
+
const out = [];
|
|
4510
|
+
for (let i = 0; i < sections.length; i++) {
|
|
4511
|
+
const s = sections[i];
|
|
4512
|
+
if (s === "title" || s === "stock" || s === "price") {
|
|
4513
|
+
let j = i;
|
|
4514
|
+
while (j < sections.length && ["title", "stock", "price"].includes(sections[j])) j++;
|
|
4515
|
+
out.push(this.renderHeadline(sections.slice(i, j)));
|
|
4516
|
+
i = j - 1;
|
|
4517
|
+
continue;
|
|
4518
|
+
}
|
|
4519
|
+
if (s === "options" && sections[i + 1] === "purchase") continue;
|
|
4520
|
+
if (s === "purchase") {
|
|
4521
|
+
const optionsInBuy = sections[i - 1] === "options";
|
|
4522
|
+
out.push(this.renderPurchase(optionsInBuy, sections.slice(i + 1)));
|
|
4523
|
+
break;
|
|
4524
|
+
}
|
|
4525
|
+
out.push(this.renderSection(s));
|
|
4526
|
+
}
|
|
4527
|
+
return out;
|
|
4528
|
+
}
|
|
4529
|
+
/** A run of title / stock / price: one `.headline`. */
|
|
4530
|
+
renderHeadline(run) {
|
|
4531
|
+
const p = this.product;
|
|
4532
|
+
const stock = this.stockLabel();
|
|
4533
|
+
const compare = this.compareAt;
|
|
4534
|
+
const showCompare = compare !== null && compare > this.unitPrice;
|
|
4535
|
+
const name = html`<h2 class="name" part="title">${p.title}</h2>`;
|
|
4536
|
+
const stockLine = html`<div class="stock ${stock.cls}" part="stock">${stock.text}</div>`;
|
|
4537
|
+
const parts = [];
|
|
4538
|
+
for (let i = 0; i < run.length; i++) {
|
|
4539
|
+
const s = run[i];
|
|
4540
|
+
if (s === "title" && run[i + 1] === "stock") {
|
|
4541
|
+
parts.push(html`<div class="title-row">
|
|
4542
|
+
${name}
|
|
4543
|
+
${stockLine}
|
|
4544
|
+
</div>`);
|
|
4545
|
+
i++;
|
|
4546
|
+
} else if (s === "title") {
|
|
4547
|
+
parts.push(html`<div class="title-row">${name}</div>`);
|
|
4548
|
+
} else if (s === "stock") {
|
|
4549
|
+
parts.push(stockLine);
|
|
4550
|
+
} else {
|
|
4551
|
+
parts.push(html`<div class="price-row">
|
|
4340
4552
|
<span class="price" part="price">${formatPrice(this.unitPrice, p.price.currency_code)}</span>
|
|
4341
4553
|
${showCompare ? html`<span class="compare-at">${formatPrice(
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
</div
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4554
|
+
compare,
|
|
4555
|
+
p.price.currency_code
|
|
4556
|
+
)}</span>` : ""}
|
|
4557
|
+
</div>`);
|
|
4558
|
+
}
|
|
4559
|
+
}
|
|
4560
|
+
return html`<div class="headline">
|
|
4561
|
+
${parts}
|
|
4562
|
+
</div>`;
|
|
4563
|
+
}
|
|
4564
|
+
/** One section that is not the headline nor the purchase group. */
|
|
4565
|
+
renderSection(section) {
|
|
4566
|
+
const p = this.product;
|
|
4567
|
+
switch (section) {
|
|
4568
|
+
case "brand":
|
|
4569
|
+
return p.brand ? html`<div class="brand" part="brand">${p.brand}</div>` : "";
|
|
4570
|
+
case "options":
|
|
4571
|
+
return p.options.length > 0 ? html`<div class="buy-options options-apart" part="buy-options">${this.renderOptionPickers(p.options)}</div>` : "";
|
|
4572
|
+
case "highlights":
|
|
4573
|
+
return this.renderHighlights();
|
|
4574
|
+
case "description":
|
|
4575
|
+
return p.description ? this.renderDescription(this.stripHtml(p.description)) : "";
|
|
4576
|
+
case "shippingReturns":
|
|
4577
|
+
return this.renderShippingReturns();
|
|
4578
|
+
default:
|
|
4579
|
+
return "";
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
/**
|
|
4583
|
+
* The SDK-managed buy group, never split: «Frakt fra…», Vipps / Apple Pay /
|
|
4584
|
+
* the other ways to pay, quantity + «Legg i handlekurv», «Du handler direkte
|
|
4585
|
+
* hos …». The options when they come right before it; then what follows it.
|
|
4586
|
+
*/
|
|
4587
|
+
renderPurchase(optionsInBuy, rest) {
|
|
4588
|
+
const p = this.product;
|
|
4589
|
+
const optionsApart = !optionsInBuy && p.options.length > 0;
|
|
4590
|
+
return html`<div class=${optionsApart ? "purchase options-apart" : "purchase"}>
|
|
4349
4591
|
<div class="buy" part="buy">
|
|
4350
|
-
${p.options.length > 0 ? html`<div class="buy-options" part="buy-options">${this.renderOptionPickers(p.options)}</div>` : ""}
|
|
4592
|
+
${optionsInBuy && p.options.length > 0 ? html`<div class="buy-options" part="buy-options">${this.renderOptionPickers(p.options)}</div>` : ""}
|
|
4351
4593
|
${this.renderDeliveryNote()}
|
|
4352
4594
|
${this.methodsPending && this.availableQuantity > 0 ? html`<div class="buy-pending" part="buy-pending" role="status" aria-label="Laster betalingsmåter"></div>` : ""}
|
|
4353
4595
|
${this.availableQuantity > 0 && this.hasPrice && this.methodEnabled("vipps") ? this.vippsOfficial ? html`
|
|
@@ -4376,7 +4618,7 @@ var VioProductDetail = class extends LitElement {
|
|
|
4376
4618
|
<span class="vipps-badge">vipps</span>
|
|
4377
4619
|
</button>
|
|
4378
4620
|
` : ""}
|
|
4379
|
-
${this.availableQuantity > 0 && this.hasPrice && this.methodEnabled("vipps")
|
|
4621
|
+
${this.availableQuantity > 0 && this.hasPrice && this.methodEnabled("vipps") ? this.renderVippsNote() : ""}
|
|
4380
4622
|
|
|
4381
4623
|
<div class="qty-cta-row" part="quantity-row">
|
|
4382
4624
|
<div class="qty-stepper">
|
|
@@ -4464,14 +4706,8 @@ var VioProductDetail = class extends LitElement {
|
|
|
4464
4706
|
${this.renderSellerNote()}
|
|
4465
4707
|
</div>
|
|
4466
4708
|
|
|
4467
|
-
${this.
|
|
4468
|
-
|
|
4469
|
-
${p.description ? this.renderDescription(this.stripHtml(p.description)) : ""}
|
|
4470
|
-
${this.renderShippingReturns()}
|
|
4471
|
-
</div>
|
|
4472
|
-
</div>
|
|
4473
|
-
</div>
|
|
4474
|
-
`;
|
|
4709
|
+
${this.renderSections(rest)}
|
|
4710
|
+
</div>`;
|
|
4475
4711
|
}
|
|
4476
4712
|
renderOptionPickers(options) {
|
|
4477
4713
|
if (options.length === 0) return "";
|
|
@@ -4555,6 +4791,9 @@ __decorateClass([
|
|
|
4555
4791
|
__decorateClass([
|
|
4556
4792
|
property({ type: Boolean, attribute: "no-added-toast" })
|
|
4557
4793
|
], VioProductDetail.prototype, "noAddedToast", 2);
|
|
4794
|
+
__decorateClass([
|
|
4795
|
+
property({ type: String, attribute: "vipps-cart-payment" })
|
|
4796
|
+
], VioProductDetail.prototype, "vippsCartPayment", 2);
|
|
4558
4797
|
__decorateClass([
|
|
4559
4798
|
property({ type: String })
|
|
4560
4799
|
], VioProductDetail.prototype, "gallery", 2);
|
|
@@ -4570,6 +4809,9 @@ __decorateClass([
|
|
|
4570
4809
|
__decorateClass([
|
|
4571
4810
|
property({ type: Object, attribute: "carrier-logos" })
|
|
4572
4811
|
], VioProductDetail.prototype, "carrierLogos", 2);
|
|
4812
|
+
__decorateClass([
|
|
4813
|
+
property({ attribute: "layout", converter: layoutAttribute })
|
|
4814
|
+
], VioProductDetail.prototype, "layout", 2);
|
|
4573
4815
|
__decorateClass([
|
|
4574
4816
|
state()
|
|
4575
4817
|
], VioProductDetail.prototype, "product", 2);
|
|
@@ -4657,6 +4899,9 @@ function normalizeValues(raw) {
|
|
|
4657
4899
|
}
|
|
4658
4900
|
return [];
|
|
4659
4901
|
}
|
|
4902
|
+
function shippingRatesShown(rates, repeats = []) {
|
|
4903
|
+
return rates.map((r) => ({ ...r, description: shippingDescriptionOf(r.description, [r.name, ...repeats]) }));
|
|
4904
|
+
}
|
|
4660
4905
|
function splitRateName(name) {
|
|
4661
4906
|
const text = String(name ?? "").trim();
|
|
4662
4907
|
const m = text.match(/^(.+?)\s+[-–—]\s+(.+)$/);
|
|
@@ -4693,12 +4938,15 @@ var VioCart = class extends LitElement {
|
|
|
4693
4938
|
this.heading = "Handlekurv";
|
|
4694
4939
|
this.emptyLabel = "Handlekurven er tom";
|
|
4695
4940
|
this.subtotalLabel = "Sum";
|
|
4941
|
+
this.vippsCartPayment = "";
|
|
4696
4942
|
this.carts = /* @__PURE__ */ new Map();
|
|
4697
4943
|
this.itemCount = 0;
|
|
4698
4944
|
this.applePayAvailable = false;
|
|
4699
4945
|
this.availableMethods = null;
|
|
4700
4946
|
this.methodsLoading = false;
|
|
4701
4947
|
this.vippsOfficial = false;
|
|
4948
|
+
/** A Vipps payment is being started from here: one at a time. */
|
|
4949
|
+
this.vippsStarting = false;
|
|
4702
4950
|
/** Whether the method lookup has been attempted — see boundOnCartChange. */
|
|
4703
4951
|
this.paymentMethodsAttempted = false;
|
|
4704
4952
|
this.confirmedOrder = null;
|
|
@@ -5274,7 +5522,6 @@ var VioCart = class extends LitElement {
|
|
|
5274
5522
|
})
|
|
5275
5523
|
);
|
|
5276
5524
|
}
|
|
5277
|
-
/** Vipps — opens the checkout with Vipps preselected. */
|
|
5278
5525
|
/**
|
|
5279
5526
|
* Open the checkout without preselecting a method.
|
|
5280
5527
|
*
|
|
@@ -5296,21 +5543,73 @@ var VioCart = class extends LitElement {
|
|
|
5296
5543
|
);
|
|
5297
5544
|
}
|
|
5298
5545
|
/**
|
|
5299
|
-
* Vipps from the cart:
|
|
5300
|
-
*
|
|
5301
|
-
*
|
|
5302
|
-
*
|
|
5303
|
-
*
|
|
5546
|
+
* Vipps from the cart (2026-10-29: «el botón negro va con el nuestro y el
|
|
5547
|
+
* botón de Vipps paga el carrito entero»): Vipps Express for the sponsor's
|
|
5548
|
+
* WHOLE cart — the same Express as the detail's «Kjøp nå med Vipps»: the
|
|
5549
|
+
* hand-over overlay, `vio:payment-redirect-*` with source `'cart'`, the
|
|
5550
|
+
* return and its confirmation. «Til kassen» is the way into our checkout.
|
|
5551
|
+
* When the brand has Express off, or this cart cannot have it (several
|
|
5552
|
+
* suppliers, no rate), the checkout opens with Vipps preselected.
|
|
5553
|
+
*
|
|
5554
|
+
* `vipps-cart-payment="checkout"` keeps the 0.31–0.34 behaviour: the
|
|
5555
|
+
* checkout opens with Vipps preselected, the standard payment.
|
|
5304
5556
|
*/
|
|
5305
5557
|
onVipps() {
|
|
5306
5558
|
if (!this.payable) return;
|
|
5307
|
-
|
|
5308
|
-
|
|
5559
|
+
if (resolveVippsCartPayment(this, this.vippsCartPayment) === "checkout") {
|
|
5560
|
+
const firstSponsorId = [...this.carts.keys()][0];
|
|
5561
|
+
if (firstSponsorId === void 0) return;
|
|
5562
|
+
this.openCheckoutWithVipps(firstSponsorId);
|
|
5563
|
+
return;
|
|
5564
|
+
}
|
|
5565
|
+
if (this.vippsStarting) return;
|
|
5566
|
+
const sponsorId = this.vippsSponsorId();
|
|
5567
|
+
if (sponsorId === void 0) return;
|
|
5568
|
+
this.vippsStarting = true;
|
|
5569
|
+
const redirect = beginPaymentRedirect({ method: "vipps", sponsorId, source: "cart" });
|
|
5570
|
+
void this.startVippsExpressOrCheckout(sponsorId, redirect).finally(() => {
|
|
5571
|
+
this.vippsStarting = false;
|
|
5572
|
+
});
|
|
5573
|
+
}
|
|
5574
|
+
/**
|
|
5575
|
+
* The one sponsor whose cart the Vipps button pays: the first with
|
|
5576
|
+
* something to pay for. Express is built on THAT sponsor's backend cart
|
|
5577
|
+
* only — another sponsor's lines are never in it.
|
|
5578
|
+
*/
|
|
5579
|
+
vippsSponsorId() {
|
|
5580
|
+
for (const cart of this.carts.values()) {
|
|
5581
|
+
const total = cart.items.reduce((sum, i) => sum + i.unitPrice * i.quantity, 0);
|
|
5582
|
+
if (cart.items.length > 0 && total > 0) return cart.sponsorId;
|
|
5583
|
+
}
|
|
5584
|
+
return void 0;
|
|
5585
|
+
}
|
|
5586
|
+
async startVippsExpressOrCheckout(sponsorId, redirect) {
|
|
5587
|
+
let fallback = true;
|
|
5588
|
+
try {
|
|
5589
|
+
await Vio.cart.waitForCartMutations(sponsorId);
|
|
5590
|
+
if (!await Vio.checkout.getVippsExpressEnabled(sponsorId)) {
|
|
5591
|
+
redirect.abort("express-off");
|
|
5592
|
+
} else {
|
|
5593
|
+
const res = await Vio.checkout.startVippsExpress(sponsorId);
|
|
5594
|
+
fallback = !res?.payment_url;
|
|
5595
|
+
if (fallback) redirect.abort("not-started");
|
|
5596
|
+
}
|
|
5597
|
+
} catch (err) {
|
|
5598
|
+
if (typeof console !== "undefined") {
|
|
5599
|
+
console.warn("[VioCart] Vipps Express not started:", err);
|
|
5600
|
+
}
|
|
5601
|
+
redirect.fail(err instanceof Error ? err.message : String(err));
|
|
5602
|
+
}
|
|
5603
|
+
if (!fallback) return;
|
|
5604
|
+
this.openCheckoutWithVipps(sponsorId);
|
|
5605
|
+
}
|
|
5606
|
+
/** Our checkout with Vipps preselected: the host opens it on `vio:checkout-open`. */
|
|
5607
|
+
openCheckoutWithVipps(sponsorId) {
|
|
5309
5608
|
this.dispatchEvent(
|
|
5310
5609
|
new CustomEvent("vio:checkout-open", {
|
|
5311
5610
|
bubbles: true,
|
|
5312
5611
|
composed: true,
|
|
5313
|
-
detail: { sponsorId
|
|
5612
|
+
detail: { sponsorId, paymentMethod: "vipps", express: false, ...sponsorDetail(sponsorId) }
|
|
5314
5613
|
})
|
|
5315
5614
|
);
|
|
5316
5615
|
}
|
|
@@ -5578,6 +5877,9 @@ __decorateClass([
|
|
|
5578
5877
|
__decorateClass([
|
|
5579
5878
|
property({ type: String, attribute: "subtotal-label" })
|
|
5580
5879
|
], VioCart.prototype, "subtotalLabel", 2);
|
|
5880
|
+
__decorateClass([
|
|
5881
|
+
property({ type: String, attribute: "vipps-cart-payment" })
|
|
5882
|
+
], VioCart.prototype, "vippsCartPayment", 2);
|
|
5581
5883
|
__decorateClass([
|
|
5582
5884
|
state()
|
|
5583
5885
|
], VioCart.prototype, "carts", 2);
|
|
@@ -9353,5 +9655,5 @@ function registerVioElements() {
|
|
|
9353
9655
|
}
|
|
9354
9656
|
|
|
9355
9657
|
export { VioCart, VioCheckout, VioProduct, VioProductCarousel, VioProductDetail, VioTokens, applyVioTheme, registerVioElements };
|
|
9356
|
-
//# sourceMappingURL=chunk-
|
|
9357
|
-
//# sourceMappingURL=chunk-
|
|
9658
|
+
//# sourceMappingURL=chunk-F7LE5AZY.js.map
|
|
9659
|
+
//# sourceMappingURL=chunk-F7LE5AZY.js.map
|