Problem Description
- I have a list of media items retrieved from Firebase Storage categorized as
usersingleMediaandusermultipleMedia. 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
selectedMediaIdto 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.