Module 4: Build Sprint 3

Understanding Your Third Ticket

Learn how to approach your third ticket in the Labs project and understand the development workflow.

Third Ticket Details

View your third ticket details and requirements on GitHub:

Third Ticket Documentation

Step-by-Step Workflow

  1. Familiarize Yourself with the Repository

    1. Read the documentation thoroughly to understand the repository. This may include API contracts, READMEs, or docs on Google/Notion.
    2. Check the README of the ticket you have been assigned to know what is expected of you.
  2. Understanding the Deliverable

    1. Check the deployed version of the product to see the expected output and match it with what you have to build.
    2. Read the example of the expected output provided in the README.
  3. Code Unit Test (if applicable)

    1. If a relevant test exists, follow the test-driven development approach to guide your development.
    2. Validate your code using the unit test to ensure you've produced the expected outcome.
  4. Code the Component/Feature

    1. Code your deliverable, the feature described in the ticket.
  5. Record a Loom Video

    1. Demonstrate the feature in the video.
    2. Provide a detailed explanation of your thought process while coding.

Submit your Sprint 3 Deliverables: Loom and Code

Technical Interview Simulation

You're in the middle of your first technical interview. The interviewer is going through your resume and stops at the section describing your Labs project. They turn to you and ask:

"How would you describe the project you built in BloomTech Labs and the contributions you had on it?"

Using Loom, record a video articulating to a hiring manager the product you'll be working on in Labs. Feel free to reference your code and ticket.

You should concisely answer the following questions:

  • What were the deliverables for your ticket?
  • What requirements did you have to keep in mind? Think tech stack, constraints, etc.
  • How did you go about shipping your ticket?
  • Why did you take the approach you took?

The video should be no longer than 5 minutes, and you must demo the project in the video.

Submission Details

Submit the links to your Loom video and code on GitHub using the form below.

You can access the submission form here.

Note: If any one link is missing, the assignment will not be graded and you will have to resubmit.

Your code should:

  • be on a forked version of the project repo.
  • meet all the requirements listed on the ticket in the README file for this build sprint.

In your Loom video, you must:

  • demo the code you created for this ticket.
  • articulate how you coded this ticket and why you took that approach.
  • showcase your workflow and what steps you took to code this ticket.

All submissions will be graded based on criteria set forth in the rubric below.

Never used Loom before?

How to get started with Loom

How to use the Loom Chrome Extension

Build Sprint Grading Criteria

Criteria Ratings
This criterion is linked to a Learning OutcomePresenting Their Work
The student clearly and accurately explains all aspects of their work, including their approach, design decisions, and results.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeOrganization
The video is well-organized, easy to follow, and presents information in a logical and coherent manner.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeTechnical Knowledge
The student demonstrates a solid understanding of the technical concepts and tools used in their work. They are able to answer technical questions.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeCode Quality
The code is well-organized and readable, follows the best practices that they learned, and the code is readable
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeFunctionality
The code runs without errors and produces the expected results. The code is complete and meets the requirements of the assignment.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeCommenting
Comments are clear and provide enough information to understand the purpose and function of the code.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeCorrectness
The code is implemented in a correct, efficient and optimal way.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeTest Execution
The student is able to execute tests and document issues or bugs found. They are able to explain how the tests are verifying the functionality of the system.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeCommunication & Delivery
The student communicates effectively and professionally, speaking clearly, using appropriate nonverbal communication, and expressing themselves in a confident and engaging manner. They show active listening skills and can build rapport.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomePreparation & Self-Presentation
The student presents themselves in a professional and polished manner and is well-prepared. They project confidence and enthusiasm.
Meets Expectations Needs Improvement
This criterion is linked to a Learning OutcomeAdaptability
The student demonstrates an ability to adapt to new information and respond appropriately to unexpected questions or changes in the interview. They display flexibility and some initiative.
Meets Expectations Needs Improvement

Approaching Your Third Feature

Learn how to implement a React client application that integrates with your backend API.

Implementation Checklist

  • Review and select 3 pages from the provided wireframes
  • Set up React project structure and routing
  • Implement authentication flow with JWT
  • Create reusable components for common UI elements
  • Integrate with backend API endpoints
  • Implement responsive design
  • Add error handling and loading states

