Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 75 additions & 135 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,135 +1,75 @@
# Lab: Task Manager

## Overview
In this lab, we’ll build a Task Manager application that allows users to add, complete, and search tasks. Utilizing the hooks of `useRef` to persist values without re-rendering, `useId` to generate unique IDs for accessibility and controlled components, and `useContext` for global state management.

## Task 1: Define the Problem
The frontend is set up, but the application lacks interactivity and state management.

As a user, I should be able to:
- Add a new task using a form (`useId`)
- Mark tasks as completed (`useContext`)
- Search tasks dynamically (`useRef`)

## Task 2: Determine the Design
Determine state and props needed for each component:
- Global states (`useContext`)
- Persistent Values (`useRef`)
- Unique IDs (`useId`)

## Task 3: Develop the Code
### Implement Global State with `useContext`
- Create `TaskProvider` as global state within `TaskContext.jsx`
- Replace tasks state in app with context

### Mark Task
- Implement `toggleComplete` function within `TaskContext.jsx`
- Call `toggleComplete` upon clicking task button

### Submit Tasks
- Apply `useId` on form input
- Implement `addTask` function within `TaskContext.jsx`
- Call `addTask` within submit

### Implement Search Functionality
- Implement `useRef` on search input
- Implement filter on task context

## Task 4: Test and Refine
Debug and test during development using the provided test suite and React DevTools in Chrome.

## Task 5: Document and Maintain
- Commit as you go, writing meaningful commit messages
- Push commit history to GitHub periodically and when lab is complete

