From 3996c2550ed524a233eb969c427fc2594eb81f5f Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Thu, 22 Jan 2026 20:28:44 +0100 Subject: [PATCH] feat(auth): implement role-based access control in SiteDashboard and SiteSettings, enhancing user experience with edit permissions --- app/sites/[id]/page.tsx | 6 ++ app/sites/[id]/settings/page.tsx | 156 +++++++++++++++++-------------- components/sites/SiteList.tsx | 18 ++-- lib/auth/context.tsx | 12 ++- 4 files changed, 115 insertions(+), 77 deletions(-) diff --git a/app/sites/[id]/page.tsx b/app/sites/[id]/page.tsx index 517e971..bf74656 100644 --- a/app/sites/[id]/page.tsx +++ b/app/sites/[id]/page.tsx @@ -1,5 +1,6 @@ 'use client' +import { useAuth } from '@/lib/auth/context' import { useEffect, useState } from 'react' import { useParams, useRouter } from 'next/navigation' import { getSite, type Site } from '@/lib/api/sites' @@ -17,6 +18,9 @@ import Chart from '@/components/dashboard/Chart' import PerformanceStats from '@/components/dashboard/PerformanceStats' export default function SiteDashboardPage() { + const { user } = useAuth() + const canEdit = user?.role === 'owner' || user?.role === 'admin' + const params = useParams() const router = useRouter() const siteId = params.id as string @@ -221,12 +225,14 @@ export default function SiteDashboardPage() { className="min-w-[100px]" /> )} + {canEdit && ( + )} diff --git a/app/sites/[id]/settings/page.tsx b/app/sites/[id]/settings/page.tsx index f8999df..203a0a0 100644 --- a/app/sites/[id]/settings/page.tsx +++ b/app/sites/[id]/settings/page.tsx @@ -12,6 +12,7 @@ import Select from '@/components/ui/Select' import { APP_URL, API_URL } from '@/lib/api/client' import { generatePrivacySnippet } from '@/lib/utils/privacySnippet' import { motion, AnimatePresence } from 'framer-motion' +import { useAuth } from '@/lib/auth/context' import { GearIcon, GlobeIcon, @@ -51,6 +52,9 @@ const TIMEZONES = [ ] export default function SiteSettingsPage() { + const { user } = useAuth() + const canEdit = user?.role === 'owner' || user?.role === 'admin' + const params = useParams() const router = useRouter() const siteId = params.id as string @@ -302,6 +306,13 @@ export default function SiteSettingsPage() { {/* Content Area */}
+ {!canEdit && ( +
+ +

You have read-only access to this site. Contact an admin to make changes.

+
+ )} +
-
- -
- +
+ {canEdit && ( + + )} +
+ -
-
-

Danger Zone

+ {canEdit && ( +
+
+

Danger Zone

Irreversible actions for your site.

@@ -450,9 +464,9 @@ export default function SiteSettingsPage() {
+ )}
- - )} + )} {activeTab === 'visibility' && (
@@ -566,21 +580,23 @@ export default function SiteSettingsPage() {
- + {canEdit && ( + + )}
@@ -819,21 +835,23 @@ export default function SiteSettingsPage() {
- + {canEdit && ( + + )}
@@ -985,21 +1003,23 @@ export default function SiteSettingsPage() {
- + {canEdit && ( + + )}
diff --git a/components/sites/SiteList.tsx b/components/sites/SiteList.tsx index daf73bc..e619a29 100644 --- a/components/sites/SiteList.tsx +++ b/components/sites/SiteList.tsx @@ -5,9 +5,11 @@ import Link from 'next/link' import { listSites, deleteSite, type Site } from '@/lib/api/sites' import { toast } from 'sonner' import LoadingOverlay from '../LoadingOverlay' +import { useAuth } from '@/lib/auth/context' import { BarChartIcon } from '@radix-ui/react-icons' export default function SiteList() { + const { user } = useAuth() const [sites, setSites] = useState([]) const [loading, setLoading] = useState(true) @@ -72,13 +74,15 @@ export default function SiteList() { View Dashboard - + {(user?.role === 'owner' || user?.role === 'admin') && ( + + )} ))} diff --git a/lib/auth/context.tsx b/lib/auth/context.tsx index 3837d7c..61687b2 100644 --- a/lib/auth/context.tsx +++ b/lib/auth/context.tsx @@ -63,8 +63,16 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { const refresh = useCallback(async () => { try { const userData = await apiRequest('/auth/user/me') - setUser(userData) - localStorage.setItem('user', JSON.stringify(userData)) + + setUser(prev => { + const merged = { + ...userData, + org_id: prev?.org_id, + role: prev?.role + } + localStorage.setItem('user', JSON.stringify(merged)) + return merged + }) } catch (e) { console.error('Failed to refresh user data', e) }