From 0fee862a3f6b95f6a6fa8c16329c8bc194001986 Mon Sep 17 00:00:00 2001 From: Ismail Barka Date: Mon, 11 Nov 2024 11:32:03 +0100 Subject: [PATCH 1/4] a lot of changes about responsive and logic settings and homepage and search --- srcs/frontend/assets/challengeBlack.svg | 16 ++ srcs/frontend/assets/messageBlack.svg | 15 ++ srcs/frontend/assets/sendRequest.svg | 27 ++ srcs/frontend/dockerfile | 17 ++ srcs/frontend/src/app/auth/signin/page.tsx | 152 ++++++----- .../src/app/auth/signup/page.module.css | 6 + srcs/frontend/src/app/auth/signup/page.tsx | 227 ++++++++-------- .../src/app/users/friend/[id]/page.module.css | 73 ++++++ .../src/app/users/friend/[id]/page.tsx | 67 +++++ .../src/app/users/home/page.module.css | 5 +- srcs/frontend/src/app/users/home/page.tsx | 34 ++- srcs/frontend/src/app/users/layout.css | 93 ++++--- srcs/frontend/src/app/users/layout.tsx | 16 +- .../src/app/users/logout/page.module.css | 75 ++++++ srcs/frontend/src/app/users/logout/page.tsx | 74 ++++++ .../app/users/settings/Settings.module.css | 161 ++++++------ srcs/frontend/src/app/users/settings/page.tsx | 4 +- .../Achievements/achievements.module.css | 113 ++++---- .../Achievements/AchievementsFr.module.css | 60 +++++ .../Achievements/AchievementsFr.tsx | 29 +++ .../FriendActions/FriendActions.module.css | 102 ++++++++ .../FriendActions/FriendActions.tsx | 61 +++++ .../FriendPage/Friends/FriendsFr.module.css | 79 ++++++ .../FriendPage/Friends/FriendsFr.tsx | 86 ++++++ .../PlayerInfos/PlayerInfosFr.module.css | 71 +++++ .../FriendPage/PlayerInfos/PlayerInfosFr.tsx | 50 ++++ .../ProgressBar/ProgressBarFr.module.css | 34 +++ .../FriendPage/ProgressBar/ProgressBarFr.tsx | 47 ++++ .../FriendPage/Rate/RateFr.module.css | 23 ++ .../src/components/FriendPage/Rate/RateFr.tsx | 77 ++++++ .../WeeklyAttendanceFr.module.css | 23 ++ .../WeeklyAttendance/WeeklyAttendanceFr.tsx | 54 ++++ .../src/components/Friends/Friends.tsx | 244 +++++++++++++----- .../src/components/Friends/friends.module.css | 146 ++++++++--- .../HorizontalNavbar.module.css | 206 +++++---------- .../SearchBar/SearchBar.module.css | 113 ++++++-- .../HorizontalNavbar/SearchBar/SearchBar.tsx | 107 +++++++- .../InputField/InputField.module.css | 57 ++-- .../src/components/InputField/InputField.tsx | 32 +-- .../src/components/NavBar/NavBar.module.css | 84 ++++++ .../frontend/src/components/NavBar/NavBar.tsx | 82 ++++++ .../components/PlayerInfos/PlayerInfos.tsx | 90 +++---- .../PlayerInfos/playerInfos.module.css | 88 +++++-- .../ProgressBar/progressBar.module.css | 56 ++-- .../src/components/Rate/rate.module.css | 27 +- .../VerticalNavbar/VerticalNavbar.module.css | 120 ++++----- .../VerticalNavbar/VerticalNavbar.tsx | 97 +++---- .../weeklyAttendance.module.css | 28 +- srcs/frontend/src/context/UserContext.tsx | 55 +++- 49 files changed, 2653 insertions(+), 950 deletions(-) create mode 100644 srcs/frontend/assets/challengeBlack.svg create mode 100644 srcs/frontend/assets/messageBlack.svg create mode 100644 srcs/frontend/assets/sendRequest.svg create mode 100644 srcs/frontend/dockerfile create mode 100644 srcs/frontend/src/app/users/friend/[id]/page.module.css create mode 100644 srcs/frontend/src/app/users/friend/[id]/page.tsx create mode 100644 srcs/frontend/src/app/users/logout/page.module.css create mode 100644 srcs/frontend/src/app/users/logout/page.tsx create mode 100644 srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.module.css create mode 100644 srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.tsx create mode 100644 srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.module.css create mode 100644 srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.tsx create mode 100644 srcs/frontend/src/components/FriendPage/Friends/FriendsFr.module.css create mode 100644 srcs/frontend/src/components/FriendPage/Friends/FriendsFr.tsx create mode 100644 srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.module.css create mode 100644 srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.tsx create mode 100644 srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.module.css create mode 100644 srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.tsx create mode 100644 srcs/frontend/src/components/FriendPage/Rate/RateFr.module.css create mode 100644 srcs/frontend/src/components/FriendPage/Rate/RateFr.tsx create mode 100644 srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.module.css create mode 100644 srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.tsx create mode 100644 srcs/frontend/src/components/NavBar/NavBar.module.css create mode 100644 srcs/frontend/src/components/NavBar/NavBar.tsx diff --git a/srcs/frontend/assets/challengeBlack.svg b/srcs/frontend/assets/challengeBlack.svg new file mode 100644 index 0000000..22b7a31 --- /dev/null +++ b/srcs/frontend/assets/challengeBlack.svg @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/srcs/frontend/assets/messageBlack.svg b/srcs/frontend/assets/messageBlack.svg new file mode 100644 index 0000000..fa27b32 --- /dev/null +++ b/srcs/frontend/assets/messageBlack.svg @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/srcs/frontend/assets/sendRequest.svg b/srcs/frontend/assets/sendRequest.svg new file mode 100644 index 0000000..47ce6a5 --- /dev/null +++ b/srcs/frontend/assets/sendRequest.svg @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/srcs/frontend/dockerfile b/srcs/frontend/dockerfile new file mode 100644 index 0000000..8f54037 --- /dev/null +++ b/srcs/frontend/dockerfile @@ -0,0 +1,17 @@ +# Use the official Node.js base image with the latest LTS version +FROM node:alpine + +# Set the working directory inside the container +WORKDIR /app + +COPY ./package*.json ./ + +RUN npm install + +COPY . . + +# RUN npm run build + +EXPOSE 3000 + +CMD ["npm", "run", "dev"] diff --git a/srcs/frontend/src/app/auth/signin/page.tsx b/srcs/frontend/src/app/auth/signin/page.tsx index ea898fa..26080bb 100644 --- a/srcs/frontend/src/app/auth/signin/page.tsx +++ b/srcs/frontend/src/app/auth/signin/page.tsx @@ -1,29 +1,26 @@ "use client" + import { useState } from 'react'; -import { z } from "zod"; -import {schema} from "../../../schemas/validationSchema.ts" -import InputField from '../../../components/InputField/InputField'; -import classes from "./page.module.css" -import axios from 'axios'; -import { AxiosError } from 'axios'; -import Image from 'next/image.js'; -import loginPlayer from '../../../../assets/loginPlayer.svg' import { useRouter } from 'next/navigation'; -import OtpForLogin from '../../../components/OtpForLogin/OtpForLogin.tsx'; - +import Image from 'next/image'; +import axios from 'axios'; +import InputField from '../../../components/InputField/InputField'; +import classes from "./page.module.css"; +import loginPlayer from '../../../../assets/loginPlayer.svg'; +import OtpForLogin from '../../../components/OtpForLogin/OtpForLogin'; -interface Errors{ +interface Errors { details: string; username: string; password: string; otp: string; } -const SignUpPage: React.FC = () => { - - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [code, setCode] = useState(""); +const SignInPage: React.FC = () => { + const [formData, setFormData] = useState({ + username: "", + password: "", + }); const [isLoading, setIsLoading] = useState(false); const [errors, setErrors] = useState({ details: '', @@ -34,79 +31,80 @@ const SignUpPage: React.FC = () => { const router = useRouter(); - const handleSubmit = async (event : React.FormEvent): void => { + const handleChange = (event: React.ChangeEvent) => { + const { name, value } = event.target; + setFormData(prev => ({ ...prev, [name]: value })); + setErrors(prev => ({ ...prev, details: '', [name]: '' })); + }; + + const handleSubmit = async (event: React.FormEvent): Promise => { event.preventDefault(); - setErrors(() => ({ - details: '', - username: '', - password: '', - otp: '', - })); + setErrors({ + details: '', + username: '', + password: '', + otp: '', + }); setIsLoading(true); - console.log("username:", username); try { - - const res = await axios.post("http://localhost:8000/api/auth/sign-in/",{ - "username": username, - "password": password, - }); - router.push("/users/home"); - setIsLoading(false); - } catch (err) { - console.error("test"); - console.error("Error response:", err.response); - setErrors(() => ({ - details: "username of password is not correct", - username: err.response?.data?.username ? err.response.data.username[0] : "", - password: err.response?.data?.password ? err.response.data.password[0] : "", - otp: err.response?.data?.otp_code[0] ? err.response?.data?.otp_code[0] : "", - })); + await axios.post("http://localhost:8000/api/auth/sign-in/", formData,{withCredentials: true}); + + router.push("/users/home"); + } catch (err: any) { + console.log("there is some errors"); + console.error("Error:", err.response); + setErrors({ + details: "Username or password is not correct", + username: err.response?.data?.username?.[0] || "", + password: err.response?.data?.password?.[0] || "", + otp: err.response?.data?.otp_code?.[0] || "", + }); setIsLoading(false); + } finally { } }; return (
-

Login

-
-
-

Welcome to the Ping Pong World

-

Welcome back! Please login to your account.

-
- {setUsername(event.target.value) ;setErrors(() => ({details: '', username: '',password: '',}));}} - error={errors.username} - /> - {setPassword(event.target.value) ;setErrors(() => ({details: '', username: '',password: '',}));}} - error={errors.password} - /> - {errors.otp && } - -

{errors.details}

- - -
-

if you dont have an account

-
-
-
- My SVG Image -
+

Login

+
+
+

Welcome to the Ping Pong World

+

Welcome back! Please login to your account.

+
+ + + {errors.otp && } + {errors.details &&

{errors.details}

} + + +
+

If you don't have an account

+
+
+
+ Login Player
+
); }; -export default SignUpPage; +export default SignInPage; \ No newline at end of file diff --git a/srcs/frontend/src/app/auth/signup/page.module.css b/srcs/frontend/src/app/auth/signup/page.module.css index 3035098..3886dfd 100644 --- a/srcs/frontend/src/app/auth/signup/page.module.css +++ b/srcs/frontend/src/app/auth/signup/page.module.css @@ -122,4 +122,10 @@ display: none; } } +} + +.errorMsg { + font-size: 14px; + color: #D32F2F; + margin-top: 5px; } \ No newline at end of file diff --git a/srcs/frontend/src/app/auth/signup/page.tsx b/srcs/frontend/src/app/auth/signup/page.tsx index 92f8cb8..a0b3643 100644 --- a/srcs/frontend/src/app/auth/signup/page.tsx +++ b/srcs/frontend/src/app/auth/signup/page.tsx @@ -1,34 +1,36 @@ "use client" + import { useState } from 'react'; -import { z } from "zod"; -import {schema} from "../../../schemas/validationSchema.ts" -import InputField from '../../../components/InputField/InputField'; -import classes from "./page.module.css" -import axios from 'axios'; -import { AxiosError } from 'axios'; -import loginPlayer from '../../../../assets/loginPlayer.svg' -import Image from 'next/image.js'; import { useRouter } from 'next/navigation'; +import Image from 'next/image'; +import axios from 'axios'; +import { schema } from "../../../schemas/validationSchema"; +import InputField from '../../../components/InputField/InputField'; +import classes from "./page.module.css"; +import loginPlayer from '../../../../assets/loginPlayer.svg'; - -interface Errors{ +interface Errors { firstname: string; lastname: string; email: string; username: string; password: string; confermPassword: string; + non_field_errors: string; } const SignUpPage: React.FC = () => { - - const [firstname, setFirstname] = useState(""); - const [lastname, setLastname] = useState(""); - const [email, setEmail] = useState(""); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [confermPassword, setConfermPassword] = useState(""); + const [formData, setFormData] = useState({ + firstname: "", + lastname: "", + email: "", + username: "", + password: "", + confermPassword: "", + // non_field_errors: "", + }); const [isLoading, setIsLoading] = useState(false); + const [isSuccess, setIsSuccess] = useState(false); const [errors, setErrors] = useState({ firstname: '', lastname: '', @@ -36,141 +38,120 @@ const SignUpPage: React.FC = () => { username: '', password: '', confermPassword: '', + non_field_errors: '', }); const router = useRouter(); + const handleChange = (event: React.ChangeEvent) => { + const { name, value } = event.target; + setFormData(prev => ({ ...prev, [name]: value })); + }; - const handleSubmit = async (event : React.FormEvent): void => { + const handleSubmit = async (event: React.FormEvent): Promise => { event.preventDefault(); - setErrors(() => ({ + setErrors({ firstname: '', lastname: '', email: '', username: '', password: '', confermPassword: '', - })); + non_field_errors: '', + }); setIsLoading(true); - const result = schema.safeParse({firstname, lastname , email , username, password, confermPassword }); + const result = schema.safeParse(formData); if (!result.success) { const errorMsg = result.error.flatten().fieldErrors; - setErrors(() => ({ - firstname: errorMsg.firstname ? errorMsg.firstname[0] : '', - lastname: errorMsg.lastname ? errorMsg.lastname[0] : '', - email: errorMsg.email ? errorMsg.email[0] : '', - username: errorMsg.username ? errorMsg.username[0] : '', - password: errorMsg.password ? errorMsg.password[0] : '', - confermPassword: errorMsg.confermPassword ? errorMsg.confermPassword[0] : '', - })); + setErrors({ + firstname: errorMsg.firstname?.[0] || '', + lastname: errorMsg.lastname?.[0] || '', + email: errorMsg.email?.[0] || '', + username: errorMsg.username?.[0] || '', + password: errorMsg.password?.[0] || '', + confermPassword: errorMsg.confermPassword?.[0] || '', + non_field_errors : errorMsg.non_field_errors?.[0] || '' + }); setIsLoading(false); return; } try { - console.log("Sending data:", { username, password, email, firstname, lastname }); - - const res = await axios.post("http://localhost:8000/api/auth/sign-up/",{ - "username": username, - "password": password, - "email": email, - "first_name": firstname, - "last_name": lastname + await axios.post("http://localhost:8000/api/auth/sign-up/", { + username: formData.username, + password: formData.password, + email: formData.email, + first_name: formData.firstname, + last_name: formData.lastname }); - console.log("tst"); - router.push("/auth/signin"); - - } catch (err) { - console.error("Error response:", err.response.data); - console.error("Error message:", err.message); - setErrors(() => ({ - firstname: err.response.data.firstname ? err.response.data.firstname[0] : "", - lastname: err.response.data.lastname ? err.response.data.lastname[0] : "", - email: err.response.data.email ? err.response.data.email[0] : "", - username: err.response.data.username ? err.response.data.username[0] : "", - password: err.response.data.password ? err.response.data.password[0] : "", - confermPassword: err.response.data.confermPassword ? err.response.data.confermPassword[0] : "", - })); - + setIsSuccess(true); + } catch (err: any) { + console.error("Error:", err.response?.data); + setErrors(prev => ({ + ...prev, + ...err.response?.data + })); + } finally { + setIsLoading(false); } }; return (
-

sign up

-
-
-

Welcome to the Ping Pong World

-

Welcome back! Please create your account.

-
- - setFirstname(event.target.value)} - error={errors.firstname} - /> - setLastname(event.target.value)} - error={errors.lastname} - /> - setEmail(event.target.value)} - error={errors.email} - /> - setUsername(event.target.value)} - error={errors.username} - /> - setPassword(event.target.value)} - error={errors.password} - /> - setConfermPassword(event.target.value)} - error={errors.confermPassword} - /> - - -
-

