@vio-live/web-sdk 0.26.0 → 0.27.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/README.md CHANGED
@@ -453,6 +453,74 @@ confirmation screen never waits. A host with its own checkout passes `buyerRef`
453
453
  (`requireConsent` until `setConsent(true)`) `buyer_id` is not sent at all: a visit
454
454
  measured with ephemeral ids carries no stable identifier of a person.
455
455
 
456
+ ## Sponsor identity — name and logo
457
+
458
+ The elements say **who sells**: the sponsor's (brand's) display name and logo.
459
+
460
+ | Where | What it shows |
461
+ |---|---|
462
+ | `<vio-product-detail>` | a small brand header at the top of the detail — the logo (the name as its `alt`), or the name — for the sponsor the product was fetched with |
463
+ | `<vio-checkout>` header | «Du handler hos ‹logo \| name›» — the checkout's sponsor («Du har handlet hos …» over a provider's own receipt) |
464
+ | `<vio-checkout>` confirmation | «Takk for bestillingen! Du har handlet hos Careless.» next to the order number, with the logo above when there is one |
465
+ | `<vio-cart>` / carousel | the sponsor label over a sponsor's lines, the `retailer` line of a carousel's cards (by name) |
466
+
467
+ No logo → the name. A logo that fails to load → the name. Nothing known → nothing
468
+ (the product detail shows no header; the confirmation keeps «Takk for bestillingen!»
469
+ without the sentence). The marks are styled with the `--vio-*` tokens and exposed as
470
+ `part="sponsor"` (`vio-checkout::part(sponsor)`).
471
+
472
+ **One rule.** `Vio.sponsorIdentity(sponsorId, { checkoutId? })` answers
473
+ `{ id, name, logoUrl, avatarUrl } | null` — and every element uses it:
474
+
475
+ 1. the live bootstrap's sponsor blocks: the config's `primarySponsor` and
476
+ `secondarySponsors`, then every `campaigns[]` entry's primary and secondaries,
477
+ first match (a surface with no active campaign still names its channel brands);
478
+ 2. when the bootstrap does not know the id (not loaded yet, a redirect return): what
479
+ this tab remembered of the checkout — when the SDK creates a checkout it keeps
480
+ `checkoutId → { sponsorId, name, logoUrl }` in `sessionStorage`
481
+ (`vio.checkoutSponsor.v1`, the last 20 checkouts; it works, for that page,
482
+ without storage) — then the latest remembered checkout of that sponsor;
483
+ 3. the cart's `sponsorName`;
484
+ 4. `null`.
485
+
486
+ With only `{ checkoutId }` the sponsor is the one remembered for that checkout. URLs
487
+ are kept as given; an empty `logoUrl` is `null`. `sponsorIdentityFrom(bootstrap,
488
+ sponsorId)` is the pure step 1, exported from `/core`.
489
+
490
+ **From the checkout, never from the page.** In the checkout and on its confirmation
491
+ the sponsor is the **checkout's** — the cart's sponsor, the one the order is with —
492
+ from the checkout state or the return URL (`vio_sponsor`, `checkout_id`), never
493
+ `Vio.attribution()`: an article of one brand may sell another brand's product. Back
494
+ from Vipps the confirmation names the brand from the memory at once, or from the
495
+ bootstrap as soon as it lands (the thanks is shown first, the name follows).
496
+
497
+ **For hosts.** `vio:checkout-open` and `vio:payment-success` carry
498
+ `sponsor: { id, name, logoUrl }` in their detail when it can be named (the key is
499
+ absent otherwise), and `Vio.checkout.getOrderReference(checkoutId, sponsorId?)`
500
+ answers `{ orderNumber, buyerRef, sponsor? }` by the same rule. The SDK cleans its
501
+ return parameters from the URL once it has used them, so its own confirmation does
502
+ not come back on a reload — a host that wants a confirmation page that survives one
503
+ keeps the two ids in its own URL and asks again:
504
+
505
+ ```ts
506
+ // On the purchase: keep what the confirmation needs in YOUR url.
507
+ document.addEventListener('vio:payment-success', (e) => {
508
+ const d = (e as CustomEvent).detail
509
+ const checkoutId = String(d.checkoutId ?? d.orderId ?? '')
510
+ history.replaceState(null, '', `/takk?checkout=${checkoutId}&sponsor=${d.sponsorId ?? ''}`)
511
+ render(d.sponsor)
512
+ })
513
+
514
+ // On /takk (also after a reload, or in another browser):
515
+ const params = new URLSearchParams(location.search)
516
+ const ref = await Vio.checkout.getOrderReference(params.get('checkout') ?? '', Number(params.get('sponsor')) || undefined)
517
+ render(ref.sponsor, ref.orderNumber) // waits for Vio.init (up to 2 s) and the bootstrap; never throws
518
+
519
+ function render(sponsor?: { name: string; logoUrl: string | null }, orderNumber?: number | null) {
520
+ // «Takk for bestillingen! Du har handlet hos {sponsor.name}.» — the logo when sponsor.logoUrl
521
+ }
522
+ ```
523
+
456
524
  ## Theming
