Kudos

Week 1 + 2

Goals


How will this work?

Weekly session where we will:

By the end, we will have a finshed project!

Why Kudos?

At Blueprint, recognizing the contributions of our developer members is crucial for fostering a positive and productive project team environment. This tool is specifically designed to highlight the efforts of these members and gather valuable feedback. By acknowledging their hard work, especially amidst their academic and other commitments, we aim to improve their overall project team experience and prevent potential feelings of being overworked or burnt out.

Setup

For any project, it is essential to have certain 'tools' installed...

These tools go by many names:

But they all serve one broad purpose: help developers build.

So, before we begin building our project, lets first install all of the necessary tools we'll need along the way.

Git and GitHub

A key foundation of software development is collaboration.

Across industry, developers collaborate using two essential tools: Git and GitHub

Later on, we will explore these two tools, but for now lets just install them.

Windows install

  1. Go to the official Git website at https://git-scm.com/downloads
  2. The download for Windows should begin automatically.
  3. Once the installer finishes downloading, run the .exe file.
  4. Follow the prompts in the installation wizard.
  5. After installation, open a new terminal and type git --version to verify the installation.

macOS install

  1. The easiest way to get Git on macOS is in the terminal.
  2. Open your Terminal application.
  3. Type git --version and press enter.
  4. If Git is not installed, a pop-up will appear asking you to install the command line developer tools. Click "Install" and follow the on-screen instructions.

Now, lets create and authenticate a GitHub account.

Creating Your GitHub Account

Creating a GitHub account is a simple process.

  1. Go to the GitHub Website: Open your web browser and navigate to github.com.
  2. Sign Up: On the homepage, you'll see a sign-up form. Enter your email address, create a password, and choose a username.
  3. Verification: You'll likely need to solve a quick puzzle to verify you're human. After that, GitHub will send a verification code to the email address you provided. Go to your inbox, find the email, and enter the code on the GitHub site.

That's it! You now have a GitHub account.

Authenticating Your Account

Authentication proves your identity when you want to push (upload) or pull (download) code from your computer. Using your password for this is no longer supported for security reasons. Instead, you should use a Personal Access Token (PAT).

A PAT is like a long, secure password that you use only for accessing GitHub from the command line or apps.

  1. Go to Your Settings:

    • Click on your profile picture in the top-right corner and select Settings.
    • In the left sidebar, scroll down and click on Developer settings.
    • Click on Personal access tokens, then select Tokens (classic).
  2. Generate a New Token:

    • Click the Generate new token button.
    • Set an Expiration date. For better security, don't set it to "No expiration". 90 days is fine.
    • Under Select scopes, select the repo scope.
  3. Copy and Save Your Token:

    • Click the Generate token button at the bottom.
    • This is the only time you will see the token!!! Copy it immediately and save it in a secure place, like a password manager. If you lose it, you'll have to generate a new one.
  4. Using Your PAT:

    • Now, when you perform a Git operation in your terminal (like git push) that requires authentication over HTTPS, you'll be prompted for your username and password.
    • Enter your GitHub username.
    • When asked for your password, paste your Personal Access Token.

You're all set! Your GitHub account is now created and authenticated for use on your computer.

Node

Like git, Node is a tool in the software development world that is a must-have.

Among many other things, it allows us to see the changes in our code live in our browser!

So as we add components of our app, we can ensure they look and function as we want them to.

Windows

  1. Go to the official Node.js website: https://nodejs.org/en/download
  2. Download correct verion.
  3. Run the installer and follow the on-screen instructions.
  4. Once the installation is complete, you can open the terminal and verify the installation by typing:
node -v
npm -v

These commands should return the version numbers for Node.js and npm, confirming a successful installation.

macOS

  1. The easiest way is to download the official .pkg installer from the Node.js website: https://nodejs.org/en/download
  2. Choose the LTS version and run the installer after it downloads.
  3. Follow the installation steps. The installer will guide you through the process.
  4. After installation, open a new Terminal window and run the same commands as above to verify: node -v and npm -v.

Visual Studio Code

We will be writing all of our code using Visual Studio.

Visual Studio has a simple install. Simply use this link and follow the steps: https://code.visualstudio.com/download

Troubleshooting

Before we move on, lets address some common issues that you may run into during setup.

Checking Node Versions (Windows Users)

