/* Sectie Kom óók buitenspelen (homepage) met een eigen, klein aanmeldformulier.
   Dit formulier staat volledig los van de formulieren op /meedoen.

   BELANGRIJK, TWEE LIJSTEN, NIET DOOR ELKAAR HALEN
   BB_ACTIVITEITEN            de echte activiteiten. Alleen hier iets invullen.
   BB_ACTIVITEITEN_VOORBEELD  drie verzonnen activiteiten om de opmaak te bekijken.
                              Die horen nooit op de live website te staan.

   De voorbeelden verschijnen alleen als BB_ACTIVITEITEN leeg is EN de schakelaar
   activiteitenDemo in index.html op true staat. Die staat sinds 30 augustus 2026 op
   false, want de voorbeelden stonden per ongeluk live en bezoekers zagen drie
   verzonnen activiteiten waar zij zich niet zinvol voor konden aanmelden.

   Activiteit toevoegen: zet een blok in BB_ACTIVITEITEN. Is die lijst leeg, dan
   verbergt de hele sectie zich automatisch. Vanaf 3 activiteiten verschijnt een
   carrousel. Volledige uitleg: source_docs/Activiteiten onderhouden.docx

   {
     id: "unieke-naam",
     titel: "Vossenjacht in het park",
     buurt: "Houtvaartkwartier",
     leeftijd: "10 tot 12 jaar",   // laat weg of zet "" voor een activiteit zonder leeftijdsgrens
     datum: "woensdag 3 september 2026",
     tijd: "15:30",
     foto: "assets/photos/voetballend.jpg",
     fotoAlt: "Beschrijf kort wat er op de foto te zien is.",
     appLink: "",            // optioneel: uitnodigingslink van de buurtapp
     aan: false,             // optioneel: zet de activiteit tijdelijk uit, zonder hem te wissen
   }
*/

// Hoofdschakelaar voor de hele sectie. Op false verdwijnt Kom óók buitenspelen van
// de homepage, ook als er activiteiten in de lijst staan.
const BB_ACTIVITEITEN_SECTIE_AAN = true;

// DE ECHTE ACTIVITEITEN. Hier hoort alles in wat op de website moet komen.
// Zolang deze lijst leeg is, verbergt de sectie zich op de homepage.
const BB_ACTIVITEITEN = [];

// VOORBEELDEN, NIET VOOR PUBLICATIE. Deze drie activiteiten zijn verzonnen en dienen
// alleen om de opmaak te bekijken: één kaart, twee kaarten of de carrousel. Zij komen
// uitsluitend in beeld als BB_ACTIVITEITEN leeg is EN activiteitenDemo in index.html
// op true staat. Zet die schakelaar dus nooit op true op de live website.
const BB_ACTIVITEITEN_VOORBEELD = [
  {
    id: "voorbeeld-1",
    titel: "Vossenjacht in de buurt",
    buurt: "Houtvaartkwartier",
    leeftijd: "10 tot 12 jaar",
    datum: "woensdag 9 september 2026",
    tijd: "15:30",
    foto: "assets/photos/voetballend.jpg",
    fotoAlt: "Kinderen voetballen op een grasveldje in de buurt.",
  },
  {
    id: "voorbeeld-2",
    titel: "Steppen en klimmen op het plein",
    buurt: "Leidsebuurt",
    leeftijd: "12 tot 16 jaar",
    datum: "zaterdag 12 september 2026",
    tijd: "14:00",
    foto: "assets/photos/steppende-kinderen.jpg",
    fotoAlt: "Twee kinderen steppen over een pleintje.",
  },
  {
    id: "voorbeeld-3",
    titel: "Buitenspeeldag met stoepkrijt en blikspel",
    buurt: "Schalkwijk",
    leeftijd: "",
    datum: "woensdag 10 juni 2026",
    tijd: "14:00",
    foto: "assets/photos/klimnet-meiden.jpg",
    fotoAlt: "Meiden klimmen in een klimnet in de speeltuin.",
  },
  {
    id: "voorbeeld-4",
    titel: "Glow in the dark paaltjesvoetbal",
    buurt: "Stationsbuurt",
    leeftijd: "12 tot 16 jaar",
    datum: "vrijdag 6 november 2026",
    tijd: "19:00",
    foto: "assets/photos/bal-tegen-muurtje.jpg",
    fotoAlt: "Een jongen trapt een bal tegen een muurtje op straat.",
  },
  {
    id: "voorbeeld-5",
    titel: "Trefbaltoernooi op het grasveld",
    buurt: "Haarlem Zuid-West",
    leeftijd: "10 tot 16 jaar",
    datum: "zondag 27 september 2026",
    tijd: "13:00",
    foto: "assets/photos/softbal-haarlem-kids-2.jpg",
    fotoAlt: "Een groep kinderen speelt samen met een bal op een veldje.",
  },
];

