321 lines
9.9 KiB
JavaScript
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);
|
|
}
|
|
};
|