updated
This commit is contained in:
parent
86e9b53b78
commit
fb200876d0
@ -0,0 +1,47 @@
|
||||
// /src/app/[locale]/match-details/[matchId]/ClientMatchLoader.tsx
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import { MatchProvider } from './MatchContext'
|
||||
import type { Match } from '../../../../types/match'
|
||||
|
||||
export default function ClientMatchLoader({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter()
|
||||
const params = useParams() as { matchId?: string | string[] }
|
||||
const matchId = Array.isArray(params.matchId) ? params.matchId?.[0] : params.matchId
|
||||
|
||||
const [match, setMatch] = useState<Match | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
let alive = true
|
||||
if (!matchId) { router.replace('/404'); return }
|
||||
|
||||
;(async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/matches/${encodeURIComponent(matchId)}`, { cache: 'no-store' })
|
||||
if (!res.ok) { router.replace('/404'); return }
|
||||
const data = (await res.json()) as Match
|
||||
if (alive) setMatch(data)
|
||||
} catch {
|
||||
router.replace('/404')
|
||||
} finally {
|
||||
if (alive) setLoading(false)
|
||||
}
|
||||
})()
|
||||
|
||||
return () => { alive = false }
|
||||
}, [matchId, router])
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="p-6 text-sm text-gray-500 dark:text-neutral-400">
|
||||
Lädt Match…
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!match) return null
|
||||
return <MatchProvider match={match}>{children}</MatchProvider>
|
||||
}
|
||||
@ -1,57 +1,9 @@
|
||||
// /src/app/[locale]/match-details/[matchId]/layout.tsx
|
||||
import { headers } from 'next/headers'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { MatchProvider } from './MatchContext'
|
||||
import type { Match } from '../../../../types/match'
|
||||
import ClientMatchLoader from './ClientMatchLoader'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const revalidate = 0
|
||||
|
||||
async function buildOrigin(): Promise<string> {
|
||||
const h = await headers()
|
||||
const proto = (h.get('x-forwarded-proto') ?? 'http').split(',')[0].trim()
|
||||
const host = (h.get('x-forwarded-host') ?? h.get('host') ?? '').split(',')[0].trim()
|
||||
if (host) return `${proto}://${host}`
|
||||
|
||||
// Fallbacks (lokale Entwicklung / SSR-Tools)
|
||||
return (
|
||||
process.env.NEXT_PUBLIC_SITE_URL ||
|
||||
process.env.NEXTAUTH_URL ||
|
||||
'http://localhost:3000'
|
||||
)
|
||||
}
|
||||
|
||||
async function loadMatch(matchId: string): Promise<Match | null> {
|
||||
const origin = await buildOrigin()
|
||||
|
||||
// ⚠️ Dev-Only: Selbstsignierte Zertifikate erlauben
|
||||
const allowInsecure =
|
||||
process.env.NODE_ENV !== 'production' ||
|
||||
process.env.ALLOW_INSECURE_FETCH === '1'
|
||||
|
||||
if (origin.startsWith('https://') && allowInsecure) {
|
||||
// global für den Node-Prozess – bitte NICHT in Production setzen
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
||||
}
|
||||
|
||||
const res = await fetch(`${origin}/api/matches/${encodeURIComponent(matchId)}`, {
|
||||
cache: 'no-store',
|
||||
})
|
||||
if (!res.ok) return null
|
||||
return res.json()
|
||||
}
|
||||
|
||||
type Params = { matchId: string }
|
||||
type Props = {
|
||||
children: React.ReactNode
|
||||
params: Promise<Params>
|
||||
}
|
||||
|
||||
export default async function MatchLayout({ children, params }: Props) {
|
||||
const { matchId } = await params
|
||||
|
||||
const match = await loadMatch(matchId)
|
||||
if (!match) notFound()
|
||||
|
||||
return <MatchProvider match={match}>{children}</MatchProvider>
|
||||
export default function MatchLayout({ children }: { children: React.ReactNode }) {
|
||||
return <ClientMatchLoader>{children}</ClientMatchLoader>
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user