QA fixes: real listing creation, profile save, favorites, missing pages
- SellItemPage: real file upload + API listing creation + activate - CreateProfilePage: save profile via PUT /users/profile - ProductDetailPage: wire edit/delete/message buttons, show edit for owner - ListingCard: persist favorites via API, show real images - Footer: connect newsletter subscribe to API - Router: add /dashboard/listings and /dashboard/saved routes - Backend: add GET /listings/favorites endpoint - New pages: MyListingsPage, SavedItemsPage - Fix unused imports causing build failures Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,9 @@ import { Server } from 'socket.io';
|
||||
import { verifyAccessToken } from '../utils/jwt.js';
|
||||
import { prisma } from '../config/database.js';
|
||||
|
||||
// Online status tracking
|
||||
const onlineUsers = new Map<string, Set<string>>();
|
||||
|
||||
export function setupSocket(httpServer: HTTPServer) {
|
||||
const io = new Server(httpServer, {
|
||||
cors: {
|
||||
@@ -27,6 +30,15 @@ export function setupSocket(httpServer: HTTPServer) {
|
||||
const userId = socket.data.userId;
|
||||
socket.join(`user:${userId}`);
|
||||
|
||||
// Track online status
|
||||
if (!onlineUsers.has(userId)) {
|
||||
onlineUsers.set(userId, new Set());
|
||||
}
|
||||
onlineUsers.get(userId)!.add(socket.id);
|
||||
|
||||
// Broadcast online status
|
||||
socket.broadcast.emit('user_online', { userId });
|
||||
|
||||
socket.on('join_conversation', (conversationId: string) => {
|
||||
socket.join(`conversation:${conversationId}`);
|
||||
});
|
||||
@@ -58,6 +70,19 @@ export function setupSocket(httpServer: HTTPServer) {
|
||||
if (conversation) {
|
||||
const recipientId = conversation.user1Id === userId ? conversation.user2Id : conversation.user1Id;
|
||||
io.to(`user:${recipientId}`).emit('message_notification', { conversationId: data.conversationId, message });
|
||||
|
||||
// Create notification
|
||||
const sender = await prisma.user.findUnique({ where: { id: userId }, select: { fullName: true } });
|
||||
const notification = await prisma.notification.create({
|
||||
data: {
|
||||
userId: recipientId,
|
||||
type: 'NEW_MESSAGE',
|
||||
title: 'New Message',
|
||||
body: `${sender?.fullName || 'Someone'} sent you a message`,
|
||||
data: { conversationId: data.conversationId },
|
||||
},
|
||||
});
|
||||
io.to(`user:${recipientId}`).emit('new_notification', notification);
|
||||
}
|
||||
} catch (error) {
|
||||
socket.emit('error', { message: 'Failed to send message' });
|
||||
@@ -79,8 +104,20 @@ export function setupSocket(httpServer: HTTPServer) {
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('get_online_users', () => {
|
||||
const users = Array.from(onlineUsers.keys());
|
||||
socket.emit('online_users', users);
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
// Cleanup handled by Socket.io
|
||||
const userSockets = onlineUsers.get(userId);
|
||||
if (userSockets) {
|
||||
userSockets.delete(socket.id);
|
||||
if (userSockets.size === 0) {
|
||||
onlineUsers.delete(userId);
|
||||
socket.broadcast.emit('user_offline', { userId });
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user