mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-05-28 04:58:43 +09:00
Hello world
First open source release of Campfire 🎉
This commit is contained in:
83
app/javascript/controllers/presence_controller.js
Normal file
83
app/javascript/controllers/presence_controller.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
import { cable } from "@hotwired/turbo-rails"
|
||||
import { delay, nextFrame } from "helpers/timing_helpers"
|
||||
|
||||
const REFRESH_INTERVAL = 50 * 1000 // 50 seconds
|
||||
|
||||
// We delay transmitting visibility changes to ignore brief periods of invisibility,
|
||||
// like switching to another tab and back
|
||||
const VISIBILITY_CHANGE_DELAY = 5000 // 5 seconds
|
||||
|
||||
export default class extends Controller {
|
||||
async connect() {
|
||||
this.channel = await cable.subscribeTo({ channel: "PresenceChannel", room_id: Current.room.id }, {
|
||||
connected: this.#websocketConnected,
|
||||
disconnected: this.#websocketDisconnected
|
||||
})
|
||||
|
||||
this.wasVisible = true
|
||||
|
||||
await nextFrame()
|
||||
this.dispatch("present", { detail: { roomId: Current.room.id } })
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.#stopRefreshTimer()
|
||||
this.channel?.unsubscribe()
|
||||
}
|
||||
|
||||
visibilityChanged = () => {
|
||||
if (this.#isVisible) {
|
||||
this.#visible()
|
||||
} else {
|
||||
this.#hidden()
|
||||
}
|
||||
}
|
||||
|
||||
#websocketConnected = () => {
|
||||
this.connected = true
|
||||
this.#startRefreshTimer()
|
||||
}
|
||||
|
||||
#websocketDisconnected = () => {
|
||||
this.connected = false
|
||||
this.#stopRefreshTimer()
|
||||
}
|
||||
|
||||
#visible = async () => {
|
||||
await delay(VISIBILITY_CHANGE_DELAY)
|
||||
|
||||
if (this.connected && this.#isVisible && !this.wasVisible) {
|
||||
this.channel.send({ action: "present" })
|
||||
this.#startRefreshTimer()
|
||||
this.wasVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
#hidden = async () => {
|
||||
await delay(VISIBILITY_CHANGE_DELAY)
|
||||
|
||||
if (this.connected && this.wasVisible && !this.#isVisible) {
|
||||
this.#stopRefreshTimer()
|
||||
this.channel.send({ action: "absent" })
|
||||
this.wasVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
#startRefreshTimer = () => {
|
||||
this.refreshTimer ??= setInterval(this.#refresh, REFRESH_INTERVAL)
|
||||
}
|
||||
|
||||
#stopRefreshTimer = () => {
|
||||
clearInterval(this.refreshTimer)
|
||||
this.refreshTimer = null
|
||||
}
|
||||
|
||||
#refresh = () => {
|
||||
this.channel.send({ action: "refresh" })
|
||||
}
|
||||
|
||||
get #isVisible() {
|
||||
return document.visibilityState === "visible"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user