Skip to main content
Source Link
Dream_Cap
  • 641
  • 7
  • 14

A recipe box that adds, edits, and removes recipes

I made a recipe box with ReactJS. Please let me know what room for improvement you see. I did notice that with codepen, the list of components started to become lengthy to look at. Is it a best practice to separate the different components into different js files? Here is the codepen: https://codepen.io/capozzic1/pen/gmpVyr. Here is the code:

var Grid = ReactBootstrap.Grid;
var Col = ReactBootstrap.Col;
var Row = ReactBootstrap.Row;

/*
Component ideas
-recipeCon
  -RecipeList
        -Recipe ingredients 
                        -edit-delete
-addRecipe button 
            -recipe entry
                        
*/

var recipes = [{
        title: "Pizza",
        ingredients: ["Tomato Sauce", "Yeast"]
    }, {
        title: "Cookies",
        ingredients: ["Cookie Dough", "Chocolate chips"]
    }, {
        title: "Turkey tacos",
        ingredients: ["Nacho cheese taco shells", "Turkey"]
    }

]
//holds all other components. has add/edit methods
class RecipeContainer extends React.Component {
    constructor(props) {
        super(props);
        this.state = ({
            recipes: recipes,
            edit: false,
            editTitle: "",
            editIngred: "",

        });
        this.addRecipe = this.addRecipe.bind(this);
        this.editRecipe = this.editRecipe.bind(this);
        this.addBtnEdit = this.addBtnEdit.bind(this);
        this.editText = this.editText.bind(this);
        this.editContents = this.editContents.bind(this);
        this.handleOpen = this.handleOpen.bind(this);
    }

    editRecipe() {
        this.setState({
            edit: true
        });

    }
    editText(editTitle, editIngred) {
        this.setState({
            editTitle: editTitle,
            editIngred: editIngred
        })
    }

    addRecipe(recipe) {
        recipes.push(recipe);
        this.setState({
            recipes: recipes
        });
    }

    addBtnEdit() {
        this.setState({
            edit: false
        });
    }
    editContents() {
        this.setState({
            recipes: recipes
        });
        console.log(recipes);
    }

    handleOpen() {
        document.querySelector(".recEntry").style.visibility = 'visible';
    }

    render() {

        return (
            <Grid>
                <Row className="show-grid">
                    <Col md={12}>
                        
                    <div className="recipeCon">
                        <h2 className="text-center mainh2">A recipe box</h2>
                  <RecipeList recipes={this.state.recipes} 
                                  edit={this.editRecipe} 
                                  editText={this.editText} 
                               deleteContents={this.editContents}  
                               open={this.handleOpen}/>
                        
                  <AddRecipeBtn editTrue={this.addBtnEdit} 
                                 open={this.handleOpen}/>

                </div>
                <div className="recEntryWrap">
            <RecipeEntry addRecipe={this.addRecipe} 
                                editStat={this.state.edit} 
                                editTitle={this.state.editTitle} 
                                editIngred={this.state.editIngred} 
                                editCont={this.editContents}/>
            </div>
                </Col>
                    </Row>
                        </Grid>
                );
    }
}

//show list of recipe names
class RecipeList extends React.Component {
    constructor(props) {
        super(props);
        this.handleEdit = this.handleEdit.bind(this);
        this.handleDelete = this.handleDelete.bind(this);
        this.handleToggle = this.handleToggle.bind(this);
    }
    handleEdit(e) {
        this.props.edit();
        var editTitle = $(e.target).siblings("h2").text();
        var editIngred = $(e.target).siblings("li").map(function(i, listi) {
            return $(listi).text();
        }).toArray().join(',');

        this.props.editText(editTitle, editIngred);
        //document.appendChild(test);
        //value={editStat ? editTitle : ""}
        $('.titleSpan').text(editTitle);
        $('.inpIngred').val(editIngred);
        this.props.open();
    }
    handleDelete(e) {
        var recTitle = $(e.target).siblings("h2").text();

        for (var i = 0; i < recipes.length; i++) {

            if (recTitle === recipes[i].title) {
                recipes.splice(i, 1);
            }
        }
        this.props.deleteContents();
    }

