Skip to content

Commit 1a674e2

Browse files
author
koladev
committed
feat : add menu pages
1 parent e0a5c38 commit 1a674e2

File tree

3 files changed

+164
-59
lines changed

3 files changed

+164
-59
lines changed

menu-frontend/src/app/add/page.js

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
"use client";
2-
31
import { useEffect, useState } from "react";
4-
import { useRouter } from "next/navigation";
2+
import { useRouter } from "next/router";
3+
4+
/**
5+
* Sends a POST request to create a new menu item.
6+
* @param {Object} data The menu item data to be sent.
7+
*/
58
async function createMenu(data) {
69
const res = await fetch("http://127.0.0.1:8000/api/menu/", {
710
method: "POST",
811
headers: {
912
"Content-Type": "application/json",
10-
// 'Content-Type': 'application/x-www-form-urlencoded',
1113
},
1214
body: JSON.stringify(data),
1315
});
@@ -21,32 +23,32 @@ async function createMenu(data) {
2123

2224
const Page = () => {
2325
const router = useRouter();
24-
const [formData, setFormData] = useState({
25-
name: "",
26-
price: "",
27-
});
28-
26+
const [formData, setFormData] = useState({ name: "", price: "" });
2927
const [isLoading, setIsLoading] = useState(false);
3028
const [error, setError] = useState(null);
3129

30+
/**
31+
* Handles the form submission.
32+
* @param {Event} event The form submission event.
33+
*/
3234
const onFinish = (event) => {
33-
setIsLoading(true);
3435
event.preventDefault();
36+
setIsLoading(true);
3537
createMenu(formData)
3638
.then(() => {
39+
// Navigate to the main page with a query parameter indicating success
3740
router.replace("/?action=add");
3841
})
39-
.catch((reason) => {
40-
setError("An error occured");
42+
.catch(() => {
43+
setError("An error occurred");
4144
setIsLoading(false);
4245
});
4346
};
4447

48+
// Cleanup effect for resetting loading state
4549
useEffect(() => {
46-
return () => {
47-
setIsLoading(false);
48-
};
49-
});
50+
return () => setIsLoading(false);
51+
}, []);
5052

5153
return (
5254
<form onSubmit={onFinish}>
@@ -57,10 +59,7 @@ const Page = () => {
5759
name="name"
5860
value={formData.name}
5961
onChange={(event) =>
60-
setFormData({
61-
...formData,
62-
name: event.target.value,
63-
})
62+
setFormData({ ...formData, name: event.target.value })
6463
}
6564
/>
6665
</div>
@@ -72,21 +71,13 @@ const Page = () => {
7271
name="price"
7372
value={formData.price}
7473
onChange={(event) =>
75-
setFormData({
76-
...formData,
77-
price: event.target.value,
78-
})
74+
setFormData({ ...formData, price: event.target.value })
7975
}
8076
/>
8177
</div>
8278
{error && <p className="error-message">{error}</p>}
8379
<div>
84-
<button
85-
disabled={isLoading}
86-
className="add-button"
87-
type="submit"
88-
name="price"
89-
>
80+
<button disabled={isLoading} className="add-button" type="submit">
9081
Submit
9182
</button>
9283
</div>

menu-frontend/src/app/page.js

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
"use client";
2-
31
import { useEffect, useState } from "react";
4-
import { useRouter, useSearchParams } from "next/navigation";
2+
import { useRouter } from "next/router";
53

4+
/**
5+
* Fetches menu data from the server.
6+
*/
67
async function getData() {
78
const res = await fetch("http://127.0.0.1:8000/api/menu/");
8-
99
if (!res.ok) {
1010
throw new Error("Failed to fetch data");
1111
}
12-
1312
return res.json();
1413
}
1514

15+
/**
16+
* Represents a single menu item.
17+
*/
1618
const MenuItem = ({ id, name, price, onEdit, onDelete }) => {
1719
return (
1820
<div className="menu-item" data-id={id}>
@@ -21,7 +23,7 @@ const MenuItem = ({ id, name, price, onEdit, onDelete }) => {
2123
<div className="menu-item-price">${price.toFixed(2)}</div>
2224
</div>
2325
<div className="menu-item-actions">
24-
<button className="edit-button" onClick={() => onEdit(id)}>
26+
<button className="edit-button" onClick={onEdit}>
2527
Edit
2628
</button>
2729
<button className="delete-button" onClick={() => onDelete(id)}>
@@ -31,51 +33,54 @@ const MenuItem = ({ id, name, price, onEdit, onDelete }) => {
3133
</div>
3234
);
3335
};
36+
37+
/**
38+
* The main page component.
39+
*/
3440
export default function Page() {
3541
const [menuItems, setMenuItems] = useState(null);
3642
const router = useRouter();
37-
const params = useSearchParams();
3843

44+
// State for displaying a success message
3945
const [displaySuccessMessage, setDisplaySuccessMessage] = useState({
4046
show: false,
41-
type: "", // either add or edit
47+
type: "", // either 'add' or 'update'
4248
});
4349

44-
useEffect(
45-
() => async () => {
50+
// Fetch menu items on component mount
51+
useEffect(() => {
52+
const fetchData = async () => {
4653
const data = await getData();
47-
if (data) {
48-
setMenuItems(data);
49-
}
50-
},
51-
[],
52-
);
54+
setMenuItems(data);
55+
};
56+
fetchData().catch(console.error);
57+
}, []);
5358

59+
// Detect changes in URL parameters for success messages
5460
useEffect(() => {
55-
if (!!params.get("action")) {
61+
const action = new URLSearchParams(window.location.search).get("action");
62+
if (action) {
5663
setDisplaySuccessMessage({
57-
type: "add",
64+
type: action,
5865
show: true,
5966
});
60-
router.replace("/");
67+
// Clear the URL parameter
68+
router.replace(router.pathname);
6169
}
62-
}, [params, router]);
70+
}, [router]);
6371

72+
// Automatically hide the success message after 3 seconds
6473
useEffect(() => {
6574
const timer = setTimeout(() => {
6675
if (displaySuccessMessage.show) {
67-
setDisplaySuccessMessage({
68-
show: false,
69-
type: "",
70-
});
76+
setDisplaySuccessMessage({ show: false, type: "" });
7177
}
7278
}, 3000);
7379
return () => clearTimeout(timer);
7480
}, [displaySuccessMessage.show]);
7581

82+
// Handle deletion of a menu item
7683
const handleDelete = (id) => {
77-
// Logic to delete the menu item
78-
console.log("Delete item with id:", id);
7984
setMenuItems((items) => items.filter((item) => item.id !== id));
8085
};
8186

@@ -87,21 +92,22 @@ export default function Page() {
8792
{displaySuccessMessage.show && (
8893
<p className="success-message">
8994
{displaySuccessMessage.type === "add" ? "Added a" : "Modified a"} menu
95+
item.
9096
</p>
9197
)}
92-
{!!menuItems ? (
98+
{menuItems ? (
9399
menuItems.map((item) => (
94100
<MenuItem
95101
key={item.id}
96102
id={item.id}
97103
name={item.name}
98104
price={item.price}
99-
onEdit={undefined}
105+
onEdit={() => router.push(`/update/${item.id}`)}
100106
onDelete={handleDelete}
101107
/>
102108
))
103109
) : (
104-
<p>Loading</p>
110+
<p>Loading...</p>
105111
)}
106112
</div>
107113
);
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { useEffect, useState } from "react";
2+
import { useRouter } from "next/router";
3+
4+
/**
5+
* Fetches a menu item by ID.
6+
* @param {number} id The ID of the menu item to retrieve.
7+
*/
8+
async function getMenu(id) {
9+
const res = await fetch(`http://127.0.0.1:8000/api/menu/${id}/`);
10+
if (!res.ok) {
11+
throw new Error("Failed to retrieve menu");
12+
}
13+
return res.json();
14+
}
15+
16+
/**
17+
* Updates a menu item by ID.
18+
* @param {number} id The ID of the menu item to update.
19+
* @param {Object} data The updated data for the menu item.
20+
*/
21+
async function updateMenu(id, data) {
22+
const res = await fetch(`http://127.0.0.1:8000/api/menu/${id}/`, {
23+
method: "PUT",
24+
headers: {
25+
"Content-Type": "application/json",
26+
},
27+
body: JSON.stringify(data),
28+
});
29+
30+
if (!res.ok) {
31+
throw new Error("Failed to update menu");
32+
}
33+
return res.json();
34+
}
35+
36+
const Page = ({ params }) => {
37+
const router = useRouter();
38+
const [formData, setFormData] = useState({ name: "", price: "" });
39+
const [isLoading, setIsLoading] = useState(false);
40+
const [error, setError] = useState(null);
41+
42+
/**
43+
* Handles form submission.
44+
* @param {Event} event The form submission event.
45+
*/
46+
const onFinish = (event) => {
47+
event.preventDefault();
48+
setIsLoading(true);
49+
updateMenu(params.menuId, formData)
50+
.then(() => {
51+
router.replace("/?action=update");
52+
})
53+
.catch(() => {
54+
setError("An error occurred");
55+
setIsLoading(false);
56+
});
57+
};
58+
59+
// Cleanup effect for resetting loading state
60+
useEffect(() => {
61+
return () => setIsLoading(false);
62+
}, []);
63+
64+
// Fetch menu item data on component mount
65+
useEffect(() => {
66+
const fetchData = async () => {
67+
try {
68+
const data = await getMenu(params.menuId);
69+
setFormData({ name: data.name, price: data.price });
70+
} catch (error) {
71+
setError(error.message);
72+
}
73+
};
74+
fetchData();
75+
}, [params.menuId]);
76+
77+
return (
78+
<form onSubmit={onFinish}>
79+
<div className="form-item">
80+
<label htmlFor="name">Name</label>
81+
<input
82+
required
83+
name="name"
84+
value={formData.name}
85+
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
86+
/>
87+
</div>
88+
<div className="form-item">
89+
<label htmlFor="price">Price</label>
90+
<input
91+
required
92+
type="number"
93+
name="price"
94+
value={formData.price}
95+
onChange={(e) => setFormData({ ...formData, price: e.target.value })}
96+
/>
97+
</div>
98+
{error && <p className="error-message">{error}</p>}
99+
<div>
100+
<button disabled={isLoading} className="add-button" type="submit">
101+
Submit
102+
</button>
103+
</div>
104+
</form>
105+
);
106+
};
107+
108+
export default Page;

0 commit comments

Comments
 (0)