Traversy Media - Build Photo Gallery With React and Firebase
Published: 2023-01-24 09:26:52

**Folder Structure :-**
![Folder Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/227otrgwjjb0n20ukhqm.png)

**App.js Code :-**
``` react
import ImageGrid from "./comps/ImageGrid";
import Modal from "./comps/Modal";
import Title from "./comps/Title";
import UploadForm from "./comps/UploadForm";
import { useState } from 'react'


function App() {
  const [selectedImg, setSelectedImg] = useState(null);

  return (
    <div className="container" onClick={() => {
      if (selectedImg) {

        setSelectedImg(null)
      }
    }}>
      <div className="row">

        
        <Title />
        <UploadForm />
        <ImageGrid setSelectedImg={setSelectedImg} />
        {selectedImg ? <Modal selectedImg={selectedImg} setSelectedImg={setSelectedImg} /> : null}

      </div>
    </div>
  );
}

export default App;
```

**firebase-config.js Code :-**
``` react
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";

// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
const firebaseConfig = {
    apiKey: "",
    authDomain: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: "",
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);

const db = getFirestore(app);
const storage = getStorage(app);

export { db, storage };
```

**useFirestore.js Code :-**
``` react
import { useEffect, useState } from 'react';
import { collection, onSnapshot } from "firebase/firestore";
import { db } from '../config/firebase-config';
import { query, orderBy } from "firebase/firestore";

const useFirestore = (aksh) => {
    const [docs, setDocs] = useState([]);

    useEffect(() => {
        const unsub = onSnapshot(query(collection(db, aksh), orderBy("createdAt", 'desc')), (snapshot) => {

            let documents = [];
            snapshot.docs.forEach((item, index) => {
                documents.push({ ...item.data(), id: item.id })
            })

            setDocs(documents);
        });

        return () => unsub();
        // eslint-disable-next-line
    }, []);

    return { docs }
}

export default useFirestore
```

**useStorage.js Code**
``` react
import { useState, useEffect } from 'react'
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import { db, storage } from '../config/firebase-config';
import { collection, addDoc, serverTimestamp } from "firebase/firestore";

const useStorage = (file) => {

  const [progress, setProgress] = useState(0);
  const [error, setError] = useState(null);
  const [url, setUrl] = useState(null);


  useEffect(() => {
    const storageRef = ref(storage, 'images/' + file.name);
    const uploadTask = uploadBytesResumable(storageRef, file);
    uploadTask.on('state_changed',
      (snapshot) => {
        const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        setProgress(progress);
      },
      (error) => {
        setError(error);
      },
      async () => {
        const url = await getDownloadURL(uploadTask.snapshot.ref)
        await addDoc(collection(db, "image1"), {
          url,
          createdAt: serverTimestamp()
        });
        setUrl(url);

      }
    );

  }, [file])

  return { progress, url, error }
}

export default useStorage
```

**ImageGrid.js Code :-**
``` react
import useFirestore from '../hooks/useFirestore'
import { motion } from 'framer-motion';

const ImageGrid = ({ setSelectedImg }) => {
    const { docs } = useFirestore('image1');


    return (
        <>
            <div className="row">

                {docs.length === 0 ? <h2 className='alert alert-success'> Loading </h2> : docs.map((item) => {
                    return <motion.div layout whileHover={{ scale: 1.2 }} key={item.id} className="col-md-4" onClick={() => setSelectedImg(item.url)}>
                        <motion.img className='img-fluid img-rounded ' src={item.url} alt='uploaded pic' />
                        <h2> </h2>
                    </motion.div>
                })}
            </div>

        </>
    )
}

export default ImageGrid
```

**Modal.js Code :-**
``` react
import React from 'react'

const Modal = (props) => {
    return (
        <div style={{ position: "fixed", top: 0, left: 0, width: "100%", minHeight: "100%", background: 'white' }} onClick={() => { props.setSelectedImg(null) }}>
            <h1> hi </h1>
            <img src={props.selectedImg} style={{ display: 'block', maxWidth: "90%", margin: "auto auto" }} alt="enlarged pic" />
        </div>
    )
}

export default Modal
```

**Progressbar.js Code :-**
``` react
import React from 'react';
import useStorage from '../hooks/useStorage';

const Progressbar = ({ file, setFile }) => {
  const { url, progress } = useStorage(file);

  React.useEffect(() => {
    if (url) {
      setFile(null)
    }
    // eslint-disable-next-line 
  }, [url])
  return (

    <>

      <div className="progress" id='pro' role="progressbar" aria-label="Example with label" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">
        <div className="progress-bar" style={{ width: `${progress}%` }}>{Math.floor(progress)}%</div>
      </div>

    </>
  )
}

export default Progressbar
```

**Title.js Code**
``` react
import React from 'react'

const Title = () => {
  return (
    <div>
        <h1> FireGram </h1>
        <h2> Your Pictures </h2>
        <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. At, sapiente! </p>
    </div>
  )
}

export default Title
```

**UploadForm.js Code**
``` react
import { useState } from 'react'
import Progressbar from './Progressbar';

const UploadForm = () => {
    const [file, setFile] = useState(null);
    const [error, setError] = useState(null);

    const handleOnChange = (e) => {
        const selected = e.target.files[0];
        console.log(selected);

        const allow_types = ["image/png", "image/jpeg"];

        if (selected && allow_types.includes(selected.type)) {
            setFile(selected);
            setError(null);
        }
        else {
            setFile(null);
            setError("Please select an image file (png or jpeg)")
        }

    }
    return (
        <>
            <form >

                {/* <input style={{ display: 'none' }} type="file" onChange={handleOnChange} id='f1' />
                <label htmlFor="f1" className='text-primary'>
                    <h1> Upload File </h1>
                </label> */}


                <div className="mb-3">
                    <label htmlFor="formFile" className="form-label">Default file input example</label>
                    <input className="form-control" type="file" id="formFile" onChange={handleOnChange} />
                </div>

                <div>
                    {error && <div> {error} </div>}

                    {file && <div> {file.name} </div>}
                    {file && <Progressbar file={file} setFile={setFile} />}

                </div>
            </form>

            <br />


        </>
    )
}

export default UploadForm;
```

**Output**
![Output Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sef74vivtluulcgw4fm1.png)


![Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uijyukqkk56aon7ug8lv.png)


![Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbm4ho5i0lsd9iwpys4c.png)
Thank You.
You can follow us on:
[Youtube ](https://www.youtube.com/c/ULTIMATEPROGRAMMING)
[Instagram](https://www.instagram.com/full_stack_web_developer1/)