File "media-preview.js"

Full Path: /home/fresvfqn/waterdamagerestorationandrepairsmithtown.com/wp-content/plugins/surerank/src/apps/admin-components/media-preview.js
File size: 3.45 KB
MIME-type: text/x-java
Charset: utf-8

import { Suspense, useEffect, memo } from '@wordpress/element';
import { FilePreview, Skeleton } from '@bsf/force-ui';
import ErrorBoundary from './error-boundary';
import { createResourcePromise } from '@Functions/utils';
import { fetchImageDataByUrl } from '@Functions/api';

// Create a resource cache for fetching image data
const imageCache = new Map();

const fetchImageDataById = ( imageId ) => {
	const image = wp.media.attachment( imageId );
	return image.fetch();
};

// Function to fetch image data with caching
const fetchImageData = ( { imageId = '', imageUrl = '' } ) => {
	// Return from cache if available
	if ( imageCache.has( imageId || imageUrl ) ) {
		return imageCache.get( imageId || imageUrl );
	}

	// Create a new resource if not in cache
	const resource = createResourcePromise(
		new Promise( ( resolve ) => {
			if ( ! imageId && ! imageUrl ) {
				resolve( {} );
				return;
			}

			const processById = ( id ) => {
				if ( ! id ) {
					resolve( {} );
					return;
				}

				const image = fetchImageDataById( id );

				// Handle both promise and non-promise returns
				if ( image && typeof image.then === 'function' ) {
					image
						.then( () => {
							resolve( image );
						} )
						.catch( () => {
							resolve( {} );
						} );
				} else {
					resolve( image );
				}
			};

			// If image url is provided, fetch the image data by url first
			if ( imageUrl ) {
				fetchImageDataByUrl( imageUrl )
					.then( ( images ) => {
						if ( images ) {
							processById( images.id );
						} else {
							resolve( {} );
						}
					} )
					.catch( () => {
						resolve( {} );
					} );
			} else if ( imageId ) {
				// If only ID is provided, fetch directly by ID
				processById( imageId );
			} else {
				resolve( {} );
			}
		} )
	);

	// Store in cache and return
	imageCache.set( imageId || imageUrl, resource );
	return resource;
};

// Loading fallback component
const LoadingFallback = () => <Skeleton className="h-14 w-full"></Skeleton>;

// Main component that reads from the resource
const MediaPreviewContent = ( { imageId, imageUrl, onRemove } ) => {
	// Use the cached resource
	let imageData = fetchImageData( { imageId, imageUrl } ).read() || {};

	if ( 'attributes' in imageData ) {
		imageData = imageData.attributes;
	}

	// Safely extract properties with defaults
	const filename = imageData.filename || '';
	const filesizeHumanReadable = imageData.filesizeInBytes || '';
	const url = imageData.url || '';
	const type = imageData.type || '';

	return (
		<div className="[&>div]:m-0">
			<FilePreview
				file={ {
					name: filename,
					url,
					type,
					size: filesizeHumanReadable,
				} }
				onRemove={ onRemove }
				size="md"
			/>
		</div>
	);
};

// Wrapper component with Suspense
const MediaPreview = ( { imageId, imageUrl, onRemove } ) => {
	useEffect( () => {
		const handleBeforeUnload = () => {
			if ( imageId || imageUrl ) {
				imageCache.delete( imageId || imageUrl );
			}
		};

		window.addEventListener( 'beforeunload', handleBeforeUnload );
		return () => {
			window.removeEventListener( 'beforeunload', handleBeforeUnload );
		};
	}, [ imageId, imageUrl ] );

	// Don't render anything if no imageId is provided
	if ( ! imageId && ! imageUrl ) {
		return null;
	}

	return (
		<ErrorBoundary>
			<Suspense fallback={ <LoadingFallback /> }>
				<MediaPreviewContent
					imageId={ imageId }
					imageUrl={ imageUrl }
					onRemove={ onRemove }
				/>
			</Suspense>
		</ErrorBoundary>
	);
};

export default memo( MediaPreview );