passo 3
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
const Ride = require('../models/Ride');
|
const Ride = require('../models/Ride');
|
||||||
const { User } = require('../models/user');
|
const { User } = require('../models/user');
|
||||||
const RideRequest = require('../models/RideRequest');
|
const RideRequest = require('../models/RideRequest');
|
||||||
|
const Feedback = require('../models/Feedback');
|
||||||
|
const Chat = require('../models/Chat');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Crea un nuovo viaggio (offerta o richiesta)
|
* @desc Crea un nuovo viaggio (offerta o richiesta)
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
const RideRequest = require('../models/RideRequest');
|
const RideRequest = require('../models/RideRequest');
|
||||||
const Ride = require('../models/Ride');
|
const Ride = require('../models/Ride');
|
||||||
const Chat = require('../models/Chat');
|
const Chat = require('../models/Chat');
|
||||||
const Message = require('../models/Message');
|
const Message = require('../models/Message');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper per convertire ID in ObjectId
|
||||||
|
*/
|
||||||
|
const toObjectId = (id) => {
|
||||||
|
if (!id) return null;
|
||||||
|
if (id instanceof mongoose.Types.ObjectId) return id;
|
||||||
|
if (typeof id === 'object' && id._id) {
|
||||||
|
return new mongoose.Types.ObjectId(id._id.toString());
|
||||||
|
}
|
||||||
|
return new mongoose.Types.ObjectId(id.toString());
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Crea una richiesta di passaggio
|
* @desc Crea una richiesta di passaggio
|
||||||
* @route POST /api/viaggi/requests
|
* @route POST /api/viaggi/requests
|
||||||
@@ -11,7 +24,6 @@ const Message = require('../models/Message');
|
|||||||
const createRequest = async (req, res) => {
|
const createRequest = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
idapp,
|
|
||||||
rideId,
|
rideId,
|
||||||
message,
|
message,
|
||||||
pickupPoint,
|
pickupPoint,
|
||||||
@@ -29,6 +41,7 @@ const createRequest = async (req, res) => {
|
|||||||
contribution,
|
contribution,
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
|
const idapp = req.body.idapp || req.query.idapp || req.user?.idapp;
|
||||||
const passengerId = req.user._id;
|
const passengerId = req.user._id;
|
||||||
|
|
||||||
// Validazione
|
// Validazione
|
||||||
@@ -72,10 +85,10 @@ const createRequest = async (req, res) => {
|
|||||||
|
|
||||||
// Verifica disponibilità posti
|
// Verifica disponibilità posti
|
||||||
const seats = seatsRequested || 1;
|
const seats = seatsRequested || 1;
|
||||||
if (ride.type === 'offer' && ride.passengers.available < seats) {
|
if (ride.type === 'offer' && ride.passengers?.available < seats) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: `Posti insufficienti. Disponibili: ${ride.passengers.available}`,
|
message: `Posti insufficienti. Disponibili: ${ride.passengers?.available || 0}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,22 +129,40 @@ const createRequest = async (req, res) => {
|
|||||||
await rideRequest.populate('rideId', 'departure destination dateTime');
|
await rideRequest.populate('rideId', 'departure destination dateTime');
|
||||||
|
|
||||||
// Crea o recupera la chat tra passeggero e conducente
|
// Crea o recupera la chat tra passeggero e conducente
|
||||||
const chat = await Chat.findOrCreateDirect(idapp, passengerId, ride.userId, rideId);
|
let chat;
|
||||||
|
let chatId = null;
|
||||||
|
|
||||||
// Invia messaggio automatico nella chat
|
try {
|
||||||
if (message) {
|
chat = await Chat.findOrCreateDirect(idapp, passengerId, ride.userId, rideId);
|
||||||
const chatMessage = new Message({
|
chatId = chat._id;
|
||||||
idapp,
|
|
||||||
chatId: chat._id,
|
// Invia messaggio automatico nella chat
|
||||||
senderId: passengerId,
|
if (message) {
|
||||||
text: message,
|
const chatMessage = new Message({
|
||||||
type: 'ride_request',
|
idapp,
|
||||||
metadata: {
|
chatId: chat._id,
|
||||||
rideId,
|
senderId: passengerId,
|
||||||
rideRequestId: rideRequest._id,
|
text: message,
|
||||||
},
|
type: 'ride_request',
|
||||||
});
|
metadata: {
|
||||||
await chatMessage.save();
|
rideId,
|
||||||
|
rideRequestId: rideRequest._id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await chatMessage.save();
|
||||||
|
|
||||||
|
// Aggiorna lastMessage della chat
|
||||||
|
chat.lastMessage = {
|
||||||
|
text: message.substring(0, 100),
|
||||||
|
senderId: passengerId,
|
||||||
|
timestamp: new Date(),
|
||||||
|
type: 'ride_request',
|
||||||
|
};
|
||||||
|
await chat.save();
|
||||||
|
}
|
||||||
|
} catch (chatError) {
|
||||||
|
console.error('Errore creazione chat:', chatError);
|
||||||
|
// Non bloccare la creazione della richiesta se la chat fallisce
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Inviare notifica push al conducente
|
// TODO: Inviare notifica push al conducente
|
||||||
@@ -140,7 +171,7 @@ const createRequest = async (req, res) => {
|
|||||||
success: true,
|
success: true,
|
||||||
message: 'Richiesta di passaggio inviata!',
|
message: 'Richiesta di passaggio inviata!',
|
||||||
data: rideRequest,
|
data: rideRequest,
|
||||||
chatId: chat._id,
|
chatId,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Errore creazione richiesta:', error);
|
console.error('Errore creazione richiesta:', error);
|
||||||
@@ -160,9 +191,17 @@ const createRequest = async (req, res) => {
|
|||||||
const getRequestsForRide = async (req, res) => {
|
const getRequestsForRide = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { rideId } = req.params;
|
const { rideId } = req.params;
|
||||||
const { idapp, status } = req.query;
|
const { status } = req.query;
|
||||||
|
const idapp = req.query.idapp || req.user?.idapp;
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
|
|
||||||
|
if (!idapp) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: 'idapp è obbligatorio',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Verifica che l'utente sia il proprietario del ride
|
// Verifica che l'utente sia il proprietario del ride
|
||||||
const ride = await Ride.findById(rideId);
|
const ride = await Ride.findById(rideId);
|
||||||
if (!ride) {
|
if (!ride) {
|
||||||
@@ -213,7 +252,8 @@ const getRequestsForRide = async (req, res) => {
|
|||||||
const getMyRequests = async (req, res) => {
|
const getMyRequests = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
const { idapp, status, page = 1, limit = 20 } = req.query;
|
const { status, page = 1, limit = 20 } = req.query;
|
||||||
|
const idapp = req.query.idapp || req.user?.idapp;
|
||||||
|
|
||||||
if (!idapp) {
|
if (!idapp) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
@@ -272,7 +312,7 @@ const getMyRequests = async (req, res) => {
|
|||||||
const getPendingRequests = async (req, res) => {
|
const getPendingRequests = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
const idapp = req.user.idapp;
|
const idapp = req.query.idapp || req.user?.idapp;
|
||||||
|
|
||||||
if (!idapp) {
|
if (!idapp) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
@@ -307,15 +347,23 @@ const getPendingRequests = async (req, res) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Accetta una richiesta di passaggio
|
* @desc Accetta una richiesta di passaggio
|
||||||
* @route PUT /api/viaggi/requests/:id/accept
|
* @route POST /api/viaggi/requests/:id/accept
|
||||||
* @access Private (solo conducente)
|
* @access Private (solo conducente)
|
||||||
*/
|
*/
|
||||||
const acceptRequest = async (req, res) => {
|
const acceptRequest = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const { responseMessage, idapp } = req.body;
|
const { responseMessage } = req.body;
|
||||||
|
const idapp = req.body.idapp || req.query.idapp || req.user?.idapp;
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
|
|
||||||
|
if (!idapp) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: 'idapp è obbligatorio',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const request = await RideRequest.findById(id).populate('rideId');
|
const request = await RideRequest.findById(id).populate('rideId');
|
||||||
|
|
||||||
if (!request) {
|
if (!request) {
|
||||||
@@ -343,7 +391,14 @@ const acceptRequest = async (req, res) => {
|
|||||||
|
|
||||||
// Verifica disponibilità posti
|
// Verifica disponibilità posti
|
||||||
const ride = request.rideId;
|
const ride = request.rideId;
|
||||||
if (ride.passengers.available < request.seatsRequested) {
|
if (!ride) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: 'Viaggio associato non trovato',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ride.passengers?.available || 0) < request.seatsRequested) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Posti non più disponibili',
|
message: 'Posti non più disponibili',
|
||||||
@@ -357,6 +412,10 @@ const acceptRequest = async (req, res) => {
|
|||||||
await request.save();
|
await request.save();
|
||||||
|
|
||||||
// Aggiorna il ride con il passeggero
|
// Aggiorna il ride con il passeggero
|
||||||
|
if (!ride.confirmedPassengers) {
|
||||||
|
ride.confirmedPassengers = [];
|
||||||
|
}
|
||||||
|
|
||||||
ride.confirmedPassengers.push({
|
ride.confirmedPassengers.push({
|
||||||
userId: request.passengerId,
|
userId: request.passengerId,
|
||||||
seats: request.seatsRequested,
|
seats: request.seatsRequested,
|
||||||
@@ -364,22 +423,59 @@ const acceptRequest = async (req, res) => {
|
|||||||
dropoffPoint: request.dropoffPoint || ride.destination,
|
dropoffPoint: request.dropoffPoint || ride.destination,
|
||||||
confirmedAt: new Date(),
|
confirmedAt: new Date(),
|
||||||
});
|
});
|
||||||
await ride.updateAvailableSeats();
|
|
||||||
|
// Aggiorna posti disponibili
|
||||||
|
if (typeof ride.updateAvailableSeats === 'function') {
|
||||||
|
await ride.updateAvailableSeats();
|
||||||
|
} else {
|
||||||
|
// Fallback manuale
|
||||||
|
const totalConfirmed = ride.confirmedPassengers.reduce(
|
||||||
|
(sum, p) => sum + (p.seats || 1),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (ride.passengers) {
|
||||||
|
ride.passengers.available = Math.max(0, (ride.passengers.total || 0) - totalConfirmed);
|
||||||
|
}
|
||||||
|
await ride.save();
|
||||||
|
}
|
||||||
|
|
||||||
// Invia messaggio nella chat
|
// Invia messaggio nella chat
|
||||||
const chat = await Chat.findOrCreateDirect(idapp, userId, request.passengerId, ride._id);
|
try {
|
||||||
const chatMessage = new Message({
|
const chat = await Chat.findOrCreateDirect(idapp, userId, request.passengerId, ride._id);
|
||||||
idapp,
|
const chatMessage = new Message({
|
||||||
chatId: chat._id,
|
idapp,
|
||||||
senderId: userId,
|
chatId: chat._id,
|
||||||
text: responseMessage || '✅ Richiesta accettata! Ci vediamo al punto di partenza.',
|
senderId: userId,
|
||||||
type: 'ride_accepted',
|
text: responseMessage || '✅ Richiesta accettata! Ci vediamo al punto di partenza.',
|
||||||
metadata: {
|
type: 'ride_accepted',
|
||||||
rideId: ride._id,
|
metadata: {
|
||||||
rideRequestId: request._id,
|
rideId: ride._id,
|
||||||
},
|
rideRequestId: request._id,
|
||||||
});
|
},
|
||||||
await chatMessage.save();
|
});
|
||||||
|
await chatMessage.save();
|
||||||
|
|
||||||
|
// Aggiorna lastMessage
|
||||||
|
chat.lastMessage = {
|
||||||
|
text: (responseMessage || '✅ Richiesta accettata!').substring(0, 100),
|
||||||
|
senderId: userId,
|
||||||
|
timestamp: new Date(),
|
||||||
|
type: 'ride_accepted',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Incrementa unread per il passeggero
|
||||||
|
if (!chat.unreadCount) {
|
||||||
|
chat.unreadCount = new Map();
|
||||||
|
}
|
||||||
|
const passengerIdStr = request.passengerId.toString();
|
||||||
|
const current = chat.unreadCount.get(passengerIdStr) || 0;
|
||||||
|
chat.unreadCount.set(passengerIdStr, current + 1);
|
||||||
|
chat.markModified('unreadCount');
|
||||||
|
|
||||||
|
await chat.save();
|
||||||
|
} catch (chatError) {
|
||||||
|
console.error('Errore invio messaggio chat:', chatError);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Inviare notifica push al passeggero
|
// TODO: Inviare notifica push al passeggero
|
||||||
|
|
||||||
@@ -403,15 +499,23 @@ const acceptRequest = async (req, res) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Rifiuta una richiesta di passaggio
|
* @desc Rifiuta una richiesta di passaggio
|
||||||
* @route PUT /api/viaggi/requests/:id/reject
|
* @route POST /api/viaggi/requests/:id/reject
|
||||||
* @access Private (solo conducente)
|
* @access Private (solo conducente)
|
||||||
*/
|
*/
|
||||||
const rejectRequest = async (req, res) => {
|
const rejectRequest = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const { responseMessage, idapp } = req.body;
|
const { responseMessage } = req.body;
|
||||||
|
const idapp = req.body.idapp || req.query.idapp || req.user?.idapp;
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
|
|
||||||
|
if (!idapp) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: 'idapp è obbligatorio',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const request = await RideRequest.findById(id);
|
const request = await RideRequest.findById(id);
|
||||||
|
|
||||||
if (!request) {
|
if (!request) {
|
||||||
@@ -444,19 +548,41 @@ const rejectRequest = async (req, res) => {
|
|||||||
await request.save();
|
await request.save();
|
||||||
|
|
||||||
// Invia messaggio nella chat
|
// Invia messaggio nella chat
|
||||||
const chat = await Chat.findOrCreateDirect(idapp, userId, request.passengerId, request.rideId);
|
try {
|
||||||
const chatMessage = new Message({
|
const chat = await Chat.findOrCreateDirect(idapp, userId, request.passengerId, request.rideId);
|
||||||
idapp,
|
const chatMessage = new Message({
|
||||||
chatId: chat._id,
|
idapp,
|
||||||
senderId: userId,
|
chatId: chat._id,
|
||||||
text: responseMessage || '❌ Mi dispiace, non posso accettare questa richiesta.',
|
senderId: userId,
|
||||||
type: 'ride_rejected',
|
text: responseMessage || '❌ Mi dispiace, non posso accettare questa richiesta.',
|
||||||
metadata: {
|
type: 'ride_rejected',
|
||||||
rideId: request.rideId,
|
metadata: {
|
||||||
rideRequestId: request._id,
|
rideId: request.rideId,
|
||||||
},
|
rideRequestId: request._id,
|
||||||
});
|
},
|
||||||
await chatMessage.save();
|
});
|
||||||
|
await chatMessage.save();
|
||||||
|
|
||||||
|
// Aggiorna lastMessage e unread
|
||||||
|
chat.lastMessage = {
|
||||||
|
text: (responseMessage || '❌ Richiesta rifiutata').substring(0, 100),
|
||||||
|
senderId: userId,
|
||||||
|
timestamp: new Date(),
|
||||||
|
type: 'ride_rejected',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!chat.unreadCount) {
|
||||||
|
chat.unreadCount = new Map();
|
||||||
|
}
|
||||||
|
const passengerIdStr = request.passengerId.toString();
|
||||||
|
const current = chat.unreadCount.get(passengerIdStr) || 0;
|
||||||
|
chat.unreadCount.set(passengerIdStr, current + 1);
|
||||||
|
chat.markModified('unreadCount');
|
||||||
|
|
||||||
|
await chat.save();
|
||||||
|
} catch (chatError) {
|
||||||
|
console.error('Errore invio messaggio chat:', chatError);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Inviare notifica push al passeggero
|
// TODO: Inviare notifica push al passeggero
|
||||||
|
|
||||||
@@ -476,8 +602,8 @@ const rejectRequest = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Cancella una richiesta (dal passeggero)
|
* @desc Cancella una richiesta (dal passeggero o conducente)
|
||||||
* @route PUT /api/viaggi/requests/:id/cancel
|
* @route POST /api/viaggi/requests/:id/cancel
|
||||||
* @access Private
|
* @access Private
|
||||||
*/
|
*/
|
||||||
const cancelRequest = async (req, res) => {
|
const cancelRequest = async (req, res) => {
|
||||||
@@ -517,11 +643,23 @@ const cancelRequest = async (req, res) => {
|
|||||||
// Se era accettata, rimuovi il passeggero dal ride
|
// Se era accettata, rimuovi il passeggero dal ride
|
||||||
if (request.status === 'accepted') {
|
if (request.status === 'accepted') {
|
||||||
const ride = await Ride.findById(request.rideId);
|
const ride = await Ride.findById(request.rideId);
|
||||||
if (ride) {
|
if (ride && ride.confirmedPassengers) {
|
||||||
ride.confirmedPassengers = ride.confirmedPassengers.filter(
|
ride.confirmedPassengers = ride.confirmedPassengers.filter(
|
||||||
(p) => p.userId.toString() !== request.passengerId.toString()
|
(p) => p.userId.toString() !== request.passengerId.toString()
|
||||||
);
|
);
|
||||||
await ride.updateAvailableSeats();
|
|
||||||
|
if (typeof ride.updateAvailableSeats === 'function') {
|
||||||
|
await ride.updateAvailableSeats();
|
||||||
|
} else {
|
||||||
|
const totalConfirmed = ride.confirmedPassengers.reduce(
|
||||||
|
(sum, p) => sum + (p.seats || 1),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (ride.passengers) {
|
||||||
|
ride.passengers.available = Math.max(0, (ride.passengers.total || 0) - totalConfirmed);
|
||||||
|
}
|
||||||
|
await ride.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,8 +716,11 @@ const getRequestById = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verifica che l'utente sia coinvolto
|
// Verifica che l'utente sia coinvolto
|
||||||
const isPassenger = request.passengerId._id.toString() === userId.toString();
|
const passengerId = request.passengerId?._id || request.passengerId;
|
||||||
const isDriver = request.driverId._id.toString() === userId.toString();
|
const driverId = request.driverId?._id || request.driverId;
|
||||||
|
|
||||||
|
const isPassenger = passengerId?.toString() === userId.toString();
|
||||||
|
const isDriver = driverId?.toString() === userId.toString();
|
||||||
|
|
||||||
if (!isPassenger && !isDriver) {
|
if (!isPassenger && !isDriver) {
|
||||||
return res.status(403).json({
|
return res.status(403).json({
|
||||||
@@ -611,9 +752,13 @@ const getReceivedRequests = async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const driverId = req.user._id;
|
const driverId = req.user._id;
|
||||||
const { status, page = 1, limit = 20 } = req.query;
|
const { status, page = 1, limit = 20 } = req.query;
|
||||||
|
const idapp = req.query.idapp || req.user?.idapp;
|
||||||
|
|
||||||
// Build query
|
// Build query
|
||||||
const query = { driverId };
|
const query = { driverId };
|
||||||
|
if (idapp) {
|
||||||
|
query.idapp = idapp;
|
||||||
|
}
|
||||||
if (status) {
|
if (status) {
|
||||||
query.status = status;
|
query.status = status;
|
||||||
}
|
}
|
||||||
@@ -622,22 +767,28 @@ const getReceivedRequests = async (req, res) => {
|
|||||||
|
|
||||||
// Fetch requests
|
// Fetch requests
|
||||||
const requests = await RideRequest.find(query)
|
const requests = await RideRequest.find(query)
|
||||||
.populate('passengerId', 'name surname profile.img') // <-- FIX: passengerId invece di userId
|
.populate('passengerId', 'username name surname profile.img profile.driverProfile.averageRating')
|
||||||
.populate('rideId', 'departure destination departureDate availableSeats')
|
.populate('rideId', 'departure destination dateTime passengers')
|
||||||
.sort({ createdAt: -1 })
|
.sort({ createdAt: -1 })
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
.limit(parseInt(limit))
|
.limit(parseInt(limit))
|
||||||
.lean();
|
.lean();
|
||||||
|
|
||||||
// Get counts by status
|
// Get counts by status
|
||||||
|
const driverObjectId = toObjectId(driverId);
|
||||||
|
const matchQuery = { driverId: driverObjectId };
|
||||||
|
if (idapp) {
|
||||||
|
matchQuery.idapp = idapp;
|
||||||
|
}
|
||||||
|
|
||||||
const counts = await RideRequest.aggregate([
|
const counts = await RideRequest.aggregate([
|
||||||
{ $match: { driverId } },
|
{ $match: matchQuery },
|
||||||
{
|
{
|
||||||
$group: {
|
$group: {
|
||||||
_id: '$status',
|
_id: '$status',
|
||||||
count: { $sum: 1 }
|
count: { $sum: 1 },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Format counts
|
// Format counts
|
||||||
@@ -647,11 +798,11 @@ const getReceivedRequests = async (req, res) => {
|
|||||||
rejected: 0,
|
rejected: 0,
|
||||||
cancelled: 0,
|
cancelled: 0,
|
||||||
expired: 0,
|
expired: 0,
|
||||||
completed: 0
|
completed: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
counts.forEach(c => {
|
counts.forEach((c) => {
|
||||||
if (statusCounts.hasOwnProperty(c._id)) {
|
if (Object.prototype.hasOwnProperty.call(statusCounts, c._id)) {
|
||||||
statusCounts[c._id] = c.count;
|
statusCounts[c._id] = c.count;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -668,20 +819,20 @@ const getReceivedRequests = async (req, res) => {
|
|||||||
page: parseInt(page),
|
page: parseInt(page),
|
||||||
limit: parseInt(limit),
|
limit: parseInt(limit),
|
||||||
total,
|
total,
|
||||||
pages: Math.ceil(total / parseInt(limit))
|
pages: Math.ceil(total / parseInt(limit)),
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching received requests:', error);
|
console.error('Error fetching received requests:', error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Errore nel recupero delle richieste ricevute',
|
message: 'Errore nel recupero delle richieste ricevute',
|
||||||
error: error.message
|
error: error.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Ottieni richieste inviate (io come passeggero)
|
* @desc Ottieni richieste inviate (io come passeggero)
|
||||||
* @route GET /api/viaggi/requests/sent
|
* @route GET /api/viaggi/requests/sent
|
||||||
@@ -691,9 +842,13 @@ const getSentRequests = async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
const { status, page = 1, limit = 20 } = req.query;
|
const { status, page = 1, limit = 20 } = req.query;
|
||||||
|
const idapp = req.query.idapp || req.user?.idapp;
|
||||||
|
|
||||||
// Build query - FIX: usa passengerId invece di userId
|
// Build query
|
||||||
const query = { passengerId: userId };
|
const query = { passengerId: userId };
|
||||||
|
if (idapp) {
|
||||||
|
query.idapp = idapp;
|
||||||
|
}
|
||||||
if (status) {
|
if (status) {
|
||||||
query.status = status;
|
query.status = status;
|
||||||
}
|
}
|
||||||
@@ -702,29 +857,59 @@ const getSentRequests = async (req, res) => {
|
|||||||
|
|
||||||
// Fetch requests
|
// Fetch requests
|
||||||
const requests = await RideRequest.find(query)
|
const requests = await RideRequest.find(query)
|
||||||
.populate('driverId', 'name surname profile.img')
|
.populate('driverId', 'username name surname profile.img profile.driverProfile.averageRating')
|
||||||
.populate('rideId', 'departure destination departureDate availableSeats currentPassengers')
|
.populate('rideId', 'departure destination dateTime passengers')
|
||||||
.sort({ createdAt: -1 })
|
.sort({ createdAt: -1 })
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
.limit(parseInt(limit))
|
.limit(parseInt(limit))
|
||||||
.lean();
|
.lean();
|
||||||
|
|
||||||
// Enrich with ride info
|
// Enrich with ride info
|
||||||
const enrichedRequests = requests.map(request => {
|
const enrichedRequests = requests.map((request) => {
|
||||||
const req = { ...request };
|
const enriched = { ...request };
|
||||||
|
|
||||||
// Add ride info if rideId is populated
|
if (enriched.rideId) {
|
||||||
if (req.rideId) {
|
enriched.rideInfo = {
|
||||||
req.rideInfo = {
|
departure: enriched.rideId.departure?.city || enriched.rideId.departure,
|
||||||
departure: req.rideId.departure?.city || req.rideId.departure,
|
destination: enriched.rideId.destination?.city || enriched.rideId.destination,
|
||||||
destination: req.rideId.destination?.city || req.rideId.destination,
|
dateTime: enriched.rideId.dateTime,
|
||||||
departureDate: req.rideId.departureDate,
|
availableSeats: enriched.rideId.passengers?.available || 0,
|
||||||
availableSeats: req.rideId.availableSeats,
|
|
||||||
currentPassengers: req.rideId.currentPassengers || 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return req;
|
return enriched;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get counts by status
|
||||||
|
const passengerObjectId = toObjectId(userId);
|
||||||
|
const matchQuery = { passengerId: passengerObjectId };
|
||||||
|
if (idapp) {
|
||||||
|
matchQuery.idapp = idapp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const counts = await RideRequest.aggregate([
|
||||||
|
{ $match: matchQuery },
|
||||||
|
{
|
||||||
|
$group: {
|
||||||
|
_id: '$status',
|
||||||
|
count: { $sum: 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const statusCounts = {
|
||||||
|
pending: 0,
|
||||||
|
accepted: 0,
|
||||||
|
rejected: 0,
|
||||||
|
cancelled: 0,
|
||||||
|
expired: 0,
|
||||||
|
completed: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
counts.forEach((c) => {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(statusCounts, c._id)) {
|
||||||
|
statusCounts[c._id] = c.count;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Total count
|
// Total count
|
||||||
@@ -734,21 +919,21 @@ const getSentRequests = async (req, res) => {
|
|||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
requests: enrichedRequests,
|
requests: enrichedRequests,
|
||||||
|
counts: statusCounts,
|
||||||
pagination: {
|
pagination: {
|
||||||
page: parseInt(page),
|
page: parseInt(page),
|
||||||
limit: parseInt(limit),
|
limit: parseInt(limit),
|
||||||
total,
|
total,
|
||||||
pages: Math.ceil(total / parseInt(limit))
|
pages: Math.ceil(total / parseInt(limit)),
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching sent requests:', error);
|
console.error('Error fetching sent requests:', error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'Errore nel recupero delle richieste inviate',
|
message: 'Errore nel recupero delle richieste inviate',
|
||||||
error: error.message
|
error: error.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ router.get('/cities/recent', authenticate, rideController.getRecentCities);
|
|||||||
*/
|
*/
|
||||||
router.post('/requests', authenticate, rideRequestController.createRequest);
|
router.post('/requests', authenticate, rideRequestController.createRequest);
|
||||||
|
|
||||||
|
// ⚠️ IMPORTANTE: Route specifiche PRIMA di quelle con :id
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @route GET /api/viaggi/requests/received
|
* @route GET /api/viaggi/requests/received
|
||||||
* @desc Richieste ricevute (sono conducente)
|
* @desc Richieste ricevute (sono conducente)
|
||||||
@@ -156,6 +158,20 @@ router.get('/requests/received', authenticate, rideRequestController.getReceived
|
|||||||
*/
|
*/
|
||||||
router.get('/requests/sent', authenticate, rideRequestController.getSentRequests);
|
router.get('/requests/sent', authenticate, rideRequestController.getSentRequests);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route GET /api/viaggi/requests/pending
|
||||||
|
* @desc Richieste pendenti (per il conducente)
|
||||||
|
* @access Private
|
||||||
|
*/
|
||||||
|
router.get('/requests/pending', authenticate, rideRequestController.getPendingRequests);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route GET /api/viaggi/requests/my
|
||||||
|
* @desc Le mie richieste (come passeggero)
|
||||||
|
* @access Private
|
||||||
|
*/
|
||||||
|
router.get('/requests/my', authenticate, rideRequestController.getMyRequests);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @route GET /api/viaggi/requests/ride/:rideId
|
* @route GET /api/viaggi/requests/ride/:rideId
|
||||||
* @desc Richieste per un viaggio specifico
|
* @desc Richieste per un viaggio specifico
|
||||||
@@ -163,6 +179,8 @@ router.get('/requests/sent', authenticate, rideRequestController.getSentRequests
|
|||||||
*/
|
*/
|
||||||
router.get('/requests/ride/:rideId', authenticate, rideRequestController.getRequestsForRide);
|
router.get('/requests/ride/:rideId', authenticate, rideRequestController.getRequestsForRide);
|
||||||
|
|
||||||
|
// ⚠️ Route con :id DOPO tutte le route specifiche
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @route GET /api/viaggi/requests/:id
|
* @route GET /api/viaggi/requests/:id
|
||||||
* @desc Dettaglio singola richiesta
|
* @desc Dettaglio singola richiesta
|
||||||
@@ -190,7 +208,6 @@ router.post('/requests/:id/reject', authenticate, rideRequestController.rejectRe
|
|||||||
* @access Private (driver o passenger)
|
* @access Private (driver o passenger)
|
||||||
*/
|
*/
|
||||||
router.post('/requests/:id/cancel', authenticate, rideRequestController.cancelRequest);
|
router.post('/requests/:id/cancel', authenticate, rideRequestController.cancelRequest);
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// 💬 CHAT - Messaggistica
|
// 💬 CHAT - Messaggistica
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -414,7 +431,7 @@ router.post('/feedback/:id/helpful', authenticate, feedbackController.markAsHelp
|
|||||||
router.get('/driver/user/:userId', async (req, res) => {
|
router.get('/driver/user/:userId', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { userId } = req.params;
|
const { userId } = req.params;
|
||||||
const idapp = req.user.idapp;
|
const idapp = req.query.idapp;
|
||||||
|
|
||||||
const { User } = require('../models/user');
|
const { User } = require('../models/user');
|
||||||
const Ride = require('../models/Ride');
|
const Ride = require('../models/Ride');
|
||||||
|
|||||||
Reference in New Issue
Block a user