if you already have an account

-
-
-
- My SVG Image -
+

Sign Up

+
+
+ {!isSuccess ? ( + <> +

Welcome to the Ping Pong World

+

Please create your account.

+
+ {Object.entries(formData).map(([key, value]) => ( + + ))} + {errors.non_field_errors &&

Error: {errors.non_field_errors}

} + + +
+

If you already have an account

+
+ + ) : ( +
+

Sign Up Successful!

+

Your account has been created successfully.

+ +
+ )} +
+
+ Login Player
+
); }; -export default SignUpPage; +export default SignUpPage; \ No newline at end of file diff --git a/srcs/frontend/src/app/users/friend/[id]/page.module.css b/srcs/frontend/src/app/users/friend/[id]/page.module.css new file mode 100644 index 0000000..a88db70 --- /dev/null +++ b/srcs/frontend/src/app/users/friend/[id]/page.module.css @@ -0,0 +1,73 @@ +.home { + display: flex; + flex: 1; + justify-content: center; + justify-content: center; + + + .container{ + + display: flex; + flex: 1; + justify-content: center; + flex-wrap: wrap; + gap: 20px; + margin: 10px; + overflow-y: scroll; + scrollbar-width: thin; /* Firefox */ + scrollbar-color: rgba(0, 0, 0, 0.111) #00000000; /* Firefox */ + padding-top: 20px; + max-width: 1220px; + + /* Scrollbar styling for WebKit browsers (Chrome, Safari) */ + &::-webkit-scrollbar { + width: 8px; /* Width of the scrollbar */ + } + &::-webkit-scrollbar-track { + background: #00000000; /* Background of the scrollbar track */ + border-radius: 6px; /* Rounded corners for the track */ + } + &::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.111); /* Color of the scrollbar thumb */ + border-radius: 6px; /* Rounded corners for the thumb */ + } + &::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.2); /* Hover state for the thumb */ + } + .box1, .box2, .box3, .box4, .box5, .box6 { + width: 370px; + @media screen and (max-width: 880px) { + width: 100%; + } + @media screen and (min-width: 880px) { + + transition: background-color 0.5s ease, transform 0.5s ease; + &:hover { + transform: scale(1.025); + } + } + box-shadow: rgba(162, 162, 162, 0.1) 0px 4px 4px; + } + + .box1, .box2, .box3 { + height: 236px; + } + + .box4, .box5, .box6 { + height: 512px; + } + + .line { + width: 95%; + height: 45px; + @media screen and (max-width: 800px) { + width: 100%; + } + box-shadow: rgba(149, 157, 165, 0.1) 0px 4px 4px; + } + + .box6 { + background-color: aquamarine; + } + } +} diff --git a/srcs/frontend/src/app/users/friend/[id]/page.tsx b/srcs/frontend/src/app/users/friend/[id]/page.tsx new file mode 100644 index 0000000..e7384fc --- /dev/null +++ b/srcs/frontend/src/app/users/friend/[id]/page.tsx @@ -0,0 +1,67 @@ +"use client" +import React, { useContext, useEffect, useState } from 'react' +import classes from "./page.module.css" +import PlayerInfos from '../../../../components/PlayerInfos/PlayerInfos' +import WeeklyAttendance from '../../../../components/weeklyAttendance/WeeklyAttendance' +import Rate from '../../../../components/Rate/Rate' +import ProgressBar from '../../../../components/ProgressBar/ProgressBar' +import Friends from '../../../../components/Friends/Friends' +import { Achievements } from '../../../../components/Achievements/Achievements' +import { useRouter } from 'next/navigation' +import { UserContext, useUserContext } from '@/context/UserContext' +import axios from 'axios' +import PlayerInfosFr from '@/components/FriendPage/PlayerInfos/PlayerInfosFr' +import WeeklyAttendanceFr from '@/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr' +import RateFr from '@/components/FriendPage/Rate/RateFr' +import ProgressBarFr from '@/components/FriendPage/ProgressBar/ProgressBarFr' +import FriendsFr from '@/components/FriendPage/Friends/FriendsFr' +import { AchievementsFr } from '@/components/FriendPage/Achievements/AchievementsFr' +import FriendActions from '@/components/FriendPage/FriendActions/FriendActions' +// import loadMyData from '@/Components/LoadMyData' +const FriendPage = ({ params }) => { + const { id } = params; + const {updateUserData, updateCurrentPage,updateSearchedUserData } = useUserContext(); + + const router = useRouter(); + useEffect(() => { + updateCurrentPage("Friend"); + const fetchData = async () => { + try { + const res = await axios.get(`http://localhost:8000/api/users/${id}/`); + // console.log(res.data.first_name); + updateSearchedUserData({ + avatar_url: res.data.avatar_url, + first_name: res.data.first_name, + id: res.data.id, + is_online: res.data.is_online, + last_name: res.data.last_name, + loses: res.data.loses, + rank: res.data.rank, + rating: res.data.rating, + username: res.data.username, + wins: res.data.wins, + }) + + } catch (err: any) { + console.log("Error in fetching user data", err); + } finally { + } + }; + + fetchData(); + }, []); + return ( +
+
+
+
+
+
+
+
+
lin6
+
+
) +} + +export default FriendPage diff --git a/srcs/frontend/src/app/users/home/page.module.css b/srcs/frontend/src/app/users/home/page.module.css index 2651cdd..a88db70 100644 --- a/srcs/frontend/src/app/users/home/page.module.css +++ b/srcs/frontend/src/app/users/home/page.module.css @@ -3,7 +3,8 @@ flex: 1; justify-content: center; justify-content: center; - width: 100%; + + .container{ display: flex; @@ -59,7 +60,7 @@ .line { width: 95%; height: 45px; - @media screen and (max-width: 720px) { + @media screen and (max-width: 800px) { width: 100%; } box-shadow: rgba(149, 157, 165, 0.1) 0px 4px 4px; diff --git a/srcs/frontend/src/app/users/home/page.tsx b/srcs/frontend/src/app/users/home/page.tsx index 52f90e5..4df2cd4 100644 --- a/srcs/frontend/src/app/users/home/page.tsx +++ b/srcs/frontend/src/app/users/home/page.tsx @@ -8,16 +8,44 @@ import ProgressBar from '../../../components/ProgressBar/ProgressBar' import Friends from '../../../components/Friends/Friends' import { Achievements } from '../../../components/Achievements/Achievements' import { useRouter } from 'next/navigation' -import { UserContext } from '@/context/UserContext' +import { UserContext, useUserContext } from '@/context/UserContext' +import axios from 'axios' // import loadMyData from '@/Components/LoadMyData' const Home = () => { - const {updateCurrentPage } = useContext(UserContext); + const {updateUserData, updateCurrentPage } = useUserContext(); const router = useRouter(); useEffect(() => { - updateCurrentPage("Home"); + updateCurrentPage("home"); const fetchData = async () => { + try { + const res = await axios.get("http://localhost:8000/api/users/me/"); + // console.log(res.data.avatar_url); + updateUserData({ + id: res.data.id, + otp_uri: res.data.otp_uri, + last_login: res.data.last_login, + is_superuser: res.data.is_superuser, + username: res.data.username, + first_name: res.data.first_name, + last_name: res.data.last_name, + email: res.data.email, + is_staff: res.data.is_staff, + is_active: res.data.is_active, + date_joined: res.data.date_joined, + two_fa_enabled: res.data.two_fa_enabled, + is_online: res.data.is_online, + avatar_url: res.data.avatar_url, + wins: res.data.wins, + loses: res.data.loses, + rating: res.data.rating, + rank: res.data.rank, + }) + } catch (err: any) { + console.log("Error in fetching user data", err); + } finally { + } }; fetchData(); diff --git a/srcs/frontend/src/app/users/layout.css b/srcs/frontend/src/app/users/layout.css index 1d34482..cab7aa6 100644 --- a/srcs/frontend/src/app/users/layout.css +++ b/srcs/frontend/src/app/users/layout.css @@ -1,39 +1,72 @@ .layout-container { - display: flex; - width: 100vw; - height: 100vh; + display: flex; + width: 100vw; + height: 100vh; +} + +.verticalNavbarr { + background-color: #F5F5F5; + width: 70px; + height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + overflow-y: auto; + overflow-x: hidden; + flex-shrink: 0; +} + +.main-content { + flex: 1; + display: flex; + flex-direction: column; + width: calc(100% - 70px); + background-color: #FFFFFF; +} + +.horizontalNavbarr { + height: 55px; + background-color: #FFFFFF; + border-bottom: 1px solid #E0E0E0; + width: 100%; +} + +.navBarContainer { + width: 100%; + background-color: #FFFFFF; + border-bottom: 1px solid #E0E0E0; +} + +.page-content { + flex: 1; + overflow: auto; +} + +@media screen and (max-width: 880px) { + .layout-container { + flex-direction: column; } - + .verticalNavbarr { - background-color: #E0E0E0; - width: 70px; - height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-between; - overflow-y: auto; - overflow-x: hidden; - flex-shrink: 0; + display: none; } - + .main-content { - flex: 1; - display: flex; - flex-direction: column; width: 100%; - background-color: #ffffff; - } - - .page-content { - flex: 1; - padding: 10px; } + .horizontalNavbarr { - height: 55px; - background-color: #FFFFFF; - border-bottom: 1px solid black; - width: calc(100vw - 70px); + width: 100%; + } + + .navBarContainer { + display: block; + } +} + +@media screen and (min-width: 881px) { + .navBarContainer { + display: none; } - - \ No newline at end of file +} \ No newline at end of file diff --git a/srcs/frontend/src/app/users/layout.tsx b/srcs/frontend/src/app/users/layout.tsx index d842f08..a485b41 100644 --- a/srcs/frontend/src/app/users/layout.tsx +++ b/srcs/frontend/src/app/users/layout.tsx @@ -1,7 +1,8 @@ import { UserContextProvider } from "@/context/UserContext"; -import VerticalNavbar from "@/components/VerticalNavbar/VerticalNavbar"; // Ensure correct path to your component -import HorizontalNavbar from "@/components/HorizontalNavbar/HorizontalNavbar"; // Ensure correct path to your component -import "./layout.css"; // Optional: add layout-specific styles +import VerticalNavbar from "@/components/VerticalNavbar/VerticalNavbar"; +import HorizontalNavbar from "@/components/HorizontalNavbar/HorizontalNavbar"; +import NavBar from "@/components/NavBar/NavBar"; +import "./layout.css"; export const metadata = { title: "User Dashboard", @@ -14,6 +15,7 @@ export default function UsersLayout({ children: React.ReactNode; }) { return ( +
@@ -22,10 +24,14 @@ export default function UsersLayout({
+
+ +
- {children} + {children}
+
); -} +} \ No newline at end of file diff --git a/srcs/frontend/src/app/users/logout/page.module.css b/srcs/frontend/src/app/users/logout/page.module.css new file mode 100644 index 0000000..b910418 --- /dev/null +++ b/srcs/frontend/src/app/users/logout/page.module.css @@ -0,0 +1,75 @@ +.container { + display: flex; + width: 100%; + height: 100vh; + align-items: center; + justify-content: center; + flex-direction: column; + background-color: #f5f5f5; + color: #000000; +} + +.question { + font-size: 1.5rem; + font-weight: bold; + margin-bottom: 2rem; + text-align: center; +} + +.btnContainer { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + gap: 1rem; + max-width: 300px; +} + +.btn { + padding: 0.75rem 1.5rem; + font-size: 1rem; + font-weight: bold; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.3s ease, opacity 0.3s ease; +} + +.btn:disabled { + cursor: not-allowed; + opacity: 0.6; +} + +.yesBtn { + background-color: #000000; + color: #ffffff; +} + +.yesBtn:hover:not(:disabled) { + background-color: #333333; +} + +.noBtn { + background-color: #ffffff; + color: #000000; + border: 2px solid #000000; +} + +.noBtn:hover:not(:disabled) { + background-color: #e0e0e0; +} + +@media (max-width: 480px) { + .question { + font-size: 1.25rem; + } + + .btnContainer { + flex-direction: column; + gap: 0.75rem; + } + + .btn { + width: 100%; + } +} \ No newline at end of file diff --git a/srcs/frontend/src/app/users/logout/page.tsx b/srcs/frontend/src/app/users/logout/page.tsx new file mode 100644 index 0000000..0723e64 --- /dev/null +++ b/srcs/frontend/src/app/users/logout/page.tsx @@ -0,0 +1,74 @@ +"use client"; + +import { useRouter } from 'next/navigation'; +import { useContext, useEffect, useState } from 'react'; +import classes from './page.module.css'; +import axios from 'axios'; +import { useUserContext } from '@/context/UserContext'; + +const Logout: React.FC = () => { + const router = useRouter(); + const [isLoading, setIsLoading] = useState(false); + const { currentPage, updateCurrentPage } = useUserContext(); + + + useEffect(() => { + updateCurrentPage("logout"); + + }, []); + + const handleNo = () => { + router.push('/users/home'); + }; + + const deleteAllCookies = () => { + const cookies = document.cookie.split(";"); + + for (let cookie of cookies) { + const eqPos = cookie.indexOf("="); + const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; + document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; + } + }; + + const handleYes = async () => { + setIsLoading(true); + try { + // Delete all cookies + deleteAllCookies(); + + // Call the sign-out API + await axios.post("http://localhost:8000/api/auth/sign-out/"); + + router.push('/auth/signin'); + } catch (error) { + console.error('Logout error:', error); + } finally { + setIsLoading(false); + } + }; + + return ( +
+

Are you sure you want to logout?

+
+ + +
+
+ ); +}; + +export default Logout; diff --git a/srcs/frontend/src/app/users/settings/Settings.module.css b/srcs/frontend/src/app/users/settings/Settings.module.css index 8848d4b..92f8de3 100644 --- a/srcs/frontend/src/app/users/settings/Settings.module.css +++ b/srcs/frontend/src/app/users/settings/Settings.module.css @@ -1,101 +1,98 @@ -.container{ +.container { width: 100%; display: flex; justify-content: center; + padding: 20px; } + .Settings { display: flex; flex-direction: column; flex: 1; align-items: center; max-width: 700px; - overflow-y: scroll; + overflow-y: auto; scrollbar-width: none; + background-color: #FFFFFF; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} - .editProfileTitle{ - font-size: 1.25rem; - width: 100%; - text-align: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.255); - padding: 20px; - } +.editProfileTitle { + font-size: 24px; + font-weight: 600; + width: 100%; + text-align: center; + border-bottom: 1px solid #E0E0E0; + padding: 20px; + color: #333333; +} - .editContainer { - display: flex; - width: 100%; - align-items: center; - justify-content: space-between; - gap: 20px; - padding: 20px; - border-bottom: 1px solid rgba(0, 0, 0, 0.229); - @media screen and (max-width: 640px) { - flex-direction: column; - } - - .label { - font-size: 1.5rem; - width: 200px; - @media screen and (max-width: 640px) { - width:auto; - } - } +.editContainer { + display: flex; + width: 100%; + align-items: center; + justify-content: space-between; + gap: 20px; + padding: 20px; + border-bottom: 1px solid #E0E0E0; +} - .inputProvisoir { +.label { + font-size: 16px; + font-weight: 500; + width: 200px; + color: #333333; +} - border-radius: 5px; - border: none; - padding: 20px; - max-width: 400px; - font-size: 1.5rem; - background: #ffffff; - cursor: pointer; - border: 1px solid #CCCCCC; - height: 50px; - } - .imageProvisoir { - font-size: 1.5rem; - border-radius: 5px; - border: none; - width: 400px; - display: flex; - align-items: center; - justify-content: center; - +.inputProvisoir { + border-radius: 4px; + border: 1px solid #CCCCCC; + padding: 10px; + max-width: 400px; + font-size: 16px; + background: #FFFFFF; + cursor: pointer; + height: 40px; +} - .image { - border-radius: 50%; - } - } - .editButton { - border: none; - font-size: 1.0625rem; - cursor: pointer; - color: hsl(216.38deg 44.76% 41.18%); - background-color: transparent; - text-decoration: none; /* Remove default underline */ - border-bottom: 2px solid hsl(216.38deg 44.76% 41.18%); /* Custom underline */ - padding-bottom: 2px; /* Adjust spacing between text and underline */ - } - +.imageProvisoir { + font-size: 16px; + border-radius: 4px; + border: none; + width: 400px; + display: flex; + align-items: center; + justify-content: center; +} + +.image { + border-radius: 50%; +} + +.editButton { + border: none; + font-size: 14px; + cursor: pointer; + color: #3366CC; + background-color: transparent; + text-decoration: none; + border-bottom: 2px solid #3366CC; + padding-bottom: 2px; + transition: color 0.3s ease, border-color 0.3s ease; +} + +.editButton:hover { + color: #264D99; + border-color: #264D99; +} + +@media screen and (max-width: 640px) { + .editContainer { + flex-direction: column; } - .buttonContainer { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - font-size: 10px; - gap: 20px; - - .button { - height: 100px; - border-radius: 5px; - border: none; - padding: 20px; - width: 200px; - font-size: 30px; - background-color: #F5F5F5; - cursor: pointer; - } + .label { + width: auto; } -} +} \ No newline at end of file diff --git a/srcs/frontend/src/app/users/settings/page.tsx b/srcs/frontend/src/app/users/settings/page.tsx index 7b402ec..bd4be8c 100644 --- a/srcs/frontend/src/app/users/settings/page.tsx +++ b/srcs/frontend/src/app/users/settings/page.tsx @@ -20,9 +20,11 @@ const Settings: React.FC = () => { const [currentPage, setCurrentPage] = React.useState(""); const router = useRouter(); const { userData } = useUserContext(); + const { updateCurrentPage } = useUserContext(); React.useEffect(() => { - + updateCurrentPage("settings"); + }, []); return ( diff --git a/srcs/frontend/src/components/Achievements/achievements.module.css b/srcs/frontend/src/components/Achievements/achievements.module.css index 3ad68d9..db42533 100644 --- a/srcs/frontend/src/components/Achievements/achievements.module.css +++ b/srcs/frontend/src/components/Achievements/achievements.module.css @@ -1,55 +1,60 @@ .achievements { - display: flex; - align-items: center; - flex-direction: column; - width: 100%; - height: 100%; - background-color: #E0E0E0; - border: 1px solid #B0B0B0; - border-radius: 5px; - } - - .title { - margin: 30px; - } - - .achievementsContainer { - width: 100%; - overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: rgba(0, 0, 0, 0.1) transparent; - } - - .achievementItem { - display: flex; - align-items: center; - padding: 10px; - border-radius: 5px; - transition: background-color 0.3s ease; - } - - .achievementItem:hover { - background-color: #00000024; - } - - .image { - border-radius: 50%; - margin-right: 10px; - } - - .details { - display: flex; - flex-direction: column; - gap: 5px; - } - - .name { - font-size: 18px; - font-weight: bold; - } - - .description { - font-size: 14px; - color: #000000; - } - \ No newline at end of file + display: flex; + align-items: center; + flex-direction: column; + width: 100%; + height: 100%; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + padding: 15px; +} + +.title { + font-size: 24px; + font-weight: 600; + color: #333333; + margin-bottom: 20px; +} + +.achievementsContainer { + width: 100%; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: rgba(0, 0, 0, 0.1) transparent; +} + +.achievementItem { + display: flex; + align-items: center; + padding: 12px; + border-radius: 8px; + transition: background-color 0.3s ease; + margin-bottom: 10px; +} + +.achievementItem:hover { + background-color: #E0E0E0; +} + +.image { + border-radius: 50%; + margin-right: 15px; +} + +.details { + display: flex; + flex-direction: column; + gap: 5px; +} + +.name { + font-size: 16px; + font-weight: 600; + color: #333333; +} + +.description { + font-size: 14px; + color: #666666; +} \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.module.css b/srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.module.css new file mode 100644 index 0000000..cbdaf9a --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.module.css @@ -0,0 +1,60 @@ +.achievements { + display: flex; + align-items: center; + flex-direction: column; + width: 100%; + height: 100%; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + padding: 15px; + } + + .title { + font-size: 24px; + font-weight: 600; + color: #333333; + margin-bottom: 20px; + } + + .achievementsContainer { + width: 100%; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: rgba(0, 0, 0, 0.1) transparent; + } + + .achievementItem { + display: flex; + align-items: center; + padding: 12px; + border-radius: 8px; + transition: background-color 0.3s ease; + margin-bottom: 10px; + } + + .achievementItem:hover { + background-color: #E0E0E0; + } + + .image { + border-radius: 50%; + margin-right: 15px; + } + + .details { + display: flex; + flex-direction: column; + gap: 5px; + } + + .name { + font-size: 16px; + font-weight: 600; + color: #333333; + } + + .description { + font-size: 14px; + color: #666666; + } \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.tsx b/srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.tsx new file mode 100644 index 0000000..b8a45b6 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/Achievements/AchievementsFr.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import classes from './AchievementsFr.module.css'; +import achieImage from '../../../../assets/achie.svg'; +import Image from 'next/image'; + +const achievements = Array(14).fill({ + title: 'Achievement Name', + desc: 'Achievement Description', + imgUrl: achieImage, +}); + +export const AchievementsFr = () => { + return ( +
+

Achievements

+
+ {achievements.map((item, index) => ( +
+ {item.title} +
+

{item.title}

+

{item.desc}

+
+
+ ))} +
+
+ ); +}; diff --git a/srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.module.css b/srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.module.css new file mode 100644 index 0000000..5ef7896 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.module.css @@ -0,0 +1,102 @@ +.overlay { + display: flex; + align-items: center; + flex-direction: column; + width: 100%; + height: 100%; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + padding: 15px; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +.modal { + + border-radius: 12px; + width: 300px; + max-width: 90%; + display: flex; + align-self: start; + justify-content: center; + width: 100%; + height: 100%; +} + + +.actions { + display: flex; + flex-direction: column; + gap: 16px; + display: flex; + align-items: center; + justify-content: center; + width: 100%; +} + +.actionItem { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + width: 100%; +} + +.button, +.buttonDanger { + width: 100%; + padding: 12px 16px; + border: none; + border-radius: 8px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: space-between; +} + +.button { + background-color: #4CAF50; + color: #FFFFFF; +} + +.button:hover { + background-color: #45a049; +} + +.buttonDanger { + background-color: #f44336; + color: #FFFFFF; +} + +.buttonDanger:hover { + background-color: #d32f2f; +} + +.buttonIcon { + margin-left: 8px; +} + +.closeButton { + margin-top: 20px; + width: 100%; + padding: 12px; + border: none; + border-radius: 8px; + background-color: #E0E0E0; + color: #333333; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.closeButton:hover { + background-color: #CCCCCC; +} \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.tsx b/srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.tsx new file mode 100644 index 0000000..46893e8 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/FriendActions/FriendActions.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import classes from './FriendActions.module.css'; +import challengeImage from '../../../../assets/challengeBlack.svg' +import snedMessageImage from '../../../../assets/messageBlack.svg' +import sendRequestImage from '../../../../assets/sendRequest.svg' +import Image from 'next/image'; + +interface FriendActionsProps { + friend: { + name: string; + isFriend: boolean; + }; + onClose: () => void; +} + +const FriendActions: React.FC = ({ friend, onClose }) => { + const handleAction = (action: string) => { + console.log(`${action} action for ${friend.name}`); + // Implement the actual action logic here + }; + + return ( +
+
+ {/*

{friend.name}

*/} +
+
+ + image +
+
+ + image +
+
+ + image +
+
+ {/* */} +
+
+ ); +}; + +// Dummy data for testing +const dummyFriend = { + name: "Ismail Barka", + isFriend: true, +}; + +const dummyOnClose = () => { + console.log("Modal closed"); +}; + +// Usage +const App = () => ( + +); + +export default App; diff --git a/srcs/frontend/src/components/FriendPage/Friends/FriendsFr.module.css b/srcs/frontend/src/components/FriendPage/Friends/FriendsFr.module.css new file mode 100644 index 0000000..424397a --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/Friends/FriendsFr.module.css @@ -0,0 +1,79 @@ +.Friends { + display: flex; + flex-direction: column; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + height: 100%; + border-radius: 8px; + overflow: hidden; +} + +.buttons { + display: flex; + justify-content: space-around; + padding: 15px; + background-color: #FFFFFF; + border-bottom: 1px solid #E0E0E0; +} + +.button { + width: 100px; + height: 40px; + border: none; + background-color: #F5F5F5; + color: #333333; + border-radius: 20px; + cursor: pointer; + font-size: 16px; + font-weight: 500; + transition: all 0.3s ease; +} + +.buttonClicked { + width: 100px; + height: 40px; + border: none; + background-color: #333333; + color: #FFFFFF; + border-radius: 20px; + cursor: pointer; + font-size: 16px; + font-weight: 500; +} + +.Online { + display: flex; + align-items: center; + padding: 10px; + transition: background-color 0.3s ease; +} + +.Online:hover { + background-color: #E0E0E0; +} + +.image { + border-radius: 50%; + margin-right: 15px; +} + +.nameAndMsg { + flex: 1; +} + +.name { + font-size: 16px; + font-weight: 600; + color: #333333; + margin-bottom: 5px; +} + +.message { + font-size: 14px; + color: #666666; +} + +.data { + overflow-y: auto; + max-height: calc(100% - 70px); +} \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/Friends/FriendsFr.tsx b/srcs/frontend/src/components/FriendPage/Friends/FriendsFr.tsx new file mode 100644 index 0000000..5d9fbda --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/Friends/FriendsFr.tsx @@ -0,0 +1,86 @@ +"use client" +import React, { useState } from 'react' +import classes from "./FriendsFr.module.css" +import TestImage from '../../../../assets/player.png' +import Image from 'next/image'; + +const buttons: string[] = ["Online", "Request", "Blocked"]; +const OnlinePeople = [{ + name: "Ismail barka", + msg: "this will be the place of the last message from this person", + url: TestImage, + + },{ + name: "imrane barka", + msg: "this will be the place of the last message from this person", + url: TestImage, + },{ + name: "anas barka", + msg: "this will be the place of the last message from this person", + url: TestImage, + },{ + name: "Ismail barka", + msg: "this will be the place of the last message from this person", + url: TestImage, + }] +const FriendsFr = () => { + + const Online =() =>{ + return( +
+ {OnlinePeople.map((item, index) =>{ + return
+ +
+

{item.name}

+

{item.msg}

+
+
+ })} + +
+ ) + } + const Request =() =>{ + return( +
testRequest
+ ) + } + const Blocked =() =>{ + return( +
testBlocked
+ ) + } + + const [clicked, setClicked] = useState("Online"); + const handleClick = (name:string) =>{ + console.log('===================================='); + setClicked(name) + console.log(name); + console.log('===================================='); + } + const handleData = (clicked:string) =>{ + if(clicked === "Online") + return + else if(clicked === "Request") + return + else if(clicked === "Blocked") + return + } + return ( +
+
+ {buttons.map((item, index) =>{ + return( + + ) + })} +
+
+ {handleData(clicked)} +
+
+ ) +} + +export default FriendsFr diff --git a/srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.module.css b/srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.module.css new file mode 100644 index 0000000..be59bc6 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.module.css @@ -0,0 +1,71 @@ +.playerinfos { + display: flex; + width: 100%; + justify-content: space-around; + height: 100%; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + padding: 10px; +} + +.imageC { + flex: 2; + display: flex; + flex-direction: column; + width: 100%; + justify-content: center; + align-items: center; + min-width: 50px; +} + +.image { + width: 80px; + height: 80px; + border-radius: 50%; + object-fit: cover; +} + +.infosContainer { + flex: 5; + display: flex; + flex-direction: column; + justify-content: center; +} + +.info { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 0; +} + +.title { + font-size: 14px; + color: #333333; + font-weight: 500; +} + +.infoAndCopy { + display: flex; + align-items: center; + gap: 5px; +} + +@media (max-width: 480px) { + .playerinfos { + flex-direction: column; + } + + .imageC { + margin-bottom: 10px; + } + + .info { + padding: 5px 0; + } + + .title { + font-size: 12px; + } +} \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.tsx b/srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.tsx new file mode 100644 index 0000000..b062829 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/PlayerInfos/PlayerInfosFr.tsx @@ -0,0 +1,50 @@ +import React, { useEffect } from 'react'; +import classes from "./PlayerInfosFr.module.css"; +import { useUserContext } from '../../../context/UserContext'; // Import the custom hook +import TimeDifference from '../../TimeDifference/TimeDifference'; +import CopyToClipboard from '../../CopyToClipboard/CopyToClipboard'; +import Image from 'next/image'; + + + + + +const PlayerInfosFr = () => { + const { searchedUserData } = useUserContext(); + return ( +
+
+ avatar +
+
+
+

username:

+
+

+ {searchedUserData?.username ? searchedUserData?.username.length > 10 ? `${searchedUserData.username.slice(0, 10)}...` : searchedUserData.username : "loading"} +

+ +
+
+
+

id:

+
+

+ {searchedUserData?.id ? searchedUserData?.id.toString().length > 10 ? `${searchedUserData.id.toString().slice(0, 10)}...` : searchedUserData.id : "loading"} +

+ +
+
+
+

status:

+
+

{searchedUserData?.username ? (searchedUserData.is_online ? "Online" : "Offline") : "loading"}

+
+
+ +
+
+ ); +}; + +export default PlayerInfosFr; diff --git a/srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.module.css b/srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.module.css new file mode 100644 index 0000000..d0c5201 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.module.css @@ -0,0 +1,34 @@ +.container { + width: 100%; + height: 100%; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + position: relative; + overflow: hidden; +} + +.textContainer { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + color: #333333; + font-size: 16px; + text-align: center; + width: 200px; + z-index: 2; +} + +.level { + font-size: 18px; + font-weight: 600; +} + +.progressBar { + position: absolute; + height: 100%; + background-color: #4CAF50; + border-radius: 8px; + transition: width 0.3s ease; +} \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.tsx b/srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.tsx new file mode 100644 index 0000000..eb568f3 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/ProgressBar/ProgressBarFr.tsx @@ -0,0 +1,47 @@ +"use client" +import React from 'react' +import classes from './ProgressBarFr.module.css' +import { Container } from 'react-bootstrap'; +import { useUserContext } from '@/context/UserContext'; + +const percentage:string = "15%"; + + +const getLastTwoDigits = (number) => { + // Convert the number to a string + const numberStr = number.toString(); + + // Get the last two characters + const lastTwoDigits = numberStr.slice(-2); + + // Return the last two digits as a number or string based on your needs + return lastTwoDigits; // returns a string +}; +const getLastThreeDigits = (number) => { + // Convert the number to a string + const numberStr = number.toString(); + + // Check if the number is 0 and return "0" if true + if (number === 0) return "0"; + + // Return the second-to-last character if the number has two or more digits + return numberStr.length >= 2 ? numberStr.slice(-3, -2) : numberStr; +}; + +const ProgressBarFr = () => { + + const { userData } = useUserContext(); + + + return ( +
+
+ +
+

level {getLastThreeDigits(999)} - {getLastTwoDigits(678)}%

+
+
+ ) +} + +export default ProgressBarFr diff --git a/srcs/frontend/src/components/FriendPage/Rate/RateFr.module.css b/srcs/frontend/src/components/FriendPage/Rate/RateFr.module.css new file mode 100644 index 0000000..c3a89ad --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/Rate/RateFr.module.css @@ -0,0 +1,23 @@ +.container { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + padding: 15px; +} + +.title { + font-size: 18px; + font-weight: 600; + color: #333333; + margin-bottom: 10px; +} + +.chartContainer { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/Rate/RateFr.tsx b/srcs/frontend/src/components/FriendPage/Rate/RateFr.tsx new file mode 100644 index 0000000..75c7871 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/Rate/RateFr.tsx @@ -0,0 +1,77 @@ +"use client"; +import dynamic from 'next/dynamic'; +import 'chart.js/auto'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; // Import the plugin +import classes from './RateFr.module.css'; + +const Line = dynamic(() => import('react-chartjs-2').then((mod) => mod.Line), { + ssr: false, +}); + +// Sample data for years and corresponding numbers +const chartData = [30, 15, 90, 65, 20]; // Numerical values for the y-axis + +// Get min and max values from the data array +const minValue = Math.min(...chartData) - Math.min(...chartData)/5; +const maxValue = Math.max(...chartData) + Math.max(...chartData)/5; + +const data = { + labels: ['2019', '2020', '2021', '2022', '2023'], // Years for the x-axis + datasets: [ + { + label: 'Performance over Years', // Label for the dataset + data: chartData, // Numerical values for the y-axis + backgroundColor: 'rgba(0, 0, 0, 0.2)', // Background color for the line + borderColor: 'rgba(0, 0, 0, 0.6)', // Line color + borderWidth: 2, + fill: true, // Fill the area under the line + tension: 0.4, // Adds some curve to the line + }, + ], +}; + +// Chart options +const options = { + responsive: true, // Ensure the chart is responsive + maintainAspectRatio: false, // Disable the default aspect ratio so it takes 100% of the container + scales: { + x: { + title: { + display: true, + }, + }, + y: { + title: { + display: true, + }, + min: minValue, // Set min from data + max: maxValue, // Set max from data + ticks: { + stepSize: 1, // Interval between ticks (optional, can be adjusted or removed) + }, + }, + }, + plugins: { + legend: { + display: true, // Show legend + }, + datalabels: { + color: 'black', // Text color for the labels + formatter: (value) => { + return value; // Return the actual value to display in the chart + }, + anchor: 'end', // Position the label at the end of the data point + align: 'top', // Align the label above the data point + }, + }, +}; + +const RateFr = () => { + return ( +
+ +
+ ); +} + +export default RateFr; diff --git a/srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.module.css b/srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.module.css new file mode 100644 index 0000000..9392a80 --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.module.css @@ -0,0 +1,23 @@ +.container { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + padding: 15px; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; +} + +.title { + font-size: 18px; + font-weight: 600; + color: #333333; + margin-bottom: 10px; +} + +.chartContainer { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.tsx b/srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.tsx new file mode 100644 index 0000000..e08c3dd --- /dev/null +++ b/srcs/frontend/src/components/FriendPage/WeeklyAttendance/WeeklyAttendanceFr.tsx @@ -0,0 +1,54 @@ +"use client"; +import dynamic from 'next/dynamic'; +import 'chart.js/auto'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; // Import the plugin +import classes from './WeeklyAttendanceFr.module.css'; + +const Pie = dynamic(() => import('react-chartjs-2').then((mod) => mod.Pie), { + ssr: false, +}); + +// Sample data for wins and losses +const matches = { win: 15, lose: 10 }; // Example match data +const data = { + labels: ['Wins', 'Losses'], // Use descriptive labels + datasets: [ + { + label: 'Game Results', + data: [matches.win, matches.lose], // Use the actual match data + backgroundColor: [ + 'rgba(0, 0, 0, 0.6)', // Color for Wins + 'rgba(255, 255, 255, 0.6)', // Color for Losses + ], + borderColor: 'rgba(0, 0, 0, 0.6)', // Border color for each segment + borderWidth: 2, + }, + ], +}; + +// Chart options +const options = { + plugins: { + legend: { + display: true, // Show legend + }, + datalabels: { + color: 'black', // Text color for the labels + formatter: (value) => { + return value; // Return the actual value to display in the chart + }, + anchor: 'center', // Center the label inside the segment + align: 'center', // Align the label to the center + }, + }, +}; + +const WeeklyAttendanceFr = () => { + return ( +
+ {/* Pass the plugin to the Pie chart */} +
+ ); +} + +export default WeeklyAttendanceFr; diff --git a/srcs/frontend/src/components/Friends/Friends.tsx b/srcs/frontend/src/components/Friends/Friends.tsx index e9399b7..70d42fd 100644 --- a/srcs/frontend/src/components/Friends/Friends.tsx +++ b/srcs/frontend/src/components/Friends/Friends.tsx @@ -1,86 +1,190 @@ "use client" -import React, { useState } from 'react' -import classes from "./friends.module.css" -import TestImage from '../../../assets/player.png' +import React, { useState, useEffect } from 'react' import Image from 'next/image'; +import axios from 'axios'; +import TestImage from '../../../assets/player.png' +import styles from './Friends.module.css' const buttons: string[] = ["Online", "Request", "Blocked"]; -const OnlinePeople = [{ - name: "Ismail barka", - msg: "this will be the place of the last message from this person", +const OnlinePeople = [ + { + name: "Ismail Barka", + msg: "This will be the place of the last message from this person", url: TestImage, - - },{ - name: "imrane barka", - msg: "this will be the place of the last message from this person", + }, + { + name: "Imrane Barka", + msg: "This will be the place of the last message from this person", url: TestImage, - },{ - name: "anas barka", - msg: "this will be the place of the last message from this person", + }, + { + name: "Anas Barka", + msg: "This will be the place of the last message from this person", url: TestImage, - },{ - name: "Ismail barka", - msg: "this will be the place of the last message from this person", + }, + { + name: "Ismail Barka", + msg: "This will be the place of the last message from this person", url: TestImage, - }] + } +]; + +type RequestType = { + id: number; + user1: { + id: number; + username: string; + avatar_url: string | null; + }; + state: string; + created_at: string; +}; +type BlockType = { + id: number; + user2: { + id: number; + username: string; + avatar_url: string | null; + }; + state: string; + created_at: string; +}; + const Friends = () => { + const [requests, setRequests] = useState([]); + const [blocked, setBlocked] = useState([]); + const [clicked, setClicked] = useState("Online"); - const Online =() =>{ - return( -
- {OnlinePeople.map((item, index) =>{ - return
- -
-

{item.name}

-

{item.msg}

-
+ useEffect(() => { + if (clicked === "Request" || clicked === "Blocked") { + fetchRequests(); + fetchBlocked(); + } + }, [clicked]); + + const fetchRequests = async () => { + try { + const res = await axios.get(`http://localhost:8000/api/users/me/relationships/friend_requests/`); + setRequests(res.data); + } catch (err) { + console.log("Error in fetching user data", err); + } + }; + const fetchBlocked = async () => { + try { + const res1 = await axios.get(`http://localhost:8000/api/users/me/relationships/block_list/`); + setBlocked(res1.data); + } catch (err) { + console.log("Error in fetching user data", err); + } + }; + + const Online = () => ( +
+ {OnlinePeople.map((item, index) => ( +
+ {item.name} +
+

{item.name}

+

{item.msg}

+
+ + +
+
- })} - -
- ) - } - const Request =() =>{ - return( -
testRequest
- ) - } - const Blocked =() =>{ - return( -
testBlocked
- ) - } + ))} +
+ ); - const [clicked, setClicked] = useState("Online"); - const handleClick = (name:string) =>{ - console.log('===================================='); - setClicked(name) - console.log(name); - console.log('===================================='); - } - const handleData = (clicked:string) =>{ - if(clicked === "Online") - return - else if(clicked === "Request") - return - else if(clicked === "Blocked") - return + const handleAcceptRequest = async (id: number) => { + try { + await axios.post(`http://localhost:8000/api/users/me/relationships/${id}/accept_request/`); + setRequests(requests.filter(item => item.id !== id)); + console.log("Friend request accepted successfully"); + } catch (error) { + console.error("Error accepting friend request", error); + } } - return ( -
-
- {buttons.map((item, index) =>{ - return( - - ) - })} + + const Request = () => ( +
+ {requests.map((item) => ( +
+ {item.user1.username} +
+

{item.user1.username}

+

Friend request from {item.user1.username}

+ +
+
+ ))}
-
- {handleData(clicked)} + ); + + const handleUnblock = async (id: number) => { + try { + await axios.post(`http://localhost:8000/api/users/me/relationships/${id}/remove_relationship/`); + setBlocked(blocked.filter(item => item.id !== id)); + console.log("User unblocked successfully"); + } catch (error) { + console.error("Error unblocking user", error); + } + }; + + const Blocked = () => ( +
+ {blocked.map((item) => ( +
+ {item.user2.username} +
+

{item.user2.username}

+

Blocked user

+ +
+
+ ))} +
+ ); + + const handleClick = (name: string) => { + setClicked(name); + }; + + const handleData = () => { + if (clicked === "Online") return ; + else if (clicked === "Request") return ; + else if (clicked === "Blocked") return ; + }; + + return ( +
+
+ {buttons.map((item, index) => ( + + ))} +
+
+ {handleData()} +
-
- ) -} + ); +}; -export default Friends +export default Friends; \ No newline at end of file diff --git a/srcs/frontend/src/components/Friends/friends.module.css b/srcs/frontend/src/components/Friends/friends.module.css index e8b5d79..0801d9a 100644 --- a/srcs/frontend/src/components/Friends/friends.module.css +++ b/srcs/frontend/src/components/Friends/friends.module.css @@ -1,46 +1,110 @@ -.Friends{ +.friends { display: flex; flex-direction: column; - background-color: #E0E0E0; - border: 1px solid #B0B0B0; - height: 100%; - border-radius: 5px; - - .buttons{ - display: flex; - justify-content: space-around; - margin: 17px; - - .button{ - width: 90px; - height: 50px; - border:none; - background-color: #ffffff; - color: #000000; - border-radius: 6px; - cursor: pointer; - font-size: 22px; - } - .buttonClicked{ - width: 90px; - height: 50px; - border:none; - background-color: #000000; - color: #ffffff; - border-radius: 6px; - cursor: pointer; - font-size: 22px; - } - } -} -.Online{ + background-color: #FFFFFF; + border: 1px solid #E0E0E0; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.buttons { + display: flex; + justify-content: space-around; + padding: 15px; + background-color: #F5F5F5; + border-bottom: 1px solid #E0E0E0; +} + +.button { + padding: 8px 16px; + border: none; + background-color: #FFFFFF; + color: #333333; + border-radius: 20px; + cursor: pointer; + font-size: 14px; + font-weight: 600; + transition: all 0.3s ease; +} + +.buttonClicked { + padding: 8px 16px; + border: none; + background-color: #333333; + color: #FFFFFF; + border-radius: 20px; + cursor: pointer; + font-size: 14px; + font-weight: 600; +} + +.data { + max-height: calc(100vh - 200px); + overflow-y: auto; +} + +.item { display: flex; align-items: center; - .image{ - border-radius: 50%; - margin: 7px; - } - &:hover{ - background-color: #00000024; - } + padding: 15px; + border-bottom: 1px solid #E0E0E0; +} + +.image { + border-radius: 50%; + margin-right: 15px; +} + +.content { + flex: 1; +} + +.name { + font-size: 16px; + font-weight: 600; + color: #333333; + margin-bottom: 5px; +} + +.message { + font-size: 14px; + color: #666666; + margin-bottom: 10px; +} + +.actionButtons { + display: flex; + gap: 10px; + margin-top: 8px; +} + +.actionButton { + padding: 6px 12px; + border: none; + border-radius: 4px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.challengeButton { + background-color: #4CAF50; + color: #FFFFFF; +} + +.messageButton { + background-color: #2196F3; + color: #FFFFFF; +} + +.acceptButton { + background-color: #4CAF50; + color: #FFFFFF; +} + +.unblockButton { + background-color: #FF5722; + color: #FFFFFF; } \ No newline at end of file diff --git a/srcs/frontend/src/components/HorizontalNavbar/HorizontalNavbar.module.css b/srcs/frontend/src/components/HorizontalNavbar/HorizontalNavbar.module.css index ec3b388..dfebc59 100644 --- a/srcs/frontend/src/components/HorizontalNavbar/HorizontalNavbar.module.css +++ b/srcs/frontend/src/components/HorizontalNavbar/HorizontalNavbar.module.css @@ -1,154 +1,90 @@ -.container{ +.container { display: flex; justify-content: space-between; align-items: center; height: 100%; width: 100%; + padding: 0 15px; +} - .searchBar{ - flex: 1; - display: flex; - justify-content: center; - align-items: center; - height: 100%; - @media screen and (max-width: 419px) { - display: none; - } +.searchBar { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} - } - .searchButton{ - flex: 1; - display: flex; - justify-content: center; - align-items: center; - height: 100%; - .iconsContainer{ - height: 40px; - width: 40px; - border-radius: 50%; - background-color: #E0E0E0; - border: 1px solid #CCCCCC; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - .image{ - width: 20px; - height: 20px; - } - } - @media screen and (min-width: 420px) { - display: none; - } +.searchButton { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} +.iconsContainer { + height: 40px; + width: 40px; + border-radius: 50%; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} - } +.image { + width: 20px; + height: 20px; +} - .container2{ - display: flex; - align-items: center; - justify-content: center; - gap: 5px; - margin: 10px; +.container2 { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; +} +.iconsContainerSelected { + background-color: #333333; + border-color: #333333; +} - .iconsContainer{ - height: 40px; - width: 40px; - border-radius: 50%; - background-color: #E0E0E0; - border: 1px solid #CCCCCC; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - .image{ - width: 20px; - height: 20px; - } - } - .iconsContainerSelected{ - height: 40px; - width: 40px; - border-radius: 50%; - background-color: black; - border: 1px solid #CCCCCC; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - .image{ - width: 20px; - height: 20px; - } - } - .iconsContainerSearchActive{ - display: none; - } +.profile { + width: 40px; + height: 40px; + border-radius: 50%; + border: 1px solid #E0E0E0; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + overflow: hidden; +} - .profile{ - width: 40px; - height: 40px; - background-color: aquamarine; - border-radius: 50%; - border: 1px solid #CCCCCC; - display: flex; - align-items: center;justify-content: center; - .image{ - width: 40px; - height: 40px; - border-radius: 50%; - border: 1px solid #CCCCCC; - } - cursor: pointer; +.X { + background-color: transparent; + border: none; + cursor: pointer; +} - .image{ - width: 40px; - height: 40px; - border-radius: 50%; - border: 1px solid #CCCCCC; - } - } - .profileSearchActive{ - - width: 40px; - height: 40px; - background-color: aquamarine; - border-radius: 50%; - border: 1px solid #CCCCCC; - display: flex; - align-items: center;justify-content: center; - .image{ - width: 40px; - height: 40px; - border-radius: 50%; - border: 1px solid #CCCCCC; - } - cursor: pointer; - @media screen and (max-width: 419px) { - display: none; - } - } - .X{ - width: 40px; - height: 40px; - background-color: transparent; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - .image{ - width: 40px; - height: 40px; - border-radius: 50%; - } - cursor: pointer; - border: none; - } +.displayNone { + display: none; +} +@media screen and (max-width: 419px) { + .searchBar { + display: none; + } + .searchButton { + display: flex; } } -.displayNone{ - display: none; +@media screen and (min-width: 420px) { + .searchButton { + display: none; + } } \ No newline at end of file diff --git a/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.module.css b/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.module.css index a5e65f9..078ce1c 100644 --- a/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.module.css +++ b/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.module.css @@ -1,29 +1,102 @@ -.container{ +.container { display: flex; border: 1px solid #CCCCCC; height: 40px; align-items: center; - justify-content: center; + justify-content: flex-start; min-width: 200px; max-width: 400px; width: 90%; - border-radius: 10px; - background-color: #E0E0E0; - - .image{ - width: 15px; - height: 15px; - margin-right: 10px; - margin-left: 10px; - } - .input{ - background-color: transparent; - border: none; - width: 100%; - height: 100%; - } - .input:focus { - border: none; - outline: none; + border-radius: 20px; + background-color: #FFFFFF; + transition: all 0.3s ease; + position: relative; +} + +.container.active { + background-color: #000000; +} + +.image { + width: 15px; + height: 15px; + margin-right: 10px; + margin-left: 15px; + cursor: pointer; +} + +.input { + background-color: transparent; + border: none; + width: 100%; + height: 100%; + color: #000000; + font-size: 14px; +} + +.container.active .input { + color: #FFFFFF; +} + +.input::placeholder { + color: #999999; +} + +.container.active .input::placeholder { + color: #CCCCCC; +} + +.input:focus { + border: none; + outline: none; +} + +.resultContainer { + position: absolute; + top: 100%; + left: 0; + right: 0; + background-color: #FFFFFF; + border: 1px solid #CCCCCC; + border-top: none; + border-radius: 0 0 20px 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + z-index: 10; +} + +.resultItem { + display: flex; + align-items: center; + padding: 10px 15px; + cursor: pointer; + transition: background-color 0.2s ease; + border: none; + background-color: transparent; + width: 100%; +} + +.resultItem:hover { + background-color: #F5F5F5; +} + +.resultItem h2 { + margin-left: 10px; + font-size: 14px; + color: #000000; +} + +@media (max-width: 480px) { + .container { + max-width: 100%; } +} + +.showAllBtn{ + width: 100%; + height: 40px; + border: none; + background-color: transparent; + color: blue; + text-decoration: underline; + cursor: pointer; } \ No newline at end of file diff --git a/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.tsx b/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.tsx index ea0daa1..3f6d63d 100644 --- a/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.tsx +++ b/srcs/frontend/src/components/HorizontalNavbar/SearchBar/SearchBar.tsx @@ -1,21 +1,106 @@ "use client"; -import React, { useContext, useState } from "react"; +import React, { useState, ChangeEvent } from "react"; import classes from './SearchBar.module.css'; -import searchLogoBlack from '../../../../assets/SearchBlack.svg' -import SearchLogoWithe from '../../../../assets/SearchWithe.svg' +import searchLogoBlack from '../../../../assets/SearchBlack.svg'; import Image from "next/image"; +import avatarImage from '../../../../assets/player.png'; +import axios from "axios"; +import { useRouter } from 'next/navigation'; +import { useUserContext } from "@/context/UserContext"; -const SearchBar = () => { - const [searchVisibile, setSearchVisibile] = useState(false); - const handleImageClick = () =>{ - setSearchVisibile(!searchVisibile); - } +// Define the type for a single search result item +interface SearchResult { + avatar_url: string; + first_name: string; + id: number; + is_online: boolean; + last_name: string; + loses: number; + rank: number; + rating: number; + username: string; + wins: number; +} + +// Define the structure for paginated search results +interface PaginatedSearchResults { + res: SearchResult[]; + next: string | null; +} + +// Define the props type for SearchResultComponent +interface SearchResultComponentProps { + searchResults: PaginatedSearchResults; +} + +const SearchResultComponent: React.FC = ({ searchResults }) => { + const router = useRouter(); + + const handleClick = (result) => { + + console.log(result); + + + router.push(`/users/friend/${result.id}`); + }; + + return ( +
+ {searchResults.res.map((result) => ( + + ))} + {searchResults.next && } +
+ ); +}; + +const SearchBar: React.FC = () => { + const [searchVisible, setSearchVisible] = useState(false); + const [searchResults, setSearchResults] = useState({ res: [], next: null }); + const { search, updateSearch } = useUserContext(); + + const getSearch = async (e: ChangeEvent) => { + const searchValue = e.target.value; + updateSearch(searchValue); + + try { + const res = await axios.get("http://localhost:8000/api/users/search/", { + params: { + page: 1, + search: searchValue, + }, + }); + setSearchResults({ next: res.data.next, res: res.data.results }); + } catch (error) { + console.error("Error fetching search results:", error); + } + }; + + const handleImageClick = () => { + setSearchVisible(!searchVisible); + }; return ( -
- search logo black - +
+ Search Logo + + {search && }
); }; diff --git a/srcs/frontend/src/components/InputField/InputField.module.css b/srcs/frontend/src/components/InputField/InputField.module.css index bcddb61..a03a3ec 100644 --- a/srcs/frontend/src/components/InputField/InputField.module.css +++ b/srcs/frontend/src/components/InputField/InputField.module.css @@ -4,36 +4,35 @@ align-items: center; margin-bottom: 20px; width: 100%; +} +.label { + font-size: 18px; + color: #000000; + margin-bottom: 5px; + width: 100%; + text-align: left; + max-width: 400px; +} - .label { - font-size: 18px; - color: #1A1A1A; - margin-bottom: 5px; - width: 100%; - text-align: left; - max-width: 400px; - } - - .input { - height: 45px; - max-width: 400px; - width: 100%; - border: 1px solid #C1BBBB; - border-radius: 25px; - padding: 0 11px; - font-size: 16px; - transition: border-color 0.3s ease; - - &:focus { - border-color: #4A90E2; - outline: none; - } - } +.input { + height: 45px; + max-width: 400px; + width: 100%; + border: 1px solid #000000; + border-radius: 25px; + padding: 0 11px; + font-size: 16px; + transition: border-color 0.3s ease; +} - .errorMsg { - font-size: 14px; - color: #D32F2F; - margin-top: 5px; - } +.input:focus { + border-color: rgb(255, 155, 4); + outline: none; } + +.errorMsg { + font-size: 14px; + color: #D32F2F; + margin-top: 5px; +} \ No newline at end of file diff --git a/srcs/frontend/src/components/InputField/InputField.tsx b/srcs/frontend/src/components/InputField/InputField.tsx index f89ec4a..80d36d4 100644 --- a/srcs/frontend/src/components/InputField/InputField.tsx +++ b/srcs/frontend/src/components/InputField/InputField.tsx @@ -1,5 +1,5 @@ -import react from "react" -import classes from './InputField.module.css' +import React from "react"; +import classes from './InputField.module.css'; interface InputFieldProps { label: string; @@ -19,21 +19,21 @@ const InputField: React.FC = ({ value, onChange, error, -}) =>{ +}) => { return ( -
- - - {error &&

{error}

} -
+
+ + + {error &&

{error}

} +
); }; diff --git a/srcs/frontend/src/components/NavBar/NavBar.module.css b/srcs/frontend/src/components/NavBar/NavBar.module.css new file mode 100644 index 0000000..b2c6abc --- /dev/null +++ b/srcs/frontend/src/components/NavBar/NavBar.module.css @@ -0,0 +1,84 @@ +.navbar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.5rem 1rem; + background-color: #FFFFFF; + border-bottom: 1px solid #E0E0E0; + } + + .logo { + display: flex; + align-items: center; + } + + .image { + height: 40px; + width: auto; + } + + .pagesButtons, + .settingsAndLogout { + display: flex; + gap: 1rem; + } + + .button, + .buttonSelected { + background: none; + border: none; + cursor: pointer; + padding: 0.5rem; + border-radius: 10px; + transition: background-color 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + gap: 5px; + } + + .button:hover { + background-color: #F5F5F5; + } + + .buttonSelected { + background-color: #00000053; + } + + .buttonImage { + width: 24px; + height: 24px; + } + + @media (max-width: 768px) { + .navbar { + flex-direction: column; + padding: 0.5rem; + } + + .logo { + margin-bottom: 0.5rem; + } + + .pagesButtons, + .settingsAndLogout { + width: 100%; + justify-content: space-around; + } + + .settingsAndLogout { + margin-top: 0.5rem; + } + } + + @media (max-width: 480px) { + .button, + .buttonSelected { + padding: 0.25rem; + } + + .buttonImage { + width: 20px; + height: 20px; + } + } \ No newline at end of file diff --git a/srcs/frontend/src/components/NavBar/NavBar.tsx b/srcs/frontend/src/components/NavBar/NavBar.tsx new file mode 100644 index 0000000..1eb1c5a --- /dev/null +++ b/srcs/frontend/src/components/NavBar/NavBar.tsx @@ -0,0 +1,82 @@ +"use client"; + +import React, { useContext, useState } from "react"; +import chatLogoWithe from '../../../assets/chatLogoWithe.svg'; +import chatLogoBlack from '../../../assets/chatLogoBlack.svg'; +import gameLogoWithe from '../../../assets/gameLogoWithe.svg'; +import gameLogoBlack from '../../../assets/gameLogoBlack.svg'; +import homeLogoWithe from '../../../assets/homeLogoWithe.svg'; +import homeLogoBlack from '../../../assets/homeLogoBlack.svg'; +import leaderboardWithe from '../../../assets/leaderboardWithe.svg'; +import leaderboardBlack from '../../../assets/leaderboardBlack.svg'; +import SettingsWithe from '../../../assets/SettingsWithe.svg'; +import SettingsBlack from '../../../assets/SettingsBlack.svg'; +import LogoutWithe from '../../../assets/LogoutWithe.svg'; +import LogoutBlack from '../../../assets/LogoutBlack.svg'; +import { useUserContext } from "@/context/UserContext"; +import mainLogo from '../../../assets/Main-Logo.svg'; +import Image from "next/image"; +import Link from "next/link"; +import classes from './NavBar.module.css' + + +const NavBar = () => { + + const pages = [ + { name: "home", logoBlack: homeLogoBlack, logoWhite: homeLogoWithe }, + { name: "chat", logoBlack: chatLogoBlack, logoWhite: chatLogoWithe }, + { name: "game", logoBlack: gameLogoBlack, logoWhite: gameLogoWithe }, + { name: "leaderboard", logoBlack: leaderboardBlack, logoWhite: leaderboardWithe }, + { name: "settings", logoBlack: SettingsBlack, logoWhite: SettingsWithe }, + { name: "logout", logoBlack: LogoutBlack, logoWhite: LogoutWithe } + ]; + const { currentPage, updateCurrentPage } = useUserContext(); + + const handlePageChange = (page: string) => { + updateCurrentPage(page); + }; + + return ( + + ); +}; + +export default NavBar; diff --git a/srcs/frontend/src/components/PlayerInfos/PlayerInfos.tsx b/srcs/frontend/src/components/PlayerInfos/PlayerInfos.tsx index 7689131..a83b45c 100644 --- a/srcs/frontend/src/components/PlayerInfos/PlayerInfos.tsx +++ b/srcs/frontend/src/components/PlayerInfos/PlayerInfos.tsx @@ -1,64 +1,60 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import classes from "./playerInfos.module.css"; import { useUserContext } from '../../context/UserContext'; // Import the custom hook import TimeDifference from '../TimeDifference/TimeDifference'; import CopyToClipboard from '../CopyToClipboard/CopyToClipboard'; +import Image from 'next/image'; + -const formatDate = (timestamp) => { - const date = new Date(timestamp); - if (isNaN(date.getTime())) { - return 'Invalid date'; - } - const options = { - year: 'numeric', - month: 'long', - day: 'numeric', - }; - return new Intl.DateTimeFormat('en-US', options).format(date); -}; -const PlayerInfos = () => { - const { userData } = useUserContext(); // Destructure userData + +const PlayerInfos = () => { + const { userData, updateCurrentPage } = useUserContext(); return (
-
-

