Updated so that the rules and class text can be updated through the admin page

This commit is contained in:
2026-04-19 13:28:13 +02:00 Verified
parent 16f5c3f22b
commit 0d4d447569
11 changed files with 103 additions and 39 deletions
+15 -12
View File
@@ -8,8 +8,12 @@ import { IoIosMail } from "react-icons/io";
import Footer from '../components/Footer';
import Header from '../components/Header';
import BeachRegistrationForm from './BeachRegistrationForm';
import { SiteConfig } from '../lib/config';
import Image from 'next/image';
import matsommar from "../../public/images/hk-mosf.webp";
export default function BeachClientPage({ config, turnstileSiteKey }: { config: any, turnstileSiteKey: string }) {
export default function BeachClientPage({ config, turnstileSiteKey }: { config: SiteConfig, turnstileSiteKey: string }) {
const [timeInfo, setTimeInfo] = useState({
dateStr: 'Laddar...',
matchStr: 'Laddar...',
@@ -54,9 +58,9 @@ export default function BeachClientPage({ config, turnstileSiteKey }: { config:
{/* Logotyp med subtil hover-effekt */}
<div className="relative group cursor-default">
<div className="absolute -inset-4 bg-white/20 blur-2xl rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-700" />
<img
<Image
className="w-full max-w-62.5 md:max-w-75 relative drop-shadow-2xl transform hover:scale-105 transition-transform duration-500"
src="/images/hk-mosf.webp"
src={matsommar}
alt="Mat- & Sommarfesten"
/>
</div>
@@ -130,20 +134,19 @@ export default function BeachClientPage({ config, turnstileSiteKey }: { config:
<FaClipboardList size={24} />
<h4 className="font-beachday text-2xl uppercase tracking-[0.05em] text-black">Regler</h4>
</div>
<p className="text-gray-700 text-base leading-relaxed">
Matcherna spelas 4v4 med <a target="_blank" rel="noreferrer" className="text-[#39979f] font-bold hover:underline" href="https://www.volleyboll.se/forbundet/valkommen-till-volleyboll/grenar-och-spelformer/volleyboll">inomhusregler</a>,
förutom poängräkningen som följer reglerna för <a target="_blank" rel="noreferrer" className="text-[#39979f] font-bold hover:underline" href="https://www.volleyboll.se/forbundet/valkommen-till-volleyboll/grenar-och-spelformer/beachvolley">beachvolley</a>.
Turneringsformen som kommer spelas är <span className='italic'>Double Elimination</span> vilket betyder att alla lag spelar minst två matcher under dagen.
</p>
<div
className="text-gray-700 text-base leading-relaxed [&_a]:text-[#39979f] [&_a]:font-bold [&_a:hover]:underline [&_i]:italic [&_em]:italic"
dangerouslySetInnerHTML={{ __html: config.beachPage?.rulesText || "" }}
/>
<div className="flex items-center gap-3 text-[#cc8124] mt-6">
<FaUsers size={24} />
<h4 className="font-beachday text-2xl uppercase tracking-[0.05em] text-black">Klasser</h4>
</div>
<div className="text-gray-700 text-sm space-y-3">
<p className="leading-snug">Turneringen kommer att delas upp i flera olika klasser beroende antal anmälda lag och dess nivå:</p>
<p className="leading-snug">{config.beachPage?.classesIntroText}</p>
<div className="flex gap-2 flex-wrap">
{classesData.map((c: any, i: number) => (
{classesData.map((c: { name: string; color: string; desc?: string }, i: number) => (
<span
key={i}
className="px-2.5 py-1 rounded-md font-bold border text-xs tracking-wider"
@@ -153,7 +156,7 @@ export default function BeachClientPage({ config, turnstileSiteKey }: { config:
</span>
))}
</div>
<p className="italic text-xs text-gray-500">Gör en gissning er nivå i anmälan skriv gärna något extra om ni är osäkra. Vi meddelar om det skulle bli ändringar.</p>
<p className="italic text-xs text-gray-500">{config.beachPage?.classesOutroText}</p>
</div>
</div>
@@ -233,6 +236,6 @@ export default function BeachClientPage({ config, turnstileSiteKey }: { config:
</main>
<Footer />
</div>
</div >
);
}
+6 -5
View File
@@ -6,8 +6,9 @@ import { Turnstile, TurnstileInstance } from '@marsidev/react-turnstile';
import React, { useRef, useActionState, useEffect } from 'react';
import { FaUser, FaEnvelope, FaPhone, FaUsers, FaTrophy, FaCheckCircle, FaExclamationTriangle } from "react-icons/fa";
import { submitRegistration } from './actions';
import { SiteConfig } from '../lib/config';
export default function BeachRegistrationForm({ config, turnstileSiteKey }: { config: any, turnstileSiteKey: string }) {
export default function BeachRegistrationForm({ config, turnstileSiteKey }: { config: SiteConfig, turnstileSiteKey: string }) {
const [state, formAction, isPending] = useActionState(submitRegistration, null);
const formRef = useRef<HTMLFormElement>(null);
const turnstileRef = useRef<TurnstileInstance>(null);
@@ -107,7 +108,7 @@ export default function BeachRegistrationForm({ config, turnstileSiteKey }: { co
<div className="flex-2">
<label className="font-bold text-[#39979f] mb-3 block text-sm uppercase">Välj klass</label>
<div className={`grid grid-cols-2 md:grid-cols-${Math.min(classesData.length, 3)} gap-3`}>
{classesData.map((c: any) => (
{classesData.map((c: { name: string; color: string; desc?: string }) => (
<LevelButton
key={c.name}
value={c.name}
@@ -130,7 +131,7 @@ export default function BeachRegistrationForm({ config, turnstileSiteKey }: { co
<input type="text" name="website" className="hidden" tabIndex={-1} />
<div className="flex justify-center py-2"><Turnstile ref={turnstileRef} siteKey={turnstileSiteKey} options={{ theme: 'light' }}/></div>
<div className="flex justify-center py-2"><Turnstile ref={turnstileRef} siteKey={turnstileSiteKey} options={{ theme: 'light' }} /></div>
{state && (
<div className={`flex items-center gap-3 p-5 rounded-2xl font-bold transition-all ${state.success ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>
@@ -153,7 +154,7 @@ export default function BeachRegistrationForm({ config, turnstileSiteKey }: { co
}
// Uppdaterad med defaultChecked support
function LevelButton({ value, label, desc, color, defaultChecked }: any) {
function LevelButton({ value, label, desc, color, defaultChecked }: { value: string; label: string; desc?: string; color: string; defaultChecked?: boolean }) {
return (
<label className="cursor-pointer flex-1 relative" style={{ '--class-color': color } as React.CSSProperties}>
<input
@@ -173,7 +174,7 @@ function LevelButton({ value, label, desc, color, defaultChecked }: any) {
);
}
function InputGroup({ icon, ...props }: any) {
function InputGroup({ icon, ...props }: React.InputHTMLAttributes<HTMLInputElement> & { icon: React.ReactNode }) {
return (
<div className="relative group">
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-[#e6be8a] group-focus-within:text-[#39979f] transition-colors">
+1 -1
View File
@@ -4,7 +4,7 @@
import nodemailer from 'nodemailer';
export async function submitRegistration(prevState: any, formData: FormData) {
export async function submitRegistration(prevState: unknown, formData: FormData) {
// 1. Spara all rådata direkt för att kunna skicka tillbaka den vid fel
const rawData = {
name: formData.get('name') as string,