Implement platform settings (Stage 9)

- Wire settings to actual platform behavior: maintenance mode, registration toggle,
  notification emails, curator feedback emails, email verification flag
- Add logo (logoUrl, showLogo) and social network links (YouTube, VK, Telegram) settings
- Show logo + school name dynamically in student layout header
- Add footer to student layout with org requisites and social links
- Register page: read settings server-side, validate terms checkbox with legal links
- Login page: show notice when redirected from closed registration
- Settings form: add Logo and Social Networks sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 15:31:10 +05:00
parent ba0a630fd9
commit c64f393a7b
8 changed files with 223 additions and 24 deletions
+46 -2
View File
@@ -16,6 +16,17 @@ export default async function StudentLayout({ children }: { children: React.Reac
if (maintenance === "true") redirect("/maintenance");
}
const [schoolName, logoUrl, showLogo, socialYoutube, socialVk, socialTelegram, orgRequisites] =
await Promise.all([
getSetting("schoolName"),
getSetting("logoUrl"),
getSetting("showLogo"),
getSetting("socialYoutube"),
getSetting("socialVk"),
getSetting("socialTelegram"),
getSetting("orgRequisites"),
]);
const isImpersonating = !!(session.session as { impersonatedBy?: string }).impersonatedBy;
return (
@@ -25,8 +36,12 @@ export default async function StudentLayout({ children }: { children: React.Reac
className="sticky top-0 z-10 flex items-center justify-between px-6 py-3"
style={{ borderBottom: "2px solid var(--border)", backgroundColor: "var(--background)" }}
>
<Link href="/dashboard" className="font-bold tracking-wide" style={{ color: "var(--foreground)" }}>
Second Brain
<Link href="/dashboard" className="flex items-center gap-2 font-bold tracking-wide" style={{ color: "var(--foreground)" }}>
{logoUrl && showLogo === "true" && (
// eslint-disable-next-line @next/next/no-img-element
<img src={logoUrl} alt={schoolName} className="h-6 w-auto object-contain" />
)}
{schoolName}
</Link>
<div className="flex items-center gap-4">
<span className="text-sm" style={{ color: "var(--muted-foreground)" }}>{session.user.name}</span>
@@ -34,6 +49,35 @@ export default async function StudentLayout({ children }: { children: React.Reac
</div>
</header>
<div className="flex-1 flex flex-col">{children}</div>
{(socialYoutube || socialVk || socialTelegram || orgRequisites) && (
<footer
className="px-6 py-4 flex flex-col sm:flex-row items-center justify-between gap-3 text-xs"
style={{ borderTop: "2px solid var(--border)", color: "var(--muted-foreground)" }}
>
{orgRequisites && (
<p className="whitespace-pre-line text-center sm:text-left">{orgRequisites}</p>
)}
{(socialYoutube || socialVk || socialTelegram) && (
<div className="flex items-center gap-4 flex-shrink-0">
{socialYoutube && (
<a href={socialYoutube} target="_blank" rel="noopener noreferrer" className="hover:underline">
YouTube
</a>
)}
{socialVk && (
<a href={socialVk} target="_blank" rel="noopener noreferrer" className="hover:underline">
VK
</a>
)}
{socialTelegram && (
<a href={socialTelegram} target="_blank" rel="noopener noreferrer" className="hover:underline">
Telegram
</a>
)}
</div>
)}
</footer>
)}
</div>
);
}