Files
euchre_camp/src/components/RecalculateEloButton.tsx
T
david caefb0dcc0 fix: resolve schedule data staleness in production builds
- Replace window.location.reload() with router.refresh() in ScheduleGenerator, MatchEditor, RecalculateEloButton for proper Next.js cache invalidation
- Add revalidatePath() call after schedule generation in POST handler
- Add ownerId to tournament creation in cucumber tests for proper permission checks
- Assign tournament_admin role via Prisma after user creation in cucumber tests
- Fix TypeScript type annotations in hooks.ts (tournament id map)
- Update page reload to use networkidle in common-steps.ts
- Clear .next/ cache before cucumber tests in justfile
- Add .turbo to clean target
- Add comprehensive debug logging to schedule API route
- Document findings in docs/TROUBLESHOOTING_SCHEDULE_GENERATION.md
2026-05-01 16:39:50 -07:00

75 lines
2.5 KiB
TypeScript

"use client"
import { useState } from "react"
import { useRouter } from "next/navigation"
export function RecalculateEloButton() {
const router = useRouter()
const [isLoading, setIsLoading] = useState(false)
const handleClick = async () => {
if (!confirm('Are you sure you want to recalculate all ELO ratings? This will reset all player stats and recalculate them from match history. This operation is idempotent and safe to run multiple times.')) {
return
}
setIsLoading(true)
try {
const response = await fetch('/api/admin/recalculate-elo', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
try {
const errorData = await response.json()
alert(`Error: ${errorData.error || 'Failed to recalculate'}`)
} catch {
alert(`Error: ${response.status} ${response.statusText}`)
}
return
}
const data = await response.json()
if (data.success) {
alert(`Recalculation completed: ${JSON.stringify(data.data)}`)
router.refresh()
} else {
alert(`Error: ${data.error}`)
}
} catch (err) {
alert(`Error: ${err instanceof Error ? err.message : 'Unknown error occurred'}`)
} finally {
setIsLoading(false)
}
}
return (
<button
type="button"
onClick={handleClick}
disabled={isLoading}
className="flex items-center justify-center px-4 py-3 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-purple-600 hover:bg-purple-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
{isLoading ? (
<>
<svg className="w-5 h-5 mr-2 animate-spin" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Recalculating...
</>
) : (
<>
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
Recalculate ELO
</>
)}
</button>
)
}