UNPKG

leumas-private-shared

Version:

Private React JSX Package For Leumas Shared Components, Headers, Footers, Asides, Login Pages, API Key Manager and much more. Styles and everything reusable to avoid DRY code across all of our subdomains

192 lines (174 loc) 7.08 kB
import React, { useState, useEffect, useRef } from 'react'; import { Container, Typography, Card, CardContent, Button, IconButton, Box } from '@mui/material'; import { Helmet } from 'react-helmet-async'; import { FaLinkedin, FaGithub, FaPlay, FaPause, FaForward, FaBackward } from 'react-icons/fa'; import { SiFiverr } from "react-icons/si"; import InfinityBackgroundComponent from '../Components/Backgrounds/Infinity'; import Gallery from '../Components/Gallery/Gallery'; const ServicePage = ({ service, galleryConfig }) => { const [audioFiles, setAudioFiles] = useState([]); const [currentAudio, setCurrentAudio] = useState(null); const [audio, setAudio] = useState(null); const [audioPlaying, setAudioPlaying] = useState(false); const [frequencyData, setFrequencyData] = useState([]); const [strobeMode, setStrobeMode] = useState(false); // State to toggle strobe mode const audioContextRef = useRef(null); const analyzerRef = useRef(null); useEffect(() => { const fetchAudioFiles = async () => { try { const response = await fetch('http://localhost:3002/cloudinary/audio/Audio', { mode: 'cors' }); const data = await response.json(); console.log(data); setAudioFiles(data); const defaultAudio = data.find(file => file.title === 'Skyfall_Lyrics_8D_Audio_z7ym2u'); if (defaultAudio) { setCurrentAudio(defaultAudio); const newAudio = new Audio(defaultAudio.src); newAudio.crossOrigin = "anonymous"; // Add crossOrigin attribute setAudio(newAudio); } } catch (error) { console.error('Error fetching audio files:', error); } }; fetchAudioFiles(); }, []); useEffect(() => { if (audio && audioPlaying) { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const analyzer = audioContext.createAnalyser(); const source = audioContext.createMediaElementSource(audio); source.connect(analyzer); analyzer.connect(audioContext.destination); analyzer.fftSize = 256; const bufferLength = analyzer.frequencyBinCount; const dataArray = new Uint8Array(bufferLength); const updateFrequencyData = () => { analyzer.getByteFrequencyData(dataArray); setFrequencyData([...dataArray]); requestAnimationFrame(updateFrequencyData); }; updateFrequencyData(); audioContextRef.current = audioContext; analyzerRef.current = analyzer; audio.play().catch(error => console.error('Error playing audio:', error)); return () => { audio.pause(); audioContext.close(); }; } }, [audio, audioPlaying]); const handleAudioChange = (newAudio) => { if (audio) { audio.pause(); } const newAudioElement = new Audio(newAudio.src); newAudioElement.crossOrigin = "anonymous"; // Add crossOrigin attribute setCurrentAudio(newAudio); setAudio(newAudioElement); setAudioPlaying(true); }; const handleAudioPlayPause = () => { if (audio) { if (audioPlaying) { audio.pause(); } else { audio.play().catch(error => console.error('Error playing audio:', error)); } setAudioPlaying(!audioPlaying); } }; const handleAudioSkip = (direction) => { if (audioFiles.length > 0) { const currentIndex = audioFiles.findIndex(file => file.src === currentAudio.src); let newIndex; if (direction === 'next') { newIndex = (currentIndex + 1) % audioFiles.length; } else { newIndex = (currentIndex - 1 + audioFiles.length) % audioFiles.length; } handleAudioChange(audioFiles[newIndex]); } }; const toggleStrobeMode = () => { setStrobeMode(!strobeMode); }; if (!service) { return <Typography variant="h6" component="p">Service not found.</Typography>; } return ( <InfinityBackgroundComponent> <Helmet> <title>{service.seo.title}</title> <meta name="description" content={service.seo.description} /> <meta name="keywords" content={service.seo.keywords} /> </Helmet> <Container sx={{ position: 'relative', height: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'start', textAlign: 'center', padding: '20px' }} > <div style={{ position: 'absolute', top: 20, left: 20 }}> <IconButton href="https://www.fiverr.com/bermudezw1008" target="_blank" color="primary"> <SiFiverr /> </IconButton> <IconButton href="https://www.linkedin.com/in/william-bermudez-15845021a/" target="_blank" color="primary"> <FaLinkedin /> </IconButton> <IconButton href="https://github.com/Leumas-Tech" target="_blank" color="primary"> <FaGithub /> </IconButton> </div> <div style={{ position: 'absolute', top: 20, right: 20 }}> <Button href={service.link} target="_blank" variant="contained" color="primary" > Learn More </Button> </div> <Typography variant="h2" component="h1" gutterBottom sx={{ fontWeight: 'bold', color: 'black', marginTop: '30px' }}> {service.title} </Typography> <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '20px' }}> <IconButton onClick={() => handleAudioSkip('previous')} color="primary"> <FaBackward /> </IconButton> <IconButton onClick={handleAudioPlayPause} color="primary"> {audioPlaying ? <FaPause /> : <FaPlay />} </IconButton> <IconButton onClick={() => handleAudioSkip('next')} color="primary"> <FaForward /> </IconButton> <Button onClick={toggleStrobeMode} variant="contained" color="secondary" sx={{ ml: 2 }}> {strobeMode ? 'Disable Strobe' : 'Enable Strobe'} </Button> </Box> <Typography variant="h6" component="p" sx={{ color: 'white', marginBottom: '10px' }}> Now Playing: {currentAudio ? currentAudio.title : 'Loading...'} </Typography> <Card sx={{ width: '100%', maxWidth: '800px', boxShadow: 3 }}> <CardContent> <Typography variant="body1" color="text.secondary" gutterBottom> <span dangerouslySetInnerHTML={{ __html: service.htmlContent }} /> </Typography> </CardContent> </Card> <Gallery images={galleryConfig} frequencyData={frequencyData} audioPlaying={audioPlaying} strobeMode={strobeMode} /> </Container> </InfinityBackgroundComponent> ); }; export default ServicePage;