5763534e26
Fix JSON parsing errors when server returns non-JSON responses: - Check response.ok before calling response.json() - Add fallback error messages using status text - Apply fix to all fetch calls across 12 components This prevents 'JSON.parse: unexpected character' errors when server returns HTML error pages or other non-JSON responses.
73 lines
2.4 KiB
TypeScript
73 lines
2.4 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
|
|
export function RecalculateEloButton() {
|
|
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)}`)
|
|
window.location.reload()
|
|
} 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>
|
|
)
|
|
}
|