diff --git a/.DS_Store b/.DS_Store index 11c1dac..b370c47 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/backend/.DS_Store b/backend/.DS_Store index 7967f16..04ef7ff 100644 Binary files a/backend/.DS_Store and b/backend/.DS_Store differ 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/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/backend/code/src/rooms/rooms.service.ts b/backend/code/src/rooms/rooms.service.ts index 52b5e12..0413fcc 100644 --- a/backend/code/src/rooms/rooms.service.ts +++ b/backend/code/src/rooms/rooms.service.ts @@ -407,9 +407,11 @@ export class RoomsService { }, }, is_banned: true, + 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}`, @@ -421,6 +423,8 @@ export class RoomsService { firstname: member.user.firstName, lastname: member.user.lastName, avatar: avatar, + isBaned: member.is_banned, + isMuted: member.is_mueted, }; } }); diff --git a/frontend/.DS_Store b/frontend/.DS_Store index d8a764c..821dbcd 100644 Binary files a/frontend/.DS_Store and b/frontend/.DS_Store differ 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", 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/Components/Conversation.tsx b/frontend/code/src/Components/Chat/Components/Conversation.tsx index 748c479..7e5916a 100644 --- a/frontend/code/src/Components/Chat/Components/Conversation.tsx +++ b/frontend/code/src/Components/Chat/Components/Conversation.tsx @@ -1,11 +1,12 @@ import { useEffect, useRef, useState } from "react"; import { ConversationProps } from ".."; -import users, { +import { Message, groupIcon, chatRooms, More, Send, + Options, } from "./tools/Assets"; import { ChatType, useChatStore } from "../Controllers/RoomChatControllers"; @@ -20,6 +21,8 @@ import { } from "../Services/MessagesServices"; import { useUserStore } from "../../../Stores/stores"; +import { formatTime } from "./tools/utils"; +import { socket } from "../Services/SocketsServices"; export interface ChatPaceHolderProps { username: string; @@ -31,46 +34,47 @@ export interface ChatPaceHolderProps { id: string; } -export const CurrentUserMessage = ({ message, time, senderId }: Message) => { - const [MyUsers] = useState(users); +export const CurrentUserMessage = ({ + message, + time, + senderId, + avatar, + isFailed, +}: Message) => { const currentUser = useUserStore((state) => state); - const SelectedChat = useChatStore((state) => state.selectedChatID); - const selectedChatType = useChatStore((state) => state.selectedChatType); - - const currentChatMessages = MyUsers.find((user) => user.id === SelectedChat); - return senderId === currentUser.id ? (
-
+
{message}
-
- Delivered +
+ {isFailed ? "Failed" : "Delivered"}
) : (
- {selectedChatType === ChatType.Chat ? ( - - ) : ( - user.id === senderId)?.image} - alt="" - /> - )} +
@@ -84,13 +88,11 @@ export const CurrentUserMessage = ({ message, time, senderId }: Message) => { export const ConversationHeader: React.FC = ({ onRemoveUserPreview, }) => { - const [MyUsers] = useState(users); - const LayoutState = useModalStore((state) => state); const ChatState = useChatStore((state) => state); const SelectedChat = useChatStore((state) => state.selectedChatID); - const currentUser = MyUsers.find((user) => user.id === SelectedChat); + const currentUser = useChatStore((state) => state.currentDmUser); const selectedChatType = useChatStore((state) => state.selectedChatType); const currentRoom = chatRooms.find((room) => room.id === SelectedChat); @@ -108,11 +110,8 @@ export const ConversationHeader: React.FC = ({
-
@@ -122,7 +121,7 @@ export const ConversationHeader: React.FC = ({ alt="" src={ selectedChatType === ChatType.Chat - ? currentUser?.image + ? currentUser?.avatar.large : groupIcon } /> @@ -130,7 +129,7 @@ export const ConversationHeader: React.FC = ({

{selectedChatType === ChatType.Chat - ? currentUser?.name + ? currentUser?.firstname : currentRoom?.isOwner ? currentRoom.name + " ♚" : currentRoom?.name} @@ -141,7 +140,7 @@ export const ConversationHeader: React.FC = ({

) : (

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

)}
@@ -191,7 +190,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) && (
@@ -277,91 +275,158 @@ 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); + const [IsLoading, setLoading] = useState(true); - // 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(() => { + scrollToBottom(); + }, [chatState.currentMessages?.length]); useEffect(() => { - const fetch = async () => + 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, + }; + chatState.pushMessage(NewMessage); + scrollToBottom(); + } + }; + socket.on("message", handleMessage); + + 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[] = []; 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); + chatState.fillCurrentMessages(messages.reverse()); } }); + }; - fetch(); - scrollToBottom(); + fetch().then(() => { + scrollToBottom(); + }); + return () => { + socket.off("message", handleMessage); + }; + // eslint-disable-next-line }, [chatState.selectedChatID]); - const scrollToBottom = () => { - if (messageContainerRef.current) { - messageContainerRef.current.scrollTop = - messageContainerRef.current.scrollHeight; - } + const sendMessage = async () => { + if (inputValue.length === 0) return; + await sendMessageCall(chatState.selectedChatID, inputValue).then((res) => { + setInputValue(""); + if (res?.status !== 200 && res?.status !== 201) { + 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); + } + } + }); }; - const handleKeyPress = (e: KeyboardEvent) => { + const handleKeyPress = async (e: KeyboardEvent) => { if (e.key === "Enter") { - // validation check - if (inputValue.length > 0) { - pushMessage({ - senderId: "2", - message: inputValue, - isRead: false, - time: "10", - }); - setInputValue(""); - } + await sendMessage().then(() => scrollToBottom()); } - // do stuff }; return (
- {(CurrentsMessages?.length as number) > 0 ? ( - CurrentsMessages?.map((message) => ( - - )) + {IsLoading === false ? ( + (chatState.currentMessages?.length as number) > 0 ? ( + chatState.currentMessages?.map((message) => ( + + )) + ) : ( + + ) ) : ( - +
+ +
)}
@@ -382,30 +447,7 @@ export const Conversation: React.FC = ({ +
+
+
+ ); +}; + +export const BlockedUsersModal = () => { + const [currentFriends, setUsers] = useState([]); + const LayoutState = useModalStore((state) => state); + const [IsLoading, setIsLoading] = useState(false); + + const [skipCount, setSkipCount] = useState(true); + + 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 +532,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); } ); @@ -442,7 +594,7 @@ export const AddUsersModal = () => { ) ) .map((user) => ( - + ))}
)} @@ -476,15 +628,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 +673,7 @@ export const RoomSettingsModal = () => { }, [LayoutState.showSettingsModal]); const resetModalState = () => { + setUpdate(false); setPassword(""); setSelectedOption(currentRoom?.type as RoomType); setName(currentRoom?.name as string); @@ -525,7 +681,7 @@ export const RoomSettingsModal = () => { return (
-
+
{TakingAction === true ? (
@@ -560,7 +716,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); + }} />
@@ -609,81 +774,59 @@ export const RoomSettingsModal = () => {
) : ( -
+
{currentUsers.length < 2 && ( )} - {currentUsers - .filter((user) => user.id !== currentUser.id) - .map((user) => ( -
-
-
- -
+
+ {currentUsers + .filter((user) => user.id !== currentUser.id) + .map((user) => ( +
+
+
+ +
-

- {user?.firstname ?? "user"} -

-
+

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

+
-
- -
    -
  • { - setTakeAction(true); - await takeActionCall( - selectedChatID as string, - user.id, - user.isBaned ? "unban" : "ban" - ).then((res) => { - setTakeAction(false); - if (res?.status === 200 || res?.status === 201) { - toast.success(res.data.message); - } - LayoutState.setShowSettingsModal( - !LayoutState.showSettingsModal - ); - }); - }} + +
      - - {user.isBaned ? "UnBan" : "Ban"} - - - - {user.isMuted === false && (
    • { setTakeAction(true); await takeActionCall( selectedChatID as string, user.id, - "mute" + user.isBaned ? "unban" : "ban" ).then((res) => { setTakeAction(false); if ( res?.status === 200 || res?.status === 201 ) { - toast.success( - "User Muted For a 5 minutes Successfully" - ); + toast.success(res.data.message); } LayoutState.setShowSettingsModal( !LayoutState.showSettingsModal @@ -691,56 +834,92 @@ export const RoomSettingsModal = () => { }); }} > - mute + + {user.isBaned ? "UnBan" : "Ban"} +
    • - )} - -
    • { - setTakeAction(true); - await takeActionCall( - selectedChatID as string, - user.id, - "kick" - ).then((res) => { - setTakeAction(false); - LayoutState.setShowSettingsModal( - !LayoutState.showSettingsModal - ); - - if (res?.status === 200 || res?.status === 201) { - toast.success("User Kicked Successfully"); - } - }); - }} - > - kick -
    • -
    • { - setTakeAction(true); - await takeActionCall( - selectedChatID as string, - user.id, - "setAdmin" - ).then((res) => { - setTakeAction(false); - if (res?.status === 200 || res?.status === 201) { - toast.success( - "User have been set as Admin Successfully" + + {user.isMuted === false && ( +
    • { + setTakeAction(true); + await takeActionCall( + selectedChatID as string, + user.id, + "mute" + ).then((res) => { + setTakeAction(false); + if ( + res?.status === 200 || + res?.status === 201 + ) { + toast.success( + "User Muted For a 5 minutes Successfully" + ); + } + LayoutState.setShowSettingsModal( + !LayoutState.showSettingsModal + ); + }); + }} + > + mute +
    • + )} + +
    • { + setTakeAction(true); + await takeActionCall( + selectedChatID as string, + user.id, + "kick" + ).then((res) => { + setTakeAction(false); + LayoutState.setShowSettingsModal( + !LayoutState.showSettingsModal ); - } - }); - }} - > - - Set as admin - -
    • -
    + + if ( + res?.status === 200 || + res?.status === 201 + ) { + toast.success("User Kicked Successfully"); + } + }); + }} + > + kick +
  • +
  • { + setTakeAction(true); + await takeActionCall( + selectedChatID as string, + user.id, + "setAdmin" + ).then((res) => { + setTakeAction(false); + if ( + res?.status === 200 || + res?.status === 201 + ) { + toast.success( + "User have been set as Admin Successfully" + ); + } + }); + }} + > + + Set as admin + +
  • +
+
-
- ))} + ))} +
)} @@ -776,38 +955,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 "} + + )}
diff --git a/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx b/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx index 4d0a34d..d1a3c5a 100644 --- a/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx +++ b/frontend/code/src/Components/Chat/Components/UserToUserChat.tsx @@ -1,13 +1,42 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { UserPreviewCard } from ".."; import { Conversation } from "./Conversation"; +import { useParams } from "react-router-dom"; +import api from "../../../Api/base"; +import { useChatStore } from "../Controllers/RoomChatControllers"; export const UserToUserChat = () => { + const params = useParams(); + console.log(`params : ${params.id} type ${typeof params.id}`); + + const ChatState = useChatStore((state) => state); const [showUserPreview, setShowUserPreview] = useState(true); - const handleRemoveUserPreview = () => { + useEffect(() => { + console.log("selected chat id ", ChatState.selectedChatID); + const fetchUser = async () => { + try { + await api.get(`profile/${params.id}`).then((res) => { + console.log(res.data); + ChatState.setCurrentDmUser({ + id: res.data.id, + firstname: res.data.name.first, + lastname: res.data.name.last, + avatar: { + thumbnail: res.data.picture.thumbnail, + medium: res.data.picture.medium, + large: res.data.picture.large, + }, + bio: res.data.bio, + }); + }); + } catch (error) {} + }; + fetchUser(); + // eslint-disable-next-line + }, [params]); + const handleRemoveUserPreview = () => { setShowUserPreview(!showUserPreview); - }; return ( <> @@ -29,59 +58,54 @@ export const UserToUserChat = () => { ); }; -
- - - - + + +
-
-
-
-
- Avatar Tailwind CSS Component + + + + - - -
+
+
+
+
+ Avatar Tailwind CSS Component +
+ {/*
{user.name}
*/} +
+
+ +
    +
  • + Block +
  • +
  • + + invite for a Pong Game + +
  • +
  • + + Show User Info + +
  • +
- {/*
{user.name}
*/} -
-
- -
    -
  • - - Block - -
  • -
  • - - invite for a Pong Game - -
  • -
  • - - Show User Info - -
  • -
- -
-
- - +
+
; diff --git a/frontend/code/src/Components/Chat/Components/tools/Assets.tsx b/frontend/code/src/Components/Chat/Components/tools/Assets.tsx index 541f7ce..596ebd8 100644 --- a/frontend/code/src/Components/Chat/Components/tools/Assets.tsx +++ b/frontend/code/src/Components/Chat/Components/tools/Assets.tsx @@ -23,6 +23,8 @@ 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"; +import Options from "../../assets/options.svg"; export enum RoomType { private, public, @@ -55,6 +57,8 @@ export { ChatGif, NullUser, owner, + exploreIcon, + Options, }; export interface Message { @@ -63,7 +67,13 @@ export interface Message { senderId: string; message: string; time: string; + avatar?: { + thumbnail: string; + medium: string; + large: string; + }; isRead?: boolean; + isFailed?: boolean; } export interface RoomMember { @@ -75,6 +85,7 @@ export interface RoomMember { medium: string; large: string; }; + bio?: string; isBaned?: boolean; isMuted?: boolean; } @@ -88,6 +99,10 @@ 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/Controllers/RoomChatControllers.tsx b/frontend/code/src/Components/Chat/Controllers/RoomChatControllers.tsx index 8b4731f..d52d5a5 100644 --- a/frontend/code/src/Components/Chat/Controllers/RoomChatControllers.tsx +++ b/frontend/code/src/Components/Chat/Controllers/RoomChatControllers.tsx @@ -2,6 +2,7 @@ import { create } from "zustand"; import users, { ChatRoom, Message, + RoomMember, RoomType, chatRooms, } from "../Components/tools/Assets"; @@ -15,13 +16,19 @@ export interface ChatState { selectedChatType: ChatType; selectedChatID: string; currentMessages: Message[]; + currentDmUser: RoomMember; currentRoomMessages: Message[]; isLoading: boolean; showChatRooms: boolean; recentRooms: ChatRoom[]; + + setCurrentDmUser: (user: RoomMember) => void; + setMessageAsFailed: (id: string) => void; + pushMessage: (message: Message) => void; deleteRoom: (id: string) => void; + fillCurrentMessages: (messages: Message[]) => void; fillRecentRooms: (rooms: ChatRoom[]) => void; setIsLoading: (isLoading: boolean) => void; selectNewChatID: (id: string) => void; @@ -40,12 +47,51 @@ export const useChatStore = create()((set) => ({ // UI state showChatRooms: false, + currentDmUser: { + id: "1", + firstname: "John", + lastname: "Doe", + avatar: { + thumbnail: "", + medium: "", + large: "", + }, + }, // to fix this currentMessages: users.find((user) => user.id === "1")?.messages as Message[], currentRoomMessages: chatRooms.find((room) => room.id === "1") ?.messages as Message[], + setCurrentDmUser: (user: RoomMember) => + set((state) => { + state.currentDmUser = user; + return { ...state }; + }), + + setMessageAsFailed: (id: string) => + set((state) => { + const messageIndex = state.currentMessages.findIndex( + (message) => message.id === id + ); + if (messageIndex !== -1) { + state.currentMessages[messageIndex].isFailed = true; + } + return { ...state }; + }), + + 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 +111,7 @@ export const useChatStore = create()((set) => ({ state.isLoading = isLoading; return { ...state }; }), - + fillRecentRooms: (rooms: ChatRoom[]) => set((state) => { chatRooms.length = 0; diff --git a/frontend/code/src/Components/Chat/Services/ChatServices.ts b/frontend/code/src/Components/Chat/Services/ChatServices.ts index f0dc5a7..632906b 100644 --- a/frontend/code/src/Components/Chat/Services/ChatServices.ts +++ b/frontend/code/src/Components/Chat/Services/ChatServices.ts @@ -4,7 +4,8 @@ import api from "../../../Api/base"; export const createNewRoomCall = async ( name: string, type: string, - password?: string + password?: string, + secondMember? : string, ) => { try { @@ -12,6 +13,7 @@ export const createNewRoomCall = async ( name: name, type: type, password: password, + secondMember: secondMember, }); console.log(response.data); console.log(response.status); @@ -199,3 +201,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/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/Services/SocketsServices.ts b/frontend/code/src/Components/Chat/Services/SocketsServices.ts new file mode 100644 index 0000000..4c1e0d9 --- /dev/null +++ b/frontend/code/src/Components/Chat/Services/SocketsServices.ts @@ -0,0 +1,7 @@ +import { io } from 'socket.io-client'; + + +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/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 @@ + + + + + + + + + + diff --git a/frontend/code/src/Components/Chat/assets/options.svg b/frontend/code/src/Components/Chat/assets/options.svg new file mode 100644 index 0000000..46fe33b --- /dev/null +++ b/frontend/code/src/Components/Chat/assets/options.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/code/src/Components/Chat/index.tsx b/frontend/code/src/Components/Chat/index.tsx index 4dc9721..a2a1e85 100644 --- a/frontend/code/src/Components/Chat/index.tsx +++ b/frontend/code/src/Components/Chat/index.tsx @@ -10,7 +10,7 @@ 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"; @@ -45,6 +45,7 @@ export const Chat = () => { const handleRemoveUserPreview = () => { setShowUserPreview(!showUserPreview); }; + return ( <>
@@ -101,11 +102,10 @@ 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); - const currentUser = MyUsers.find((user) => user.id === SelectedChat); + const currentUser = useChatStore((state) => state.currentDmUser); const selectedChatType = useChatStore((state) => state.selectedChatType); const currentRoom = chatRooms.find((room) => room.id === SelectedChat); @@ -142,7 +142,7 @@ export const UserPreviewCard: React.FC = ({
{selectedChatType === ChatType.Chat ? (

- {currentUser?.name}'s Info + {currentUser?.firstname}'s Info

) : (

@@ -164,14 +164,16 @@ export const UserPreviewCard: React.FC = ({ className="w-36 rounded-full " alt="" src={ - selectedChatType === ChatType.Chat ? currentUser?.image : groupIcon + selectedChatType === ChatType.Chat + ? currentUser?.avatar.large + : groupIcon } />

{selectedChatType === ChatType.Chat - ? currentUser?.name + ? currentUser?.firstname : currentRoom?.name}

@@ -183,11 +185,11 @@ export const UserPreviewCard: React.FC = ({
{} -

{currentUser?.name}'s Bio

+

{currentUser?.firstname}'s Bio

-

- hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +

+ {currentUser?.bio ?? "NO"}

@@ -198,16 +200,16 @@ export const UserPreviewCard: React.FC = ({ {}

{currentRoom?.name}'s Members

-
+
{isLoading === false ? ( <> {currentUsers.map((user) => ( -
+
Avatar Tailwind CSS Component
diff --git a/frontend/code/src/Components/Layout/index.tsx b/frontend/code/src/Components/Layout/index.tsx index 225f958..ae9767e 100644 --- a/frontend/code/src/Components/Layout/index.tsx +++ b/frontend/code/src/Components/Layout/index.tsx @@ -14,10 +14,11 @@ 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" }, + { path: "Dm/:id" }, { path: "Settings" }, { path: "Home" }, { path: "Chat" }, @@ -26,13 +27,15 @@ const routes = [ { path: "Game" }, ]; - const useCurrentPath = () => { const location = useLocation(); const [{ route }]: any = matchRoutes(routes, location); return route.path; }; +function onConnect() { + console.log("hello"); +} export const Layout: FC = (): JSX.Element => { const user = useUserStore(); const navigate = useNavigate(); @@ -40,16 +43,18 @@ export const Layout: FC = (): JSX.Element => { useLayoutEffect(() => { const log = async () => { try { - await user.login(); + await user.login(); + } catch (e) { + navigate("/"); + user.logout(); } - catch(e){ - navigate("/"); - user.logout(); - } - - }; + + socket.on("connect", onConnect); log(); + return () => { + socket.off("connect", onConnect); + }; //eslint-disable-next-line }, []); const path: string = useCurrentPath(); @@ -62,7 +67,6 @@ export const Layout: FC = (): JSX.Element => {
@@ -80,11 +84,14 @@ export const Layout: FC = (): JSX.Element => { - +
- +
diff --git a/frontend/code/src/Components/Profile/index.tsx b/frontend/code/src/Components/Profile/index.tsx index 6bcf321..fa844c4 100644 --- a/frontend/code/src/Components/Profile/index.tsx +++ b/frontend/code/src/Components/Profile/index.tsx @@ -1,105 +1,186 @@ -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 { BlockedUsersModal } from "../Chat/Components/RoomChatHelpers"; +import { useModalStore } from "../Chat/Controllers/LayoutControllers"; +import { createNewRoomCall } from "../Chat/Services/ChatServices"; +import toast from "react-hot-toast"; +import { + ChatType, + useChatStore, +} from "../Chat/Controllers/RoomChatControllers"; // 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(); + const ChatState = useChatStore((state) => state); + 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" ? - (<> - ) - : - ( - - ) +
+
+
+ {users?.name?.first ? ( +
+ {users?.name?.first} {users.name.last}{" "} +
+ ) : ( + + )}{" "} +
+ + {users?.bio} +
+
+
+ {params.id !== "me" ? ( + <> +
{ + await createNewRoomCall( + "", + "dm", + undefined, + params.id + ).then((res) => { + if (res?.status === 200 || res?.status === 201) { + ChatState.changeChatType(ChatType.Chat); + ChatState.selectNewChatID(res?.data?.id); + ChatState.setCurrentDmUser({ + id: users?.id, + firstname: users?.name.first, + lastname: users?.name.last, + avatar: { + thumbnail: users?.picture.thumbnail, + medium: users?.picture.medium, + large: users?.picture.large, + }, + bio: users?.bio, + }); + navigate(`/Dm/${params.id}`); + } else { + toast.error( + "You Can't Send Message To this User For Now, try Again later" + ); } -
-
- newbie badge - Master badge - Ultimate badge -
- -
    -
  • Block
  • -
  • Send friend request
  • -
-
-
-
+ }); + }} + > + +
+ + + ) : ( + + + + )}
-
- +
+ newbie badge + Master badge + Ultimate badge +
+ +
    +
  • +
    Block
    +
  • +
  • +
    Send friend request
    +
  • +
  • { + LayoutState.setShowBlockedList( + !LayoutState.showBlockedLIstModal + ); + }} + > + +
    See Blocked List
    +
    +
  • +
+
+
+
+
+
+
- ) -} \ No newline at end of file + ); +}; diff --git a/frontend/code/src/Routes/index.tsx b/frontend/code/src/Routes/index.tsx index 6960ede..5c08948 100644 --- a/frontend/code/src/Routes/index.tsx +++ b/frontend/code/src/Routes/index.tsx @@ -59,7 +59,7 @@ const router = createBrowserRouter([ }, }, { - path: "Pure", + path: "Dm/:id", lazy: async () => { let { UserToUserChat } = await import("../Components/Chat/Components/UserToUserChat"); return { Component: UserToUserChat }; diff --git a/package-lock.json b/package-lock.json index 53bd024..2110002 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "PongGame-WebApp", + "name": "PongGame-WebApp-1", "lockfileVersion": 3, "requires": true, "packages": { @@ -10,7 +10,8 @@ "@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" } }, "node_modules/@babel/code-frame": { @@ -662,6 +663,11 @@ "url": "https://opencollective.com/popperjs" } }, + "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/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -804,6 +810,22 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=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" } }