Update README.md

parent a80c60ec
...@@ -57,10 +57,10 @@ my-product-management-system/ ...@@ -57,10 +57,10 @@ my-product-management-system/
├── src/ ├── src/
│ ├── components/ │ ├── components/
│ │ ├── Category/ │ │ ├── Category/
│ │ │ ├── CategoryListClass.js
│ │ │ ├── CategoryFormClass.js │ │ │ ├── CategoryFormClass.js
│ │ │ ├── CategoryListFunction.js │ │ │ ├── CategoryListClass.js
│ │ │ ├── CategoryFormFunction.js │ │ │ ├── CategoryFormFunction.js
│ │ │ ├── CategoryListFunction.js
│ │ │ ├── Category.css │ │ │ ├── Category.css
│ │ ├── Product/ │ │ ├── Product/
│ │ │ ├── ProductListClass.js │ │ │ ├── ProductListClass.js
...@@ -78,21 +78,133 @@ my-product-management-system/ ...@@ -78,21 +78,133 @@ my-product-management-system/
└── ... └── ...
``` ```
### 4. Creating Class Components (30 minutes) ### 5. Creating Class Components (30 minutes)
- Deep dive into creating class components. - Deep dive into creating class components.
- Create `CategoryFormClass.js` and `CategoryListClass.js` as class components. - Create `CategoryFormClass.js` and `CategoryListClass.js` as class components.
- Discuss state management, event handling, and lifecycle methods. - Discuss state management, event handling, and lifecycle methods.
CategoryFormClass.js
```jsx CategoryFormClass.js
##### I: Importing Dependencies
Start by importing React and any necessary services:
```
import React, { Component } from 'react'; import React, { Component } from 'react';
import { createCategory } from '../../services/ApiCategory'; ```
#### II: Defining the Class Component
```
class CategoryFormClass extends Component { class CategoryFormClass extends Component {
state = { state = {
name: '', name: '',
description: '' description: ''
}; };
render() {
return (
"test"
);
}
}
```
#### III: Exporting the Component
```
export default CategoryFormClass;
```
#### IV: Handling Input Changes & Submit Function
```
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
handleSubmit = (event) => {
event.preventDefault();
const { name, description } = this.state;
console.log(this.state);
alert(`Category Name: ${name}\nCategory Description: ${description}`);
this.setState({ name: "", description: "" });
// Call the addCategory method passed down from CategoryListClass
// this.props.addCategory({ name, description });
// API integration will be handled in the next chapter
// await createCategory({ name, description });
// this.props.fetchCategories();
};
```
```
// handleSubmit = (event) => {
// event.preventDefault();
// const { name, description } = this.state;
// console.log(this.state);
// alert(`Category Name: ${name}\nCategory Description: ${description}`);
// this.setState({ name: "", description: "" });
// // Call the addCategory method passed down from CategoryListClass
// this.props.addCategory({ name, description });
// // Call the createCategory function, which uses axios to create a new category
// createCategory({ name, description })
// .then(response => {
// console.log("Category created successfully:", response.data);
// // Optionally, you could call fetchCategories here if you want to refresh the category list
// // this.props.fetchCategories();
// })
// .catch(error => {
// console.error("There was an error creating the category:", error);
// });
// };
```
#### V: Rendering the Form
```
render() {
const { name, description } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
name="name"
value={name}
onChange={this.handleChange}
placeholder="Category Name"
/>
<input
type="text"
name="description"
value={description}
onChange={this.handleChange}
placeholder="Category Description"
/>
<button type="submit">Add Category</button>
</form>
);
}
```
<details>
<summary>full code</summary>
```jsx
import React, { Component } from 'react';
import { createCategory } from '../../services/ApiCategory';
class CategoryFormClass extends Component {
state = {
name: '',
description: ''
};
handleChange = (event) => { handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value }); this.setState({ [event.target.name]: event.target.value });
...@@ -107,7 +219,7 @@ class CategoryFormClass extends Component { ...@@ -107,7 +219,7 @@ class CategoryFormClass extends Component {
}; };
render() { render() {
const { name, description } = this.state const { name, description } = this.state;
return ( return (
<form onSubmit={this.handleSubmit}> <form onSubmit={this.handleSubmit}>
...@@ -129,65 +241,126 @@ class CategoryFormClass extends Component { ...@@ -129,65 +241,126 @@ class CategoryFormClass extends Component {
</form> </form>
); );
} }
} }
export default CategoryFormClass; export default CategoryFormClass;
``` ```
</details>
CategoryListClass.js CategoryListClass.js
```jsx
#### I: Importing Dependencies
Start by importing React and any necessary services:
```
import React, { Component } from 'react'; import React, { Component } from 'react';
import CategoryFormClass from './CategoryFormClass';
import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
import './Category.css'; import './Category.css';
import CategoryFormClass from './CategoryFormClass';
// import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
```
#### II: Defining the Class Component and Initial State
```
class CategoryListClass extends Component { class CategoryListClass extends Component {
state = { state = {
categories: [], categories: [
// Hardcoded categories for initial testing
{ id: 1, name: "Electronics", description: "Devices and gadgets" },
{ id: 2, name: "Books", description: "Various books and literature" },
],
isEditing: false, isEditing: false,
currentCategory: { id: '', name: '', description: '' }, currentCategory: { id: "", name: "", description: "" },
}; };
componentDidMount() { render() {
this.fetchCategories(); return "test";
} }
}
```
fetchCategories = async () => { #### III: Lifecycle Method and Fetch Categories
const categories = await getCategories();
this.setState({ categories });
};
handleDelete = async (id) => {
await deleteCategory(id);
this.fetchCategories();
};
handleEdit = (category) => { ```
componentDidMount() {
// this.fetchCategories();
}
fetchCategories = async () => {
// const categories = await getCategories();
// this.setState({ categories });
};
```
#### IV: Handling Delete, Edit, and Cancel Edit
```
handleDelete = (id) => {
const filteredCategories = this.state.categories.filter(category => category.id !== id);
this.setState({ categories: filteredCategories });
console.log(id);
alert(`Deleted Id: ${id}`);
// await deleteCategory(id);
// this.fetchCategories();
};
handleEdit = (category) => {
this.setState({ isEditing: true, currentCategory: category }); this.setState({ isEditing: true, currentCategory: category });
}; };
handleCancelEdit = () => { handleCancelEdit = () => {
this.setState({ isEditing: false, currentCategory: { id: '', name: '', description: '' } }); this.setState({ isEditing: false, currentCategory: { id: '', name: '', description: '' } });
}; };
handleChange = (event) => { ```
#### V: Handling Input Changes and Update and Add using props
```
handleChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
this.setState((prevState) => ({ this.setState((prevState) => ({
currentCategory: { ...prevState.currentCategory, [name]: value } currentCategory: { ...prevState.currentCategory, [name]: value }
})); }));
}; };
handleUpdate = async (event) => { handleUpdate = (event) => {
event.preventDefault(); event.preventDefault();
const { currentCategory } = this.state;
await updateCategory(currentCategory.id, { name: currentCategory.name, description: currentCategory.description });
this.setState({ isEditing: false, currentCategory: { id: '', name: '', description: '' } });
this.fetchCategories();
};
render() { const { categories, currentCategory } = this.state;
const updatedCategories = categories.map((category) =>
category.id === currentCategory.id ? { ...currentCategory } : category
);
this.setState({
categories: updatedCategories,
isEditing: false,
currentCategory: { id: "", name: "", description: "" },
});
alert(`Category Name: ${currentCategory.name}\nCategory Description: ${currentCategory.description}`);
console.log(this.state);
// await updateCategory(currentCategory.id, { name: currentCategory.name, description: currentCategory.description });
// this.fetchCategories();
};
addCategory = (newCategory) => {
this.setState((prevState) => ({
categories: [...prevState.categories, { id: prevState.categories.length + 1, ...newCategory }],
}));
};
```
#### VI: Rendering the Component
```
render() {
const { categories, isEditing, currentCategory } = this.state; const { categories, isEditing, currentCategory } = this.state;
return ( return (
<div> <div>
...@@ -212,8 +385,10 @@ class CategoryListClass extends Component { ...@@ -212,8 +385,10 @@ class CategoryListClass extends Component {
<button type="button" className="button button-delete" onClick={this.handleCancelEdit}>Cancel</button> <button type="button" className="button button-delete" onClick={this.handleCancelEdit}>Cancel</button>
</form> </form>
) : ( ) : (
<CategoryFormClass fetchCategories={this.fetchCategories} /> <CategoryFormClass addCategory={this.addCategory} />
// <CategoryFormClass fetchCategories={this.fetchCategories} />
)} )}
<div style={{ display: "inline-block", textAlign: "left", marginTop: "20px"}}>
<table> <table>
<thead> <thead>
<tr> <tr>
...@@ -238,150 +413,105 @@ class CategoryListClass extends Component { ...@@ -238,150 +413,105 @@ class CategoryListClass extends Component {
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
); );
}
} }
export default CategoryListClass;
``` ```
### 5. Creating Functional Components (30 minutes)
- Deep dive into creating functional components with hooks.
- Create `CategoryFormFunction.js` and `CategoryListFunction.js` as functional components.
- Discuss useState and useEffect hooks.
CategoryFormFunction.js
```jsx
import React, { useState } from 'react';
import { createCategory } from '../../services/ApiCategory';
const CategoryFormFunction = ({ fetchCategories }) => {
const [categoryName, setCategoryName] = useState('');
const [description, setDescription] = useState('');
const handleChange = (event) => {
const { name, value } = event.target;
if (name === 'name') setCategoryName(value);
if (name === 'description') setDescription(value);
};
const handleSubmit = async (event) => { #### VI: Exporting the Component
event.preventDefault();
await createCategory({ name: categoryName, description });
setCategoryName('');
setDescription('');
fetchCategories();
};
return ( ```
<form onSubmit={handleSubmit}> export default CategoryListClass;
<input
type="text"
name="name"
value={categoryName}
onChange={handleChange}
placeholder="Category Name"
/>
<input
type="text"
name="description"
value={description}
onChange={handleChange}
placeholder="Category Description"
/>
<button type="submit">Add Category</button>
</form>
);
};
export default CategoryFormFunction;
``` ```
CategoryListFunction.js
```jsx <details>
import React, { useEffect, useState } from 'react'; <summary>full code</summary>
import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
```jsx
import React, { Component } from 'react';
// import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
import './Category.css'; import './Category.css';
import CategoryFormFunction from './CategoryFormFunction'; import CategoryFormClass from './CategoryFormClass';
const CategoryListFunction = () => { class CategoryListClass extends Component {
const [categories, setCategories] = useState([]); state = {
const [isEditing, setIsEditing] = useState(false); categories: [
const [currentCategory, setCurrentCategory] = useState({ id: '', name: '', description: '' }); { id: 1, name: 'Electronics', description: 'Devices and gadgets' },
{ id: 2, name: 'Books', description: 'Various books and literature' }
],
isEditing: false,
currentCategory: { id: '', name: '', description: '' },
};
useEffect(() => { // componentDidMount() {
fetchCategories(); // this.fetchCategories();
}, []); // }
const fetchCategories = async () => { // fetchCategories = async () => {
const categories = await getCategories(); // const categories = await getCategories();
setCategories(categories); // this.setState({ categories });
}; // };
const handleDelete = async (id) => { handleDelete = (id) => {
await deleteCategory(id); const filteredCategories = this.state.categories.filter(category => category.id !== id);
fetchCategories(); this.setState({ categories: filteredCategories });
}; };
const handleEdit = (category) => { handleEdit = (category) => {
setIsEditing(true); this.setState({ isEditing: true, currentCategory: category });
setCurrentCategory(category);
}; };
const handleCancelEdit = () => { handleCancelEdit = () => {
setIsEditing(false); this.setState({ isEditing: false, currentCategory: { id: '', name: '', description: '' } });
setCurrentCategory({ id: '', name: '', description: '' });
}; };
const handleChange = (event) => { handleChange = (event) => {
const { name, value } = event.target; const { name, value } = event.target;
setCurrentCategory((prevCategory) => ({ this.setState((prevState) => ({
...prevCategory, currentCategory: { ...prevState.currentCategory, [name]: value }
[name]: value,
})); }));
}; };
const handleUpdate = async (event) => { handleUpdate = (event) => {
event.preventDefault(); event.preventDefault();
await updateCategory(currentCategory.id, { const { categories, currentCategory } = this.state;
name: currentCategory.name, const updatedCategories = categories.map(category =>
description: currentCategory.description, category.id === currentCategory.id
}); ? { ...currentCategory }
setIsEditing(false); : category
setCurrentCategory({ id: '', name: '', description: '' }); );
fetchCategories(); this.setState({ categories: updatedCategories, isEditing: false, currentCategory: { id: '', name: '', description: '' } });
}; };
render() {
const { categories, isEditing, currentCategory } = this.state;
return ( return (
<div> <div>
<h2>Categories</h2> <h2>Categories</h2>
{isEditing ? ( {isEditing ? (
<form onSubmit={handleUpdate}> <form onSubmit={this.handleUpdate}>
<input <input
type="text" type="text"
name="name" name="name"
value={currentCategory.name} value={currentCategory.name}
onChange={handleChange} onChange={this.handleChange}
placeholder="Category Name" placeholder="Category Name"
/> />
<input <input
type="text" type="text"
name="description" name="description"
value={currentCategory.description} value={currentCategory.description}
onChange={handleChange} onChange={this.handleChange}
placeholder="Category Description" placeholder="Category Description"
/> />
<button type="submit" className="button button-update"> <button type="submit" className="button button-update">Update</button>
Update <button type="button" className="button button-delete" onClick={this.handleCancelEdit}>Cancel</button>
</button>
<button type="button" className="button button-delete" onClick={handleCancelEdit}>
Cancel
</button>
</form> </form>
) : ( ) : (
<CategoryFormFunction fetchCategories={fetchCategories} /> <CategoryFormClass fetchCategories={this.fetchCategories} />
)} )}
<table> <table>
<thead> <thead>
...@@ -393,18 +523,14 @@ const CategoryListFunction = () => { ...@@ -393,18 +523,14 @@ const CategoryListFunction = () => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{categories.map((category) => ( {categories.map(category => (
<tr key={category.id}> <tr key={category.id}>
<td>{category.id}</td> <td>{category.id}</td>
<td>{category.name}</td> <td>{category.name}</td>
<td>{category.description}</td> <td>{category.description}</td>
<td> <td>
<button className="button button-update" onClick={() => handleEdit(category)}> <button className="button button-update" onClick={() => this.handleEdit(category)}>Edit</button>
Edit <button className="button button-delete" onClick={() => this.handleDelete(category.id)}>Delete</button>
</button>
<button className="button button-delete" onClick={() => handleDelete(category.id)}>
Delete
</button>
</td> </td>
</tr> </tr>
))} ))}
...@@ -412,16 +538,20 @@ const CategoryListFunction = () => { ...@@ -412,16 +538,20 @@ const CategoryListFunction = () => {
</table> </table>
</div> </div>
); );
}; }
}
export default CategoryListClass;
```
</details>
export default CategoryListFunction;
```
### 6. Adding CSS (15 minutes) ### 6. Adding CSS (15 minutes)
- Demonstrate how to add and apply CSS in React. - Demonstrate how to add and apply CSS in React.
- Style the category and product forms. - Style the category and product forms.
Category.css Category.css *
```css ```css
form { form {
margin: 20px; margin: 20px;
...@@ -478,108 +608,100 @@ export default CategoryListFunction; ...@@ -478,108 +608,100 @@ export default CategoryListFunction;
.button-update:hover { .button-update:hover {
background-color: blue; background-color: blue;
} }
```
```
### 7. Break (5 minutes) ### 7. Integrating MockAPI for CRUD Operations (20 minutes)
### 8. Integrating MockAPI for CRUD Operations (30 minutes)
- Set up MockAPI for category and product management. - Set up MockAPI for category and product management.
- Perform CRUD operations (Create, Read, Update, Delete) using MockAPI. - Perform CRUD operations (Create, Read, Update, Delete) using MockAPI.
- Url Localhost / Mockapi: 'https://66b1b4381ca8ad33d4f4d9c0.mockapi.io/api/v1/category'; - Url Localhost / Mockapi: 'https://66b1b4381ca8ad33d4f4d9c0.mockapi.io/api/v1/category';
- Discuss Axios/ Await Fectch - Discuss Axios/ Await Fectch
- **Install React Router:**
ApiCategory.js ```bash
npm install axios --save
```
- ApiCategory.js
```jsx ```jsx
const apiUrl = 'https://mockapi.io/endpoint'; import axios from 'axios';
export const getCategories = () => fetch(apiUrl).then((res) => res.json());
export const createCategory = (category) =>
fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(category),
}).then((res) => res.json());
export const deleteCategory = (id) =>
fetch(\`\${apiUrl}/\${id}\`, {
method: 'DELETE',
}).then((res) => res.json());
export const updateCategory = (id, category) =>
fetch(\`\${apiUrl}/\${id}\`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(category),
}).then((res) => res.json());
```
### 9. Task to Create Product Page (60 minutes)
- Follow category page, task to create product registration page. Can use class / functional component
- Link forms to MockAPI for data submission.
- Url localhost / Mockapi: 'https://66b1b4381ca8ad33d4f4d9c0.mockapi.io/api/v1/product';
- Implement similar logic for \`ProductForm.js\` & \`ProductList.js\`
const apiUrl = 'https://66b1b4381ca8ad33d4f4d9c0.mockapi.io/api/v1/category';
```jsx export const getCategories = () => {
import React, { Component } from 'react'; return axios.get(apiUrl)
import ProductForm from './ProductForm'; .then((response) => response.data);
import { deleteProduct, updateProduct, getProduct } from '../../services/ApiProduct'; };
import './Product.css';
class ProductList extends Component { export const createCategory = (category) => {
state = { return axios.post(apiUrl, category)
products: [], .then((response) => response.data);
isEditing: false, };
currentProduct: { id: '', name: '', description: '', category: '' },
};
componentDidMount() { export const deleteCategory = (id) => {
} return axios.delete(`${apiUrl}/${id}`)
.then((response) => response.data);
};
render() { export const updateCategory = (id, category) => {
} return axios.put(`${apiUrl}/${id}`, category)
} .then((response) => response.data);
};
export default ProductList;
``` // Example with custom headers
// export const createCategory = (category, token) => {
// return axios.post(apiUrl, category, {
// headers: {
// Authorization: `Bearer ${token}` // Example of an auth token
// }
// }).then((response) => response.data);
// };
// export const createCategory = (category) =>
// fetch(apiUrl, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify(category),
// }).then((res) => res.json());
// export const deleteCategory = (id) =>
// fetch(\`\${apiUrl}/\${id}\`, {
// method: 'DELETE',
// }).then((res) => res.json());
// export const updateCategory = (id, category) =>
// fetch(\`\${apiUrl}/\${id}\`, {
// method: 'PUT',
// headers: {
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify(category),
// }).then((res) => res.json());
```
### 10. Routing Navigation (15 minutes) ### 8. Routing Navigation (15 minutes)
- Discus how React Rauter works - Discus how React Rauter works
- Modify \`App.js\` to include a welcome message and links to the category and product registration pages. - Modify \`App.js\` to include a welcome message and links to the category and product registration pages.
- Step-by-Step Instructions: - Step-by-Step Instructions:
- **Install React Router:** - **Install React Router:**
- Run the following command to install React Router: - Run the following command to install React Router:
```bash ```bash
npm install react-router-dom npm install react-router-dom
``` ```
- **Modify App.js:** - **Modify App.js:**
- Replace the content of App.js with the following code: - Replace the content of \`App.js\` with the following code:
```jsx ```jsx
import React from 'react'; import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'; import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom';
import logo from './logo.svg'; import logo from './logo.svg';
import './App.css'; import './App.css';
import CategoryListClass from './components/Category/CategoryListClass'; import CategoryListClass from './components/Category/CategoryListClass';
import CategoryFormClass from './components/Category/CategoryFormClass';
import CategoryListFunction from './components/Category/CategoryListFunction';
function App() { function App() {
return ( return (
...@@ -596,24 +718,30 @@ export default ProductList; ...@@ -596,24 +718,30 @@ export default ProductList;
</li> </li>
</ul> </ul>
</nav> </nav>
<Route path="/category" component={CategoryFormClass} /> <Routes>
<Route path="/product" component={CategoryListFunction} /> <Route path="/category" element={<CategoryListClass />} />
<Route path="/product" element={<CategoryListClass />} />
</Routes>
</div> </div>
</Router> </Router>
); );
} }
export default App; export default App;
``` ```
### 11. Design Content Navigation (15 minutes) ### 9. Design Content Navigation (15 minutes)
- Modify \`App.js\` to design topbar,sidebar and contentregistration pages. - Modify \`App.js\` to design topbar,sidebar and contentregistration pages.
- Step-by-Step Instructions: - Step-by-Step Instructions:
- **Modify App.js:** - **Modify App.js:**
- Replace code to App.js: - Replace code to App.js:
```jsx ```jsx
import logo from './logo.svg';
import './App.css';
import CategoryListClass from './components/Category/CategoryListClass';
import { BrowserRouter as Router, Link, Route, Routes } from 'react-router-dom';
function App() { function App() {
return ( return (
...@@ -626,10 +754,7 @@ export default ProductList; ...@@ -626,10 +754,7 @@ export default ProductList;
<nav className="sidebar"> <nav className="sidebar">
<ul> <ul>
<li> <li>
<Link to="/category1">Category Class</Link> <Link to="/category1">Category</Link>
</li>
<li>
<Link to="/category2">Category Functional</Link>
</li> </li>
<li> <li>
<Link to="/product">Product</Link> <Link to="/product">Product</Link>
...@@ -639,8 +764,7 @@ export default ProductList; ...@@ -639,8 +764,7 @@ export default ProductList;
<div className="content"> <div className="content">
<Routes> <Routes>
<Route path="/category1" element={<CategoryListClass />} /> <Route path="/category1" element={<CategoryListClass />} />
<Route path="/category2" element={<CategoryListFunction />} /> {/*<Route path="/product" element={<ProductList />} /> */}
<Route path="/product" element={<ProductList />} />
</Routes> </Routes>
</div> </div>
</div> </div>
...@@ -648,12 +772,15 @@ export default ProductList; ...@@ -648,12 +772,15 @@ export default ProductList;
</Router> </Router>
); );
} }
export default App;
``` ```
- **Modify App.css:** - **Modify App.css:**
- Add the content of \`App.css\` with the following code: - Add the content of \`App.css\` with the following code:
```css ```css
.App { .App {
font-family: sans-serif; font-family: sans-serif;
...@@ -704,6 +831,476 @@ export default ProductList; ...@@ -704,6 +831,476 @@ export default ProductList;
``` ```
### 10. Break (5 minutes)
### 11. Creating Functional Components (30 minutes)
- Deep dive into creating functional components with hooks.
- Create `CategoryFormFunction.js` and `CategoryListFunction.js` as functional components.
- Discuss useState and useEffect hooks.
CategoryFormFunction.js
#### I: Importing Dependencies
Start by importing React and any necessary services:
```
import React, { useState } from 'react';
//import { createCategory } from '../../services/ApiCategory';
```
#### II: Defining the Functional Component
```
const CategoryFormFunction = () => {
return (
"test"
);
};
```
#### III: Introducing useState Hook
```
const [categoryName, setCategoryName] = useState('');
const [description, setDescription] = useState('');
```
#### IV: Handling Input Changes & Submit Function
```
const handleChange = (event) => {
const { name, value } = event.target;
if (name === 'name') setCategoryName(value);
if (name === 'description') setDescription(value);
};
```
```
const handleSubmit = (event) => {
event.preventDefault();
// Log the current state values
console.log({
categoryName: categoryName,
description: description,
});
// Display an alert with the submitted category name and description
alert(`Category Name: ${categoryName}\nCategory Description: ${description}`);
// Clear the input fields after submission
setCategoryName('');
setDescription('');
// API integration will be handled in the next chapter
//await createCategory({ name: categoryName, description });
//fetchCategories();
};
```
#### V: Rendering the Form
```
const CategoryFormFunction = () => {
return (
<form>
<input type="text" name="name" placeholder="Category Name" />
<input type="text" name="description" placeholder="Category Description" />
<button type="submit">Add Category</button>
</form>
);
};
```
#### VII: Rendering the Form with Function
Start by importing React and any necessary services:
```
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="name"
value={categoryName}
onChange={handleChange}
placeholder="Category Name"
/>
<input
type="text"
name="description"
value={description}
onChange={handleChange}
placeholder="Category Description"
/>
<button type="submit">Add Category</button>
</form>
);
```
#### VI: Exporting the Component
```
export default CategoryFormFunction;
```
<details>
<summary>full code</summary>
```jsx
import React, { useState } from 'react';
import { createCategory } from '../../services/ApiCategory';
const CategoryFormFunction = ({ fetchCategories }) => {
const [categoryName, setCategoryName] = useState('');
const [description, setDescription] = useState('');
const handleChange = (event) => {
const { name, value } = event.target;
if (name === 'name') setCategoryName(value);
if (name === 'description') setDescription(value);
};
const handleSubmit = async (event) => {
event.preventDefault();
await createCategory({ name: categoryName, description });
setCategoryName('');
setDescription('');
fetchCategories();
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="name"
value={categoryName}
onChange={handleChange}
placeholder="Category Name"
/>
<input
type="text"
name="description"
value={description}
onChange={handleChange}
placeholder="Category Description"
/>
<button type="submit">Add Category</button>
</form>
);
};
export default CategoryFormFunction;
```
</details>
CategoryListFunction.js
#### I: Importing Dependencies
Start by importing React and any necessary services:
```
import React, { useEffect, useState } from 'react';
import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
import './Category.css';
import CategoryFormFunction from './CategoryFormFunction';
```
#### II: Defining the Functional Component
```
const CategoryListFunction = () => {
return (
"testCategory"
);
}
```
#### III: Introducing useState Hook
```
const [categories, setCategories] = useState([]);
const [isEditing, setIsEditing] = useState(false);
const [currentCategory, setCurrentCategory] = useState({ id: '', name: '', description: '' });
```
#### III: Lifecycle Method and Fetch Categories
```
componentDidMount() {
// this.fetchCategories();
}
fetchCategories = async () => {
// const categories = await getCategories();
// this.setState({ categories });
};
```
#### IV: Handling Delete, Edit, and Cancel Edit
```
const handleDelete = async (id) => {
await deleteCategory(id);
fetchCategories(); // Refresh the list after deletion
};
const handleEdit = (category) => {
setIsEditing(true);
setCurrentCategory(category);
};
const handleCancelEdit = () => {
setIsEditing(false);
setCurrentCategory({ id: '', name: '', description: '' });
};
```
#### V: Handling Input Changes and Update and Add using props
```
const handleChange = (event) => {
const { name, value } = event.target;
setCurrentCategory((prevCategory) => ({
...prevCategory,
[name]: value,
}));
};
const handleUpdate = async (event) => {
event.preventDefault();
await updateCategory(currentCategory.id, {
name: currentCategory.name,
description: currentCategory.description,
});
setIsEditing(false);
setCurrentCategory({ id: '', name: '', description: '' });
fetchCategories();
};
```
#### II: Rendering the Functional Component
```
return (
<div>
<h2>Categories</h2>
{isEditing ? (
<form onSubmit={handleUpdate}>
<input
type="text"
name="name"
value={currentCategory.name}
onChange={handleChange}
placeholder="Category Name"
/>
<input
type="text"
name="description"
value={currentCategory.description}
onChange={handleChange}
placeholder="Category Description"
/>
<button type="submit" className="button button-update">
Update
</button>
<button type="button" className="button button-delete" onClick={handleCancelEdit}>
Cancel
</button>
</form>
) : (
<CategoryFormFunction fetchCategories={fetchCategories} />
)}
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{categories.map((category) => (
<tr key={category.id}>
<td>{category.id}</td>
<td>{category.name}</td>
<td>{category.description}</td>
<td>
<button className="button button-update" onClick={() => handleEdit(category)}>
Edit
</button>
<button className="button button-delete" onClick={() => handleDelete(category.id)}>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
```
<details>
<summary>full code</summary>
```jsx
import React, { useEffect, useState } from 'react';
import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
import './Category.css';
import CategoryFormFunction from './CategoryFormFunction';
const CategoryListFunction = () => {
const [categories, setCategories] = useState([]);
const [isEditing, setIsEditing] = useState(false);
const [currentCategory, setCurrentCategory] = useState({ id: '', name: '', description: '' });
useEffect(() => {
fetchCategories();
}, []);
const fetchCategories = async () => {
const categories = await getCategories();
setCategories(categories);
};
const handleDelete = async (id) => {
await deleteCategory(id);
fetchCategories();
};
const handleEdit = (category) => {
setIsEditing(true);
setCurrentCategory(category);
};
const handleCancelEdit = () => {
setIsEditing(false);
setCurrentCategory({ id: '', name: '', description: '' });
};
const handleChange = (event) => {
const { name, value } = event.target;
setCurrentCategory((prevCategory) => ({
...prevCategory,
[name]: value,
}));
};
const handleUpdate = async (event) => {
event.preventDefault();
await updateCategory(currentCategory.id, {
name: currentCategory.name,
description: currentCategory.description,
});
setIsEditing(false);
setCurrentCategory({ id: '', name: '', description: '' });
fetchCategories();
};
return (
<div>
<h2>Categories</h2>
{isEditing ? (
<form onSubmit={handleUpdate}>
<input
type="text"
name="name"
value={currentCategory.name}
onChange={handleChange}
placeholder="Category Name"
/>
<input
type="text"
name="description"
value={currentCategory.description}
onChange={handleChange}
placeholder="Category Description"
/>
<button type="submit" className="button button-update">
Update
</button>
<button type="button" className="button button-delete" onClick={handleCancelEdit}>
Cancel
</button>
</form>
) : (
<CategoryFormFunction fetchCategories={fetchCategories} />
)}
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{categories.map((category) => (
<tr key={category.id}>
<td>{category.id}</td>
<td>{category.name}</td>
<td>{category.description}</td>
<td>
<button className="button button-update" onClick={() => handleEdit(category)}>
Edit
</button>
<button className="button button-delete" onClick={() => handleDelete(category.id)}>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default CategoryListFunction;
```
</details>
### 12. Task to Create Product Page (60 minutes)
- Follow category page, task to create product registration page. Can use class / functional component
- Link forms to MockAPI for data submission.
- Url localhost / Mockapi: 'https://66b1b4381ca8ad33d4f4d9c0.mockapi.io/api/v1/product';
- Implement similar logic for \`ProductForm.js\` & \`ProductList.js\`
Example form and list structure with API integration
```jsx
import React, { Component } from 'react';
import ProductForm from './ProductForm';
import { deleteProduct, updateProduct, getProduct } from '../../services/ApiProduct';
import './Product.css';
class ProductList extends Component {
state = {
products: [],
isEditing: false,
currentProduct: { id: '', name: '', description: '', category: '' },
};
componentDidMount() {
}
render() {
}
}
export default ProductList;
```
## Conclusion (15 minutes) ## Conclusion (15 minutes)
- Recap the key concepts covered. - Recap the key concepts covered.
...@@ -753,5 +1350,5 @@ export default ProductList; ...@@ -753,5 +1350,5 @@ export default ProductList;
This comprehensive 3-hour training module ensures that students gain an in-depth understanding of React components, styling, and CRUD operations, with ample time for hands-on practice and advanced topics. This comprehensive 4-hour training module ensures that students gain an in-depth understanding of React components, styling, and CRUD operations, with ample time for hands-on practice and advanced topics.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment