sei-ec-remote / team-project-issues

0 stars 0 forks source link

reviewForm - image doesn't clear after review submit #120

Closed amishizaki closed 1 year ago

amishizaki commented 1 year ago

Describe the bug A clear and concise description of what the bug is. The review form utilizes Cloudinary. When a user submits a review. The image stays in the review form. Every other piece of data clear the form, except for the image.

What is the problem you are trying to solve? Why the image won't clear away after the review is submitted

Expected behavior A clear and concise description of what you expected to happen. For the image to disappear after review submission

What is the actual behavior? A clear and concise description of what actually happened. The image does NOT disappear. It lingers.

Post any code you think might be relevant (one fenced block per file) NewReview.js

import React, { useState } from 'react'
import Accordion from 'react-bootstrap/Accordion';
import ReviewForm from '../shared/ReviewForm'
import { reviewCreate } from '../../api/review'

const NewReview = (props) => {
    const {
        user, restaurant, msgAlert, triggerRefresh
    } = props

    const [review, setReview] = useState({
        comment: '',
        rating: '',
        image: ''
    })

    const handleChange = (e) => {
        setReview(prevReview => {
            const name = e.target.name
            let value = e.target.value
            const updatedReview = { [name]: value }
            return {
                ...prevReview, ...updatedReview
            }
        })
    }
    const handleImageChange = (image) => {
        setReview(prevReview => {
            const name = 'image'
            const updatedReview = {[name]: image}
            return {
                ...prevReview, ...updatedReview
            }
        })
    } 

    const handleSubmit = (e) => {
        e.preventDefault()
        let updatedReview = review
        // console.log('updatedREview', updatedReview)
        updatedReview.ownerEmail = user.email
        setReview({
            comment: '',
            rating: '',
            image: ''
        })
        console.log('review', review)
        reviewCreate(user, restaurant._id, updatedReview)
            .then(() => {
                msgAlert({
                    heading: 'Thanks!',
                    message: 'We appreciate you taking the time to review this restaurant!',
                    variant: 'success'
                })
            })
            .then(() => triggerRefresh())
            .catch(() => {
                msgAlert({
                    heading: 'Oh No!',
                    message: 'Something went wrong! Please try again',
                    variant: 'danger'
                })
            })
    }

    return (

        <Accordion>
            <Accordion.Item style={{ backgroundColor: '#f2f6ec' }} eventKey="0">
                <Accordion.Header>Add a Review</Accordion.Header>
                <Accordion.Body style={{ backgroundColor: '#f2f6ec' }}>
                    <ReviewForm
                        review={review}
                        handleChange={handleChange}
                        handleImageChange={handleImageChange}
                        handleSubmit={handleSubmit}
                        heading="Please submit a review!"
                    />
                </Accordion.Body>
            </Accordion.Item>
        </Accordion>

    )
}

export default NewReview

CloudinaryUploadWidget.js

import React, { useState } from "react";
import Axios from 'axios'
import { Button } from 'react-bootstrap'
// import { Image } from 'cloudinary-react'

const CloudinaryUploadWidget = ({ handleImageChange }) => {

    const [imageSelected, setImageSelected] = useState('')
    const [picture, setPicture] = useState('')

    const uploadImage = (files) => {
        // console.log(files[0])
        const formData = new FormData()
        formData.append("file", imageSelected)
        formData.append("upload_preset", "gxc7sx3v")

        Axios.post("https://api.cloudinary.com/v1_1/dtszeeznm/image/upload", formData).then((response) => {
            // console.log(response.data.url);
            setPicture(response.data.url)
            handleImageChange(response.data.url)
            // console.log('this is public_id', public_id)
            .then(() => {
                setPicture('')
                console.log('setPicture', setPicture)
            })
        });
    };

    return (
        <div>
            <input
                type="file"
                onChange={(e) => { setImageSelected(e.target.files[0]) }}
            />
            <Button id="upload_widget" className="m-2 cloudinary-button btn-secondary" onClick={uploadImage}
            >
                Upload
            </Button>

            <img
                style={{ width: 200 }}
                cloudName="dtszeeznm"
                // publicId= { picture }
                src={picture}
            />
        </div>
    );

}

export default CloudinaryUploadWidget;

What is your best guess as to the source of the problem? I think I need to reset the useState in the CloudinaryUploadWidget.js to be an empty string.