If you recieve an error when running the node - v and npm -v commands:

  1. Search 'Terminal' in your taskbar start menu.
  2. Hover over the Terminal Icon, then right-click.
  3. A menu should appear. Click on the option to 'Run as Administrator'. This should open a new terminal that indicates you are an Administrator in the title bar.
  4. Run this command: Set-ExecutionPolicy RemoteSigned.
  5. Now, try running node - v and npm -v once again, and you should be able to see their versions, confirming your Node has installed correctly.

Creating a Repository

You now know the basics of git and GitHub!

The next step is to create your own repository where you'll store all of your code for the project.

On the main page of GitHub's site, you will see a green box in the top left corner that says 'New'.

Screenshot 2025-09-10 at 9.20.12 AM.png

Click it, and you will be redirected to a new page that looks like this:

Screenshot 2025-09-10 at 9.21.29 AM.png

On this page, you will enter the details of your repository. In our case, this includes a specific set of options that oyu should copy from the screenshot above. Your repository name should be my-kudos, visibility should be public, and add README option shoud be toggled on.

Click create, and you will again be redirected.

Screenshot 2025-09-10 at 9.21.47 AM.png

This is your repo! Now, all you have to do is follow some of the steps from the prior section.

The first is cloning your repo with git clone.

Screenshot 2025-09-10 at 9.24.04 AM.png

Like before, to check that the clone was successful, cd into your new directory.

Screenshot 2025-09-10 at 9.24.51 AM.png

Note: In this example, I also used the ls command, which lists the contents for your directory. Since we just created our repo and initialized it with a README.md file, the only thing in our project folder should be that file - and it is.

Making a Change

As a way to test what we've done so far, lets try actually making changes to file and seeing them reflected in our repository.

Our goal will be to edit a file in our project - then upload the changes to our GitHub repo using the commands we just learned.

Editing a file

In VSCode, open your README.md file.

It should look something like this:

Screenshot 2025-09-16 at 9.17.38 PM.png

Lets make a simple change: add a short sentence about yourself!

It should look like something like this:

Screenshot 2025-09-16 at 9.22.27 PM.png

Note: Those green bars next to each of the lines we just wrote indicate that these are new (uncommitted) lines. This is good! It means that we now have code to upload (commit) to our repo!

Making a Commit

Once the change is made, use the git add command in order to include or 'stage' our changes for the next commit. Commits can be thought of as checkpoints; more on that later.

In this case, we made changes to the README.MD , so our file path is /README.MD and we type in:

git add /README.MD

Note: You can use git add to add as many files as you need, and another common option is to use git add . to add all files with changes. Also, The file path is case sensitive.

Checking Changes to be Committed

You can use the git status command to check what files have been added or "staged" for a commit to ensure you added the right things. In this case, it's only the one contributors file that we added.

Screenshot 2025-09-16 at 9.27.16 PM.png

You can see here that our file is under changes to be committed and is in green text. Changes not staged for commit will be in red (if there are any).

Committing Changes

With our changes made and staged, we can create a commit which can be thought of as a checkpoint for our code. We can revert to this point if we make mistakes or need to look at the version of the code at this point in time.

It is also good practice to include a commit message by using the -m flag to describe what changes were made. For us, we will just say that we are adding a new contributor, like so:

git commit -m "Added info about me!"

Commit Messages: When writing a commit, it is usually good practice to follow a convention. At Blueprint, we use the Conventional Commits specification: www.conventionalcommits.org, but don't worry about that right now!

We can commit as often as we want, or when we feel it is necessary before making big changes.

Screenshot 2025-09-16 at 9.29.03 PM.png

Pushing a Commit

In order for our changes to appear on the remote repository (the one on Github, which is online), we need to push our changes using the git push command. If we run it as is, however, we will encounter an error:

It is no big deal - the reason it happens is because when we create the branch contributors/johnDoe, we only created it locally and it does not exist on the Github repository.

Therefore, we must run the command shown:

git push --set-upstream origin contributors/<your name>

Once the branch is set up remotely, or if the branch already existed remotely and was not created locally, we can simply use git push.

Seeing our Changes

Finally, we can confirm that all of these steps were done correctly by going over to our repo on GitHub and refreshing the page.

Upon doing so, we should see any changes we made reflected on the web, like this:

Screenshot 2025-09-16 at 9.31.04 PM.png

Note: Another way to check is by opening VSCode again, and seeing if those green bars from earlier are still there. If not, then that means there are no new lines to stage, and your commit was successful!

