// Timeline controller for handling timezone conversion and animations import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["row", "time", "bar", "timestamp", "date"] static values = { mode: { type: String, default: "timeline" } // "timeline", "events", or "individual" } connect() { if (this.modeValue === "timeline") { this.maxTotal = this.calculateMaxTotal() this.updateTimeline() } else if (this.modeValue === "events") { this.updateEventsTimes() } else { this.updateIndividualTimes() } } calculateMaxTotal() { const totals = this.rowTargets.map(row => parseInt(row.dataset.total)) return Math.max(...totals, 1) } updateTimeline() { this.rowTargets.forEach((row, index) => { this.updateRow(row, index) }) } updateRow(row, index) { const timeIso = row.dataset.timeIso const total = parseInt(row.dataset.total) const timeElement = this.timeTargets.find(target => target.closest('[data-timeline-target="row"]') === row) const barElement = this.barTargets.find(target => target.closest('[data-timeline-target="row"]') === row) // Convert ISO time to local time const date = new Date(timeIso) const localTime = date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', hour12: false }) timeElement.textContent = localTime timeElement.title = date.toLocaleString(undefined, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' }) // Animate the bar width with a slight delay for each row const barWidth = Math.max((total / this.maxTotal) * 100, 5) setTimeout(() => { barElement.style.width = `${barWidth}%` }, 100 + (index * 50)) } updateEventsTimes() { this.timestampTargets.forEach(element => { const iso = element.dataset.iso if (iso) { this.convertToLocalTime(element, iso, "time") } }) this.dateTargets.forEach(element => { const iso = element.dataset.iso if (iso) { this.convertToLocalTime(element, iso, "date") } }) } updateIndividualTimes() { const iso = this.element.dataset.iso if (iso) { this.convertToLocalTime(this.element, iso, this.element.dataset.format || "both") } } convertToLocalTime(element, isoString, format) { const date = new Date(isoString) switch (format) { case "time": element.textContent = date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) element.title = date.toLocaleString(undefined, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'short' }) break case "date": element.textContent = date.toLocaleDateString(undefined, { year: 'numeric', month: '2-digit', day: '2-digit' }) element.title = date.toLocaleString(undefined, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'short' }) break case "both": element.textContent = date.toLocaleString(undefined, { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) element.title = date.toLocaleString(undefined, { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'short' }) break } } }