Advertisement
2t8gewjihrokhjdoe

PlayerComponent

Feb 15th, 2024 (edited)
256
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. "use client";
  2.  
  3. import usePlayer from "@/hooks/usePlayer";
  4. import { Song } from "@/types";
  5.  
  6. import { useEffect, useRef, useState } from "react";
  7. import toast from "react-hot-toast";
  8. import { BsPauseFill, BsPlayFill } from "react-icons/bs";
  9. import { HiSpeakerWave, HiSpeakerXMark } from "react-icons/hi2";
  10. import { LuRepeat, LuRepeat1, LuShuffle, LuStepBack, LuStepForward } from "react-icons/lu";
  11.  
  12. import useSound from "use-sound";
  13. import FavoriteButton from "./FavoriteButton";
  14. import MediaItem from "./MediaItem";
  15. import Slider from "./Slider";
  16.  
  17. interface PlayerContentProps {
  18.     song: Song;
  19.     songUrl: string;
  20. }
  21.  
  22. const PlayerContent: React.FC<PlayerContentProps> = ({
  23.     song,
  24.     songUrl
  25. }) => {
  26.     const player = usePlayer();
  27.  
  28.     const [volume, setVolume] = useState(1);
  29.     const [isPlaying, setIsPlaying] = useState(false);
  30.     const [isRepeating, setIsRepeating] = useState(false);
  31.     const isRepeatingRef = useRef(isRepeating);
  32.  
  33.     const Icon = isPlaying ? BsPauseFill : BsPlayFill;
  34.     const VolumeIcon = volume === 0 ? HiSpeakerXMark : HiSpeakerWave;
  35.     const RepeatIcon = isRepeating ? LuRepeat1 : LuRepeat;
  36.  
  37.     const onPlayNext = () => {
  38.         if (player.ids.length === 0) { return; }
  39.  
  40.         const currentIndex = player.ids.findIndex((id) => id === player.activeId);
  41.         const nextSong = player.ids[currentIndex + 1];
  42.  
  43.         if (!nextSong) { return player.setId(player.ids[0]); }
  44.  
  45.         player.setId(nextSong);
  46.     }
  47.  
  48.     const onPlayPrevious = () => {
  49.         if (player.ids.length === 0) { return; }
  50.  
  51.         const currentIndex = player.ids.findIndex((id) => id === player.activeId);
  52.         const previousSong = player.ids[currentIndex - 1];
  53.  
  54.         if (!previousSong) { return player.setId(player.ids[player.ids.length - 1]); }
  55.  
  56.         player.setId(previousSong);
  57.     }
  58.  
  59.     const [play, { pause, sound }] = useSound(
  60.         songUrl,
  61.         {
  62.             volume: volume,
  63.             onplay: () => setIsPlaying(true),
  64.             onend: () => {
  65.                 setIsPlaying(false);
  66.                 toast("Song ended");
  67.                 if (isRepeatingRef.current) {
  68.                     toast("Repeating song...");
  69.                     sound?.pause().then(() => {
  70.                         toast("Song paused, now playing...");
  71.                         sound?.play();
  72.                     });
  73.                 } else {
  74.                     onPlayNext();
  75.                 }
  76.             },
  77.             onpause: () => setIsPlaying(false),
  78.             format: ['mp3'],
  79.             loop: isRepeating
  80.         }
  81.     );
  82.  
  83.     const handlePlay = () => {
  84.         !isPlaying ? play() : pause();
  85.     }
  86.  
  87.     const toggleMute = () => {
  88.         setVolume(volume === 0 ? 1 : 0);
  89.     }
  90.  
  91.     const handleShuffling = () => {
  92.         toast.error('Shuffle mode is coming soon...')
  93.     }
  94.  
  95.     useEffect(() => {
  96.         isRepeatingRef.current = isRepeating
  97.     }, [isRepeating])
  98.  
  99.     const handleRepeating = () => {
  100.         setIsRepeating(!isRepeating)
  101.         if (!isRepeating) {
  102.             toast.success('Repeat mode enabled')
  103.         } else {
  104.             toast.success('Repeat mode disabled')
  105.         }
  106.     }
  107.  
  108.     useEffect(() => {
  109.         sound?.play();
  110.  
  111.         return () => { sound?.unload(); }
  112.     }, [sound]);
  113.  
  114.     return (
  115.         <div className="grid grid-cols-2 md:grid-cols-3 h-full">
  116.             <div className="flex w-full justify-start">
  117.                 <div className="flex items-center gap-x-4">
  118.                     <MediaItem data={song} />
  119.                     <FavoriteButton songId={song.id} />
  120.                 </div>
  121.             </div>
  122.  
  123.             <div className="flex md:hidden col-auto w-full justify-end items-center">
  124.                 <div onClick={handlePlay} className="size-10 flex items-center justify-center rounded-full bg-white p-1 cursor-pointer">
  125.                     <Icon size={30} className="text-black" />
  126.                 </div>
  127.             </div>
  128.  
  129.             <div className="hidden h-full md:flex justify-center items-center w-full max-w-[722px] gap-x-6">
  130.                 <LuShuffle onClick={handleShuffling} size={25} className="text-neutral-400 cursor-pointer hover:text-white transition" />
  131.                 <LuStepBack onClick={onPlayPrevious} size={30} className="text-neutral-400 cursor-pointer hover:text-white transition" />
  132.                 <div onClick={handlePlay} className="flex items-center justify-center size-10 rounded-full bg-white p-1 cursor-pointer">
  133.                     <Icon size={30} className="text-black" />
  134.                 </div>
  135.                 <LuStepForward onClick={onPlayNext} size={30} className="text-neutral-400 cursor-pointer hover:text-white transition" />
  136.                 <RepeatIcon onClick={handleRepeating} size={25} className={`cursor-pointer hover:text-white transition ${isRepeating ? 'text-white' : 'text-neutral-400'}`} />
  137.             </div>
  138.  
  139.             <div className="hidden md:flex w-full justify-end pr-2">
  140.                 <div className="flex items-center gap-x-2 w-[120px]">
  141.                     <VolumeIcon onClick={toggleMute} className="cursor-pointer" size={34} />
  142.                     <Slider value={volume} onChange={(value) => setVolume(value)} />
  143.                 </div>
  144.             </div>
  145.         </div>
  146.     );
  147. }
  148.  
  149. export default PlayerContent;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement