Image Upload With Dropdown

NPM Dependencies

npm i react-dropzone

npm i react-avatar-editor

Import Dependencies

import React, { useEffect, useState } from 'react';
import AvatarEditor from 'react-avatar-editor';
import Dropzone from 'react-dropzone';
import { FiUploadCloud } from 'react-icons/fi';

Components

function UploadComponent() {
    const [picture, setPicture] = useState({
        cropperOpen: false,
        img: "https://via.placeholder.com/200",
        zoom: 1,
        croppedImg:
            "https://via.placeholder.com/100"
    });
    const [imgArray, setImgArray] = useState([]);
    const [isUploadImg, setIsUploadImg] = useState(false);

    const handleAddImg = (img) => {
        console.log(img);
        setFormData({
            ...formData,
            image: img.img,
        });
    };
    
    const handleRemoveImg = (index) => {
        let newArr = [...imgArray];
        newArr.splice(index, 1);
        setImgArray(newArr);
    };
    
    const Dropzones = (props) => {
        var editor = "";

        const handleSlider = (value) => {
            setPicture({
                ...picture,
                zoom: value
            });
        };

        const handleCancel = () => {
            setPicture({
                ...picture,
                img: null,
                cropperOpen: false,
            });
        };

        const setEditorRef = (ed) => {
            editor = ed;
        };

        const handleSave = (e) => {
            if (setEditorRef) {
                const canvasScaled = editor.getImageScaledToCanvas();
                const croppedImg = canvasScaled.toDataURL();
                handleAddImg({ img: croppedImg });
                setPicture({
                    ...picture,
                    img: null,
                    cropperOpen: false,
                });
                setIsUploadImg(false);
                console.log(croppedImg, "croppedImg");
            }
        };

        return (
            <HStack spacing={4} w={"full"} justifyContent={"space-between"} borderRadius={"lg"}>
                {picture.cropperOpen ? (
                    <Box w={"xs"}>
                        <Center>
                            <AvatarEditor
                                ref={setEditorRef}
                                image={picture.img}
                                width={150}
                                height={150}
                                scale={picture.zoom}
                                color={[100, 84, 0, 0.4]}
                                rotate={0}
                            />
                        </Center>

                        <Center>
                            <Slider
                                min={1}
                                max={5}
                                step={0.1}
                                value={picture.zoom}
                                defaultValue={picture.zoom}
                                onChange={handleSlider}
                                aria-label='slider-ex-4'
                                mt={5}
                                w={"80%"}
                            >
                                <SliderTrack>
                                    <SliderFilledTrack />
                                </SliderTrack>
                                <SliderThumb />
                            </Slider>
                        </Center>

                        <HStack spacing={4} mt={3} justifyContent={"space-between"}>
                            <Button variant="contained" onClick={handleCancel}>
                                Cancel
                            </Button>
                            <Button onClick={handleSave}>Save</Button>
                        </HStack>
                    </Box>) : (
                    <Dropzone onDrop={(acceptedFiles) => {
                        acceptedFiles.forEach((file) => {
                            const reader = new FileReader()

                            reader.onabort = () => console.log('file reading was aborted')
                            reader.onerror = () => console.log('file reading has failed')
                            reader.onload = () => {
                                // Do whatever you want with the file contents
                                const binaryStr = reader.result
                                console.log(binaryStr)
                                setPicture({
                                    ...picture,
                                    img: binaryStr,
                                    cropperOpen: true
                                });
                            }
                            // reader.readAsArrayBuffer(file)
                            reader.readAsDataURL(file)
                        }
                        )
                    }
                    }
                        noKeyboard
                    >
                        {({ getRootProps, getInputProps }) => (
                            <Center
                                borderWidth="1px"
                                borderRadius="lg"
                                bg={"gray.50"}
                                {...props}
                                w={"100%"}
                                _hover={{ cursor: 'pointer', shadow: 'inner' }}
                                {...getRootProps()}
                            >
                                <VStack spacing="3">
                                    <Square size="10" bg="bg-subtle" borderRadius="lg">
                                        <Icon as={FiUploadCloud} boxSize="5" color="muted" />
                                    </Square>
                                    <VStack spacing="1" p={2}>
                                        {/* <HStack spacing="1" whiteSpace="nowrap"> */}
                                        <Button variant="link" colorScheme="blue" size="sm">
                                            Click to upload
                                        </Button>
                                        <Text fontSize="xs" color="muted">
                                            or
                                        </Text>
                                        <Text fontSize="xs" color="muted">
                                            drag and drop
                                        </Text>
                                        {/* </HStack> */}
                                        <Text fontSize="xs" color="muted">
                                            PNG, JPG or GIF up to 2MB
                                        </Text>
                                    </VStack>
                                </VStack>
                                <input {...getInputProps()} />
                            </Center>
                        )
                        }
                    </Dropzone >
                )}
            </HStack>
        );
    }; 
     
    const Card = (props) => (
        <Box
            maxW="3xl"
            mx="auto"
            bg={useColorModeValue('white', 'gray.700')}
            rounded={{
                md: 'xl',
            }}
            padding="5"
            shadow={{
                md: 'inner',
            }}
            px={{
                base: '6',
                md: '8',
            }}
            mt={3}
            bgColor={"blackAlpha.50"}
            {...props}
        />
    )

    const UserCard = () => {
        return (
            <Box as="section">
                <Card>
                    <Stack
                        direction={{
                            base: 'column',
                            md: 'row',
                        }}
                        spacing={{
                            base: '3',
                            md: '10',
                        }}
                        align="flex-start"
                    >
                        <Stack spacing="4">
                            <Avatar
                                size="2xl"
                                src={formData.image !== "" ? formData.image : formData.gender === "Female" ? "https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80" : "https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1160&q=80"}
                                name="Melinda Paul"
                                shadow={"base"}
                            />
                            <Button
                                width="full"
                                colorScheme="blue"
                                display={{
                                    base: 'none',
                                    md: 'initial',
                                }}
                                onClick={() => setIsUploadImg(true)}
                                shadow={"base"}
                            >
                                Upload Image
                            </Button>
                        </Stack>
                    </Stack>
                </Card>
            </Box>
        )
    }
    
  return (
        <>
            <Center w={"40%"}>
                {isUploadImg ? (
                    <>
                        <Stack w={"100%"} spacing={5} justifyContent={"space-between"} p={5} borderRadius={"lg"}>
                            <Dropzones />
                            <Button onClick={() => setIsUploadImg(false)}>Cancel</Button>
                        </Stack>
                    </>
                ) : (
                    <>
                        <UserCard />
                    </>
                )}
            </Center>
        </>
    );      
};

