Video Wrapper - Copy this React, Mui Component to your project
Convert code này sang MUi giúp tôi import React, { useEffect, useRef, useState } from "react"; import { useDispatch, useSelector } from "react redux"; import { getMutedSelector } from "../../redux/selectors/selector"; import { VideoType } from "../../types"; import { handleToast } from "../../utils"; import { Swiper, SwiperClass, SwiperSlide } from "swiper/react"; import { Mousewheel } from "swiper"; import { setMuted } from "../../redux/slices/appSlice"; import { turnOff, turnOn } from "../../redux/slices/loadingSlice"; import { videoAPI } from "../../services"; import { Modal } from "antd"; import { useParams } from "react router dom"; import { withErrorBoundary } from "react error boundary"; const WebViewVideo: React.FC = () => { const dispatch = useDispatch(); const { videoKey } = useParams(); const isMuted = useSelector(getMutedSelector); const swiperRef = useRef<SwiperClass | null>(null); const videoRef = useRef<HTMLVideoElement>(null); const [videoList, setVideoList] = useState<VideoType[]>([]); const [videoIndex, setVideoIndex] = useState(0); // Index of video is active const [videoStatus, setVideoStatus] = useState<"loading" | "playing" | "pause">("loading"); const [isOverflowText, setIsOverflowText] = useState(true); const [isShowShareLink, setIsShowShareLink] = useState(false); const [isFirstInteraction, setIsFirstInteraction] = useState(false); // Check first interaction to autoplay video const handleGetVideoList = async () => { try { videoList.length === 0 && dispatch(turnOn()); const resultVideoApi = await videoAPI(videoKey || ""); if (resultVideoApi.data.result) { setVideoList((prev) => [...prev, ...resultVideoApi.data.data]); } else { videoList.length === 0 && handleToast("error", resultVideoApi.data.msg); } } catch (error) { videoList.length === 0 && handleToast("error", "Lỗi hệ thống, vui lòng thử lại!"); } finally { videoList.length === 0 && dispatch(turnOff()); } }; const handleChangeVideoByKeyBoard = (e: KeyboardEvent) => { if (swiperRef.current && e.key === "ArrowUp") { swiperRef.current.slidePrev(); } else if (swiperRef.current && e.key === "ArrowDown") { swiperRef.current.slideNext(); } }; const handleTogglePlayVideo = () => { if (videoRef.current) { if (videoStatus === "playing") { videoRef.current.pause(); } else if (videoStatus === "pause") { videoRef.current.play(); } } }; const handleShare = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { e.stopPropagation(); // Check browser support Web Share API or not if (navigator.share) { try { await navigator.share({ title: videoList[videoIndex]?.Title || "Chia sẻ", text: videoList[videoIndex]?.Description || "Chia sẻ", url: window.location.href, }); } catch (error) {} } else { // Show modal to user copy link navigator?.clipboard ? setIsShowShareLink(true) : handleToast("error", "Trình duyệt không hỗ trợ."); } }; const handleCopyText = () => { navigator.clipboard.writeText(`${window.location.href}`); handleToast("success", "Copy thành công."); }; useEffect(() => { document.body.classList.add("overflow hidden"); // Hidden footer const footerEle = document.querySelector(".footer"); if (footerEle) { footerEle.classList.add("d none"); footerEle.classList.remove("d flex"); } // Add event listener for keyboard document.addEventListener("keydown", handleChangeVideoByKeyBoard); handleGetVideoList(); return () => { document.removeEventListener("keydown", handleChangeVideoByKeyBoard); document.body.classList.remove("overflow hidden"); if (footerEle) { footerEle.classList.remove("d none"); footerEle.classList.add("d flex"); } }; // eslint disable next line react hooks/exhaustive deps }, []); useEffect(() => { setVideoStatus("loading"); setIsOverflowText(true); if (videoRef.current) { videoRef.current.src = videoList[videoIndex]?.Stream || ""; videoRef.current.load(); } }, [videoIndex, videoList, isFirstInteraction]); return ( <div className="webview video"> {!isFirstInteraction ? ( <div className="webview video__thumbnail position relative"> {videoList.length > 0 && <img src={videoList[0].Thumb} className="w 100 h 100" alt="" />} <button className="position absolute h 100 w 100 border 0 bg transparent" onClick={() => setIsFirstInteraction(true)} > <img src="/assets/images/play.png" alt="play toggle" width={50} /> </button> </div> ) : ( <> <video autoPlay playsInline controls={false} loop muted={isMuted} ref={videoRef} onPlay={() => setVideoStatus("playing")} onPause={() => setVideoStatus("pause")} /> <Swiper direction={"vertical"} onSwiper={(swiper) => { swiperRef.current = swiper; }} slidesPerView={1} mousewheel={{ thresholdTime: 300 }} modules={[Mousewheel]} className="mySwiper zIndex 2" onSetTranslate={(swiper, translate) => { videoRef.current?.style.setProperty( "transform", `translate( 50%, ${translate + swiper.height * videoIndex}px)` ); }} onTransitionEnd={() => { videoRef.current?.style.setProperty("transform", "translate( 50%, 0px)"); }} onTouchEnd={() => { videoRef.current?.style.setProperty("transition duration", "300ms"); setTimeout(() => { videoRef.current?.style.setProperty("transition duration", "0ms"); }, 300); }} onSlideChange={(swiper) => { setVideoIndex(swiper.activeIndex); if (swiper.activeIndex === swiper.slides.length 3) { handleGetVideoList(); } }} > {videoList.map((video, index) => ( <SwiperSlide key={index}> {({ isActive }) => ( <div className="webview video__slider"> <img src={video.Thumb} alt="video thumb" className={`w 100 h 100 ${isActive && videoStatus !== "loading" ? "opacity 1" : "opacity 100"}`} /> <div className="webview video__slider__toggle play position absolute top 0 left 0 w 100 h 100 d flex justify content center align items center" onClick={handleTogglePlayVideo} > <img src="/assets/images/play.png" className={videoStatus === "pause" ? "d block" : "d none"} alt="play toggle" width={50} /> {videoStatus === "loading" && <div className="video loading"></div>} </div> <div className="position absolute bottom 0 d flex align items end w 100 pt 35" style={{ backgroundImage: "linear gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5))" }} onClick={handleTogglePlayVideo} > <div className="webview video__slider__description cursor pointer" onClick={(e) => { e.stopPropagation(); setIsOverflowText((prev) => !prev); }} > {isOverflowText ? ( <p className="mb 0 text white text overflow 2"> {video.Title}. {video.Description} </p> ) : ( <div className="text white"> <h5 className="mb 2">{video.Title}</h5> <p className="mb 0">{video.Description}</p> </div> )} </div> <div className="webview video__slider__action list d flex flex column"> <button className="border 0 rounded circle mb 4" onClick={(e) => handleShare(e)}> <img src="/assets/svg/share.svg" alt="share" className="img white" /> </button> <button className={`${isMuted ? "bg white" : ""} border 0 rounded circle`} onClick={(e) => { e.stopPropagation(); dispatch(setMuted(!isMuted)); }} > {isMuted ? ( <img src="/assets/svg/volume muted.svg" alt="volume muted" /> ) : ( <img src="/assets/svg/volume.svg" className="img white" alt="volume" /> )} </button> </div> </div> </div> )} </SwiperSlide> ))} </Swiper> <Modal open={isShowShareLink} onCancel={() => setIsShowShareLink(false)} title={<p className="mb 0 font size h3">Share</p>} footer={null} > <div className="webview video__share link position relative mt 5"> <img src="/assets/svg/link.svg" width={20} alt="link" className="position absolute" /> <input readOnly className="form control form control lg font size h4" type="text" value={window.location.href} /> <button className="position absolute btn btn sm btn primary rounded pill" onClick={handleCopyText}> Copy </button> </div> </Modal> </> )} </div> ); }; export default withErrorBoundary(WebViewVideo, { FallbackComponent: () => { return <div className="text danger">!!! Something went wrong ...</div>; }, });
