pages/ValuePartnership/PartnershipsPage/CategoryOverlay.jsxjavascript
import { useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { UIMCButton } from "@ui-marcom/react/button";
import "./CategoryOverlay.scss";

const isVideo = (path) => /\.mp4$/i.test(path);

// Plays only while its card is actually scrolled into view. A category can
// have many video-preview cards, and letting all of them decode/play
// simultaneously regardless of visibility is wasted CPU/GPU on a kiosk that
// runs for hours - the same class of always-be-rendering waste the globe's
// pauseAnimation()-while-hidden fix addressed.
const CardVideo = ({ src }) => {
  const videoRef = useRef(null);

  useEffect(() => {
    const video = videoRef.current;
    if (!video) return undefined;
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) video.play().catch(() => {});
        else video.pause();
      },
      { threshold: 0.25 }
    );
    observer.observe(video);
    return () => observer.disconnect();
  }, []);

  return (
    <video ref={videoRef} muted loop playsInline preload="metadata">
      <source src={src} type="video/mp4" />
    </video>
  );
};

CardVideo.propTypes = {
  src: PropTypes.string.isRequired,
};

/**
 * PPT-deck overlay for one department/role, ported from
 * value-partnerships-page.js's renderOverlay/renderCard. Shows every
 * `content.valuePartnership.partnerships.ppt` item whose location/roles
 * match the selected category as a clickable preview card.
 *
 * @param {Object} props
 * @param {{id: string, title: string, isntRole: boolean}} props.category
 * @param {"departments"|"roles"} props.selectedView
 * @param {Array<Object>} props.ppt - Full presentation-deck list.
 * @param {function(Object): void} props.onSelectPpt
 * @param {function(): void} props.onClose
 */
export const CategoryOverlay = ({ category, selectedView, ppt, onSelectPpt, onClose }) => {
  const items = ppt.filter((el) =>
    selectedView === "departments" || category.isntRole
      ? el.location === category.id
      : (el.roles || []).includes(category.id)
  );

  return (
    <div className="category-overlay">
      <div className="category-overlay__content">
        <h2>{category.title}</h2>
        <div className="category-overlay__cards">
          {items.map((item) => (
            <div
              key={item.id || item.content}
              className="category-overlay__card"
              onClick={() => onSelectPpt(item)}>
              <div className="category-overlay__card-media">
                {item.pictures?.[0] &&
                  (isVideo(item.pictures[0]) ? (
                    <CardVideo src={item.pictures[0]} />
                  ) : (
                    <img src={item.preview || item.pictures[0]} alt="" loading="lazy" />
                  ))}
              </div>
              <h5>{item.content}</h5>
            </div>
          ))}
        </div>
        <div className="category-overlay__buttons">
          <UIMCButton variant="standard" title="Close overlay" onClick={onClose}>
            Close overlay
          </UIMCButton>
        </div>
      </div>
    </div>
  );
};

CategoryOverlay.propTypes = {
  category: PropTypes.shape({
    id: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    isntRole: PropTypes.bool,
  }).isRequired,
  selectedView: PropTypes.oneOf(["departments", "roles"]).isRequired,
  ppt: PropTypes.array.isRequired,
  onSelectPpt: PropTypes.func.isRequired,
  onClose: PropTypes.func.isRequired,
};