diff --git a/src/components/layout/Navbar.jsx b/src/components/layout/Navbar.jsx index 6d47ae8..6881e70 100644 --- a/src/components/layout/Navbar.jsx +++ b/src/components/layout/Navbar.jsx @@ -4,6 +4,7 @@ import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { selectCurrentUser } from '../../features/auth/authSelectors'; import { logoutUser } from '../../features/auth/authThunks'; import { toastSuccess } from '../../utils/toast'; +import { useRole } from '../../hooks/useRole'; const NAV_LINKS = [ { label: 'How it works', to: '/how-it-works' }, @@ -24,6 +25,7 @@ export default function Navbar() { const dispatch = useAppDispatch(); const navigate = useNavigate(); const user = useAppSelector(selectCurrentUser); + const { isAdmin } = useRole(); const [menuOpen, setMenuOpen] = useState(false); const [avatarOpen, setAvatarOpen] = useState(false); @@ -365,6 +367,12 @@ export default function Navbar() {
{user.name}
setAvatarOpen(false)}>Dashboard + {isAdmin && ( + setAvatarOpen(false)}>Admin Panel + )} + {!isAdmin && ( + setAvatarOpen(false)}>Create Campaign + )} setAvatarOpen(false)}>Profile setAvatarOpen(false)}>Settings
@@ -417,6 +425,12 @@ export default function Navbar() { {user ? ( <> Dashboard + {isAdmin && ( + Admin Panel + )} + {!isAdmin && ( + Create Campaign + )} Profile Settings
diff --git a/src/hooks/useRole.js b/src/hooks/useRole.js new file mode 100644 index 0000000..c8e2ceb --- /dev/null +++ b/src/hooks/useRole.js @@ -0,0 +1,21 @@ +import { useAppSelector } from '../store/hooks'; +import { selectCurrentUser } from '../features/auth/authSelectors'; + +/** + * Custom hook to determine user roles + * @returns {Object} { isAdmin: boolean, isUser: boolean } + */ +export const useRole = () => { + const user = useAppSelector(selectCurrentUser); + + // Determine if user is admin based on role property + const isAdmin = user?.role === 'admin'; + + // Determine if user is a regular user (authenticated but not admin) + const isUser = !!user && user?.role !== 'admin'; + + return { + isAdmin, + isUser, + }; +}; diff --git a/src/pages/CampaignDetails.jsx b/src/pages/CampaignDetails.jsx index 6330275..e93c243 100644 --- a/src/pages/CampaignDetails.jsx +++ b/src/pages/CampaignDetails.jsx @@ -1,12 +1,76 @@ -import { useParams } from 'react-router-dom'; +import { useParams, useNavigate } from 'react-router-dom'; +import { useAppSelector } from '../store/hooks'; +import { selectCurrentUser } from '../features/auth/authSelectors'; +import { useState } from 'react'; const CampaignDetails = () => { const { id } = useParams(); + const navigate = useNavigate(); + const user = useAppSelector(selectCurrentUser); + + // TODO: Replace with actual API call to fetch campaign by id + // For now, using mock data structure + const [campaign] = useState({ + id: id, + title: 'Sample Campaign', + description: 'This is a sample campaign description', + ownerId: null, // This should come from the API response + ownerName: 'Campaign Owner', + // ... other campaign fields + }); + + // Check if current user is the campaign owner + const isOwner = user && campaign?.ownerId === user.id; + + const handleEdit = () => { + navigate(`/campaign/${id}/edit`); + }; + + const handleDelete = () => { + if (window.confirm('Are you sure you want to delete this campaign?')) { + // TODO: Implement delete campaign API call + console.log('Deleting campaign:', id); + // After successful deletion, redirect to explore page + // navigate('/explore'); + } + }; return ( -
-

Campaign Details

-

Viewing details for campaign ID: {id}

+
+
+
+
+

+ {campaign.title} +

+

Campaign ID: {id}

+
+ + {/* Edit and Delete buttons - only visible to campaign owner */} + {isOwner && ( +
+ + +
+ )} +
+ +
+

{campaign.description}

+
+ + {/* TODO: Add more campaign details here */} +
); }; diff --git a/src/routes/AdminRoute.jsx b/src/routes/AdminRoute.jsx new file mode 100644 index 0000000..e94de9c --- /dev/null +++ b/src/routes/AdminRoute.jsx @@ -0,0 +1,24 @@ +import { Navigate } from 'react-router-dom'; +import { useRole } from '../hooks/useRole'; + +/** + * AdminRoute - A route wrapper that only allows admin users + * Redirects non-admin users to /dashboard + * + * @param {Object} props - Component props + * @param {React.ReactNode} props.children - The component to render if user is admin + * @returns {React.ReactElement} Either the children or a redirect + */ +const AdminRoute = ({ children }) => { + const { isAdmin } = useRole(); + + // If user is not an admin, redirect to dashboard + if (!isAdmin) { + return ; + } + + // User is admin, render the protected component + return children; +}; + +export default AdminRoute; diff --git a/src/routes/AppRouter.jsx b/src/routes/AppRouter.jsx index 9775d6b..4402e15 100644 --- a/src/routes/AppRouter.jsx +++ b/src/routes/AppRouter.jsx @@ -6,6 +6,7 @@ import GlobalLoadingWrapper from '../components/common/GlobalLoadingWrapper'; import Spinner from '../components/common/Spinner'; import NotFound from '../pages/NotFound'; import ErrorTest from '../components/common/ErrorTest'; +import AdminRoute from './AdminRoute'; // Auth pages import Login from '../pages/Login'; @@ -51,7 +52,11 @@ const AppRouter = () => { {/* App pages */} } /> - } /> + + + + } /> {/* 404 */} } />