Add profile settings page, mentor management, and S3 email logos

- Add universal /settings/profile page accessible to all roles with
  avatar upload, bio, phone, password change, and account deletion
- Expand updateProfile endpoint to accept bio (metadataJson), phone,
  and notification preference
- Add deleteAccount endpoint with password confirmation
- Add Profile Settings link to all nav components (admin, jury, mentor,
  observer)
- Add /admin/mentors list page and /admin/mentors/[id] detail page for
  mentor management
- Add Mentors nav item to admin sidebar
- Update email logo URLs to S3 (s3.monaco-opc.com/public/)
- Add ocean.png background image to email wrapper

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-30 19:57:12 +01:00
parent 0c0a9b7eb5
commit 402bdfd8c5
10 changed files with 1248 additions and 10 deletions

View File

@@ -0,0 +1,55 @@
import { redirect } from 'next/navigation'
import { auth } from '@/lib/auth'
const ROLE_DASHBOARDS: Record<string, string> = {
SUPER_ADMIN: '/admin',
PROGRAM_ADMIN: '/admin',
JURY_MEMBER: '/jury',
MENTOR: '/mentor',
OBSERVER: '/observer',
}
export default async function SettingsLayout({
children,
}: {
children: React.ReactNode
}) {
const session = await auth()
if (!session?.user) {
redirect('/login')
}
const dashboardUrl = ROLE_DASHBOARDS[session.user.role] || '/login'
return (
<div className="min-h-screen bg-background">
<header className="sticky top-0 z-40 border-b bg-card">
<div className="container mx-auto flex h-16 max-w-3xl items-center px-4">
<a
href={dashboardUrl}
className="flex items-center gap-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m15 18-6-6 6-6" />
</svg>
Back to Dashboard
</a>
</div>
</header>
<main className="container mx-auto max-w-3xl px-4 py-6 lg:py-8">
{children}
</main>
</div>
)
}