Skip to main content

Week 5

Welcome!

Goals

  • Learn about React state and hooks
  • Build the Kudos form with KudosForm.tsx and style with KudosForm.css
  • Implement functionality by creating fields that can recieve and display real repsonses!

Quick Recap

Last week we learned:

  • CSS fundamentals (box model, colors, typography)
  • How to build the KudosCard component
  • How to display multiple cards using sample data

This week we're going to make our app interactive!

Here is a quick preview...

Part 1: Understanding React State

What is State?

Remember our house analogy?

  • HTML is the walls (structure)
  • CSS is the paint (styling)
  • TypeScript is the door (logic)

State is the furniture inside the house - it can change and move around dynamically!

State is data that can change over time in your React component. When state changes, React automatically re-renders the component to show the updated information.

In effect, this is what gives functionality and actual usefulness to your code.

Some Real-World Examples...

There are a few ways to think about state in everyday terms:

A light switch - It has two states: ON or OFF

  • Current state: The light is currently ON
  • Action: You flip the switch
  • New state: The light is now OFF

A shopping cart - It has a list of items

  • Current state: 3 items in cart
  • Action: You add a new item
  • New state: 4 items in cart

Our Kudos App - It will have a list of kudos cards

  • Current state: 1 kudos card displayed
  • Action: User submits the form
  • New state: 2 kudos cards displayed

This is exactly what we're building today!

Hooks

Hooks are functions that let you "hook into" and control React states.

Since we can use hooks for each individual (functional) component, it is actually possible to write entire React applications using only functional components, which in turn HIGHLY simplifies the component model that we discussed last week.

Before we dive into how they are used in our project, let's go over some properties of hooks that will help you understand them better

General Properties

  • They can only be used with functional components. You CANNOT use them in class components.
  • Every time our function runs/is called, its hooks must run in the exact same order. In other words, we cant really have a hook inside of a conditional statement, since if the statement didn't run, we would have an error. This follows that we really can't have hooks nested inside of anything (loops, conditionals, functions, etc.). They must be at the top level of our function, and always called in the exact same order.
  • Lastly, there are a few important types of hooks that React allows us to use. In the next section, I will go over one of these types.

The useState Hook

React gives us a special function called useState to manage state. The pattern looks like this:

const [currentValue, functionToUpdateIt] = useState(initialValue);

Think of it like this:

  • currentValue - What the state is right now
  • functionToUpdateIt - How to change it
  • initialValue - What it starts as

Don't worry if this seems abstract - it'll make perfect sense once we start building!

Part 2: Building the Kudos Form Component

Step 1: Setting Up the KudosForm File

First, let's create a new file for our form component.

We will start with just the imports and the component shell:

CREATE: src/components/KudosForm.tsx

import { useState } from 'react';
import './KudosForm.css';

export function KudosForm() {
  return (
    <div>
      <h2>Form goes here</h2>
    </div>
  );
}