username:

-
-

- {userData?.username ? userData?.username.length > 10 ? `${userData.username.slice(0, 10)}...` : userData.username : "loading"} -

- -
+
+ avatar
-
-

id:

-
-

- {userData?.id ? userData?.id.toString().length > 10 ? `${userData.id.toString().slice(0, 10)}...` : userData.id : "loading"} -

- +
+
+

username:

+
+

+ {userData?.username ? userData?.username.length > 10 ? `${userData.username.slice(0, 10)}...` : userData.username : "loading"} +

+ +
-
-
-

status:

-
-

{userData?.username ? (userData.is_active ? "Online" : "Offline") : "loading"}

+
+

id:

+
+

+ {userData?.id ? userData?.id.toString().length > 10 ? `${userData.id.toString().slice(0, 10)}...` : userData.id : "loading"} +

+ +
-
- {!userData.is_active && (
-

last seen:

-

+

status:

+
+

{userData?.username ? (userData.is_active ? "Online" : "Offline") : "loading"}

+
- )} -
-

email:

-
-

- {userData?.email ? userData?.email.length > 10 ? `${userData.email.slice(0, 10)}...` : userData.email : "loading"} -

- + {!userData.is_active && ( +
+

last seen:

+

+
+ )} +
+

email:

+
+

+ {userData?.email ? userData?.email.length > 10 ? `${userData.email.slice(0, 10)}...` : userData.email : "loading"} +

