2026-02-26 09:20:51 +01:00
|
|
|
"use client";
|
2026-02-27 09:49:42 +01:00
|
|
|
/**
|
2026-02-27 11:12:53 +01:00
|
|
|
* TEE OFF DETAIL VIEW - COMPLETE v3.18
|
2026-02-27 09:49:42 +01:00
|
|
|
* ---------------------------------------------------------------------------
|
2026-02-27 11:12:53 +01:00
|
|
|
* FIX: Fjernet emojier/ikoner ved siden av "GJESTESPILL" og "MEDLEMSKAP".
|
|
|
|
|
* FIX: Forbedret Greenfee-logikk for å sikre at ALLE priser og baner (Østmork/Vestmork) vises.
|
|
|
|
|
* FIX: Skjuler under-header hvis den bare gjentar "Gjestespill".
|
|
|
|
|
* REGEL: Beholder monokrome ikoner, 22/78 layout og 0047-prefix på telefon.
|
2026-02-27 09:49:42 +01:00
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
|
*/
|
2026-02-26 09:20:51 +01:00
|
|
|
|
2026-02-26 16:32:34 +01:00
|
|
|
import { useState, useEffect } from 'react';
|
2026-02-26 09:20:51 +01:00
|
|
|
import { STATUS_MAP, FALLBACK_IMAGE } from "@/config/constants";
|
|
|
|
|
import Link from 'next/link';
|
|
|
|
|
import CourseDisplay from './CourseDisplay';
|
|
|
|
|
|
2026-02-27 10:15:52 +01:00
|
|
|
const formatPhoneForUrl = (phone: string) => {
|
|
|
|
|
if (!phone) return "";
|
|
|
|
|
return phone.replace('+', '00').replace(/\s/g, '');
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-26 16:32:34 +01:00
|
|
|
const Icon = ({ children, className = "w-5 h-5" }: { children: React.ReactNode, className?: string }) => (
|
2026-02-27 10:15:52 +01:00
|
|
|
<svg
|
|
|
|
|
className={`${className} flex-shrink-0 text-[#11280f]`}
|
2026-02-27 10:27:25 +01:00
|
|
|
viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
|
|
|
|
|
style={{ width: '20px', height: '20px' }}
|
2026-02-27 10:15:52 +01:00
|
|
|
>
|
|
|
|
|
{children}
|
|
|
|
|
</svg>
|
2026-02-26 16:32:34 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const ICONS = {
|
2026-02-27 10:15:52 +01:00
|
|
|
web: <><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></>,
|
2026-02-26 16:32:34 +01:00
|
|
|
phone: <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" />,
|
|
|
|
|
mail: <><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" /><polyline points="22,6 12,13 2,6" /></>,
|
2026-02-27 10:15:52 +01:00
|
|
|
pin: <><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" /><circle cx="12" cy="10" r="3" /></>,
|
2026-02-27 10:27:25 +01:00
|
|
|
booking: <><path d="M3 10h18M7 15h.01M11 15h.01M15 15h.01M7 19h.01M11 19h.01M15 19h.01M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2zM16 3v4M8 3v4"/></>,
|
|
|
|
|
trophy: <><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6M18 9h1.5a2.5 2.5 0 0 0 0-5H18M4 22h16M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22M18 2H6v7a6 6 0 0 0 12 0V2z"/></>,
|
|
|
|
|
guide: <><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20M4 4.5A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1-2.5-2.5V4.5z"/></>,
|
|
|
|
|
camera: <><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></>,
|
|
|
|
|
chart: <><path d="M18 20V10M12 20V4M6 20v-6"/></>,
|
2026-02-27 10:15:52 +01:00
|
|
|
weather: <><path d="M12 2v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="M20 12h2"/><path d="m19.07 4.93-1.41 1.41"/><path d="M15.947 12.65a4 4 0 0 0-5.925-4.128"/><path d="M13 22H7a5 5 0 1 1 4.9-6H13a3 3 0 0 1 0 6Z"/></>
|
2026-02-26 09:20:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default function FacilityDetailView({ facility }: { facility: any }) {
|
2026-02-26 16:32:34 +01:00
|
|
|
const [showBackToTop, setShowBackToTop] = useState(false);
|
|
|
|
|
const [currentSlide, setCurrentSlide] = useState(0);
|
|
|
|
|
|
2026-02-27 09:49:42 +01:00
|
|
|
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 gallery = parseJson(facility.gallery, [facility.image_url || FALLBACK_IMAGE]);
|
2026-02-27 11:12:53 +01:00
|
|
|
const greenfeeRaw = parseJson(facility.greenfee, []);
|
2026-02-27 09:49:42 +01:00
|
|
|
const shotzoom = parseJson(facility.shotzoom, []);
|
2026-02-27 11:12:53 +01:00
|
|
|
|
|
|
|
|
// Grupper priser etter bane (f.eks Østmork, Vestmork)
|
|
|
|
|
const groupedGreenfee: Record<string, any[]> = greenfeeRaw.reduce((acc: any, curr: any) => {
|
|
|
|
|
const bane = curr.banenavn || "Gjestespill";
|
|
|
|
|
if (!acc[bane]) acc[bane] = [];
|
|
|
|
|
acc[bane].push(curr);
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
2026-02-26 16:32:34 +01:00
|
|
|
const linkClass = "text-orange-600 hover:underline transition-colors font-bold";
|
2026-02-27 10:15:52 +01:00
|
|
|
const sidebarLinkClass = "flex items-center gap-4 hover:text-orange-600 transition-colors group";
|
2026-02-27 10:27:25 +01:00
|
|
|
const resourceBtnClass = "flex justify-between items-center p-5 bg-gray-50 rounded-2xl text-[11px] font-black uppercase hover:bg-orange-600 hover:text-white transition-all group";
|
2026-02-26 16:32:34 +01:00
|
|
|
|
|
|
|
|
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' });
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-27 08:53:14 +01:00
|
|
|
const formatDate = (d: string) => d ? new Date(d).toLocaleDateString('nb-NO', { day: 'numeric', month: 'long', year: 'numeric' }) : null;
|
2026-02-26 09:20:51 +01:00
|
|
|
const weatherImg = facility.weather_url?.replace("/graf/dag/", "/innhold/").replace(/\/$/, "") + "/meteogram.svg";
|
|
|
|
|
|
|
|
|
|
return (
|
2026-02-26 16:32:34 +01:00
|
|
|
<main className="min-h-screen bg-[#f1f7ed] pb-20 relative font-sans text-[#11280f]">
|
2026-02-26 09:20:51 +01:00
|
|
|
|
2026-02-27 10:27:25 +01:00
|
|
|
{/* 1. HERO SLIDER */}
|
2026-02-26 16:32:34 +01:00
|
|
|
<div className="h-[55vh] min-h-[450px] relative overflow-hidden bg-[#11280f]">
|
|
|
|
|
{gallery.map((img: string, i: number) => (
|
|
|
|
|
<img key={i} src={img} className={`absolute inset-0 w-full h-full object-cover transition-opacity duration-1000 ${i === currentSlide ? 'opacity-100 z-10' : 'opacity-0 z-0'}`} alt="" />
|
|
|
|
|
))}
|
|
|
|
|
<div className="absolute inset-0 bg-gradient-to-t from-[#11280f]/90 via-transparent to-black/10 z-20" />
|
2026-02-27 10:27:25 +01:00
|
|
|
<div className="absolute top-8 right-8 z-40 flex flex-wrap justify-end gap-2">
|
|
|
|
|
{activeCourses.map((c: any) => (
|
|
|
|
|
<span key={c.id} className="px-3 py-1.5 rounded-lg text-[10px] font-black uppercase bg-[#7ca982] text-white shadow-xl">{STATUS_MAP[c.status] || c.status}</span>
|
|
|
|
|
))}
|
2026-02-26 09:20:51 +01:00
|
|
|
</div>
|
2026-02-27 10:27:25 +01:00
|
|
|
<div className="relative z-30 max-w-[1200px] mx-auto px-6 w-full h-full flex flex-col justify-end pb-12">
|
2026-02-27 10:15:52 +01:00
|
|
|
{facility.logo_url && (
|
|
|
|
|
<div className="hidden md:block mb-8 w-24 h-24 bg-white p-2 rounded-2xl shadow-2xl border-4 border-white/20 overflow-hidden"><img src={facility.logo_url} className="w-full h-full object-contain" alt="Logo" /></div>
|
|
|
|
|
)}
|
2026-02-27 08:53:14 +01:00
|
|
|
<h1 className="text-5xl md:text-8xl font-black text-white mb-3 tracking-tighter drop-shadow-2xl">{facility.name}</h1>
|
2026-02-26 16:32:34 +01:00
|
|
|
<p className="text-[#7ca982] uppercase tracking-[0.4em] font-black text-xs md:text-sm pl-1">{facility.county} • {facility.city}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-02-26 09:20:51 +01:00
|
|
|
|
2026-02-27 10:27:25 +01:00
|
|
|
{/* 2. STICKY NAV */}
|
2026-02-26 16:32:34 +01:00
|
|
|
<nav className="sticky top-0 z-50 bg-white/95 backdrop-blur-md border-b border-gray-100 shadow-sm overflow-hidden">
|
|
|
|
|
<div className="max-w-[1200px] mx-auto px-6 flex justify-between md:justify-start gap-4 md:gap-10 h-16 items-center text-[10px] font-black uppercase tracking-widest text-gray-400">
|
|
|
|
|
<button onClick={() => scrollTo('intro')}>Info</button>
|
|
|
|
|
<button onClick={() => scrollTo('weather')}>Vær</button>
|
|
|
|
|
<button onClick={() => scrollTo('details')}>Detaljer</button>
|
2026-02-27 10:27:25 +01:00
|
|
|
<button onClick={() => scrollTo('map')}>Kart</button>
|
|
|
|
|
{facility.video_url && <button onClick={() => scrollTo('video')}>Video</button>}
|
2026-02-26 16:32:34 +01:00
|
|
|
<button onClick={() => scrollTo('prices')}>Priser</button>
|
|
|
|
|
<button onClick={() => scrollTo('scorecards')}>Scorekort</button>
|
|
|
|
|
</div>
|
|
|
|
|
</nav>
|
2026-02-26 09:20:51 +01:00
|
|
|
|
2026-02-26 16:32:34 +01:00
|
|
|
<div className="max-w-[1200px] mx-auto px-0 md:px-6 space-y-4 md:space-y-12 mt-0 md:mt-12">
|
|
|
|
|
|
2026-02-27 10:27:25 +01:00
|
|
|
{/* 3. INTRO & SIDEBAR */}
|
2026-02-26 16:32:34 +01:00
|
|
|
<section id="intro" className="flex flex-col lg:flex-row gap-0 md:gap-8 items-stretch">
|
2026-02-27 10:27:25 +01:00
|
|
|
<div className="lg:w-[22%] bg-white p-10 md:rounded-[3rem] shadow-sm flex flex-col">
|
2026-02-27 10:15:52 +01:00
|
|
|
<h3 className="text-[10px] font-black text-gray-300 uppercase tracking-widest mb-10">Kontakt & Adresse</h3>
|
|
|
|
|
<div className="flex-grow space-y-7 text-sm font-bold">
|
2026-02-27 10:27:25 +01:00
|
|
|
<a href={facility.website_url} target="_blank" className={sidebarLinkClass}><Icon children={ICONS.web} /> Besøk nettsiden</a>
|
|
|
|
|
<a href={`tel:${formatPhoneForUrl(facility.phone)}`} className={sidebarLinkClass}><Icon children={ICONS.phone} /> {facility.phone || 'Ikke oppgitt'}</a>
|
|
|
|
|
<a href={`mailto:${facility.email}`} className={sidebarLinkClass}><Icon children={ICONS.mail} /> <span className="truncate">{facility.email || 'Ikke oppgitt'}</span></a>
|
2026-02-27 10:15:52 +01:00
|
|
|
<div className="pt-2 border-t border-gray-50 mt-4">
|
|
|
|
|
<a href={`https://www.google.com/maps/search/?api=1&query=${facility.lat},${facility.lng}`} target="_blank" className={sidebarLinkClass + " pt-4 leading-tight items-start"}>
|
2026-02-27 10:27:25 +01:00
|
|
|
<Icon children={ICONS.pin} /> <span className="text-gray-400 group-hover:text-orange-600 transition-colors">{facility.address}<br/>{facility.city}</span>
|
2026-02-27 10:15:52 +01:00
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mt-auto pt-10 border-t border-gray-50">
|
2026-02-27 10:27:25 +01:00
|
|
|
<Link href={`/`} className="text-[10px] font-black uppercase tracking-widest text-[#7ca982] hover:text-[#11280f] transition-all flex items-center gap-1">Se alle baner i {facility.county} →</Link>
|
2026-02-26 09:20:51 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-02-27 10:27:25 +01:00
|
|
|
<div className="lg:w-[78%] bg-white p-10 md:p-16 md:rounded-[3rem] shadow-sm">
|
|
|
|
|
{facility.footnote && <div className="mb-8 pb-8 border-b border-gray-50 italic text-gray-400 text-lg font-serif">{facility.footnote}</div>}
|
2026-02-27 09:49:42 +01:00
|
|
|
<div className="leading-relaxed text-lg md:text-xl text-gray-600" dangerouslySetInnerHTML={{ __html: facility.description || 'Ingen beskrivelse tilgjengelig.' }} />
|
2026-02-26 16:32:34 +01:00
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
2026-02-27 10:27:25 +01:00
|
|
|
{/* 4. 3-KOLONNE INFO */}
|
|
|
|
|
<section id="details" className="grid grid-cols-1 lg:grid-cols-3 gap-4 md:gap-8">
|
|
|
|
|
<div className="bg-white p-10 md:rounded-[3rem] shadow-sm">
|
|
|
|
|
<h3 className="text-lg font-black mb-8 uppercase tracking-tighter">Andre Ressurser</h3>
|
|
|
|
|
<div className="space-y-2.5">
|
|
|
|
|
{facility.golfbox_booking_url && (
|
|
|
|
|
<a href={facility.golfbox_booking_url} target="_blank" className={resourceBtnClass}>
|
|
|
|
|
<span className="flex items-center gap-3"><Icon children={ICONS.booking} className="group-hover:text-white" /> Book Starttid</span><span>→</span>
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
|
|
|
|
{facility.golfbox_tournament_url && (
|
|
|
|
|
<a href={facility.golfbox_tournament_url} target="_blank" className={resourceBtnClass}>
|
|
|
|
|
<span className="flex items-center gap-3"><Icon children={ICONS.trophy} className="group-hover:text-white" /> Turneringer</span><span>→</span>
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
|
|
|
|
{facility.baneguide_url && (
|
|
|
|
|
<a href={facility.baneguide_url} target="_blank" className={resourceBtnClass}>
|
|
|
|
|
<span className="flex items-center gap-3"><Icon children={ICONS.guide} className="group-hover:text-white" /> Baneguide</span><span>→</span>
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
|
|
|
|
{facility.flyfoto_url && (
|
|
|
|
|
<a href={facility.flyfoto_url} target="_blank" className={resourceBtnClass}>
|
|
|
|
|
<span className="flex items-center gap-3"><Icon children={ICONS.camera} className="group-hover:text-white" /> Flyfoto</span><span>→</span>
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
2026-02-26 16:32:34 +01:00
|
|
|
{shotzoom.map((sz: any, i: number) => (
|
2026-02-27 10:27:25 +01:00
|
|
|
<a key={i} href={sz.shotzoom_url} target="_blank" className={resourceBtnClass}>
|
2026-02-27 11:12:53 +01:00
|
|
|
<span className="flex items-center gap-3"><Icon children={ICONS.chart} className="group-hover:text-white" /> Statistikk: {sz.shotzoom_beskrivelse?.replace(/ ?/g, ' ').trim().toUpperCase()}</span><span>→</span>
|
2026-02-27 10:27:25 +01:00
|
|
|
</a>
|
2026-02-26 16:32:34 +01:00
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-02-27 10:27:25 +01:00
|
|
|
<div className="bg-white p-10 md:rounded-[3rem] shadow-sm text-sm font-bold text-gray-700">
|
|
|
|
|
<h3 className="text-lg font-black mb-8 uppercase tracking-tighter text-[#11280f]">Banen</h3>
|
|
|
|
|
<div className="space-y-5">
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Hull:</span><span>{amenities.antall_hull || '--'}</span></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Lengde:</span><span>{facility.length_meters ? `${facility.length_meters}m` : '--'}</span></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Sesong:</span><span>{facility.season || '--'}</span></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Byggeår:</span><span>{facility.established_year || '--'}</span></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Banetype:</span><span>{facility.banetype || 'Park/Skog'}</span></div>
|
|
|
|
|
<div className="flex justify-between"><span className="text-gray-400">Arkitekt:</span><span className="text-right truncate ml-4">{facility.architect || '--'}</span></div>
|
2026-02-26 09:20:51 +01:00
|
|
|
</div>
|
2026-02-27 10:27:25 +01:00
|
|
|
</div>
|
|
|
|
|
<div className="bg-white p-10 md:rounded-[3rem] shadow-sm text-sm font-bold text-gray-700">
|
|
|
|
|
<h3 className="text-lg font-black mb-8 uppercase tracking-tighter text-[#11280f]">Andre Tilbud</h3>
|
|
|
|
|
<div className="space-y-5">
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Drivingrange:</span><span>{amenities.drivingrange || 'Nei'}</span></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Nærspill:</span><span>{amenities.treningsgreen || 'Ja'}</span></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Proshop:</span><span className="text-right ml-4 text-orange-600" dangerouslySetInnerHTML={{ __html: amenities.proshop || 'Nei' }} /></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Kølleutleie:</span><span>{amenities.kolleutleie || 'Ja'}</span></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Simulator:</span><span className="text-orange-600" dangerouslySetInnerHTML={{ __html: amenities.simulator || 'Nei' }} /></div>
|
|
|
|
|
<div className="flex justify-between border-b border-gray-50 pb-3"><span className="text-gray-400">Head Pro:</span><span className="text-orange-600" dangerouslySetInnerHTML={{ __html: amenities.pro || '--' }} /></div>
|
|
|
|
|
<div className="flex justify-between"><span className="text-gray-400">Kafé:</span><span className="text-orange-600" dangerouslySetInnerHTML={{ __html: amenities.kafe || '--' }} /></div>
|
2026-02-26 09:20:51 +01:00
|
|
|
</div>
|
2026-02-26 16:32:34 +01:00
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
2026-02-27 10:27:25 +01:00
|
|
|
{/* 5. VÆR SEKSJON */}
|
|
|
|
|
<section id="weather" className="bg-white p-0 md:p-12 md:rounded-[3rem] shadow-sm border-b md:border-none overflow-hidden text-center">
|
|
|
|
|
<h3 className="text-[10px] font-black text-gray-300 uppercase tracking-[0.2em] py-8 md:py-0 md:mb-10 flex items-center justify-center gap-3"><Icon children={ICONS.weather} /> Vær for {facility.name}</h3>
|
|
|
|
|
<div className="w-full flex justify-center px-4 md:px-0">
|
|
|
|
|
{facility.weather_url ? ( <img src={weatherImg} className="w-full h-auto block max-w-5xl" alt="Vær" /> ) : <p className="text-center py-24 text-gray-300 italic text-sm">Værvarsel ikke tilgjengelig</p>}
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
{/* 6. KART SEKSJON */}
|
2026-02-26 16:32:34 +01:00
|
|
|
<section id="map" className="space-y-6">
|
|
|
|
|
<h2 className="text-3xl md:text-4xl font-black uppercase tracking-tighter flex items-center gap-5 ml-6 md:ml-0">Kart <span className="h-1 flex-grow bg-gray-100 rounded-full" /></h2>
|
2026-02-27 10:27:25 +01:00
|
|
|
<div className="w-full md:rounded-[3rem] overflow-hidden shadow-xl h-[450px] md:h-[650px] border-y-4 md:border-[12px] border-white bg-gray-100">
|
|
|
|
|
<iframe width="100%" height="100%" style={{ border: 0 }} src={`https://maps.google.com/maps?q=${facility.lat},${facility.lng}&t=k&z=15&ie=UTF8&iwloc=&output=embed`} allowFullScreen />
|
|
|
|
|
</div>
|
2026-02-26 16:32:34 +01:00
|
|
|
</section>
|
|
|
|
|
|
2026-02-27 10:27:25 +01:00
|
|
|
{/* 7. VIDEO SEKSJON */}
|
|
|
|
|
{facility.video_url && (
|
|
|
|
|
<section id="video" className="space-y-6">
|
|
|
|
|
<h2 className="text-3xl md:text-4xl font-black uppercase tracking-tighter flex items-center gap-5 ml-6 md:ml-0">Video <span className="h-1 flex-grow bg-gray-100 rounded-full" /></h2>
|
|
|
|
|
<div className="w-full md:rounded-[3rem] overflow-hidden shadow-2xl aspect-video bg-black border-y-4 md:border-[12px] border-white">
|
|
|
|
|
<iframe src={facility.video_url} className="w-full h-full" allowFullScreen />
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-02-27 11:12:53 +01:00
|
|
|
{/* 8. PRISER & MEDLEMSKAP (IKONER FJERNET) */}
|
2026-02-26 16:32:34 +01:00
|
|
|
<section id="prices" className="grid grid-cols-1 lg:grid-cols-2 gap-0 md:gap-8">
|
2026-02-27 11:12:53 +01:00
|
|
|
<div className="bg-white p-10 md:p-14 md:rounded-[3rem] shadow-sm">
|
|
|
|
|
<h3 className="text-2xl font-black mb-10 uppercase tracking-tighter">Gjestespill</h3>
|
|
|
|
|
<div className="space-y-10">
|
|
|
|
|
{Object.keys(groupedGreenfee).length > 0 ? (
|
|
|
|
|
Object.entries(groupedGreenfee).map(([bane, priser], idx) => (
|
|
|
|
|
<div key={idx} className="space-y-4">
|
|
|
|
|
{/* Skjul baneheader hvis den bare gjentar "Gjestespill" og det bare er én gruppe */}
|
|
|
|
|
{!(bane === "Gjestespill" && Object.keys(groupedGreenfee).length === 1) && (
|
|
|
|
|
<h4 className="text-lg font-black uppercase tracking-tighter text-[#11280f] border-b-2 border-gray-50 pb-2">{bane}</h4>
|
|
|
|
|
)}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest">Voksne</p>
|
|
|
|
|
{priser.map((g, i) => (
|
|
|
|
|
<div key={i} className="flex justify-between py-2 border-b border-gray-50/50 text-sm font-bold">
|
|
|
|
|
<span className="text-gray-500">{g.priskategori}</span>
|
|
|
|
|
<span>kr {g.pris_voksne || '--'},-</span>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
{priser.some(g => g.pris_junior) && (
|
|
|
|
|
<div className="space-y-2 pt-4">
|
|
|
|
|
<p className="text-[10px] font-black text-gray-400 uppercase tracking-widest">Junior</p>
|
|
|
|
|
{priser.map((g, i) => (
|
|
|
|
|
<div key={i} className="flex justify-between py-2 border-b border-gray-50/50 text-sm font-bold">
|
|
|
|
|
<span className="text-gray-500">{g.priskategori}</span>
|
|
|
|
|
<span>kr {g.pris_junior || '--'},-</span>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-02-26 16:32:34 +01:00
|
|
|
))
|
|
|
|
|
) : <p className="text-gray-400 italic py-6">Ingen priser funnet.</p>}
|
|
|
|
|
</div>
|
2026-02-27 11:12:53 +01:00
|
|
|
<p className="mt-10 text-[10px] text-gray-300 font-black uppercase tracking-widest italic">Krav: {facility.guest_requirements || 'Klubbhandicap'}</p>
|
2026-02-26 16:32:34 +01:00
|
|
|
</div>
|
2026-02-27 11:12:53 +01:00
|
|
|
|
|
|
|
|
<div className="bg-white p-10 md:p-14 md:rounded-[3rem] shadow-sm flex flex-col justify-between">
|
2026-02-26 16:32:34 +01:00
|
|
|
<div>
|
2026-02-27 11:12:53 +01:00
|
|
|
<h3 className="text-2xl font-black mb-10 uppercase tracking-tighter">Medlemskap</h3>
|
2026-02-26 16:32:34 +01:00
|
|
|
<div className="bg-[#f1f7ed] p-12 md:rounded-[2.5rem] mb-8 text-center border border-[#7ca982]/10">
|
2026-02-27 11:12:53 +01:00
|
|
|
<p className="text-[#7ca982] text-[11px] font-black uppercase mb-3 tracking-widest">{facility.navn_standard_medlemskap || "Standard"}</p>
|
2026-02-27 09:49:42 +01:00
|
|
|
<p className="text-6xl font-black text-[#11280f]">kr {facility.standard_medlemskap || '--'},-</p>
|
2026-02-27 11:12:53 +01:00
|
|
|
{facility.standard_medlemskap_kommentarer && <p className="text-[10px] text-gray-400 mt-4 uppercase font-bold italic leading-tight">{facility.standard_medlemskap_kommentarer}</p>}
|
2026-02-26 16:32:34 +01:00
|
|
|
</div>
|
2026-02-27 11:12:53 +01:00
|
|
|
{facility.navn_rimeligste_alternativ && (
|
|
|
|
|
<div className="px-8 py-5 bg-gray-50 rounded-2xl border border-gray-100 flex justify-between items-center text-sm font-bold"><span className="text-gray-400 uppercase text-[10px] tracking-widest">{facility.navn_rimeligste_alternativ}</span><span className="text-[#11280f]">kr {facility.rimeligste_alternativ},-</span></div>
|
|
|
|
|
)}
|
2026-02-26 16:32:34 +01:00
|
|
|
</div>
|
2026-02-27 11:12:53 +01:00
|
|
|
<a href={facility.medlemskap_url} target="_blank" className="mt-10 block w-full text-center bg-[#11280f] text-white p-7 rounded-2xl font-black uppercase text-xs tracking-widest shadow-xl hover:bg-black transition-all">Se alle alternativer</a>
|
2026-02-26 16:32:34 +01:00
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
2026-02-27 10:27:25 +01:00
|
|
|
{/* 9. SCOREKORT SEKSJON */}
|
2026-02-26 16:32:34 +01:00
|
|
|
<section id="scorecards" className="pt-10 space-y-20 overflow-hidden">
|
|
|
|
|
<h3 className="text-center text-3xl md:text-5xl font-black uppercase tracking-tighter">Scorekort</h3>
|
|
|
|
|
<div className="w-full flex flex-col items-center gap-20">
|
|
|
|
|
{activeCourses.map((c: any) => (
|
|
|
|
|
<div key={c.id} className="w-full overflow-x-auto md:overflow-visible no-scrollbar">
|
|
|
|
|
<div className="min-w-[800px] md:min-w-0"><CourseDisplay course={c} /></div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
2026-02-26 09:20:51 +01:00
|
|
|
</div>
|
2026-02-26 16:32:34 +01:00
|
|
|
|
2026-02-27 11:12:53 +01:00
|
|
|
{showBackToTop && (
|
|
|
|
|
<button onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} className="fixed bottom-8 right-8 w-14 h-14 bg-[#11280f] text-white rounded-full shadow-2xl flex items-center justify-center text-2xl z-[100] border-4 border-white/20 hover:scale-110 transition-all">↑</button>
|
|
|
|
|
)}
|
2026-02-26 09:20:51 +01:00
|
|
|
</main>
|
|
|
|
|
);
|
2026-02-26 16:32:34 +01:00
|
|
|
}
|