Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dm #110

Merged
merged 2 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions api/src/modules/chat/channels.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -622,12 +622,12 @@ export class ChannelsService {
}

const channelName = this.getDmChannelName(user.login, dm.login);
const channel = await this.prisma.channel.findUnique({
let channel = await this.prisma.channel.findUnique({
where: { name: channelName },
});

if (!channel) {
await this.prisma.channel.create({
channel = await this.prisma.channel.create({
data: {
name: channelName,
type: ChannelType.PRIVATE,
Expand Down Expand Up @@ -662,7 +662,7 @@ export class ChannelsService {
return {
createdAt: created.createdAt,
content: created.content,
channel: channelName,
channel: channel,
user: {
...created.author,
role: ChannelRole.USER,
Expand Down
2 changes: 1 addition & 1 deletion api/src/modules/chat/chat.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
async onDirectMessageUser(@MessageBody() dm: SendDmDTO, @ConnectedSocket() client: Socket) {
const data = await this.channelsService.sendDM(dm, client.data.user);

const sockets = this.socketsID.get(client.data.user.login) || [];
const sockets = this.socketsID.get(dm.login) || [];
for (const socket of sockets) {
this.io.to(socket.id).emit(ChatEvent.DirectMessage, data);
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/modules/user/user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class UserLoginDto {
}

export class UpdateUserDto {
@MaxLength(20)
@MaxLength(14)
@IsString()
@IsOptional()
displayName: string;
Expand Down
16 changes: 15 additions & 1 deletion front/src/components/chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const Chat = () => {
const [loading, setLoading] = useState<boolean>(true);
const [joinedChannels, setJoinedChannels] = useState<ChannelType[]>([]);
const [currentChannel, setCurrentChannel] = useState<ChannelType | null>(null);
const [showChannels, setShowChannels] = useState<boolean>(false);
const [showChannels, setShowChannels] = useState<boolean>(true);
let me: userDto | undefined;

const { data: user } = useApi().get('get user infos', '/user/me') as UseQueryResult<userDto>;
Expand Down Expand Up @@ -72,6 +72,17 @@ const Chat = () => {
console.log('youJoined - channel list :', joinedChannels);
});

tmpSocket.on('dm', (data) => {
setCurrentChannel(data.channel);
setJoinedChannels((prev) => {
if (!prev.some((c) => c.name === data.channel.name)) {
return [...prev, data.channel];
}
return prev;
});
setShowChannels(false);
});

tmpSocket.on('exception', (data) => {
if (Array.isArray(data.message)) {
alert(data.message.join('\n'));
Expand All @@ -84,6 +95,7 @@ const Chat = () => {
return () => {
socket?.off('youJoined');
socket?.off('exception');
socket?.off('dm');
socket?.disconnect();
};
}, []);
Expand Down Expand Up @@ -204,6 +216,8 @@ const Chat = () => {
joinedChannels={joinedChannels.filter((c) => c.isDM === true)}
setCurrentChannel={setCurrentChannel}
currentChannel={currentChannel}
socket={socket}
setJoinedChannels={setJoinedChannels}
/>
</div>
)}
Expand Down
12 changes: 8 additions & 4 deletions front/src/components/chat/ChatInfos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const ChatInfos = ({
const [users, setUsers] = useState<UserType[]>([]);
const [isAdmin, setIsAdmin] = useState<boolean>(false);
const [showMuteModal, setShowMuteModal] = useState<boolean>(false);
const [muteUserState, setMuteUser] = useState<UserType>();
const muteDurationRef = useRef<HTMLInputElement>(null);
const muteReasonRef = useRef<HTMLInputElement>(null);

Expand Down Expand Up @@ -95,12 +96,12 @@ const ChatInfos = ({
setBlockedUsers(blockedUsers.filter((u) => u.id !== user.id));
};

const muteUser = (e: React.FormEvent<HTMLFormElement>, user: UserType) => {
const muteUser = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

const muteData = {
channel: channelName,
login: user.login,
login: muteUserState?.login,
reason: muteReasonRef.current?.value,
duration: Number(muteDurationRef.current?.value),
};
Expand Down Expand Up @@ -188,7 +189,10 @@ const ChatInfos = ({
className="rounded-full p-1 enabled:hover:bg-red disabled:cursor-not-allowed"
title={isAdmin ? 'Mute user' : "Can't mute user because you are not admin"}
disabled={!isAdmin}
onClick={() => setShowMuteModal(true)}
onClick={() => {
setShowMuteModal(true);
setMuteUser(user);
}}
>
<img className="w-6" src={mute_icon} alt="mute" />
</button>
Expand All @@ -214,7 +218,7 @@ const ChatInfos = ({
<div className="flex flex-col gap-2 rounded-lg bg-white-1 p-4">
<div className="flex flex-col items-center justify-between gap-4">
<h2 className="text-2xl">Mute user</h2>
<form className="flex flex-col gap-2" onSubmit={(e) => muteUser(e, user)}>
<form className="flex flex-col gap-2" onSubmit={(e) => muteUser(e)}>
<input
className="rounded-lg border-2 border-white-3 p-2"
placeholder="Mute duration in seconds"
Expand Down
35 changes: 22 additions & 13 deletions front/src/components/chat/DmConversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Socket } from 'socket.io-client';
import info_icon from '@/assets/chat/info.svg';
import send_icon from '@/assets/chat/send.svg';
import { userDto } from '@/dto/userDto';
import { useApi } from '@/hooks/useApi';

import { ChannelType } from './Chat';
import ChatModal from './ChatModal';
Expand Down Expand Up @@ -42,7 +43,7 @@ const DmConversation = ({ channel, socket, me, allUsers }: ConversationProps) =>
const bottomEl = useRef<HTMLDivElement>(null);

useEffect(() => {
socket.on('message', (data: MessageType) => {
socket.on('dm', (data: MessageType) => {
setMessages((messages) => [...messages, data]);
});

Expand All @@ -54,10 +55,6 @@ const DmConversation = ({ channel, socket, me, allUsers }: ConversationProps) =>
},
);

socket.on('mute', (data) => {
alert(`Channel ${channel.name}, ${data.reason}`);
});

return () => {
socket.off('message');
};
Expand All @@ -67,25 +64,37 @@ const DmConversation = ({ channel, socket, me, allUsers }: ConversationProps) =>
bottomEl?.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);

const sendMessage = (e: React.FormEvent<HTMLFormElement>) => {
const sendMessage = (e: React.FormEvent<HTMLFormElement>, channelName: string) => {
e.preventDefault();
if (!message) return;
socket.emit('message', { channel: channel.name, content: message });
const names = channelName.substring(1).split('_');
const otherLogin = names[0] === me?.login ? names[1] : names[0];
socket.emit('dm', { login: otherLogin, content: message });
setMessage('');
};

function findUserInfos(chatName: string) {
if (!chatName) return '';
chatName = chatName.substring(1);
const names = chatName.split('_');

const { data: users } = useApi().get('get all users', 'user/all') as UseQueryResult<userDto[]>;
allUsers = users;

const names = chatName.substring(1).split('_');
if (names[0] === me?.login) {
const user = allUsers?.filter((user) => user.login === names[1]);
if (user) return user[0].displayName ? user[0].displayName : user[0]?.login;
if (user?.length) {
return user[0].displayName ? user[0].displayName : user[0]?.login;
} else {
return names[1];
}
} else {
const user = allUsers?.filter((user) => user.login === names[0]);
if (user) return user[0].displayName ? user[0].displayName : user[0]?.login;
if (user?.length) {
return user[0].displayName ? user[0].displayName : user[0]?.login;
} else {
return names[0];
}
}
return '';
}

return (
Expand Down Expand Up @@ -131,7 +140,7 @@ const DmConversation = ({ channel, socket, me, allUsers }: ConversationProps) =>
<div className="border-t border-t-white-3">
<form
className="m-2 flex gap-3 rounded-2xl bg-white-3 p-2"
onSubmit={(e) => sendMessage(e)}
onSubmit={(e) => sendMessage(e, channel.name)}
>
<input
className="w-full bg-white-3 outline-none"
Expand Down
9 changes: 1 addition & 8 deletions front/src/components/chat/DmCreate.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { ChangeEvent, useEffect, useState } from 'react';
import React, { useState } from 'react';
import { Socket } from 'socket.io-client';

import lock from '@/assets/chat/lock.svg';
import { userDto } from '@/dto/userDto';

import { ChannelType } from './Chat';
Expand All @@ -18,12 +17,6 @@ const DmCreate = ({ setShowModal, socket, users, setCurrentChannel }: DmChannelP
const [userButtonSelected, setUserButtonSelected] = useState<HTMLButtonElement | null>(null);
const [selectedLogin, setSelectedLogin] = useState<string>('');

useEffect(() => {
socket.on('dm', (data) => {
setCurrentChannel(data.channel);
});
}, []);

const useSetLogin = (displayName: string): void => {
const selectedUser = users?.find((user) => user.displayName == displayName);
setSelectedLogin(selectedUser?.login || '');
Expand Down
60 changes: 4 additions & 56 deletions front/src/components/chat/DmInfos.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { useEffect, useRef, useState } from 'react';
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { Socket } from 'socket.io-client';

import game_icon from '@/assets/chat/boxing-glove.svg';

import ChatModal from './ChatModal';
import { UserType } from './DmConversation';

interface DmInfosProps {
Expand All @@ -22,36 +21,19 @@ interface UserListResponse {
// TODO: leaver button ??
const DmInfos = ({ setShowModal, socket, channelName, currentUserLogin }: DmInfosProps) => {
const [users, setUsers] = useState<UserType[]>([]);
const [isAdmin, setIsAdmin] = useState<boolean>(false);
const [showMuteModal, setShowMuteModal] = useState<boolean>(false);
const muteDurationRef = useRef<HTMLInputElement>(null);
const muteReasonRef = useRef<HTMLInputElement>(null);

useEffect(() => {
socket.emit('userList', { channel: channelName }, (res: UserListResponse) => {
setUsers(res.users.filter((user) => user.login !== currentUserLogin));
const user = res.users.find((user) => user.login === currentUserLogin) || null;
if (user && (user.role === 'ADMIN' || user.role === 'OWNER')) setIsAdmin(true);
});
}, []);

const muteUser = (e: React.FormEvent<HTMLFormElement>, user: UserType) => {
e.preventDefault();

const muteData = {
channel: channelName,
login: user.login,
reason: muteReasonRef.current?.value,
duration: Number(muteDurationRef.current?.value),
};

socket.emit('mute', muteData);
};

const startGame = () => {
const code = (Math.random() + 1).toString(36).substring(7);
const message = `Come join me in a Pong game! ${window.location.origin}/game?code=${code}`;
socket.emit('message', { channel: channelName, content: message });
const names = channelName.substring(1).split('_');
const otherLogin = names[0] === currentUserLogin ? names[1] : names[0];
socket.emit('dm', { login: otherLogin, content: message });
};

// Contains the list of members in the channel, whith a possibility to kick them, to promote them as admin, and to start a game with them
Expand Down Expand Up @@ -84,40 +66,6 @@ const DmInfos = ({ setShowModal, socket, channelName, currentUserLogin }: DmInfo
>
<img className="w-6" src={game_icon} alt="close" />
</button>
{showMuteModal && (
<ChatModal>
<div className="flex flex-col gap-2 rounded-lg bg-white-1 p-4">
<div className="flex flex-col items-center justify-between gap-4">
<h2 className="text-2xl">Mute user</h2>
<form className="flex flex-col gap-2" onSubmit={(e) => muteUser(e, user)}>
<input
className="rounded-lg border-2 border-white-3 p-2"
placeholder="Mute duration in seconds"
ref={muteDurationRef}
required
></input>
<input
className="rounded-lg border-2 border-white-3 p-2"
placeholder="Mute reason (optional)"
ref={muteReasonRef}
></input>
<div className="flex justify-between">
<button
onClick={() => setShowMuteModal(false)}
className="rounded-lg border-2 border-white-3 p-2 hover:bg-red hover:text-white-1"
>
Cancel
</button>
<button className="rounded-lg border-2 border-white-3 p-2 hover:bg-darkBlue-2 hover:text-white-1">
Mute
</button>
</div>
</form>
</div>
<div className="flex flex-col gap-2"></div>
</div>
</ChatModal>
)}
</div>
</div>
);
Expand Down
37 changes: 28 additions & 9 deletions front/src/components/chat/DmList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// import logo from '@/assets/logo.svg';

import { Dispatch, SetStateAction, useEffect } from 'react';
import { UseQueryResult } from 'react-query';
import { Socket } from 'socket.io-client';

import { userDto } from '@/dto/userDto';
import { useApi } from '@/hooks/useApi';

import { ChannelType } from './Chat';

Expand All @@ -24,18 +29,28 @@ const DmListElem = ({
};
let user;

const findUserInfos = (chatName: string) => {
chatName = chatName.substring(1);
const names = chatName.split('_');
function findUserInfos(chatName: string) {
if (!chatName) return '';

const { data: users } = useApi().get('get all users', 'user/all') as UseQueryResult<userDto[]>;

const names = chatName.substring(1).split('_');
if (names[0] === me?.login) {
user = allUsers?.filter((user) => user.login === names[1]);
if (user) return user[0].displayName ? user[0].displayName : user[0]?.login;
const user = users?.filter((user) => user.login === names[1]);
if (user?.length) {
return user[0].displayName ? user[0].displayName : user[0]?.login;
} else {
return names[1];
}
} else {
user = allUsers?.filter((user) => user.login === names[0]);
if (user) return user[0].displayName ? user[0].displayName : user[0]?.login;
const user = users?.filter((user) => user.login === names[0]);
if (user?.length) {
return user[0].displayName ? user[0].displayName : user[0]?.login;
} else {
return names[0];
}
}
return '';
};
}

return (
<button
Expand Down Expand Up @@ -63,6 +78,8 @@ interface DmListProps {
currentChannel: ChannelType | null;
setCurrentChannel: (channel: ChannelType) => void;
me: userDto | undefined;
socket: Socket;
setJoinedChannels: Dispatch<SetStateAction<ChannelType[]>>;
}

const DmList = ({
Expand All @@ -71,6 +88,8 @@ const DmList = ({
setCurrentChannel,
allUsers,
me,
socket,
setJoinedChannels,
}: DmListProps) => {
return (
<div className="h-full w-full overflow-y-auto" style={{ maxHeight: '600px' }}>
Expand Down
Loading