diff --git a/front-end/public/slavery-whip.svg b/front-end/public/slavery-whip.svg new file mode 100644 index 00000000..a3aacff2 --- /dev/null +++ b/front-end/public/slavery-whip.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/front-end/src/app/globals.css b/front-end/src/app/globals.css index 4506815d..a94debc0 100644 --- a/front-end/src/app/globals.css +++ b/front-end/src/app/globals.css @@ -195,7 +195,7 @@ body { .friends { position: absolute; top: 5.9px; - right: 0vw; + right: 0; display: flex; flex-direction: row; align-items: center; @@ -429,6 +429,44 @@ body { padding-left: 0.4vw; } +#adminOptionsSettings{ + position: relative; + bottom: 0; + right: 0; + margin: 0.5em; + padding: 0.5em; + background: rgba(0, 0, 0, 0.47); + border: 2px rgba(0, 0, 0, 0.11); + box-shadow: 3px 4px 10px rgba(0, 0, 0, 0.27); + border-radius: 8px; + z-index: 1; +} + +#muteDuration{ + position: relative; + width: 1vw; + bottom: 0; + right: 0; + margin: 0.5em; + padding: 0.5em; + background: rgba(0, 0, 0, 0.47); + border: 2px rgba(0, 0, 0, 0.11); + box-shadow: 3px 4px 10px rgba(0, 0, 0, 0.27); + border-radius: 8px; + z-index: 1; +} + +#muteDuration input{ + background-color: #2d3748; + padding: 0.5rem; + border-radius: 0.5rem; + color: #f56565; + height: 1rem; + text-align: center; + outline:inset; + width:42% +} + .game{ display: inline; margin-inline: auto; diff --git a/front-end/src/app/home/page.tsx b/front-end/src/app/home/page.tsx index 4c6ae9c2..6176ef26 100644 --- a/front-end/src/app/home/page.tsx +++ b/front-end/src/app/home/page.tsx @@ -18,6 +18,7 @@ export default function ShowHomePage() { router.push("/auth"); else setIsTokenExists(true); + return; }); return ( isTokenExists ? diff --git a/front-end/src/app/layout.tsx b/front-end/src/app/layout.tsx index e035accf..8c1f1834 100644 --- a/front-end/src/app/layout.tsx +++ b/front-end/src/app/layout.tsx @@ -1,5 +1,4 @@ import { Providers } from "@/context/providers"; -import { NavBar } from '@/components/(ben_proto)/DevTools/NavBarDev' import './globals.css' import { Inter } from 'next/font/google' @@ -24,7 +23,6 @@ export default function RootLayout({ {/*
*/} {children} -
diff --git a/front-end/src/components/(ben_proto)/DevTools/NavBarDev.tsx b/front-end/src/components/(ben_proto)/DevTools/NavBarDev.tsx deleted file mode 100644 index 72971ff3..00000000 --- a/front-end/src/components/(ben_proto)/DevTools/NavBarDev.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' -import Link from 'next/link' -import React, {useState, useContext, useEffect, } from 'react' -import {UserContext, LoggedContext} from "@/context/globalContext"; -import * as apiReq from '@/components/api/ApiReq' - - - -export function NavBar({className}: {className: string}) { - - const {userContext, setUserContext} = useContext(UserContext); - const {logged, setLogged} = useContext(LoggedContext); - const [isHovered, setIsHovered] = useState(false); - const [turnOffAuth, setTurnOffAuth] = useState(false); - // const [isHovered, setIsHovered] = useState(false); - - const [infoUser, setInfoUser] = useState(<>) - - useEffect(() => { - setInfoUser( -
id: -
{userContext?.UserID}
- | -
{userContext?.login}
- | -
{userContext?.nickname}
-
) - }, [userContext]) - - - const handleMouseEnter = () => { - setIsHovered(true); - } - - const handleMouseLeave = () => { - setIsHovered(false); - } - - - function Dropdown() { - const [isOpen, setIsOpen] = useState(false); - - return ( -
-
- -
- {isOpen && ( -
-
- -
-
- )} -
- ); -} - - - - -function toggleAuthRequired() { - if (turnOffAuth) - { - setLogged(false); - setTurnOffAuth(false); - } - else - { - setLogged(true); - setTurnOffAuth(true); - } -} - - function SubNav() { - - return ( - <> - {/* HOME */} - {/* CHAT v2 */} - {/* CHATROOM */} - {/* PROFILE */} - {/* AUTH */} - {/* */} - {infoUser} - {/* */} - - ) - } - - - function SubNavNotLog() { - - return ( - <> - {/* HOME */} - {/* AUTH LOGIN */} - - {/* */} - {/* OLD LOGIN */} -
user:(not logged)
- - ) - } - - - return ( - <> -
- {!isHovered ? ( -
-
- -
-
- ) : ( -
-
-
Navbar Dev
- {logged ? : - // - - } - -
-
- )} -
- - ); -} \ No newline at end of file diff --git a/front-end/src/components/AvatarComponent.tsx b/front-end/src/components/AvatarComponent.tsx index bf0124c8..316d44f4 100644 --- a/front-end/src/components/AvatarComponent.tsx +++ b/front-end/src/components/AvatarComponent.tsx @@ -54,6 +54,7 @@ const Avatar: React.FC = ({path, width, height, playerStatus, isMai useEffect(() => { setStatusColor(getEnumNameByIndex(Colors, playerStatus)); + return; }, [playerStatus]); path = !path ? "/tests/avatar.jpg" : path; diff --git a/front-end/src/components/LeaderboardComponent.tsx b/front-end/src/components/LeaderboardComponent.tsx index f95fd28e..5fccdc7c 100644 --- a/front-end/src/components/LeaderboardComponent.tsx +++ b/front-end/src/components/LeaderboardComponent.tsx @@ -1,15 +1,22 @@ -import React, {useEffect, useState} from "react"; -import {ILeaderboard} from "@/shared/types"; +import React, {useContext, useEffect, useRef, useState} from "react"; +import {EStatus, ILeaderboard, IUser} from "@/shared/types"; import {getApi} from "@/components/api/ApiReq"; import {v4 as uuidv4} from "uuid"; import Profile from "@/components/ProfileComponent"; +import {SocketContextChat, UserContext} from "@/context/globalContext"; const Leaderboard : React.FC = () => { const [leaderboard, setLeaderboard] = useState([]); let leaderboardElements: React.JSX.Element[] = []; + const socketChat = useContext(SocketContextChat); + const socketChatRef = useRef(socketChat); + const {userContext} = useContext(UserContext); + let refreshLeaderboard = true; useEffect(() => { - if (leaderboard && leaderboard.length == 0) + if (refreshLeaderboard) + { + //if (leaderboard && leaderboard.length == 0) getApi.getLeaderboard() .then((res) => { setLeaderboard(res.data); @@ -20,12 +27,24 @@ const Leaderboard : React.FC = () => { setLeaderboard(res.data); }) }, 30000); - + refreshLeaderboard = false; return () => { clearInterval(timer); }; - }, ) + } + + }, [refreshLeaderboard] ) + + socketChatRef.current?.on("userUpdate", (data: IUser) => { + if (data.UserID == userContext.UserID && data.status == EStatus.Online) + { + refreshLeaderboard = true; + console.log("refresh leaderboard"); + } + }); + + socketChatRef.current?.off("userUpdate", () => {}); if (leaderboard.length > 0 ){ const rankColorsArray = ["gold", "silver", "sienna"] diff --git a/front-end/src/components/MatchHistoryComponent.tsx b/front-end/src/components/MatchHistoryComponent.tsx index d82326d5..b88b0dac 100644 --- a/front-end/src/components/MatchHistoryComponent.tsx +++ b/front-end/src/components/MatchHistoryComponent.tsx @@ -1,8 +1,8 @@ -import React, {useContext, useEffect, useState} from "react"; -import {IMatch, IRelationships} from "@/shared/types"; +import React, {useContext, useEffect, useRef, useState} from "react"; +import {EStatus, IMatch, IRelationships, IUser} from "@/shared/types"; import {getApi} from "@/components/api/ApiReq"; import {v4 as uuidv4} from "uuid"; -import {SelectedUserContext} from "@/context/globalContext"; +import {SelectedUserContext, SocketContextChat} from "@/context/globalContext"; import UserOptions from "@/components/UserOptions"; const MatchHistory : React.FC = () => { @@ -11,6 +11,8 @@ const MatchHistory : React.FC = () => { const [selectedUserRelationships, setSelectedUserRelationships] = useState({followed:[], blocked:[]}); const [refresh, setRefresh] = useState(false); let matchElements : React.JSX.Element[] = []; + const socketChat = useContext(SocketContextChat); + const socketChatRef = useRef(socketChat); useEffect(() => { if (selectedUserContext) @@ -24,19 +26,29 @@ const MatchHistory : React.FC = () => { .then((res) => { setSelectedUserRelationships({followed:res.data.followed, blocked:res.data?.blocked}); }); - const timer = setInterval(() => { + /*const timer = setInterval(() => { getApi.getMatchHistoryFromUserId(selectedUserContext.UserID) .then((res) => { setMatchesList(res.data); }) }, 10000); - +*/ return () => { - clearInterval(timer); + //clearInterval(timer); }; } }, [selectedUserContext]) + socketChatRef.current?.on("userUpdate", (data: IUser) => { + if (selectedUserContext && data.UserID == selectedUserContext.UserID && selectedUserContext.status == EStatus.Online) + setSelectedUserContext(data); + }); + + socketChatRef.current?.off("userUpdate", (data: IUser) => { + if (selectedUserContext && data.UserID == selectedUserContext.UserID && selectedUserContext.status == EStatus.Online) + setSelectedUserContext(data); + }); + if (matchesList.length > 0 && matchesList.at(0).ID >= 0){ for (const match of matchesList) { @@ -70,8 +82,9 @@ const MatchHistory : React.FC = () => {

MATCHES HISTORY

{selectedUserContext ?
    -
    {selectedUserContext.nickname}
    - ({selectedUserContext.login}) + {selectedUserContext.nickname} + ({selectedUserContext.login}) +
    {matchElements}
: "No user selected" diff --git a/front-end/src/components/ProfileComponent.tsx b/front-end/src/components/ProfileComponent.tsx index e63bf40e..0f4112f8 100644 --- a/front-end/src/components/ProfileComponent.tsx +++ b/front-end/src/components/ProfileComponent.tsx @@ -32,6 +32,7 @@ const Profile: React.FC = ({children, className ,user, avatarSize, useEffect(() => { setStatusColor(getEnumNameByIndex(Colors, user.status)); + return; }, [user.login]); socketChatRef.current?.on("userUpdate", (data: IUser) => { @@ -42,6 +43,8 @@ const Profile: React.FC = ({children, className ,user, avatarSize, } }); + socketChatRef.current?.off("userUpdate", () => {}); + useEffect(() => { if (isNicknameUsed && modifiedNick !== user.nickname) { setNickErrMsg("Unavailable"); diff --git a/front-end/src/components/StatsComponent.tsx b/front-end/src/components/StatsComponent.tsx index eb7036d1..e546911b 100644 --- a/front-end/src/components/StatsComponent.tsx +++ b/front-end/src/components/StatsComponent.tsx @@ -1,7 +1,8 @@ -import React, {useEffect, useState} from "react"; +import React, {useContext, useEffect, useRef, useState} from "react"; import {getApi} from "@/components/api/ApiReq"; import {IGameStats, IUser} from "@/shared/types"; import getUserStatsById = getApi.getUserStatsById; +import {SocketContextChat} from "@/context/globalContext"; interface StatsProps { user: IUser; @@ -10,6 +11,8 @@ interface StatsProps { const Stats: React.FC = ({className, user})=>{ const [stats, setStats] = useState({nbWin:0, level:-1, rank:0, nbLoose:0, exp: 0}); + const socketChat = useContext(SocketContextChat); + const socketChatRef = useRef(socketChat); useEffect(() => { if (stats.level < 0) @@ -17,10 +20,23 @@ const Stats: React.FC = ({className, user})=>{ setStats(result.data); }) .catch((error) => console.error("Request for STATS failed: " + error)); + return () => {}; }) + socketChatRef.current?.on("userUpdate", (data: IUser) => { + if (data.UserID == user.UserID && data.status != user.status) + { + getUserStatsById(user.UserID).then((result) => { + setStats(result.data); + }) + .catch((error) => console.error("Request for STATS failed: " + error)); + } + }); + socketChatRef.current?.off("userUpdate", () => {}); + + return ( -
+
{" " + stats.nbWin + "🏆 "} {" " + stats.nbLoose + " 🏳 "} {" " + stats.rank +" 🎖 "}️ diff --git a/front-end/src/components/UserListComponent.tsx b/front-end/src/components/UserListComponent.tsx index cd0d23ab..77ac9972 100644 --- a/front-end/src/components/UserListComponent.tsx +++ b/front-end/src/components/UserListComponent.tsx @@ -1,4 +1,4 @@ -import React, { use, useEffect, useState} from "react"; +import React, {useEffect, useState} from "react"; import Profile from "@/components/ProfileComponent"; import Button from "@/components/CustomButtonComponent"; import {v4 as uuidv4} from "uuid"; @@ -17,14 +17,14 @@ interface UserListProps { userID?: number; } const UserList : React.FC = ({ - className, - id, - userListIdProperty, - avatarSize, - showUserProps, + className, + id, + userListIdProperty, + avatarSize, + showUserProps, usersList, - channelID, - userID, + channelID, + userID, }) => { const [userElements, setUserElements] = useState([]); @@ -103,10 +103,11 @@ const UserList : React.FC = ({ }) .catch((error) => console.error("[UserList] Impossible to get relationships of actual user: " + error)); } + return; }, [refresh]); const allDivPush = ( - allDiv: React.JSX.Element[], + allDiv: React.JSX.Element[], user: IUser, muteList: channelsDTO.IMuteEntity[], follow: IUser[], @@ -129,7 +130,6 @@ const UserList : React.FC = ({ banID={banID} muteID={muteList.find(muteUser => muteUser.user.UserID === user.UserID)?.muteID ?? undefined} adminID={userAdmin?.UserID ?? undefined} - isOwner={isOwner} />} diff --git a/front-end/src/components/UserOptions.tsx b/front-end/src/components/UserOptions.tsx index 0e8624fd..055ca580 100644 --- a/front-end/src/components/UserOptions.tsx +++ b/front-end/src/components/UserOptions.tsx @@ -18,17 +18,17 @@ export interface userOptionsProps { banID?: number; muteID?: number; adminID?: number; - isOwner?: boolean; setRefresh: React.Dispatch>; } -const UserOptions: React.FC = ({classname, idProperty, user, showAdminOptions, relationships, channelID, setRefresh, banID, muteID, adminID, isOwner}) => { +const UserOptions: React.FC = ({classname, idProperty, user, showAdminOptions, relationships, channelID, setRefresh, banID, muteID, adminID}) => { const {userContext} = useContext(UserContext); const [isFollowed, setIsFollowed] = useState(relationships.followed && !!relationships.followed.find(tmpUser => user.UserID === tmpUser.UserID)); const [isBlocked, setIsBlocked] = useState(relationships.blocked && !!relationships.blocked.find(tmpUser => user.UserID == tmpUser.UserID)); const [isWaitingChallenge, setIsWaitingChallenge] = useState(false); const [isDurationVisible, setIsDurationVisible] = useState(false); const [durType, setDurationType] = useState(DurationType.Ban); + const [showPopupAdmin, setShowPopupAdmin] = useState(false); const socketRef = useContext(SocketContextChat) const socketRefGame = useContext(SocketContextGame) @@ -97,19 +97,19 @@ const UserOptions: React.FC = ({classname, idProperty, user, s } function handleKick() { - if (!showAdminOptions || channelID === undefined) return console.log('NO RIGHTS TO DO THIS ACTION'); + if (!showAdminOptions || channelID === undefined) return NotificationManager.error(`You can\'t kick ${user.nickname} (${user.login})`); apiReq.putApi.putKickUser(channelID, user.UserID) .then(() => { - console.log('KICK SUCCESS') + NotificationManager.success(`You kicked ${user.nickname} (${user.login})`); setRefresh(true); }) .catch(() => { - console.log('KICK FAILED') + NotificationManager.error(`You can\'t kick ${user.nickname} (${user.login})`); }) } function handleBan() { - if (!showAdminOptions || channelID === undefined) return console.log('NO RIGHTS TO DO THIS ACTION'); + if (!showAdminOptions || channelID === undefined) return NotificationManager.error(`You can\'t ban ${user.nickname} (${user.login})`); if (banID === undefined) { setDurationType(DurationType.Ban); setIsDurationVisible(!isDurationVisible); @@ -117,17 +117,17 @@ const UserOptions: React.FC = ({classname, idProperty, user, s else { apiReq.putApi.putUnbanUser(banID) .then(() => { - console.log('UNBAN SUCCESS') + NotificationManager.success(`You unbanned ${user.nickname} (${user.login})`); setRefresh(true); }) .catch(() => { - console.log('UNBAN FAILED') + NotificationManager.error(`You can\'t unban ${user.nickname} (${user.login})`); }) } } function handleMute() { - if (!showAdminOptions || channelID === undefined) return console.log('NO RIGHTS TO DO THIS ACTION'); + if (!showAdminOptions || channelID === undefined) return NotificationManager.error(`You can\'t mute ${user.nickname} (${user.login})`); if (muteID === undefined) { setDurationType(DurationType.Mute); setIsDurationVisible(!isDurationVisible); @@ -135,35 +135,45 @@ const UserOptions: React.FC = ({classname, idProperty, user, s else { apiReq.putApi.putUnmuteUser(muteID ? muteID : -1) .then(() => { - console.log('UNMUTE SUCCESS') + NotificationManager.success(`You unmuted ${user.nickname} (${user.login})`); setRefresh(true); }) .catch(() => { - console.log('UNMUTE FAILED') + NotificationManager.error(`You can\'t unmute ${user.nickname} (${user.login})`); }) } } + const adminOptionsSettings = () => { + return ( +
+
+ ) + } function handleGrant() { - if (!showAdminOptions || channelID === undefined) return console.log('NO RIGHTS TO DO THIS ACTION'); + if (!showAdminOptions || channelID === undefined) return NotificationManager.error(`You can\'t grant ${user.nickname} (${user.login})`); if (adminID === undefined) { apiReq.putApi.putGrantAdmin(channelID, user.UserID) .then(() => { - console.log('GRANT SUCCESS') + NotificationManager.success(`You granted ${user.nickname} (${user.login})`); setRefresh(true); }) .catch(() => { - console.log('GRANT FAILED') + NotificationManager.error(`You can\'t grant ${user.nickname} (${user.login})`); }) } else { apiReq.putApi.putRevokeAdmin(channelID, user.UserID) //adminID === user.UserID .then(() => { - console.log('REVOKE SUCCESS') + NotificationManager.success(`You revoked ${user.nickname} (${user.login})`); setRefresh(true); }) .catch(() => { - console.log('REVOKE FAILED') + NotificationManager.error(`You can\'t revoke ${user.nickname} (${user.login})`); }) } } @@ -191,26 +201,25 @@ const UserOptions: React.FC = ({classname, idProperty, user, s : )}
)} -
+ ); } diff --git a/front-end/src/shared/routesApi.ts b/front-end/src/shared/routesApi.ts index 49ebcd93..de820aef 100644 --- a/front-end/src/shared/routesApi.ts +++ b/front-end/src/shared/routesApi.ts @@ -153,10 +153,10 @@ export namespace strRoutes { return `${serverApi}/${routeUsers}/get/Relationships/${targetId}` } export const getUsersAll = () => { - return `${serverApi})${routeUsers}/get/` + return `${serverApi}/${routeUsers}/get/` } export const getUserById = () => { - return `${serverApi})${routeUsers}/get/` + return `${serverApi}/${routeUsers}/get/` } export const getUserByLogin = () => { return `${serverApi}/${routeUsers}/get/`