PageSourceSearch

https://littlebirdelectronics.com.au/assets/controllers/ecommerce/cart_prompt_controller-6d1458cf.js

js littlebirdelectronics.com.au collected 2026-09-25 14:09:48 UTC 2,497 bytes, 81 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3// The add-to-cart flyout (LBE-61).
4//
5// Two behaviours matter:
6//   * A plain "added to cart" receipt gets out of the way on its own.
7//   * A "works with" prompt (the product needs a power supply) waits for the
8//     customer, because they have to read it and decide.
9//
10// Either way it's dismissible, and dismissing a prompt is remembered for the
11// rest of the tab session so re-adding the same board doesn't nag again.
12export default class extends Controller {
13  static targets = ["panel", "prompt"]
14  static values = {
15    productId: String,
16    sticky: Boolean,
17    timeout: { type: Number, default: 5000 }
18  }
19
20  connect() {
21    // Already said no to this board's companion? Drop the upsell but keep the
22    // receipt — dismissing the prompt shouldn't cost them the confirmation that
23    // the thing they clicked went in the cart.
24    if (this.dismissed) {
25      if (this.hasPromptTarget) this.promptTarget.remove()
26      this.stickyValue = false
27    }
28
29    // Enter on the next frame so the transition actually runs — the element is
30    // inserted with its "off" classes already applied.
31    this.frame = requestAnimationFrame(() => {
32      this.panelTarget.classList.remove("translate-y-3", "opacity-0")
33    })
34
35    if (!this.stickyValue) {
36      this.timer = setTimeout(() => this.hide(), this.timeoutValue)
37    }
38  }
39
40  disconnect() {
41    cancelAnimationFrame(this.frame)
42    clearTimeout(this.timer)
43  }
44
45  dismiss() {
46    // Only remember an explicit dismissal of a prompt. Waving away a receipt
47    // says nothing about whether they want the power supply.
48    if (this.stickyValue) this.remember()
49    this.hide()
50  }
51
52  hide() {
53    clearTimeout(this.timer)
54    this.panelTarget.classList.add("translate-y-3", "opacity-0")
55    this.timer = setTimeout(() => this.element.remove(), 200)
56  }
57
58  get storageKey() {
59    return this.hasProductIdValue && this.productIdValue
60      ? `lb:accessory-prompt-dismissed:${this.productIdValue}`
61      : null
62  }
63
64  get dismissed() {
65    if (!this.stickyValue || !this.storageKey) return false
66    try {
67      return sessionStorage.getItem(this.storageKey) === "1"
68    } catch {
69      return false // private mode / storage disabled — showing it again is the safe failure
70    }
71  }
72
73  remember() {
74    if (!this.storageKey) return
75    try {
76      sessionStorage.setItem(this.storageKey, "1")
77    } catch {
78      // Nothing to do; worst case they see the prompt once more.
79    }
80  }
81}

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.