react-icons/md#MdAddAPhoto TypeScript Examples

The following examples show how to use react-icons/md#MdAddAPhoto. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: InputFileField.tsx    From hub with Apache License 2.0 4 votes vote down vote up
InputFileField = (props: Props) => {
  const imgRef = useRef(null);
  const previewCanvasRef = useRef(null);
  const [upImg, setUpImg] = useState<ArrayBuffer | string | null>(null);
  const [crop, setCrop] = useState<Crop | undefined>();
  const [completedCrop, setCompletedCrop] = useState<PixelCrop | null>(null);
  const fileInput = useRef<HTMLInputElement | null>(null);
  const [isSending, setIsSending] = useState<boolean>(false);
  const [openStatus, setOpenStatus] = useState<boolean>(false);
  const [image, setImage] = useState<any>(null);

  async function saveImage(data: string | ArrayBuffer) {
    try {
      const logo: LogoImage = await API.saveImage(data);
      setIsSending(false);
      if (!isUndefined(props.onImageChange)) {
        props.onImageChange(logo.imageId);
      }
    } catch (err: any) {
      setIsSending(false);
      if (err.kind !== ErrorKind.Unauthorized) {
        alertDispatcher.postAlert({
          type: 'danger',
          message: 'An error occurred saving the image, please try again later.',
        });
      } else {
        props.onAuthError();
      }
    }
  }

  const onClose = () => {
    setOpenStatus(false);
    if (!isNull(fileInput) && !isNull(fileInput.current)) {
      fileInput.current!.value = '';
    }
    setCrop(undefined);
    setUpImg(null);
    setCompletedCrop(null);
    setImage(null);
  };

  const saveOriginal = (file: any) => {
    setIsSending(true);
    const reader = new FileReader();
    reader.onloadend = (r: ProgressEvent<FileReader>) => {
      if (!isNull(r.target) && !isNull(r.target.result)) {
        saveImage(r.target.result);
      }
    };
    reader.readAsArrayBuffer(file);
  };

  const saveCroppedImage = (canvas: any, crop: any) => {
    if (!crop || !canvas) {
      alertDispatcher.postAlert({
        type: 'danger',
        message: 'An error occurred saving the image, please try again later.',
      });
      return;
    }

    setIsSending(true);
    canvas.toBlob(
      (blob: any) => {
        saveImage(blob);
        onClose();
      },
      'image/png',
      1
    );
  };

  const onSelectFile = () => {
    if (
      !isNull(fileInput) &&
      !isNull(fileInput.current) &&
      !isNull(fileInput.current.files) &&
      fileInput.current.files.length > 0
    ) {
      setIsSending(false);
      setImage(fileInput.current.files[0]);
      const file = fileInput.current.files[0];
      if (!file.type.startsWith('image/')) {
        alertDispatcher.postAlert({
          type: 'danger',
          message: 'Sorry, only images are accepted',
        });
      } else {
        const type = file.type;
        if (type === 'image/svg+xml') {
          saveOriginal(file);
        } else {
          setOpenStatus(true);
          const reader = new FileReader();
          reader.addEventListener('load', () => {
            setUpImg(reader.result);
          });
          reader.readAsDataURL(file);
        }
      }
      setIsSending(false);
    }
  };

  const onImageLoad = useCallback((e: any) => {
    const { width, height } = e.currentTarget;

    const cropped = centerCrop(
      makeAspectCrop(
        {
          // You don't need to pass a complete crop into
          // makeAspectCrop or centerCrop.
          unit: '%',
          width: 90,
        },
        1,
        width,
        height
      ),
      width,
      height
    );

    imgRef.current = e.currentTarget;
    setCrop(cropped);
  }, []);

  useEffect(() => {
    if (!isNull(completedCrop) && openStatus) {
      const img: any = imgRef.current;
      const canvas: any = previewCanvasRef.current;

      if (!isNull(canvas) && !isNull(img)) {
        const tmpCrop: any = completedCrop;

        const scaleX = img.naturalWidth / img.width;
        const scaleY = img.naturalHeight / img.height;
        const ctx = canvas.getContext('2d');
        const pixelRatio = window.devicePixelRatio;

        canvas.width = tmpCrop.width * pixelRatio;
        canvas.height = tmpCrop.height * pixelRatio;

        ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
        ctx.imageSmoothingQuality = 'high';

        ctx.drawImage(
          img,
          tmpCrop.x * scaleX,
          tmpCrop.y * scaleY,
          tmpCrop.width * scaleX,
          tmpCrop.height * scaleY,
          0,
          0,
          tmpCrop.width,
          tmpCrop.height
        );
      }
    }
  }, [completedCrop]); /* eslint-disable-line react-hooks/exhaustive-deps */

  const onClick = () => {
    if (!isNull(fileInput) && !isNull(fileInput.current)) {
      fileInput.current.click();
    }
  };

  return (
    <>
      <div className={` mb-4 ${props.className}`}>
        <div className="d-flex flex-column">
          <label className={`form-label ${styles.label}`} htmlFor={props.name}>
            <span className="fw-bold">{props.label}</span>
            {props.labelLegend && <>{props.labelLegend}</>}
          </label>

          <div className="position-relative">
            <button
              className={classnames(
                'btn p-0 overflow-hidden position-relative border border-3 lh-1 rounded-circle fs-2 bg-white',
                styles.btn,
                { 'opacity-50': isSending }
              )}
              type="button"
              onClick={onClick}
              aria-label="Add image"
              disabled={isSending}
            >
              {props.value ? (
                <Image
                  imageId={props.value}
                  className="mh-100 mw-100"
                  classNameForSquare={`position-absolute w-100 h-100 top-0 start-0 ${styles.imageAsBg}`}
                  alt="Logo"
                />
              ) : (
                <>{props.placeholderIcon ? <>{props.placeholderIcon}</> : <MdAddAPhoto data-testid="defaultIcon" />}</>
              )}
            </button>
            {isSending && (
              <span className={`position-absolute spinner-border spinner-border-lg text-primary ${styles.spinner}`} />
            )}
          </div>
        </div>

        <input
          type="file"
          id={props.name}
          name={props.name}
          ref={fileInput}
          className="d-none"
          onChange={onSelectFile}
        />
      </div>

      {openStatus && (
        <Modal
          header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Crop image</div>}
          open={openStatus}
          modalClassName={styles.modal}
          onClose={onClose}
          closeButton={
            <>
              <button
                className="btn btn-sm btn-outline-secondary"
                onClick={() => {
                  if (!isNull(image)) {
                    saveImage(image);
                    onClose();
                  }
                }}
                disabled={isNull(image)}
                aria-label="Save original"
              >
                <div className="d-flex flex-row align-items-center">
                  <BiImageAlt className="me-2" />
                  <span>Save original</span>
                </div>
              </button>

              <button
                type="button"
                className="btn btn-sm btn-secondary ms-3"
                disabled={!completedCrop?.width || !completedCrop?.height}
                onClick={() => saveCroppedImage(previewCanvasRef.current, completedCrop)}
              >
                <div className="d-flex flex-row align-items-center">
                  <BiCrop className="me-2" />
                  <span>Save cropped image</span>
                </div>
              </button>
            </>
          }
        >
          <div className="w-100 h-100 d-flex flex-column">
            <div className={`flex-grow-1 d-flex align-items-center justify-content-center pt-1 ${styles.cropWrapper}`}>
              <div className="overflow-auto mx-auto mw-100 mh-100">
                {upImg && (
                  <ReactCrop
                    crop={crop}
                    aspect={1}
                    circularCrop
                    onChange={(c, percentCrop) => setCrop(c)}
                    onComplete={(c: PixelCrop, percentCrop: PercentCrop) => setCompletedCrop(c)}
                  >
                    <img alt={props.label} src={upImg as string} onLoad={onImageLoad} />
                  </ReactCrop>
                )}
              </div>
            </div>
            <div className="d-flex flex-row align-items-center mt-3">
              <div className="fw-bold me-3 text-uppercase">Preview</div>
              <div
                className={`overflow-hidden position-relative border border-3 rounded-circle bg-white ${styles.imageWrapper}`}
              >
                {completedCrop && (
                  <canvas className={`rounded-circle mw-100 mh-100 ${styles.imageAsBg}`} ref={previewCanvasRef} />
                )}
              </div>
            </div>
          </div>
        </Modal>
      )}
    </>
  );
}