From 9da939c66f5f6a776f92699320f47702aa63bee5 Mon Sep 17 00:00:00 2001 From: slawk0 Date: Thu, 2 Jan 2025 23:38:04 +0100 Subject: [PATCH] fixed authorization --- client/src/App.tsx | 30 +++++------ .../chat/chatArea/AnimatedMessage.tsx | 10 ++-- .../components/chat/chatArea/MessageForm.tsx | 6 +++ .../components/chat/chatArea/MessagesArea.tsx | 20 +++++--- .../chat/leftSidebar/LastActiveTime.tsx | 3 ++ .../chat/leftSidebar/UserProfile.tsx | 8 +-- .../chat/rightSidebar/ParticipantsBar.tsx | 12 ++--- client/src/pages/Login.tsx | 4 +- client/src/pages/Signup.tsx | 4 +- client/src/utils/AuthContext.tsx | 16 ------ client/src/utils/AuthProvider.tsx | 51 ++++++++++--------- client/src/utils/ProtectedRoutes.tsx | 16 +++--- client/src/utils/PublicRoute.tsx | 9 ++-- client/src/utils/useAuth.tsx | 4 -- 14 files changed, 92 insertions(+), 101 deletions(-) delete mode 100644 client/src/utils/AuthContext.tsx delete mode 100644 client/src/utils/useAuth.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 3037371..e5afd55 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,19 +1,17 @@ import { + RouterProvider, createBrowserRouter, Navigate, - RouterProvider, } from 'react-router-dom'; -import { Suspense } from 'react'; -import Chat from './pages/Chat'; -import Login from './pages/Login'; -import Signup from './pages/Signup'; -import Settings from './pages/Settings'; -import Lost from './pages/404'; -import { AuthProvider } from '@/utils/AuthProvider.tsx'; -import ProtectedRoutes from './utils/ProtectedRoutes'; -import PublicRoute from './utils/PublicRoute'; -import { ChatProvider } from './context/chat/ChatProvider'; -import LoadingScreen from './components/LoadingScreen'; +import Chat from './pages/Chat.tsx'; +import Login from './pages/Login.tsx'; +import Signup from './pages/Signup.tsx'; +import Settings from './pages/Settings.tsx'; +import Lost from './pages/404.tsx'; +import { AuthProvider } from './utils/AuthProvider.tsx'; +import ProtectedRoutes from './utils/ProtectedRoutes.tsx'; +import { ChatProvider } from '@/context/chat/ChatProvider.tsx'; +import PublicRoute from '@/utils/PublicRoute.tsx'; const router = createBrowserRouter([ { @@ -26,11 +24,9 @@ const router = createBrowserRouter([ { path: '/chat', element: ( - }> - - - - + + + ), }, { diff --git a/client/src/components/chat/chatArea/AnimatedMessage.tsx b/client/src/components/chat/chatArea/AnimatedMessage.tsx index ae21ef6..10697dd 100644 --- a/client/src/components/chat/chatArea/AnimatedMessage.tsx +++ b/client/src/components/chat/chatArea/AnimatedMessage.tsx @@ -1,9 +1,9 @@ -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { Trash2 } from 'lucide-react'; import AttachmentPreview from './AttachmentPreview.tsx'; -import { ChatMessagesProps, UserType } from '@/types/types.ts'; -import { useOutletContext } from 'react-router-dom'; +import { ChatMessagesProps } from '@/types/types.ts'; import { useChat } from '@/context/chat/useChat.ts'; +import { AuthContext } from '@/utils/AuthProvider.tsx'; type AnimatedMessageProps = { message: ChatMessagesProps; @@ -11,7 +11,7 @@ type AnimatedMessageProps = { }; const AnimatedMessage = ({ onDelete, message }: AnimatedMessageProps) => { - const user: UserType = useOutletContext(); + const { user } = useContext(AuthContext); const { me, groupOwner } = useChat(); const [isRemoving, setIsRemoving] = useState(false); @@ -51,7 +51,7 @@ const AnimatedMessage = ({ onDelete, message }: AnimatedMessageProps) => { )} {me.isGroupOwner || - message.sender == user.username || + message.sender == user?.username || (me.isGroupAdmin && me.isGroupOwner && message.sender_id !== groupOwner) ? ( diff --git a/client/src/components/chat/chatArea/MessageForm.tsx b/client/src/components/chat/chatArea/MessageForm.tsx index 3a3fe4e..3b1c497 100644 --- a/client/src/components/chat/chatArea/MessageForm.tsx +++ b/client/src/components/chat/chatArea/MessageForm.tsx @@ -100,6 +100,12 @@ const MessageForm = () => { }, ); setIsUploading(false); + console.error(response.data); + if (!response.data) { + setErrorMessage('Failed to upload attachments'); + return console.error('Failed to upload attachments'); + } + return response.data; } catch (e) { setIsUploading(false); diff --git a/client/src/components/chat/chatArea/MessagesArea.tsx b/client/src/components/chat/chatArea/MessagesArea.tsx index 4b62ab0..7315083 100644 --- a/client/src/components/chat/chatArea/MessagesArea.tsx +++ b/client/src/components/chat/chatArea/MessagesArea.tsx @@ -1,11 +1,11 @@ -import { useEffect, useRef, useState } from 'react'; +import { useContext, useEffect, useRef, useState } from 'react'; import { socket } from '@/socket/socket.ts'; -import { useOutletContext } from 'react-router-dom'; import { sendContact } from '@/api/contactsApi.tsx'; import LoadingWheel from '../LoadingWheel.tsx'; import AnimatedMessage from '@/components/chat/chatArea/AnimatedMessage.tsx'; -import { ChatMessagesProps, UserType } from '@/types/types.ts'; +import { ChatMessagesProps } from '@/types/types.ts'; import { useChat } from '@/context/chat/useChat.ts'; +import { AuthContext } from '@/utils/AuthProvider.tsx'; function MessagesArea() { const { @@ -19,7 +19,7 @@ function MessagesArea() { fetchPreviousMessages, } = useChat(); const containerRef = useRef(null); - const user: UserType = useOutletContext(); + const { user } = useContext(AuthContext); const [isLoading, setIsLoading] = useState(false); const [shouldScrollToBottom, setShouldScrollToBottom] = useState(true); const previousMessagesLength = useRef(messages.length); @@ -90,7 +90,7 @@ function MessagesArea() { console.log('Received message: ', msg); if ( msg.conversation_id !== currentContact?.conversation_id && - msg.sender !== user.username + msg.sender !== user?.username ) { setContactsList((prevContacts) => { // Find if contact already exists1 @@ -197,10 +197,10 @@ function MessagesArea() { currentContainer.removeEventListener('scroll', handleScroll); } socket.off('chat message'); + socket.off('delete message'); }; - }, [currentContact, user.username, setContactsList, updateContactStatus]); + }, [currentContact, user?.username, setContactsList, updateContactStatus]); - // Handle auto-scrolling when new messages arrive useEffect(() => { const hasNewMessages = messages.length > previousMessagesLength.current; previousMessagesLength.current = messages.length; @@ -222,7 +222,11 @@ function MessagesArea() {
    {isLoading ? : null} {messages.map((msg: ChatMessagesProps) => ( - + ))}
diff --git a/client/src/components/chat/leftSidebar/LastActiveTime.tsx b/client/src/components/chat/leftSidebar/LastActiveTime.tsx index ccdb93b..79a3ea0 100644 --- a/client/src/components/chat/leftSidebar/LastActiveTime.tsx +++ b/client/src/components/chat/leftSidebar/LastActiveTime.tsx @@ -12,6 +12,9 @@ const LastActiveTime = ({ contact }: LastActiveTimeProps) => { useEffect(() => { const updateTime = () => { + if (!contact?.last_message_time) { + return; + } const lastActiveDate = new Date(contact.last_message_time); const secondsDiff = differenceInSeconds(new Date(), lastActiveDate); diff --git a/client/src/components/chat/leftSidebar/UserProfile.tsx b/client/src/components/chat/leftSidebar/UserProfile.tsx index 9ca1b4f..a96221b 100644 --- a/client/src/components/chat/leftSidebar/UserProfile.tsx +++ b/client/src/components/chat/leftSidebar/UserProfile.tsx @@ -1,11 +1,11 @@ import zdjecie from '../../../../assets/turtleProfileImg3.webp'; import logoutIcon from '../../../../assets/logout.svg'; import Cookies from 'js-cookie'; -import { useOutletContext } from 'react-router-dom'; -import { UserType } from '@/types/types.ts'; +import { useContext } from 'react'; +import { AuthContext } from '@/utils/AuthProvider.tsx'; function UserProfile() { - const user: UserType = useOutletContext(); + const { user } = useContext(AuthContext); function logout() { Cookies.remove('token'); localStorage.removeItem('contact'); @@ -27,7 +27,7 @@ function UserProfile() { />
-

{user.username}

+

{user?.username}

diff --git a/client/src/components/chat/rightSidebar/ParticipantsBar.tsx b/client/src/components/chat/rightSidebar/ParticipantsBar.tsx index fc03777..82c9332 100644 --- a/client/src/components/chat/rightSidebar/ParticipantsBar.tsx +++ b/client/src/components/chat/rightSidebar/ParticipantsBar.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useContext, useEffect, useMemo, useState } from 'react'; import { socket } from '@/socket/socket.ts'; import { Crown, Sword } from 'lucide-react'; import { @@ -7,17 +7,17 @@ import { ContextMenuItem, ContextMenuTrigger, } from '@/components/ui/context-menu.tsx'; -import { useOutletContext } from 'react-router-dom'; import zdjecie from '../../../../assets/turtleProfileImg3.webp'; -import { ParticipantsProps, UserType } from '@/types/types.ts'; +import { ParticipantsProps } from '@/types/types.ts'; import { useChat } from '@/context/chat/useChat.ts'; import { axiosClient } from '@/utils/axiosClient.ts'; +import { AuthContext } from '@/utils/AuthProvider.tsx'; function ParticipantsBar() { const { setMe, initializeContact, setGroupOwner, currentContact, me } = useChat(); const [participants, setParticipants] = useState([]); - const user: UserType = useOutletContext(); + const { user } = useContext(AuthContext); const getParticipants = async () => { try { const response = await axiosClient.get( @@ -90,7 +90,6 @@ function ParticipantsBar() { }; useEffect(() => { - console.error(participants.length, user.id); if (participants.length > 0 && user?.id) { const userIsAdmin = participants.some( (participant) => participant.user_id === user.id && participant.isadmin, @@ -104,7 +103,6 @@ function ParticipantsBar() { ); setGroupOwner(whoIsOwner?.user_id); setMe({ isGroupAdmin: userIsAdmin, isGroupOwner: userIsOwner }); - console.error('SETME: ', userIsAdmin, userIsOwner); } }, [participants, user?.id]); @@ -256,7 +254,7 @@ function ParticipantsBar() { - {user.id !== participant.user_id && + {user?.id !== participant.user_id && me.isGroupAdmin && (!participant.isadmin || me.isGroupOwner) ? ( diff --git a/client/src/pages/Login.tsx b/client/src/pages/Login.tsx index 82a40c6..74952ac 100644 --- a/client/src/pages/Login.tsx +++ b/client/src/pages/Login.tsx @@ -2,10 +2,10 @@ import { useForm, SubmitHandler } from 'react-hook-form'; import icon from '../../assets/icon.png'; import { Link, useNavigate } from 'react-router-dom'; import { useContext, useState } from 'react'; -import { AuthContext } from '@/utils/AuthContext.tsx'; import LoadingWheel from '../components/chat/LoadingWheel.tsx'; import { axiosClient } from '@/utils/axiosClient.ts'; +import { AuthContext } from '@/utils/AuthProvider.tsx'; export type Inputs = { username: string; @@ -31,7 +31,7 @@ export default function Login() { setAuthorized(true); setIsLoading(false); console.log('redirecting'); - navigate('/chat'); + navigate('/'); }) .catch((err) => { if (err.response) { diff --git a/client/src/pages/Signup.tsx b/client/src/pages/Signup.tsx index e545a94..591bdb1 100644 --- a/client/src/pages/Signup.tsx +++ b/client/src/pages/Signup.tsx @@ -2,9 +2,9 @@ import icon from '../../assets/icon.png'; import { useForm, SubmitHandler } from 'react-hook-form'; import { Link, useNavigate } from 'react-router-dom'; import { useContext, useState } from 'react'; -import { AuthContext } from '@/utils/AuthContext.tsx'; import LoadingWheel from '../components/chat/LoadingWheel.tsx'; import { axiosClient } from '@/utils/axiosClient.ts'; +import { AuthContext } from '@/utils/AuthProvider.tsx'; type Inputs = { username: string; @@ -44,7 +44,7 @@ export default function Signup() { .then(() => { setAuthorized(true); setIsLoading(false); - navigate('/chat'); + navigate('/'); console.log('Signed up'); }) .catch((err) => { diff --git a/client/src/utils/AuthContext.tsx b/client/src/utils/AuthContext.tsx deleted file mode 100644 index 1caed72..0000000 --- a/client/src/utils/AuthContext.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createContext } from 'react'; -import { UserType } from '@/types/types.ts'; - -interface AuthContextType { - authorized: boolean; - isLoading: boolean; - user: UserType | null; - setAuthorized: (value: boolean) => void; -} - -export const AuthContext = createContext({ - authorized: false, - isLoading: true, - user: null, - setAuthorized: () => {}, -}); diff --git a/client/src/utils/AuthProvider.tsx b/client/src/utils/AuthProvider.tsx index 226b25a..74b1874 100644 --- a/client/src/utils/AuthProvider.tsx +++ b/client/src/utils/AuthProvider.tsx @@ -1,47 +1,52 @@ -import { AuthContext } from './AuthContext'; -import Cookies from 'js-cookie'; -import { axiosClient } from '@/utils/axiosClient.ts'; -import { ReactNode, useEffect, useState } from 'react'; +import { createContext, useState, useEffect, ReactNode } from 'react'; +import Cookie from 'js-cookie'; +import { axiosClient } from '@/utils/axiosClient'; import { UserType } from '@/types/types.ts'; +type AuthContextType = { + authorized: boolean | null; + setAuthorized: (value: boolean) => void; + user: UserType | null; + setUser: (user: UserType | null) => void; +}; + +export const AuthContext = createContext({ + authorized: null, + setAuthorized: () => {}, + user: null, + setUser: () => {}, +}); + export function AuthProvider({ children }: { children: ReactNode }) { - const [authorized, setAuthorized] = useState(false); - const [isLoading, setIsLoading] = useState(true); + const [authorized, setAuthorized] = useState(null); const [user, setUser] = useState(null); - const token = Cookies.get('token'); useEffect(() => { - async function validateAuth() { + async function validateToken() { + const token = Cookie.get('token'); if (!token) { - setIsLoading(false); + setAuthorized(false); return; } try { - const response = await axiosClient.get('/api/auth/validate', { + const res = await axiosClient.get('/api/auth/validate', { withCredentials: true, }); - setUser({ - username: response.data.username, - id: response.data.user_id, - }); + setUser({ username: res.data.username, id: res.data.user_id }); setAuthorized(true); - } catch (error) { - console.error('Auth validation failed:', error); + } catch (err) { setAuthorized(false); setUser(null); - } finally { - setIsLoading(false); + console.error('Token validation failed:', err); } } - validateAuth(); - }, [token]); + validateToken(); + }, []); return ( - + {children} ); diff --git a/client/src/utils/ProtectedRoutes.tsx b/client/src/utils/ProtectedRoutes.tsx index 5dd4d87..0688b76 100644 --- a/client/src/utils/ProtectedRoutes.tsx +++ b/client/src/utils/ProtectedRoutes.tsx @@ -1,18 +1,16 @@ import { Navigate, Outlet } from 'react-router-dom'; -import { useAuth } from '@/utils/useAuth.tsx'; -import LoadingScreen from '@/components/LoadingScreen'; +import { useContext } from 'react'; +import { AuthContext } from './AuthProvider'; +import LoadingScreen from '../components/LoadingScreen'; function ProtectedRoutes() { - const { authorized, isLoading, user } = useAuth(); - if (isLoading) { + const { authorized } = useContext(AuthContext); + + if (authorized === null) { return ; } - return authorized ? ( - - ) : ( - - ); + return authorized ? : ; } export default ProtectedRoutes; diff --git a/client/src/utils/PublicRoute.tsx b/client/src/utils/PublicRoute.tsx index 850c890..c6098c6 100644 --- a/client/src/utils/PublicRoute.tsx +++ b/client/src/utils/PublicRoute.tsx @@ -1,11 +1,12 @@ import { Navigate, Outlet } from 'react-router-dom'; -import { useAuth } from '@/utils/useAuth.tsx'; -import LoadingScreen from '@/components/LoadingScreen'; +import { useContext } from 'react'; +import { AuthContext } from './AuthProvider'; +import LoadingScreen from '../components/LoadingScreen'; function PublicRoute() { - const { authorized, isLoading } = useAuth(); + const { authorized } = useContext(AuthContext); - if (isLoading) { + if (authorized === null) { return ; } diff --git a/client/src/utils/useAuth.tsx b/client/src/utils/useAuth.tsx deleted file mode 100644 index 239ef19..0000000 --- a/client/src/utils/useAuth.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import { useContext } from 'react'; -import { AuthContext } from '@/utils/AuthContext.tsx'; - -export const useAuth = () => useContext(AuthContext);