Media Viewer in React: Displaying Single and Multiple Images from Firebase Storage

33 Views Asked by At

Problem Description

  • I have a list of media items retrieved from Firebase Storage categorized as usersingleMedia and usermultipleMedia. The media can be a single image, a single video, or a folder containing multiple images.
  • When the user clicks on a media item in my custom media viewer, I use selectedMediaId to identify the selected media. If it's a single image or video (usersingleMedia), everything works as expected.
  • However, when the selected media is part of a folder (usermultipleMedia), I want to display all the images from that folder, but the current implementation is not achieving the desired result.
  • It is giving me alt, which is selectedMediaId.

Code samples

yourvideo's page

import React, { useState, useRef, useEffect } from 'react';
import "../styles/yourvideos.css";
import { ref, getDownloadURL, listAll } from 'firebase/storage';
import { useUserContext } from './Usercontext';
import { storage } from './firebaseconfig';

// Splitting the ID into name, v4Id, and userId
const splitPipeSeparatedId = (id) => {
  const [name, v4Id, userId] = id.split('|');
  return { name, v4Id, userId };
};

const Yourvideos = () => {
  const [selectedMediaId, setSelectedMediaId] = useState(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [isPauseIconVisible, setPauseIconVisible] = useState(true);
  const mediaRef = useRef(null);
  const pauseIconTimer = useRef(null);
  const { user } = useUserContext();
  const [usersingleMedia, setUsersingleMedia] = useState([]);
  const [usermultipleMedia, setUserMultipleMedia] = useState([]);
  const [usermultiplebackerMedia, setUserMultiplebackerMedia] = useState([]);

  // Fetching individual images
  const fetchIndividualImages = async () => {
    if (user && user[5]) {
      try {
        const userMediaFolder = ref(storage, `images`);
        const mediaList = await listAll(userMediaFolder);

        const media = await Promise.all(
          mediaList.items.map(async (mediaRef) => {
            const downloadUrl = await getDownloadURL(mediaRef);
            const { userId } = splitPipeSeparatedId(mediaRef.name);

            if (userId === user[5]) {
              return {
                name: mediaRef.name,
                downloadUrl,
              };
            }

            return null;
          })
        );

        const filteredMedia = media.filter((item) => item !== null);

        setUsersingleMedia(filteredMedia);
      } catch (error) {
        console.error('Error fetching user media: ', error);
      }
    }
  };

  // Fetching images in subfolders
  const fetchImagesInSubfolders = async () => {
    if (user && user[5]) {
      try {
        const userMediaFolder = ref(storage, `images`);
        const mediaList = await listAll(userMediaFolder);

        const nestedMedia = await Promise.all(
          mediaList.prefixes.map(async (folderRef) => {
            const folderMediaList = await listAll(folderRef);
            return Promise.all(
              folderMediaList.items.map(async (mediaRef) => {
                const downloadUrl = await getDownloadURL(mediaRef);
                const { userId } = splitPipeSeparatedId(mediaRef.name);

                if (userId === user[5]) {
                  return {
                    name: mediaRef.name,
                    downloadUrl,
                  };
                }
                return null;
              })
            );
          })
        );
        const flattenedMedia = nestedMedia.flat();
        const filteredMedia = flattenedMedia.filter((item) => item !== null);

        setUserMultipleMedia(filteredMedia);
        setUserMultiplebackerMedia(filteredMedia);
      } catch (error) {
        console.error('Error fetching images within subfolders: ', error);
      }
    }
  };

  // Other hooks and functions
  useEffect(() => {
    if (isPlaying) {
      pauseIconTimer.current = setTimeout(() => {
        setPauseIconVisible(false);
      }, 1500);
    } else {
      clearTimeout(pauseIconTimer.current);
      setPauseIconVisible(true);
    }

    return () => {
      clearTimeout(pauseIconTimer.current);
    };
  }, [isPlaying]);

  const handleTogglePlayPause = () => {
    if (isPlaying) {
      setIsPlaying(false);
      mediaRef.current.pause();
    } else {
      setIsPlaying(true);
      mediaRef.current.play();
    }
  };

  const handleStopMedia = () => {
    if (selectedMediaId.endsWith('.mp4')) {
      setSelectedMediaId(null);
      setIsPlaying(false);
      mediaRef.current.pause();
    } else {
      setSelectedMediaId(null);
    }
  };

  useEffect(() => {
    fetchIndividualImages();
    fetchImagesInSubfolders();
  }, [user]);

  return (
    <div className='yourvideos_main_wrapper_ksdab'>
      <div className="yourvideos_main_container_ksdab">
        {/* Rendering single images */}
        {usersingleMedia && usersingleMedia.map((media) => (
          <div key={media.name} className="ksdab-media-container">
            {media.name.endsWith('.mp4') ? (
              <video
                id={`media-${media.name}`}
                className="ksdab-media"
                controls={false}
                onClick={() => {
                  setSelectedMediaId(media.name);
                }}
              >
                <source src={media.downloadUrl} type="video/mp4" />
              </video>
            ) : (
              <img
                id={`media-${media.name}`}
                className="ksdab-media"
                src={media.downloadUrl}
                alt="Error Displaying image"
                onClick={() => {
                  setSelectedMediaId(media.name);
                }}
              />
            )}

            {media.name.endsWith('.mp4') && (
              <div className="custom-controls">
                <i
                  className="fa-solid fa-play"
                  style={{ color: '#ffffff' }}
                  onClick={() => {
                    setSelectedMediaId(media.name);
                  }}
                ></i>
              </div>
            )}
          </div>
        ))}

        {/* Rendering first image from each folder */}
        {usermultipleMedia && usermultipleMedia.map((media, index) => (
          <div key={media.name} className="ksdab-media-container">
            {index === 0 && (
              <div>
                {media.name.endsWith('.mp4') ? (
                  <video
                    id={`media-${media.name}`}
                    className="ksdab-media"
                    controls={false}
                    onClick={() => {
                      setSelectedMediaId(media.name);
                    }}
                  >
                    <source src={media.downloadUrl} type="video/mp4" />
                  </video>
                ) : (
                  <img
                    id={`media-${media.name}`}
                    className="ksdab-media"
                    src={media.downloadUrl}
                    alt="Error Displaying image"
                    onClick={() => {
                      setSelectedMediaId(media.name);
                    }}
                  />
                )}

                {media.name.endsWith('.mp4') && (
                  <div className="custom-controls">
                    <i
                      className="fa-solid fa-play"
                      style={{ color: '#ffffff' }}
                      onClick={() => {
                        setSelectedMediaId(media.name);
                      }}
                    ></i>
                  </div>
                )}
              </div>
            )}
          </div>
        ))}
      </div>

      {/* Rendering selected media in the medialinker */}
      {selectedMediaId && (
        <div className="medialinker-container scrollable">
          <div className="custom-media-container">
            <div className="media-content scrollable">
              {selectedMediaId.endsWith('.mp4') ? (
                <video
                  id={`media-${selectedMediaId}`} 
                  className="custom-media"
                  controls={false}
                  ref={mediaRef}
                >
                  <source src={
                    usersingleMedia.find((media) => media.name === selectedMediaId)?.downloadUrl ||
                    (selectedMediaId in usermultipleMedia
                      ? usermultipleMedia
                        .filter((media) => media.name === selectedMediaId)
                        .map((media) => media.downloadUrl)
                        .join(' || ')
                      : '')
                  } type="video/mp4" />
                </video>
              ) : (
                <img
                  id={`media-${selectedMediaId}`}
                  className="custom-media"
                  src={
                    usersingleMedia.find((media) => media.name === selectedMediaId)?.downloadUrl ||
                    (selectedMediaId in usermultipleMedia
                      ? usermultipleMedia
                        .filter((media) => media.name === selectedMediaId)
                        .map((media) => {
                          return media.downloadUrl;
                        })
                      : '')
                  }
                  alt={selectedMediaId}
                />
              )}
              <div
                id={`controls-${selectedMediaId}`}
                className="medialinker-controls"
                onClick={handleTogglePlayPause}
              >
                {selectedMediaId.endsWith('.mp4') && (
                  <i className={`fa-solid ${isPlaying ? 'fa-pause' : 'fa-play'}`} style={{ color: '#ffffff', visibility: isPauseIconVisible ? 'visible' : 'hidden' }}></i>
                )}
              </div>
            </div>

            <div className="vertical-line"></div>

            <div className="blank_area_div">
              <i className="fa-solid fa-times" style={{ color: 'black', fontSize: '24px', cursor: 'pointer' }} onClick={handleStopMedia}></i>
              hi
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

export default Yourvideos;


## What I've Tried
I attempted to modify the source logic in my media viewer component, considering the different scenarios of single and multiple media.
I explored using conditional rendering and mapping through the usermultipleMedia array to display multiple images when selectedMediaId is part of a folder.
0

There are 0 best solutions below