hMarket Trae ilk versiyon
This commit is contained in:
653
backend/src/routes/items.js
Normal file
653
backend/src/routes/items.js
Normal file
@@ -0,0 +1,653 @@
|
||||
const express = require('express');
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const { authenticateToken, checkListMembership, requireListEditPermission } = require('../middleware/auth');
|
||||
const { asyncHandler } = require('../middleware/errorHandler');
|
||||
const {
|
||||
validateListItemCreation,
|
||||
validateListItemUpdate,
|
||||
validateUUIDParam,
|
||||
validateCuidParam,
|
||||
validateCuid,
|
||||
validatePagination
|
||||
} = require('../utils/validators');
|
||||
const { validationResult, param } = require('express-validator');
|
||||
const { successResponse, errorResponse, calculatePagination, createPaginationMeta } = require('../utils/helpers');
|
||||
const notificationService = require('../services/notificationService');
|
||||
|
||||
const router = express.Router();
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
/**
|
||||
* Liste öğelerini getir
|
||||
* GET /api/items/:listId
|
||||
*/
|
||||
router.get('/:listId',
|
||||
authenticateToken,
|
||||
param('listId').custom(validateCuid).withMessage('Geçerli bir liste ID\'si girin'),
|
||||
validatePagination,
|
||||
checkListMembership,
|
||||
asyncHandler(async (req, res) => {
|
||||
console.log('🔍 Items API called with params:', req.params);
|
||||
console.log('🔍 Items API called with query:', req.query);
|
||||
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
console.log('❌ Validation errors:', errors.array());
|
||||
return res.status(400).json(errorResponse('Doğrulama hatası', errors.array()));
|
||||
}
|
||||
|
||||
const { listId } = req.params;
|
||||
const { page = 1, limit = 50, category, purchased, search } = req.query;
|
||||
const { skip, take } = calculatePagination(page, limit);
|
||||
|
||||
// Filtreleme koşulları
|
||||
const where = {
|
||||
listId
|
||||
};
|
||||
|
||||
if (category) {
|
||||
where.product = {
|
||||
categoryId: category
|
||||
};
|
||||
}
|
||||
|
||||
if (purchased !== undefined) {
|
||||
where.isPurchased = purchased === 'true';
|
||||
}
|
||||
|
||||
if (search) {
|
||||
where.OR = [
|
||||
{ name: { contains: search, mode: 'insensitive' } },
|
||||
{ notes: { contains: search, mode: 'insensitive' } },
|
||||
{ product: { name: { contains: search, mode: 'insensitive' } } }
|
||||
];
|
||||
}
|
||||
|
||||
console.log('🔍 Database where conditions:', JSON.stringify(where, null, 2));
|
||||
console.log('🔍 Pagination - skip:', skip, 'take:', take);
|
||||
|
||||
// Toplam sayı ve öğeleri getir
|
||||
const [total, items] = await Promise.all([
|
||||
prisma.listItem.count({ where }),
|
||||
prisma.listItem.findMany({
|
||||
where,
|
||||
skip,
|
||||
take,
|
||||
include: {
|
||||
product: {
|
||||
include: {
|
||||
category: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: [
|
||||
{ isPurchased: 'asc' },
|
||||
{ createdAt: 'desc' }
|
||||
]
|
||||
})
|
||||
]);
|
||||
|
||||
const meta = createPaginationMeta(total, parseInt(page), parseInt(limit));
|
||||
|
||||
// Priority değerlerini string'e çevir
|
||||
const itemsWithStringPriority = items.map(item => ({
|
||||
...item,
|
||||
priority: item.priority === 0 ? 'LOW' : item.priority === 1 ? 'MEDIUM' : 'HIGH'
|
||||
}));
|
||||
|
||||
res.json(successResponse('Liste öğeleri başarıyla getirildi', itemsWithStringPriority, meta));
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Liste öğesi detayını getir
|
||||
* GET /api/items/:listId/:itemId
|
||||
*/
|
||||
router.get('/:listId/:itemId',
|
||||
authenticateToken,
|
||||
param('listId').custom(validateCuid).withMessage('Geçerli bir liste ID\'si girin'),
|
||||
param('itemId').custom(validateCuid).withMessage('Geçerli bir öğe ID\'si girin'),
|
||||
checkListMembership,
|
||||
asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json(errorResponse('Doğrulama hatası', errors.array()));
|
||||
}
|
||||
|
||||
const { listId, itemId } = req.params;
|
||||
|
||||
const item = await prisma.listItem.findFirst({
|
||||
where: {
|
||||
id: itemId,
|
||||
listId
|
||||
},
|
||||
include: {
|
||||
product: {
|
||||
include: {
|
||||
category: true,
|
||||
priceHistory: {
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
addedBy: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
firstName: true,
|
||||
lastName: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!item) {
|
||||
return res.status(404).json(errorResponse('Liste öğesi bulunamadı'));
|
||||
}
|
||||
|
||||
// Priority değerini string'e çevir
|
||||
const itemWithStringPriority = {
|
||||
...item,
|
||||
priority: item.priority === 0 ? 'LOW' : item.priority === 1 ? 'MEDIUM' : 'HIGH'
|
||||
};
|
||||
|
||||
res.json(successResponse('Liste öğesi detayı başarıyla getirildi', itemWithStringPriority));
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Listeye öğe ekle
|
||||
* POST /api/items/:listId
|
||||
*/
|
||||
router.post('/:listId',
|
||||
authenticateToken,
|
||||
param('listId').custom(validateCuid).withMessage('Geçerli bir liste ID\'si girin'),
|
||||
validateListItemCreation,
|
||||
checkListMembership,
|
||||
requireListEditPermission,
|
||||
asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json(errorResponse('Doğrulama hatası', errors.array()));
|
||||
}
|
||||
|
||||
const { listId } = req.params;
|
||||
const { name, quantity = 1, unit, notes, productId, estimatedPrice } = req.body;
|
||||
const userId = req.user.id;
|
||||
|
||||
// Eğer productId verilmişse, ürünün var olduğunu kontrol et
|
||||
let product = null;
|
||||
if (productId) {
|
||||
product = await prisma.product.findUnique({
|
||||
where: { id: productId }
|
||||
});
|
||||
|
||||
if (!product) {
|
||||
return res.status(404).json(errorResponse('Ürün bulunamadı'));
|
||||
}
|
||||
}
|
||||
|
||||
// Aynı öğenin listede zaten var olup olmadığını kontrol et
|
||||
const existingItem = await prisma.listItem.findFirst({
|
||||
where: {
|
||||
listId,
|
||||
OR: [
|
||||
{ productId: productId || undefined },
|
||||
{ customName: productId ? undefined : name }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (existingItem) {
|
||||
return res.status(409).json(errorResponse('Bu öğe zaten listede mevcut'));
|
||||
}
|
||||
|
||||
// Yeni öğe oluştur
|
||||
const newItem = await prisma.listItem.create({
|
||||
data: {
|
||||
customName: productId ? product.name : name,
|
||||
quantity,
|
||||
unit: unit || "adet",
|
||||
note: notes,
|
||||
price: estimatedPrice,
|
||||
listId,
|
||||
productId
|
||||
},
|
||||
include: {
|
||||
product: {
|
||||
include: {
|
||||
category: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Ürün kullanım sayısını artır (Product modelinde usageCount alanı yok, bu özellik kaldırıldı)
|
||||
|
||||
// Liste güncelleme tarihini güncelle
|
||||
await prisma.shoppingList.update({
|
||||
where: { id: listId },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
|
||||
// Aktivite kaydı oluştur
|
||||
await prisma.activity.create({
|
||||
data: {
|
||||
action: 'item_added',
|
||||
details: {
|
||||
itemId: newItem.id,
|
||||
itemName: newItem.customName || newItem.product?.name || 'Öğe',
|
||||
userName: `${req.user.firstName} ${req.user.lastName}`
|
||||
},
|
||||
userId,
|
||||
listId
|
||||
}
|
||||
});
|
||||
|
||||
// Liste üyelerine bildirim gönder (geçici olarak devre dışı - notifyListMembers fonksiyonu mevcut değil)
|
||||
// await notificationService.notifyListMembers(
|
||||
// listId,
|
||||
// userId,
|
||||
// 'ITEM_ADDED',
|
||||
// `${req.user.firstName} ${req.user.lastName} listeye "${newItem.customName || newItem.product?.name || 'Öğe'}" öğesini ekledi`,
|
||||
// { itemId: newItem.id, itemName: newItem.customName || newItem.product?.name }
|
||||
// );
|
||||
|
||||
// Socket.IO ile gerçek zamanlı güncelleme
|
||||
const io = req.app.get('io');
|
||||
if (io) {
|
||||
io.to(`list_${listId}`).emit('itemAdded', {
|
||||
item: newItem,
|
||||
addedBy: req.user
|
||||
});
|
||||
}
|
||||
|
||||
// Priority değerini string'e çevir
|
||||
const newItemWithStringPriority = {
|
||||
...newItem,
|
||||
priority: newItem.priority === 0 ? 'LOW' : newItem.priority === 1 ? 'MEDIUM' : 'HIGH'
|
||||
};
|
||||
|
||||
res.status(201).json(successResponse('Öğe başarıyla eklendi', newItemWithStringPriority));
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Liste öğesini güncelle
|
||||
* PUT /api/items/:listId/:itemId
|
||||
*/
|
||||
router.put('/:listId/:itemId',
|
||||
authenticateToken,
|
||||
param('listId').custom(validateCuid).withMessage('Geçerli bir liste ID\'si girin'),
|
||||
param('itemId').custom(validateCuid).withMessage('Geçerli bir öğe ID\'si girin'),
|
||||
validateListItemUpdate,
|
||||
checkListMembership,
|
||||
// Sadece isPurchased güncellemesi değilse edit yetkisi gerekli
|
||||
(req, res, next) => {
|
||||
const { name, quantity, unit, notes, price, priority } = req.body;
|
||||
const isOnlyPurchaseUpdate = !name && !quantity && !unit && !notes && !price && !priority;
|
||||
|
||||
if (isOnlyPurchaseUpdate) {
|
||||
// Sadece isPurchased güncellemesi - tüm üyeler yapabilir
|
||||
return next();
|
||||
} else {
|
||||
// Diğer alanlar güncelleniyor - edit yetkisi gerekli
|
||||
const allowedRoles = ['owner', 'admin'];
|
||||
if (!allowedRoles.includes(req.userRole)) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: 'Bu işlem için yeterli yetkiniz yok.'
|
||||
});
|
||||
}
|
||||
return next();
|
||||
}
|
||||
},
|
||||
asyncHandler(async (req, res) => {
|
||||
console.log('🔍 PUT /api/items/:listId/:itemId başladı');
|
||||
console.log('📝 Request params:', req.params);
|
||||
console.log('📝 Request body:', req.body);
|
||||
console.log('👤 User ID:', req.user.id);
|
||||
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
console.log('❌ Validation errors:', errors.array());
|
||||
return res.status(400).json(errorResponse('Doğrulama hatası', errors.array()));
|
||||
}
|
||||
|
||||
const { listId, itemId } = req.params;
|
||||
const { name, quantity, unit, notes, isPurchased, price, priority } = req.body;
|
||||
const userId = req.user.id;
|
||||
|
||||
// Öğenin var olduğunu kontrol et
|
||||
console.log('🔍 Öğe aranıyor:', { itemId, listId });
|
||||
const existingItem = await prisma.listItem.findFirst({
|
||||
where: {
|
||||
id: itemId,
|
||||
listId
|
||||
},
|
||||
include: {
|
||||
product: true
|
||||
}
|
||||
});
|
||||
|
||||
if (!existingItem) {
|
||||
console.log('❌ Öğe bulunamadı');
|
||||
return res.status(404).json(errorResponse('Liste öğesi bulunamadı'));
|
||||
}
|
||||
|
||||
console.log('✅ Öğe bulundu:', existingItem.name);
|
||||
|
||||
// Güncelleme verilerini hazırla
|
||||
const updateData = {};
|
||||
if (name !== undefined) updateData.customName = name;
|
||||
if (quantity !== undefined) updateData.quantity = quantity;
|
||||
if (unit !== undefined) updateData.unit = unit;
|
||||
if (notes !== undefined) updateData.note = notes;
|
||||
if (price !== undefined) updateData.price = price;
|
||||
if (priority !== undefined) {
|
||||
// Priority string'i sayıya çevir
|
||||
const priorityMap = { 'LOW': 0, 'MEDIUM': 1, 'HIGH': 2 };
|
||||
updateData.priority = priorityMap[priority] !== undefined ? priorityMap[priority] : 1;
|
||||
}
|
||||
|
||||
// Satın alma durumu değişikliği
|
||||
if (isPurchased !== undefined && isPurchased !== existingItem.isPurchased) {
|
||||
updateData.isPurchased = isPurchased;
|
||||
if (isPurchased) {
|
||||
updateData.purchasedAt = new Date();
|
||||
updateData.purchasedBy = userId;
|
||||
} else {
|
||||
updateData.purchasedAt = null;
|
||||
updateData.purchasedBy = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Öğeyi güncelle
|
||||
const updatedItem = await prisma.listItem.update({
|
||||
where: { id: itemId },
|
||||
data: updateData,
|
||||
include: {
|
||||
product: {
|
||||
include: {
|
||||
category: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Fiyat geçmişi ekle (eğer fiyat girilmişse ve ürün varsa)
|
||||
if (price && existingItem.productId && isPurchased) {
|
||||
await prisma.priceHistory.create({
|
||||
data: {
|
||||
price: price,
|
||||
productId: existingItem.productId,
|
||||
userId,
|
||||
location: 'Market' // Varsayılan konum
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Liste güncelleme tarihini güncelle
|
||||
await prisma.shoppingList.update({
|
||||
where: { id: listId },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
|
||||
// Aktivite kaydı oluştur
|
||||
let activityDescription = `${req.user.firstName} ${req.user.lastName} "${updatedItem.name}" öğesini güncelledi`;
|
||||
if (isPurchased !== undefined) {
|
||||
activityDescription = isPurchased
|
||||
? `${req.user.firstName} ${req.user.lastName} "${updatedItem.name}" öğesini satın aldı`
|
||||
: `${req.user.firstName} ${req.user.lastName} "${updatedItem.name}" öğesinin satın alma durumunu iptal etti`;
|
||||
}
|
||||
|
||||
await prisma.activity.create({
|
||||
data: {
|
||||
action: isPurchased !== undefined ? (isPurchased ? 'ITEM_PURCHASED' : 'ITEM_UNPURCHASED') : 'ITEM_UPDATED',
|
||||
details: {
|
||||
description: activityDescription,
|
||||
itemId: updatedItem.id,
|
||||
itemName: updatedItem.name
|
||||
},
|
||||
userId,
|
||||
listId
|
||||
}
|
||||
});
|
||||
|
||||
// Liste üyelerine bildirim gönder (sadece satın alma durumu değişikliğinde)
|
||||
if (isPurchased !== undefined) {
|
||||
await notificationService.notifyListMembers(
|
||||
listId,
|
||||
userId,
|
||||
{
|
||||
type: isPurchased ? 'ITEM_PURCHASED' : 'ITEM_UNPURCHASED',
|
||||
message: activityDescription,
|
||||
data: { itemId: updatedItem.id, itemName: updatedItem.name }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Socket.IO ile gerçek zamanlı güncelleme
|
||||
const io = req.app.get('io');
|
||||
if (io) {
|
||||
io.to(`list_${listId}`).emit('itemUpdated', {
|
||||
item: updatedItem,
|
||||
updatedBy: req.user
|
||||
});
|
||||
}
|
||||
|
||||
// Priority değerini string'e çevir
|
||||
const updatedItemWithStringPriority = {
|
||||
...updatedItem,
|
||||
priority: updatedItem.priority === 0 ? 'LOW' : updatedItem.priority === 1 ? 'MEDIUM' : 'HIGH'
|
||||
};
|
||||
|
||||
res.json(successResponse('Öğe başarıyla güncellendi', updatedItemWithStringPriority));
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Liste öğesini sil
|
||||
* DELETE /api/items/:listId/:itemId
|
||||
*/
|
||||
router.delete('/:listId/:itemId',
|
||||
authenticateToken,
|
||||
param('listId').custom(validateCuid).withMessage('Geçerli bir liste ID\'si girin'),
|
||||
param('itemId').custom(validateCuid).withMessage('Geçerli bir öğe ID\'si girin'),
|
||||
checkListMembership,
|
||||
requireListEditPermission,
|
||||
asyncHandler(async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json(errorResponse('Doğrulama hatası', errors.array()));
|
||||
}
|
||||
|
||||
const { listId, itemId } = req.params;
|
||||
const userId = req.user.id;
|
||||
|
||||
// Öğenin var olduğunu kontrol et
|
||||
const existingItem = await prisma.listItem.findFirst({
|
||||
where: {
|
||||
id: itemId,
|
||||
listId
|
||||
}
|
||||
});
|
||||
|
||||
if (!existingItem) {
|
||||
return res.status(404).json(errorResponse('Liste öğesi bulunamadı'));
|
||||
}
|
||||
|
||||
// Öğeyi sil
|
||||
await prisma.listItem.delete({
|
||||
where: { id: itemId }
|
||||
});
|
||||
|
||||
// Liste güncelleme tarihini güncelle
|
||||
await prisma.shoppingList.update({
|
||||
where: { id: listId },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
|
||||
// Aktivite kaydı oluştur (Prisma şemasına uygun)
|
||||
const itemName = existingItem.customName || existingItem.product?.name || 'Öğe';
|
||||
await prisma.activity.create({
|
||||
data: {
|
||||
action: 'ITEM_REMOVED',
|
||||
details: {
|
||||
description: `${req.user.firstName} ${req.user.lastName} "${itemName}" öğesini listeden kaldırdı`,
|
||||
itemId: existingItem.id,
|
||||
itemName: itemName
|
||||
},
|
||||
userId,
|
||||
listId
|
||||
}
|
||||
});
|
||||
|
||||
// Liste üyelerine bildirim gönder
|
||||
await notificationService.notifyListMembers(
|
||||
listId,
|
||||
userId,
|
||||
{
|
||||
type: 'ITEM_REMOVED',
|
||||
message: `${req.user.firstName} ${req.user.lastName} "${itemName}" öğesini listeden kaldırdı`,
|
||||
data: { itemId: existingItem.id, itemName: itemName }
|
||||
}
|
||||
);
|
||||
|
||||
// Socket.IO ile gerçek zamanlı güncelleme
|
||||
const io = req.app.get('io');
|
||||
if (io) {
|
||||
io.to(`list_${listId}`).emit('itemRemoved', {
|
||||
itemId: existingItem.id,
|
||||
itemName: existingItem.name,
|
||||
removedBy: req.user
|
||||
});
|
||||
}
|
||||
|
||||
res.json(successResponse('Öğe başarıyla silindi'));
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* Birden fazla öğeyi toplu güncelle
|
||||
* PATCH /api/items/:listId/bulk
|
||||
*/
|
||||
router.patch('/:listId/bulk',
|
||||
authenticateToken,
|
||||
validateCuidParam('listId'),
|
||||
requireListEditPermission,
|
||||
asyncHandler(async (req, res) => {
|
||||
const { listId } = req.params;
|
||||
const { items, action } = req.body; // items: [itemId1, itemId2], action: 'purchase' | 'unpurchase' | 'delete'
|
||||
const userId = req.user.id;
|
||||
|
||||
if (!items || !Array.isArray(items) || items.length === 0) {
|
||||
return res.status(400).json(errorResponse('Geçerli öğe listesi gerekli'));
|
||||
}
|
||||
|
||||
if (!['purchase', 'unpurchase', 'delete'].includes(action)) {
|
||||
return res.status(400).json(errorResponse('Geçerli bir işlem seçin'));
|
||||
}
|
||||
|
||||
// Öğelerin var olduğunu kontrol et
|
||||
const existingItems = await prisma.listItem.findMany({
|
||||
where: {
|
||||
id: { in: items },
|
||||
listId
|
||||
}
|
||||
});
|
||||
|
||||
if (existingItems.length !== items.length) {
|
||||
return res.status(404).json(errorResponse('Bazı öğeler bulunamadı'));
|
||||
}
|
||||
|
||||
let updateData = {};
|
||||
let activityType = '';
|
||||
let activityDescription = '';
|
||||
|
||||
switch (action) {
|
||||
case 'purchase':
|
||||
updateData = {
|
||||
isPurchased: true,
|
||||
purchasedAt: new Date(),
|
||||
purchasedById: userId
|
||||
};
|
||||
activityType = 'ITEMS_PURCHASED';
|
||||
activityDescription = `${req.user.firstName} ${req.user.lastName} ${existingItems.length} öğeyi satın aldı`;
|
||||
break;
|
||||
case 'unpurchase':
|
||||
updateData = {
|
||||
isPurchased: false,
|
||||
purchasedAt: null,
|
||||
purchasedBy: null
|
||||
};
|
||||
activityType = 'ITEMS_UNPURCHASED';
|
||||
activityDescription = `${req.user.firstName} ${req.user.lastName} ${existingItems.length} öğenin satın alma durumunu iptal etti`;
|
||||
break;
|
||||
case 'delete':
|
||||
activityType = 'ITEMS_REMOVED';
|
||||
activityDescription = `${req.user.firstName} ${req.user.lastName} ${existingItems.length} öğeyi listeden kaldırdı`;
|
||||
break;
|
||||
}
|
||||
|
||||
// Toplu güncelleme veya silme
|
||||
if (action === 'delete') {
|
||||
await prisma.listItem.deleteMany({
|
||||
where: {
|
||||
id: { in: items },
|
||||
listId
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await prisma.listItem.updateMany({
|
||||
where: {
|
||||
id: { in: items },
|
||||
listId
|
||||
},
|
||||
data: updateData
|
||||
});
|
||||
}
|
||||
|
||||
// Liste güncelleme tarihini güncelle
|
||||
await prisma.shoppingList.update({
|
||||
where: { id: listId },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
|
||||
// Aktivite kaydı oluştur
|
||||
await prisma.activity.create({
|
||||
data: {
|
||||
type: activityType,
|
||||
description: activityDescription,
|
||||
userId,
|
||||
listId
|
||||
}
|
||||
});
|
||||
|
||||
// Liste üyelerine bildirim gönder
|
||||
await notificationService.notifyListMembers(
|
||||
listId,
|
||||
userId,
|
||||
{
|
||||
type: activityType,
|
||||
message: activityDescription,
|
||||
data: { itemCount: existingItems.length }
|
||||
}
|
||||
);
|
||||
|
||||
// Socket.IO ile gerçek zamanlı güncelleme
|
||||
const io = req.app.get('io');
|
||||
if (io) {
|
||||
io.to(`list_${listId}`).emit('itemsBulkUpdated', {
|
||||
items: items,
|
||||
action: action,
|
||||
updatedBy: req.user
|
||||
});
|
||||
}
|
||||
|
||||
res.json(successResponse(`${existingItems.length} öğe başarıyla ${action === 'purchase' ? 'satın alındı' : action === 'unpurchase' ? 'satın alma iptal edildi' : 'silindi'}`));
|
||||
})
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user