wwwlayermeshusa/src/blocks/FDServiceChooserBlock/Component.tsx

146 lines
5.4 KiB
TypeScript

'use client'
import React, { useState, useRef, useEffect } from 'react'
import type { FDServiceChooserBlock as Props } from '@/payload-types'
/* Consistent radius system — same as CardGrid, PricingCard, etc. */
const cardRadius = 'rounded-[32px] md:rounded-[50px] lg:rounded-[70px]'
export const FDServiceChooserBlockComponent: React.FC<Props> = ({
heading,
description,
categories = [],
sectionBackground = 'gray',
anchorId,
}) => {
const [activeIndex, setActiveIndex] = useState(0)
const [animating, setAnimating] = useState(false)
const [prefersReducedMotion, setPrefersReducedMotion] = useState(false)
const prevIndex = useRef(0)
/* Priority #8: Detect prefers-reduced-motion */
useEffect(() => {
const mql = window.matchMedia('(prefers-reduced-motion: reduce)')
setPrefersReducedMotion(mql.matches)
const handler = (e: MediaQueryListEvent) => setPrefersReducedMotion(e.matches)
mql.addEventListener('change', handler)
return () => mql.removeEventListener('change', handler)
}, [])
const isDark = sectionBackground === 'navy'
const bgClass = isDark ? 'bg-fd-navy' : sectionBackground === 'gray' ? 'bg-fd-surface-alt dark:bg-fd-navy' : 'bg-white dark:bg-fd-navy'
const titleClass = isDark ? 'text-fd-yellow' : 'text-fd-navy dark:text-fd-yellow'
const bodyClass = isDark ? 'text-white' : 'text-fd-navy dark:text-white'
const cardBg = isDark ? 'bg-white/10 border-[5px] border-white/10' : 'bg-white border-[5px] border-gray-200 dark:bg-white/10 dark:border-white/10'
const handleTabChange = (i: number) => {
if (i === activeIndex) return
if (prefersReducedMotion) {
/* Instant switch — no animation */
setActiveIndex(i)
return
}
setAnimating(true)
prevIndex.current = activeIndex
setTimeout(() => {
setActiveIndex(i)
setAnimating(false)
}, 200)
}
const activeCategory = (categories ?? [])[activeIndex]
return (
<section id={anchorId || undefined} className={`w-full py-16 md:py-20 lg:py-[99px] ${bgClass}`}>
<div className="max-w-[1200px] mx-auto px-6 md:px-8">
<div className="text-center mb-10 md:mb-12">
{heading && (
<h2 className={`font-joey-heavy text-fd-h1 mb-4 ${titleClass}`}>
{heading}
</h2>
)}
{description && (
<p className={`font-joey text-fd-body-lg max-w-[600px] mx-auto ${bodyClass}`}>
{description}
</p>
)}
</div>
<div className="flex flex-wrap justify-center gap-2 md:gap-3 mb-10 md:mb-12">
{(categories ?? []).map((cat, i) => (
<button
key={i}
onClick={() => handleTabChange(i)}
className={`px-5 py-2 rounded-full font-joey-medium text-fd-body transition-all duration-200 border-2 ${
activeIndex === i
? 'bg-fd-yellow border-fd-yellow text-fd-navy shadow-sm'
: isDark
? 'border-white/30 text-white hover:border-fd-yellow hover:text-fd-yellow'
: 'border-fd-navy/20 text-fd-navy hover:border-fd-yellow hover:bg-fd-yellow/10 dark:border-white/30 dark:text-white dark:hover:border-fd-yellow dark:hover:text-fd-yellow'
}`}
>
{cat.label}
</button>
))}
</div>
<div
className={
prefersReducedMotion
? '' /* No transition when motion is reduced */
: `transition-all duration-200 ${animating ? 'opacity-0 translate-y-2' : 'opacity-100 translate-y-0'}`
}
style={{ minHeight: '200px' }}
>
{activeCategory?.intro && (
<p className={`text-center font-joey text-fd-body mb-6 opacity-70 ${bodyClass}`}>
{activeCategory.intro}
</p>
)}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 md:gap-6">
{activeCategory?.services?.map((service, i) => (
<div
key={i}
className={`${cardRadius} p-8 md:p-12 flex flex-col gap-4 ${cardBg}`}
style={
prefersReducedMotion
? undefined
: {
transition: 'opacity 0.3s, transform 0.3s',
transitionDelay: `${i * 60}ms`,
opacity: animating ? 0 : 1,
transform: animating ? 'translateY(8px)' : 'translateY(0)',
}
}
>
<h3 className={`font-joey-bold text-fd-h3 ${isDark ? 'text-fd-yellow' : 'text-fd-navy dark:text-fd-yellow'}`}>
{service.title}
</h3>
{service.description && (
<p className={`font-joey text-fd-body opacity-80 flex-1 ${bodyClass}`}>
{service.description}
</p>
)}
{service.ctaText && (
<div className="mt-auto pt-2">
<a
href={service.ctaLink || '/kontakt'}
className={isDark ? 'fd-btn-secondary-dark' : 'fd-btn-secondary dark:fd-btn-secondary-dark'}
>
{service.ctaText}
</a>
</div>
)}
</div>
))}
</div>
</div>
</div>
</section>
)
}