fix: Fix Svelte 5 reactivity issues in matches page and update API handling

- Fix toast notification imports: change from showToast to toast.success/error
- Remove hover preloading from app.html and Tabs component
- Fix match rounds API handling with safe parsing for incomplete data
- Fix pagination timestamp calculation (API returns Unix timestamp, not ISO string)
- Refactor matches page state management to fix reactivity issues:
  - Replace separate state variables with single matchesState object
  - Completely replace state object on updates to trigger reactivity
  - Fix infinite loop in intersection observer effect
  - Add keyed each blocks for proper list rendering
- Remove client-side filtering (temporarily) to isolate reactivity issues
- Add error state handling with nextPageTime in matches loader

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-12 23:11:50 +01:00
parent 8f21b56223
commit 05e6182bcf
7 changed files with 142 additions and 199 deletions

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { Upload, Check, AlertCircle, Loader2 } from 'lucide-svelte';
import { matchesAPI } from '$lib/api/matches';
import { showToast } from '$lib/stores/toast';
import { toast } from '$lib/stores/toast';
import { goto } from '$app/navigation';
let shareCode = $state('');
@@ -21,12 +21,12 @@
const trimmedCode = shareCode.trim().toUpperCase();
if (!trimmedCode) {
showToast('Please enter a share code', 'error');
toast.error('Please enter a share code');
return;
}
if (!isValidShareCode(trimmedCode)) {
showToast('Invalid share code format', 'error');
toast.error('Invalid share code format');
parseStatus = 'error';
statusMessage = 'Share code must be in format: CSGO-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX';
return;
@@ -45,7 +45,7 @@
statusMessage =
response.message ||
'Match submitted successfully! Parsing may take a few minutes. You can view the match once parsing is complete.';
showToast('Match submitted for parsing!', 'success');
toast.success('Match submitted for parsing!');
// Wait a moment then redirect to the match page
setTimeout(() => {
@@ -54,12 +54,12 @@
} else {
parseStatus = 'error';
statusMessage = response.message || 'Failed to parse share code';
showToast(statusMessage, 'error');
toast.error(statusMessage);
}
} catch (error: unknown) {
parseStatus = 'error';
statusMessage = error instanceof Error ? error.message : 'Failed to parse share code';
showToast(statusMessage, 'error');
toast.error(statusMessage);
} finally {
isLoading = false;
}

View File

@@ -2,7 +2,7 @@
import { createEventDispatcher } from 'svelte';
import Modal from '$lib/components/ui/Modal.svelte';
import { playersAPI } from '$lib/api/players';
import { showToast } from '$lib/stores/toast';
import { toast } from '$lib/stores/toast';
interface Props {
playerId: string;
@@ -31,12 +31,12 @@
try {
await playersAPI.trackPlayer(playerId, authCode, shareCode || undefined);
showToast('Player tracking activated successfully!', 'success');
toast.success('Player tracking activated successfully!');
isOpen = false;
dispatch('tracked');
} catch (err: unknown) {
error = err instanceof Error ? err.message : 'Failed to track player';
showToast(error, 'error');
toast.error(error);
} finally {
isLoading = false;
}
@@ -53,12 +53,12 @@
try {
await playersAPI.untrackPlayer(playerId, authCode);
showToast('Player tracking removed successfully', 'success');
toast.success('Player tracking removed successfully');
isOpen = false;
dispatch('untracked');
} catch (err: unknown) {
error = err instanceof Error ? err.message : 'Failed to untrack player';
showToast(error, 'error');
toast.error(error);
} finally {
isLoading = false;
}

View File

@@ -59,7 +59,6 @@
class:tab-active={isActive(tab)}
class:tab-disabled={tab.disabled}
aria-disabled={tab.disabled}
data-sveltekit-preload-data="hover"
>
{tab.label}
</a>