function WaGlyph({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M12.04 2C6.58 2 2.13 6.45 2.13 11.91c0 1.75.46 3.45 1.32 4.95L2 22l5.25-1.38a9.9 9.9 0 0 0 4.79 1.22h.01c5.46 0 9.91-4.45 9.91-9.91C21.96 6.45 17.5 2 12.04 2zm0 18.15h-.01a8.2 8.2 0 0 1-4.18-1.15l-.3-.18-3.11.82.83-3.04-.19-.31a8.19 8.19 0 0 1-1.26-4.38c0-4.54 3.7-8.23 8.23-8.23 2.2 0 4.26.86 5.82 2.41a8.17 8.17 0 0 1 2.41 5.82c0 4.54-3.7 8.24-8.24 8.24zm4.52-6.16c-.25-.12-1.47-.72-1.69-.81-.23-.08-.39-.12-.56.13-.16.25-.64.81-.79.97-.14.17-.29.19-.54.06-.25-.12-1.05-.39-2-1.23-.74-.66-1.24-1.47-1.38-1.72-.15-.25-.02-.39.11-.51.11-.11.25-.29.37-.44.12-.14.16-.25.25-.41.08-.17.04-.31-.02-.44-.06-.12-.56-1.35-.77-1.84-.2-.49-.41-.42-.56-.43h-.48c-.16 0-.42.06-.64.31-.22.25-.84.82-.84 2 0 1.18.86 2.32.98 2.48.12.17 1.69 2.58 4.09 3.62.57.25 1.02.39 1.37.5.58.18 1.1.16 1.52.1.46-.07 1.47-.6 1.68-1.18.21-.58.21-1.08.15-1.18-.06-.11-.23-.17-.48-.29z"></path>
    </svg>
  );
}

function ActiviteitKaart({ a, onDoeMee, tabbable = true }) {
  // De link wijst naar het anker van de activiteiten-sectie, zodat wie het bericht
  // opent direct bij de activiteit uitkomt en zich meteen kan aanmelden. Altijd het
  // echte domein, ook vanaf een testomgeving, zodat het gedeelde bericht meteen klopt.
  const tekst = "Buiten Buddies: " + a.titel + " in " + a.buurt + ", " + a.datum + " om " + a.tijd + " uur"
    + ". Ga je ook mee? Meld je dan altijd ook zelf eerst aan voor de activiteit via de homepage van Buiten Buddies.\n"
    + "https://www.buitenbuddies.org/#activiteiten";
  return (
    <FadeUp className="bb-act__card">
      {a.foto && (
        <div className="bb-act__foto">
          <img src={a.foto} alt={a.fotoAlt || ""} />
        </div>
      )}
      <div className="bb-act__body">
        <h3>{a.titel}</h3>
        <ul className="bb-act__meta">
          <li className="bb-act__chip bb-act__chip--buurt"><Icon name="map" size={15} /><span>{a.buurt}</span></li>
          <li className="bb-act__chip bb-act__chip--leeftijd"><Icon name="users" size={15} /><span>{a.leeftijd ? a.leeftijd : "Alle leeftijden"}</span></li>
          <li className="bb-act__chip bb-act__chip--wanneer"><Icon name="calendar" size={15} /><span>{a.datum + ", om " + a.tijd + " uur"}</span></li>
        </ul>
        <div className="bb-act__acts">
          <button type="button" className="bb-btn bb-btn--yellow" onClick={() => onDoeMee(a)} tabIndex={tabbable ? 0 : -1}>Doe mee</button>
          <a
            className="bb-act__wa"
            href={"https://wa.me/?text=" + encodeURIComponent(tekst)}
            target="_blank" rel="noopener noreferrer" tabIndex={tabbable ? 0 : -1}
          >
            <WaGlyph /> Deel via WhatsApp
          </a>
        </div>
      </div>
    </FadeUp>
  );
}

