From 91313ac7d54c03ebf9f65142d18decd2f312137c Mon Sep 17 00:00:00 2001 From: Timo Date: Thu, 1 Jan 2026 20:18:45 +0100 Subject: [PATCH] footer+responsivenes --- Dockerfile | 4 ++ src/app/(app)/layout.tsx | 63 ++++++++++++++++++++- src/app/api/newsletter/admin-login/route.ts | 9 +++ src/app/api/user/route.ts | 39 +++++++++++++ src/components/ui/Footer.tsx | 63 +++++++++++++++++++++ src/middleware.ts | 22 +++++++ 6 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 src/app/api/user/route.ts create mode 100644 src/components/ui/Footer.tsx diff --git a/Dockerfile b/Dockerfile index 5ddb421..c8a7ee8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,6 +33,10 @@ ENV IP_SALT="build-time-salt" ENV STRIPE_SECRET_KEY="sk_test_placeholder_for_build" ENV RESEND_API_KEY="re_placeholder_for_build" ENV NEXT_PUBLIC_APP_URL="http://localhost:3000" +# PostHog Analytics - REQUIRED at build time for client-side bundle +ENV NEXT_PUBLIC_POSTHOG_KEY="phc_97JBJVVQlqqiZuTVRHuBnnG9HasOv3GSsdeVjossizJ" +ENV NEXT_PUBLIC_POSTHOG_HOST="https://us.i.posthog.com" +ENV NEXT_PUBLIC_INDEXABLE="true" RUN npx prisma generate RUN npm run build diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx index 5c65d08..bbf4363 100644 --- a/src/app/(app)/layout.tsx +++ b/src/app/(app)/layout.tsx @@ -1,12 +1,20 @@ 'use client'; -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import Link from 'next/link'; import { usePathname, useRouter } from 'next/navigation'; import { Button } from '@/components/ui/Button'; import { Dropdown, DropdownItem } from '@/components/ui/Dropdown'; +import { Footer } from '@/components/ui/Footer'; import { useTranslation } from '@/hooks/useTranslation'; +interface User { + id: string; + name: string | null; + email: string; + plan: string | null; +} + export default function AppLayout({ children, }: { @@ -16,6 +24,24 @@ export default function AppLayout({ const router = useRouter(); const { t } = useTranslation(); const [sidebarOpen, setSidebarOpen] = useState(false); + const [user, setUser] = useState(null); + + // Fetch user data on mount + useEffect(() => { + const fetchUser = async () => { + try { + const response = await fetch('/api/user'); + if (response.ok) { + const userData = await response.json(); + setUser(userData); + } + } catch (error) { + console.error('Error fetching user:', error); + } + }; + + fetchUser(); + }, []); const handleSignOut = async () => { // Track logout event before clearing data @@ -37,6 +63,34 @@ export default function AppLayout({ router.push('/'); }; + // Get user initials for avatar (e.g., "Timo Schmidt" -> "TS") + const getUserInitials = () => { + if (!user) return 'U'; + + if (user.name) { + const names = user.name.trim().split(' '); + if (names.length >= 2) { + return (names[0][0] + names[names.length - 1][0]).toUpperCase(); + } + return user.name.substring(0, 2).toUpperCase(); + } + + // Fallback to email + return user.email.substring(0, 1).toUpperCase(); + }; + + // Get display name (first name or full name) + const getDisplayName = () => { + if (!user) return 'User'; + + if (user.name) { + return user.name; + } + + // Fallback to email without domain + return user.email.split('@')[0]; + }; + const navigation = [ { name: t('nav.dashboard'), @@ -169,11 +223,11 @@ export default function AppLayout({