+ +
diff --git a/srcs/frontend/src/components/PlayerInfos/playerInfos.module.css b/srcs/frontend/src/components/PlayerInfos/playerInfos.module.css index 647c498..be59bc6 100644 --- a/srcs/frontend/src/components/PlayerInfos/playerInfos.module.css +++ b/srcs/frontend/src/components/PlayerInfos/playerInfos.module.css @@ -1,31 +1,71 @@ -.playerinfos{ +.playerinfos { display: flex; - flex-direction: column; width: 100%; justify-content: space-around; height: 100%; - background-color: #E0E0E0; - border: 1px solid #B0B0B0; - border-radius: 5px; - - - - .info{ - display: flex; - align-items: center; - justify-content: center; - justify-content: space-between; - padding: 10px; - .title{ - font-size: 18px; - } - - .infoAndCopy{ - display: flex; - align-items: center; - justify-content: center; - gap: 5px; - } + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + padding: 10px; +} + +.imageC { + flex: 2; + display: flex; + flex-direction: column; + width: 100%; + justify-content: center; + align-items: center; + min-width: 50px; +} + +.image { + width: 80px; + height: 80px; + border-radius: 50%; + object-fit: cover; +} + +.infosContainer { + flex: 5; + display: flex; + flex-direction: column; + justify-content: center; +} + +.info { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 0; +} + +.title { + font-size: 14px; + color: #333333; + font-weight: 500; +} + +.infoAndCopy { + display: flex; + align-items: center; + gap: 5px; +} + +@media (max-width: 480px) { + .playerinfos { + flex-direction: column; } + .imageC { + margin-bottom: 10px; + } + + .info { + padding: 5px 0; + } + + .title { + font-size: 12px; + } } \ No newline at end of file diff --git a/srcs/frontend/src/components/ProgressBar/progressBar.module.css b/srcs/frontend/src/components/ProgressBar/progressBar.module.css index 862c0e3..d0c5201 100644 --- a/srcs/frontend/src/components/ProgressBar/progressBar.module.css +++ b/srcs/frontend/src/components/ProgressBar/progressBar.module.css @@ -1,30 +1,34 @@ -.container{ +.container { width: 100%; height: 100%; - background-color: #E0E0E0; - border: 1px solid #B0B0B0; - border-radius: 5px; - position:relative; - - .textContainer{ - position: absolute; - left: calc(50% + -100px) ; - top: 50%; - transform: translateY(-50%); - color: white; - font-size: 24px; - text-align: center; - width: 200px; - .level{ - font-size: 24px; - } - } - .progressBar{ - position: absolute; - height: 100%; - background-color: black; - width: 75%; - border-radius: 5px; - } + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + position: relative; + overflow: hidden; +} +.textContainer { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + color: #333333; + font-size: 16px; + text-align: center; + width: 200px; + z-index: 2; +} + +.level { + font-size: 18px; + font-weight: 600; +} + +.progressBar { + position: absolute; + height: 100%; + background-color: #4CAF50; + border-radius: 8px; + transition: width 0.3s ease; } \ No newline at end of file diff --git a/srcs/frontend/src/components/Rate/rate.module.css b/srcs/frontend/src/components/Rate/rate.module.css index 39e3e9f..c3a89ad 100644 --- a/srcs/frontend/src/components/Rate/rate.module.css +++ b/srcs/frontend/src/components/Rate/rate.module.css @@ -1,18 +1,23 @@ -.container{ +.container { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; - background-color: #E0E0E0; - border: 1px solid #B0B0B0; - border-radius: 5px; - - .title{ + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; + padding: 15px; +} - } - .chartContainer{ - width: 100%; - height: 100%; - } +.title { + font-size: 18px; + font-weight: 600; + color: #333333; + margin-bottom: 10px; +} + +.chartContainer { + width: 100%; + height: 100%; } \ No newline at end of file diff --git a/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.module.css b/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.module.css index 59f6f02..caf951b 100644 --- a/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.module.css +++ b/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.module.css @@ -1,79 +1,71 @@ -.choices { +.navbar { display: flex; flex-direction: column; align-items: center; justify-content: space-between; - width: 100px; + width: 70px; height: 100vh; - background-color: #E0E0E0; + background-color: #F5F5F5; + padding: 20px 0; + transition: all 0.3s ease; +} - .logo { - width: 100px; - height: 100px; - display: flex; - align-items: center; - justify-content: center; +.logo { + width: 70px; + height: 70px; + display: flex; + align-items: center; + justify-content: center; +} - .image { - width: 50px; - height: 50px; - } - } +.image { + width: 40px; + height: 40px; +} - .pagesButtons { - display: flex; - flex-direction: column; - } +.pagesButtons, +.settingsAndLogout { + display: flex; + flex-direction: column; + align-items: center; +} - .settingsAndLogout { - display: flex; - flex-direction: column; - } +.button, +.buttonSelected { + width: 50px; + height: 50px; + margin: 10px 0; + display: flex; + justify-content: center; + align-items: center; + border: none; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; +} - .button { - width: 50px; - height: 50px; - margin: 10px; - display: flex; - justify-content: center; - align-items: center; - border: 1px solid #000000; - border-radius: 10px; - cursor: pointer; - background-color: #FFFFFF; - color: #000000; - - .buttonImage { - width: 30px; - height: 30px; - } +.button { + background-color: transparent; + color: #333333; +} - &:hover { - background-color: #CCCCCC; - } - } +.buttonSelected { + background-color: #333333; + color: #FFFFFF; +} - .buttonSelected { - width: 50px; - height: 50px; - margin: 10px; - display: flex; - justify-content: center; - align-items: center; - border: 1px solid #CCCCCC; - border-radius: 10px; - cursor: pointer; - background-color: #000000; - color: #FFFFFF; - - .buttonImage { - width: 30px; - height: 30px; - } +.button:hover, +.buttonSelected:hover { + background-color: #E0E0E0; +} +.buttonImage { + width: 24px; + height: 24px; +} - &:hover { - background-color: #CCCCCC; - } +@media screen and (max-width: 880px) { + .navbar { + display: none; } -} +} \ No newline at end of file diff --git a/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx b/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx index ae487ba..2ba7774 100644 --- a/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx +++ b/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx @@ -16,94 +16,65 @@ import SettingsWithe from '../../../assets/SettingsWithe.svg'; import SettingsBlack from '../../../assets/SettingsBlack.svg'; import LogoutWithe from '../../../assets/LogoutWithe.svg'; import LogoutBlack from '../../../assets/LogoutBlack.svg'; -import { UserContext } from "../../context/UserContext"; +import { UserContext, useUserContext } from "../../context/UserContext"; import Link from "next/link"; import axios from "axios"; const VerticalNavbar = () => { - const pagesMiddle = [ + const pages = [ { name: "home", logoBlack: homeLogoBlack, logoWhite: homeLogoWithe }, { name: "chat", logoBlack: chatLogoBlack, logoWhite: chatLogoWithe }, { name: "game", logoBlack: gameLogoBlack, logoWhite: gameLogoWithe }, - { name: "leaderboard", logoBlack: leaderboardBlack, logoWhite: leaderboardWithe } - ]; - const pagesEnd = [ + { name: "leaderboard", logoBlack: leaderboardBlack, logoWhite: leaderboardWithe }, { name: "settings", logoBlack: SettingsBlack, logoWhite: SettingsWithe }, { name: "logout", logoBlack: LogoutBlack, logoWhite: LogoutWithe } ]; - const { currentPage, updateCurrentPage, userData, updateUserData } = useContext(UserContext); + + const { currentPage, updateCurrentPage } = useUserContext(); + const handlePageChange = (page: string) => { updateCurrentPage(page); }; - useEffect(() => { - - const fetchData = async () =>{ - try { - const res = await axios.get("http://localhost:8000/api/users/me/",); - console.log("res"); - console.log(res.data); - updateUserData({ - id: res.data.id, - otp_uri: res.data.otp_uri, - last_login: res.data.last_login, - is_superuser: res.data.is_superuser, - username: res.data.username, - first_name: res.data.first_name, - last_name: res.data.last_name, - email: res.data.email, - is_staff: res.data.is_staff, - is_active: res.data.is_active, - date_joined: res.data.date_joined, - two_fa_enabled: res.data.two_fa_enabled, - is_online: res.data.is_online, - avatar_url: res.data.avatar_url , - wins: res.data.wins, - loses: res.data.loses, - rating: res.data.rating, - }) - - - } catch (err) { - console.log("test"); - } - } - - fetchData(); - }, []); - - - - return ( -
+
+ ); }; -export default VerticalNavbar; +export default VerticalNavbar; \ No newline at end of file diff --git a/srcs/frontend/src/components/weeklyAttendance/weeklyAttendance.module.css b/srcs/frontend/src/components/weeklyAttendance/weeklyAttendance.module.css index 51d13a7..9392a80 100644 --- a/srcs/frontend/src/components/weeklyAttendance/weeklyAttendance.module.css +++ b/srcs/frontend/src/components/weeklyAttendance/weeklyAttendance.module.css @@ -1,19 +1,23 @@ -.container{ +.container { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; - padding: 10px; - background-color: #E0E0E0; - border: 1px solid #B0B0B0; - border-radius: 5px; - - .title{ + padding: 15px; + background-color: #F5F5F5; + border: 1px solid #E0E0E0; + border-radius: 8px; +} - } - .chartContainer{ - width: 100%; - height: 100%; - } +.title { + font-size: 18px; + font-weight: 600; + color: #333333; + margin-bottom: 10px; +} + +.chartContainer { + width: 100%; + height: 100%; } \ No newline at end of file diff --git a/srcs/frontend/src/context/UserContext.tsx b/srcs/frontend/src/context/UserContext.tsx index 0e0cbaa..d96394d 100644 --- a/srcs/frontend/src/context/UserContext.tsx +++ b/srcs/frontend/src/context/UserContext.tsx @@ -8,6 +8,10 @@ interface UserContextType { updateCurrentPage: (pageName: string) => void; userData: UserDataType; updateUserData: (data: UserDataType) => void; + search: string; + updateSearch: (data: string) => void; + searchedUserData: SearchedUserDataType; + updateSearchedUserData: (data: SearchedUserDataType) => void; } // Define a type for the user data @@ -30,7 +34,20 @@ interface UserDataType { loses: number; rating: number; rank: number; +} +// Define a type for the searched user data +interface SearchedUserDataType { + avatar_url: string; + first_name: string; + id: number; + is_online: boolean; + last_name: string; + loses: number; + rank: number; + rating: number; + username: string; + wins: number; } // Create the context with a default value of `undefined` for type safety @@ -57,25 +74,55 @@ export const UserContextProvider = ({ children }: UserContextProviderProps) => { date_joined: "", two_fa_enabled: false, is_online: "", - avatar_url: "" , + avatar_url: "", wins: 0, loses: 0, rating: 0, rank: 0, - + }); + const [searchedUserData, setSearchedUserData] = useState({ + avatar_url: "", + first_name: "", + id: 0, + is_online: false, + last_name: "", + loses: 0, + rank: 0, + rating: 0, + username: "", + wins: 0, }); + const [search, setSearch] = useState(""); + + const updateSearchedUserData = (data: SearchedUserDataType) => { + setSearchedUserData(data); + }; + const updateCurrentPage = (pageName: string) => { setCurrentPage(pageName); }; + const updateSearch = (data: string) => { + setSearch(data); + }; + const updateUserData = (data: UserDataType) => { setUserData(data); - console.log("daata", data) + console.log("data", data); }; return ( - + {children} ); From e22fa24a4d32583c70d318b665443f473c72eaa2 Mon Sep 17 00:00:00 2001 From: ZakariaElbouzkri Date: Mon, 11 Nov 2024 11:55:22 +0100 Subject: [PATCH 2/4] feat: Add DJANGO_SECRET_KEY to environment variables This commit adds the `DJANGO_SECRET_KEY` environment variable to the `.env.example` file and updates the necessary files to use this variable instead of the previous `SECRET_KEY` variable. This change improves the security of the Django application by using a more specific and unique key for cryptographic operations. --- .env.example | 3 +-- docker-compose.yml | 1 + srcs/api/config/django/base.py | 2 +- srcs/api/config/env.py | 2 +- srcs/api/config/settings/simplejwt.py | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index 928861c..8069162 100644 --- a/.env.example +++ b/.env.example @@ -5,8 +5,7 @@ POSTGRES_DB='postgres_db' POSTGRES_USER='postgres_user' # django superuser credentials - +DJANGO_SECRET_KEY='django_secret_key' DJANGO_SUPERUSER_USERNAME='django_admin_user' DJANGO_SUPERUSER_EMAIL='django_admin_email' DJANGO_SUPERUSER_PASSWORD='django_admin_password' - diff --git a/docker-compose.yml b/docker-compose.yml index cad9dbd..c8a5b1f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,6 +36,7 @@ services: DJANGO_SUPERUSER_USERNAME: ${DJANGO_SUPERUSER_USERNAME} DJANGO_SUPERUSER_EMAIL: ${DJANGO_SUPERUSER_EMAIL} DJANGO_SUPERUSER_PASSWORD: ${DJANGO_SUPERUSER_PASSWORD} + DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY} volumes: diff --git a/srcs/api/config/django/base.py b/srcs/api/config/django/base.py index 407ea3d..ba5552a 100644 --- a/srcs/api/config/django/base.py +++ b/srcs/api/config/django/base.py @@ -1,7 +1,7 @@ from config.env import BASE_DIR, env # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = env('SECRET_KEY') +SECRET_KEY = env('DJANGO_SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = env.bool('DEBUG', default=True) diff --git a/srcs/api/config/env.py b/srcs/api/config/env.py index 109dff9..eb9d4b1 100644 --- a/srcs/api/config/env.py +++ b/srcs/api/config/env.py @@ -6,4 +6,4 @@ env = environ.Env() -environ.Env.read_env(BASE_DIR / '.env') +# environ.Env.read_env(BASE_DIR / '.env') diff --git a/srcs/api/config/settings/simplejwt.py b/srcs/api/config/settings/simplejwt.py index 8fc435e..fa72310 100644 --- a/srcs/api/config/settings/simplejwt.py +++ b/srcs/api/config/settings/simplejwt.py @@ -9,7 +9,7 @@ "UPDATE_LAST_LOGIN": True, "ALGORITHM": "HS256", - "SIGNING_KEY": env('SECRET_KEY'), + "SIGNING_KEY": env('DJANGO_SECRET_KEY'), "VERIFYING_KEY": "", "AUDIENCE": None, "ISSUER": None, @@ -39,4 +39,4 @@ "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer", "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer", "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", -} \ No newline at end of file +} From 6eb7e3b8266c98acf31a8d9f5a4d6dd3c66db2f2 Mon Sep 17 00:00:00 2001 From: Fahd Date: Wed, 13 Nov 2024 11:33:51 +0100 Subject: [PATCH 3/4] Revert "Adding ELK stack and solving some frontend errors" --- .env.example | 30 ++---- .gitignore | 1 - ELK/docker-compose.yml | 91 ------------------- ELK/elasticsearch/config/elasticsearch.yml | 8 -- ELK/kibana/config/kibana.yml | 7 -- ELK/logstash/config/logstash.yml | 5 - ELK/logstash/pipeline/logstash.conf | 36 -------- ELK/tools/init-kibana.sh | 16 ---- Makefile | 23 +---- docker-compose.yml | 45 +++------ srcs/api/.dockerignore | 3 - srcs/api/Dockerfile | 2 +- srcs/api/apps/users/views.py | 4 +- srcs/api/apps/utils/validators.py | 3 - srcs/api/config/django/base.py | 12 +-- srcs/api/config/settings/logstash.py | 41 --------- srcs/api/requirements.txt | 27 +----- srcs/frontend/src/app/auth/signin/page.tsx | 32 +++---- srcs/frontend/src/app/auth/signup/page.tsx | 4 +- srcs/frontend/src/app/users/logout/page.tsx | 9 +- .../ChangeFirstname/ChangeFirstname.tsx | 3 - .../ChangeFirstname/change.module.css | 1 - .../Settings/ChangeImage/ImageUpload.tsx | 5 +- .../ChangeLastname/ChangeLastname.tsx | 3 - .../Settings/ChangeLastname/change.module.css | 1 - .../ChangePassword/ChangePassword.tsx | 3 - .../Settings/ChangePassword/change.module.css | 1 - .../Settings/ChangeTFA/ChangeTFA.tsx | 14 +-- .../Settings/ChangeTFA/change.module.css | 2 +- .../ChangeUsername/ChangeUsername.tsx | 3 - .../ChangeUsername/changeUsername.module.css | 1 - .../VerticalNavbar/VerticalNavbar.tsx | 41 --------- 32 files changed, 49 insertions(+), 428 deletions(-) delete mode 100644 ELK/docker-compose.yml delete mode 100644 ELK/elasticsearch/config/elasticsearch.yml delete mode 100644 ELK/kibana/config/kibana.yml delete mode 100644 ELK/logstash/config/logstash.yml delete mode 100644 ELK/logstash/pipeline/logstash.conf delete mode 100755 ELK/tools/init-kibana.sh delete mode 100644 srcs/api/config/settings/logstash.py diff --git a/.env.example b/.env.example index 2d6ab02..8069162 100644 --- a/.env.example +++ b/.env.example @@ -1,23 +1,11 @@ -DJANGO_SECRET_KEY='django-insecure-(fffc75h_s6tm=%7a&r8vc2lf7*0q+w2k+=*g=@82nube9s*a-' -DEBUG=True +# postgres credentials -FORTYTWO_CLIENT_ID='u-s4t2ud-ab8fff39c8779f781296f279fd71d49a1ae34cb59003ad44bb0dc94d475ceffc' -FORTYTWO_CLIENT_SECRET='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' -FORTYTWO_REDIRECT_URI='http://localhost:4444' +POSTGRES_PASSWORD='postgres_password' +POSTGRES_DB='postgres_db' +POSTGRES_USER='postgres_user' -# google social_auth -GOOGLE_CLIENT_ID='GOOGLE_CLIENT_ID' -GOOGLE_REDIRECT_URI='GOOGLE_REDIRECT_URI' - - -# github social_auth -GITHUB_CLIENT_ID='GITHUB_CLIENT_ID' -GITHUB_REDIRECT_URI='GITHUB_REDIRECT_URI' - -POSTGRES_USER="postgres" -POSTGRES_PASSWORD="A9wadPassW0rd/" -POSTGRES_DB="db" -DATABASE_URL="postgres://postgres:A9wadPassW0rd/@db:5432/db" - -LOGSTASH_HOST="logstash" -LOGSTASH_PORT="50000" +# django superuser credentials +DJANGO_SECRET_KEY='django_secret_key' +DJANGO_SUPERUSER_USERNAME='django_admin_user' +DJANGO_SUPERUSER_EMAIL='django_admin_email' +DJANGO_SUPERUSER_PASSWORD='django_admin_password' diff --git a/.gitignore b/.gitignore index a086576..af1d51b 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,3 @@ htmlcov/ # Migrations **/migrations/* !**/migrations/__init__.py -*todo* \ No newline at end of file diff --git a/ELK/docker-compose.yml b/ELK/docker-compose.yml deleted file mode 100644 index 29ed744..0000000 --- a/ELK/docker-compose.yml +++ /dev/null @@ -1,91 +0,0 @@ -version: '3' - -services: - elasticsearch: - container_name: elasticsearch - image: docker.elastic.co/elasticsearch/elasticsearch:8.10.1 - environment: - - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - - KIBANA_SYSTEM_PASSWORD=${KIBANA_PASSWORD} - - discovery.type=single-node - - xpack.security.enabled=true - - ELASTIC_USERNAME=elastic - - ES_JAVA_OPTS=-Xms1g -Xmx1g - healthcheck: - test: ["CMD-SHELL", "curl -s -u elastic:lol123 http://localhost:9200/_cat/health >/dev/null || exit 1"] - interval: 30s - timeout: 30s - retries: 3 - start_period: 60s - volumes: - - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml - - es_data:/usr/share/elasticsearch/data - ports: - - "9200:9200" - - "9300:9300" - networks: - - elk - restart: always - - setup_kibana: - image: curlimages/curl:latest - volumes: - - ./tools/init-kibana.sh:/init-kibana.sh - command: ["sh", "/init-kibana.sh"] - networks: - - elk - env_file: - - .env - depends_on: - elasticsearch: - condition: service_healthy - - logstash: - container_name: logstash - image: docker.elastic.co/logstash/logstash:8.10.1 - volumes: - - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml - - ./logstash/pipeline:/usr/share/logstash/pipeline - ports: - - "50000:50000" - - "9600:9600" - env_file: - - .env - environment: - - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} - - ELASTICSEARCH_USERNAME=elastic - - ELASTICSEARCH_PASSWORD=${ELASTIC_PASSWORD} - - LS_JAVA_OPTS=-Xms256m -Xmx256m - networks: - - elk - depends_on: - elasticsearch: - condition: service_healthy - - kibana: - container_name: kibana - image: docker.elastic.co/kibana/kibana:8.10.1 - depends_on: - setup_kibana: - condition: service_completed_successfully - environment: - - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 - - ELASTICSEARCH_USERNAME=kibana_system - - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} - - ELASTICSEARCH_SSL_VERIFICATIONMODE=none - volumes: - - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml - ports: - - "5601:5601" - networks: - - elk - -volumes: - es_data: - driver: local - -networks: - elk: - external: true - name: elk_net - # driver: bridge diff --git a/ELK/elasticsearch/config/elasticsearch.yml b/ELK/elasticsearch/config/elasticsearch.yml deleted file mode 100644 index d567d34..0000000 --- a/ELK/elasticsearch/config/elasticsearch.yml +++ /dev/null @@ -1,8 +0,0 @@ -cluster.name: "docker-cluster" -network.host: 0.0.0.0 -discovery.type: single-node -xpack.security.enabled: true -xpack.security.authc.api_key.enabled: true - -# Add these memory settings -bootstrap.memory_lock: true \ No newline at end of file diff --git a/ELK/kibana/config/kibana.yml b/ELK/kibana/config/kibana.yml deleted file mode 100644 index b3e09cb..0000000 --- a/ELK/kibana/config/kibana.yml +++ /dev/null @@ -1,7 +0,0 @@ -server.host: "0.0.0.0" -elasticsearch.hosts: ["http://elasticsearch:9200"] -elasticsearch.username: "kibana_system" -elasticsearch.password: "lil123" -elasticsearch.ssl.verificationMode: none -xpack.security.enabled: true -xpack.reporting.roles.enabled: false \ No newline at end of file diff --git a/ELK/logstash/config/logstash.yml b/ELK/logstash/config/logstash.yml deleted file mode 100644 index 69dd8bc..0000000 --- a/ELK/logstash/config/logstash.yml +++ /dev/null @@ -1,5 +0,0 @@ -http.host: "0.0.0.0" -xpack.monitoring.elasticsearch.hosts: ["http://elasticsearch:9200"] -xpack.monitoring.elasticsearch.username: "elastic" -xpack.monitoring.elasticsearch.password: "lol123" -xpack.monitoring.enabled: true \ No newline at end of file diff --git a/ELK/logstash/pipeline/logstash.conf b/ELK/logstash/pipeline/logstash.conf deleted file mode 100644 index 99a3183..0000000 --- a/ELK/logstash/pipeline/logstash.conf +++ /dev/null @@ -1,36 +0,0 @@ -input { - tcp { - port => 50000 - codec => json - type => "django" - } -} - -filter { - if [type] == "django" { - # Lowercase the level field and rename it to match the standard 'level' in Elasticsearch - mutate { - lowercase => ["levelname"] # Convert 'levelname' to lowercase - rename => { "levelname" => "level" } # Rename for consistent index field name - } - - # Parse the timestamp from Django to ensure it's used as @timestamp in Elasticsearch - date { - match => ["asctime", "YYYY-MM-dd HH:mm:ss"] - target => "@timestamp" - remove_field => ["asctime"] # Clean up to avoid duplicate timestamp fields - } - } -} - -output { - elasticsearch { - hosts => ["elasticsearch:9200"] - index => "django-logs-%{+YYYY.MM.dd}" # Adjusted to only include date in the index - user => "elastic" # Use environment variables for security - password => "${ELASTIC_PASSWORD}" - } - stdout { - codec => rubydebug - } -} diff --git a/ELK/tools/init-kibana.sh b/ELK/tools/init-kibana.sh deleted file mode 100755 index 8034d98..0000000 --- a/ELK/tools/init-kibana.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -echo "Waiting for Elasticsearch to be ready..." -while true; do - if curl -s elasticsearch:9200 >/dev/null; then - break - fi - sleep 5 -done - -echo "Setting up kibana_system user..." -# echo "${ELASTIC_PASSWORD} ${KIBANA_PASSWORD}" -curl -X POST -u elastic:${ELASTIC_PASSWORD} "elasticsearch:9200/_security/user/kibana_system/_password" -H "Content-Type: application/json" -d" -{ - \"password\": \"${KIBANA_PASSWORD}\" -}" \ No newline at end of file diff --git a/Makefile b/Makefile index 40b61ed..9935db8 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,8 @@ images=$(shell docker image ls -aq) -elk_net=$(shell docker network ls -qf name="elk_net") - all: build -create_net: - if [ -n "$(elk_net)" ];\ - then echo "Network elk_net already exists";\ - else\ - docker network create elk_net;\ - fi - -build: create_net +build: docker-compose -f docker-compose.yml build up: build @@ -20,12 +11,6 @@ up: build down: docker-compose -f docker-compose.yml down -ELK: create_net - docker-compose -f ./ELK/docker-compose.yml up - -ELK_down: - docker-compose -f ./ELK/docker-compose.yml down - delete_images: if [ -n "$(images)" ];\ then docker rmi $(images);\ @@ -33,9 +18,9 @@ delete_images: echo "No images to delete";\ fi -fclean: down ELK_down delete_images +fclean: down delete_images docker system prune -a --force -.PHONY: all build up down delete_images fclean ELK ELK_down create_net +.PHONY: all build up down delete_images fclean -.SILENT: all build up down delete_images fclean create_net ELK ELK_down +.SILENT: all build up down delete_images fclean diff --git a/docker-compose.yml b/docker-compose.yml index 5dbdc91..c8a5b1f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,12 +9,10 @@ services: networks: - transcendance_net restart: always - env_file: - - .env.example - # environment: - # POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - # POSTGRES_DB: ${POSTGRES_DB} - # POSTGRES_USER: ${POSTGRES_USER} + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} backend: @@ -23,37 +21,23 @@ services: build: context: ./srcs/api/ volumes: - - ./srcs/api/:/var/www/ + - backend_files:/var/www/ networks: - transcendance_net - - elk_net ports: - 8000:8000 depends_on: - pgdb - env_file: - - .env.example restart: on-failure - # environment: - # DEBUG: True # ['True', 'False'] - # DJANGO_SETTING_MODULE: config.django.local - # DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@pgdb:5432/${POSTGRES_DB} - # DJANGO_SUPERUSER_USERNAME: ${DJANGO_SUPERUSER_USERNAME} - # DJANGO_SUPERUSER_EMAIL: ${DJANGO_SUPERUSER_EMAIL} - # DJANGO_SUPERUSER_PASSWORD: ${DJANGO_SUPERUSER_PASSWORD} + environment: + DEBUG: True # ['True', 'False'] + DJANGO_SETTING_MODULE: config.django.local + DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@pgdb:5432/${POSTGRES_DB} + DJANGO_SUPERUSER_USERNAME: ${DJANGO_SUPERUSER_USERNAME} + DJANGO_SUPERUSER_EMAIL: ${DJANGO_SUPERUSER_EMAIL} + DJANGO_SUPERUSER_PASSWORD: ${DJANGO_SUPERUSER_PASSWORD} + DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY} - frontend: - build: ./srcs/frontend - container_name: nextJs - ports: - - "3000:3000" # Map host port 3000 to container port 3000 - volumes: - - ./srcs/frontend/src/:/app/src/ - depends_on: - - backend - networks: - - transcendance_net - restart: on-failure volumes: postgres_data: @@ -66,6 +50,3 @@ volumes: networks: transcendance_net: - elk_net: - external: true - name: elk_net diff --git a/srcs/api/.dockerignore b/srcs/api/.dockerignore index 2e1304b..e69de29 100644 --- a/srcs/api/.dockerignore +++ b/srcs/api/.dockerignore @@ -1,3 +0,0 @@ -db.sqlite3 -*__pycache__/ -*.pyc diff --git a/srcs/api/Dockerfile b/srcs/api/Dockerfile index 80b9187..52ed666 100644 --- a/srcs/api/Dockerfile +++ b/srcs/api/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12-slim-bullseye +FROM python:3.11-slim-bullseye # Set the working directory in the container WORKDIR /var/www/ diff --git a/srcs/api/apps/users/views.py b/srcs/api/apps/users/views.py index f2e9cfe..757a5da 100644 --- a/srcs/api/apps/users/views.py +++ b/srcs/api/apps/users/views.py @@ -1,5 +1,5 @@ from rest_framework import generics, filters -from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.permissions import AllowAny from .models import User from rest_framework.response import Response @@ -7,8 +7,6 @@ class AuthUserView(generics.RetrieveUpdateDestroyAPIView): - permission_classes = [IsAuthenticated] - def get_serializer_class(self): if self.request.method in ['PUT', 'PATCH']: return serializers.UpdateAuthUserSerializer diff --git a/srcs/api/apps/utils/validators.py b/srcs/api/apps/utils/validators.py index 54db162..d68b399 100644 --- a/srcs/api/apps/utils/validators.py +++ b/srcs/api/apps/utils/validators.py @@ -1,7 +1,6 @@ from django.contrib.auth import get_user_model from rest_framework import serializers import re -from django.contrib.auth import get_user_model User = get_user_model() @@ -47,8 +46,6 @@ def __call__(self, value): if any(bad in value for bad in ["__", "--", "_-", "-_"]): errors.append("Username cannot contain consecutive special characters like '__', '_-', or similar.") reserved_usernames = ['admin', 'root', 'superuser'] - if get_user_model().objects.filter(username=value).exists(): - errors.append("A user with that username already exists.") if value.lower() in reserved_usernames: errors.append("This username is reserved and cannot be used.") if errors: diff --git a/srcs/api/config/django/base.py b/srcs/api/config/django/base.py index 66faade..ba5552a 100644 --- a/srcs/api/config/django/base.py +++ b/srcs/api/config/django/base.py @@ -1,5 +1,4 @@ from config.env import BASE_DIR, env -import os # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = env('DJANGO_SECRET_KEY') @@ -9,6 +8,7 @@ ALLOWED_HOSTS = [] + # Application definition INSTALLED_APPS = [ @@ -28,7 +28,7 @@ 'rest_framework_simplejwt.token_blacklist', 'drf_spectacular', 'channels', - 'corsheaders', + 'corsheaders' ] # local apps @@ -40,7 +40,6 @@ ]] MIDDLEWARE = [ - 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -51,12 +50,6 @@ 'apps.authentication.middleware.JWTAuthenticationMiddleware', ] -CORS_ALLOW_CREDENTIALS = True - -CORS_ALLOWED_ORIGINS = [ - "http://localhost:3000", -] - ROOT_URLCONF = 'config.urls' TEMPLATES = [ @@ -136,4 +129,3 @@ from config.settings.rest_framework import * from config.settings.simplejwt import * from config.settings.drf_spectacular import * -from config.settings.logstash import * diff --git a/srcs/api/config/settings/logstash.py b/srcs/api/config/settings/logstash.py deleted file mode 100644 index 3eb4933..0000000 --- a/srcs/api/config/settings/logstash.py +++ /dev/null @@ -1,41 +0,0 @@ -import logstash -from pythonjsonlogger import jsonlogger -from config.env import env - -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'logstash': { - '()': 'logstash.formatter.LogstashFormatterVersion1', - }, - 'simple': { - 'format': '[%(asctime)s][%(levelname)s][%(name)s] %(message)s ' - }, - }, - 'handlers': { - 'logstash': { - 'level': 'INFO', - 'class': 'logstash.TCPLogstashHandler', - 'host': env('LOGSTASH_HOST', default='logstash'), - 'port': env.int('LOGSTASH_PORT', default=50000), - 'version': 1, - 'message_type': 'django', - 'fqdn': False, - 'tags': ['django'], - 'formatter': 'logstash', - }, - 'console': { - # 'level': 'DEBUG', - 'class': 'logging.StreamHandler', - 'formatter': 'simple', - }, - }, - 'loggers': { - 'django': { - 'handlers': ['logstash', 'console'], - # 'level': 'INFO', - 'propagate': True, - }, - } -} \ No newline at end of file diff --git a/srcs/api/requirements.txt b/srcs/api/requirements.txt index 0671166..5b66ccc 100644 --- a/srcs/api/requirements.txt +++ b/srcs/api/requirements.txt @@ -5,6 +5,7 @@ Automat==24.8.1 certifi==2024.8.30 cffi==1.17.1 channels==4.1.0 +charset-normalizer==3.3.2 constantly==23.10.4 cryptography==43.0.1 daphne==4.1.2 @@ -35,7 +36,7 @@ referencing==0.35.1 requests==2.32.3 rpds-py==0.20.0 service-identity==24.1.0 - +setuptools==75.1.0 sqlparse==0.5.1 Twisted==24.7.0 txaio==23.1.1 @@ -43,27 +44,3 @@ typing_extensions==4.12.2 uritemplate==4.1.1 urllib3==2.2.3 zope.interface==7.1.0 -certifi==2024.8.30 -django-elasticsearch-dsl==8.0 -elastic-transport==8.15.1 -elasticsearch>=8.0.0,<9.0.0 -elasticsearch-dsl>=8.9.0,<9.0.0 -python-dateutil==2.9.0.post0 - -charset-normalizer==3.4.0 -Deprecated==1.2.14 -idna==3.10 -importlib_resources==6.4.5 -limits==3.13.0 -packaging==24.1 -pylogbeat==2.0.1 -python-logstash==0.4.8 -requests==2.32.3 -six==1.16.0 -python-dateutil==2.9.0.post0 -python-json-logger==2.0.7 -# logstash==0.1.dev0 -wheel==0.44.0 -wrapt==1.16.0 -setuptools==75.2.0 -logstash_formatter==0.5.17 \ No newline at end of file diff --git a/srcs/frontend/src/app/auth/signin/page.tsx b/srcs/frontend/src/app/auth/signin/page.tsx index f9e844d..26080bb 100644 --- a/srcs/frontend/src/app/auth/signin/page.tsx +++ b/srcs/frontend/src/app/auth/signin/page.tsx @@ -48,28 +48,18 @@ const SignInPage: React.FC = () => { setIsLoading(true); try { - const res = await axios.post("http://localhost:8000/api/auth/sign-in/", { - "username": formData.username, - "password": formData.password, - }, { - withCredentials: true, - }).catch(err => { - console.error("Sign-in error:", err); + await axios.post("http://localhost:8000/api/auth/sign-in/", formData,{withCredentials: true}); + + router.push("/users/home"); + } catch (err: any) { + console.log("there is some errors"); + console.error("Error:", err.response); + setErrors({ + details: "Username or password is not correct", + username: err.response?.data?.username?.[0] || "", + password: err.response?.data?.password?.[0] || "", + otp: err.response?.data?.otp_code?.[0] || "", }); - - if (res.status === 200) { // Check if the response is OK - router.push("/users/home"); - setIsLoading(false); - } - } catch (err) { - console.error("test"); - console.error("Error response:", err.response); - setErrors(() => ({ - details: "username of password is not correct", - username: err.response?.data?.username ? err.response.data.username[0] : "", - password: err.response?.data?.password ? err.response.data.password[0] : "", - otp: err.response?.data?.otp_code[0] ? err.response?.data?.otp_code[0] : "", - })); setIsLoading(false); } finally { } diff --git a/srcs/frontend/src/app/auth/signup/page.tsx b/srcs/frontend/src/app/auth/signup/page.tsx index 26c538e..a0b3643 100644 --- a/srcs/frontend/src/app/auth/signup/page.tsx +++ b/srcs/frontend/src/app/auth/signup/page.tsx @@ -84,9 +84,7 @@ const SignUpPage: React.FC = () => { email: formData.email, first_name: formData.firstname, last_name: formData.lastname - }, - {withCredentials: true}, - ); + }); setIsSuccess(true); } catch (err: any) { console.error("Error:", err.response?.data); diff --git a/srcs/frontend/src/app/users/logout/page.tsx b/srcs/frontend/src/app/users/logout/page.tsx index 4d0f971..0723e64 100644 --- a/srcs/frontend/src/app/users/logout/page.tsx +++ b/srcs/frontend/src/app/users/logout/page.tsx @@ -38,14 +38,7 @@ const Logout: React.FC = () => { deleteAllCookies(); // Call the sign-out API - await axios.post("http://localhost:8000/api/auth/sign-out/", - {}, - { - withCredentials: true, - } - ).catch(err => { - console.error("Sign-in error:", err); - }); + await axios.post("http://localhost:8000/api/auth/sign-out/"); router.push('/auth/signin'); } catch (error) { diff --git a/srcs/frontend/src/components/Settings/ChangeFirstname/ChangeFirstname.tsx b/srcs/frontend/src/components/Settings/ChangeFirstname/ChangeFirstname.tsx index c7de982..e952a40 100644 --- a/srcs/frontend/src/components/Settings/ChangeFirstname/ChangeFirstname.tsx +++ b/srcs/frontend/src/components/Settings/ChangeFirstname/ChangeFirstname.tsx @@ -38,9 +38,6 @@ const ChangeFirstname: React.FC = ({ setCurrentPage }) => const res = await axios.patch( "http://localhost:8000/api/users/me/", { first_name: newFirstName }, - { - withCredentials: true, - } ); console.log(res.data); updateUserData({ ...userData, first_name: newFirstName }); diff --git a/srcs/frontend/src/components/Settings/ChangeFirstname/change.module.css b/srcs/frontend/src/components/Settings/ChangeFirstname/change.module.css index 0966e81..1d7fb21 100644 --- a/srcs/frontend/src/components/Settings/ChangeFirstname/change.module.css +++ b/srcs/frontend/src/components/Settings/ChangeFirstname/change.module.css @@ -64,7 +64,6 @@ background-color: transparent; border: 1px solid black; width: 100%; - color: black; transition: background-color 0.5s ease, transform 0.5s ease; &:focus { transform: scale(1.025);; diff --git a/srcs/frontend/src/components/Settings/ChangeImage/ImageUpload.tsx b/srcs/frontend/src/components/Settings/ChangeImage/ImageUpload.tsx index 7e6c4be..27f3877 100644 --- a/srcs/frontend/src/components/Settings/ChangeImage/ImageUpload.tsx +++ b/srcs/frontend/src/components/Settings/ChangeImage/ImageUpload.tsx @@ -24,9 +24,7 @@ const ImageUpload: React.FC = ({ setCurrentPage }) => { useEffect(() => { const fetchData = async () => { try { - const res = await axios.get("http://localhost:8000/api/users/me/", { - withCredentials: true - }); + const res = await axios.get("http://localhost:8000/api/users/me/"); console.log(res.data.avatar_url); setNewImage(res.data.avatar_url || "https://res.cloudinary.com/doufu6atn/image/upload/v1726742774/nxdrt0md7buyeghyjyvj.png"); } catch (err: any) { @@ -105,7 +103,6 @@ const ImageUpload: React.FC = ({ setCurrentPage }) => { Authorization: `Bearer ${localStorage.getItem("access")}`, "Content-Type": "application/json", }, - withCredentials: true, } ); console.log(res.data); diff --git a/srcs/frontend/src/components/Settings/ChangeLastname/ChangeLastname.tsx b/srcs/frontend/src/components/Settings/ChangeLastname/ChangeLastname.tsx index a4778b0..ad56c43 100644 --- a/srcs/frontend/src/components/Settings/ChangeLastname/ChangeLastname.tsx +++ b/srcs/frontend/src/components/Settings/ChangeLastname/ChangeLastname.tsx @@ -36,9 +36,6 @@ const ChangeLastname: React.FC = ({ setCurrentPage }) => { const res = await axios.patch( "http://localhost:8000/api/users/me/", { last_name: newLastName }, - { - withCredentials: true, - } ); console.log(res.data); updateUserData({ ...userData, last_name: newLastName }); diff --git a/srcs/frontend/src/components/Settings/ChangeLastname/change.module.css b/srcs/frontend/src/components/Settings/ChangeLastname/change.module.css index 2e52cf4..1d7fb21 100644 --- a/srcs/frontend/src/components/Settings/ChangeLastname/change.module.css +++ b/srcs/frontend/src/components/Settings/ChangeLastname/change.module.css @@ -65,7 +65,6 @@ border: 1px solid black; width: 100%; transition: background-color 0.5s ease, transform 0.5s ease; - color: black; &:focus { transform: scale(1.025);; } diff --git a/srcs/frontend/src/components/Settings/ChangePassword/ChangePassword.tsx b/srcs/frontend/src/components/Settings/ChangePassword/ChangePassword.tsx index a33d4d6..ce854fe 100644 --- a/srcs/frontend/src/components/Settings/ChangePassword/ChangePassword.tsx +++ b/srcs/frontend/src/components/Settings/ChangePassword/ChangePassword.tsx @@ -36,9 +36,6 @@ const ChangePassword: React.FC = ({ setCurrentPage }) => { const res = await axios.patch( "http://localhost:8000/api/users/me/", { password: newPassword }, - { - withCredentials: true, - } ); console.log(res.data); updateUserData({ ...userData, password: newPassword }); diff --git a/srcs/frontend/src/components/Settings/ChangePassword/change.module.css b/srcs/frontend/src/components/Settings/ChangePassword/change.module.css index 2e52cf4..1d7fb21 100644 --- a/srcs/frontend/src/components/Settings/ChangePassword/change.module.css +++ b/srcs/frontend/src/components/Settings/ChangePassword/change.module.css @@ -65,7 +65,6 @@ border: 1px solid black; width: 100%; transition: background-color 0.5s ease, transform 0.5s ease; - color: black; &:focus { transform: scale(1.025);; } diff --git a/srcs/frontend/src/components/Settings/ChangeTFA/ChangeTFA.tsx b/srcs/frontend/src/components/Settings/ChangeTFA/ChangeTFA.tsx index 83076d1..dcc1787 100644 --- a/srcs/frontend/src/components/Settings/ChangeTFA/ChangeTFA.tsx +++ b/srcs/frontend/src/components/Settings/ChangeTFA/ChangeTFA.tsx @@ -22,9 +22,7 @@ const ChangeTFA: React.FC = ({ setCurrentPage }) => { const fetchData = async () => { setIsloading(true); try { - const res = await axios.get("http://localhost:8000/api/users/me/", { - withCredentials: true - }); + const res = await axios.get("http://localhost:8000/api/users/me/"); setBoolIsActive(res.data.two_fa_enabled); setToggleActive(res.data.two_fa_enabled); } catch (err: any) { @@ -40,9 +38,7 @@ const ChangeTFA: React.FC = ({ setCurrentPage }) => { setIsloading(true); setToggleActive(!toggleActive); try { - const res = await axios.get("http://localhost:8000/api/users/me/", { - withCredentials: true - }); + const res = await axios.get("http://localhost:8000/api/users/me/"); setCode(res.data.otp_uri); } catch (err: any) { console.log("Error in fetching OTP URI", err); @@ -56,9 +52,6 @@ const ChangeTFA: React.FC = ({ setCurrentPage }) => { try { const res = await axios.post("http://localhost:8000/api/auth/2fa/enable/", { "otp_code": inputCode, - }, - { - withCredentials: true }); // Navigate back after success @@ -72,9 +65,6 @@ const ChangeTFA: React.FC = ({ setCurrentPage }) => { const res = await axios.patch( "http://localhost:8000/api/users/me/", { last_name: newLastName }, - { - withCredentials: true, - } ); console.log(res.data); updateUserData({ ...userData, last_name: newLastName }); diff --git a/srcs/frontend/src/components/Settings/ChangeTFA/change.module.css b/srcs/frontend/src/components/Settings/ChangeTFA/change.module.css index e34fece..2b924ae 100644 --- a/srcs/frontend/src/components/Settings/ChangeTFA/change.module.css +++ b/srcs/frontend/src/components/Settings/ChangeTFA/change.module.css @@ -103,7 +103,7 @@ font-size: 16px; width: 100%; transition: transform 0.3s ease, background-color 0.3s ease; - color: black; + &:focus { background-color: #f0f0f0; transform: scale(1.02); diff --git a/srcs/frontend/src/components/Settings/ChangeUsername/ChangeUsername.tsx b/srcs/frontend/src/components/Settings/ChangeUsername/ChangeUsername.tsx index 61deb69..bc514be 100644 --- a/srcs/frontend/src/components/Settings/ChangeUsername/ChangeUsername.tsx +++ b/srcs/frontend/src/components/Settings/ChangeUsername/ChangeUsername.tsx @@ -38,9 +38,6 @@ const ChangeUsername: React.FC = ({ setCurrentPage }) => { const res = await axios.patch( "http://localhost:8000/api/users/me/", { username: newUsername }, - { - withCredentials: true, - } ); console.log(res.data); updateUserData({ ...userData, username: newUsername }); diff --git a/srcs/frontend/src/components/Settings/ChangeUsername/changeUsername.module.css b/srcs/frontend/src/components/Settings/ChangeUsername/changeUsername.module.css index 3baea57..694b632 100644 --- a/srcs/frontend/src/components/Settings/ChangeUsername/changeUsername.module.css +++ b/srcs/frontend/src/components/Settings/ChangeUsername/changeUsername.module.css @@ -65,7 +65,6 @@ border: 1px solid black; width: 100%; transition: background-color 0.5s ease, transform 0.5s ease; - color: black; &:focus { transform: scale(1.025);; } diff --git a/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx b/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx index 2ac204d..2ba7774 100644 --- a/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx +++ b/srcs/frontend/src/components/VerticalNavbar/VerticalNavbar.tsx @@ -36,47 +36,6 @@ const VerticalNavbar = () => { updateCurrentPage(page); }; - useEffect(() => { - - const fetchData = async () =>{ - try { - const res = await axios.get("http://localhost:8000/api/users/me/", { - withCredentials: true - }); - console.log("res"); - console.log(res.data); - updateUserData({ - id: res.data.id, - otp_uri: res.data.otp_uri, - last_login: res.data.last_login, - is_superuser: res.data.is_superuser, - username: res.data.username, - first_name: res.data.first_name, - last_name: res.data.last_name, - email: res.data.email, - is_staff: res.data.is_staff, - is_active: res.data.is_active, - date_joined: res.data.date_joined, - two_fa_enabled: res.data.two_fa_enabled, - is_online: res.data.is_online, - avatar_url: res.data.avatar_url , - wins: res.data.wins, - loses: res.data.loses, - rating: res.data.rating, - }) - - - } catch (err) { - console.log("test"); - } - } - - fetchData(); - }, []); - - - - return (