// Leest de leeftijdsgrenzen uit de tekst van de activiteit, bijvoorbeeld
// "10 tot 12 jaar", "12-16 jaar" of "vanaf 10 jaar". Staat er geen leeftijd bij de
// activiteit, dan geldt er geen leeftijdsgrens en mag ieder kind meedoen.
function bbLeeftijdGrenzen(tekst) {
  const getallen = String(tekst || "").match(/\d{1,2}/g);
  if (!getallen || !getallen.length) return { min: 1, max: 18, vrij: true };
  const n = getallen.map(Number);
  if (n.length === 1) return /vanaf|ouder/i.test(tekst) ? { min: n[0], max: 18 } : { min: n[0], max: n[0] };
  return { min: Math.min.apply(null, n), max: Math.max.apply(null, n) };
}

function bbValidateActiviteit(v, grenzen) {
  const g = grenzen || { min: 1, max: 18, vrij: true };
  const e = {};
  const kv = v.kindVoornaam.trim();
  if (!kv) e.kindVoornaam = "Vul de voornaam van je kind in.";
  else if (!window.bbIsVoornaam(kv)) e.kindVoornaam = window.BB_VOORNAAM_KIND_FOUT;
  if (!v.kindAchternaam.trim()) e.kindAchternaam = "Vul de achternaam van je kind in.";
  const leeftijd = parseInt(v.kindLeeftijd, 10);
  if (!v.kindLeeftijd) e.kindLeeftijd = "Vul de leeftijd van je kind in.";
  else if (isNaN(leeftijd) || leeftijd < g.min || leeftijd > g.max) {
    e.kindLeeftijd = g.vrij
      ? "Vul de leeftijd van je kind in, in hele jaren."
      : g.min === g.max
        ? "Deze activiteit is voor kinderen van " + g.min + " jaar."
        : "Deze activiteit is voor kinderen van " + g.min + " tot " + g.max + " jaar. Vul een leeftijd in binnen die groep.";
  }
  const ov = v.ouderVoornaam.trim();
  if (!ov) e.ouderVoornaam = "Vul je voornaam in.";
  else if (!window.bbIsVoornaam(ov)) e.ouderVoornaam = window.BB_VOORNAAM_FOUT;
  if (!v.ouderAchternaam.trim()) e.ouderAchternaam = "Vul je achternaam in.";
  if (!v.ouderTelefoon.trim()) e.ouderTelefoon = "Vul je telefoonnummer in.";
  else if (!window.bbIsPhone(v.ouderTelefoon)) e.ouderTelefoon = "Vul een geldig Nederlands telefoonnummer in van 10 cijfers, bijvoorbeeld 06-12345678.";
  if (!v.toestemming) e.toestemming = "Zonder jouw toestemming kunnen we je kind niet aanmelden.";
  return e;
}