Project Outcomes

At the end of our time together, I hope that you all improve on a two key areas of software development:

Technical Skills

Project Management Skills

Week 3

Goals

A Note About Project Versions and Installations...

I knwo we had some mix-ups and discrepencies last session when trying to create a project.

So, we need to do some cleaning to ensure there is no confusion in the future with project names, versions, etc.

Let's take a few minutes to delete all prior projects relating to Kudos (blueprint_kudos, kudos-me, etc.)

For the last time (fingers crossed) let's create a React project configured to use TypeScript.

In your root directory, run:

npx create-react-app blueprint_kudos --template typescript

After running, you may be asked a few questions. Simply respond yes to all of them.

Then, to open your project in VSCode and start your live development server, run:

cd blueprint_kudos
npm install
npm start

Part 1: CSS Basics

Last week you saw some live changes made to the browser, and hopefully gained some understanding of why we really need tools like Node and git.

This week, we will be getting hands-on with one of the main languages of our app: CSS.

What is CSS?

CSS, which stands for Cascading Style Sheets, is a style sheet language used for describing the presentation of a document written in a markup language like HTML.

Basically, it makes websites look nice.

HTML

You may have heard of HTML, but what does it actually do?

HTML is the structure of a webpage. It's like the skeleton or framework that holds everything together.

Here is some brief info about HTML before we begin diving into CSS. Feel free to check out some tutorials/videos on HTML ifn you want to learn more tha what is in these docs.

How HTML Works

HTML uses tags (words in angle brackets) to define different parts of a webpage:

<h1>This is a heading</h1>
<p>This is a paragraph</p>
<button>Click me</button>

Cheatsheet

Use this as a cheatsheet for whenever you forgot/don't know which tags to use.

And remember: HTML is the foundation - everything else builds on top of it!

A Useful Analogy

A classic analogy that I will probably continue using throughout the next few sessions is this:

Our app is like a house...

HTML is the walls.

TypeScript is the door.

CSS is the paint.

We need all three to build a house, and in our case, this app.

But, specifically, CSS controls:

Let's see how this works in practice.

Classes

You may have heard of classes before... but CSS classes are slightly different.

CSS classes are reusable style definitions that you can apply to HTML elements. They're like templates for styling that you can use over and over again.

We can think of CSS classes like labels or tags that you apply to HTML elements to style them.

Imagine you have a box of different colored stickers:

You stick these labels on different objects, and everyone knows what each color means.

CSS classes work the same way. You "stick" a class name on an HTML (wall) element, and the browser knows how to style it with CSS (paint).

Selectors

Before we can style anything, we need to tell CSS what we want to style. This is where selectors come in.

The purpose of selectors is to tell CSS which HTML elements we want to style

Let's create a simple demo TypeScript file to see this in action.

First though, let's create a directory (folder) to store our components:

CREATE: src/components

Then,

CREATE: src/components/CSSBasicsDemo.tsx

// Creating the demo component
export function CSSBasicsDemo() {
  return (
    <div className="demo-container"> {/* 1. demo-container class*/}
      <h2>CSS Basics Demo</h2>
      <div className="box-model-demo">
        <h3>Box Model</h3>
        <div className="box-example"> {/* 2. box-example class */}
          <div className="content">Content</div>
        </div>
      </div>
    </div>
  );
}
export default CSSBasicsDemo;

Now, let me add the CSS file. Notice how I'm targeting these elements using class names:

CREATE: src/components/CSSBasicsDemo.css