What's happening:

  • We import useState from React - this is the hook we'll use for state
  • We import our CSS file (which we'll create next)
  • We export a function component called KudosForm
  • For now, it just returns a simple div with text

Step 2: Defining the Props Interface

In this step, we are going to learn about a few key React topics so be sure to ask questions if you are confused.

Currently, we know that our form needs some way to communicate with its parent component (App.tsx).

So, how can we do this? How can we connect the live state of our component - in this case, our kudos form - with its parent component?

To facilitate this communication, we use props.

Props

Props are read-only properties that are passed from a parent component to a child component.

They are a fundamental concept for passing data and configuration down the component tree and ensuring that components can talk to each other in real-time.

Interfaces

This may seem like a lot to manage - and it is - but thankfully, React makes it really easy for us to organize and manage this data. To show this, let's talk a bit about interfaces.

Interfaces are primarily used to define the structure and types that the props of a component's object must adhere to.

It is a little tricky to understand at first, but it is important to note that interfaces do not actually recieve or store this data, but rather, they enforce 'rules' that an object must follow.

An interface is basically a blueprint (hahahaha😅😐) that describes the data we want to receive from objects.

Destructuring

To make processing this data easier, we can employ a technique called destructuring.

Destructuring allows us to unpack an object's props into easy-to-use variables that we can call right in the function.

Without destructuring, our code looks like this:

//Regular Function component
function Welcome(props) {
  return <h1>Hello, {props.name} from {props.city}!</h1>;
}

See how we have to use dot-notation to retrieve information from an object? We are making it harder for ourselves than it has to be.

By destructuring objects, we can simply take their distinct variables as parameters rather than calling them from an object.

It looks like this:

// Destructuring { name, city } from the props object
function Welcome({ name, city }) {
  return <h1>Hello, {name} from {city}!</h1>;
}

Putting these ideas together...

Let's define what data it expects and what it will send eventually send back.

UPDATE: Add this interface at the top of src/components/KudosForm.tsx:

import { useState } from 'react';
import './KudosForm.css';

// Define what props this component accepts
interface KudosFormProps {
  onSubmit: (kudos: {
    recipient: string; // recipient name as a string
    message: string; // kudos message as a string
    giver: string; // kudos giver as a string
    type: 'kudos' | 'feedback'; // type (kudos or feedback)
    date: string; // date as a string
  }) => void;
}

export function KudosForm({ onSubmit }: KudosFormProps) {
  return (
    <div>
      <h2>Form goes here</h2>
    </div>
  );
}

What's happening:

  • KudosFormProps is a TypeScript interface that defines what props our component expects
  • onSubmit - when the user submits the form, we'll create a kudos object and pass it to the parent component using this function. The parent decides what to do with it (like adding it to a list).
  • The function accepts a kudos object with all the fields we need to track
  • type: 'kudos' | 'feedback' means type can ONLY be one of these two strings
  • void means the function doesn't return anything
  • { onSubmit }: KudosFormProps - we destructure the props to get the onSubmit function

Step 3: Creating the Form Structure - Header

Let's build the actual form, starting with the header and structure.

UPDATE: Replace the return statement in src/components/KudosForm.tsx:

export function KudosForm({ onSubmit }: KudosFormProps) {
  return (
    <form className="kudos-form">
      <h2 className="form-title">✨ Give Kudos</h2>
    </form>
  );
}

What's happening:

  • We use <form> instead of <div> - this is the HTML element for forms
  • className="kudos-form" - this is how we attach CSS classes in React (remember: not class, but className)
  • The emoji ✨ gives it some swag
  • form-title is a CSS class we'll style later

Step 4: Adding the Recipient Input Field

Finally, let's add our first input field!

This will be for the main input we are handling in this program... a Kudos message!

And again, feel free to ask questions as we walk through this - it is super important.

UPDATE: Add the first form group inside the <form> in src/components/KudosForm.tsx:

export function KudosForm({ onSubmit }: KudosFormProps) {
  return (
    <form className="kudos-form">
      <h2 className="form-title">✨ Give Kudos</h2>
      
      <div className="form-group">
        <label htmlFor="recipient">To:</label>
        <input
          id="recipient"
          type="text"
          placeholder="Enter recipient name"
          required
        />
      </div>
    </form>
  );
}

What's happening:

  • <div className="form-group"> - A container for the label and input
  • <label htmlFor="recipient"> - The label describes what the input is for
    • htmlFor="recipient" connects this label to the input with id="recipient"
    • When you click the label, it focuses the input!
  • <input> - The actual text field
    • id="recipient" - Unique identifier, connects to the label
    • type="text" - Makes it a text input
    • placeholder - The gray text that shows when empty
    • required - HTML validation - form won't submit if empty

Step 5: Adding the Message Text area

Next, let's add a textarea for the kudos message.

UPDATE: Add the message field in src/components/KudosForm.tsx:

export function KudosForm({ onSubmit }: KudosFormProps) {
  return (
    <form className="kudos-form">
      <h2 className="form-title">✨ Give Kudos</h2>
      
      <div className="form-group">
        <label htmlFor="recipient">To:</label>
        <input
          id="recipient"
          type="text"
          placeholder="Enter recipient name"
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="message">Message:</label>
        <textarea
          id="message"
          placeholder="Write your kudos or feedback..."
          rows={4}
          required
        />
      </div>
    </form>
  );
}

What's happening:

  • <textarea> - Like an input, but for multi-line text
  • rows={4} - Start with 4 visible rows (users can type more)
  • Notice we use {4} with curly braces because it's a number, not a string
  • Same pattern: label with htmlFor, textarea with matching id

Step 6: Adding the Giver Input Field

Now let's add a field for who's giving the kudos.

UPDATE: Add the giver field in src/components/KudosForm.tsx:

export function KudosForm({ onSubmit }: KudosFormProps) {
  return (
    <form className="kudos-form">
      <h2 className="form-title">✨ Give Kudos</h2>
      
      <div className="form-group">
        <label htmlFor="recipient">To:</label>
        <input
          id="recipient"
          type="text"
          placeholder="Enter recipient name"
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="message">Message:</label>
        <textarea
          id="message"
          placeholder="Write your kudos or feedback..."
          rows={4}
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="giver">From:</label>
        <input
          id="giver"
          type="text"
          placeholder="Your name"
          required
        />
      </div>
    </form>
  );
}

What's happening:

  • Same pattern as the recipient field
  • This captures who is giving the kudos
  • Notice the consistent structure: div wrapper, label, input

Step 7: Adding the Type Selector (Dropdown)

Let's add a dropdown to choose between "kudos" and "feedback".

UPDATE: Add the type selector in src/components/KudosForm.tsx:

export function KudosForm({ onSubmit }: KudosFormProps) {
  return (
    <form className="kudos-form">
      <h2 className="form-title">✨ Give Kudos</h2>
      
      <div className="form-group">
        <label htmlFor="recipient">To:</label>
        <input
          id="recipient"
          type="text"
          placeholder="Enter recipient name"
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="message">Message:</label>
        <textarea
          id="message"
          placeholder="Write your kudos or feedback..."
          rows={4}
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="giver">From:</label>
        <input
          id="giver"
          type="text"
          placeholder="Your name"
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="type">Type:</label>
        <select id="type">
          <option value="kudos">Kudos</option>
          <option value="feedback">Feedback</option>
        </select>
      </div>
    </form>
  );
}

What's happening:

  • <select> - Creates a dropdown menu
  • <option value="kudos"> - Each option has a value (what gets stored) and text (what user sees)
  • The first option (Kudos) is selected by default
  • This will let users choose whether they're giving kudos or feedback through the simple logic we impleemnted a few steps ago

Step 8: Adding the Submit Button

Finally, let's add the submit button to complete our form structure.

UPDATE: Add the button at the end of the form in src/components/KudosForm.tsx:

export function KudosForm({ onSubmit }: KudosFormProps) {
  return (
    <form className="kudos-form">
      <h2 className="form-title">✨ Give Kudos</h2>
      
      <div className="form-group">
        <label htmlFor="recipient">To:</label>
        <input
          id="recipient"
          type="text"
          placeholder="Enter recipient name"
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="message">Message:</label>
        <textarea
          id="message"
          placeholder="Write your kudos or feedback..."
          rows={4}
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="giver">From:</label>
        <input
          id="giver"
          type="text"
          placeholder="Your name"
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="type">Type:</label>
        <select id="type">
          <option value="kudos">Kudos</option>
          <option value="feedback">Feedback</option>
        </select>
      </div>

      <button type="submit" className="submit-button">
        Send Kudos 🎉
      </button>
    </form>
  );
}

What's happening:

  • <button type="submit"> - When clicked, this will submit the form
  • type="submit" is crucial - it tells the browser this button submits the form
  • className="submit-button" for styling
  • We're doing great work!

Step 8a: Import the Form Component

Now let's see our form structure! Even though it's not styled yet, we can display it to make sure everything is working.

UPDATE: Add imports at the top of src/App.tsx:

import { useState } from 'react';
import { KudosCard } from './components/KudosCard';
import { KudosForm } from './components/KudosForm';  // ← Add this
import './components/KudosCard.css';
import './App.css';

What's happening:

  • We import the KudosForm component we just created
  • Now we can use <KudosForm /> in our JSX
  • Note: We're NOT importing the CSS yet - we'll add that after we create it

Step 8b: Create a Temporary Handler Function

Our form expects an onSubmit prop (remember the interface we created?). Let's create a temporary function to pass to it.

UPDATE: Add this inside the App function in src/App.tsx, right before the return statement:

function App() {
  const sampleKudos = [
    {
      recipient: "Jane Smith",
      message: "Amazing work on the authentication refactor! Your attention to detail made the whole team more productive.",
      giver: "John Doe",
      type: "kudos" as const,
      date: "Mar 22, 2024"
    },
    {
      recipient: "Bob Wilson",
      message: "Could improve code documentation in the API module.",
      giver: "Alice Chen",
      type: "feedback" as const,
      date: "Mar 20, 2024"
    }
  ];

  // Temporary function - we'll make this work properly later!
  const handleAddKudos = (kudos: any) => {
    console.log('New kudos submitted:', kudos);
  };

  return (
    // ... rest of code ...
  );
}

What's happening:

  • We create a function called handleAddKudos that takes a kudos object
  • For now, it just logs to the console - we'll make it actually add kudos later
  • kudos: any - TypeScript type any means "any type" (we'll make this properly typed later)
  • This function will be called when the form is submitted

Step 8c: Add the Form to the JSX

UPDATE: Add the form component in src/App.tsx:

return (
  <div className="app-container">
    <div className="app-content">
      <h1 className="app-title">🎉 Kudos Board</h1>
      
      {/* Add the form here! */}
      <KudosForm onSubmit={handleAddKudos} />
      
      <div className="cards-grid">
        {sampleKudos.map((kudos, index) => (
          <KudosCard
            key={index}
            recipient={kudos.recipient}
            message={kudos.message}
            giver={kudos.giver}
            type={kudos.type}
            date={kudos.date}
          />
        ))}
      </div>
    </div>
  </div>
);

What's happening:

  • <KudosForm onSubmit={handleAddKudos} /> - We render the form component
  • onSubmit={handleAddKudos} - We pass our temporary function as a prop
  • The form appears ABOVE the kudos cards
  • The form will receive the handleAddKudos function through its props

Step 8d: Check Your Browser!

Look at your browser now!

You should see your unstyled form appear above the kudos cards. It won't look pretty yet (that's coming in Part 3!), but you should see:

  • ✅ The "✨ Give Kudos" header
  • ✅ The "To:" label and input field
  • ✅ The "Message:" label and textarea
  • ✅ The "From:" label and input field
  • ✅ The "Type:" label and dropdown
  • ✅ The "Send Kudos 🎉" button
  • ✅ All the existing kudos cards below

Try clicking around:

  • You can type in the fields
  • You can select from the dropdown
  • If you click the button, the form will submit (though nothing will happen yet - we haven't added the submit logic)

Don't worry that it looks plain! In the next section (Part 3), we'll make it beautiful with CSS.CSS!

Part 3: Styling with CSS

Step 9: Creating the CSS File - Container Styles

Now let's make this form look good! We'll build the CSS step by step too.

CREATE: src/components/KudosForm.css

Start with the main form container:

/* Main form container */
.kudos-form {
  background-color: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 12px;
  padding: 32px;
  max-width: 500px;
  margin: 0 auto 32px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

What's happening:

    background-color: #ffffff - White background border: 1px solid #e2e8f0 - Thin light gray border border-radius: 12px - Rounded corners (remember from last week!) padding: 32px - Space inside the form max-width: 500px - Won't get wider than 500px margin: 0 auto 32px - Centers horizontally (auto left/right), 32px bottom margin box-shadow - Subtle shadow for depth (remember the box model!)

    Step 10: Styling the Form Title

    UPDATE: Add title styling to src/components/KudosForm.css:

    /* ... previous code ... */
    
    /* Form title */
    .form-title {
      font-size: 24px;
      font-weight: 600;
      color: #0f172a;
      margin: 0 0 24px 0;
      text-align: center;
    }
    

    What's happening:

      font-size: 24px - Nice big heading font-weight: 600 - Semi-bold (remember: 400 is normal, 700 is bold) color: #0f172a - Very dark gray (almost black) margin: 0 0 24px 0 - Top: 0, Right: 0, Bottom: 24px, Left: 0 text-align: center - Centers the text

      Step 11: Styling Form Groups

      UPDATE: Add form group styling to src/components/KudosForm.css:

      /* ... previous code ... */
      
      /* Each form field container */
      .form-group {
        margin-bottom: 20px;
      }
      

      What's happening:

        .form-group targets all our field containers margin-bottom: 20px - Adds space between each form field This creates consistent vertical spacing between all inputs

        Step 12: Styling Labels

        UPDATE: Add label styling to src/components/KudosForm.css:

        /* ... previous code ... */
        
        /* Labels for inputs */
        .form-group label {
          display: block;
          font-size: 14px;
          font-weight: 500;
          color: #475569;
          margin-bottom: 8px;
        }
        

        What's happening:

          .form-group label - Targets labels inside form groups display: block - Makes the label take up the full width (pushes input to next line) font-size: 14px - Slightly smaller than default font-weight: 500 - Medium weight color: #475569 - Medium gray margin-bottom: 8px - Small space between label and input

          Step 13: Styling Inputs, Textareas, and Selects - Base Styles

          UPDATE: Add input styling to src/components/KudosForm.css:

          /* ... previous code ... */
          
          /* All input fields, textareas, and selects */
          .form-group input,
          .form-group textarea,
          .form-group select {
            width: 100%;
            padding: 12px;
            border: 1px solid #cbd5e1;
            border-radius: 8px;
            font-size: 14px;
            font-family: inherit;
            transition: border-color 0.2s ease;
          }
          

          What's happening:

            We target all three types at once (comma-separated = same styles for all) width: 100% - Take up full width of container padding: 12px - Space inside the input (makes text not touch the edges) border: 1px solid #cbd5e1 - Light gray border border-radius: 8px - Slightly rounded corners font-size: 14px - Readable size font-family: inherit - Use the same font as the rest of the page transition: border-color 0.2s ease - Smooth color change when we focus (you'll see this next!)

            Step 14: Styling Focus States

            UPDATE: Add focus styling to src/components/KudosForm.css:

            /* ... previous code ... */
            
            /* When input is focused (clicked/active) */
            .form-group input:focus,
            .form-group textarea:focus,
            .form-group select:focus {
              outline: none;
              border-color: #3b82f6;
              box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
            }
            

            What's happening:

              :focus - CSS pseudo-class that activates when you click/tab into an input outline: none - Remove the default browser outline (we're making our own) border-color: #3b82f6 - Change border to blue when focused box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) - Creates a subtle blue glow
                First 3 numbers (0 0 0) = no offset or blur 3px = shadow size rgba = blue color with 10% opacity The transition we added earlier makes this change smooth!

                Step 15: Textarea Specific Styling

                UPDATE: Add textarea-specific styling to src/components/KudosForm.css:

                /* ... previous code ... */
                
                /* Textarea specific */
                .form-group textarea {
                  resize: vertical;
                  min-height: 100px;
                }
                

                What's happening:

                  We target ONLY textareas now resize: vertical - Users can resize it, but only up and down (not horizontally) min-height: 100px - Won't shrink smaller than 100px tall This overrides the general styles just for textareas

                  Step 16: Styling the Submit Button - Base

                  UPDATE: Add submit button base styling to src/components/KudosForm.css:

                  /* ... previous code ... */
                  
                  /* Submit button */
                  .submit-button {
                    width: 100%;
                    padding: 14px;
                    background-color: #3b82f6;
                    color: white;
                    border: none;
                    border-radius: 8px;
                    font-size: 16px;
                    font-weight: 600;
                    cursor: pointer;
                    transition: background-color 0.2s ease;
                  }
                  

                  What's happening:

                    width: 100% - Full width button padding: 14px - Nice chunky padding (easier to click) background-color: #3b82f6 - Blue background color: white - White text border: none - Remove default button border border-radius: 8px - Rounded corners font-size: 16px - Slightly larger text font-weight: 600 - Semi-bold cursor: pointer - Shows hand cursor on hover transition - Smooth background color change

                    Step 17: Button Hover and Active States

                    UPDATE: Add button interaction states to src/components/KudosForm.css:

                    /* ... previous code ... */
                    
                    /* Button hover state */
                    .submit-button:hover {
                      background-color: #2563eb;
                    }
                    
                    /* Button click state */
                    .submit-button:active {
                      transform: translateY(1px);
                    }
                    

                    What's happening:

                      :hover - When mouse is over the button
                        background-color: #2563eb - Darker blue on hover :active - When button is being clicked
                          transform: translateY(1px) - Move down 1 pixel (looks like it's being pressed!) The transitions make these changes smooth

                          Step 18: Display the Form in App.tsx - Import

                          Now let's see our form! We need to import it in App.tsx first.

                          UPDATE: Add imports at the top of src/App.tsx:

                          import React from 'react';
                          import { KudosCard } from './components/KudosCard';
                          import { KudosForm } from './components/KudosForm';  // ← Add this
                          import './components/KudosCard.css';
                          import './components/KudosForm.css';  // ← Add this
                          import './App.css';
                          

                          What's happening:

                            We import the KudosForm component we just created We import the CSS file we just created Now we can use <KudosForm /> in our JSX

                            Step 19: Display the Form in App.tsx - Temporary Function

                            UPDATE: Add a temporary handler function in src/App.tsx:

                            // ... imports ...
                            
                            function App() {
                              const sampleKudos = [
                                // ... existing sample data ...
                              ];
                            
                              // Temporary function - we'll make this work properly later!
                              const handleAddKudos = (kudos: any) => {
                                console.log('New kudos submitted:', kudos);
                              };
                            
                              return (
                                // ... rest of App ...
                              );
                            }
                            

                            What's happening:

                              We create a temporary function to pass to our form Right now it just logs to the console kudos: any - We'll make this properly typed later This function will be called when the form is submitted

                              Step 20: Display the Form in App.tsx - Add to JSX

                              UPDATE: Add the form to the JSX in src/App.tsx:

                              function App() {
                                // ... sampleKudos and handleAddKudos ...
                              
                                return (
                                  <div className="app-container">
                                    <div className="app-content">
                                      <h1 className="app-title">
                                        🎉 Kudos Board  {/* ← Changed from "Kudos Cards Demo" */}
                                      </h1>
                                      
                                      {/* Add the form here! */}
                                      <KudosForm onSubmit={handleAddKudos} />
                                      
                                      <div className="cards-grid">
                                        {sampleKudos.map((kudos, index) => (
                                          <KudosCard
                                            key={index}
                                            recipient={kudos.recipient}
                                            message={kudos.message}
                                            giver={kudos.giver}
                                            type={kudos.type}
                                            date={kudos.date}
                                          />
                                        ))}
                                      </div>
                                    </div>
                                  </div>
                                );
                              }
                              

                              What's happening:

                                <KudosForm onSubmit={handleAddKudos} /> - We render the form onSubmit={handleAddKudos} - We pass our temporary function as a prop The form appears ABOVE the kudos cards

                                ==Check your browser now! You should see the beautiful form appear above your kudos cards. Try clicking around, focusing inputs (see the blue border!), and hovering the button!==


                                Step 21: Adding State - First Field

                                Now let's make the form actually work! We'll start with just the recipient field to understand state.

                                UPDATE: Add state to src/components/KudosForm.tsx:

                                export function KudosForm({ onSubmit }: KudosFormProps) {
                                  // STATE: Track what user types in recipient field
                                  const [recipient, setRecipient] = useState(''); // ← Add this
                                
                                  return (
                                    <form className="kudos-form">
                                      <h2 className="form-title">✨ Give Kudos</h2>
                                      
                                      <div className="form-group">
                                        <label htmlFor="recipient">To:</label>
                                        <input
                                          id="recipient"
                                          type="text"
                                          value={recipient}  // ← Connect state to input
                                          onChange={(e) => setRecipient(e.target.value)}  // ← Update state
                                          placeholder="Enter recipient name"
                                          required
                                        />
                                        {/* Debug: show what's in state */}
                                        <p style={{ fontSize: '12px', color: '#64748b', marginTop: '4px' }}>
                                          You're typing: "{recipient}"
                                        </p>
                                      </div>
                                
                                      {/* ... rest of form ... */}
                                    </form>
                                  );
                                }
                                

                                What's happening:

                                  const [recipient, setRecipient] = useState('');
                                    Creates a state variable called recipient that starts as an empty string '' setRecipient is the function to update it value={recipient} - The input shows whatever is in state onChange={(e) => setRecipient(e.target.value)}
                                      Fires every time you type e is the event object e.target is the input element e.target.value is what's currently typed We pass that to setRecipient to update state The debug paragraph shows the state value in real-time

                                      Test it! Go to your browser and type in the "To:" field. Watch the debug text right below the input field update with every keystroke.

                                      That's React state in action!

                                      This is called a "controlled component" - React controls the input's value through state.


                                      Step 22: Adding State - All Fields

                                      Now let's add state for all the other fields too.

                                      UPDATE: Add all state variables to src/components/KudosForm.tsx:

                                      export function KudosForm({ onSubmit }: KudosFormProps) {
                                        // STATE: One variable for each form field
                                        const [recipient, setRecipient] = useState('');
                                        const [message, setMessage] = useState('');
                                        const [giver, setGiver] = useState('');
                                        const [type, setType] = useState<'kudos' | 'feedback'>('kudos');
                                      
                                        return (
                                          // ... form JSX ...
                                        );
                                      }
                                      

                                      What's happening:

                                        We create 4 state variables total message and giver work just like recipient - empty strings type is special:
                                          useState<'kudos' | 'feedback'>('kudos') - TypeScript generic This tells TypeScript the type can ONLY be 'kudos' or 'feedback' It starts as 'kudos' (the default) Each state variable has its own setter function

                                          Step 23: Connecting State - Message Field

                                          UPDATE: Connect message state to the textarea in src/components/KudosForm.tsx:

                                          <div className="form-group">
                                            <label htmlFor="message">Message:</label>
                                            <textarea
                                              id="message"
                                              value={message}  // ← Connect state
                                              onChange={(e) => setMessage(e.target.value)}  // ← Update state
                                              placeholder="Write your kudos or feedback..."
                                              rows={4}
                                              required
                                            />
                                          </div>
                                          

                                          What's happening:

                                            Same pattern as the recipient field value={message} - Textarea displays the state onChange updates the state when user types Works exactly the same way, just with a textarea instead of input

                                            Step 24: Connecting State - Giver Field

                                            UPDATE: Connect giver state to the input in src/components/KudosForm.tsx:

                                            <div className="form-group">
                                              <label htmlFor="giver">From:</label>
                                              <input
                                                id="giver"
                                                type="text"
                                                value={giver}  // ← Connect state
                                                onChange={(e) => setGiver(e.target.value)}  // ← Update state
                                                placeholder="Your name"
                                                required
                                              />
                                            </div>
                                            

                                            What's happening:

                                              Same exact pattern again value={giver} - Display state onChange with setGiver - Update state Notice the pattern? Every controlled input follows this formula!

                                              Step 25: Connecting State - Type Selector

                                              UPDATE: Connect type state to the select in src/components/KudosForm.tsx:

                                              <div className="form-group">
                                                <label htmlFor="type">Type:</label>
                                                <select
                                                  id="type"
                                                  value={type}  // ← Connect state
                                                  onChange={(e) => setType(e.target.value as 'kudos' | 'feedback')}  // ← Update state
                                                >
                                                  <option value="kudos">Kudos</option>
                                                  <option value="feedback">Feedback</option>
                                                </select>
                                              </div>
                                              

                                              What's happening:

                                                Same pattern, but for a select dropdown value={type} - Shows the current selection from state onChange - Updates state when user picks a different option as 'kudos' | 'feedback' - TypeScript type assertion
                                                  e.target.value is normally just a string We tell TypeScript "trust me, this will only be 'kudos' or 'feedback'"

                                                  Test it! Now you can type in ALL the fields and everything is tracked in state. Remove the debug paragraph from the recipient field - we don't need it anymore!


                                                  Step 26: Handling Form Submit - Prevent Default

                                                  Now let's make the form DO something when you click "Send Kudos"!

                                                  UPDATE: Add handleSubmit function to src/components/KudosForm.tsx:

                                                  export function KudosForm({ onSubmit }: KudosFormProps) {
                                                    const [recipient, setRecipient] = useState('');
                                                    const [message, setMessage] = useState('');
                                                    const [giver, setGiver] = useState('');
                                                    const [type, setType] = useState<'kudos' | 'feedback'>('kudos');
                                                  
                                                    const handleSubmit = (e: React.FormEvent) => {
                                                      // Step 1: Prevent page reload
                                                      e.preventDefault();
                                                    };
                                                  
                                                    return (
                                                      <form className="kudos-form" onSubmit={handleSubmit}>
                                                        {/* ... rest of form ... */}
                                                      </form>
                                                    );
                                                  }
                                                  

                                                  What's happening:

                                                    const handleSubmit = (e: React.FormEvent) => { ... } - Create function to handle form submission e.preventDefault() - CRUCIAL!
                                                      By default, forms reload the page when submitted This stops that behavior Without this, the page would refresh and you'd lose everything onSubmit={handleSubmit} - Attach the function to the form
                                                        When form is submitted (button click or Enter key), this function runs

                                                        Step 27: Handling Form Submit - Create Kudos Object

                                                        UPDATE: Build the kudos object in handleSubmit in src/components/KudosForm.tsx:

                                                        const handleSubmit = (e: React.FormEvent) => {
                                                          // Step 1: Prevent page reload
                                                          e.preventDefault();
                                                          
                                                          // Step 2: Create kudos object from our state
                                                          const newKudos = {
                                                            recipient,    // Short for recipient: recipient
                                                            message,      // Short for message: message
                                                            giver,        // Short for giver: giver
                                                            type,         // Short for type: type
                                                            date: new Date().toLocaleDateString('en-US', { 
                                                              month: 'short', 
                                                              day: 'numeric', 
                                                              year: 'numeric' 
                                                            })
                                                          };
                                                        };
                                                        

                                                        What's happening:

                                                          We create an object with all our state values recipient, is shorthand for recipient: recipient (ES6 feature) date: new Date().toLocaleDateString(...) creates today's date
                                                            new Date() - Gets current date and time .toLocaleDateString('en-US', {...}) - Formats it { month: 'short', day: 'numeric', year: 'numeric' } - Options for format Results in something like "Oct 7, 2024"

                                                            Step 28: Handling Form Submit - Send to Parent

                                                            UPDATE: Send the kudos to the parent component in src/components/KudosForm.tsx:

                                                            const handleSubmit = (e: React.FormEvent) => {
                                                              e.preventDefault();
                                                              
                                                              const newKudos = {
                                                                recipient,
                                                                message,
                                                                giver,
                                                                type,
                                                                date: new Date().toLocaleDateString('en-US', { 
                                                                  month: 'short', 
                                                                  day: 'numeric', 
                                                                  year: 'numeric' 
                                                                })
                                                              };
                                                            
                                                              // Step 3: Send to parent component
                                                              onSubmit(newKudos);
                                                            };
                                                            

                                                            What's happening:

                                                              onSubmit(newKudos) - Call the function we got from props This passes our new kudos object to the parent (App.tsx) The parent can then decide what to do with it Right now it just logs to console (remember our temporary function?)

                                                              Step 29: Handling Form Submit - Reset Form

                                                              UPDATE: Clear the form after submission in src/components/KudosForm.tsx:

                                                              const handleSubmit = (e: React.FormEvent) => {
                                                                e.preventDefault();
                                                                
                                                                const newKudos = {
                                                                  recipient,
                                                                  message,
                                                                  giver,
                                                                  type,
                                                                  date: new Date().toLocaleDateString('en-US', { 
                                                                    month: 'short', 
                                                                    day: 'numeric', 
                                                                    year: 'numeric' 
                                                                  })
                                                                };
                                                              
                                                                onSubmit(newKudos);
                                                              
                                                                // Step 4: Reset form by clearing all state
                                                                setRecipient('');
                                                                setMessage('');
                                                                setGiver('');
                                                                setType('kudos');
                                                              };
                                                              

                                                              What's happening:

                                                                We call all our setter functions with empty values setRecipient('') - Clears the recipient field setMessage('') - Clears the message setGiver('') - Clears the giver setType('kudos') - Resets type back to default When state updates, React re-renders, and all inputs are empty! This gives the user a fresh form for the next kudos

                                                                Test it! Fill out the form and click "Send Kudos". The form should clear, and you should see the kudos object logged in your console (F12 → Console).

                                                                Part 4: Connecting Everything Together

                                                                Step 30: Understanding Where State Should Live

                                                                Whew! That was A LOT of steps... but we made it!

                                                                At this point, there is really only one questioin you should be asking yourself: Where does all of this go???

                                                                In other words, where should the list of ALL kudos cards live?

                                                                Think about it:

                                                                  The FORM needs to ADD kudos to the list The CARDS need to READ from the list

                                                                  If we put the list in the form (KudosForm.tsx), the cards can't access it...

                                                                  If we put it in the cards display... wait, there IS no single cards display component!

                                                                  So, we put the state in the PARENT component (App.tsx) that contains both the form and the cards.

                                                                  App (has the list state)
                                                                  ├── KudosForm (adds to the list via function)
                                                                  └── KudosCards (reads from the list)
                                                                  

                                                                  Step 31: Creating State in App - Interface

                                                                  First, let's define the Kudos type properly.

                                                                  UPDATE: Add the interface at the top of src/App.tsx:

                                                                  import { useState } from 'react';  // ← Add useState import
                                                                  import React from 'react';
                                                                  import { KudosCard } from './components/KudosCard';
                                                                  import { KudosForm } from './components/KudosForm';
                                                                  import './components/KudosCard.css';
                                                                  import './components/KudosForm.css';
                                                                  import './App.css';
                                                                  
                                                                  // Define what a Kudos object looks like
                                                                  interface Kudos {
                                                                    recipient: string;
                                                                    message: string;
                                                                    giver: string;
                                                                    type: 'kudos' | 'feedback';
                                                                    date: string;
                                                                  }
                                                                  
                                                                  function App() {
                                                                    // ... rest of code ...
                                                                  }
                                                                  

                                                                  What's happening:

                                                                    We import useState from React We create an interface for TypeScript This ensures all kudos objects have the same structure It matches what KudosForm sends and what KudosCard expects

                                                                    Step 32: Creating State in App - Initialize State

                                                                    UPDATE: Create state for the kudos list in src/App.tsx:

                                                                    function App() {
                                                                      // STATE: Array to hold ALL kudos
                                                                      const [kudosList, setKudosList] = useState<Kudos[]>([
                                                                        {
                                                                          recipient: "Jane Smith",
                                                                          message: "Amazing work on the authentication refactor!",
                                                                          giver: "John Doe",
                                                                          type: "kudos",
                                                                          date: "Mar 22, 2024"
                                                                        }
                                                                      ]);
                                                                    
                                                                      // ... rest of App ...
                                                                    }
                                                                    

                                                                    What's happening:

                                                                      useState<Kudos[]>([...]) - Create state that's an array of Kudos <Kudos[]> tells TypeScript this is an array of Kudos objects We start with one example kudos in the array kudosList is the current array setKudosList is how we update it

                                                                      Step 33: Creating the Add Function - Understanding Spread

                                                                      UPDATE: Create the add function in src/App.tsx:

                                                                      function App() {
                                                                        const [kudosList, setKudosList] = useState<Kudos[]>([
                                                                          // ... initial kudos ...
                                                                        ]);
                                                                      
                                                                        // FUNCTION: Add a new kudos to the array
                                                                        const handleAddKudos = (newKudos: Kudos) => {
                                                                          setKudosList([newKudos, ...kudosList]);
                                                                        };
                                                                      
                                                                        // ... rest of App ...
                                                                      }
                                                                      

                                                                      What's happening:

                                                                        handleAddKudos takes a new kudos object as a parameter [newKudos, ...kudosList] creates a NEW array:
                                                                          newKudos - The new kudos goes first ...kudosList - The spread operator "unpacks" the old array Result: new kudos at the front, all old kudos after it We pass this new array to setKudosList

                                                                          Why not just kudosList.push(newKudos)?

                                                                            Never modify state directly! .push() modifies the existing array React won't detect the change Always create a NEW array/object when updating state

                                                                            Step 34: Connecting the Form to State

                                                                            UPDATE: Pass the function to the form in src/App.tsx:

                                                                            function App() {
                                                                              const [kudosList, setKudosList] = useState<Kudos[]>([...]);
                                                                              
                                                                              const handleAddKudos = (newKudos: Kudos) => {
                                                                                setKudosList([newKudos, ...kudosList]);
                                                                              };
                                                                            
                                                                              return (
                                                                                <div className="app-container">
                                                                                  <div className="app-content">
                                                                                    <h1 className="app-title">🎉 Kudos Board</h1>
                                                                                    
                                                                                    {/* Pass our function to the form */}
                                                                                    <KudosForm onSubmit={handleAddKudos} />
                                                                                    
                                                                                    {/* ... cards ... */}
                                                                                  </div>
                                                                                </div>
                                                                              );
                                                                            }
                                                                            

                                                                            What's happening:

                                                                              onSubmit={handleAddKudos} - Pass our function as a prop When the form calls onSubmit(newKudos), it's actually calling handleAddKudos(newKudos) This updates our state in App React re-renders App, which re-renders everything inside

                                                                              Step 35: Rendering the List from State

                                                                              UPDATE: Use kudosList to render cards in src/App.tsx:

                                                                              function App() {
                                                                                const [kudosList, setKudosList] = useState<Kudos[]>([...]);
                                                                                const handleAddKudos = (newKudos: Kudos) => {
                                                                                  setKudosList([newKudos, ...kudosList]);
                                                                                };
                                                                              
                                                                                return (
                                                                                  <div className="app-container">
                                                                                    <div className="app-content">
                                                                                      <h1 className="app-title">🎉 Kudos Board</h1>
                                                                                      
                                                                                      <KudosForm onSubmit={handleAddKudos} />
                                                                                      
                                                                                      {/* Render cards from state */}
                                                                                      <div className="cards-grid">
                                                                                        {kudosList.map((kudos, index) => (
                                                                                          <KudosCard
                                                                                            key={index}
                                                                                            recipient={kudos.recipient}
                                                                                            message={kudos.message}
                                                                                            giver={kudos.giver}
                                                                                            type={kudos.type}
                                                                                            date={kudos.date}
                                                                                          />
                                                                                        ))}
                                                                                      </div>
                                                                                    </div>
                                                                                  </div>
                                                                                );
                                                                              }
                                                                              

                                                                              What's happening:

                                                                                kudosList.map(...) - Loop through each kudos in the array (kudos, index) => (...) - For each kudos, return JSX <KudosCard ... /> - Render a card with the kudos data key={index} - React needs a unique key for each item in a list
                                                                                  Helps React efficiently update the list When kudosList state changes, React re-renders this, showing the new cards

                                                                                  Step 36: Adding Empty State

                                                                                  What if there are no kudos? Let's show a friendly message.

                                                                                  UPDATE: Add empty state to src/App.tsx:

                                                                                  function App() {
                                                                                    const [kudosList, setKudosList] = useState<Kudos[]>([...]);
                                                                                    const handleAddKudos = (newKudos: Kudos) => {
                                                                                      setKudosList([newKudos, ...kudosList]);
                                                                                    };
                                                                                  
                                                                                    return (
                                                                                      <div className="app-container">
                                                                                        <div className="app-content">
                                                                                          <h1 className="app-title">🎉 Kudos Board</h1>
                                                                                          
                                                                                          <KudosForm onSubmit={handleAddKudos} />
                                                                                          
                                                                                          <div className="cards-grid">
                                                                                            {kudosList.map((kudos, index) => (
                                                                                              <KudosCard
                                                                                                key={index}
                                                                                                recipient={kudos.recipient}
                                                                                                message={kudos.message}
                                                                                                giver={kudos.giver}
                                                                                                type={kudos.type}
                                                                                                date={kudos.date}
                                                                                              />
                                                                                            ))}
                                                                                          </div>
                                                                                  
                                                                                          {/* Show message when list is empty */}
                                                                                          {kudosList.length === 0 && (
                                                                                            <p className="empty-state">
                                                                                              No kudos yet. Be the first to give some! 🌟
                                                                                            </p>
                                                                                          )}
                                                                                        </div>
                                                                                      </div>
                                                                                    );
                                                                                  }
                                                                                  

                                                                                  What's happening:

                                                                                    {kudosList.length === 0 && (...)} - Conditional rendering
                                                                                      If kudosList.length === 0 is true, show what's after && If false, show nothing className="empty-state" - CSS class for styling This only appears when the array is empty

                                                                                      Step 37: Styling the Empty State

                                                                                      UPDATE: Add empty state styling to src/App.css:

                                                                                      /* ... existing styles ... */
                                                                                      
                                                                                      /* Message when no kudos exist */
                                                                                      .empty-state {
                                                                                        text-align: center;
                                                                                        color: #94a3b8;
                                                                                        font-size: 18px;
                                                                                        padding: 40px;
                                                                                        font-style: italic;
                                                                                      }
                                                                                      

                                                                                      What's happening:

                                                                                        text-align: center - Center the text color: #94a3b8 - Light gray (not too bold) font-size: 18px - Slightly larger than normal padding: 40px - Lots of space around it font-style: italic - Makes it look softer

                                                                                        Step 38: THE MAGIC MOMENT - Testing!

                                                                                        🎉 Everything is connected! Let's test it:

                                                                                          Go to your browser Fill out the form:
                                                                                            To: "Sarah Johnson" Message: "Great presentation today!" From: "Your Name" Type: "Kudos" Click "Send Kudos"

                                                                                            Watch what happens:

                                                                                              ✅ The form clears instantly ✅ A new kudos card appears at the top ✅ It has all the information you entered ✅ It's styled beautifully with the blue "KUDOS" badge

                                                                                              Try it again!

                                                                                                Create a "Feedback" type this time Notice it gets a gray badge instead of blue

                                                                                                The Flow:

                                                                                                  You type → State updates in KudosForm You submit → KudosForm calls onSubmit(newKudos) onSubmit is actually handleAddKudos in App handleAddKudos updates the kudosList state React sees state changed → Re-renders App New card appears in the list!

                                                                                                  Wrap-Up & Key Takeaways

                                                                                                  What we learned today:

                                                                                                    State - Data that changes over time

                                                                                                      const [value, setValue] = useState(initial) Calling setValue triggers a re-render State is local to the component (unless lifted up)

                                                                                                      Controlled Components - React controls the input

                                                                                                        value={state} - Display state onChange={e => setState(e.target.value)} - Update state Input and state stay in sync

                                                                                                        Form Handling

                                                                                                          e.preventDefault() - Stop page reload Collect state into an object Send to parent via props Reset state to clear form

                                                                                                          Lifting State Up

                                                                                                            Put state in the parent when multiple children need it Pass state down as props (to read) Pass functions down as props (to modify) Data flows down, events flow up

                                                                                                            Array State

                                                                                                              Use spread operator: [newItem, ...oldArray] Never mutate state directly Create new arrays/objects React detects changes and re-renders

                                                                                                              The React Mental Model:

                                                                                                              State Changes → React Re-renders → UI Updates