File size: 3,883 Bytes
1e480b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
const Category = require('../models/Category');
const MenuItem = require('../models/MenuItem');
const { uploadMenuImage } = require('../config/cloudinary');

// GET /api/menu/all β€” returns categories + their items (used for offline cache seeding)
exports.getAll = async (req, res) => {
  const [categories, items] = await Promise.all([
    Category.find({ hidden: false }).sort({ order: 1, name: 1 }),
    MenuItem.find().populate('category', 'name order').sort({ name: 1 }),
  ]);
  res.json({ categories, items });
};

// ── Categories ──────────────────────────────────────────────

exports.getCategories = async (req, res) => {
  const cats = await Category.find().sort({ order: 1, name: 1 });
  res.json(cats);
};

exports.createCategory = async (req, res) => {
  const { name, order, hidden } = req.body;
  const cat = await Category.create({ name, order: order ?? 0, hidden: hidden ?? false });
  res.status(201).json(cat);
};

exports.updateCategory = async (req, res) => {
  const cat = await Category.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
  if (!cat) return res.status(404).json({ message: 'Category not found' });
  res.json(cat);
};

exports.deleteCategory = async (req, res) => {
  const count = await MenuItem.countDocuments({ category: req.params.id });
  if (count > 0) return res.status(400).json({ message: `Cannot delete: ${count} menu item(s) use this category` });
  await Category.findByIdAndDelete(req.params.id);
  res.json({ message: 'Category deleted' });
};

// ── Menu Items ───────────────────────────────────────────────

exports.createItem = async (req, res) => {
  const { name, category, variants, available } = req.body;
  const parsedVariants = typeof variants === 'string' ? JSON.parse(variants) : variants;
  const image = req.file ? req.file.path : null; // Cloudinary URL

  const item = await MenuItem.create({ name, category, variants: parsedVariants, available: available ?? true, image });
  await item.populate('category', 'name order');
  res.status(201).json(item);
};

exports.updateItem = async (req, res) => {
  const { variants, ...rest } = req.body;
  const update = { ...rest };
  if (variants) update.variants = typeof variants === 'string' ? JSON.parse(variants) : variants;
  if (req.file) update.image = req.file.path;

  const item = await MenuItem.findByIdAndUpdate(req.params.id, update, { new: true, runValidators: true }).populate('category', 'name order');
  if (!item) return res.status(404).json({ message: 'Item not found' });
  res.json(item);
};

exports.deleteItem = async (req, res) => {
  const item = await MenuItem.findByIdAndDelete(req.params.id);
  if (!item) return res.status(404).json({ message: 'Item not found' });
  res.json({ message: 'Item deleted' });
};

exports.toggleAvailability = async (req, res) => {
  const { available, variantId } = req.body;
  const item = await MenuItem.findById(req.params.id);
  if (!item) return res.status(404).json({ message: 'Item not found' });

  if (variantId) {
    // Toggle a specific variant
    const variant = item.variants.id(variantId);
    if (!variant) return res.status(404).json({ message: 'Variant not found' });
    variant.available = available ?? !variant.available;
  } else {
    // Toggle the whole item
    item.available = available ?? !item.available;
  }

  await item.save();
  res.json(item);
};

// POST /api/menu/upload-image β€” standalone image upload (returns URL for use in create/update)
exports.uploadImage = [
  uploadMenuImage.single('image'),
  (req, res) => {
    if (!req.file) return res.status(400).json({ message: 'No image uploaded' });
    res.json({ url: req.file.path });
  },
];