/* I'm targeting the demo-container class */
.demo-container {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

/* I'm targeting the box-example class */
.box-example {
  width: 200px;
  height: 100px;
  padding: 20px;
  margin: 20px;
  border: 3px solid #3b82f6;
  background-color: #f8fafc;
}

See how this works? I'm using class names - those are the words after 'className=' in the HTML - to target specific elements. This is the most common way to style things in React.

Recall: src/App.tsx is the main file in any React project, because it is where the main application structure is defined, and where each component is referenced.

So, let's update ours with our new components:

import React from 'react';
import { CSSBasicsDemo } from './components/CSSBasicsDemo'; // refernces .tsx demo file
import './components/CSSBasicsDemo.css'; // refernces .css demo file

function App() {
	return <CSSBasicsDemo />;
}

export default App;

Screenshot 2025-10-01 at 12.45.51 AM.png

If you're seeing a page that looks like this, then you've done everything correctly so far!

The Box Model

Note: This is a VERY important section, so be sure to ask any questions if you need to. The Box Model is absolutely crucial to understand.

The Box Model describes that every single element on a webpage is a box.

To show you what I mean, let's use some developer tools (DevTools) made availible to us through Inspect Element.

To access your DevTools, right-click the object you want to examine (in our case, the blue box), and selectInspect Element from the dropdown.

Screenshot 2025-10-01 at 12.35.35 PM.png

You should now see a new window appear. It should look something like this:

Screenshot 2025-10-01 at 12.35.56 PM.png

Let me break down what's happening here:

Each class is made up of properties which describe it in many ways.

In this example:

Let's see what heppns when we make a change to one of these properties...

First, hover over some of the <div>s so you can see exactly how your code is visualized on our webpage. Like this:

Screenshot 2025-10-01 at 12.36.08 PM.png

See how when my mouse is hovered over "box-example" it is highlighted on our webpage? This makes knwoing what our code does visually super clear.

We can see the properties of any element we want in the right panel that looks like this:

Screenshot 2025-10-01 at 12.47.26 PM.png

Hmm... some of those properties in the panel seem very familiar...

Remember how we gave our classes certain properties earlier in src/components/CSSBasicsDemo.css? We can now play around with their values to see their effect visually on our webpage.

Let's do some experimentation.

UPDATE: src/components/CSSBasicsDemo.css

.box-example {
  padding: 40px; /* Changed from 20px */
}

See how the content moved further from the border? That's padding.

Now let us change the margin...

.box-example {
  margin: 40px; /* Changed from 20px */
}

See how the entire box moved away from other elements? That's margin.

This is so important because when you're building layouts, you need to understand how these four things work together.

Most layout problems you'll face when first starting off come from not understanding the box model.

To close off this section, experimentsome more with the box-example properties and see the changes visually in your live server.

.demo-container {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

/* Play around here and see the visual changes */
.box-example {
  width: 200px;
  height: 200px; /* 100 -> 200 */
  padding: 80px; /* 20 -> 40 -> 80 */
  margin: 60px; /* 20 -> 60 */
  border: 3px solid #3b82f6;
  background-color: #f8fafc;
}

Part 2: Building Our Kudos Card Component

Step 1: Planning Our Component

In software development, the first step is always to plan.

Since we already have an idea of what our end product looks like, and we now understand how our app is structured, we can actually do this step without any pre-existing visualization!

But, because we have an end product already, let's look back to it and create a quick list of components we will need to build.

[look at final Kudos example from Week 1]

One clear one that we should consider is the card layout - especially since it is the heart of our app.

Let's think about what this component needs:

This is a great example of a real-world component. It's not too simple, but not too complex either.

Let me create the basic structure first...

Step 2: Structuring the Component

Let's create a new file for our kudos card component.

Note: In React, it's common to have one component per file.

CREATE: src/components/KudosCard.tsx

import React from 'react';

interface KudosCardProps {
  recipient: string;
  message: string;
  giver: string;
  type: 'kudos' | 'feedback';
  date: string;
}

export function KudosCard({ recipient, message, giver, type, date }: KudosCardProps) {
  return (
    <div className="kudos-card">
      <div className="kudos-header">
        <h3 className="recipient-name">{recipient}</h3>
        <span className="kudos-type">{type}</span>
      </div>
      
      <p className="kudos-message">{message}</p>
      
      <div className="kudos-footer">
        <span className="giver-name">From: {giver}</span>
        <span className="kudos-date">{date}</span>
      </div>
    </div>
  );
}

Let me walk through what I'm doing here:

First, I'm defining the TypeScript interface. This tells us exactly what props this component expects. This is really helpful because if someone tries to use this component incorrectly, TypeScript will catch the error.

The component structure is semantic - I'm using meaningful HTML elements. The header contains the recipient name and type, the message is in a paragraph, and the footer has the giver and date.

Notice how I'm using className for all the styling. This is how we connect our HTML to our CSS.

Now let me add the CSS...

Step 3: Applying CSS Styles

I'm creating a separate CSS file for this component. This keeps things organized and makes the component reusable.

CREATE: src/components/KudosCard.css

/* src/components/KudosCard.css */

.kudos-card {

	/* Box Model */
	width: 100%; /* Full width of container */
	max-width: 400px; /* Maximum width */
	padding: 24px; /* Space inside the card */
	margin: 16px 0; /* Space above and below */
	border: 1px solid #e2e8f0; /* Light gray border */
	border-radius: 12px; /* Rounded corners */
	
	/* Layout */
	display: flex; /* Make it a flex container */
	flex-direction: column; /* Stack children vertically */
	gap: 16px; /* Space between children */
	
	/* Colors */
	background-color: #ffffff; /* White background */
	color: #1e293b; /* Dark gray text */
	
	/* Typography */
	font-family: 'Inter', -apple-system, sans-serif; /* Font family */
	font-size: 14px; /* Base font size */
	line-height: 1.5; /* Line spacing */
	
	/* Visual Effects */
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); /* Subtle shadow */	
	transition: all 0.2s ease; /* Smooth transitions */
}

Let me break this down:

I'm using the box model we learned about: padding for internal space, margin for external space, border for the outline.

max-width: 400px means the card won't get wider than 400 pixels, but it can be smaller on mobile devices.

display: flex with flex-direction: column stacks the elements vertically.

gap: 16px puts consistent space between all the child elements.

I know we can really strecth our skills though, so let's keep adding props...

For the hover effect from before:

	/* ...prior code... */

.kudos-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
  border-color: #cbd5e1;
}

