csa-backend-test/app/controllers/menu.controller.js

321 lines
9.9 KiB
JavaScript

// ENVIRONMENT
require('dotenv').config();
// DATABASE
const { PrismaClient: CMSClient } = require("../../prisma/clients/cms");
const prisma = new CMSClient();
// CONSTANTS
const { badRequestResponse, successResponse, notFoundResponse } = require("../res/responses.js");
// SERVICES
const fileServices = require('../services/file.services.js');
const logger = require('../services/logger.services.js');
const { localTime } = require("../services/time.services.js");
const { default: prefixes } = require('../static/prefix.js');
exports.getMenus = async (req, res) => {
try {
const { isActive } = req.query;
const filter = {};
if (isActive !== undefined) {
filter.IsActive_AM = isActive === 'true';
}
const menus = await prisma.appMenu.findMany({
where: filter,
orderBy: {
Order_AM: 'asc'
}
});
const formattedMenus = menus.map(menu => ({
id: menu.UUID_AM,
name: menu.Name_AM,
route: menu.Route_AM,
icon: menu.Icon_AM,
isActive: menu.IsActive_AM,
badge: menu.Badge_AM,
order: menu.Order_AM,
type: menu.Type_AM,
createdAt: menu.CreatedAt_AM,
updatedAt: menu.UpdatedAt_AM
}));
logger.info(`Retrieved ${formattedMenus.length} menus`);
return successResponse(res, "Menus retrieved successfully", formattedMenus);
} catch (error) {
logger.error(`Error getting menus: ${error.message}`);
return badRequestResponse(res, "Failed to retrieve menus", error.message);
}
};
exports.getMenuById = async (req, res) => {
try {
const { id } = req.params;
const menu = await prisma.appMenu.findUnique({
where: {
UUID_AM: id
}
});
if (!menu) {
logger.warn(`Menu not found with id: ${id}`);
return notFoundResponse(res, "Menu not found", null);
}
const formattedMenu = {
id: menu.UUID_AM,
name: menu.Name_AM,
route: menu.Route_AM,
icon: menu.Icon_AM,
isActive: menu.IsActive_AM,
badge: menu.Badge_AM,
order: menu.Order_AM,
createdAt: menu.CreatedAt_AM,
updatedAt: menu.UpdatedAt_AM
};
logger.info(`Retrieved menu: ${menu.Name_AM}`);
return successResponse(res, "Menu retrieved successfully", formattedMenu);
} catch (error) {
logger.error(`Error getting menu by id: ${error.message}`);
return badRequestResponse(res, "Failed to retrieve menu", error.message);
}
};
exports.createMenu = async (req, res) => {
try {
const { name, route, isActive, badge, order, type } = req.body;
const iconFile = req.files;
if (!name || !route) {
return badRequestResponse(res, "Name and route are required", null);
}
if (type && !['IN_APP_ROUTE', 'WEB_OPEN'].includes(type)) {
return badRequestResponse(res, "Type must be either IN_APP_ROUTE or WEB_OPEN", null);
}
const parsedIsActive = isActive === 'true' || isActive === true;
const parsedOrder = order !== undefined ? parseInt(order, 10) : 0;
if (!iconFile || iconFile.length === 0) {
return badRequestResponse(res, "Icon file is required", null);
}
const existingMenu = await prisma.appMenu.findFirst({
where: {
Route_AM: route
}
});
if (existingMenu) {
return badRequestResponse(res, "Menu with this route already exists", null);
}
const [iconUrl, fileName] = await fileServices.upload(
prefixes.bucketName,
'menu-icons',
iconFile[0].mimetype,
iconFile
);
const menu = await prisma.appMenu.create({
data: {
Name_AM: name,
Route_AM: route,
Icon_AM: iconUrl,
IsActive_AM: parsedIsActive,
Badge_AM: badge || null,
Order_AM: parsedOrder,
Type_AM: type || 'IN_APP_ROUTE',
CreatedAt_AM: localTime(new Date()),
UpdatedAt_AM: localTime(new Date())
}
});
const formattedMenu = {
id: menu.UUID_AM,
name: menu.Name_AM,
route: menu.Route_AM,
icon: menu.Icon_AM,
isActive: menu.IsActive_AM,
badge: menu.Badge_AM,
order: menu.Order_AM,
type: menu.Type_AM,
createdAt: menu.CreatedAt_AM,
updatedAt: menu.UpdatedAt_AM
};
logger.info(`Menu created: ${menu.Name_AM} with icon: ${fileName}`);
return successResponse(res, "Menu created successfully", formattedMenu);
} catch (error) {
logger.error(`Error creating menu: ${error.message}`);
return badRequestResponse(res, "Failed to create menu", error.message);
}
};
exports.updateMenu = async (req, res) => {
try {
const { id } = req.params;
const { name, route, isActive, badge, order, type } = req.body;
const iconFile = req.files;
// Parse FormData values to correct types
const parsedIsActive = isActive !== undefined ? (isActive === 'true' || isActive === true) : undefined;
const parsedOrder = order !== undefined ? parseInt(order, 10) : undefined;
if (type && !['IN_APP_ROUTE', 'WEB_OPEN'].includes(type)) {
return badRequestResponse(res, "Type must be either IN_APP_ROUTE or WEB_OPEN", null);
}
if (type && !['IN_APP_ROUTE', 'WEB_OPEN'].includes(type)) {
return badRequestResponse(res, "Type must be either IN_APP_ROUTE or WEB_OPEN", null);
}
const existingMenu = await prisma.appMenu.findUnique({
where: {
UUID_AM: id
}
});
if (!existingMenu) {
logger.warn(`Menu not found with id: ${id}`);
return notFoundResponse(res, "Menu not found", null);
}
if (route && route !== existingMenu.Route_AM) {
const duplicateRoute = await prisma.appMenu.findFirst({
where: {
Route_AM: route,
UUID_AM: {
not: id
}
}
});
if (duplicateRoute) {
return badRequestResponse(res, "Menu with this route already exists", null);
}
}
const updateData = {};
if (name !== undefined) updateData.Name_AM = name;
if (route !== undefined) updateData.Route_AM = route;
if (parsedIsActive !== undefined) updateData.IsActive_AM = parsedIsActive;
if (badge !== undefined) updateData.Badge_AM = badge;
if (parsedOrder !== undefined) updateData.Order_AM = parsedOrder;
if (type !== undefined) updateData.Type_AM = type;
updateData.UpdatedAt_AM = localTime(new Date());
if (iconFile && iconFile.length > 0) {
const [iconUrl, fileName] = await fileServices.upload(
prefixes.bucketName,
'menu-icons',
iconFile[0].mimetype,
iconFile
);
updateData.Icon_AM = iconUrl;
logger.info(`New icon uploaded: ${fileName}`);
}
const menu = await prisma.appMenu.update({
where: {
UUID_AM: id
},
data: updateData
});
const formattedMenu = {
id: menu.UUID_AM,
name: menu.Name_AM,
route: menu.Route_AM,
icon: menu.Icon_AM,
isActive: menu.IsActive_AM,
badge: menu.Badge_AM,
order: menu.Order_AM,
type: menu.Type_AM,
createdAt: menu.CreatedAt_AM,
updatedAt: menu.UpdatedAt_AM
};
logger.info(`Menu updated: ${menu.Name_AM}`);
return successResponse(res, "Menu updated successfully", formattedMenu);
} catch (error) {
logger.error(`Error updating menu: ${error.message}`);
return badRequestResponse(res, "Failed to update menu", error.message);
}
};
exports.deleteMenu = async (req, res) => {
try {
const { id } = req.params;
const existingMenu = await prisma.appMenu.findUnique({
where: {
UUID_AM: id
}
});
if (!existingMenu) {
logger.warn(`Menu not found with id: ${id}`);
return notFoundResponse(res, "Menu not found", null);
}
await prisma.appMenu.delete({
where: {
UUID_AM: id
}
});
logger.info(`Menu deleted: ${existingMenu.Name_AM}`);
return successResponse(res, "Menu deleted successfully", null);
} catch (error) {
logger.error(`Error deleting menu: ${error.message}`);
return badRequestResponse(res, "Failed to delete menu", error.message);
}
};
exports.reorderMenus = async (req, res) => {
try {
const { menuOrders } = req.body;
if (!Array.isArray(menuOrders) || menuOrders.length === 0) {
return badRequestResponse(res, "menuOrders array is required", null);
}
const updatePromises = menuOrders.map(({ id, order }) =>
prisma.appMenu.update({
where: {
UUID_AM: id
},
data: {
Order_AM: order
}
})
);
await Promise.all(updatePromises);
logger.info(`Reordered ${menuOrders.length} menus`);
return successResponse(res, "Menus reordered successfully", null);
} catch (error) {
logger.error(`Error reordering menus: ${error.message}`);
return badRequestResponse(res, "Failed to reorder menus", error.message);
}
};