PageSourceSearch

https://littlebirdelectronics.com.au/assets/controllers/ecommerce/dispatch_countdown_controller-e92a68f7.js

js littlebirdelectronics.com.au collected 2026-09-25 14:10:23 UTC 2,223 bytes, 61 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3// Ticks the "Order within Xh Ym for same-day dispatch" line on the PDP down to
4// the day's 2pm-Sydney cutoff, then swaps to the "ships next business day"
5// message once it lapses. Stimulus connect()/disconnect() are Turbo-safe (the
6// controller (dis)connects as the element enters/leaves the DOM across Turbo
7// visits) so there is no DOMContentLoaded here.
8//
9// cutoffAt arrives as an offset-bearing ISO timestamp (e.g.
10// 2026-07-24T14:00:00+10:00), so `new Date()` resolves the correct absolute
11// instant no matter what timezone the shopper's browser is in.
12export default class extends Controller {
13  static targets = ["countdown", "timer", "lapsed"]
14  static values = { cutoffAt: String, sameDay: Boolean }
15
16  connect() {
17    // Server said we're already past the cutoff (or it's a weekend/holiday):
18    // just show the next-business-day message, nothing to tick.
19    if (!this.sameDayValue) {
20      this.showLapsed()
21      return
22    }
23    this.deadline = new Date(this.cutoffAtValue).getTime()
24    this.tick()
25    // Align to the wall clock so the seconds digit changes on the second.
26    this.timer = setInterval(() => this.tick(), 1000)
27  }
28
29  disconnect() {
30    if (this.timer) clearInterval(this.timer)
31  }
32
33  tick() {
34    const remaining = this.deadline - Date.now()
35    if (remaining <= 0) {
36      this.showLapsed()
37      if (this.timer) clearInterval(this.timer)
38      return
39    }
40    if (this.hasTimerTarget) {
41      this.timerTarget.textContent = this.format(remaining)
42    }
43  }
44
45  // Swap the same-day countdown for the next-business-day fallback. Both states
46  // are server-rendered; we only flip which is visible.
47  showLapsed() {
48    if (this.hasCountdownTarget) this.countdownTarget.classList.add("hidden")
49    if (this.hasLapsedTarget) this.lapsedTarget.classList.remove("hidden")
50  }
51
52  format(ms) {
53    const totalSeconds = Math.floor(ms / 1000)
54    const hours = Math.floor(totalSeconds / 3600)
55    const minutes = Math.floor((totalSeconds % 3600) / 60)
56    const seconds = totalSeconds % 60
57    if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`
58    if (minutes > 0) return `${minutes}m ${seconds}s`
59    return `${seconds}s`
60  }
61}

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.