From ac96887b1412879f7fa5218b9072e2fc66fd4d1c Mon Sep 17 00:00:00 2001 From: Ouadia Essendoubi Date: Mon, 30 Oct 2023 08:42:16 +0100 Subject: [PATCH 01/11] unban --- backend/code/src/rooms/rooms.service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/code/src/rooms/rooms.service.ts b/backend/code/src/rooms/rooms.service.ts index 0d4e0cf..35ae678 100644 --- a/backend/code/src/rooms/rooms.service.ts +++ b/backend/code/src/rooms/rooms.service.ts @@ -407,6 +407,7 @@ export class RoomsService { }, }, is_banned: true, + is_mueted: true, }, }); return members.map((member) => { @@ -421,6 +422,8 @@ export class RoomsService { firstname: member.user.firstName, lastname: member.user.lastName, avatar: avatar, + isBaned: member.is_banned, + isMuted: member.is_mueted, }; } }); From 5450acabeda9eff81d8f34ad4b5a56b4d0e0dfe9 Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Mon, 30 Oct 2023 10:41:53 +0100 Subject: [PATCH 02/11] wsync --- .../src/Components/Chat/Components/Conversation.tsx | 8 +++----- .../src/Components/Chat/Components/RoomChatHelpers.tsx | 2 +- .../src/Components/Chat/Components/tools/Assets.tsx | 2 ++ .../src/Components/Chat/Services/MessagesServices.ts | 2 ++ .../code/src/Components/Chat/assets/explore_icon.svg | 10 ++++++++++ 5 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 frontend/code/src/Components/Chat/assets/explore_icon.svg diff --git a/frontend/code/src/Components/Chat/Components/Conversation.tsx b/frontend/code/src/Components/Chat/Components/Conversation.tsx index 748c479..51e0146 100644 --- a/frontend/code/src/Components/Chat/Components/Conversation.tsx +++ b/frontend/code/src/Components/Chat/Components/Conversation.tsx @@ -191,7 +191,6 @@ export const ConversationHeader: React.FC = ({ tabIndex={0} className="p-2 shadow menu dropdown-content z-[1] bg-base-100 rounded-box w-52 absolute right-full " > - {/* check if current user is admin or owner to show the settings toast */} {(currentRoom?.isAdmin === true || currentRoom?.isOwner === true) && (
@@ -282,12 +281,11 @@ export const Conversation: React.FC = ({ const [inputValue, setInputValue] = useState(""); const [FailToSendMessage, setFail] = useState(false); - // Function to handle input changes const handleInputChange = (e: { target: { value: React.SetStateAction }; }) => { setFail(false); - setInputValue(e.target.value); // Update the input value in state + setInputValue(e.target.value); }; useEffect(() => { @@ -352,8 +350,8 @@ export const Conversation: React.FC = ({ {(CurrentsMessages?.length as number) > 0 ? ( CurrentsMessages?.map((message) => ( { ) ) .map((user) => ( - + ))}
)} diff --git a/frontend/code/src/Components/Chat/Components/tools/Assets.tsx b/frontend/code/src/Components/Chat/Components/tools/Assets.tsx index 541f7ce..4948e1b 100644 --- a/frontend/code/src/Components/Chat/Components/tools/Assets.tsx +++ b/frontend/code/src/Components/Chat/Components/tools/Assets.tsx @@ -23,6 +23,7 @@ import Lock from "../../assets/lockIcon.svg"; import Unlock from "../../assets/UnlockIcon.svg"; import ChatGif from "../../assets/chatGif.gif"; import NullUser from "../../assets/User_duotone.svg"; +import exploreIcon from "../../assets/explore_icon.svg" export enum RoomType { private, public, @@ -55,6 +56,7 @@ export { ChatGif, NullUser, owner, + exploreIcon }; export interface Message { diff --git a/frontend/code/src/Components/Chat/Services/MessagesServices.ts b/frontend/code/src/Components/Chat/Services/MessagesServices.ts index 5dfef84..18a9eeb 100644 --- a/frontend/code/src/Components/Chat/Services/MessagesServices.ts +++ b/frontend/code/src/Components/Chat/Services/MessagesServices.ts @@ -2,6 +2,8 @@ import api from "../../../Api/base"; + + export const getRoomMessagesCall = async ( id: string, offset: number, diff --git a/frontend/code/src/Components/Chat/assets/explore_icon.svg b/frontend/code/src/Components/Chat/assets/explore_icon.svg new file mode 100644 index 0000000..585f232 --- /dev/null +++ b/frontend/code/src/Components/Chat/assets/explore_icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + From 21be3088c558bb1513e5402a389ed24ac445aa6b Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Mon, 30 Oct 2023 18:04:36 +0100 Subject: [PATCH 03/11] async --- .DS_Store | Bin 8196 -> 8196 bytes frontend/.DS_Store | Bin 6148 -> 6148 bytes .../Chat/Components/RoomChatHelpers.tsx | 85 ++++++++++-------- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/.DS_Store b/.DS_Store index 11c1dacf64c943f299afc9d9e23c2c7aaba14c86..27fb4559d0a584b9b982c3a5b4cd860c74920c24 100644 GIT binary patch delta 114 zcmZp1XmQw}DiEtGcanjDfrUYjA)O(Up(Hoo#U&{xKM5$t!NAav&s1^L5mi0~uY5s< dVQ_MOZUIma15@heCIKlXCjD)j=Lx0p0s!^88r=W@ delta 114 zcmZp1XmQw}DiAASb%ud~frUYjA)O(Up(Hoo#U&{xKM5$t0mPSCN{%|B%BSF!FUT+q bPR`FQ0P1023g6r$AjQO_J7e=ap)_6q?1CDF diff --git a/frontend/.DS_Store b/frontend/.DS_Store index d8a764c472cf49513b89d3d7bd7f6b4d41d22a4f..cfaec8c82cdbd5f2a3ed0f5cff97177924a1ef94 100644 GIT binary patch delta 15 WcmZoMXffDuj*Us|(B=zlCV~Jju?3X? delta 15 WcmZoMXffDuj*UrV$>s}eCV~Ji?*(-L diff --git a/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx b/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx index 5dec569..1a3b5de 100644 --- a/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx +++ b/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx @@ -476,15 +476,18 @@ export const RoomSettingsModal = () => { const [RoomName, setName] = useState(""); const [RoomPassword, setPassword] = useState(""); const [LoadingUsers, setLOading] = useState(false); + const [IsUpdated, setUpdate] = useState(false); const handlePasswordChange = (event: { target: { value: SetStateAction }; }) => { + setUpdate(true); setPassword(event.target.value); }; const handleChange = (event: { target: { value: SetStateAction }; }) => { + setUpdate(true); setName(event.target.value); }; const [selectedOption, setSelectedOption] = useState(RoomType.public); @@ -518,6 +521,7 @@ export const RoomSettingsModal = () => { }, [LayoutState.showSettingsModal]); const resetModalState = () => { + setUpdate(false); setPassword(""); setSelectedOption(currentRoom?.type as RoomType); setName(currentRoom?.name as string); @@ -560,7 +564,10 @@ export const RoomSettingsModal = () => { value="Public" className="radio checked:bg-purple-500" checked={selectedOption === RoomType.public} - onChange={() => setSelectedOption(RoomType.public)} + onChange={() => { + setUpdate(true); + setSelectedOption(RoomType.public); + }} /> @@ -776,38 +789,40 @@ export const RoomSettingsModal = () => { > {"Close "} - { - console.log(RoomType[selectedOption]); - if (RoomName !== "" && RoomName.length > 3) { - setIsLoading(true); - await updateRoomCall( - RoomName, - RoomType[selectedOption], - currentRoom?.id!, - selectedOption === RoomType.protected - ? RoomPassword - : undefined - ).then((res) => { - if (res?.status !== 200 && res?.status !== 201) { - resetModalState(); - } else { - toast.success("Room Updated Successfully"); - editRoom(RoomName, selectedOption, currentRoom?.id!); - resetModalState(); - } - setIsLoading(false); - }); - } else { - toast.error("Room name must be at least 4 characters"); - resetModalState(); - } - }} - className="btn hover:bg-purple-500" - > - {"Save "} - + {IsUpdated === true && ( + { + console.log(RoomType[selectedOption]); + if (RoomName !== "" && RoomName.length > 3) { + setIsLoading(true); + await updateRoomCall( + RoomName, + RoomType[selectedOption], + currentRoom?.id!, + selectedOption === RoomType.protected + ? RoomPassword + : undefined + ).then((res) => { + if (res?.status !== 200 && res?.status !== 201) { + resetModalState(); + } else { + toast.success("Room Updated Successfully"); + editRoom(RoomName, selectedOption, currentRoom?.id!); + resetModalState(); + } + setIsLoading(false); + }); + } else { + toast.error("Room name must be at least 4 characters"); + resetModalState(); + } + }} + className="btn hover:bg-purple-500" + > + {"Save "} + + )} From 30468ef80fddd131bc299c3401ad7d7a1a14b342 Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Tue, 31 Oct 2023 18:28:55 +0100 Subject: [PATCH 04/11] finish rooms state & working on unban --- backend/code/src/friends/friends.service.ts | 26 +- backend/code/src/rooms/rooms.service.ts | 3 +- .../Chat/Components/Conversation.tsx | 33 ++- .../Chat/Components/RoomChatHelpers.tsx | 214 ++++++++++++++-- .../Chat/Components/tools/Assets.tsx | 10 + .../Components/Chat/Components/tools/utils.ts | 23 ++ .../Chat/Controllers/LayoutControllers.tsx | 9 + .../Components/Chat/Services/ChatServices.ts | 2 + .../Chat/Services/FriendsServices.ts | 38 +++ frontend/code/src/Components/Chat/index.tsx | 8 +- .../code/src/Components/Profile/index.tsx | 241 +++++++++++------- 11 files changed, 456 insertions(+), 151 deletions(-) create mode 100644 frontend/code/src/Components/Chat/Components/tools/utils.ts create mode 100644 frontend/code/src/Components/Chat/Services/FriendsServices.ts diff --git a/backend/code/src/friends/friends.service.ts b/backend/code/src/friends/friends.service.ts index c591434..cf417f1 100644 --- a/backend/code/src/friends/friends.service.ts +++ b/backend/code/src/friends/friends.service.ts @@ -223,29 +223,29 @@ export class FriendsService { }, }); - return friends.map((friend: any) => { + return friends.map((friend) => { if (friend.from.userId === userId) { - friend = friend.to as any; const avatar: PICTURE = { - thumbnail: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_48,w_48/${friend.avatar}`, - medium: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_72,w_72/${friend.avatar}`, - large: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_128,w_128/${friend.avatar}`, + thumbnail: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_48,w_48/${friend.to.avatar}`, + medium: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_72,w_72/${friend.to.avatar}`, + large: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_128,w_128/${friend.to.avatar}`, }; - delete friend.avatar; return { - ...friend.to, + id: friend.to.userId, + firstname: friend.to.firstName, + lastname: friend.to.lastName, avatar, }; } else { - friend = friend.from as any; const avatar: PICTURE = { - thumbnail: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_48,w_48/${friend.avatar}`, - medium: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_72,w_72/${friend.avatar}`, - large: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_128,w_128/${friend.avatar}`, + thumbnail: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_48,w_48/${friend.from.avatar}`, + medium: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_72,w_72/${friend.from.avatar}`, + large: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_128,w_128/${friend.from.avatar}`, }; - delete friend.avatar; return { - ...friend.from, + id: friend.from.userId, + firstname: friend.from.firstName, + lastname: friend.from.lastName, avatar, }; } diff --git a/backend/code/src/rooms/rooms.service.ts b/backend/code/src/rooms/rooms.service.ts index de7df2a..0413fcc 100644 --- a/backend/code/src/rooms/rooms.service.ts +++ b/backend/code/src/rooms/rooms.service.ts @@ -410,7 +410,8 @@ export class RoomsService { is_mueted: true, }, }); - return members.map((member) => { + const filtredmembers = members.filter((member) => !member.is_banned || user.is_admin) + return filtredmembers.map((member) => { if (!member.is_banned || user.is_admin) { const avatar: PICTURE = { thumbnail: `https://res.cloudinary.com/trandandan/image/upload/c_thumb,h_48,w_48/${member.user.avatar}`, diff --git a/frontend/code/src/Components/Chat/Components/Conversation.tsx b/frontend/code/src/Components/Chat/Components/Conversation.tsx index 51e0146..c0f2976 100644 --- a/frontend/code/src/Components/Chat/Components/Conversation.tsx +++ b/frontend/code/src/Components/Chat/Components/Conversation.tsx @@ -20,6 +20,7 @@ import { } from "../Services/MessagesServices"; import { useUserStore } from "../../../Stores/stores"; +import { formatTime } from "./tools/utils"; export interface ChatPaceHolderProps { username: string; @@ -31,7 +32,7 @@ export interface ChatPaceHolderProps { id: string; } -export const CurrentUserMessage = ({ message, time, senderId }: Message) => { +export const CurrentUserMessage = ({ message, time, senderId , avatar}: Message) => { const [MyUsers] = useState(users); const currentUser = useUserStore((state) => state); @@ -44,7 +45,7 @@ export const CurrentUserMessage = ({ message, time, senderId }: Message) => {
@@ -58,19 +59,16 @@ export const CurrentUserMessage = ({ message, time, senderId }: Message) => {
- {selectedChatType === ChatType.Chat ? ( - - ) : ( - user.id === senderId)?.image} + - )} +
@@ -141,7 +139,7 @@ export const ConversationHeader: React.FC = ({

) : (

- {currentRoom?.usersId.length} members + {currentRoom?.membersCount} members

)}
@@ -297,19 +295,25 @@ export const Conversation: React.FC = ({ res.data.forEach( (message: { id: string; + avatar: { + thumbnail: string; + medium: string; + large: string; + }; content: string; time: string; roomId: string; authorId: string; }) => { messages.push({ + avatar : message.avatar, senderId: message.authorId, message: message.content, time: message.time, }); } ); - setMessages(messages); + setMessages(messages.reverse()); } }); @@ -350,8 +354,9 @@ export const Conversation: React.FC = ({ {(CurrentsMessages?.length as number) > 0 ? ( CurrentsMessages?.map((message) => ( = ({ } else { // hard coded to change pushMessage({ - senderId: "2000", + senderId: "10", message: inputValue, isRead: false, - time: "10", + time: Date().toString(), }); } }); diff --git a/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx b/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx index 1a3b5de..0bfb0e3 100644 --- a/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx +++ b/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx @@ -31,6 +31,8 @@ import toast from "react-hot-toast"; import { Logo } from "../../Layout/Assets/Logo"; import { useModalStore } from "../Controllers/LayoutControllers"; import { useUserStore } from "../../../Stores/stores"; +import { formatTime } from "./tools/utils"; +import { getBlockedCall, unblockCall } from "../Services/FriendsServices"; interface NullComponentProps { message: string; @@ -51,9 +53,14 @@ export const RoomChatPlaceHolder = () => { const rooms: ChatRoom[] = []; res.data.forEach( (room: { + countMembers :number, id: string; is_admin: boolean; is_owner: boolean; + last_message : { + content : string, + createdAt :string, + } name: string; type: string; }) => { @@ -65,6 +72,8 @@ export const RoomChatPlaceHolder = () => { usersId: [], isOwner: room.is_owner, isAdmin: room.is_admin, + membersCount : room.countMembers, + last_message : room.last_message }); } ); @@ -102,22 +111,23 @@ export const RoomChatPlaceHolder = () => {

- {room?.usersId.length + 1} Members + {room?.membersCount} Members

- {room.messages.length > 0 - ? room.messages[room.messages?.length - 1]?.message - : "No Messages*"} + { + room.last_message?.content ?? "No Messages*"}

- {room.messages[room.messages?.length - 1]?.isRead === false ? ( -
-
+ {room.last_message !== null && ( +
+
- ) : ( - check - )} + ) + + }
@@ -345,6 +355,167 @@ export const FriendTile = (props: { user: RoomMember }) => { ); }; + +export const BlockedFriendTile = (props: { user: RoomMember }) => { + const [IsAdding, setIsAdding] = useState(false); + const selectedChatID = useChatStore((state) => state.selectedChatID); + const LayoutState = useModalStore((state) => state); + const user = props.user; + + return ( +
+
+
+
+ +
+ +

+ {user?.firstname ?? "user"} +

+
+ +
+ +
+
+
+ ); +}; + + + + + + + + +export const BlockedUsersModal = () => { + const [currentFriends, setUsers] = useState([]); + const [currentRoomMembers, setRoomMembers] = useState([]); + const LayoutState = useModalStore((state) => state); + const [IsLoading, setIsLoading] = useState(false); + + const [skipCount, setSkipCount] = useState(true); + const ChatState = useChatStore((state) => state); + + useEffect(() => { + if (skipCount) setSkipCount(false); + if (!skipCount) { + const fetchData = async () => { + try { + setIsLoading(true); + + + await getBlockedCall(0, 100).then((res) => { + setIsLoading(false); + if (res?.status === 200 || res?.status === 201) { + const friends: RoomMember[] = []; + res.data.forEach( + (friend: { + userId: string; + firstName: string; + lastName: string; + avatar?: { + thumbnail: string; + medium: string; + large: string; + }; + }) => { + friends.push({ + id: friend.userId, + firstname: friend.firstName, + lastname: friend.lastName, + // to inject it with the real images later + avatar: friend.avatar + } as RoomMember); + } + ); + + setUsers(friends); + } else { + } + }); + } catch (error) { + console.error("Error fetching data: ", error); + } + }; + + fetchData(); + } + // eslint-disable-next-line + }, [LayoutState.showBlockedLIstModal]); + return ( +
+
+
+
+

+ Blocked Friends List +

+
+ + {IsLoading === true ? ( +
+ +
+ ) : ( +
+ {currentFriends. + + length < 1 && ( + + )} + {currentFriends + .map((user) => ( + + ))} +
+ )} + + +
+
+
+ ); +}; + + + + + + export const AddUsersModal = () => { const [currentFriends, setUsers] = useState([]); const [currentRoomMembers, setRoomMembers] = useState([]); @@ -381,20 +552,21 @@ export const AddUsersModal = () => { const friends: RoomMember[] = []; res.data.forEach( (friend: { - userId: string; - firstName: string; - LastName: string; + id: string; + firstname: string; + lastname: string; + avatar: { + thumbnail: string; + medium: string; + large: string; + }; }) => { friends.push({ - id: friend.userId, - firstname: friend.firstName, - lastname: friend.LastName, + id: friend.id, + firstname: friend.firstname, + lastname: friend.lastname, // to inject it with the real images later - avatar: { - thumbnail: NullUser, - medium: NullUser, - large: NullUser, - }, + avatar: friend.avatar } as RoomMember); } ); diff --git a/frontend/code/src/Components/Chat/Components/tools/Assets.tsx b/frontend/code/src/Components/Chat/Components/tools/Assets.tsx index 4948e1b..23aa3c3 100644 --- a/frontend/code/src/Components/Chat/Components/tools/Assets.tsx +++ b/frontend/code/src/Components/Chat/Components/tools/Assets.tsx @@ -65,6 +65,11 @@ export interface Message { senderId: string; message: string; time: string; + avatar?: { + thumbnail: string; + medium: string; + large: string; + }; isRead?: boolean; } @@ -90,6 +95,11 @@ export interface ChatRoom { isAdmin: boolean; type: RoomType; membersCount?: number; + last_message? : { + content? : string, + createdAt? :string, + } + } export interface User { diff --git a/frontend/code/src/Components/Chat/Components/tools/utils.ts b/frontend/code/src/Components/Chat/Components/tools/utils.ts new file mode 100644 index 0000000..d3b5750 --- /dev/null +++ b/frontend/code/src/Components/Chat/Components/tools/utils.ts @@ -0,0 +1,23 @@ + +export const formatTime = (backendDate: string) => { + const currentDate = new Date(); + const date = new Date(backendDate); + const day = date.getDate(); + const month = date.toLocaleString('en-US', { month: 'short' }); + const hours = date.getHours(); + const minutes = date.getMinutes(); + const ampm = hours >= 12 ? " PM" : " AM"; + const formattedHours = (hours % 12).toString().padStart(2, "0"); + const formattedMinutes = minutes.toString().padStart(2, "0"); + + if (date.toDateString() === currentDate.toDateString()) { + return `${formattedHours}:${formattedMinutes}${ampm}`; + } else { + return `${day} ${month} ${formattedHours}:${formattedMinutes}${ampm}`; + } + + + +} + + diff --git a/frontend/code/src/Components/Chat/Controllers/LayoutControllers.tsx b/frontend/code/src/Components/Chat/Controllers/LayoutControllers.tsx index ce032a4..528d3f4 100644 --- a/frontend/code/src/Components/Chat/Controllers/LayoutControllers.tsx +++ b/frontend/code/src/Components/Chat/Controllers/LayoutControllers.tsx @@ -5,11 +5,13 @@ export interface ModalState { showPreviewCard: boolean; showAddUsersModal: boolean; showSettingsModal: boolean; + showBlockedLIstModal : boolean; setShowExploreModal: (showExploreModal: boolean) => void; setShowPreviewCard: (showPreviewCard: boolean) => void; setShowAddUsersModal: (showAddUsersModal: boolean) => void; setShowSettingsModal: (showSettingsModal: boolean) => void; + setShowBlockedList : (showBlockedLIstModal : boolean) => void; } export const useModalStore = create((set) => ({ @@ -17,6 +19,13 @@ export const useModalStore = create((set) => ({ showPreviewCard: false, showAddUsersModal: false, showSettingsModal: false, + showBlockedLIstModal : false, + + setShowBlockedList : (showBlockedLIstModal : boolean) => set((state) => { + state.showBlockedLIstModal = showBlockedLIstModal; + return { ...state }; + }), + setShowSettingsModal: (showSettingsModal: boolean) => set((state) => { diff --git a/frontend/code/src/Components/Chat/Services/ChatServices.ts b/frontend/code/src/Components/Chat/Services/ChatServices.ts index f0dc5a7..920058a 100644 --- a/frontend/code/src/Components/Chat/Services/ChatServices.ts +++ b/frontend/code/src/Components/Chat/Services/ChatServices.ts @@ -199,3 +199,5 @@ export const getFriendsCall = async ( } + + diff --git a/frontend/code/src/Components/Chat/Services/FriendsServices.ts b/frontend/code/src/Components/Chat/Services/FriendsServices.ts new file mode 100644 index 0000000..68e12bb --- /dev/null +++ b/frontend/code/src/Components/Chat/Services/FriendsServices.ts @@ -0,0 +1,38 @@ +import api from "../../../Api/base"; + +export const getBlockedCall = async ( + offset: number, + limit: number, + + + ) => { + + try { + const response = await api.get(`/friends/blocklist`, + { params: { offset: offset, limit: limit } }); + console.log("blocked list response"); + console.log(response.status); + console.log(response.data); + return response; + } catch (e: any) { + console.log(e.response.data.message); + } + + } + + export const unblockCall = async ( + friendId : string + ) => { + try { + + const response = await api.post("/friends/unblock", { + friendId :friendId + }); + console.log(response.data); + console.log(response.status); + return response; + } catch (e: any) { + console.log(e.response.data.message); + } + }; + \ No newline at end of file diff --git a/frontend/code/src/Components/Chat/index.tsx b/frontend/code/src/Components/Chat/index.tsx index 4dc9721..4bb432e 100644 --- a/frontend/code/src/Components/Chat/index.tsx +++ b/frontend/code/src/Components/Chat/index.tsx @@ -17,6 +17,7 @@ import { ChatType, useChatStore } from "./Controllers/RoomChatControllers"; import { RecentConversations } from "./Components/RecentChat"; import { AddUsersModal, + BlockedUsersModal, CreateNewRoomModal, ExploreRoomsModal, NullPlaceHolder, @@ -54,6 +55,7 @@ export const Chat = () => { +
= ({ {}

{currentRoom?.name}'s Members

-
+
{isLoading === false ? ( <> {currentUsers.map((user) => ( -
+
Avatar Tailwind CSS Component
diff --git a/frontend/code/src/Components/Profile/index.tsx b/frontend/code/src/Components/Profile/index.tsx index 6bcf321..812cb13 100644 --- a/frontend/code/src/Components/Profile/index.tsx +++ b/frontend/code/src/Components/Profile/index.tsx @@ -1,105 +1,148 @@ -import { Pong } from './assets/Pong' -import { File } from './assets/File' -import { Share } from './assets/ShareB' -import { Message } from './assets/MessageB' -import { History } from './History' -import Hero from './assets/Hero.gif' -import { useState , useEffect } from 'react' -import { Link, useNavigate, useParams } from 'react-router-dom' -import { Load } from '../Loading/' -import Newbie from '../Badges/Newbie.svg' -import Master from '../Badges/Master.svg' -import Ultimate from '../Badges/Ultimate.svg' -import { Edit } from './assets/Edit' -import { useUserStore } from '../../Stores/stores' -import dots from './assets/svg/threedots.svg' -import api from '../../Api/base' +import { Pong } from "./assets/Pong"; +import { File } from "./assets/File"; +import { Share } from "./assets/ShareB"; +import { Message } from "./assets/MessageB"; +import { History } from "./History"; +import Hero from "./assets/Hero.gif"; +import { useState, useEffect } from "react"; +import { Link, useNavigate, useParams } from "react-router-dom"; +import { Load } from "../Loading/"; +import Newbie from "../Badges/Newbie.svg"; +import Master from "../Badges/Master.svg"; +import Ultimate from "../Badges/Ultimate.svg"; +import { Edit } from "./assets/Edit"; +import { useUserStore } from "../../Stores/stores"; +import dots from "./assets/svg/threedots.svg"; +import api from "../../Api/base"; +import { GroupChat } from "../Chat/Components/tools/Assets"; +import { BlockedUsersModal } from "../Chat/Components/RoomChatHelpers"; +import { useModalStore } from "../Chat/Controllers/LayoutControllers"; // import toast from 'react-hot-toast' -export const Profile = () =>{ - const user = useUserStore(); - const params = useParams(); - const navigate = useNavigate(); - console.log(`params : ${params.id} type ${typeof(params.id)}`) - const [users, setUsers] = useState(undefined); - - useEffect(() => { - const fetchUser = async() => { - try { - const res = await api.get(`profile/${params.id}`) - setUsers(res.data) - - } catch (error) { - navigate("/NotFound") - } - } - if (params.id !== user.id || params.id !== "me") - fetchUser(); - else - setUsers(user) - //eslint-disable-next-line - },[params, user]) - // console.log(users) - // const handleSendReq = async() => { - // toast.promise(api.post("friend/add",{friendId:users.id}),{loading:`Sending friend request`,success:`request sent to ${users.name.first}`,error:"could not send friend request"}) - // } - return ( - <> -
-
- -
bg hero -
- -
- -
-
- { - users?.picture?.large ? profile avatar: - } - -
-
+export const Profile = () => { + const user = useUserStore(); + const params = useParams(); + const LayoutState = useModalStore((state) => state); + const navigate = useNavigate(); + console.log(`params : ${params.id} type ${typeof params.id}`); + const [users, setUsers] = useState(undefined); + + useEffect(() => { + const fetchUser = async () => { + try { + const res = await api.get(`profile/${params.id}`); + setUsers(res.data); + } catch (error) { + navigate("/NotFound"); + } + }; + if (params.id !== user.id || params.id !== "me") fetchUser(); + else setUsers(user); + //eslint-disable-next-line + }, [params, user]); + // console.log(users) + // const handleSendReq = async() => { + // toast.promise(api.post("friend/add",{friendId:users.id}),{loading:`Sending friend request`,success:`request sent to ${users.name.first}`,error:"could not send friend request"}) + // } + return ( + <> + +
+
+
+ bg hero +
+ +
+ +
+
+ {users?.picture?.large ? ( + profile avatar + ) : ( + + )}
-
- { - users?.name?.first ?
{users?.name?.first} {users.name.last}
: - }
- - {users?.bio} -
-
-
- { - params.id !== "me" ? - (<> - ) - : - ( - - ) - } -
-
- newbie badge - Master badge - Ultimate badge -
- -
    -
  • Block
  • -
  • Send friend request
  • -
-
-
-
+
+
+
+ {users?.name?.first ? ( +
+ {users?.name?.first} {users.name.last}{" "} +
+ ) : ( + + )}{" "} +
+ + {users?.bio} +
+
+
+ {params.id !== "me" ? ( + <> + + + + ) : ( + + + + )}
-
- +
+ newbie badge + Master badge + Ultimate badge +
+ +
    +
  • +
    Block
    +
  • +
  • +
    Send friend request
    +
  • +
  • { + LayoutState.setShowBlockedList( + !LayoutState.showBlockedLIstModal + ); + }} + > + +
    See Blocked List
    +
    +
  • +
+
+
+
+
+
+
- ) -} \ No newline at end of file + ); +}; From 953a5cb4ab724976459406940f0bfa6a97052de3 Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Wed, 1 Nov 2023 11:15:47 +0100 Subject: [PATCH 05/11] async --- backend/code/src/gateways/gateways.gateway.ts | 1 + frontend/code/package.json | 1 + .../Chat/Services/SocketsServices.ts | 10 ++ frontend/code/src/Components/Chat/index.tsx | 36 +++++- package-lock.json | 105 +++++++++++++++++- package.json | 3 +- 6 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 frontend/code/src/Components/Chat/Services/SocketsServices.ts diff --git a/backend/code/src/gateways/gateways.gateway.ts b/backend/code/src/gateways/gateways.gateway.ts index ad2fee1..92e264a 100644 --- a/backend/code/src/gateways/gateways.gateway.ts +++ b/backend/code/src/gateways/gateways.gateway.ts @@ -47,6 +47,7 @@ export class Gateways implements OnGatewayConnection { @OnEvent('sendMessages') sendMessage(message: MessageFormatDto) { + console.log("recive msg !") const chanellname: string = `Romm:${message.roomId}`; this.server.to(chanellname).emit('message', message); } diff --git a/frontend/code/package.json b/frontend/code/package.json index dd76a8a..11c8b68 100644 --- a/frontend/code/package.json +++ b/frontend/code/package.json @@ -26,6 +26,7 @@ "react-hot-toast": "^2.4.1", "react-icons": "^4.10.1", "react-konva": "^18.2.10", + "socket.io-client": "^4.7.2", "react-scripts": "^5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4", diff --git a/frontend/code/src/Components/Chat/Services/SocketsServices.ts b/frontend/code/src/Components/Chat/Services/SocketsServices.ts new file mode 100644 index 0000000..2718520 --- /dev/null +++ b/frontend/code/src/Components/Chat/Services/SocketsServices.ts @@ -0,0 +1,10 @@ +import { io } from 'socket.io-client'; + +// "undefined" means the URL will be computed from the `window.location` object +const URL = process.env.NODE_ENV === 'production' ? undefined : 'http://localhost:4000'; + + +export const socket = io("http://localhost:3004", { + transports: ['websocket'], + withCredentials: true, + }); \ No newline at end of file diff --git a/frontend/code/src/Components/Chat/index.tsx b/frontend/code/src/Components/Chat/index.tsx index 4bb432e..15862ea 100644 --- a/frontend/code/src/Components/Chat/index.tsx +++ b/frontend/code/src/Components/Chat/index.tsx @@ -30,6 +30,7 @@ import { getRoomMembersCall } from "./Services/ChatServices"; import toast from "react-hot-toast"; import { classNames } from "../../Utils/helpers"; import { useModalStore } from "./Controllers/LayoutControllers"; +import { socket } from "./Services/SocketsServices"; export interface ConversationProps { onRemoveUserPreview: () => void; @@ -46,6 +47,40 @@ export const Chat = () => { const handleRemoveUserPreview = () => { setShowUserPreview(!showUserPreview); }; + + const [isConnected, setIsConnected] = useState(socket.connected); + const [fooEvents, setFooEvents] = useState([]); + // const [messages, setMessages] = useState([]); + useEffect(() => { + function onConnect() { + console.log("hello"); + setIsConnected(true); + } + + function onDisconnect() { + setIsConnected(false); + } + + + + + + + socket.on("connect", onConnect); + socket.emit('sendMessages',) + + socket.on('message', (message) => { + console.log("message") + }) + // socket.on("disconnect", onDisconnect); + + + + return () => { + // socket.off("connect", onConnect); + // socket.off("disconnect", onDisconnect); + }; + }, []); return ( <>
@@ -55,7 +90,6 @@ export const Chat = () => { -
=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -813,6 +835,26 @@ "csstype": "^3.0.2" } }, + "node_modules/engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1029,6 +1071,11 @@ "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1184,6 +1231,32 @@ "object-assign": "^4.1.1" } }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -1232,6 +1305,34 @@ "node": ">=4" } }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", diff --git a/package.json b/package.json index b34d6ec..2b902a5 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "@material-ui/core": "^4.12.4", "@mui/material": "^5.14.13", "lord-icon-element": "^4.1.2", - "lottie-web": "^5.12.2" + "lottie-web": "^5.12.2", + "socket.io-client": "^4.7.2" } } From 182646061d52c98612c146ecf194fe89afd2018b Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Wed, 1 Nov 2023 11:56:19 +0100 Subject: [PATCH 06/11] async --- .../Chat/Components/Conversation.tsx | 31 +++++++++++++------ frontend/code/src/Components/Chat/index.tsx | 31 ------------------- 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/frontend/code/src/Components/Chat/Components/Conversation.tsx b/frontend/code/src/Components/Chat/Components/Conversation.tsx index c0f2976..2143c46 100644 --- a/frontend/code/src/Components/Chat/Components/Conversation.tsx +++ b/frontend/code/src/Components/Chat/Components/Conversation.tsx @@ -21,6 +21,7 @@ import { import { useUserStore } from "../../../Stores/stores"; import { formatTime } from "./tools/utils"; +import { socket } from "../Services/SocketsServices"; export interface ChatPaceHolderProps { username: string; @@ -32,7 +33,12 @@ export interface ChatPaceHolderProps { id: string; } -export const CurrentUserMessage = ({ message, time, senderId , avatar}: Message) => { +export const CurrentUserMessage = ({ + message, + time, + senderId, + avatar, +}: Message) => { const [MyUsers] = useState(users); const currentUser = useUserStore((state) => state); @@ -45,7 +51,7 @@ export const CurrentUserMessage = ({ message, time, senderId , avatar}: Message)
@@ -59,16 +65,12 @@ export const CurrentUserMessage = ({ message, time, senderId , avatar}: Message)
- - +
@@ -287,6 +289,16 @@ export const Conversation: React.FC = ({ }; useEffect(() => { + function onConnect() { + console.log("hello"); + } + + socket.on("connect", onConnect); + + socket.on("message", (message) => { + console.log("message :", message); + }); + const fetch = async () => getRoomMessagesCall(chatState.selectedChatID, 0, 30).then((res) => { if (res?.status !== 200 && res?.status !== 201) { @@ -306,7 +318,7 @@ export const Conversation: React.FC = ({ authorId: string; }) => { messages.push({ - avatar : message.avatar, + avatar: message.avatar, senderId: message.authorId, message: message.content, time: message.time, @@ -354,7 +366,6 @@ export const Conversation: React.FC = ({ {(CurrentsMessages?.length as number) > 0 ? ( CurrentsMessages?.map((message) => ( { setShowUserPreview(!showUserPreview); }; - const [isConnected, setIsConnected] = useState(socket.connected); - const [fooEvents, setFooEvents] = useState([]); - // const [messages, setMessages] = useState([]); - useEffect(() => { - function onConnect() { - console.log("hello"); - setIsConnected(true); - } - - function onDisconnect() { - setIsConnected(false); - } - - - - - - socket.on("connect", onConnect); - socket.emit('sendMessages',) - socket.on('message', (message) => { - console.log("message") - }) - // socket.on("disconnect", onDisconnect); - - - - return () => { - // socket.off("connect", onConnect); - // socket.off("disconnect", onDisconnect); - }; - }, []); return ( <>
From c0c607ff91c7523581cd7d72d32f758cfde22e97 Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Wed, 1 Nov 2023 19:04:12 +0100 Subject: [PATCH 07/11] working on sockets --- .DS_Store | Bin 8196 -> 8196 bytes backend/.DS_Store | Bin 6148 -> 6148 bytes frontend/.DS_Store | Bin 6148 -> 6148 bytes .../Chat/Components/Conversation.tsx | 90 ++++++++++++------ .../Chat/Controllers/RoomChatControllers.tsx | 16 +++- 5 files changed, 75 insertions(+), 31 deletions(-) diff --git a/.DS_Store b/.DS_Store index 27fb4559d0a584b9b982c3a5b4cd860c74920c24..f9a38f55aadd092c5bee688852819c116735c43b 100644 GIT binary patch delta 214 zcmZp1XmQw}Di9mydx3$0frUYjA)O(Up(Hoo#U&{xKM5$t0mPe3D~~#&%BSF!FUT+q zPR`FQ0P102+B>;Pz=_Swb`7&c#pDkHB9re4@F2L(%pBXxCYuS$u}zVk5ougGxj|55 za-JX$+cW9J?Rp@tA`_p&WI8nB)2f-m+dBu}I2#8F+C%}W?Iy18$IX>A;P>!v5#XFFS20@X@ zd4fC$t|Al9hslD%qLX(BK4H?|HhG?q5?g~&N%2ufAX9Ae9U&eT5O?w$Ar;1i&4R+8 Fc>uypLKXl3 diff --git a/backend/.DS_Store b/backend/.DS_Store index 7967f165c39b0c94a5d68d6a242b51bea2a4d8ae..04ef7ff2ad40167995ce0be7b71f23f958e656c5 100644 GIT binary patch delta 158 zcmZoMXfc=|#>CJ*F;Q%yo+2a5!~knXmdQMfl5rgKycrl6SQwHS@)=SXQgicNT#|C~ zlYn9z3=9ns#+64MQRP#RS18uy|8&9V;bA!4UF?Pvvcrs a0384n_|80;U&N4+VX_U6^yV0m70dv#)+a3h delta 193 zcmZoMXfc=|#>B`mF;Q%yo+2ab!~pBb3XBavMvr7Y`|3Fi3=Av`$qe}nDGaH(`7SO= zIr&LIF%BRWC@MVah$^3gSH2*_FgQ6sw*aVzfq`cMh=iM67F?8k5>>T_YKnHFXWc%7lJ*eU!wdjbK`1Q% diff --git a/frontend/.DS_Store b/frontend/.DS_Store index cfaec8c82cdbd5f2a3ed0f5cff97177924a1ef94..6e69669cb12112adf4ef0864321c38c0d9abc825 100644 GIT binary patch delta 39 qcmZoMXffDuj*ZDTY4Qa&DHaAsr^?Ci*km9KK6V+#g3a3OHw6IlpbJL; delta 39 rcmZoMXffDuj*Us|(BunjQY;NdCB>89vB^LfeC#re0-LqjZwdea6{`%& diff --git a/frontend/code/src/Components/Chat/Components/Conversation.tsx b/frontend/code/src/Components/Chat/Components/Conversation.tsx index 2143c46..8b07665 100644 --- a/frontend/code/src/Components/Chat/Components/Conversation.tsx +++ b/frontend/code/src/Components/Chat/Components/Conversation.tsx @@ -276,8 +276,14 @@ export const Conversation: React.FC = ({ const chatState = useChatStore((state) => state); const messageContainerRef = useRef(null); - const pushMessage = useChatStore((state) => state.addNewMessage); - const [CurrentsMessages, setMessages] = useState([]); + const scrollToBottom = () => { + if (messageContainerRef.current) { + const container = messageContainerRef.current; + container.scrollTop = container.scrollHeight; + } + }; + + const currentUser = useUserStore((state) => state); const [inputValue, setInputValue] = useState(""); const [FailToSendMessage, setFail] = useState(false); @@ -295,9 +301,40 @@ export const Conversation: React.FC = ({ socket.on("connect", onConnect); - socket.on("message", (message) => { - console.log("message :", message); - }); + socket.on( + "message", + (message: { + id: string; + avatar: { + thumbnail: string; + medium: string; + large: string; + }; + content: string; + time: string; + roomId: string; + authorId: string; + }) => { + console.log(message); + if (message.roomId === chatState.selectedChatID) { + const NewMessage: Message = { + avatar: message.avatar, + senderId: message.authorId, + message: message.content, + time: message.time, + }; + + if ( + chatState.currentMessages.findIndex( + (message) => message.id === NewMessage.id + ) === -1 + ) { + chatState.pushMessage(NewMessage); + } + } + scrollToBottom(); + } + ); const fetch = async () => getRoomMessagesCall(chatState.selectedChatID, 0, 30).then((res) => { @@ -325,31 +362,31 @@ export const Conversation: React.FC = ({ }); } ); - setMessages(messages.reverse()); + chatState.fillCurrentMessages(messages.reverse()); } }); - fetch(); - scrollToBottom(); + fetch().then((res) => { + scrollToBottom(); + }); }, [chatState.selectedChatID]); - const scrollToBottom = () => { - if (messageContainerRef.current) { - messageContainerRef.current.scrollTop = - messageContainerRef.current.scrollHeight; - } - }; - const handleKeyPress = (e: KeyboardEvent) => { if (e.key === "Enter") { - // validation check if (inputValue.length > 0) { - pushMessage({ - senderId: "2", + chatState.pushMessage({ + avatar: { + thumbnail: "", + medium: "", + large: "", + }, + senderId: currentUser.id, message: inputValue, - isRead: false, - time: "10", + time: Date().toString(), }); + + scrollToBottom(); + setInputValue(""); } } @@ -360,11 +397,11 @@ export const Conversation: React.FC = ({
- {(CurrentsMessages?.length as number) > 0 ? ( - CurrentsMessages?.map((message) => ( + {(chatState.currentMessages?.length as number) > 0 ? ( + chatState.currentMessages?.map((message) => ( = ({ ); // set the input to red color } else { - // hard coded to change - pushMessage({ - senderId: "10", - message: inputValue, - isRead: false, - time: Date().toString(), - }); } }); } diff --git a/frontend/code/src/Components/Chat/Controllers/RoomChatControllers.tsx b/frontend/code/src/Components/Chat/Controllers/RoomChatControllers.tsx index 8b4731f..0f04d8f 100644 --- a/frontend/code/src/Components/Chat/Controllers/RoomChatControllers.tsx +++ b/frontend/code/src/Components/Chat/Controllers/RoomChatControllers.tsx @@ -21,7 +21,9 @@ export interface ChatState { showChatRooms: boolean; recentRooms: ChatRoom[]; + pushMessage: (message: Message) => void; deleteRoom: (id: string) => void; + fillCurrentMessages: (messages: Message[]) => void; fillRecentRooms: (rooms: ChatRoom[]) => void; setIsLoading: (isLoading: boolean) => void; selectNewChatID: (id: string) => void; @@ -46,6 +48,18 @@ export const useChatStore = create()((set) => ({ currentRoomMessages: chatRooms.find((room) => room.id === "1") ?.messages as Message[], + pushMessage: (message: Message) => + set((state) => { + state.currentMessages = [...state.currentMessages, message]; + + return { ...state }; + }), + fillCurrentMessages: (messages: Message[]) => + set((state) => { + state.currentMessages = [...messages]; + return { ...state }; + }), + deleteRoom: (id: string) => set((state) => { const roomIndex = chatRooms.findIndex((room) => room.id === id); @@ -65,7 +79,7 @@ export const useChatStore = create()((set) => ({ state.isLoading = isLoading; return { ...state }; }), - + fillRecentRooms: (rooms: ChatRoom[]) => set((state) => { chatRooms.length = 0; From 08bc2cbd93f349cc4dca001e03d5c66b403c54d1 Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Fri, 3 Nov 2023 09:37:14 +0100 Subject: [PATCH 08/11] finish rooms realtime chat --- .DS_Store | Bin 8196 -> 8196 bytes frontend/.DS_Store | Bin 6148 -> 6148 bytes .../Chat/Components/Conversation.tsx | 177 +++++------ .../Chat/Components/RoomChatHelpers.tsx | 297 +++++++++--------- .../Chat/Components/tools/Assets.tsx | 16 +- .../Chat/Controllers/RoomChatControllers.tsx | 12 + .../src/Components/Chat/assets/options.svg | 4 + 7 files changed, 258 insertions(+), 248 deletions(-) create mode 100644 frontend/code/src/Components/Chat/assets/options.svg diff --git a/.DS_Store b/.DS_Store index f9a38f55aadd092c5bee688852819c116735c43b..b370c47e970336732a58c9d76976551d18cf0135 100644 GIT binary patch delta 142 zcmZp1XmQw}DiAl%(UpOLfrUYjA)O(Up(Hoo#U&{xKM5$t!NAbKai;R9BdUA~UipFy z!{Frn+ybB;24;#EMviDZT6c20Lk { const [MyUsers] = useState(users); const currentUser = useUserStore((state) => state); @@ -54,11 +56,19 @@ export const CurrentUserMessage = ({ {formatTime(time)}
-
+
{message}
-
- Delivered +
+ {isFailed ? "Failed" : "Delivered"}
) : ( @@ -108,11 +118,8 @@ export const ConversationHeader: React.FC = ({
-
@@ -283,9 +290,11 @@ export const Conversation: React.FC = ({ } }; + const [isFail, SetFailedMsg] = useState(false); const currentUser = useUserStore((state) => state); const [inputValue, setInputValue] = useState(""); const [FailToSendMessage, setFail] = useState(false); + const [IsLoading, setLoading] = useState(true); const handleInputChange = (e: { target: { value: React.SetStateAction }; @@ -293,6 +302,9 @@ export const Conversation: React.FC = ({ setFail(false); setInputValue(e.target.value); }; + useEffect(() => { + scrollToBottom(); + }, [chatState.currentMessages?.length]); useEffect(() => { function onConnect() { @@ -301,43 +313,36 @@ export const Conversation: React.FC = ({ socket.on("connect", onConnect); - socket.on( - "message", - (message: { - id: string; - avatar: { - thumbnail: string; - medium: string; - large: string; + const handleMessage = (message: { + id: string; + avatar: { + thumbnail: string; + medium: string; + large: string; + }; + content: string; + time: string; + roomId: string; + authorId: string; + }) => { + console.log(message); + if (message.roomId === chatState.selectedChatID) { + const NewMessage: Message = { + avatar: message.avatar, + senderId: message.authorId, + message: message.content, + time: message.time, }; - content: string; - time: string; - roomId: string; - authorId: string; - }) => { - console.log(message); - if (message.roomId === chatState.selectedChatID) { - const NewMessage: Message = { - avatar: message.avatar, - senderId: message.authorId, - message: message.content, - time: message.time, - }; - - if ( - chatState.currentMessages.findIndex( - (message) => message.id === NewMessage.id - ) === -1 - ) { - chatState.pushMessage(NewMessage); - } - } + chatState.pushMessage(NewMessage); scrollToBottom(); } - ); + }; + socket.on("message", handleMessage); - const fetch = async () => + const fetch = async () => { + setLoading(true); getRoomMessagesCall(chatState.selectedChatID, 0, 30).then((res) => { + setLoading(false); if (res?.status !== 200 && res?.status !== 201) { } else { const messages: Message[] = []; @@ -365,32 +370,37 @@ export const Conversation: React.FC = ({ chatState.fillCurrentMessages(messages.reverse()); } }); + }; - fetch().then((res) => { + fetch().then(() => { scrollToBottom(); }); - }, [chatState.selectedChatID]); - - const handleKeyPress = (e: KeyboardEvent) => { - if (e.key === "Enter") { - if (inputValue.length > 0) { - chatState.pushMessage({ - avatar: { - thumbnail: "", - medium: "", - large: "", - }, - senderId: currentUser.id, - message: inputValue, - time: Date().toString(), - }); - scrollToBottom(); + // Cleanup function to remove event listeners when component unmounts + return () => { + socket.off("connect", onConnect); + socket.off("message", handleMessage); + }; + }, [chatState.selectedChatID]); - setInputValue(""); + const sendMessage = async () => { + if (inputValue.length === 0) return; + await sendMessageCall(chatState.selectedChatID, inputValue).then((res) => { + setInputValue(""); + if (res?.status !== 200 && res?.status !== 201) { + SetFailedMsg(true); + setFail(true); + toast.error("you are not authorized to send messages in this room"); + chatState.setMessageAsFailed(res?.data.id); + } else { } + }); + }; + + const handleKeyPress = async (e: KeyboardEvent) => { + if (e.key === "Enter") { + await sendMessage().then(() => scrollToBottom()); } - // do stuff }; return ( @@ -400,19 +410,26 @@ export const Conversation: React.FC = ({ className="flex-grow overflow-y-auto no-scrollbar " ref={messageContainerRef} > - {(chatState.currentMessages?.length as number) > 0 ? ( - chatState.currentMessages?.map((message) => ( - - )) + {IsLoading === false ? ( + (chatState.currentMessages?.length as number) > 0 ? ( + chatState.currentMessages?.map((message) => ( + + )) + ) : ( + + ) ) : ( - +
+ +
)}
@@ -433,23 +450,7 @@ export const Conversation: React.FC = ({

- { - room.last_message?.content ?? "No Messages*"} + {room.last_message?.content ?? "No Messages*"}

{room.last_message !== null && ( -
+
- ) - - } + )}
@@ -355,7 +351,6 @@ export const FriendTile = (props: { user: RoomMember }) => { ); }; - export const BlockedFriendTile = (props: { user: RoomMember }) => { const [IsAdding, setIsAdding] = useState(false); const selectedChatID = useChatStore((state) => state.selectedChatID); @@ -383,17 +378,15 @@ export const BlockedFriendTile = (props: { user: RoomMember }) => {
@@ -290,7 +282,6 @@ export const Conversation: React.FC = ({ } }; - const [isFail, SetFailedMsg] = useState(false); const currentUser = useUserStore((state) => state); const [inputValue, setInputValue] = useState(""); const [FailToSendMessage, setFail] = useState(false); @@ -307,12 +298,6 @@ export const Conversation: React.FC = ({ }, [chatState.currentMessages?.length]); useEffect(() => { - function onConnect() { - console.log("hello"); - } - - socket.on("connect", onConnect); - const handleMessage = (message: { id: string; avatar: { @@ -375,12 +360,10 @@ export const Conversation: React.FC = ({ fetch().then(() => { scrollToBottom(); }); - - // Cleanup function to remove event listeners when component unmounts return () => { - socket.off("connect", onConnect); socket.off("message", handleMessage); }; + // eslint-disable-next-line }, [chatState.selectedChatID]); const sendMessage = async () => { @@ -388,11 +371,25 @@ export const Conversation: React.FC = ({ await sendMessageCall(chatState.selectedChatID, inputValue).then((res) => { setInputValue(""); if (res?.status !== 200 && res?.status !== 201) { - SetFailedMsg(true); setFail(true); toast.error("you are not authorized to send messages in this room"); chatState.setMessageAsFailed(res?.data.id); } else { + // for debug + if (chatState.selectedChatType === ChatType.Chat) { + const message: Message = { + id: res.data.id, + avatar: { + thumbnail: currentUser.picture.thumbnail, + medium: currentUser.picture.medium, + large: currentUser.picture.large, + }, + senderId: currentUser.id, + message: res.data.content, + time: res.data.time, + }; + chatState.pushMessage(message); + } } }); }; diff --git a/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx b/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx index 59f06d0..2c89e64 100644 --- a/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx +++ b/frontend/code/src/Components/Chat/Components/RoomChatHelpers.tsx @@ -7,12 +7,12 @@ import { Lock, More, NullImage, - NullUser, + RoomMember, RoomType, Unlock, chatRooms, - check, + groupIcon, } from "./tools/Assets"; @@ -119,12 +119,12 @@ export const RoomChatPlaceHolder = () => { {room?.membersCount} Members

-
+

{room.last_message?.content ?? "No Messages*"}

{room.last_message !== null && ( -
+
@@ -359,7 +359,6 @@ export const FriendTile = (props: { user: RoomMember }) => { export const BlockedFriendTile = (props: { user: RoomMember }) => { const [IsAdding, setIsAdding] = useState(false); - const selectedChatID = useChatStore((state) => state.selectedChatID); const LayoutState = useModalStore((state) => state); const user = props.user; @@ -408,12 +407,10 @@ export const BlockedFriendTile = (props: { user: RoomMember }) => { export const BlockedUsersModal = () => { const [currentFriends, setUsers] = useState([]); - const [currentRoomMembers, setRoomMembers] = useState([]); const LayoutState = useModalStore((state) => state); const [IsLoading, setIsLoading] = useState(false); const [skipCount, setSkipCount] = useState(true); - const ChatState = useChatStore((state) => state); useEffect(() => { if (skipCount) setSkipCount(false); diff --git a/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx b/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx index d5fb7b6..d1a3c5a 100644 --- a/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx +++ b/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx @@ -4,7 +4,6 @@ import { Conversation } from "./Conversation"; import { useParams } from "react-router-dom"; import api from "../../../Api/base"; import { useChatStore } from "../Controllers/RoomChatControllers"; -import { RoomMember, chatRooms } from "./tools/Assets"; export const UserToUserChat = () => { const params = useParams(); @@ -14,9 +13,10 @@ export const UserToUserChat = () => { const [showUserPreview, setShowUserPreview] = useState(true); useEffect(() => { + console.log("selected chat id ", ChatState.selectedChatID); const fetchUser = async () => { try { - const res = await api.get(`profile/${params.id}`).then((res) => { + await api.get(`profile/${params.id}`).then((res) => { console.log(res.data); ChatState.setCurrentDmUser({ id: res.data.id, diff --git a/frontend/code/src/Components/Chat/Services/SocketsServices.ts b/frontend/code/src/Components/Chat/Services/SocketsServices.ts index 2718520..4c1e0d9 100644 --- a/frontend/code/src/Components/Chat/Services/SocketsServices.ts +++ b/frontend/code/src/Components/Chat/Services/SocketsServices.ts @@ -1,8 +1,5 @@ import { io } from 'socket.io-client'; -// "undefined" means the URL will be computed from the `window.location` object -const URL = process.env.NODE_ENV === 'production' ? undefined : 'http://localhost:4000'; - export const socket = io("http://localhost:3004", { transports: ['websocket'], diff --git a/frontend/code/src/Components/Chat/index.tsx b/frontend/code/src/Components/Chat/index.tsx index 3122ba8..a2a1e85 100644 --- a/frontend/code/src/Components/Chat/index.tsx +++ b/frontend/code/src/Components/Chat/index.tsx @@ -10,14 +10,13 @@ import { import { useEffect, useState } from "react"; import { Conversation } from "./Components/Conversation"; import { ChatPaceHolderProps } from "./Components/Conversation"; -import users from "./Components/tools/Assets"; + import React from "react"; import { ChatType, useChatStore } from "./Controllers/RoomChatControllers"; import { RecentConversations } from "./Components/RecentChat"; import { AddUsersModal, - BlockedUsersModal, CreateNewRoomModal, ExploreRoomsModal, NullPlaceHolder, @@ -30,7 +29,6 @@ import { getRoomMembersCall } from "./Services/ChatServices"; import toast from "react-hot-toast"; import { classNames } from "../../Utils/helpers"; import { useModalStore } from "./Controllers/LayoutControllers"; -import { socket } from "./Services/SocketsServices"; export interface ConversationProps { onRemoveUserPreview: () => void; @@ -104,7 +102,6 @@ export const UserPreviewCard: React.FC = ({ }) => { const [isLoading, setIsLoading] = useState(false); const [currentUsers, setUsers] = useState([]); - const [MyUsers] = useState(users); const LayoutState = useModalStore((state) => state); const SelectedChat = useChatStore((state) => state.selectedChatID); @@ -203,7 +200,7 @@ export const UserPreviewCard: React.FC = ({ {}

{currentRoom?.name}'s Members

-
+
{isLoading === false ? ( <> {currentUsers.map((user) => ( diff --git a/frontend/code/src/Components/Layout/index.tsx b/frontend/code/src/Components/Layout/index.tsx index 6c5e093..ae9767e 100644 --- a/frontend/code/src/Components/Layout/index.tsx +++ b/frontend/code/src/Components/Layout/index.tsx @@ -14,6 +14,7 @@ import { matchRoutes, useLocation } from "react-router-dom"; import { useUserStore } from "../../Stores/stores"; import { useNavigate } from "react-router-dom"; import { FirstLogin } from "../FirstLogin"; +import { socket } from "../Chat/Services/SocketsServices"; const routes = [ { path: "Profile/:id" }, @@ -32,6 +33,9 @@ const useCurrentPath = () => { return route.path; }; +function onConnect() { + console.log("hello"); +} export const Layout: FC = (): JSX.Element => { const user = useUserStore(); const navigate = useNavigate(); @@ -45,7 +49,12 @@ export const Layout: FC = (): JSX.Element => { user.logout(); } }; + + socket.on("connect", onConnect); log(); + return () => { + socket.off("connect", onConnect); + }; //eslint-disable-next-line }, []); const path: string = useCurrentPath(); diff --git a/frontend/code/src/Components/Profile/index.tsx b/frontend/code/src/Components/Profile/index.tsx index 7dc26e4..fa844c4 100644 --- a/frontend/code/src/Components/Profile/index.tsx +++ b/frontend/code/src/Components/Profile/index.tsx @@ -14,7 +14,6 @@ import { Edit } from "./assets/Edit"; import { useUserStore } from "../../Stores/stores"; import dots from "./assets/svg/threedots.svg"; import api from "../../Api/base"; -import { GroupChat } from "../Chat/Components/tools/Assets"; import { BlockedUsersModal } from "../Chat/Components/RoomChatHelpers"; import { useModalStore } from "../Chat/Controllers/LayoutControllers"; import { createNewRoomCall } from "../Chat/Services/ChatServices"; From a9c43d66e2eacc876788329a44c7a4d7b6720553 Mon Sep 17 00:00:00 2001 From: Wadie-ess Date: Sun, 5 Nov 2023 12:42:08 +0100 Subject: [PATCH 11/11] Finish Rooms Socket --- frontend/code/package-lock.json | 80 +++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/frontend/code/package-lock.json b/frontend/code/package-lock.json index 1a0aa2e..219bfb2 100644 --- a/frontend/code/package-lock.json +++ b/frontend/code/package-lock.json @@ -32,6 +32,7 @@ "react-icons": "^4.10.1", "react-konva": "^18.2.10", "react-scripts": "^5.0.1", + "socket.io-client": "^4.7.2", "typescript": "^4.9.5", "web-vitals": "^2.1.4", "zustand": "^4.4.1" @@ -4619,6 +4620,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -8043,6 +8049,46 @@ "node": ">= 0.8" } }, + "node_modules/engine.io-client": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz", + "integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -15598,6 +15644,32 @@ "node": ">=8" } }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -17926,6 +17998,14 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",