You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ImagePicker.js 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import React, { useCallback, useEffect, useRef, useState } from "react";
  2. import PropTypes from "prop-types";
  3. import {
  4. AddFile,
  5. AddIcon,
  6. ImageOverlay,
  7. ImagePickerContainer,
  8. ImageUploaded,
  9. Tools,
  10. } from "./ImagePicker.styled";
  11. import { IconButton } from "../Buttons/IconButton/IconButton";
  12. import { ReactComponent as EditIcon } from "../../assets/images/svg/edit.svg";
  13. import { ReactComponent as TrashIcon } from "../../assets/images/svg/trash.svg";
  14. import { getImageUrl, variants } from "../../util/helpers/imageUrlGetter";
  15. const ImagePicker = (props) => {
  16. const fileInputRef = useRef(null);
  17. const imageRef = useRef(null);
  18. const [image, setImage] = useState("");
  19. const [isEditing, setIsEditing] = useState(false);
  20. // Check if file is type of string or File
  21. useEffect(() => {
  22. if (props.image) {
  23. if (typeof props.image === "string") {
  24. setImage(getImageUrl(props.image, variants.offerCard));
  25. } else {
  26. handleImage(props.image);
  27. }
  28. }
  29. }, [props.image]);
  30. const listener = useCallback(
  31. (event) => {
  32. if (imageRef.current) {
  33. if (imageRef.current.contains(event.target)) {
  34. setIsEditing(true);
  35. } else {
  36. setIsEditing(false);
  37. }
  38. }
  39. },
  40. [imageRef.current]
  41. );
  42. useEffect(() => {
  43. window.addEventListener("click", listener);
  44. return () => window.removeEventListener("click", listener);
  45. }, []);
  46. // Simulate click on file input
  47. const handleChange = () => {
  48. fileInputRef.current.value = "";
  49. fileInputRef.current.click();
  50. };
  51. // Reads image as both base64 and multipart type
  52. const handleImage = (file) => {
  53. if (
  54. file.type !== "image/jpeg" &&
  55. file.type !== "image/jpg" &&
  56. file.type !== "image/png"
  57. )
  58. return;
  59. let reader = new FileReader();
  60. reader.readAsDataURL(file);
  61. reader.onload = () => {
  62. if (props.setImage) props.setImage(file);
  63. setImage(reader.result);
  64. };
  65. reader.onerror = (error) => {
  66. console.dir(error);
  67. };
  68. };
  69. const handleDelete = () => {
  70. if (props.deleteImage) props.deleteImage();
  71. setImage("");
  72. setIsEditing(false);
  73. };
  74. return (
  75. <ImagePickerContainer
  76. className={props.className}
  77. onClick={!image ? handleChange : () => {}}
  78. hasImage={props.image}
  79. component="form"
  80. singleImage={props.singleImage}
  81. >
  82. <AddFile
  83. type="file"
  84. ref={fileInputRef}
  85. onInput={(event) => handleImage(event.target.files[0])}
  86. accept=".jpg, .jpeg, .png"
  87. formEncType="multipart/form-data"
  88. />
  89. {image ? (
  90. <React.Fragment>
  91. <ImageUploaded src={image} draggable={false} ref={imageRef} />
  92. {isEditing && (
  93. <React.Fragment>
  94. <ImageOverlay />
  95. <Tools showDeleteIcon={props.showDeleteIcon}>
  96. <IconButton onClick={handleChange}>
  97. <EditIcon />
  98. </IconButton>
  99. {props.showDeleteIcon && (
  100. <IconButton onClick={handleDelete}>
  101. <TrashIcon />
  102. </IconButton>
  103. )}
  104. </Tools>
  105. </React.Fragment>
  106. )}
  107. </React.Fragment>
  108. ) : (
  109. <AddIcon />
  110. )}
  111. {props.children}
  112. </ImagePickerContainer>
  113. );
  114. };
  115. ImagePicker.propTypes = {
  116. children: PropTypes.node,
  117. className: PropTypes.string,
  118. setImage: PropTypes.func,
  119. image: PropTypes.func,
  120. deleteImage: PropTypes.func,
  121. showDeleteIcon: PropTypes.bool,
  122. singleImage: PropTypes.bool,
  123. };
  124. export default ImagePicker;