React Project Structure

// Example project structure
src/
├── components/
│   ├── common/
│   │   ├── Button.jsx
│   │   ├── Card.jsx
│   │   └── Navbar.jsx
│   ├── auth/
│   │   ├── LoginForm.jsx
│   │   └── ProtectedRoute.jsx
│   └── pages/
│       ├── Home.jsx
│       ├── Dashboard.jsx
│       └── AssignmentView.jsx
├── services/
│   ├── api.js
│   └── auth.js
├── context/
│   └── AuthContext.jsx
└── utils/
    └── helpers.js

Authentication Context Example

// Example of authentication context setup
import { createContext, useContext, useState, useEffect } from 'react';
import api from '../services/api';

const AuthContext = createContext();

export function AuthProvider({ children }) {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);

    const login = async (credentials) => {
        try {
            const response = await api.post('/api/auth/login', credentials);
            const { token } = response.data;
            localStorage.setItem('token', token);
            
            // Decode token and set user
            const decodedUser = decodeToken(token);
            setUser(decodedUser);
            return { success: true };
        } catch (error) {
            return { 
                success: false, 
                message: error.response?.data?.message || 'Login failed' 
            };
        }
    };

    const logout = () => {
        localStorage.removeItem('token');
        setUser(null);
    };

    // Check if user is authenticated on initial load
    useEffect(() => {
        const checkAuth = async () => {
            const token = localStorage.getItem('token');
            if (token) {
                try {
                    // Verify token is still valid
                    const response = await api.get('/api/auth/me');
                    setUser(response.data);
                } catch (error) {
                    localStorage.removeItem('token');
                }
            }
            setLoading(false);
        };
        
        checkAuth();
    }, []);

    const value = {
        user,
        loading,
        login,
        logout,
        isAuthenticated: !!user
    };

    return (
        <AuthContext.Provider value={value}>
            {children}
        </AuthContext.Provider>
    );
}

export function useAuth() {
    return useContext(AuthContext);
}

API Integration

Learn how to integrate your React frontend with your Spring Boot backend API.

API Service Example

// Example of API service setup
import axios from 'axios';

const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8080/api';

const api = axios.create({
    baseURL: API_URL,
    headers: {
        'Content-Type': 'application/json'
    }
});

// Add request interceptor to include auth token
api.interceptors.request.use(
    (config) => {
        const token = localStorage.getItem('token');
        if (token) {
            config.headers['Authorization'] = `Bearer ${token}`;
        }
        return config;
    },
    (error) => Promise.reject(error)
);

// Add response interceptor to handle common errors
api.interceptors.response.use(
    (response) => response,
    (error) => {
        if (error.response && error.response.status === 401) {
            // Unauthorized - token expired or invalid
            localStorage.removeItem('token');
            window.location.href = '/login';
        }
        return Promise.reject(error);
    }
);

export default api;

React Component Example

// Example of a component that fetches and displays data
import { useState, useEffect } from 'react';
import api from '../services/api';
import { useAuth } from '../context/AuthContext';

function Dashboard() {
    const [assignments, setAssignments] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const { user } = useAuth();

    useEffect(() => {
        const fetchAssignments = async () => {
            try {
                const response = await api.get('/assignments');
                setAssignments(response.data);
                setLoading(false);
            } catch (err) {
                setError('Failed to load assignments');
                setLoading(false);
            }
        };

        fetchAssignments();
    }, []);

    if (loading) return <div>Loading assignments...</div>;
    if (error) return <div>{error}</div>;

    return (
        <div className="dashboard">
            <h1>Welcome, {user.name}!</h1>
            <h2>Your Assignments</h2>
            
            <div className="assignment-list">
                {assignments.length === 0 ? (
                    <p>No assignments found.</p>
                ) : (
                    assignments.map(assignment => (
                        <div key={assignment.id} className="assignment-card">
                            <h3>{assignment.title}</h3>
                            <p>{assignment.description}</p>
                            <span className="status">{assignment.status}</span>
                            <button onClick={() => navigate(`/assignments/${assignment.id}`)}>
                                View Details
                            </button>
                        </div>
                    ))
                )}
            </div>
        </div>
    );
}