function ActiviteitFormulier({ activiteit, onKlaar }) {
  const [v, setV] = useState({
    kindVoornaam: "", kindTussenvoegsel: "", kindAchternaam: "", kindLeeftijd: "",
    ouderVoornaam: "", ouderTussenvoegsel: "", ouderAchternaam: "", ouderTelefoon: "",
    toestemming: false,
  });
  const [errors, setErrors] = useState({});
  const [status, setStatus] = useState("idle");
  const summaryRef = useRef(null);
  const grenzen = bbLeeftijdGrenzen(activiteit.leeftijd);

  const set = (k) => (val) => {
    setV((p) => Object.assign({}, p, { [k]: val }));
    if (errors[k]) setErrors((p) => { const n = Object.assign({}, p); delete n[k]; return n; });
  };
  const blur = (k) => () => {
    const e = bbValidateActiviteit(v, grenzen);
    setErrors((p) => {
      const n = Object.assign({}, p);
      if (e[k]) n[k] = e[k]; else delete n[k];
      return n;
    });
  };
  const send = async () => {
    setStatus("sending");
    try {
      await window.bbSubmitForm("activiteit", Object.assign({}, v, {
        activiteit: activiteit.titel, buurt: activiteit.buurt,
        wanneer: activiteit.datum + " om " + activiteit.tijd + " uur",
        leeftijdsgroep: activiteit.leeftijd ? activiteit.leeftijd : "Alle leeftijden",
      }));
      setStatus("sent");
      if (window.bbGaEvent) window.bbGaEvent("formulier_verzonden", { formulier: "activiteit", activiteit: activiteit.titel, buurt: activiteit.buurt });
    } catch (err) { setStatus("senderror"); }
  };
  const onSubmit = (e) => {
    e.preventDefault();
    const errs = bbValidateActiviteit(v, grenzen);
    setErrors(errs);
    if (Object.keys(errs).length) {
      requestAnimationFrame(() => { if (summaryRef.current) summaryRef.current.focus(); });
      return;
    }
    send();
  };

  if (status === "sent") {
    return (
      <div className="bb-act__klaar" role="status">
        <ConfettiRain />
        <span className="bb-act__vink" aria-hidden="true"><Icon name="check" size={26} /></span>
        <h4>Bedankt voor je aanmelding!</h4>
        <p>We nemen contact op met meer informatie over de activiteit.</p>
        <div className="bb-act__klaaracts">
          {activiteit.appLink && (
            <Button variant="yellow" href={activiteit.appLink} external>
              Open de buurtapp <Icon name="arrowRight" size={16} />
            </Button>
          )}
          <Button variant="secondary" onClick={onKlaar}>Sluiten</Button>
        </div>
      </div>
    );
  }

  return (
    <form className="bb-form bb-act__form" onSubmit={onSubmit} noValidate>
      <ErrorSummary
        errors={errors} summaryRef={summaryRef}
        order={["kindVoornaam", "kindAchternaam", "kindLeeftijd", "ouderVoornaam", "ouderAchternaam", "ouderTelefoon", "toestemming"]}
      />

      <p className="bb-form__grouplabel">Je kind</p>
      <div className="bb-form__row bb-form__row--name">
        <Field id="act-kindVoornaam" label="Voornaam" error={errors.kindVoornaam} required>
          <TextInput id="act-kindVoornaam" value={v.kindVoornaam} onChange={set("kindVoornaam")} onBlur={blur("kindVoornaam")} error={errors.kindVoornaam} />
        </Field>
        <Field id="act-kindTussenvoegsel" label="Tussenvoegsel" hideOpt>
          <TextInput id="act-kindTussenvoegsel" value={v.kindTussenvoegsel} onChange={set("kindTussenvoegsel")} />
        </Field>
        <Field id="act-kindAchternaam" label="Achternaam" error={errors.kindAchternaam} required>
          <TextInput id="act-kindAchternaam" value={v.kindAchternaam} onChange={set("kindAchternaam")} onBlur={blur("kindAchternaam")} error={errors.kindAchternaam} />
        </Field>
      </div>
      <div className="bb-form__row bb-act__row--leeftijd">
        <Field
          id="act-kindLeeftijd" label="Leeftijd"
          hint={grenzen.vrij
            ? "Deze activiteit is voor alle leeftijden."
            : grenzen.min === grenzen.max
              ? "Deze activiteit is voor " + grenzen.min + " jaar."
              : "Deze activiteit is voor " + grenzen.min + " tot " + grenzen.max + " jaar."}
          error={errors.kindLeeftijd} required
        >
          <TextInput id="act-kindLeeftijd" type="number" min={String(grenzen.min)} max={String(grenzen.max)} inputMode="numeric" value={v.kindLeeftijd} onChange={set("kindLeeftijd")} onBlur={blur("kindLeeftijd")} error={errors.kindLeeftijd} hint />
        </Field>
      </div>

      <p className="bb-form__grouplabel">Ouder of verzorger</p>
      <div className="bb-form__row bb-form__row--name">
        <Field id="act-ouderVoornaam" label="Voornaam" error={errors.ouderVoornaam} required>
          <TextInput id="act-ouderVoornaam" value={v.ouderVoornaam} onChange={set("ouderVoornaam")} onBlur={blur("ouderVoornaam")} error={errors.ouderVoornaam} autoComplete="given-name" />
        </Field>
        <Field id="act-ouderTussenvoegsel" label="Tussenvoegsel" hideOpt>
          <TextInput id="act-ouderTussenvoegsel" value={v.ouderTussenvoegsel} onChange={set("ouderTussenvoegsel")} autoComplete="additional-name" />
        </Field>
        <Field id="act-ouderAchternaam" label="Achternaam" error={errors.ouderAchternaam} required>
          <TextInput id="act-ouderAchternaam" value={v.ouderAchternaam} onChange={set("ouderAchternaam")} onBlur={blur("ouderAchternaam")} error={errors.ouderAchternaam} autoComplete="family-name" />
        </Field>
      </div>
      <div className="bb-form__row">
        <Field id="act-ouderTelefoon" label="Telefoonnummer ouder" hint="Voor contact over de activiteit." error={errors.ouderTelefoon} required>
          <TextInput id="act-ouderTelefoon" type="tel" value={v.ouderTelefoon} onChange={set("ouderTelefoon")} onBlur={blur("ouderTelefoon")} error={errors.ouderTelefoon} hint autoComplete="tel" placeholder="06-12345678" />
        </Field>
      </div>

      <div className="bb-checks">
        <CheckRow id="act-toestemming" checked={v.toestemming} onChange={set("toestemming")} error={errors.toestemming}>
          Ik geef als ouder of verzorger toestemming voor deelname van mijn kind aan deze activiteit.
          Ik begrijp dat de activiteit te vergelijken is met vrij buitenspelen in de buurt: Buiten
          Buddies of een groepsbeheerder uit de buurt verzorgt het spel, maar houdt geen toezicht en
          draagt geen verantwoordelijkheid of aansprakelijkheid voor de kinderen. <span className="bb-field__req" aria-hidden="true">*</span>
        </CheckRow>
      </div>

      {status === "senderror" && (
        <div className="bb-form__summary bb-form__summary--send" role="alert">
          <strong>Het versturen is niet gelukt.</strong>
          <p>
            Probeer het nog een keer, of mail je aanmelding naar{" "}
            <a href="mailto:info@buitenbuddies.org">info@buitenbuddies.org</a>.
          </p>
        </div>
      )}

      <div className="bb-form__foot">
        <Button variant="yellow" type="submit" disabled={status === "sending"}>
          {status === "sending" ? "Versturen\u2026" : "Aanmelden voor deze activiteit"} <Icon name="arrowRight" />
        </Button>
        <p className="bb-form__note">Velden met een <span className="bb-field__req">*</span> zijn verplicht.</p>
      </div>
    </form>
  );
}