    handleToggle(e) {
            var sib = $(e.target).siblings().toggle();
            console.log(sib);
        }
        //onclick of edit, get title and ingredients
    render() {
    //generate list of li items and add to ul
        var recipes = this.props.recipes;
        var recLi = recipes.map((recipe, index) =>
            <div key={index}>
            <h2 className="rech2" onClick={this.handleToggle}>{recipe.title}</h2>
                {
                recipe.ingredients.map((ingred,index) =><li key={index + "id"}>                 {ingred}</li>)
                }                       
        <button onClick={this.handleEdit} className="editBtn">Edit</button>
        <button onClick={this.handleDelete} className="deleteBtn">Delete</button>
            </div>
        );
        return (
            <div className="recList">
            <ul className="recUl">
        {recLi}
        </ul>
      </div>
        );
    }
}
//recipe button for showing recipe entry div 
class AddRecipeBtn extends React.Component {
    constructor(props) {
        super(props);
        this.showEntry = this.showEntry.bind(this);
    }

    showEntry() {
        this.props.open();
        this.props.editTrue();
        //empty the inputs and spans whenever add new recipe is clicked
        $(".inpIngred").val("");
        $(".inpName").val("");
        $(".titleSpan").text("");
    }
    render() {
        return (
            <button onClick={this.showEntry} className="bigAdd">Add New Recipe</button>
        );
    }

}
//enter a new recipe, also handles edit of recipes 
class RecipeEntry extends React.Component {
    constructor(props) {
        super(props);
        this.handleAdd = this.handleAdd.bind(this);
        this.handleEdit = this.handleEdit.bind(this);
        this.handleClose = this.handleClose.bind(this);
    }
    handleAdd() {
        var titleVal = document.querySelector(".inpName").value;
        var ingVal = document.querySelector(".inpIngred").value;
        var newRecipe;
        var ingArr = ingVal.split(",");

        for (var i = 0; i <= recipes.length; i++) {
            if (recipes.length >= 0) {
                newRecipe = {
                    title: titleVal,
                    ingredients: ingArr
                };
                this.props.addRecipe(newRecipe);
                this.handleClose();
                break;
            } else if (titleVal === recipes[i].title) {
                alert("This recipe already exists");
                break;
            }
        }

    }
    handleClose() {
        var recEntry = document.querySelector(".recEntry");
        recEntry.style.visibility = "hidden";

    }
    handleEdit() {

        var titleVal = document.querySelector(".titleSpan").textContent;
        var ingVal = document.querySelector(".inpIngred").value;

        var ingArr = ingVal.split(",");
        console.log(titleVal);
        //update specific object for recipes array
        for (var i = 0; i < recipes.length; i++) {

            if (recipes[i].title == titleVal) {
                var newTitle = document.querySelector(".inpName").value;
                recipes[i].title = newTitle;
                recipes[i].ingredients = ingArr;

            }
        }
        console.log(recipes);
        //let the recipe container know to update the state
        this.props.editCont();

        this.handleClose();
    }

    render() {
        var editStat = this.props.editStat;
        var editTitle = this.props.editTitle;
        var editIng = this.props.editIngred;

        return (
            <div className="recEntry">
                        
                    <h2>{editStat ? 'Edit a recipe' : 'Add a recipe'}</h2>
                    <h3>Title</h3>
                <p><b>{editStat ? 'Old title: ' :  ""}</b><span className="titleSpan"></span></p>
                    <input type="text" className="inpName" />
                  <h3>Ingredients</h3>
                <p className="instruct">Please put commas(",") in between ingredient names.</p>
                    <textarea className="inpIngred" />
                    <button onClick={editStat ? this.handleEdit : this.handleAdd} className="saveBtn">{editStat ? 'Save' : 'Add recipe'}</button>
                    <button onClick={this.handleClose} className="closeBtn">Close</button>
                    
            </div>
        );
    }
}

ReactDOM.render(<RecipeContainer/>, document.querySelector(".recWrap"));

/*$(".rech2").on('click',function(){
    console.log("test");
});*/