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,
};