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
|
// /src/app/[locale]/match-details/[matchId]/layout.tsx
|
||||||
import { headers } from 'next/headers'
|
import ClientMatchLoader from './ClientMatchLoader'
|
||||||
import { notFound } from 'next/navigation'
|
|
||||||
import { MatchProvider } from './MatchContext'
|
|
||||||
import type { Match } from '../../../../types/match'
|
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic'
|
export const dynamic = 'force-dynamic'
|
||||||
export const revalidate = 0
|
export const revalidate = 0
|
||||||
|
|
||||||
async function buildOrigin(): Promise<string> {
|
export default function MatchLayout({ children }: { children: React.ReactNode }) {
|
||||||
const h = await headers()
|
return <ClientMatchLoader>{children}</ClientMatchLoader>
|
||||||
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>
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user