mirror of
https://github.com/SrIzan10/hc-harbor.git
synced 2026-05-01 10:45:21 +00:00
124 lines
3.3 KiB
JavaScript
124 lines
3.3 KiB
JavaScript
import { Controller } from "@hotwired/stimulus"
|
|
|
|
export default class extends Controller {
|
|
static targets = ["container", "count"]
|
|
static values = {
|
|
interval: { type: Number, default: 60000 }, // 60 seconds to match cron
|
|
url: String
|
|
}
|
|
|
|
connect() {
|
|
this.lastFullFetch = Date.now() // Initialize to now to prevent immediate refetch on click
|
|
this.isExpanded = false
|
|
this.startPolling()
|
|
this.boundClickHandler = this.handleClick.bind(this)
|
|
this.containerTarget.addEventListener('click', this.boundClickHandler)
|
|
}
|
|
|
|
disconnect() {
|
|
this.stopPolling()
|
|
this.containerTarget.removeEventListener('click', this.boundClickHandler)
|
|
}
|
|
|
|
handleClick(event) {
|
|
const header = event.target.closest('.currently-hacking')
|
|
if (header) {
|
|
this.toggle()
|
|
// Poll immediately when opening if we haven't fetched the list recently
|
|
if (this.isExpanded) {
|
|
const now = Date.now()
|
|
const timeSinceLastFetch = now - this.lastFullFetch
|
|
if (timeSinceLastFetch > 30000) {
|
|
this.poll()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
toggle() {
|
|
this.isExpanded = !this.isExpanded
|
|
const frame = document.getElementById("currently_hacking")
|
|
if (frame) {
|
|
frame.style.display = this.isExpanded ? 'block' : 'none'
|
|
}
|
|
}
|
|
|
|
isVisible() {
|
|
return this.isExpanded
|
|
}
|
|
|
|
startPolling() {
|
|
this.stopPolling() // Clear any existing interval
|
|
this.poll() // Initial poll
|
|
this.intervalId = setInterval(() => {
|
|
this.poll()
|
|
}, this.intervalValue)
|
|
}
|
|
|
|
stopPolling() {
|
|
if (this.intervalId) {
|
|
clearInterval(this.intervalId)
|
|
this.intervalId = null
|
|
}
|
|
}
|
|
|
|
async poll() {
|
|
try {
|
|
const includeList = this.isVisible()
|
|
const url = new URL(this.urlValue, window.location.origin)
|
|
url.searchParams.set('include_list', includeList.toString())
|
|
|
|
// Track when we request the full list, not just when we get it back
|
|
if (includeList) {
|
|
this.lastFullFetch = Date.now()
|
|
}
|
|
|
|
const response = await fetch(url, {
|
|
headers: {
|
|
"Accept": "application/json"
|
|
}
|
|
})
|
|
|
|
if (response.ok) {
|
|
const data = await response.json()
|
|
this.updateCount(data.count)
|
|
if (data.html) {
|
|
this.updateFrame(data.html)
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to poll currently hacking:", error)
|
|
}
|
|
}
|
|
|
|
updateCount(count) {
|
|
if (this.hasCountTarget) {
|
|
const plural = count === 1 ? "person" : "people"
|
|
this.countTarget.textContent = `${count} ${plural} currently hacking`
|
|
}
|
|
}
|
|
|
|
updateFrame(html) {
|
|
const frame = document.getElementById("currently_hacking")
|
|
if (frame && html) {
|
|
// Save scroll position before updating
|
|
const scrollContainer = frame.querySelector(".currently-hacking-list")
|
|
const scrollTop = scrollContainer ? scrollContainer.scrollTop : 0
|
|
|
|
// Update content
|
|
frame.innerHTML = html
|
|
frame.style.display = this.isExpanded ? 'block' : 'none'
|
|
|
|
// Restore scroll position after a brief delay to allow DOM update
|
|
if (scrollTop > 0) {
|
|
requestAnimationFrame(() => {
|
|
const newScrollContainer = frame.querySelector(".currently-hacking-list")
|
|
if (newScrollContainer) {
|
|
newScrollContainer.scrollTop = scrollTop
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|