feat(frontend): composables ze stanem panelu
Logika, która w app.js żyła w zmiennych globalnych, trafia do czterech
composables o wyraźnym zakresie odpowiedzialności:
- useBotStatus jedno połączenie WebSocket na aplikację, z licznikiem
subskrybentów i ponawianiem po zerwaniu. Flaga paused
wstrzymuje aktualizacje na czas przeciągania utworów.
- useToasts kolejka powiadomień wraz z helperem run(), który
opakowuje wywołanie API w parę komunikatów sukces/błąd.
- useTrackProgress płynny pasek postępu - między pakietami z serwera czas
dopisujemy lokalnie, a każdy pakiet resynchronizuje licznik.
- useUploads serwerowa baza plików, współdzielona przez kafelek na
pulpicie i okno z pełną listą.
Dochodzi też utils/plural.ts z polską odmianą liczebników, zamiast
powtarzanego w kilku miejscach warunku count < 5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6bfa9b2a77
commit
119bff00a3
5 files changed
+227
No files matched your search
@@ -0,0 +1,73 @@
|
||||
import { onUnmounted, ref } from 'vue'
|
||||
import type { BotStatus } from '@/types/status'
|
||||
import { useToasts } from '@/composables/useToasts'
|
||||
|
||||
const RECONNECT_DELAY_MS = 3000
|
||||
|
||||
const status = ref<BotStatus | null>(null)
|
||||
const connected = ref(false)
|
||||
/** Wstrzymuje przyjmowanie aktualizacji, gdy użytkownik przeciąga utwory. */
|
||||
const paused = ref(false)
|
||||
|
||||
let socket: WebSocket | null = null
|
||||
let reconnectTimer: number | null = null
|
||||
let connectedOnce = false
|
||||
let subscribers = 0
|
||||
|
||||
/** Jedno połączenie WebSocket na aplikację, niezależnie od liczby komponentów. */
|
||||
export function useBotStatus() {
|
||||
const { notify } = useToasts()
|
||||
|
||||
function open() {
|
||||
const scheme = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||
socket = new WebSocket(`${scheme}//${window.location.host}/ws`)
|
||||
|
||||
socket.onopen = () => {
|
||||
connected.value = true
|
||||
notify(
|
||||
connectedOnce ? 'Połączenie WebSocket przywrócone (Live)!' : 'WebSocket zsynchronizowany (Live)!',
|
||||
'success',
|
||||
)
|
||||
connectedOnce = true
|
||||
}
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
if (paused.value) return
|
||||
try {
|
||||
status.value = JSON.parse(event.data) as BotStatus
|
||||
} catch (error) {
|
||||
console.error('Błąd parsowania danych z WS:', error)
|
||||
}
|
||||
}
|
||||
|
||||
socket.onclose = () => {
|
||||
connected.value = false
|
||||
socket = null
|
||||
if (subscribers > 0) {
|
||||
reconnectTimer = window.setTimeout(open, RECONNECT_DELAY_MS)
|
||||
}
|
||||
}
|
||||
|
||||
socket.onerror = () => socket?.close()
|
||||
}
|
||||
|
||||
function connect() {
|
||||
subscribers += 1
|
||||
if (!socket) open()
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
subscribers = Math.max(0, subscribers - 1)
|
||||
if (subscribers > 0) return
|
||||
if (reconnectTimer !== null) {
|
||||
window.clearTimeout(reconnectTimer)
|
||||
reconnectTimer = null
|
||||
}
|
||||
socket?.close()
|
||||
socket = null
|
||||
}
|
||||
|
||||
onUnmounted(disconnect)
|
||||
|
||||
return { status, connected, paused, connect, disconnect }
|
||||
}
|
||||
Reference in new issue
Block a user