/** * @fileoverview React component for ConfettiOverlay.jsx * * @module components.game.ConfettiOverlay */ import React, { useEffect, useRef } from "react"; import PropTypes from "prop-types"; import { confetti } from "@tsparticles/confetti"; const ConfettiOverlay = ({ isActive, onComplete, // english alias active, onFinish }) => { const isActiveEffective = isActive ?? active; const onCompleteEffective = onComplete ?? onFinish; const canvasRef = useRef(null); const timeoutRef = useRef(null); useEffect(() => { if (isActiveEffective && canvasRef.current) { const canvas = canvasRef.current; const randomInRange = (min, max) => { return Math.random() * (max - min) + min; }; const triggerConfettiBlast = async () => { const defaultOptions = { angle: randomInRange(55, 125), spread: randomInRange(50, 70), particleCount: randomInRange(50, 100), origin: { y: 0.6 }, canvas: canvas, }; await confetti(defaultOptions); }; triggerConfettiBlast(); timeoutRef.current = setTimeout(() => { if (onCompleteEffective) { onCompleteEffective(); } }, 500); } else if (!isActive && canvasRef.current) { const canvas = canvasRef.current; const ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); } return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, [isActiveEffective, onCompleteEffective]); useEffect(() => { const updateCanvasSize = () => { if (canvasRef.current) { canvasRef.current.width = window.innerWidth; canvasRef.current.height = window.innerHeight; } }; updateCanvasSize(); window.addEventListener("resize", updateCanvasSize); return () => window.removeEventListener("resize", updateCanvasSize); }, []); return ( ); }; ConfettiOverlay.propTypes = { isActive: PropTypes.bool, active: PropTypes.bool, onComplete: PropTypes.func, onFinish: PropTypes.func, }; export default ConfettiOverlay;