// app/beach/page.tsx 'use client'; import { Turnstile, TurnstileInstance } from '@marsidev/react-turnstile'; import Link from 'next/link'; import React, { useEffect, useRef, useState } from 'react'; import { IoIosMail } from "react-icons/io"; import { PiWarningCircle } from "react-icons/pi"; import { PiCheckCircle } from "react-icons/pi"; interface TimeInfo { dateStr: string; matchStr: string; deadlineText: string; isClosed: boolean; } interface AlertState { show: boolean; type: 'success' | 'danger' | ''; message: string; } interface SubmitResponse { success: boolean; message: string; detail?: string; } export default function BeachPage() { const [timeInfo, setTimeInfo] = useState({ dateStr: 'Laddar datum...', matchStr: 'Laddar tider...', deadlineText: 'Anmälningar kan göras senast...', isClosed: false, }); useEffect(() => { const updateTournamentInfo = () => { const matchStart = new Date('2026-06-13T10:00:00+02:00'); const now = new Date(); const infoGathering = new Date(matchStart.getTime() - 30 * 60000); const closingDate = new Date(matchStart.getTime() - 24 * 60 * 60000); const dateOptions: Intl.DateTimeFormatOptions = { day: 'numeric', month: 'long', year: 'numeric' }; const timeOptions: Intl.DateTimeFormatOptions = { hour: '2-digit', minute: '2-digit' }; const dateStr = matchStart.toLocaleDateString('sv-SE', dateOptions); const matchTime = matchStart.toLocaleTimeString('sv-SE', timeOptions); const infoTime = infoGathering.toLocaleTimeString('sv-SE', timeOptions); const deadlineDate = closingDate.toLocaleDateString('sv-SE', dateOptions); const deadlineTime = closingDate.toLocaleTimeString('sv-SE', timeOptions); setTimeInfo({ dateStr, matchStr: `Matchstart kl.${matchTime} (Infosamling kl.${infoTime})`, deadlineText: `Anmälan stänger den ${deadlineDate} kl.${deadlineTime} (24 timmar innan start) eller om alla platser har blivit fyllda.`, isClosed: now >= closingDate, }); }; updateTournamentInfo(); const interval = setInterval(updateTournamentInfo, 60000); return () => clearInterval(interval); }, []); const [isSubmitting, setIsSubmitting] = useState(false); const [wasValidated, setWasValidated] = useState(false); const [alert, setAlert] = useState({ show: false, type: '', message: '' }); const formRef = useRef(null); const turnstileRef = useRef(null); const handleSubmit: React.FormEventHandler = async (e) => { e.preventDefault(); const form = formRef.current; if (!form) return; setWasValidated(true); if (!form.checkValidity()) { return; } setIsSubmitting(true); setAlert({ show: false, type: '', message: '' }); const formData = new FormData(form); try { const response = await fetch('/api/submit', { method: 'POST', body: formData, }); if (!response.ok) throw new Error(`Network error: ${response.status}`); const result = (await response.json()) as SubmitResponse; const message = result.detail ? `${result.message} ${result.detail}` : result.message; setAlert({ show: true, type: result.success ? 'success' : 'danger', message: message, }); if (result.success) { form.reset(); setWasValidated(false); if (turnstileRef.current) turnstileRef.current.reset(); } } catch (error) { console.error('An error occurred:', error); setAlert({ show: true, type: 'danger', message: 'Ett tekniskt fel uppstod. Försök igen senare.', }); } finally { setIsSubmitting(false); } }; // SVG Icons for validation (Extracted from your original CSS) // const CheckmarkIcon = () => #198754 // const ErrorIcon = () => #dc3545 return (
Lerbergets Volleybollsällskap

Mat- & Sommarfesten

Beachturnering

Samla ihop ett kompisgäng och anmäl er!

{timeInfo.isClosed && (

Anmälan är nu stängd!

Det är hela 26 lag anmälda och vi kan tyvärr inte ta emot fler anmälningar.

Vi är glada över förväntan och bjuder in alla andra till att komma och kolla men vi har tyvärr inte kapaciteten till att ha med fler lag.

)}

Var:

Kvickbadet i Höganäs

När:

{timeInfo.dateStr}

{timeInfo.matchStr}

Samtidigt som Höganäs Mat- & Sommarfest

Regler:

Matcherna spelas 4v4 med inomhusregler, förutom poängräkningen som följer reglerna för beachvolleyboll.

Klasser:

Turneringen kan komma att delas upp i tre olika klasser beroende på antal anmälda lag och baserat på nivå:
Grön (Nybörjare),{' '} Blå (Amatör),{' '} Svart (Proffs)

Gör en gissning i vilken nivå ni tror att ert lag skulle passa och skriv gärna något i anmälan om ni är osäkra.

Kostnad:

Gratis!!!

Anmälan:

Anmälan görs genom anmälningsformuläret nedan. Du får ett bekräftelsemejl när vi kollat igenom er anmälan.

{timeInfo.deadlineText}

Övrig info:

Turneringen upskattas hålla på till ca 17-18 tiden

Det kommer finnas duschmöjligheter i anslutning till stranden.

Det kommer att finnas fina priser till alla pallplatser! 🏆

{!timeInfo.isClosed && (

Anmälningsformulär

{/* Form starts here - uses group/form to track the .was-validated state natively */}
{/* NAME */}
Glöm inte ditt namn!
{/* EMAIL */}
Email addressen är inte giltig.
{/* PHONE */}
Glöm inte ett telefonnummer!
{/* TEAM */}
Glöm inte ert Lagnamn!
{/* COUNT */}
Glöm inte ange antal lagmedlemmar!
{/* RADIOS */}


Glöm inte ange spelarnivå!
{/* TEXTAREA */}
{/* HONEYPOT */}
{/* ALERT */} {alert.show && (
{alert.message}
)} {/* TURNSTILE */}
{/* SUBMIT BUTTON */}
)} {/* Contact Section */}
{/* Footer */}
); }