This creates a nice interactive effect. When you hover over the card, it should move up slightly and get a stronger shadow.

Now let me style the header...

	/* ...prior code... */

.kudos-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.recipient-name {
  font-size: 18px;
  font-weight: 600;
  color: #0f172a;
  margin: 0;
}

.kudos-type {
  padding: 4px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

The header uses flexbox to put the name on the left and the type badge on the right.

The type badge has rounded corners (border-radius: 20px) and is styled like a pill.

Let me add different colors for different types...

	/* ...prior code... */

.kudos-type.kudos {
  background-color: #dbeafe;
  color: #1e40af;
}

.kudos-type.feedback {
  background-color: #f3f4f6;
  color: #374151;
}

This uses CSS class combination. When an element has both kudos-type and kudos classes, it gets the blue styling. When it has kudos-type and feedback, it gets the gray styling.

Now let me style the message and footer...

	/* ...prior code... */

.kudos-message {
  font-size: 15px;
  line-height: 1.6;
  color: #475569;
  margin: 0;
  flex-grow: 1;
}

.kudos-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 12px;
  border-top: 1px solid #f1f5f9;
  font-size: 12px;
  color: #64748b;
}

The message uses flex-grow: 1 which means it will take up all available space, pushing the footer to the bottom.

All together now...

/* src/components/KudosCard.css */

.kudos-card {

	/* Box Model */
	width: 100%; /* Full width of container */
	max-width: 400px; /* Maximum width */
	padding: 24px; /* Space inside the card */
	margin: 16px 0; /* Space above and below */
	border: 1px solid #e2e8f0; /* Light gray border */
	border-radius: 12px; /* Rounded corners */
	
	/* Layout */
	display: flex; /* Make it a flex container */
	flex-direction: column; /* Stack children vertically */
	gap: 16px; /* Space between children */
	
	/* Colors */
	background-color: #ffffff; /* White background */
	color: #1e293b; /* Dark gray text */
	
	/* Typography */
	font-family: 'Inter', -apple-system, sans-serif; /* Font family */
	font-size: 14px; /* Base font size */
	line-height: 1.5; /* Line spacing */
	
	/* Visual Effects */
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); /* Subtle shadow */	
	transition: all 0.2s ease; /* Smooth transitions */

}

.kudos-card:hover {

	transform: translateY(-2px); /* Move up slightly on hover */	
	box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); /* Stronger shadow on hover */
	border-color: #cbd5e1; /* Lighter border on hover */
}

  
.kudos-header {
	display: flex; /* Make it a flex container */
	justify-content: space-between; /* Space items apart */
	align-items: center; /* Center items vertically */
	margin-bottom: 8px; /* Space below header */
}

.recipient-name {
	font-size: 18px; /* Larger font size */
	font-weight: 600; /* Bold text */
	color: #0f172a; /* Very dark gray */
	margin: 0; /* Remove default margin */
}