457
525
 
458
526
  Every component reads its colors and fonts from `--vio-*` CSS custom properties
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-67QESEV2.js.map
3
+ //# sourceMappingURL=chunk-67QESEV2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-NCP76AXW.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-67QESEV2.js"}
@@ -1,5 +1,5 @@
1
- import { Vio, __decorateClass, primaryImageUrl, displayPrice, toCampaignId, getGlobalCurrency, ensureVippsButton, formatPrice, buyerRefOf, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, gatewayHasBuyerRef, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, normalizeScope, campaignCandidates } from './chunk-5KWICUME.js';
2
- import { LitElement, css, html } from 'lit';
1
+ import { Vio, __decorateClass, primaryImageUrl, displayPrice, toCampaignId, getGlobalCurrency, ensureVippsButton, formatPrice, buyerRefOf, nexiReturnPaymentId, readNexiPending, kustomReturnOutcome, KUSTOM_RETURN_QUERY_KEYS, ADYEN_RETURN_METHOD, adyenReturnParams, ADYEN_RETURN_QUERY_KEYS, adyenReturnOutcome, gatewayHasBuyerRef, rememberedCheckoutSponsor, checkoutSponsorOf, AdyenOriginError, normalizeSlotId, autoSlotDisplayName, autoSlotId, sponsorIdentityFrom, Configuration, normalizeScope, campaignCandidates } from './chunk-HJRIPCWB.js';
2
+ import { LitElement, css, html, nothing } from 'lit';
3
3
  import { property, state, query } from 'lit/decorators.js';
4
4
 
5
5
  // src/ui/tokens.ts