function ActiviteitDialoog({ activiteit, onSluit }) {
  const paneelRef = useRef(null);
  const vorigeFocus = useRef(null);

  useEffect(() => {
    vorigeFocus.current = document.activeElement;
    const vorigeOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    const eerste = paneelRef.current && paneelRef.current.querySelector("input, button");
    if (eerste) eerste.focus();
    const onKey = (e) => {
      if (e.key === "Escape") { e.preventDefault(); onSluit(); return; }
      if (e.key !== "Tab" || !paneelRef.current) return;
      const f = paneelRef.current.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');
      if (!f.length) return;
      const eerst = f[0], laatst = f[f.length - 1];
      if (e.shiftKey && document.activeElement === eerst) { e.preventDefault(); laatst.focus(); }
      else if (!e.shiftKey && document.activeElement === laatst) { e.preventDefault(); eerst.focus(); }
    };
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("keydown", onKey);
      document.body.style.overflow = vorigeOverflow;
      if (vorigeFocus.current && vorigeFocus.current.focus) vorigeFocus.current.focus();
    };
  }, [onSluit]);

  return (
    <div className="bb-act__overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onSluit(); }}>
      <div className="bb-act__paneel" role="dialog" aria-modal="true" aria-labelledby="act-dialoog-titel" ref={paneelRef}>
        <div className="bb-act__paneelkop">
          <div>
            <p className="bb-act__paneelkicker">Aanmelden</p>
            <h3 id="act-dialoog-titel">{activiteit.titel}</h3>
            <p className="bb-act__paneelmeta">{activiteit.buurt} · {activiteit.datum}, om {activiteit.tijd} uur · {activiteit.leeftijd ? activiteit.leeftijd : "alle leeftijden"}</p>
          </div>
          <button type="button" className="bb-act__sluit" onClick={onSluit} aria-label="Formulier sluiten">
            <Icon name="close" size={20} />
          </button>
        </div>
        <div className="bb-act__paneelbody">
          <ActiviteitFormulier activiteit={activiteit} onKlaar={onSluit} />
        </div>
      </div>
    </div>
  );
}