## Tools and Resources
- GitHub Repo:
- `useRef`: [React useRef](https://react.dev/reference/react/useRef)
- `useContext`: [React useContext](https://react.dev/reference/react/useContext)
- `useId`: [React useId](https://react.dev/reference/react/useId)

## Instructions
### Set Up
Before we begin coding, let's complete the initial setup for this lesson:

#### Fork and Clone
- Go to the provided GitHub repository link.
- Fork the repository to your GitHub account.
- Clone the forked repository to your local machine.

#### Open and Run File
- Open the project in VSCode.
- Run `npm install` to install all necessary dependencies.

## Instructions
### Task 1: Define the Problem
The frontend is set up, but the application lacks interactivity and state management.

As a user, I should be able to:
- Add a new task using a form (`useId`)
- Mark tasks as completed (`useContext`)
- Search tasks dynamically (`useRef`)

### Task 2: Determine the Design
Determine state and props needed for each component.

### Task 3: Develop, Test, and Refine the Code
#### Open React application in browser
```sh
npm run dev
```

#### Run the included backend
```sh
npm run server
```

#### Run test suite
```sh
npm run test
```

### Create feature branch
#### Implement Global State with `useContext`
- Create `TaskProvider` as global state within `TaskContext.jsx`
- Replace tasks state in app with context
- Update `App` within `main.jsx` to be wrapped in `TaskProvider`

#### Mark Task
- Implement `toggleComplete` function within `TaskContext.jsx`
- Ensure `toggleComplete` function edits both the `db.json` and page
- Call `toggleComplete` upon clicking task button

#### Submit Tasks
- Apply `useId` on form input
- Implement `addTask` function within `TaskContext.jsx`
- Call `addTask` within submit

#### Implement Search Functionality
- Implement `useRef` on search input
- Implement filter task context on `TaskList`

### Push feature branch and open a PR on GitHub
- Merge to main

## Task 4: Document and Maintain
### Best Practice documentation steps:
- Add comments to code to explain purpose and logic
- Clarify intent/functionality of code to other developers
- Add screenshot of completed work included in Markdown in `README.md`
- Update `README.md` text to reflect the functionality of the application following [Make a README](https://makeareadme.com)
- Delete any stale branches on GitHub
- Remove unnecessary/commented-out code
- If needed, update `.gitignore` to remove sensitive data

## Submission
Once all tests are passing and working code is pushed to the GitHub main branch, submit your GitHub repo through Canvas using CodeGrade.

## Grading Criteria
The application passes all test suites.

Ensure the application:
- Loads tasks with context.
- Submits new task with `useId`
- Marks tasks as complete.
- Filters tasks shown on the page by a search input.
# 📝 Task Manager App

A React Task Manager that demonstrates global state management using Context API and React Hooks.

---

## 🚀 Features

- Add tasks using `useId`
- Mark tasks as completed using `useContext`
- Search tasks dynamically using `useRef`
- Global state management via Context API
- Backend integration with JSON Server

---

## 📸 Application Screenshot

### 👉 Your final UI output goes here:

![Task Manager App Screenshot](./react-hooks-task-manager-lab.png)

> If the image does not appear, ensure it is saved in: `./react-hooks-task-manager-lab.png`

---

## 🧠 Tech Stack

- React
- Context API
- useState / useEffect
- useRef
- useId
- JSON Server

---

## 📦 Setup Instructions

```bash id="setup1"
npm install


































4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added react-hooks-task-manager-lab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 35 additions & 12 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
import React, { useEffect, useContext, useState } from "react";
import { TaskContext } from "../context/TaskContext";
import TaskForm from "./TaskForm";
import SearchBar from "./SearchBar";
// import React, { useEffect, useContext, useState } from "react";
// import { TaskContext } from "../context/TaskContext";
// import TaskForm from "./TaskForm";
// import SearchBar from "./SearchBar";

function App() {
const [tasks, setTasks] = useState([]);
// function App() {
// const [tasks, setTasks] = useState([]);

useEffect(() => {
fetch('http://localhost:6001/tasks')
.then(r=>r.json())
.then(data=>setTasks(data))
// useEffect(() => {
// fetch('http://localhost:6001/tasks')
// .then(r=>r.json())
// .then(data=>setTasks(data))

}, []);
// }, []);

// return (
// <div>
// <h1>Task Manager</h1>
// <TaskForm />
// <SearchBar />
// </div>
// );
// }

// export default App;








import React from "react";
import TaskForm from "./TaskForm";
import SearchBar from "./SearchBar";

function App() {
return (
<div>
<h1>Task Manager</h1>
Expand All @@ -22,4 +45,4 @@ function App() {
);
}

export default App;
export default App;
19 changes: 15 additions & 4 deletions src/components/SearchBar.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
import React, { useRef, useState, useContext } from "react";






import React, { useRef, useState, useEffect } from "react";
import TaskList from "./TaskList";
import { TaskContext } from "../context/TaskContext";

function SearchBar() {
const [query, setQuery] = useState("");
const inputRef = useRef();

function handleSearch(e) {
setQuery(e.target.value);
}


useEffect(() => {
inputRef.current?.focus();
}, []);

return (
<div>
<input
ref={inputRef}
type="text"
placeholder="Search tasks..."
value={query}
onChange={handleSearch}
/>
<TaskList query={query}/>
<TaskList query={query} />
</div>
);
}

export default SearchBar;
export default SearchBar;
56 changes: 56 additions & 0 deletions src/components/TaskContext.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { createContext, useState, useEffect } from "react";

export const TaskContext = createContext();

export function TaskProvider({ children }) {
const [tasks, setTasks] = useState([]);


useEffect(() => {
fetch("http://localhost:6001/tasks")
.then(res => res.json())
.then(data => setTasks(data));
}, []);


function addTask(title) {
const newTask = {
id: Date.now(),
title,
completed: false,
};

setTasks(prev => [...prev, newTask]);

fetch("http://localhost:6001/tasks", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(newTask),
});
}


function toggleComplete(id) {
const updated = tasks.map(task =>
task.id === id
? { ...task, completed: !task.completed }
: task
);

setTasks(updated);

const task = updated.find(t => t.id === id);

fetch(`http://localhost:6001/tasks/${id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ completed: task.completed }),
});
}

return (
<TaskContext.Provider value={{ tasks, addTask, toggleComplete }}>
{children}
</TaskContext.Provider>
);
}
Loading