Update README.md

parent a80c60ec
......@@ -57,10 +57,10 @@ my-product-management-system/
├── src/
│ ├── components/
│ │ ├── Category/
│ │ │ ├── CategoryListClass.js
│ │ │ ├── CategoryFormClass.js
│ │ │ ├── CategoryListFunction.js
│ │ │ ├── CategoryListClass.js
│ │ │ ├── CategoryFormFunction.js
│ │ │ ├── CategoryListFunction.js
│ │ │ ├── Category.css
│ │ ├── Product/
│ │ │ ├── ProductListClass.js
......@@ -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.
- Create `CategoryFormClass.js` and `CategoryListClass.js` as class components.
- 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 { createCategory } from '../../services/ApiCategory';
```
#### II: Defining the Class Component
```
class CategoryFormClass extends Component {
state = {
name: '',
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) => {
this.setState({ [event.target.name]: event.target.value });
......@@ -107,7 +219,7 @@ class CategoryFormClass extends Component {
};
render() {
const { name, description } = this.state
const { name, description } = this.state;
return (
<form onSubmit={this.handleSubmit}>
......@@ -129,65 +241,126 @@ class CategoryFormClass extends Component {
</form>
);
}
}
}
export default CategoryFormClass;
export default CategoryFormClass;
```
</details>
CategoryListClass.js
```jsx
#### I: Importing Dependencies
Start by importing React and any necessary services:
```
import React, { Component } from 'react';
import CategoryFormClass from './CategoryFormClass';
import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
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 {
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,
currentCategory: { id: '', name: '', description: '' },
currentCategory: { id: "", name: "", description: "" },
};
componentDidMount() {
this.fetchCategories();
render() {
return "test";
}
}
```
fetchCategories = async () => {
const categories = await getCategories();
this.setState({ categories });
};
#### III: Lifecycle Method and Fetch 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 });
};
};
handleCancelEdit = () => {
handleCancelEdit = () => {
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;
this.setState((prevState) => ({
currentCategory: { ...prevState.currentCategory, [name]: value }
}));
};
};
handleUpdate = async (event) => {
handleUpdate = (event) => {
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;
return (
<div>
......@@ -212,8 +385,10 @@ class CategoryListClass extends Component {
<button type="button" className="button button-delete" onClick={this.handleCancelEdit}>Cancel</button>
</form>
) : (
<CategoryFormClass fetchCategories={this.fetchCategories} />
<CategoryFormClass addCategory={this.addCategory} />
// <CategoryFormClass fetchCategories={this.fetchCategories} />
)}
<div style={{ display: "inline-block", textAlign: "left", marginTop: "20px"}}>
<table>
<thead>
<tr>
......@@ -238,150 +413,105 @@ class CategoryListClass extends Component {
</tbody>
</table>
</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) => {
event.preventDefault();
await createCategory({ name: categoryName, description });
setCategoryName('');
setDescription('');
fetchCategories();
};
#### VI: Exporting the Component
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 CategoryListClass;
export default CategoryFormFunction;
```
CategoryListFunction.js
```jsx
import React, { useEffect, useState } from 'react';
import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
<details>
<summary>full code</summary>
```jsx
import React, { Component } from 'react';
// import { getCategories, deleteCategory, updateCategory } from '../../services/ApiCategory';
import './Category.css';
import CategoryFormFunction from './CategoryFormFunction';
import CategoryFormClass from './CategoryFormClass';
const CategoryListFunction = () => {
const [categories, setCategories] = useState([]);
const [isEditing, setIsEditing] = useState(false);
const [currentCategory, setCurrentCategory] = useState({ id: '', name: '', description: '' });
class CategoryListClass extends Component {
state = {
categories: [
{ id: 1, name: 'Electronics', description: 'Devices and gadgets' },
{ id: 2, name: 'Books', description: 'Various books and literature' }
],
isEditing: false,
currentCategory: { id: '', name: '', description: '' },
};
useEffect(() => {
fetchCategories();
}, []);
// componentDidMount() {
// this.fetchCategories();
// }
const fetchCategories = async () => {
const categories = await getCategories();
setCategories(categories);
};
// fetchCategories = async () => {
// const categories = await getCategories();
// this.setState({ categories });
// };
const handleDelete = async (id) => {
await deleteCategory(id);
fetchCategories();
handleDelete = (id) => {
const filteredCategories = this.state.categories.filter(category => category.id !== id);
this.setState({ categories: filteredCategories });
};
const handleEdit = (category) => {
setIsEditing(true);
setCurrentCategory(category);
handleEdit = (category) => {
this.setState({ isEditing: true, currentCategory: category });
};
const handleCancelEdit = () => {
setIsEditing(false);
setCurrentCategory({ id: '', name: '', description: '' });
handleCancelEdit = () => {
this.setState({ isEditing: false, currentCategory: { id: '', name: '', description: '' } });
};
const handleChange = (event) => {
handleChange = (event) => {
const { name, value } = event.target;
setCurrentCategory((prevCategory) => ({
...prevCategory,
[name]: value,
this.setState((prevState) => ({
currentCategory: { ...prevState.currentCategory, [name]: value }
}));
};
const handleUpdate = async (event) => {
handleUpdate = (event) => {
event.preventDefault();
await updateCategory(currentCategory.id, {
name: currentCategory.name,
description: currentCategory.description,
});
setIsEditing(false);
setCurrentCategory({ id: '', name: '', description: '' });
fetchCategories();
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: '' } });
};
render() {
const { categories, isEditing, currentCategory } = this.state;
return (
<div>
<h2>Categories</h2>
{isEditing ? (
<form onSubmit={handleUpdate}>
<form onSubmit={this.handleUpdate}>
<input
type="text"
name="name"
value={currentCategory.name}
onChange={handleChange}
onChange={this.handleChange}
placeholder="Category Name"
/>
<input
type="text"
name="description"
value={currentCategory.description}
onChange={handleChange}
onChange={this.handleChange}
placeholder="Category Description"
/>
<button type="submit" className="button button-update">
Update
</button>
<button type="button" className="button button-delete" onClick={handleCancelEdit}>
Cancel
</button>
<button type="submit" className="button button-update">Update</button>
<button type="button" className="button button-delete" onClick={this.handleCancelEdit}>Cancel</button>
</form>
) : (
<CategoryFormFunction fetchCategories={fetchCategories} />
<CategoryFormClass fetchCategories={this.fetchCategories} />
)}
<table>
<thead>
......@@ -393,18 +523,14 @@ const CategoryListFunction = () => {
</tr>
</thead>
<tbody>
{categories.map((category) => (
{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>
<button className="button button-update" onClick={() => this.handleEdit(category)}>Edit</button>
<button className="button button-delete" onClick={() => this.handleDelete(category.id)}>Delete</button>
</td>
</tr>
))}
......@@ -412,16 +538,20 @@ const CategoryListFunction = () => {
</table>
</div>
);
};
}
}
export default CategoryListClass;
```
</details>
export default CategoryListFunction;
```
### 6. Adding CSS (15 minutes)
- Demonstrate how to add and apply CSS in React.
- Style the category and product forms.
Category.css
Category.css *
```css
form {
margin: 20px;
......@@ -478,108 +608,100 @@ export default CategoryListFunction;
.button-update:hover {
background-color: blue;
}
```
### 7. Break (5 minutes)
### 8. Integrating MockAPI for CRUD Operations (30 minutes)
```
### 7. Integrating MockAPI for CRUD Operations (20 minutes)
- Set up MockAPI for category and product management.
- Perform CRUD operations (Create, Read, Update, Delete) using MockAPI.
- Url Localhost / Mockapi: 'https://66b1b4381ca8ad33d4f4d9c0.mockapi.io/api/v1/category';
- Discuss Axios/ Await Fectch
ApiCategory.js
- **Install React Router:**
```bash
npm install axios --save
```
- ApiCategory.js
```jsx
const apiUrl = 'https://mockapi.io/endpoint';
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\`
import axios from 'axios';
const apiUrl = 'https://66b1b4381ca8ad33d4f4d9c0.mockapi.io/api/v1/category';
```jsx
import React, { Component } from 'react';
import ProductForm from './ProductForm';
import { deleteProduct, updateProduct, getProduct } from '../../services/ApiProduct';
import './Product.css';
export const getCategories = () => {
return axios.get(apiUrl)
.then((response) => response.data);
};
class ProductList extends Component {
state = {
products: [],
isEditing: false,
currentProduct: { id: '', name: '', description: '', category: '' },
};
export const createCategory = (category) => {
return axios.post(apiUrl, category)
.then((response) => response.data);
};
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
- Modify \`App.js\` to include a welcome message and links to the category and product registration pages.
- Step-by-Step Instructions:
- **Install React Router:**
- Run the following command to install React Router:
```bash
npm install react-router-dom
```
- **Modify App.js:**
- Replace the content of App.js with the following code:
- Replace the content of \`App.js\` with the following code:
```jsx
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 './App.css';
import CategoryListClass from './components/Category/CategoryListClass';
import CategoryFormClass from './components/Category/CategoryFormClass';
import CategoryListFunction from './components/Category/CategoryListFunction';
function App() {
return (
......@@ -596,24 +718,30 @@ export default ProductList;
</li>
</ul>
</nav>
<Route path="/category" component={CategoryFormClass} />
<Route path="/product" component={CategoryListFunction} />
<Routes>
<Route path="/category" element={<CategoryListClass />} />
<Route path="/product" element={<CategoryListClass />} />
</Routes>
</div>
</Router>
);
}
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.
- Step-by-Step Instructions:
- **Modify App.js:**
- Replace code to App.js:
```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() {
return (
......@@ -626,10 +754,7 @@ export default ProductList;
<nav className="sidebar">
<ul>
<li>
<Link to="/category1">Category Class</Link>
</li>
<li>
<Link to="/category2">Category Functional</Link>
<Link to="/category1">Category</Link>
</li>
<li>
<Link to="/product">Product</Link>
......@@ -639,8 +764,7 @@ export default ProductList;
<div className="content">
<Routes>
<Route path="/category1" element={<CategoryListClass />} />
<Route path="/category2" element={<CategoryListFunction />} />
<Route path="/product" element={<ProductList />} />
{/*<Route path="/product" element={<ProductList />} /> */}
</Routes>
</div>
</div>
......@@ -648,12 +772,15 @@ export default ProductList;
</Router>
);
}
export default App;
```
- **Modify App.css:**
- Add the content of \`App.css\` with the following code:
```css
.App {
font-family: sans-serif;
......@@ -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)
- Recap the key concepts covered.
......@@ -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