What things have you already tried to solve the problem? I tried to reset the useState in the CloudinaryUploadWidget.js to be an empty string in a .then within the axios.post I also added the clear image to an empty string line in NewReview.js

Additional context Add any other context about the problem here.

Paste a link to your repository here https://github.com/sam-phillips21/Client-theGoodAvocado/ https://github.com/sam-phillips21/Api-theGoodAvocado/

timmshinbone commented 1 year ago

Check back on the notes we made in the react-hooks lesson, there's a way to use useEffect like componentWillUnmount, that's where you should reset the state of the form

amishizaki commented 1 year ago

Ok, I'm trying this

amishizaki commented 1 year ago

Was able to use the useEffect format to reset the form to an empty string. Thanks!

Axios.post("https://api.cloudinary.com/v1_1/dtszeeznm/image/upload", formData)
            .then((response) => {
                // console.log(response.data.url);
                setPicture(response.data.url)
                handleImageChange(response.data.url)
                // console.log('this is public_id', public_id)
            });
            return () => {
                console.log('post setPictureMount', setPicture)
                setPicture('')
            }
    };

    // useEffect(() => {
    //     console.log('setPicture pre', setPicture)

    //     return () => {
    //       console.log('setPicture post', setPicture)
    //       setPicture('')
    //     }
    //   }, [])
amishizaki commented 1 year ago

nope, that was a lie. I'm still having issues

amishizaki commented 1 year ago

I can't use the reacthooks because it is not a class function. -> wait, I misspoke here

timmshinbone commented 1 year ago

wut?

amishizaki commented 1 year ago

The function that I'm using to grab the image isn't a class component, so the useEffect doesn't work with it?

timmshinbone commented 1 year ago

Yeah, useEffect was made specifically for function components, so, that's not the issue

amishizaki commented 1 year ago

So, I've tried setting up the clearing action on the NewReview.js and the CloudinaryUploadWidget.js. I think I'm just getting further into the woods with this. Would you give me one more hint before I code myself into a corner?

timmshinbone commented 1 year ago

Definitely! I'm on my way

amishizaki commented 1 year ago

Fixed! Had to do some mapping from the NewReview.js (that was useEffect friendly) back to the CloudinaryUploadWidget.js and the through the ReviewForm.js

NewReview.js

import React, { useState, useEffect } from 'react'
import Accordion from 'react-bootstrap/Accordion';
import ReviewForm from '../shared/ReviewForm'
import { reviewCreate } from '../../api/review'

const NewReview = (props) => {
    const {
        user, restaurant, msgAlert, triggerRefresh
    } = props

    const [review, setReview] = useState({
        comment: '',
        rating: '',
        image: ''
    })
    // const [clear, setClear] = useState(false)
    const [picture, setPicture] = useState('')
    const [imageSelected, setImageSelected] = useState('')

    const handleChange = (e) => {
        setReview(prevReview => {
            const name = e.target.name
            let value = e.target.value
            const updatedReview = { [name]: value }
            return {
                ...prevReview, ...updatedReview
            }
        })
    }
    const handleImageChange = (image) => {
        setReview(prevReview => {
            const name = 'image'
            const updatedReview = {[name]: image}
            return {
                ...prevReview, ...updatedReview
            }
        })
    } 

    // image won't clear with everything else
    // useEffect((image) => {
    //         console.log('image', image)
    //         const name = 'image'
    //         const updatedReview = {[name]: image}

    //         return () => {
    //           console.log('image', image)
    //           updatedReview('')
    //           setClear(!clear)
    //         }
    //       }, [])

    const handleSubmit = (e) => {
        e.preventDefault()
        let updatedReview = review
        // console.log('updatedREview', updatedReview)
        updatedReview.ownerEmail = user.email
        setReview({
            comment: '',
            rating: '',
            image: ''
        })

        // console.log('review', review)
        reviewCreate(user, restaurant._id, updatedReview)
            .then(() => {
                msgAlert({
                    heading: 'Thanks!',
                    message: 'We appreciate you taking the time to review this restaurant!',
                    variant: 'success'
                })
            })
            .then(() => {
                setPicture('')
                setImageSelected('')
            })
            .then(() => triggerRefresh())
            .catch(() => {
                msgAlert({
                    heading: 'Oh No!',
                    message: 'Something went wrong! Please try again',
                    variant: 'danger'
                })
            })
    }

    return (

        <Accordion>
            <Accordion.Item style={{ backgroundColor: '#f2f6ec' }} eventKey="0">
                <Accordion.Header>Add a Review</Accordion.Header>
                <Accordion.Body style={{ backgroundColor: '#f2f6ec' }}>
                    <ReviewForm
                        imageSelected={imageSelected}
                        setImageSelected={setImageSelected}
                        picture={picture}
                        setPicture={setPicture}
                        review={review}
                        handleChange={handleChange}
                        handleImageChange={handleImageChange}
                        handleSubmit={handleSubmit}
                        heading="Please submit a review!"
                    />
                </Accordion.Body>
            </Accordion.Item>
        </Accordion>

    )
}

