- Fix login: role field was missing from session (admin page inaccessible)
- Add onlineUsers map in socket/state.ts to track connected users
- Join personal user:${id} socket room on connect for targeted notifications
- Emit friendRequestReceived/friendRequestAccepted socket events from friends controller
- Add sendGameInvite socket event handler on server
- New NotificationContext: global socket provider for registered users
- New NotificationPanel: bell icon with unread badge and dropdown in header
- Friends page: inline game invite input per friend with sendGameInvite
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import type { Socket } from "socket.io";
|
|
|
|
import { io } from "../server.js";
|
|
import {
|
|
chat,
|
|
claimAbandoned,
|
|
claimTimeout,
|
|
getLatestGame,
|
|
joinAsPlayer,
|
|
joinLobby,
|
|
leaveLobby,
|
|
sendMove
|
|
} from "./game.socket.js";
|
|
import { onlineUsers } from "./state.js";
|
|
|
|
const socketConnect = (socket: Socket) => {
|
|
const req = socket.request;
|
|
|
|
socket.use((__, next) => {
|
|
req.session.reload((err) => {
|
|
if (err) {
|
|
socket.disconnect();
|
|
} else {
|
|
next();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Track online users and join personal notification room
|
|
const userId = req.session.user?.id;
|
|
if (userId && typeof userId === "number") {
|
|
onlineUsers.set(userId, socket.id);
|
|
socket.join(`user:${userId}`);
|
|
}
|
|
|
|
socket.on("disconnect", () => {
|
|
if (userId && typeof userId === "number") onlineUsers.delete(userId);
|
|
leaveLobby.call(socket);
|
|
});
|
|
|
|
// Forward game invites to target user's personal room
|
|
socket.on("sendGameInvite", ({ toId, gameCode }: { toId: number; gameCode: string }) => {
|
|
const fromUser = req.session.user;
|
|
if (!fromUser?.id || typeof fromUser.id === "string") return;
|
|
io.to(`user:${toId}`).emit("gameInviteReceived", {
|
|
fromId: fromUser.id,
|
|
fromName: fromUser.name,
|
|
gameCode
|
|
});
|
|
});
|
|
|
|
socket.on("joinLobby", joinLobby);
|
|
socket.on("leaveLobby", leaveLobby);
|
|
|
|
socket.on("getLatestGame", getLatestGame);
|
|
socket.on("sendMove", sendMove);
|
|
socket.on("joinAsPlayer", joinAsPlayer);
|
|
socket.on("chat", chat);
|
|
socket.on("claimAbandoned", claimAbandoned);
|
|
socket.on("claimTimeout", claimTimeout);
|
|
};
|
|
|
|
export const init = () => {
|
|
io.on("connection", socketConnect);
|
|
};
|