Media Player with React - javascript

IM trying to create an audio player, with a master play and pause button, each song has its play and pause button but that can be override by the master play and pause.
const playing = () => {
if(isPlaying){
setIsPlaying(false)
masterPlay()
}else{
setIsPlaying(true)
handlePlay()
}
};
const handlePlay = (song) =\> {
setCurrentTrack(song);
setIsPlaying(true);
};
const masterPlay = () => {
handlePlay()
setIsPlaying(true);
console.log(isPlaying)
}
{!isPlaying ? (
//if playing is false, play the audio
<PlayArrowIcon onClick = {masterPlay} /\>
) : (
//else pause the audio
<PauseIcon onClick = {handlePause} /\>
)}
<button className="next_button" onClick={() => handlePrevious}>
<SkipPreviousIcon />
</button>
<ul>
{songs.map((song) => {
return (
<li key={song.id}>
{song.track_name}
<PlayArrowIcon onClick={() => handlePlay(song)} />
<button onClick={() => handlePlaylist(song)}>
create playlist
</button>
</li>
);
})}
</ul>
{currentTrack && (
<audio
ref={audioRef}
src={currentTrack.track_url}
onPlay={playing}
onPause={()=>handlePause}
onEnded={handleEnded}
onTimeUpdate={handleTimeUpdate}
autoPlay={isPlaying}
/>
)}
</div>
`
I'm having difficulty passing the current track into the master play, without ,mapping the songs array how can I make the master play control the music

Related

How to make Mantine burger close after link is selected?

I want to make the Mantine burger auto close after a nav choice is selected in the modal. It seems as if it is not possible for the Mantine burger to automatically close (because the x icon stays). I am using NextJS with Mantine & react-icons.
export default function HeaderMiddle({ links }: HeaderMiddleProps) {
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
const dark = colorScheme === 'dark';
const [opened, { toggle, open, close }] = useDisclosure(false, {
onOpen: () => burgerClick(),
onClose: () => closeAllModals(),
});
const [active, setActive] = useState(links[0].link);
const { classes, cx } = useStyles();
const items = links.map((link) => (
<a
key={link.label}
href={link.link}
className={cx(classes.link, {
[classes.linkActive]: active === link.link,
})}
onClick={(event) => {
event.preventDefault();
setActive(link.link);
}}
>
{link.label}
</a>
));
const burgerItems = links.map((link) => (
<a
key={link.label}
href={link.link}
className={cx(classes.link, {
[classes.linkActive]: active === link.link,
})}
onClick={(event) => {
event.preventDefault();
setActive(link.link);
closeAllModals();
}}
>
{link.label}
</a>
));
const burgerClick = () => {
openModal({
title: 'Subscribe to newsletter',
children: <>{burgerItems}</>,
});
};
return (
<Header height={56} mb={120}>
<Container className={classes.inner}>
<Burger
opened={opened}
onClick={toggle}
size="sm"
className={classes.burger}
/>
<Group className={classes.links} spacing={5}>
{items}
</Group>
{/* <MantineLogo size={28} /> */}
<Group spacing={0} className={classes.social} position="right" noWrap>
...
</Group>
</Container>
</Header>
);
}
Any help with this would be appreciated.
next: 12.1.5
#mantine/core: 4.2.12
After clicking the link call close method of useDisclosure, it will make opened to false. Burger state is depend on opened so, it wil close the burger on false.
const burgerItems = links.map((link) => (
<a
key={link.label}
href={link.link}
className={cx(classes.link, {
[classes.linkActive]: active === link.link,
})}
onClick={(event) => {
event.preventDefault();
setActive(link.link);
closeAllModals();
// It will set opened to false (so it will close Burger)
close()
}}
>
{link.label}
</a>
));
I found something that might help you
On the Mantine Doc, one header called 'Responsive header' is working fine after you clicked on any of the burger items.
Simply follow the codes and should be fine!

React Lifecycle Video

I was creating this React component and I was astonished by the fact that when I clicked on the video I got false on console immediatelly after the video started. I was expecting that it would print true when the video started, and false when it finished. I think I'm confusing the lifecycle of this particular component, and I would be really grateful if someone could clarify this to me.
const Video = ({src, type, index, isAutoPlay}) => {
const [play, setPlay] = useState(isAutoPlay)
const playRef = useRef();
useEffect(() => {
if (play && playRef.current) {
playRef.current.play();
}
return () => setPlay(false)
}, [play]);
return (
<>
<video
className="slide"
ref={playRef}
onClick={() => {
setPlay(true);
console.log(play);}}>
<source src={src} type={type} key={index}/>
Your browser does not support the video tag.
</video>
</>
)
}

Pause other video if selected video is playing in react

I'm using react-player https://github.com/cookpete/react-player to play my videos. My problem is, how can I pause other videos while selected video is playing?
const videoRef = useRef();
const updateVideoHandler = async (videoId, videoTitle) => {
setSelectedVideoId(videoId);
if (!selectedVideoId) {
videoRef?.current?.player?.player?.onPause();
}
};
<ReactPlayer
ref={videoRef}
onPlay={() => updateVideoHandler(video.id, video.title)}
playsinline={true}
playing={true}
controls={true}
url={video?.url}
width="100%"
height="100%"
playIcon={
<div
className="play-icon"
role="button"
tabIndex={0}
style={{ outline: "none" }}
>
{" "}
<img src="/images/play.png" alt="" />
</div>
}
light={video?.pic}
/>;
You could store all player instances in a Context and use a Provider and Consumer to pause all players if one starts playing.
Since you pass a playing boolean to ReactPlayer, you can easily store a id or reference of the current playing player.
For example:
PlayerProvider.jsx
export const PlayerContext = React.createContext({
play: (playerId) => true,
pause: (playerId) => true,
isPlaying: (playerId) => false,
});
function PlayerProvider({ children }) {
// store the id of the current playing player
const [playing, setPlaying] = useState('');
// set playing to the given id
const play = playerId => setPlaying(playerId);
// unset the playing player
const pause = () => setPlaying(false);
// returns true if the given playerId is playing
const isPlaying = playerId => playerId === playing;
return (
<PlayerContext.Provider value={{ play, pause, isPlaying }}>
{children}
</PlayerContext.Provider>
)
}
export default PlayerProvider;
Player.jsx
import { PlayerContext } from './PlayerProvider';
function Player({ video, id }) {
const { isPlaying, play, pause } = useContext(PlayerContext);
<ReactPlayer
ref={videoRef}
playsinline={true}
playing={isPlaying(id)}
controls={true}
url={video?.url}
width="100%"
height="100%"
onPause={() => pause(id)}
onEnded={() => pause(id)}
onClickPreview={() => play(id)}
playIcon={
<div
className="play-icon"
role="button"
tabIndex={0}
style={{ outline: "none" }}
>
{" "}
<img src="/images/play.png" alt="" />
</div>
}
light={video?.pic}
/>;
}
export default Player;
Page.jsx
import PlayerProvider from './PlayerProvider';
import Player from './Player';
function Page() {
return (
<PlayerProvider>
<Player video="/path/to/video1.mp4" id="player1" />
<Player video="/path/to/video2.mp4" id="player2" />
<Player video="/path/to/video3.mp4" id="player3" />
</PlayerProvider>
)
}
Actially this is very easy process to get
try it out
export const VideoPlayer = () =>{
const videoooo = useRef();
const pauseVideo = () => {
//at the place of pauseVideo you can use "stopVideo", "playVideo"
videoooo.current.contentWindow.postMessage(
'{"event":"command","func":"pauseVideo","args":""}',
"*"
);
};
return(<> <iframe
ref={videoooo}
id="myVideoId"
src="https://www.youtube.com/embed/Q63qjIXMqwU?enablejsapi=1"
></iframe>
<button
onClick={() => {
pauseVideo();
}}
>
Pause
</button></>)
}
it is very easy and useful syntax from js
// unset the playing player
const pause = () => setPlaying(false);
if you remove this line from the code it is working perfectly, when one video is already playing and you click on the second video, onPause is invoked and it is calling the pause function due to that setPlaying updating the playing value due to that page rerendering and in that time playing value is false and it does not match with any video id and that's why every video is stopped playing.
I implemented it using video-react here :
react-video-js
You need to use
controls,
preload='auto',
autoplay
Or
You can also pop-up a modal and show videos and use this
<div>
<button onClick={this.playVideo}>
Play!
</button>
<button onClick={this.pauseVideo}>
Pause!
</button>
</div>
where you need to store the states inside these onClick for play and pause depending upon the useref of a particular video else if you use a Modal then destroy it after close so that video doesn't play once you close.

How to play one song from array at a time react js

I am building a simple music player but where I fail is at trying to execute one item from the array at a time. I am using React H5 Audio Player package to play the music. I am currently mapping through all the songs but I don't know how to properly play one at a time. I appreciate any help. I've been stuck on this for a few days.
import { SongContext } from '../../SongContext';
import AudioPlayer from 'react-h5-audio-player';
import 'react-h5-audio-player/lib/styles.css';
import './Player.css';
const Player = () => {
const { songs } = useContext(SongContext);
return (
<>
{songs.length > 0 &&
songs.map((song) => (
<div className="player" key={song.id}>
<AudioPlayer
// autoPlay
// src={song.preview}
showJumpControls={false}
customVolumeControls={[]}
customAdditionalControls={[]}
onPlay={() => console.log('playing')}
/>
</div>
))}
</>
);
};
export default Player;
Don't map all the songs at once, take a song by index (currentSong), and when it's done, use the onEnded event to increment the index, so the next one would play.
Example (codepen):
const Player = () => {
const { songs } = useContext(SongContext);
const [currentSong, setCurrentSong] = useState(0);
const song = songs[currentSong];
if(!song) return null; // don't render the player when no song is available
return (
<div className="player">
<AudioPlayer
autoPlay
src={song.preview}
showJumpControls={false}
customVolumeControls={[]}
customAdditionalControls={[]}
onPlay={() => console.log('playing')}
onEnded={() => setCurrentSong(i => i + 1)}
/>
</div>
);
};

implementing local storage in react application

I am creating a challenge tracking app in React. I would like to, after clicking on the challenge button and approving it, be able to add it and save it to the local storage (as a value to save the name of the chosen challenge) and later to print it in the dashboard.
Could anyone please help me with that.
I have 3 classes I am working now and will paste them below.
ChooseChallenge.js
function Challange() {
const [isPopped, setPop] = useState(false);
const pop = () => {
setPop(!isPopped);
};
return (
//Fragments
<>
{isPopped && <Dialog />}
<div className="chooseChallenge">
{/* <Leaf/> */}
<h1 className="newchallenge">New Challange</h1>
<hr />
<div className="challanges">
<button className="challangeBtn" onClick={pop}>
Eat Vegetarian (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Take the bike to work (14days)
</button>
<button className="challangeBtn" onClick={pop}>
Recycle your plastic bottles (31days)
</button>
<button className="challangeBtn" onClick={pop} >
Use public transport to commute (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Don't fly an airplane (365days)
</button>
</div>
<br />
</div>
</>
);
}
export default Challange;
Dialog.js
function Dialog (){
const [isOpen, setOpennes] = useState(true);
const Close = () => {
setOpennes(false);
}
const [value, setValue] = React.useState(
localStorage.getItem('challengeName') || ''
);
React.useEffect(() => {
localStorage.setItem('challengeName', value);
}, [value]);
const onChange = event => setValue(event.target.value);
return(
<div className={isOpen ? 'dialogBox' : 'dialogHide'}>
<h3 id="header">Do you accept the challange?</h3>
<div className="approvalButtons">
<button className= "approvalButton" onClick = {Close} value={value} onChange={onChange}> Approve </button>
<button className= "approvalButton" onClick = {Close}> Decline </button>
</div>
</div>
)
}
export default Dialog;
Dashboard.js
export default function Dashboard() {
// const challengelist = document.querySelector('#challange-list')
const [challs, setChalls] = useState([]);
useEffect(() => {
const fetchData = async () => {
var challs = [];
await database
.collection("Challenges")
.get()
.then((snapshot) => {
snapshot.docs.forEach((doc) => {
challs.push(doc.data().ChallengeName);
});
});
setChalls(challs);
};
fetchData();
}, []);
return (
<div className="Dashboard">
<Header />
<div className="circle">
<img id="leafpicture" src={leafpic} alt="eco-picture" />
<div className="textIn">
<h1> You saved </h1>
<h5>0.00 CO2</h5>
</div>
</div>
<div>
<ul id="challange-list">
{challs.map((ch) => (
<li key={ch}>{ch}</li>
))}
</ul>
</div>
<div className="progressbar">
<h3>Track your challenges!</h3>
{testData.map((item, idx) => (
<ProgressBar
key={idx}
bgcolor={item.bgcolor}
completed={item.completed}
/>
))}
</div>
<br />
</div>
);
}
on dialog.js the value of the button starts with an empty string and this value never changes, so you are always storing and empty string.

Categories