export default NewReview

ReviewForm.js

import React from 'react'
import { Form, Container, Button } from 'react-bootstrap'
import CloudinaryUploadWidget from "./CloudinaryUploadWidget";

const ReviewForm = (props) => {
    const { review, handleChange, handleSubmit, heading, handleImageChange, picture, setPicture, imageSelected, setImageSelected } = props

    return (
        <Container className="justify-content-center">
            <h3>{heading}</h3>
            <Form onSubmit={handleSubmit}>
                <Form.Label>Comment:</Form.Label>
                <Form.Control
                    placeholder="Add comments about the restaurant, the food, and your overall experience"
                    name="comment"
                    id="comment"
                    value={review.comment}
                    onChange={handleChange}
                    as="textarea"
                    rows={3}
                />
                <Form.Select
                    aria-label="rating"
                    name="rating"
                    value={review.rating} 
                    onChange={handleChange}
                >
                    <option>Add a rating</option>
                    <option value="0">0</option>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                    <option value="4">4</option>
                    <option value="5">5</option>
                </Form.Select>
                <>
                    <CloudinaryUploadWidget 
                        handleImageChange={handleImageChange}
                        picture={picture}
                        setPicture={setPicture}
                        imageSelected={imageSelected}
                        setImageSelected={setImageSelected}
                    />
                </>

                <Button variant='success' type="submit">Submit</Button>
            </Form>
        </Container>
    )
}

export default ReviewForm

CloudinaryUploadWidget.js

import React, { useState, useEffect } from "react";
import Axios from 'axios'
import { Button } from 'react-bootstrap'
// import { Image } from 'cloudinary-react'

const CloudinaryUploadWidget = ({ handleImageChange, picture, setPicture, setImageSelected, imageSelected }) => {

    // const [imageSelected, setImageSelected] = useState('')
    // const [picture, setPicture] = useState('')
    // const [clear, setClear] = useState(false)

    const uploadImage = (files) => {
        // console.log(files[0])
        const formData = new FormData()
        formData.append("file", imageSelected)
        formData.append("upload_preset", "gxc7sx3v")

        Axios.post("https://api.cloudinary.com/v1_1/dtszeeznm/image/upload", formData)
            .then((response) => {
                // console.log(response.data.url);
                setPicture(response.data.url)
                handleImageChange(response.data.url)
                // setClear(true)
                // console.log('this is public_id', public_id)
            })
            // .then(() =>{
            //     setPicture('')
            // })
            // return () => {
            //     // e.target.files = ''
            //     // console.log('post setPictureMount', setPicture)
            //     setPicture('')
            //     // // setImageSelected('')
            //     // // handleImageChange('')
            // }
    };

    // if(clear) {
    //     setPicture('')
    //     // setClear(!clear)
    // }

    useEffect(() => {
        return () => {
            setPicture('')
        }
    }, [])

    console.log('picture', picture)
    return (
        <div>
            <input
                type="file"
                onChange={(e) => { setImageSelected(e.target.files[0]) }}
            />
            <Button id="upload_widget" className="m-2 cloudinary-button btn-secondary" onClick={uploadImage}>
                Upload
            </Button>

            <img
                style={{ width: 200 }}
                cloudName="dtszeeznm"
                // publicId= { picture }
                src={picture}
            />
        </div>
    );

}

export default CloudinaryUploadWidget;
amishizaki commented 1 year ago

Specifically, the set and unsetting commands had to start in the ReviewForm.js

const [picture, setPicture] = useState('')
const [imageSelected, setImageSelected] = useState('')