function ActiviteitenCarrousel({ lijst, onDoeMee }) {
  const [perView, setPerView] = useState(2);
  const [page, setPage] = useState(0);
  const [stap, setStap] = useState(0);
  const touchX = useRef(null);
  const trackRef = useRef(null);

  useEffect(() => {
    const calc = () => setPerView(Math.min(lijst.length, window.innerWidth >= 760 ? 2 : 1));
    calc();
    window.addEventListener("resize", calc);
    return () => window.removeEventListener("resize", calc);
  }, [lijst.length]);

  // Schuifafstand uit de echte kaartbreedte, zodat de laatste pagina exact past.
  useEffect(() => {
    const meet = () => {
      const t = trackRef.current;
      const eerste = t && t.firstElementChild;
      if (!eerste) return;
      const gap = parseFloat(getComputedStyle(t).columnGap) || 24;
      setStap(perView * (eerste.getBoundingClientRect().width + gap));
    };
    meet();
    const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(meet) : null;
    if (ro && trackRef.current) ro.observe(trackRef.current);
    window.addEventListener("resize", meet);
    return () => { if (ro) ro.disconnect(); window.removeEventListener("resize", meet); };
  }, [perView, lijst.length]);

  const pages = Math.max(1, Math.ceil(lijst.length / perView));
  useEffect(() => { setPage((p) => Math.min(p, pages - 1)); }, [pages]);

  const goTo = (p) => setPage(Math.max(0, Math.min(pages - 1, p)));
  const onKeyDown = (e) => {
    if (e.key === "ArrowRight") { e.preventDefault(); goTo(page + 1); }
    if (e.key === "ArrowLeft") { e.preventDefault(); goTo(page - 1); }
  };
  const onTouchStart = (e) => { touchX.current = e.touches[0].clientX; };
  const onTouchEnd = (e) => {
    if (touchX.current == null) return;
    const dx = e.changedTouches[0].clientX - touchX.current;
    if (Math.abs(dx) > 45) goTo(page + (dx < 0 ? 1 : -1));
    touchX.current = null;
  };

  return (
    <div
      className="bb-carousel bb-act__carousel" role="group" aria-roledescription="carrousel"
      aria-label="Activiteiten in de buurt" onKeyDown={onKeyDown}
    >
      <div className="bb-carousel__viewport" onTouchStart={onTouchStart} onTouchEnd={onTouchEnd}>
        <div
          className="bb-carousel__track"
          ref={trackRef}
          style={{ "--per-view": perView, transform: "translateX(" + (-page * stap) + "px)" }}
        >
          {lijst.map((a, i) => {
            const zichtbaar = i >= page * perView && i < page * perView + perView;
            return (
              <div
                key={a.id} className="bb-carousel__slide" role="group"
                aria-roledescription="slide" aria-label={a.titel} aria-hidden={!zichtbaar}
              >
                <ActiviteitKaart a={a} onDoeMee={onDoeMee} tabbable={zichtbaar} />
              </div>
            );
          })}
        </div>
      </div>
      {pages > 1 && (
        <div className="bb-carousel__controls">
          <button
            type="button" className={"bb-carousel__arrow" + (page === pages - 1 ? " is-glow" : "")} onClick={() => goTo(page - 1)}
            disabled={page === 0} aria-label="Vorige activiteiten"
          ><Icon name="arrowLeft" size={20} /></button>
          <div className="bb-carousel__dots">
            {Array.from({ length: pages }).map((_, p) => (
              <button
                key={p} type="button" className="bb-carousel__dot" onClick={() => goTo(p)}
                aria-current={p === page ? "true" : undefined}
                aria-label={"Ga naar positie " + (p + 1) + " van " + pages}
              ><span aria-hidden="true"></span></button>
            ))}
          </div>
          <button
            type="button" className={"bb-carousel__arrow" + (page < pages - 1 ? " is-glow" : "")} onClick={() => goTo(page + 1)}
            disabled={page === pages - 1} aria-label="Volgende activiteiten"
          ><Icon name="arrowRight" size={20} /></button>
        </div>
      )}
    </div>
  );
}

