samoulla-backend / controllers /categoryController.js
Samoulla Sync Bot
Auto-deploy Samoulla Backend: b68e45770de26ed39feb4b1c0925e5345eb3a61d
634b9bb
const Category = require('../models/categoryModel');
// Get all categories (optionally filter by parent to get root categories or subcategories)
exports.getAllCategories = async (req, res) => {
try {
const { parentId } = req.query;
// Build filter - if parentId is 'root' or null, get root categories
let filter = {};
if (parentId === 'root' || parentId === 'null') {
filter.parent = null;
} else if (parentId) {
filter.parent = parentId;
}
const categories = await Category.find(filter)
.populate('parent', 'nameAr nameEn slug')
.lean();
res.status(200).json({
status: 'success',
results: categories.length,
data: {
categories,
},
});
} catch (err) {
res.status(500).json({
status: 'fail',
message: err.message,
});
}
};
// Get single category with parent and children
exports.getCategory = async (req, res) => {
try {
const category = await Category.findById(req.params.id)
.populate('parent', 'nameAr nameEn slug')
.populate('children', 'nameAr nameEn slug level')
.lean();
if (!category) {
return res.status(404).json({
status: 'fail',
message: 'No category found with that ID',
});
}
res.status(200).json({
status: 'success',
data: { category },
});
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Create a new category
exports.createCategory = async (req, res) => {
try {
const lastCategory = await Category.findOne().sort({ id: -1 });
const autoId = lastCategory ? lastCategory.id + 1 : 1;
const newCategory = await Category.create({
// eslint-disable-next-line node/no-unsupported-features/es-syntax
...req.body,
id: req.body.id || autoId,
});
res.status(201).json({
status: 'success',
data: { category: newCategory },
});
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Update a category
exports.updateCategory = async (req, res) => {
try {
const updatedCategory = await Category.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, runValidators: true },
);
if (!updatedCategory) {
return res.status(404).json({
status: 'fail',
message: 'No category found with that ID',
});
}
res.status(200).json({
status: 'success',
data: { category: updatedCategory },
});
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Delete a category
exports.deleteCategory = async (req, res) => {
try {
// First check if category has children
const childrenCount = await Category.countDocuments({
parent: req.params.id,
});
if (childrenCount > 0) {
return res.status(400).json({
status: 'fail',
message:
'Cannot delete category with subcategories. Delete subcategories first.',
});
}
const category = await Category.findByIdAndDelete(req.params.id);
if (!category) {
return res.status(404).json({
status: 'fail',
message: 'No category found with that ID',
});
}
res.status(204).json({
status: 'success',
data: null,
});
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Get all subcategories of a specific category
exports.getSubcategories = async (req, res) => {
try {
const subcategories = await Category.find({ parent: req.params.id }).lean();
res.status(200).json({
status: 'success',
results: subcategories.length,
data: {
subcategories,
},
});
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Get full category tree (hierarchical structure)
exports.getCategoryTree = async (req, res) => {
try {
// Fetch all categories once to build tree in memory
const allCategories = await Category.find().lean();
const categoryMap = {};
allCategories.forEach((cat) => {
categoryMap[cat._id.toString()] = { ...cat, children: [] };
});
const tree = [];
allCategories.forEach((cat) => {
const catObj = categoryMap[cat._id.toString()];
if (cat.parent) {
const parentId = cat.parent.toString();
if (categoryMap[parentId]) {
categoryMap[parentId].children.push(catObj);
}
} else {
tree.push(catObj);
}
});
res.status(200).json({
status: 'success',
results: tree.length,
data: {
categories: tree,
},
});
} catch (err) {
res.status(500).json({
status: 'fail',
message: err.message,
});
}
};