Files
zyrarbot/frontend/src/composables/useTrackProgress.ts
T
lgooseandClaude Bot 119bff00a3 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>
2026-08-21 01:08:04 +02:00

51 lines
1.5 KiB
TypeScript

import { computed, onUnmounted, ref, watch, type Ref } from 'vue'
import type { BotStatus } from '@/types/status'
const TICK_MS = 100
/**
* Płynny pasek postępu. Backend przysyła `elapsed` raz na sekundę, więc między
* aktualizacjami dopisujemy czas lokalnie, a każdy pakiet resynchronizuje licznik.
*/
export function useTrackProgress(status: Ref<BotStatus | null>) {
const elapsed = ref(0)
const duration = ref(0)
const timer = window.setInterval(() => {
if (!status.value?.playing || !status.value.current) return
elapsed.value = duration.value > 0
? Math.min(elapsed.value + TICK_MS / 1000, duration.value)
: elapsed.value + TICK_MS / 1000
}, TICK_MS)
watch(
() => status.value?.current,
(current) => {
duration.value = current?.duration ?? 0
elapsed.value = current?.elapsed ?? 0
},
{ immediate: true, deep: true },
)
onUnmounted(() => window.clearInterval(timer))
const percent = computed(() =>
duration.value > 0 ? Math.min((elapsed.value / duration.value) * 100, 100) : 100,
)
return { elapsed, duration, percent }
}
export function formatTime(seconds: number | null | undefined): string {
if (seconds === null || seconds === undefined || Number.isNaN(seconds) || seconds < 0) {
return '0:00'
}
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const secs = Math.floor(seconds % 60).toString().padStart(2, '0')
return hours > 0
? `${hours}:${minutes.toString().padStart(2, '0')}:${secs}`
: `${minutes}:${secs}`
}