feat(02-02): login page UI, header/sidebar auth wiring, i18n keys

- Create split-screen login page with branding left (#ffed00) and form right (D-01)
- Login form has username, password, and remember-me checkbox (D-02)
- Wire header user avatar with auth store: shows user initial, dropdown with role badge and logout
- Wire sidebar footer with auth store: shows user name, role, and initial
- Add auth, header role, and admin i18n keys to both de.json and en.json
- All new UI strings use t() function (no hardcoded text)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 13:34:43 +02:00
parent cdf4d60038
commit e7b2a70fc9
5 changed files with 459 additions and 43 deletions
@@ -2,11 +2,21 @@
import { useTranslations } from 'next-intl';
import { useSidebarStore } from '@/lib/stores/sidebar-store';
import { useAuthStore } from '@/lib/stores/auth-store';
import { LocaleSwitcher } from '@/components/locale-switcher';
export function SidebarFooter() {
const t = useTranslations('sidebar');
const tHeader = useTranslations('header');
const isCollapsed = useSidebarStore((s) => s.isCollapsed);
const user = useAuthStore((s) => s.user);
const userInitial = user
? (user.displayName ?? user.username).charAt(0).toUpperCase()
: '?';
const userName = user?.displayName ?? user?.username ?? t('userPlaceholder');
const roleLabel = user ? tHeader(`role.${user.role}`) : '';
return (
<div className="border-t border-sidebar-border p-3 flex flex-col gap-2">
@@ -39,29 +49,22 @@ export function SidebarFooter() {
)}
</button>
{/* User info placeholder */}
{/* User info - wired to auth store */}
<div className="flex items-center gap-3 px-2 py-1.5">
<div className="h-7 w-7 shrink-0 rounded-full bg-muted flex items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="text-muted-foreground"
>
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
<div className="h-7 w-7 shrink-0 rounded-full bg-primary flex items-center justify-center text-xs font-medium text-primary-foreground">
{userInitial}
</div>
{!isCollapsed && (
<span className="text-sm text-sidebar-foreground truncate">
{t('userPlaceholder')}
</span>
<div className="flex flex-col overflow-hidden">
<span className="text-sm text-sidebar-foreground truncate">
{userName}
</span>
{user && (
<span className="text-xs text-muted-foreground truncate">
{roleLabel}
</span>
)}
</div>
)}
</div>
</div>