.kudos-type {
	padding: 4px 12px; /* Space inside badge */
	border-radius: 20px; /* Pill-shaped */
	font-size: 12px; /* Small font size */
	font-weight: 500; /* Medium bold */
	text-transform: uppercase; /* All caps */
	letter-spacing: 0.5px; /* Space between letters */
}

  
.kudos-type.kudos {
	background-color: #dbeafe; /* Light blue background */
	color: #1e40af; /* Dark blue text */
}

  
.kudos-type.feedback {
	background-color: #f3f4f6; /* Light gray background */
	color: #374151; /* Dark gray text */
}


.kudos-message {
	font-size: 15px; /* Slightly larger font */
	line-height: 1.6; /* Good line spacing */
	color: #475569; /* Medium gray text */
	margin: 0; /* Remove default margin */
	flex-grow: 1; /* Take up available space */
}


.kudos-footer {
	display: flex; /* Make it a flex container */
	justify-content: space-between; /* Space items apart */
	align-items: center; /* Center items vertically */
	padding-top: 12px; /* Space above footer */
	border-top: 1px solid #f1f5f9; /* Light border on top */
	font-size: 12px; /* Small font size */
	color: #64748b; /* Light gray text */
}

.giver-name {
	font-weight: 500; /* Medium bold */
}


.kudos-date {
	color: #94a3b8; /* Very light gray */
}

Finally, let's create a demo page to show this in action...

Step 4: Creating the Demo Page

We need to update the App component to show our kudos cards...

// src/App.tsx
import React from 'react';
import { KudosCard } from './components/KudosCard';
import './components/KudosCard.css';

function App() {
  const sampleKudos = [
    {
      recipient: "Jane Smith",
      message: "Amazing work on the authentication refactor! Your clean code and thorough testing saved us so much time.",
      giver: "John Doe",
      type: "kudos" as const,
      date: "Mar 22, 2024"
    },
    {
      recipient: "Mike Johnson", 
      message: "Thanks for staying late to help debug the payment integration. Your persistence really paid off!",
      giver: "Sarah Wilson",
      type: "kudos" as const,
      date: "Mar 21, 2024"
    },
    {
      recipient: "Alex Chen",
      message: "Great job presenting the technical architecture to stakeholders. You explained everything so clearly!",
      giver: "Emily Davis", 
      type: "feedback" as const,
      date: "Mar 20, 2024"
    }
  ];

  return (
    <div className="app-container">
      <div className="app-content">
        <h1 className="app-title">
          - Kudos Cards Demo -
        </h1>
        
        <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>
  );
}

export default App;

Let me add some CSS for the app layout...

/* Add to App.css or create App.css */
.app-container {
  min-height: 100vh;
  background-color: #f8fafc;
  padding: 32px 0;
}

.app-content {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 16px;
}

.app-title {
  font-size: 48px;
  font-weight: 700;
  text-align: center;
  color: #0f172a;
  margin-bottom: 32px;
}

.cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
  gap: 24px;
}

@media (max-width: 768px) {
  .cards-grid {
    grid-template-columns: 1fr;
  }
}

Look at that! We have working kudos cards!!!

Notice how they respond to hover, how the different types have different colors, how the layout is clean and structured!

Week 4

Welcome!

Goals

Quick Recap

Last week we learned:

A Quick Note...

The nest few sessions (weeks) will be dedicated to implementing KudosForm and the respective cards that are created after a submission is made.

This will take some time, so I decided to split it up into a few parts (3, to be exact). Part 1 covers the TypeScript aspect (this doc), part 2 dives into CSS by having you complete a challenge (week 5), and part 3 is about implementing state, also through a challenge (week 6). Before moving ahead and reading this doc, make sure you've read week 3 as you'll need it for the challenges that lie ahead... 🤫

Good luck!

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:

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:


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:


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:


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:


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:


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:


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:

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:


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:


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:


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:

Try clicking around:

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

Week 5

Goals

Your Objective

Your goal is to style the KudosForm.tsx component by adding CSS rules to the KudosForm.css file. We've already set up all the className attributes you'll need in the component.

Your job is to target those classes and bring the app to life!

Try to create a design that is:

Task Outline

