"use client"; /** * TEE OFF DETAIL VIEW - COMPLETE v3.21 * --------------------------------------------------------------------------- * FIX: Gjenopprettet "Turneringer" i den flytende knapperaden over bildet. * FIX: Byttet plass på tekst og sidebar (Tekst øverst på mobil). * FIX: Økt padding (pb-32) i Hero-teksten på mobil for å unngå krasj med knapper. * FIX: Alle 4 kontaktpunkter i sidebar er klikkbare (tel:0047 fix inkludert). * NEW: Webkamera under Andre ressurser, NSG, Golfamore og Bilutleie under Andre Tilbud. * REGEL: Beholder monokrome ikoner, 22/78 layout og robust JSON-parsing. * --------------------------------------------------------------------------- */ import { useState, useEffect } from 'react'; import { STATUS_MAP, FALLBACK_IMAGE } from "@/config/constants"; import Link from 'next/link'; import CourseDisplay from './CourseDisplay'; const formatPhoneForUrl = (phone: string) => { if (!phone) return ""; return phone.replace('+', '00').replace(/\s/g, ''); }; const renderValue = (val: string) => { if (!val) return "Nei"; const hasLink = val.includes(' ); }; const Icon = ({ children, className = "w-5 h-5" }: { children: React.ReactNode, className?: string }) => ( {children} ); const ICONS = { web: <>, phone: , mail: <>, pin: <>, booking: <>, trophy: <>, guide: <>, camera: <>, webcam: <>, chart: <>, weather: <> }; export default function FacilityDetailView({ facility }: { facility: any }) { const [showBackToTop, setShowBackToTop] = useState(false); const [currentSlide, setCurrentSlide] = useState(0); const parseJson = (val: any, fallback: any) => { if (!val) return fallback; if (typeof val === 'object') return val; try { return JSON.parse(val); } catch (e) { return fallback; } }; const rawCourses = parseJson(facility.courses, []); const activeCourses = Array.isArray(rawCourses) ? rawCourses.filter((c: any) => c.holes && (typeof c.holes === 'string' || c.holes.length > 0)) : []; const amenities = parseJson(facility.amenities, {}); const galleryRaw = parseJson(facility.gallery, []); const gallery = galleryRaw.length > 0 ? galleryRaw : [facility.image_url || FALLBACK_IMAGE]; const greenfeeRaw = parseJson(facility.greenfee, []); const shotzoom = parseJson(facility.shotzoom, []); // Parse Golfamore og NSG const golfamoreData = parseJson(facility.golfamore_data, {}); const nsgData = parseJson(facility.nsg_data, {}); // Sjekker om de er aktive const hasGolfamore = facility.golfamore === true; const hasNSG = facility.nsg_url || (nsgData && Object.keys(nsgData).length > 0); const groupedGreenfee: Record = greenfeeRaw.reduce((acc: any, curr: any) => { const bane = curr.banenavn || "Gjestespill"; if (!acc[bane]) acc[bane] = []; acc[bane].push(curr); return acc; }, {}); const sidebarLinkClass = "flex items-center gap-4 hover:text-[#ff5722] transition-colors group"; const resourceBtnClass = "flex justify-between items-center p-5 bg-gray-50 rounded-2xl text-[11px] font-black uppercase hover:bg-[#ff5722] hover:text-white transition-all group"; useEffect(() => { if (gallery.length <= 1) return; const timer = setInterval(() => setCurrentSlide((p) => (p + 1) % gallery.length), 5000); return () => clearInterval(timer); }, [gallery.length]); useEffect(() => { const handleScroll = () => setShowBackToTop(window.scrollY > 500); window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); const scrollTo = (id: string) => { const el = document.getElementById(id); if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.pageYOffset - 80, behavior: 'smooth' }); }; const formatDate = (d: string) => d ? new Date(d).toLocaleDateString('nb-NO', { day: 'numeric', month: 'long', year: 'numeric' }) : null; const weatherImg = facility.weather_url?.replace("/graf/dag/", "/innhold/").replace(/\/$/, "") + "/meteogram.svg"; return (
{/* 1. HERO SLIDER */}
{gallery.map((img: string, i: number) => ( ))}
{/* BANESTATUS BADGES */}
{activeCourses.map((c: any) => ( {c.name.toUpperCase()}: {STATUS_MAP[c.status] || c.status} ))}
{facility.status_updated_at && ( Sist oppdatert: {formatDate(facility.status_updated_at)} )}
{/* FLYTENDE HURTIGKNAPPER (Inkludert Turneringer) */}
{facility.website_url && } {facility.golfbox_booking_url && } {facility.golfbox_tournament_url && } {facility.weather_url && }
{/* HERO TEXT */}
{facility.logo_url && (
Logo
)}

{facility.name}

{facility.county} • {facility.city}

{/* 2. STICKY NAV */}
{/* 3. INTRO & SIDEBAR */}
{/* HOVEDINNHOLD (78%) */}
{facility.footnote &&
{facility.footnote}
}
{/* SIDEBAR (22%) */}
{/* 4. 3-KOLONNE INFO */}

Andre Ressurser

{facility.golfbox_booking_url && ( Book Starttid )} {facility.golfbox_tournament_url && ( Turneringer )} {facility.baneguide_url && ( Baneguide )} {facility.flyfoto_url && ( Flyfoto )} {/* Ny rad for Webkamera */} {facility.webcam_url && ( Webkamera )} {shotzoom.map((sz: any, i: number) => ( Statistikk: {sz.shotzoom_beskrivelse?.replace(/ ?/g, ' ').trim().toUpperCase()} ))}

Banen

Hull:{amenities.antall_hull || '--'}
Lengde:{facility.length_meters ? `${facility.length_meters}m` : '--'}
Sesong:{facility.season || '--'}
Byggeår:{facility.established_year || '--'}
Banetype:{facility.banetype || 'Park/Skog'}
Arkitekt:{facility.architect || '--'}

Andre Tilbud

Drivingrange:{amenities.drivingrange || 'Nei'}
Nærspill:{amenities.treningsgreen || 'Ja'}
Proshop:{renderValue(amenities.proshop)}
Kølleutleie:{amenities.kolleutleie || 'Ja'}
Bilutleie:{amenities.bilutleie || 'Nei'}
Simulator:{renderValue(amenities.simulator)}
Head Pro:{renderValue(amenities.pro)}
Kafé:{renderValue(amenities.kafe)}
{/* NYE RADER: Golfamore og NSG */}
Golfamore: {hasGolfamore ? {golfamoreData.gyldighet || "Ja"} : "Nei"}
Seniorgolf (NSG): {hasNSG && facility.nsg_url ? Ja (Vis Avtale) : (hasNSG ? Ja : "Nei") }
{/* 5. VÆR SEKSJON */}

Vær for {facility.name}

{facility.weather_url ? ( Vær ) :

Værvarsel ikke tilgjengelig

}
{/* 6. KART SEKSJON */}

Kart