I like Cookies and I like Christmas, and hey Datastax is pretty cool too. so lets build something.

I like Cookies and I like Christmas, and hey Datastax is pretty cool too. so lets build something.

Overview

HEY HEY and happy holidays yall. When I heard Datastax was doing a 12 days of Codemas challenge, well you KNOW your boy had to take a crack at it. What better way to do that than a Christmas Cookie Recipe Finder! It’s a web application that allows users to search for cookie recipes. I used React (cuz not smart enough for other stuff haha) for the frontend and Datastax’s own AstraDB as the backend to store and retrieve recipe data. The application is designed to be responsive and user-friendly.

Key Components

  1. IngredientForm Component: (so initially this was a recipe finder where you enter two ingredients and it spits out recipes you can do with them, but TBF it got HELLA complicated so I pared it down and never changed my filenames.) This component is responsible for handling user input and initiating the search for recipes.

     import React, { useState } from 'react';
     import './IngredientForm.css';
    
     const IngredientForm = ({ onSearch }) => {
       const [keyword, setKeyword] = useState('');
    
       const handleSubmit = async (e) => {
         e.preventDefault();
         await onSearch(keyword);
       };
    
       return (
         <div className="form-container">
           <form className="card" onSubmit={handleSubmit}>
             <h1>Christmas Cookie Recipe Finder</h1>
             <input
               type="text"
               value={keyword}
               onChange={(e) => setKeyword(e.target.value)}
               placeholder="Search for a cookie recipe"
             />
             <button type="submit">Search</button>
           </form>
         </div>
       );
     };
    
     export default IngredientForm;
    
    • State Management: Uses useState to manage the keyword input by the user.

    • Form Handling: The form submission triggers the handleSubmit function, which calls the onSearch function passed as a prop.

  2. RecipeCard Component: This component displays the details of a selected recipe.

     import React from 'react';
     import './RecipeCard.css';
    
     const RecipeCard = ({ recipe, onBack }) => {
       return (
         <div className="recipe-card">
           <button onClick={onBack}>Back to Search</button>
           <h2>{recipe.name}</h2>
           <p>{recipe.description}</p>
           <h3>Ingredients:</h3>
           <ul>
             {recipe.ingredients.map((ingredient, index) => (
               <li key={index}>{ingredient}</li>
             ))}
           </ul>
           <h3>Instructions:</h3>
           <p>{recipe.instructions}</p>
         </div>
       );
     };
    
     export default RecipeCard;
    
    • Props: Receives recipe and onBack as props to display recipe details and handle navigation back to the search form.
  3. App Component: The main component that manages the state of the application and coordinates between IngredientForm and RecipeCard.

     import React, { useState } from 'react';
     import IngredientForm from './components/IngredientForm';
     import RecipeCard from './components/RecipeCard';
     import astraClient from './api/astraClient';
    
     const App = () => {
       const [recipes, setRecipes] = useState([]);
       const [selectedRecipe, setSelectedRecipe] = useState(null);
    
       const fetchRecipes = async (keyword) => {
         try {
           const response = await astraClient.get('/recipes', {
             params: { keyword },
           });
           setRecipes(response.data);
         } catch (error) {
           console.error('Error fetching recipes:', error);
           setRecipes([]);
         }
       };
    
       const handleRecipeSelect = (recipe) => {
         setSelectedRecipe(recipe);
       };
    
       return (
         <div>
           {!selectedRecipe ? (
             <IngredientForm onSearch={fetchRecipes} />
           ) : (
             <RecipeCard recipe={selectedRecipe} onBack={() => setSelectedRecipe(null)} />
           )}
         </div>
       );
     };
    
     export default App;
    
    • State Management: Uses useState to manage the list of recipes and the currently selected recipe.

    • Data Fetching: The fetchRecipes function uses astraClient to fetch recipes from AstraDB based on the keyword.

  4. AstraDB Client: Configured to interact with AstraDB using Axios.

     import axios from 'axios';
    
     const astraClient = axios.create({
       baseURL: `/api/rest/v2/keyspaces/${process.env.REACT_APP_ASTRA_DB_KEYSPACE}`,
       headers: {
         'X-Cassandra-Token': process.env.REACT_APP_ASTRA_DB_TOKEN,
         'Content-Type': 'application/json',
       },
     });
    
     export default astraClient;
    
    • Axios Instance: Configures Axios with the base URL and headers required for authentication with AstraDB.

Environment Setup

To run the application, you need to set up environment variables in a .env file:

REACT_APP_ASTRA_DB_TOKEN=your_astra_db_token
REACT_APP_ASTRA_DB_KEYSPACE=your_keyspace_name

Running the Application

  1. Clone the Repository:

     git clone https://github.com/yourusername/cookie-recipe-search-tool.git
     cd cookie-recipe-search-tool
    
  2. Install Dependencies:

     npm install
    
  3. Start the Development Server:

     npm start
    
  4. Access the Application: Open your browser and navigate to http://localhost:3000.

This setup provides a comprehensive view of how the application is structured and how each component interacts with AstraDB to provide a seamless user experience. If you have any further questions or need additional details, feel free to ask!