Here's a breakdown of the elements to style:

  1. The Main Container (.kudos-form)

    • Make the form stand out from the background. It should look like a distinct "card." How can you give it some depth and defined edges?
  2. The Title (.form-title)

    • The title "Give Kudos" should be a clear and prominent header for the form. How can you make it the focal point?
  3. Field Groups (.form-group)

    • Currently, all the labels and inputs are squished together. Add some vertical spacing between each field group to let the form breathe.
  4. Field Labels (.form-group label)

    • Style the labels (To:, Message:, etc.) so they are clear and distinct from the input fields they describe. They should sit neatly above their respective inputs.
  5. Inputs, Textareas, & Selects

    • Target .form-group input, .form-group textarea, and .form-group select all at once.
    • Give them a consistent look. They should have clean borders, nice internal padding, and stretch to the full width of the form.
  6. The Focus State (:focus)

    • This is a key part of user experience! When a user clicks into an input field, it should be visually obvious which one is active. How can you change the border or add a glow effect?
  7. The Submit Button (.submit-button)

    • Make it look like the primary action on the form. Think about its color, font size, and shape.

Some Hints...

Here are a few CSS properties that might help you out:

If you do get stuck, feel free to refer back to last week's session where we discussed CSS styling!

Here is an example of what your cards could look like (ignore dark mode):

Screenshot 2025-10-22 at 2.58.36 PM.png

Uhhh... what now?

Great job building the static components for our Kudos Board! You have a beautiful <KudosForm /> that you can type in and a stylish <KudosCard /> component ready to display data.

There's just one problem... they don't talk to each other. 😅

Next week, we will tie evrything together and get this component working with state! Get hype!

Week 6 + 7

Welcome!

Goals

A Quick Recap...

Last week was awesome!!! Evevryone stepped up and took a leap of faith by styling a component all on your own... Kudos (😏) to you!

Big shoutout to Palak for catching the W last week!

Understanding React State

A recurring question that has been asked for the last few weeks (and rightfully so) is how the form submission works. In other words, if someone is actually using the app on the web, how is their response to the form reflected in our project.

Currently, as you may have noticed in your code, we are hardcoding cards, which obviously isn't how an actual app works.

We want our app to be able to recieve user inputs (kudos) in real-time and update our card layout accordingly.

And you guessed it, this is state!

What is State?

Remember our house analogy?

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

A shopping cart - It has a list of items

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

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

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:

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

Your Objective

Last week, you successfully built the static UI for our Kudos Board!

There's just one problem... they don't talk to each other. 😅

These components aren't connected yet; they don't share any data.

When you fill out the form and hit "Send Kudos," nothing happens. The form data just disappears, and no new card appears.

Your goal this week is to fix this. You need to use React's useState hook to capture the form submissions and display them as new cards.

Task Outline

Make the app fully functional. When a user fills out the KudosForm and clicks "Send Kudos," a new KudosCard should appear in the cards-grid.

To solve this, you will need to:

  1. Find the Right Home for State: Where does the list of all kudos need to live so that both the form (to add kudos) and the card display (to read kudos) can access it?
  2. Initialize the State: In the correct component (if you cant figure which, let us know), use the useState hook to create a state variable that holds an array of Kudos objects. You can start it with an empty array [] or use the example kudos from the lesson plan.
  3. Create an "Add" Function: In the same component where you created your state, write a function (like handleAddKudos) that takes a new Kudos object as an argument and updates the state by adding this new object to the array.
  4. Pass the Function: Pass your new "add" function down to the <KudosForm /> as a prop (e.g., onSubmit).
  5. Render the List: Use your state array to render the list of cards. Instead of hard-coding a <KudosCard />, you'll need to map over your state array and return a <KudosCard /> for each item.

Bonus (If ur trying to flex)

Once it's working, try implementing a "Empty State" message. Your app should show a friendly message like "No kudos yet. Be the first!" only when the kudosList array is empty.

Resources Some Hints...

This is a great resource to get you started. There is a also a really good example implementation: Managing State

As always, Derrick and I are here for you!!! Just ask if you get stuck.

Week 8

Goals

Here are the goals for this week:

Recap and a Quick Note...

I know a lot of people couldn't finish implementing state during last week's session, and that is ok! The concept of state is non-trivial and much harder to implement on your own than tasks from prior weeks.

Which brings me to my note...

If you have free time, go watch a YouTube video and go back in to try again! Even better, read the documentation!

I hate to admit it, but reading documentation is something I only really started doing a few months ago, and I realize now that it is extremely useful and a high ROI for your skills as a programmer/student/human imo.

Try it out!

Now for the objective...

Your Objective

Right now, our Kudos Board is just a form and some cards on a blank page. "Real" apps have navigation, a persistent header, and a consistent layout. When you click a menu button on a mobile site, you naturally expect a sidebar to behave and feel a certain way.

