Workers P3: Reiter Freigabe mit Kopieren & öffnen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
777d5272bf
commit
f8f8df2cbd
6 files changed
+750
-4
No files matched your search
@@ -0,0 +1,65 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
|
||||
// Die Liste des Pults wird bei sichtbarem Tab alle 30 s neu geholt
|
||||
const POLL_MS = 30000
|
||||
const UNKNOWN_ERROR = 'Unbekannter Fehler'
|
||||
|
||||
const isVisible = () => document.visibilityState === 'visible'
|
||||
|
||||
// { items, loading, error, refresh }: Pult-Einträge von der Dienst-API (api.pult). `statuses` ist die Komma-Liste eines Filters aus
|
||||
// PULT_FILTERS (ein Text, kein Array: er ist der Schlüssel des Abrufs). Beim Start und bei jedem Wechsel des Filters wird sofort
|
||||
// geladen, danach alle 30 s und beim Zurückkehren in den Tab (visibilitychange), jeweils nur bei sichtbarem Tab.
|
||||
// items zeigt nie die Einträge eines anderen Filters (loading, bis die erste Antwort für diesen Filter da ist); schlägt ein
|
||||
// späterer Abruf fehl, bleiben die letzten Einträge stehen und error ist der deutsche Satz aus der API (sonst null).
|
||||
// Nur die jüngste Anfrage zählt: eine späte Antwort (auch ein später Fehler) einer älteren Anfrage, eines früheren Filters
|
||||
// oder nach dem Abbau wird verworfen. refresh() holt sofort neu (z. B. nach einer Aktion) und endet, wenn die Antwort verarbeitet ist.
|
||||
export function usePultFeed({ api, statuses }) {
|
||||
const key = Array.isArray(statuses) ? statuses.join(',') : String(statuses ?? '')
|
||||
const [state, setState] = useState({ key: null, items: [], error: null })
|
||||
const seqRef = useRef(0)
|
||||
const aliveRef = useRef(true)
|
||||
const loadRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
aliveRef.current = true
|
||||
return () => { aliveRef.current = false }
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
seqRef.current += 1
|
||||
const mine = seqRef.current
|
||||
try {
|
||||
const data = await api.pult(key)
|
||||
if (!aliveRef.current || mine !== seqRef.current) return
|
||||
setState({ key, items: Array.isArray(data?.items) ? data.items : [], error: null })
|
||||
} catch (err) {
|
||||
if (!aliveRef.current || mine !== seqRef.current) return
|
||||
// die letzten Einträge desselben Filters bleiben stehen, der Fehler kommt dazu
|
||||
setState((prev) => ({ key, items: prev.key === key ? prev.items : [], error: err?.message || UNKNOWN_ERROR }))
|
||||
}
|
||||
}
|
||||
loadRef.current = load
|
||||
|
||||
const timer = window.setInterval(() => { if (isVisible()) load() }, POLL_MS)
|
||||
const onVisibility = () => { if (isVisible()) load() }
|
||||
document.addEventListener('visibilitychange', onVisibility)
|
||||
load()
|
||||
return () => {
|
||||
seqRef.current += 1 // eine noch offene Anfrage dieses Filters zählt nicht mehr
|
||||
loadRef.current = null
|
||||
window.clearInterval(timer)
|
||||
document.removeEventListener('visibilitychange', onVisibility)
|
||||
}
|
||||
}, [api, key])
|
||||
|
||||
const refresh = useCallback(() => (loadRef.current ? loadRef.current() : Promise.resolve()), [])
|
||||
|
||||
const current = state.key === key
|
||||
return {
|
||||
items: current ? state.items : [],
|
||||
loading: !current,
|
||||
error: current ? state.error : null,
|
||||
refresh,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user