diff --git a/app/src/context/auth-context.ts b/app/src/context/auth-context.ts index 770857c..551027b 100644 --- a/app/src/context/auth-context.ts +++ b/app/src/context/auth-context.ts @@ -1,6 +1,7 @@ import { createContext, useContext } from 'react'; export interface ProfileData { + id?: number; name?: string; email?: string; is_verified?: boolean; diff --git a/app/src/pages/post/PostView.tsx b/app/src/pages/post/PostView.tsx index b9e05ff..7c923fb 100644 --- a/app/src/pages/post/PostView.tsx +++ b/app/src/pages/post/PostView.tsx @@ -3,12 +3,14 @@ import { useParams, useNavigate, Link } from 'react-router-dom'; import { Zap, Hammer, Trash2, Pencil, X, Check, Calendar, MapPin, BedDouble, MessageSquare, Wrench, ArrowLeft, AlertCircle, - Clock, Users, + Clock, Users, LogIn, UserCircle2, Mail, } from 'lucide-react'; import { MainLayout } from '../../components/layout/MainLayout'; import { POST_PLACES } from '../../constants/models'; import { CommentBox } from '../../components/CommentBox'; import { Loader } from '../../components/Loader'; +import { useAuth } from '../../context/auth-context'; +import type { ProfileData } from '../../context/auth-context'; type Role = 'faculty' | 'warden' | 'centrehead'; @@ -40,8 +42,30 @@ interface ComplaintPost { comments?: ComplaintComment[] | null; status_audit_logs?: StatusAudit[] | null; people_in_thread?: string[] | null; + // author foreign key, one of these depending on the post's role + faculty_id?: number; + warden_id?: number; + centrehead_id?: number; + // preloaded author; the Go struct field has no json tag, so the key is "Author" + Author?: { id: number; name: string; email: string }; } +// roleOf derives the complaint-side role of a logged-in profile from the +// role-specific field the profile API returns; admins and super admins get null. +function roleOf(profile: ProfileData | null): Role | null { + if (!profile || profile.position || profile.role === 'superadmin') return null; + if (profile.department !== undefined) return 'faculty'; + if (profile.hostel !== undefined) return 'warden'; + if (profile.building !== undefined) return 'centrehead'; + return null; +} + +const LOGIN_PATH: Record = { + faculty: '/faculty/login', + warden: '/warden/login', + centrehead: '/centre-head/login', +}; + interface EditForm { title: string; description: string; @@ -87,6 +111,8 @@ function formatDateTime(iso: string) { export function PostView() { const { role, post_id } = useParams<{ role: Role; post_id: string }>(); const navigate = useNavigate(); + const { status: authStatus, profile } = useAuth(); + const isLoggedIn = authStatus === 'authenticated'; const [post, setPost] = useState(null); const [loading, setLoading] = useState(true); @@ -190,6 +216,12 @@ export function PostView() { const comments = post.comments ?? []; const editExpired = isEditWindowExpired(post.created_at); + // Only the post's author may edit or delete it. The API enforces this too; + // this just keeps the buttons away from everyone else. + const authorId = role === 'faculty' ? post.faculty_id : role === 'warden' ? post.warden_id : post.centrehead_id; + const isOwner = isLoggedIn && roleOf(profile) === role && profile?.id !== undefined && profile.id === authorId; + const canManage = isOwner && !editExpired; + const editBase = isFaculty ? '/api/posts/faculty/edit' : isWarden ? '/api/posts/warden/edit' : '/api/posts/centrehead/edit'; const deleteBase = isFaculty ? '/api/posts/faculty/delete' : isWarden ? '/api/posts/warden/delete' : '/api/posts/centrehead/delete'; @@ -289,13 +321,13 @@ export function PostView() { {/* Back Link */}
- - Back to Dashboard + + {isLoggedIn ? 'Back to Dashboard' : 'Back to Home'} {/* Action buttons */}
- {!isEditing && !editExpired && ( + {!isEditing && canManage && (