Your goal this week is to build a component of that static app layout. You'll create a static <Sidebar /> (side menu) using TypeScript, and style it using CSS.

Motivation

You might be thinking, "Why are we making an individual Sidebar.tsx file? Couldn't I just dump all the HTML into App.tsx?"

Welllll yes, you couldddd, BUT you'd be setting yourself up for a massive headache later.

This idea of breaking your UI into small, self-contained pieces is one of the most important concepts in React (and web dev).

Here's some reasons why:

By building a clean component today, you're building a something that you can trust, understand, and reuse anywhere, which is key to building large, complex projects.

Task Outline

Implement a responsive navigation layout. This will involve creating a <Sidebar /> component.

Your Checklist

To get this done, you'll need to:

  1. Create a new component file Sidebar.tsx (and a CSS file, Sidebar.css).
  2. Build the <Sidebar />.
    • It should be a vertical bar positioned on the left side of the screen.
    • Add a few placeholder links inside like "Home," "Give Kudos," and "Profile." (don't worry about them not going anywhere yet!)
  3. Now, go into your .css files and make it look good! In Sidebar.css, style the .sidebar class to be a vertical bar that's always visible on the left.
  4. In your main App.tsx, implement your component.

Some Hints...

Remember prior weeks! Our past sessions have covered the skills you need to do this, so feel free to reference them

Here's some icons for your sidebar. Simply copy this code and paste (define) at the top of your Sidebar.tsx file:

import './sidebar.css';

// --- Helper Icon Components (Replaces lucide-react) ---
// We define simple SVGs here to keep the file self-contained.

// Icon for "Home"
const HomeIcon = ({ className }: { className: string }) => (
  <svg
    className={className}
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
  >
    <path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
    <polyline points="9 22 9 12 15 12 15 22" />
  </svg>
);

// Icon for "Give Kudos" (using a simple "gift" icon)
const KudosIcon = ({ className }: { className: string }) => (
  <svg
    className={className}
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
  >
    <polyline points="20 12 20 22 4 22 4 12" />
    <rect x="2" y="7" width="20" height="5" />
    <line x1="12" y1="22" x2="12" y2="7" />
    <path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z" />
    <path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z" />
  </svg>
);

// Icon for "Profile" or "User"
const UserIcon = ({ className }: { className: string }) => (
  <svg
    className={className}
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
  >
    <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
    <circle cx="12" cy="7" r="4" />
  </svg>
);

I'm done... what's next!?

Nice! You've got a clean and modern sidebar!

Next week, we'll look into how to make those sidebar links actually go to different pages by introducing React Router!

End of Semester Challenge! (Week 9)

Goals

Here are this week's goals:

Your Objective

Get ready for the ultimate challenge... building Kudos from scratch! 🙀

For the final session of this semester, lets leverage all of the skills and practices we've obtained from prior weeks to build Kudos as if we came up with it on our own.

In other words, your goal is to setup, build, and run a React app (namely, Kudos) all on your own!

Your Checklist

To get this done, you'll need to recall each prior week to some extent.

Let's walk through some high-level steps that you might take to do this:

  1. Create a react app. Not much to add here, but if you run into any errors, just remember that the command you enter in the terminal must follow a specific syntax.
  2. Open your project. After creating the app, you should open it in VSCode. If you remember how to do this from your terminal, awesome! If you don't, no worries, just do it via the VSCode window.
  3. Start a development server. In the VSCode project terminal (you can open it from the navbar), run the command to start your localhost.
  4. Create a folder to store your components and create the necessary component files. Create and move the files you'll need to build the form and cards in your components folder. You can decide what to name them, but remember to keep the naming consistent.
  5. Write the code! Remember to check past weeks if you need guidance. Also, remember to save your changes frequently with Ctrl + S / Cmd + S

Closing Remarks and an Exit Ticket

Thank you all for an amazing semester!!!!!

I had a great time learning and coding with everyone, and am even more hype for when we return in the Spring.

My last ask is that you complete this form: EOS Feedback

I designed it for a few reasons:

  1. To get your feedback on the sessions.
  2. To see where you feel like are now vs. where you were in August when we started.
  3. Lastly, and most importantly, to get your input on what we should do next semester!

Blueprint is still super young and this is our first time running Tech Team this way, so your thoughts and opinions will directly shape how we run it for semesters to come.

On that note, please be brutally honest and open about what you liked and didn't like, it will help us out massively.

I appreciate you all and thanks again for a great semester!