diff --git a/client/src/App.jsx b/client/src/App.jsx index ac6fda2..71ee91b 100755 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,5 +1,5 @@ -import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; +import { ToastContainer, Slide } from 'react-toastify'; import Router from "./Router"; import Loading from './components/Loading'; @@ -17,7 +17,13 @@ export default function App() { - + ) } diff --git a/client/src/Router.jsx b/client/src/Router.jsx index 5ade7f9..109d6f8 100755 --- a/client/src/Router.jsx +++ b/client/src/Router.jsx @@ -3,12 +3,13 @@ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; import Home from './pages/home/Home'; import Login from './pages/login/Login'; +import Retro from './pages/retro/Retro'; +import Group from './pages/groups/Group'; import RetroBoard from './pages/retro/RetroBoard'; import ServerUnavl from './pages/503/ServerUnavl'; import PageNotFound from './pages/404/PageNotFound'; import { AuthProvider } from './contexts/AuthContext'; import PrivateRoutes from './middleware/PrivateRoutes'; -import Retro from './pages/retro/Retro'; // Router component to render the application routes @@ -34,6 +35,7 @@ export default function Router() { } /> }> } /> + } /> } /> } /> diff --git a/client/src/components/group/GroupView.jsx b/client/src/components/group/GroupView.jsx deleted file mode 100644 index aa74f71..0000000 --- a/client/src/components/group/GroupView.jsx +++ /dev/null @@ -1,180 +0,0 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -import PropTypes from 'prop-types'; -import { useEffect, useState } from 'react'; -import { - Dialog, DialogTitle, DialogContent, Button, IconButton, InputAdornment, - TableContainer, Paper, Table, TableHead, TableRow, TableCell, TableBody, TextField, -} from '@mui/material'; -import DeleteIcon from '@mui/icons-material/Delete'; - -import "./Group.css"; -import { useAuth } from '../../hooks/useAuth'; -import { useLoading } from '../../hooks/useLoading'; -import { toast } from 'react-toastify'; -import ConfirmPop from '../ConfirmPop'; - - -export default function GroupView({ openData, setOpenData, isOwner }) { - - const { http } = useAuth(); - const { setLoading } = useLoading(); - const [open, setOpen] = useState(false); - const [members, setMembers] = useState([]); - const [newMember, setNewMember] = useState(''); - const [tempLoad, setTempLoad] = useState(false); - - useEffect(() => { - if (!http.defaults.headers.common.Authorization) return null; - if (!openData?._id) return null; - - fetchMembers(); - }, [http, openData]); - - - const fetchMembers = async () => { - try { - setLoading(true); - const response = await http.get('/group/fetch/' + openData?._id); - setMembers(response?.data?.members); - } catch (error) { - console.error(error); - } finally { - setLoading(false); - } - }; - - - const addMember = async (email) => { - try { - setTempLoad(true); - const response = await http.post('/group/add-member', { email, groupId: openData?._id }); - toast.success(response?.data?.message ?? 'Member added successfully'); - setNewMember(''); - fetchMembers(); - } catch (error) { - console.error(error); - toast.error(error?.response?.data?.message ?? 'Failed to add member'); - } finally { - setTempLoad(false); - } - }; - - - const deleteMember = async (email) => { - try { - setLoading(true); - await http.delete('/group/delete-member', { data: { groupId: openData?._id, email } }); - toast.success('Member removed successfully'); - fetchMembers(); - } catch (error) { - console.error(error); - toast.error(error?.response?.data?.message ?? 'Failed to remove member'); - } finally { - setLoading(false); - } - }; - - - const deleteGroup = async () => { - try { - setOpen(false); - setLoading(true); - await http.delete(`/group/delete/${openData?._id}`); - toast.success('Group deleted successfully'); - localStorage.removeItem('group'); - setOpenData(null); - } catch (error) { - console.error(error); - toast.error(error?.response?.data?.message ?? 'Failed to delete group'); - } finally { - setLoading(false); - } - }; - - - return ( - setOpenData(null)} - > - {open && } - - Group Details | {openData?.name} - - - - - - - - # - Member Name - Member Email - Joined On - - - - - {members?.length > 0 && members.map((member, index) => ( - - {index + 1} - - {member?.name} - - {member?.email} - - {new Date(member?.createdAt).toLocaleString()} - - - deleteMember(member?.email)}> - - - - - ))} - -
-
- {isOwner && ( -
- setNewMember(e.target.value)} - slotProps={{ - input: { - endAdornment: ( - - - - ), - }, - }} - /> - -
- )} -
-
- ) -} - -GroupView.propTypes = { - openData: PropTypes.object.isRequired, - setOpenData: PropTypes.func.isRequired, - isOwner: PropTypes.bool.isRequired, -}; diff --git a/client/src/hooks/useGetRetroData.js b/client/src/hooks/useGetRetroData.js new file mode 100644 index 0000000..2b89cc1 --- /dev/null +++ b/client/src/hooks/useGetRetroData.js @@ -0,0 +1,23 @@ +import { useAuth } from "./useAuth"; +import { useLoading } from "./useLoading"; + +export const useGetRetroData = () => { + const { http } = useAuth(); + const { setLoading } = useLoading(); + + const getRetroData = async () => { + try { + setLoading(true); + const response = await http.get('/group/fetch'); + localStorage.setItem('retroData', JSON.stringify(response?.data)); + return response?.data; + } catch (error) { + console.error("Error fetching retro:", error); + return null; + } finally { + setLoading(false); + } + }; + + return { getRetroData }; +}; diff --git a/client/src/hooks/useRetroSocket.js b/client/src/hooks/useRetroSocket.js index 132d102..d732514 100755 --- a/client/src/hooks/useRetroSocket.js +++ b/client/src/hooks/useRetroSocket.js @@ -60,19 +60,16 @@ export const useRetroSocket = (retroId) => { // update mood const updateMood = (emoji) => { - console.log("UPDATING EMOJI", { emoji, email: userData?.email }); socket?.emit("updateMood", { emoji, email: userData?.email }); }; // add review const addReview = (column, comment) => { - console.log("ADDING REVIEW", { column, comment, email: userData?.email }); socket?.emit("addReview", { column, comment, email: userData?.email }); }; // update review const updateReview = (column, comment, index) => { - console.log("UPDATING REVIEW", { column, comment, index, email: userData?.email }); socket?.emit("updateReview", { column, comment, index, email: userData?.email }); }; diff --git a/client/src/layout/Header.jsx b/client/src/layout/Header.jsx index c7fc24a..7a05d68 100755 --- a/client/src/layout/Header.jsx +++ b/client/src/layout/Header.jsx @@ -9,8 +9,10 @@ import AdbIcon from '@mui/icons-material/Adb'; import MenuIcon from '@mui/icons-material/Menu'; import CloseIcon from '@mui/icons-material/Close'; import HomeIcon from '@mui/icons-material/Home'; +import GroupIcon from '@mui/icons-material/Group'; +import LogoutIcon from '@mui/icons-material/Logout'; import ReviewsIcon from '@mui/icons-material/Reviews'; -import DescriptionIcon from '@mui/icons-material/Description'; +import AccountCircleIcon from '@mui/icons-material/AccountCircle'; import './Header.css'; import { useAuth } from '../hooks/useAuth'; @@ -26,8 +28,7 @@ export default function Header() { const [popUser, setPopUser] = useState(null); const [openLogout, setOpenLogout] = useState(false); - const settings = ['Account', 'Logout']; - const isActive = (page) => location.pathname === '/' + page; + const isActive = (page) => location.pathname.split('/')[1] === page; const toggleDrawer = (page) => { setOpen(!open); @@ -42,8 +43,7 @@ export default function Header() { const handleCloseUserMenu = (setting) => { setPopUser(null); - if (setting === 'Account') navigate('/account'); - else if (setting === 'Logout') setOpenLogout(true); + if (setting === 'logout') setOpenLogout(true); }; return ( @@ -60,11 +60,14 @@ export default function Header() { navigate('/home')} className={isActive('home') ? "active-route" : "non-active-route"}>  Home + navigate('/group')} className={isActive('group') ? "active-route" : "non-active-route"}> +  Group + navigate('/retro')} className={isActive('retro') ? "active-route" : "non-active-route"}>  Retro-Board - navigate('/journal')} className={isActive('journal') ? "active-route" : "non-active-route"}> -  Reports + navigate('/account')} className={isActive('account') ? "active-route" : "non-active-route"}> +  Account @@ -84,7 +87,7 @@ export default function Header() { - + @@ -105,11 +108,11 @@ export default function Header() { open={Boolean(popUser)} onClose={handleCloseUserMenu} > - {settings.map((setting) => ( - handleCloseUserMenu(setting)}> - {setting} - - ))} + handleCloseUserMenu("logout")}> + + Logout   + + @@ -129,11 +132,14 @@ export default function Header() { toggleDrawer('home')} className={isActive('home') ? "pop-active" : "pop-non-active"}>  Home + toggleDrawer('group')} className={isActive('group') ? "pop-active" : "pop-non-active"}> +  Group + toggleDrawer('retro')} className={isActive('retro') ? "pop-active" : "pop-non-active"}>  Retro-Board - toggleDrawer('journal')} className={isActive('journal') ? "pop-active" : "pop-non-active"}> -  Reports + toggleDrawer('account')} className={isActive('account') ? "pop-active" : "pop-non-active"}> +  Account diff --git a/client/src/middleware/PrivateRoutes.jsx b/client/src/middleware/PrivateRoutes.jsx index dfbf605..bd206be 100755 --- a/client/src/middleware/PrivateRoutes.jsx +++ b/client/src/middleware/PrivateRoutes.jsx @@ -10,14 +10,12 @@ import { useAuth } from '../hooks/useAuth'; // PrivateRoutes component to protect routes export default function PrivateRoutes() { - const { isAuthLoading, isAuthenticated, logout } = useAuth(); + const { isAuthLoading, isAuthenticated, http, logout } = useAuth(); useEffect(() => { - if (isAuthLoading) return; - if (!isAuthenticated) logout(); - - }, [isAuthLoading, isAuthenticated, logout]); + if (isAuthLoading || !http.defaults.headers.common.Authorization) return; + }, [isAuthLoading, isAuthenticated, http, logout]); if (!isAuthenticated) { return null; @@ -32,10 +30,16 @@ export default function PrivateRoutes() { //