@@ -705,6 +705,54 @@ __decorateClass([
705
705
  __decorateClass([
706
706
  state()
707
707
  ], VioProduct.prototype, "justAdded", 2);
708
+ function resolveSponsorIdentity(sponsorId, checkoutId) {
709
+ try {
710
+ if (typeof Vio.sponsorIdentity === "function") return Vio.sponsorIdentity(sponsorId, { checkoutId });
711
+ return sponsorIdentityFrom(Vio.bootstrapCache, sponsorId);
712
+ } catch {
713
+ return null;
714
+ }
715
+ }
716
+ function sponsorDetail(sponsorId, checkoutId) {
717
+ const sponsor = checkoutSponsorOf(resolveSponsorIdentity(sponsorId, checkoutId));
718
+ return sponsor ? { sponsor } : {};
719
+ }
720
+ var failedLogos = /* @__PURE__ */ new Set();
721
+ function usableLogo(identity) {
722
+ const url = identity?.logoUrl;
723
+ return url && !failedLogos.has(url) ? url : null;
724
+ }
725
+ function renderSponsorMark(host, identity, classes) {
726
+ if (!identity) return nothing;
727
+ const logo = usableLogo(identity);
728
+ if (logo) {
729
+ return html`<img
730
+ class=${classes.logo}
731
+ src=${logo}
732
+ alt=${identity.name}
733
+ decoding="async"
734
+ @error=${() => {
735
+ failedLogos.add(logo);
736
+ host.requestUpdate();
737
+ }}
738
+ />`;
739
+ }
740
+ return identity.name ? html`<span class=${classes.name}>${identity.name}</span>` : nothing;
741
+ }
742
+ var INIT_WAIT_MS = 1e4;
743
+ async function whenBootstrapped() {
744
+ try {
745
+ if (Vio.bootstrapCache) return true;
746
+ if (!Configuration.isInitialized) await Configuration.whenReady(INIT_WAIT_MS);
747
+ if (!Configuration.isInitialized || typeof Vio.bootstrap !== "function") return false;
748
+ await Vio.bootstrap();
749
+ return !!Vio.bootstrapCache;
750
+ } catch {
751
+ return false;
752
+ }
753
+ }
754
+
755
+ // src/ui/components/vio-product-carousel.ts
708
756
  var VioProductCarousel = class extends LitElement {
709
757
  constructor() {
710
758
  super(...arguments);
@@ -1077,7 +1125,7 @@ var VioProductCarousel = class extends LitElement {
1077
1125
  if (this.fetched && this.fetched.length > 0) {
1078
1126
  return html`${this.fetched.map(({ product: p, sponsorId }) => {
1079
1127
  const img = primaryImageUrl(p) ?? "";
1080
- const retailer = sponsorNameFromBootstrap(sponsorId) ?? p.brand ?? "";
1128
+ const retailer = resolveSponsorIdentity(sponsorId)?.name || p.brand || "";
1081
1129
  return html`
1082
1130
  <vio-product
1083
1131
  product-id=${String(p.id)}
@@ -1195,12 +1243,6 @@ __decorateClass([
1195
1243
  __decorateClass([
1196
1244
  state()
1197
1245
  ], VioProductCarousel.prototype, "fetchError", 2);
1198
- function sponsorNameFromBootstrap(sponsorId) {
1199
- const boot = Vio.bootstrapCache;
1200
- if (!boot) return void 0;
1201
- if (boot.primarySponsor?.id === sponsorId) return boot.primarySponsor.name;
1202
- return boot.secondarySponsors?.find((s) => s.id === sponsorId)?.name;
1203
- }
1204
1246
 
1205
1247
  // src/core/checkout/method-taxonomy.ts
1206
1248
  function normalizeMethodName(name) {
@@ -1701,6 +1743,29 @@ var VioProductDetail = class extends LitElement {
1701
1743
  }
1702
1744
  .gallery-thumb.active { border-color: var(--vio-color-text, #0a0a0a); }
1703
1745
 
1746
+ /* Who sells it: the sponsor's logo, or its name — small, above everything. */
1747
+ .sponsor-header {
1748
+ grid-column: 1 / -1;
1749
+ display: flex;
1750
+ align-items: center;
1751
+ min-height: 24px;
1752
+ }
1753
+ .sponsor-logo {
1754
+ display: block;
1755
+ width: auto;
1756
+ height: auto;
1757
+ max-height: 28px;
1758
+ max-width: 160px;
1759
+ object-fit: contain;
1760
+ }
1761
+ .sponsor-name {
1762
+ font-size: 12px;
1763
+ text-transform: uppercase;
1764
+ letter-spacing: var(--vio-tracking-label, 0.1em);
1765
+ color: var(--vio-color-text-secondary, #666);
1766
+ font-weight: 600;
1767
+ }
1768
+
1704
1769
  /* Info column */
1705
1770
  .info { display: flex; flex-direction: column; gap: 24px; }
1706
1771
  .brand {
@@ -2384,9 +2449,7 @@ var VioProductDetail = class extends LitElement {
2384
2449
  addCurrentToCart() {
2385
2450
  if (!this.product) return void 0;
2386
2451
  const variant = this.selectedVariant();
2387
- const sponsor = Vio.bootstrapCache?.primarySponsor;
2388
- const secondaries = Vio.bootstrapCache?.secondarySponsors ?? [];
2389
- const sponsorName = sponsor?.id === this.sponsorId ? sponsor.name : secondaries.find((s) => s.id === this.sponsorId)?.name;
2452
+ const sponsorName = resolveSponsorIdentity(this.sponsorId)?.name || void 0;
2390
2453
  const { campaignId, slot, contentId, componentTemplateId, contentUrl, contentTitle } = this.attribution();
2391
2454
  Vio.cart.addProduct({
2392
2455
  product: this.product,
@@ -2437,7 +2500,7 @@ var VioProductDetail = class extends LitElement {
2437
2500
  new CustomEvent("vio:checkout-open", {
2438
2501
  bubbles: true,
2439
2502
  composed: true,
2440
- detail: { sponsorId: this.sponsorId, paymentMethod: "klarna", express: true, ...this.attribution() }
2503
+ detail: { sponsorId: this.sponsorId, paymentMethod: "klarna", express: true, ...this.attribution(), ...sponsorDetail(this.sponsorId) }
2441
2504
  })
2442
2505
  );
2443
2506
  } finally {
@@ -2467,7 +2530,7 @@ var VioProductDetail = class extends LitElement {
2467
2530
  new CustomEvent("vio:checkout-open", {
2468
2531
  bubbles: true,
2469
2532
  composed: true,
2470
- detail: { sponsorId: this.sponsorId, express: false, ...this.attribution() }
2533
+ detail: { sponsorId: this.sponsorId, express: false, ...this.attribution(), ...sponsorDetail(this.sponsorId) }
2471
2534
  })
2472
2535
  );
2473
2536
  }
@@ -2503,7 +2566,7 @@ var VioProductDetail = class extends LitElement {
2503
2566
  new CustomEvent("vio:checkout-open", {
2504
2567
  bubbles: true,
2505
2568
  composed: true,
2506
- detail: { sponsorId: this.sponsorId, paymentMethod: "vipps", express: false, ...this.attribution() }
2569
+ detail: { sponsorId: this.sponsorId, paymentMethod: "vipps", express: false, ...this.attribution(), ...sponsorDetail(this.sponsorId) }
2507
2570
  })
2508
2571
  );
2509
2572
  }
@@ -2516,7 +2579,7 @@ var VioProductDetail = class extends LitElement {
2516
2579
  new CustomEvent("vio:checkout-open", {
2517
2580
  bubbles: true,
2518
2581
  composed: true,
2519
- detail: { sponsorId: this.sponsorId, paymentMethod: "stripe", express: false, ...this.attribution() }
2582
+ detail: { sponsorId: this.sponsorId, paymentMethod: "stripe", express: false, ...this.attribution(), ...sponsorDetail(this.sponsorId) }
2520
2583
  })
2521
2584
  );
2522
2585
  }
@@ -2556,6 +2619,21 @@ var VioProductDetail = class extends LitElement {
2556
2619
  this.sellerName = name;
2557
2620
  this.sellerSettled = true;
2558
2621
  }
2622
+ /**
2623
+ * Who sells the product: the brand of the sponsor it was fetched with —
2624
+ * its logo, with the name as `alt`. Without a logo that loads, the topbar
2625
+ * already names the seller (its Company name, else the brand), so the name
2626
+ * goes here only when the topbar names nobody once the seller is known —
2627
+ * never the same name twice. Nothing at all when no identity is known.
2628
+ */
2629
+ renderSponsorHeader() {
2630
+ const identity = resolveSponsorIdentity(this.sponsorId);
2631
+ if (!identity) return nothing;
2632
+ if (!usableLogo(identity) && (!this.sellerSettled || this.headerName())) return nothing;
2633
+ const mark = renderSponsorMark(this, identity, { logo: "sponsor-logo", name: "sponsor-name" });
2634
+ if (mark === nothing) return nothing;
2635
+ return html`<div class="sponsor-header" part="sponsor">${mark}</div>`;
2636
+ }
2559
2637
  render() {
2560
2638
  return html`
2561
2639
  <div class="backdrop" @click=${this.close}></div>
@@ -2595,6 +2673,7 @@ var VioProductDetail = class extends LitElement {
2595
2673
  const activeImage = this.activeImage;
2596
2674
  return html`
2597
2675
  <div class="body">
2676
+ ${this.renderSponsorHeader()}
2598
2677
  <div class="gallery">
2599
2678
  <div class="gallery-main">
2600
2679
  ${activeImage?.url ? html`<img src=${activeImage.url} alt=${p.title} />` : ""}
@@ -2780,8 +2859,8 @@ var VioProductDetail = class extends LitElement {
2780
2859
  })}`;
2781
2860
  }
2782
2861
  /** Best-effort HTML strip for description. */
2783
- stripHtml(html6) {
2784
- return html6.replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").trim();
2862
+ stripHtml(html7) {
2863
+ return html7.replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").trim();
2785
2864
  }
2786
2865
  };
2787
2866
  __decorateClass([
@@ -3356,6 +3435,8 @@ var VioCart = class extends LitElement {
3356
3435
  const handle = this.applePayHandle;
3357
3436
  if (!handle || !handle.available || this.itemCount === 0) return;
3358
3437
  const snapshot = this.buildConfirmation();
3438
+ const sponsorIds = [...this.carts.keys()];
3439
+ const sponsor = sponsorIds.length === 1 ? sponsorDetail(sponsorIds[0]) : {};
3359
3440
  void handle.show().then((result) => {
3360
3441
  if (!result) return;
3361
3442
  this.confirmedOrder = snapshot;
@@ -3367,7 +3448,7 @@ var VioCart = class extends LitElement {
3367
3448
  new CustomEvent("vio:payment-success", {
3368
3449
  bubbles: true,
3369
3450
  composed: true,
3370
- detail: { method: "apple-pay", result, ...buyerRef ? { buyerRef } : {} }
3451
+ detail: { method: "apple-pay", result, ...buyerRef ? { buyerRef } : {}, ...sponsor }
3371
3452
  })
3372
3453
  );
3373
3454
  });
@@ -3403,7 +3484,7 @@ var VioCart = class extends LitElement {
3403
3484
  new CustomEvent("vio:checkout-open", {
3404
3485
  bubbles: true,
3405
3486
  composed: true,
3406
- detail: { sponsorId: firstSponsorId, paymentMethod: "klarna", express: true }
3487
+ detail: { sponsorId: firstSponsorId, paymentMethod: "klarna", express: true, ...sponsorDetail(firstSponsorId) }
3407
3488
  })
3408
3489
  );
3409
3490
  }
@@ -3424,7 +3505,7 @@ var VioCart = class extends LitElement {
3424
3505
  new CustomEvent("vio:checkout-open", {
3425
3506
  bubbles: true,
3426
3507
  composed: true,
3427
- detail: { sponsorId: firstSponsorId, express: false }
3508
+ detail: { sponsorId: firstSponsorId, express: false, ...sponsorDetail(firstSponsorId) }
3428
3509
  })
3429
3510
  );
3430
3511
  }
@@ -3461,7 +3542,7 @@ var VioCart = class extends LitElement {
3461
3542
  new CustomEvent("vio:checkout-open", {
3462
3543
  bubbles: true,
3463
3544
  composed: true,
3464
- detail: { sponsorId, paymentMethod: "vipps", express: false }
3545
+ detail: { sponsorId, paymentMethod: "vipps", express: false, ...sponsorDetail(sponsorId) }
3465
3546
  })
3466
3547
  );
3467
3548
  }
@@ -3474,10 +3555,14 @@ var VioCart = class extends LitElement {
3474
3555
  new CustomEvent("vio:checkout-open", {
3475
3556
  bubbles: true,
3476
3557
  composed: true,
3477
- detail: { sponsorId: firstSponsorId, paymentMethod: "stripe", express: false }
3558
+ detail: { sponsorId: firstSponsorId, paymentMethod: "stripe", express: false, ...sponsorDetail(firstSponsorId) }
3478
3559
  })
3479
3560
  );
3480
3561
  }
3562
+ /** The name over a sponsor's lines: the brand's display name by the one rule, else what the cart kept. */
3563
+ sponsorLabel(cart) {
3564
+ return resolveSponsorIdentity(cart.sponsorId)?.name || cart.sponsorName || "";
3565
+ }
3481
3566
  get totalAcrossSponsors() {
3482
3567
  let sum = 0;
3483
3568
  for (const cart of this.carts.values()) {
@@ -3518,7 +3603,7 @@ var VioCart = class extends LitElement {
3518
3603
  ${sponsorCarts.map(
3519
3604
  (cart) => html`
3520
3605
  <div class="sponsor-group">
3521
- ${cart.sponsorName ? html`<div class="sponsor-label">${cart.sponsorName}</div>` : ""}
3606
+ ${this.sponsorLabel(cart) ? html`<div class="sponsor-label">${this.sponsorLabel(cart)}</div>` : ""}
3522
3607
  ${cart.items.map(
3523
3608
  (item) => html`
3524
3609
  <div class="item">
@@ -3755,6 +3840,9 @@ var _VioCheckout = class _VioCheckout extends LitElement {
3755
3840
  this.verifyingReturn = null;
3756
3841
  /** The checkout whose confirmation is on screen — see fillOrderNumber. */
3757
3842
  this.confirmedCheckoutId = null;
3843
+ this.orderSponsor = null;
3844
+ /** The bootstrap that names the checkout's sponsor was asked for (once per checkout) — see watchSponsorBootstrap. */
3845
+ this.sponsorBootstrapAsked = false;
3758
3846
  this.confirmedOrder = null;
3759
3847
  /** Active Klarna Payments widget handle + the subtotal it was mounted for. */
3760
3848
  this.klarnaHandle = null;
@@ -3905,6 +3993,8 @@ var _VioCheckout = class _VioCheckout extends LitElement {
3905
3993
  this.paymentNotice = null;
3906
3994
  this.verifyingReturn = null;
3907
3995
  this.confirmedCheckoutId = null;
3996
+ this.orderSponsor = null;
3997
+ this.sponsorBootstrapAsked = false;
3908
3998
  this.express = false;
3909
3999
  this.availableMethods = null;
3910
4000
  this.paymentMethodsResolved = false;
@@ -4090,6 +4180,33 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4090
4180
  font-weight: 400;
4091
4181
  margin: 0;
4092
4182
  }
4183
+ .topbar-title {
4184
+ display: flex;
4185
+ flex-direction: column;
4186
+ gap: 4px;
4187
+ min-width: 0;
4188
+ }
4189
+ /* Who the shopper buys from — the checkout's sponsor, compact under the heading. */
4190
+ .topbar-sponsor {
4191
+ margin: 0;
4192
+ display: flex;
4193
+ align-items: center;
4194
+ gap: 6px;
4195
+ font-size: 12px;
4196
+ line-height: 1.3;
4197
+ color: var(--vio-color-text-secondary, #666);
4198
+ }
4199
+ .topbar-sponsor-logo {
4200
+ display: block;
4201
+ width: auto;
4202
+ height: 18px;
4203
+ max-width: 120px;
4204
+ object-fit: contain;
4205
+ }
4206
+ .topbar-sponsor-name {
4207
+ color: var(--vio-color-text, #0a0a0a);
4208
+ font-weight: 600;
4209
+ }
4093
4210
  .close {
4094
4211
  background: none;
4095
4212
  border: none;
@@ -4419,6 +4536,23 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4419
4536
  font-weight: 400;
4420
4537
  margin: 0;
4421
4538
  }
4539
+ /* The brand the order is with: its logo over the thanks, its name in it. */
4540
+ .confirm-brand { display: flex; align-items: center; }
4541
+ .confirm-brand-logo {
4542
+ display: block;
4543
+ width: auto;
4544
+ height: auto;
4545
+ max-height: 32px;
4546
+ max-width: 160px;
4547
+ object-fit: contain;
4548
+ }
4549
+ .confirm-sponsor {
4550
+ font-size: 14px;
4551
+ line-height: 1.4;
4552
+ color: var(--vio-color-text, #0a0a0a);
4553
+ margin: 4px 0 0;
4554
+ }
4555
+ .confirm-sponsor strong { font-weight: 600; }
4422
4556
  .confirm-text {
4423
4557
  font-size: 14px;
4424
4558
  color: var(--vio-color-text-secondary, #666);
@@ -4619,6 +4753,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4619
4753
  * Vipps-specific (GetVippsStatus) return-verification paths. */
4620
4754
  applyReturnOutcome(outcome, sawStatus, vioMethod, sponsorId, checkoutId) {
4621
4755
  if (outcome === "paid") {
4756
+ this.setOrderSponsor(sponsorId, checkoutId);
4622
4757
  if (sponsorId > 0) Vio.cart.clearSponsorCart(sponsorId);
4623
4758
  this.confirmedOrder = {
4624
4759
  items: [],
@@ -4679,6 +4814,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4679
4814
  if (kustomReturn?.kind === "confirmation") {
4680
4815
  const kustomOrderId = kustomReturn.orderId;
4681
4816
  this.returningFrom = "kustom";
4817
+ this.setOrderSponsor(sponsorId, kustomReturn.checkoutId);
4682
4818
  if (!this.checkoutState) {
4683
4819
  const spIdToUse = sponsorId || [...Vio.cart.getAllCarts().keys()][0] || 0;
4684
4820
  if (spIdToUse) {
@@ -4722,6 +4858,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4722
4858
  if (!vioPayment && !checkoutId) return;
4723
4859
  if (urlParams.get("payment_processor") === "QLIRO" && checkoutId) {
4724
4860
  this.returningFrom = "qliro";
4861
+ this.setOrderSponsor(sponsorId, checkoutId);
4725
4862
  if (!this.checkoutState) {
4726
4863
  const spIdToUse = sponsorId || [...Vio.cart.getAllCarts().keys()][0] || 0;
4727
4864
  if (spIdToUse) {
@@ -4776,6 +4913,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4776
4913
  }
4777
4914
  if (urlParams.get("payment_processor") === "WALLEY" && checkoutId) {
4778
4915
  this.returningFrom = "walley";
4916
+ this.setOrderSponsor(sponsorId, checkoutId);
4779
4917
  if (!this.checkoutState) {
4780
4918
  const spIdToUse = sponsorId || [...Vio.cart.getAllCarts().keys()][0] || 0;
4781
4919
  if (spIdToUse) {
@@ -4832,6 +4970,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4832
4970
  this.cleanReturnQueryParams(ADYEN_RETURN_QUERY_KEYS);
4833
4971
  if (!adyenReturn) return;
4834
4972
  this.returningFrom = "adyen";
4973
+ this.setOrderSponsor(sponsorId, checkoutId);
4835
4974
  this.adyenSettled = true;
4836
4975
  this.autoSelectAttempted = true;
4837
4976
  if (!this.checkoutState) {
@@ -4888,6 +5027,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4888
5027
  }
4889
5028
  }
4890
5029
  }
5030
+ this.setOrderSponsor(sponsorId, checkoutId);
4891
5031
  this.open = true;
4892
5032
  this.verifyingReturn = "Bekrefter betalingen med Vipps\u2026";
4893
5033
  const { outcome, sawStatus } = await this.pollVippsStatus(checkoutId, sponsorId);
@@ -4898,6 +5038,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4898
5038
  let outcome = "pending";
4899
5039
  let sawStatus = false;
4900
5040
  if (checkoutId) {
5041
+ this.setOrderSponsor(sponsorId, checkoutId);
4901
5042
  this.open = true;
4902
5043
  this.verifyingReturn = "Bekrefter betalingen\u2026";
4903
5044
  for (const delayMs of _VioCheckout.RETURN_VERIFY_DELAYS_MS) {
@@ -4996,6 +5137,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
4996
5137
  this.unmountStripe();
4997
5138
  this.paymentError = null;
4998
5139
  }
5140
+ this.watchSponsorBootstrap();
4999
5141
  if (!this.isConnected) return;
5000
5142
  void this.mountKlarnaIfNeeded();
5001
5143
  void this.mountKustomIfNeeded();
@@ -5472,6 +5614,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5472
5614
  const email = String(this.form.email ?? "").trim();
5473
5615
  const checkoutId = returnCheckoutId || this.checkoutState?.checkoutId;
5474
5616
  const providerOrderId = r.order?.orderId != null ? String(r.order.orderId) : "";
5617
+ this.setOrderSponsor(sponsorId, checkoutId);
5475
5618
  this.confirmedOrder = {
5476
5619
  items: [...this.items],
5477
5620
  currency: this.checkoutState?.currency ?? "",
@@ -5518,13 +5661,17 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5518
5661
  */
5519
5662
  async emitPaymentSuccess(detail, checkoutId, sponsorId, afterwards) {
5520
5663
  let done = false;
5664
+ const sponsorAtStart = this.sponsorOfOrder(sponsorId, checkoutId);
5521
5665
  const finish = (buyerRef) => {
5522
5666
  if (done) return;
5523
5667
  done = true;
5668
+ const named = this.sponsorOfOrder(sponsorId, checkoutId);
5669
+ const sponsor = named.sponsor ? named : sponsorAtStart;
5670
+ const withSponsor = sponsor.sponsor ? { ...detail, ...sponsor } : detail;
5524
5671
  const event = new CustomEvent("vio:payment-success", {
5525
5672
  bubbles: true,
5526
5673
  composed: true,
5527
- detail: buyerRef ? { ...detail, buyerRef } : detail
5674
+ detail: buyerRef ? { ...withSponsor, buyerRef } : withSponsor
5528
5675
  });
5529
5676
  this.dispatchEvent(event);
5530
5677
  if (!this.isConnected && typeof window !== "undefined") {
@@ -5712,7 +5859,10 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5712
5859
  >
5713
5860
  <div class="handle" @click=${this.close} aria-hidden="true"></div>
5714
5861
  <div class="topbar">
5715
- <h2 class="heading">${this.orderConfirmed ? "Takk!" : this.heading}</h2>
5862
+ <div class="topbar-title">
5863
+ <h2 class="heading">${this.orderConfirmed ? "Takk!" : this.heading}</h2>
5864
+ ${this.renderTopbarSponsor()}
5865
+ </div>
5716
5866
  <button class="close" @click=${this.close} aria-label="Lukk">×</button>
5717
5867
  </div>
5718
5868
 
@@ -5722,6 +5872,82 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5722
5872
  </div>
5723
5873
  `;
5724
5874
  }
5875
+ /**
5876
+ * Remember whose order this is and how it is named right now, before the
5877
+ * cart that names it is cleared. Whose: the sponsor this tab remembered for
5878
+ * the checkout when it was created (exact for that checkout id), else the
5879
+ * one given (the return URL's `vio_sponsor`, the state it was paid in),
5880
+ * else the open state's — a return without `vio_sponsor` (Qliro, Walley)
5881
+ * re-opens the state with whichever cart comes first, which is a guess.
5882
+ */
5883
+ setOrderSponsor(sponsorId, checkoutId) {
5884
+ try {
5885
+ const checkout = checkoutId || void 0;
5886
+ const id = rememberedCheckoutSponsor(checkout)?.sponsorId ?? (sponsorId && sponsorId > 0 ? sponsorId : void 0) ?? this.checkoutState?.sponsorId;
5887
+ if (!id) return;
5888
+ const named = checkoutSponsorOf(resolveSponsorIdentity(id, checkout));
5889
+ const previous = this.orderSponsor;
5890
+ const snapshot = named ?? (previous && previous.sponsorId === id ? previous.snapshot : void 0);
5891
+ this.orderSponsor = { sponsorId: id, ...checkout ? { checkoutId: checkout } : {}, ...snapshot ? { snapshot } : {} };
5892
+ } catch {
5893
+ }
5894
+ }
5895
+ /**
5896
+ * Who this checkout is with, as a shopper sees it: the order being
5897
+ * confirmed / verified (`orderSponsor`), else the open checkout's own
5898
+ * sponsor (`checkoutState.sponsorId`) — named by `Vio.sponsorIdentity`,
5899
+ * which falls back to this tab's memory of the checkout and the cart; the
5900
+ * name taken before the cart was cleared last. Never the page's
5901
+ * attribution. `null` when nothing names it.
5902
+ */
5903
+ checkoutSponsorIdentity() {
5904
+ const o = this.orderSponsor;
5905
+ if (o) return checkoutSponsorOf(resolveSponsorIdentity(o.sponsorId, o.checkoutId)) ?? o.snapshot ?? null;
5906
+ const s = this.checkoutState;
5907
+ return s?.sponsorId ? checkoutSponsorOf(resolveSponsorIdentity(s.sponsorId, s.checkoutId)) ?? null : null;
5908
+ }
5909
+ /**
5910
+ * `{ sponsor }` for the payment event — the same sponsor the screen names
5911
+ * (`orderSponsor`, set by every path right before it emits): named now, else
5912
+ * as named before the cart was cleared; `{}` when nothing names it.
5913
+ */
5914
+ sponsorOfOrder(sponsorId, checkoutId) {
5915
+ try {
5916
+ const o = this.orderSponsor;
5917
+ const sameOrder = !!o && (o.checkoutId ?? void 0) === (checkoutId || void 0);
5918
+ const id = sameOrder ? o.sponsorId : sponsorId > 0 ? sponsorId : void 0;
5919
+ const live = sponsorDetail(id, checkoutId);
5920
+ if (live.sponsor) return live;
5921
+ if (sameOrder && o.snapshot) return { sponsor: o.snapshot };
5922
+ } catch {
5923
+ }
5924
+ return {};
5925
+ }
5926
+ /**
5927
+ * Ask once per checkout for the bootstrap when it is not there yet and a
5928
+ * sponsor has to be named (a redirect return renders before it), then
5929
+ * render again — the name and the logo appear when it lands.
5930
+ */
5931
+ watchSponsorBootstrap() {
5932
+ if (this.sponsorBootstrapAsked || !this.open || Vio.bootstrapCache) return;
5933
+ if (!this.orderSponsor && !this.checkoutState?.sponsorId) return;
5934
+ this.sponsorBootstrapAsked = true;
5935
+ void whenBootstrapped().then(() => this.requestUpdate());
5936
+ }
5937
+ /**
5938
+ * The checkout's sponsor in the header — «Du handler hos <logo|name>»
5939
+ * («Du har handlet hos» on a provider's receipt). Not on our own
5940
+ * confirmation, which says it in its body.
5941
+ */
5942
+ renderTopbarSponsor() {
5943
+ if (this.orderConfirmed) return nothing;
5944
+ const sponsor = this.checkoutSponsorIdentity();
5945
+ const mark = renderSponsorMark(this, sponsor, { logo: "topbar-sponsor-logo", name: "topbar-sponsor-name" });
5946
+ if (mark === nothing) return nothing;
5947
+ return html`<p class="topbar-sponsor" part="sponsor">
5948
+ <span>${this.providerReceipt ? "Du har handlet hos" : "Du handler hos"}</span> ${mark}
5949
+ </p>`;
5950
+ }
5725
5951
  /**
5726
5952
  * The provider's receipt on its own. It must not depend on the cart: the
5727
5953
  * payment step is rendered from the cart, and clearing the cart after a
@@ -5749,6 +5975,7 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5749
5975
  this.confirmedMethod = method;
5750
5976
  this.open = true;
5751
5977
  const checkoutId = returnCheckoutId || this.checkoutState?.checkoutId;
5978
+ this.setOrderSponsor(sponsorId, checkoutId);
5752
5979
  void this.emitPaymentSuccess(
5753
5980
  { method, sponsorId, result, checkoutId },
5754
5981
  checkoutId,
@@ -5777,12 +6004,17 @@ var _VioCheckout = class _VioCheckout extends LitElement {
5777
6004
  details.push(["Betalingsm\xE5te", o?.paidWith || this.methodLabel(this.confirmedMethod)]);
5778
6005
  if (o?.providerRef) details.push([o.providerRef.label, o.providerRef.value]);
5779
6006
  if (email) details.push(["Kvittering til", email]);
6007
+ const sponsor = this.checkoutSponsorIdentity();
5780
6008
  return html`
5781
6009
  <section class="confirmation">
6010
+ ${usableLogo(sponsor) ? html`<div class="confirm-brand" part="sponsor">
6011
+ ${renderSponsorMark(this, sponsor, { logo: "confirm-brand-logo", name: "confirm-brand-name" })}
6012
+ </div>` : ""}
5782
6013
  <header class="confirm-head">
5783
6014
  <div class="confirm-check" aria-hidden="true">✓</div>
5784
6015
  <div>
5785
6016
  <h3 class="confirm-title">Takk for bestillingen!</h3>
6017
+ ${sponsor?.name ? html`<p class="confirm-sponsor">Du har handlet hos <strong>${sponsor.name}</strong>.</p>` : ""}
5786
6018
  <p class="confirm-text">
5787
6019
  Betalingen er bekreftet.${email ? html` Du får en ordrebekreftelse på e-post.` : ""}
5788
6020
  </p>
@@ -7075,6 +7307,9 @@ __decorateClass([
7075
7307
  __decorateClass([
7076
7308
  state()
7077
7309
  ], _VioCheckout.prototype, "verifyingReturn", 2);
7310
+ __decorateClass([
7311
+ state()
7312
+ ], _VioCheckout.prototype, "orderSponsor", 2);
7078
7313
  __decorateClass([
7079
7314
  state()
7080
7315
  ], _VioCheckout.prototype, "confirmedOrder", 2);
@@ -7211,5 +7446,5 @@ function registerVioElements() {
7211
7446
  }
7212
7447
 
7213
7448
  export { VioCart, VioCheckout, VioProduct, VioProductCarousel, VioProductDetail, VioTokens, applyVioTheme, registerVioElements };
7214
- //# sourceMappingURL=chunk-A3LN5JEM.js.map
7215
- //# sourceMappingURL=chunk-A3LN5JEM.js.map
7449
+ //# sourceMappingURL=chunk-GLAKUYQA.js.map
7450
+ //# sourceMappingURL=chunk-GLAKUYQA.js.map