Fire Storage Upload Utils

import { storage } from "../Configs/firebase";
import {
  ref,
  uploadString,
  uploadBytes,
  getDownloadURL,
} from "firebase/storage";

export const Upload = async (title, type, image, selectedCompanies) => {
  console.log(title, "in upload image.js");
  const path = `${selectedCompanies}/${type}/${title}`;
  const storageRef = ref(storage, path);

  return new Promise((resolve, reject) => {
    uploadString(storageRef, image, "data_url")
      .then((snapshot) => {
        console.log("Uploaded a data_url string!", snapshot);
        getDownloadURL(snapshot.ref).then((downloadURL) => {
          resolve({
            path: path,
            url: downloadURL,
          });
          console.log("Uploaded a data_url string!", downloadURL);
        });
      })
      .catch((error) => reject(error.message));
  });
};

export const UploadWithBytes = async (title, type, file, selectedCompanies) => {
  console.log(title, "in upload image.js");

  const path = `${selectedCompanies}/${type}/${title}`;
  const storageRef = ref(storage, path);

  return new Promise((resolve, reject) => {
    uploadBytes(storageRef, file)
      .then((snapshot) => {
        getDownloadURL(snapshot.ref).then((downloadURL) => {
          resolve({
            path: path,
            url: downloadURL,
          });
          console.log("Uploaded a blob or file!", downloadURL);
        });
      })
      .catch((error) => reject(error.message));
  });
};

Last updated

Was this helpful?