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
49 changes: 48 additions & 1 deletion controllers/menuController.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,54 @@ const readRestaurants = () => {
const writeRestaurants = (restaurants) => {
fs.writeFileSync(writePath, JSON.stringify(restaurants, null, 2));
};

exports.addMenuItem = async (req, res) => {

};

exports.getMenu = async (req, res) => {
try {
const menu = await menuService.getMenu(req.params.restaurantId);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

menuService is not imported into the controller file but is used throughout.

res.status(200).json(menu);
} catch (error) {
res.status(error.status || 500).json({ error: error.message });
}
};

exports.updateMenuItem = async (req, res) => {
const { itemId } = req.params;
const updatedData = req.body;

const result = await menuService.updateMenuItem(itemId, updatedData);
if (result.error) {
return res.status(404).json({ error: result.error });
}
res
.status(200)
.json({ message: "Menu item updated successfully", menu: result.menu });
};

exports.updateAvailability = async (req, res) => {
const { itemId } = req.params;
const { availability } = req.body;

const result = await menuService.updateAvailability(itemId, availability);
if (result.error) {
return res.status(404).json({ error: result.error });
}
res
.status(200)
.json({ message: "Availability updated successfully", menu: result.menu });
};

exports.deleteMenuItem = async (req, res) => {
const { itemId } = req.params;

const result = await menuService.deleteMenuItem(itemId);
if (result.error) {
return res.status(404).json({ error: result.error });
}
res
.status(500)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wrong status code of 500 instead of 200 is returned. This will confuse the client into thinking the request failed.

.json({ message: "Menu item deleted successfully", menu: result.menu });
};
159 changes: 159 additions & 0 deletions routes/menuRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const { validateMenu } = require("../middleware/validateMenu");

router.post("/:restaurantId", validateMenu, menuController.addMenuItem);

router.get("/:restaurantId", menuController.getMenu);
router.put("/item/:itemId", menuController.updateMenuItem);
router.patch("/item/:itemId", menuController.updateAvailability);
router.delete("/item/:itemId", menuController.deleteMenuItem);

/**
* @swagger
* tags:
Expand Down Expand Up @@ -105,4 +110,158 @@ router.post("/:restaurantId", validateMenu, menuController.addMenuItem);
* message: "Availability is required."
*/

/**
* @swagger
* /menu/{restaurantId}:
* get:
* summary: Retrieve the entire menu of a specific restaurant
* tags: [Menu]
* parameters:
* - in: path
* name: restaurantId
* required: true
* description: ID of the restaurant to retrieve the menu from
* schema:
* type: string
* responses:
* 200:
* description: Successfully retrieved menu
* content:
* application/json:
* schema:
* type: array
* items:
* type: object
* properties:
* itemId:
* type: string
* name:
* type: string
* price:
* type: number
* format: float
* category:
* type: string
* availability:
* type: boolean
*/

/**
* @swagger
* /menu/item/{itemId}:
* put:
* summary: Update one or more details of a specific menu item
* tags: [Menu]
* parameters:
* - in: path
* name: itemId
* required: true
* description: ID of the menu item to update
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* itemId:
* type: string
* name:
* type: string
* price:
* type: number
* format: float
* category:
* type: string
* availability:
* type: boolean
* responses:
* 200:
* description: Menu item updated successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
*/

/**
* @swagger
* /menu/item/{itemId}:
* patch:
* summary: Update the availability status of a specific menu item
* tags: [Menu]
* parameters:
* - in: path
* name: itemId
* required: true
* description: ID of the menu item to update availability
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* availability:
* type: boolean
* responses:
* 200:
* description: Availability updated successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
*/

/**
* @swagger
* /menu/item/{itemId}:
* delete:
* summary: Delete a specific menu item by its ID
* tags: [Menu]
* parameters:
* - in: path
* name: itemId
* required: true
* description: ID of the menu item to delete
* schema:
* type: string
* responses:
* 200:
* description: Menu item deleted successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* menu:
* type: array
* items:
* type: object
* properties:
* itemId:
* type: string
* name:
* type: string
* price:
* type: number
* format: float
* category:
* type: string
* availability:
* type: boolean
*/

module.exports = router;
70 changes: 70 additions & 0 deletions services/menuService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const fs = require("fs").promises;
const path = require("path");
const writePath = path.join(__dirname, "../data/updated_restaurants.json");

const readRestaurants = async () => {
try {
const data = await fs.readFile("data/restaurants.json", "utf-8");
return JSON.parse(data);
} catch (error) {
throw new Error("Failed to read restaurant data.");
}
};

async function writeRestaurants(restaurants) {
await fs.writeFile(writePath, restaurants);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data should be stringified before writing using JSON.stringify, or the file content will be invalid.

}

exports.getMenu = async (restaurantId) => {
try {
const restaurants = await readRestaurants();

const restaurant = restaurants.find((r) => r.id === restaurantId);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use findIndex instead of find to get the correct index. Using find returns the object, causing an error when accessing restaurants[restaurant].menu.


return restaurants[restaurant].menu;
} catch (error) {
throw error;
}
};

exports.updateMenuItem = async (itemId, updatedData) => {
try {
const restaurants = await readRestaurants();
let itemFound = false;
let updatedItem = null;

for (const restaurant of restaurants) {
const menuItem = restaurants.menu?.find((item) => item.itemId === itemId);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: It should be restaurant instead of restaurants. This will result in undefined property access.

if (menuItem) {
Object.assign(null, updatedData);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Object.assign with null as the target will throw a TypeError. The first parameter should be menuItem.

updatedItem = menuItem;
itemFound = true;
break;
}
}

await writeRestaurants(restaurants);
return {
message: "Menu item updated successfully",
item: updatedItem,
};
} catch (error) {
throw error;
}
};

exports.updateAvailability = async (itemId, availability) => {
return exports.updateMenuItem(itemId, { availability });
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing await for updateMenuItem will return an unresolved Promise.

};

exports.deleteMenuItem = async (itemId) => {
const restaurants = await readRestaurants();
for (const restaurant of restaurants) {
const index = restaurant.menu.findIndex((item) => item.itemId === itemId);
if (index !== -1) {
restaurant.menu.slice(index, 1);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using slice instead of splice will not modify the original array, so the menu item will not be removed.

await writeRestaurants(restaurants);
return;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning undefined instead of the menu: { menu: restaurant.menu }

}
}
};