Platform review round 2: audit logging migration, nav unification, DB indexes, and UI polish
- Migrate ~41 inline audit log calls to shared logAudit() utility across all routers - Add transaction-aware prisma parameter to logAudit() for atomic operations - Unify jury/mentor/observer navigation into shared RoleNav component - Add composite DB indexes (Evaluation, GracePeriod, AuditLog) for query performance - Fix profile page: consolidate dual save buttons, proper useEffect initialization - Enhance auth error page with MOPC branding and navigation - Improve observer dashboard with prominent read-only badge - Fix DI-3: fetch projects before bulk status update for accurate notifications - Remove unused aiBoost field from smart-assignment scoring - Add shared image-upload utility and structured logger module Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { useSearchParams } from 'next/navigation'
|
||||
import Link from 'next/link'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Logo } from '@/components/shared/logo'
|
||||
import { AlertCircle } from 'lucide-react'
|
||||
|
||||
const errorMessages: Record<string, string> = {
|
||||
@@ -21,16 +22,22 @@ export default function AuthErrorPage() {
|
||||
return (
|
||||
<Card className="w-full max-w-md">
|
||||
<CardHeader className="text-center">
|
||||
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10">
|
||||
<div className="mx-auto mb-4">
|
||||
<Logo variant="small" />
|
||||
</div>
|
||||
<div className="mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10">
|
||||
<AlertCircle className="h-6 w-6 text-destructive" />
|
||||
</div>
|
||||
<CardTitle className="text-xl">Authentication Error</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4 text-center">
|
||||
<p className="text-muted-foreground">{message}</p>
|
||||
<div className="border-t pt-4">
|
||||
<div className="flex gap-3 justify-center border-t pt-4">
|
||||
<Button asChild>
|
||||
<Link href="/login">Try again</Link>
|
||||
<Link href="/login">Return to Login</Link>
|
||||
</Button>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/">Home</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -67,19 +67,24 @@ async function ObserverDashboardContent() {
|
||||
return (
|
||||
<>
|
||||
{/* Observer Notice */}
|
||||
<Card className="border-blue-200 bg-blue-50 dark:border-blue-900 dark:bg-blue-950/30">
|
||||
<CardContent className="flex items-center gap-3 py-4">
|
||||
<Eye className="h-5 w-5 text-blue-600 dark:text-blue-400" />
|
||||
<div className="rounded-lg border-2 border-blue-300 bg-blue-50 px-4 py-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-blue-100">
|
||||
<Eye className="h-4 w-4 text-blue-600" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-blue-900 dark:text-blue-100">
|
||||
Observer Mode
|
||||
</p>
|
||||
<p className="text-sm text-blue-700 dark:text-blue-300">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="font-semibold text-blue-900">Observer Mode</p>
|
||||
<Badge variant="outline" className="border-blue-300 text-blue-700 text-xs">
|
||||
Read-Only
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-sm text-blue-700">
|
||||
You have read-only access to view platform statistics and reports.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats Grid */}
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||
|
||||
@@ -239,19 +239,6 @@ export default function ProfileSettingsPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={handleSaveProfile}
|
||||
disabled={updateProfile.isPending}
|
||||
>
|
||||
{updateProfile.isPending ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Save className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Save Changes
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -285,19 +272,6 @@ export default function ProfileSettingsPage() {
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={handleSaveProfile}
|
||||
disabled={updateProfile.isPending}
|
||||
>
|
||||
{updateProfile.isPending ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Save className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Save Preferences
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -320,22 +294,25 @@ export default function ProfileSettingsPage() {
|
||||
maxTags={15}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={handleSaveProfile}
|
||||
disabled={updateProfile.isPending}
|
||||
>
|
||||
{updateProfile.isPending ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Save className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Save Expertise
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Save All Profile Changes */}
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={handleSaveProfile}
|
||||
disabled={updateProfile.isPending}
|
||||
size="lg"
|
||||
>
|
||||
{updateProfile.isPending ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Save className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Save All Changes
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Change Password */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
Reference in New Issue
Block a user