huridocs/uwazi

View on GitHub
app/react/V2/Components/UI/MediaPlayer.tsx

Summary

Maintainability
A
0 mins
Test Coverage
F
13%
/* eslint-disable react/no-multi-comp */
import React, { useEffect, useRef, useState } from 'react';
import ReactPlayer, { ReactPlayerProps } from 'react-player';
import { PlayIcon } from '@heroicons/react/20/solid';
import { Translate } from 'app/I18N';

type MediaType = 'embedded' | 'internal' | 'invalid';

interface MediaPlayerProps extends ReactPlayerProps {
  url: string;
  thumbnail?: {
    url?: string;
    fileName?: string;
  };
}

const verifyUrl = (url: string): MediaType => {
  if (!ReactPlayer.canPlay(url)) {
    return 'invalid';
  }

  if (url.startsWith('https') || url.startsWith('http')) {
    return 'embedded';
  }

  return 'internal';
};

const ThumbnailOverlay = ({ thumbnail }: { thumbnail?: MediaPlayerProps['thumbnail'] }) => {
  const overlayBackgroundStyle = thumbnail?.url
    ? {
        backgroundImage: `url("${thumbnail.url}")`,
        backgroundSize: 'cover',
        backgroundPosition: 'center',
      }
    : { background: 'linear-gradient(180deg, rgba(0,0,0,0.4) 6%, rgba(156,163,175,0.6) 50%)' };

  const mediaTitleStyle = thumbnail?.url ? 'text-gray-100' : '';

  return (
    <div className="relative w-full h-full" style={overlayBackgroundStyle}>
      <p
        className={`overflow-hidden p-4 font-normal text-left overflow-ellipsis whitespace-nowrap opacity-1 ${mediaTitleStyle}`}
      >
        {thumbnail?.fileName}
      </p>
    </div>
  );
};

const MediaPlayer = ({ url, width, height, thumbnail }: MediaPlayerProps) => {
  const [playing, setPlaying] = useState(false);
  const [playerHeight, setPlayerHeight] = useState(0);
  const containerRef = useRef<HTMLDivElement>(null);

  const mediaType: MediaType = verifyUrl(url);

  const playIconColor = thumbnail?.url
    ? 'text-gray-100 hover:text-white'
    : 'text-gray-500 hover:text-gray-700';

  const renderThumbnail =
    mediaType === 'internal' ? <ThumbnailOverlay thumbnail={thumbnail} /> : false;

  useEffect(() => {
    if (containerRef.current?.clientHeight) {
      setPlayerHeight(containerRef.current.clientHeight);
    }
  }, []);

  return (
    <div
      style={{ width: width || '100%', height: height || '100%' }}
      className="relative"
      ref={containerRef}
    >
      {mediaType === 'invalid' && (
        <div className="flex absolute top-0 left-0 justify-center items-center p-4 w-full h-full bg-gray-50 rounded border">
          <p className="text-center">
            <Translate>This file type is not supported on media fields</Translate>
          </p>
        </div>
      )}

      {mediaType !== 'invalid' && playerHeight ? (
        <ReactPlayer
          className="absolute top-0 left-0"
          width="100%"
          height="100%"
          controls
          url={url}
          playing={playing}
          light={renderThumbnail}
          config={{
            facebook: {
              attributes: {
                'data-height': playerHeight,
              },
            },
          }}
          playIcon={
            <PlayIcon className={`absolute w-1/5 min-w-[20px] max-w-[120px] ${playIconColor}`} />
          }
          onClickPreview={() => !playing && setPlaying(true)}
        />
      ) : (
        <div />
      )}
    </div>
  );
};

export { MediaPlayer };