function ActiviteitenSection({ demo, demoAantal }) {
  // De echte activiteiten hebben altijd voorrang. Staat er iets in BB_ACTIVITEITEN, dan
  // doen de voorbeelden nooit meer mee, ook niet als de schakelaar activiteitenDemo aan
  // zou staan. Is de echte lijst leeg, dan blijft de sectie leeg, tenzij die schakelaar
  // in index.html op true staat. Zo kunnen de voorbeelden nooit ongemerkt live komen.
  // Een activiteit met aan: false doet niet mee, die staat tijdelijk uit. Dat werkt in
  // beide lijsten, dus ook bij de voorbeelden.
  const uit = (a) => a && a.aan !== false;
  const echt = BB_ACTIVITEITEN.filter(uit);
  const bron = echt.length ? echt : (demo ? BB_ACTIVITEITEN_VOORBEELD.filter(uit) : []);
  // Alleen voor de voorbeelden: beperk het aantal om de opmaak bij 1 of 2 activiteiten te bekijken.
  const max = echt.length ? 0 : parseInt(demoAantal, 10) || 0;
  const lijst = max ? bron.slice(0, max) : bron;
  const [open, setOpen] = useState(null);
  if (!BB_ACTIVITEITEN_SECTIE_AAN || !lijst.length) return null;
  // Vanaf 3 activiteiten een carrousel, daaronder gewoon onder elkaar of naast elkaar.
  const carrousel = lijst.length >= 3;

  return (
    <section className="bb-section bb-act" id="activiteiten" aria-labelledby="act-heading" data-screen-label="Activiteiten">
      <Container>
        <div className="bb-section__head">
          <FadeUp>
            <div className="bb-eyebrow">
              <span className="dot" aria-hidden="true"></span>
              Activiteiten
            </div>
          </FadeUp>
          <FadeUp delay={80}><h2 id="act-heading">Kom óók buitenspelen!</h2></FadeUp>
          <FadeUp delay={140}>
            <p>Soms organiseren we buurtspellen of activiteiten zodat jongeren elkaar makkelijker leren kennen. Meld je daarom nu ook aan voor onze speciale en superleuke buitenspeelactiviteit, binnenkort misschien bij jou in de buurt.</p>
          </FadeUp>
        </div>
        {carrousel ? (
          <FadeUp delay={200}>
            <ActiviteitenCarrousel lijst={lijst} onDoeMee={setOpen} />
          </FadeUp>
        ) : (
          <div className={"bb-act__lijst" + (lijst.length === 1 ? " bb-act__lijst--een" : "")}>
            {lijst.map((a) => <ActiviteitKaart key={a.id} a={a} onDoeMee={setOpen} />)}
          </div>
        )}
      </Container>
      {open && <ActiviteitDialoog activiteit={open} onSluit={() => setOpen(null)} />}
    </section>
  );
}

Object.assign(window, {
  ActiviteitenSection, ActiviteitenCarrousel, ActiviteitKaart, ActiviteitDialoog, ActiviteitFormulier,
  BB_ACTIVITEITEN, BB_ACTIVITEITEN_VOORBEELD, BB_ACTIVITEITEN_SECTIE_AAN, bbLeeftijdGrenzen,
});
