Guten Tag, {displayName}
Überblick über deine Credits und laufende Generierungen.
"use client"; import Image from "next/image"; import { useRouter } from "next/navigation"; import { useEffect, useRef, useState } from "react"; import { useTheme } from "next-themes"; import { useMutation } from "convex/react"; import { useTranslations } from "next-intl"; import { ChevronDown, Coins, LayoutTemplate, Monitor, Moon, Search, Sun, } from "lucide-react"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { api } from "@/convex/_generated/api"; import type { Doc } from "@/convex/_generated/dataModel"; import { authClient } from "@/lib/auth-client"; import { CreditOverview } from "@/components/dashboard/credit-overview"; import { RecentTransactions } from "@/components/dashboard/recent-transactions"; import CanvasCard from "@/components/dashboard/canvas-card"; import { toast } from "@/lib/toast"; import { useAuthQuery } from "@/hooks/use-auth-query"; function getInitials(nameOrEmail: string) { const normalized = nameOrEmail.trim(); if (!normalized) return "U"; const parts = normalized.split(/\s+/).filter(Boolean); if (parts.length >= 2) { return `${parts[0][0]}${parts[1][0]}`.toUpperCase(); } return normalized.slice(0, 2).toUpperCase(); } export default function DashboardPage() { const t = useTranslations('toasts'); const router = useRouter(); const welcomeToastSentRef = useRef(false); const { theme = "system", setTheme } = useTheme(); const { data: session, isPending: isSessionPending } = authClient.useSession(); const canvases = useAuthQuery( api.canvases.list, session?.user && !isSessionPending ? {} : "skip", ); const createCanvas = useMutation(api.canvases.create); const [isCreatingWorkspace, setIsCreatingWorkspace] = useState(false); const [hasClientMounted, setHasClientMounted] = useState(false); useEffect(() => { setHasClientMounted(true); }, []); useEffect(() => { if (!isSessionPending && !session?.user) { router.replace("/auth/sign-in"); } }, [isSessionPending, router, session?.user]); const displayName = session?.user.name?.trim() || session?.user.email || "Nutzer"; const initials = getInitials(displayName); useEffect(() => { if (!session?.user || welcomeToastSentRef.current) return; const key = `ls-dashboard-welcome-${session.user.id}`; if (typeof window !== "undefined" && sessionStorage.getItem(key)) return; welcomeToastSentRef.current = true; sessionStorage.setItem(key, "1"); toast.success(t('auth.welcomeOnDashboard')); }, [t, session?.user]); const handleSignOut = async () => { toast.info(t('auth.signedOut')); await authClient.signOut(); router.replace("/auth/sign-in"); router.refresh(); }; const handleCreateWorkspace = async () => { if (isCreatingWorkspace) return; if (!session?.user) return; setIsCreatingWorkspace(true); try { const canvasId = await createCanvas({ name: "Neuer Workspace", description: "", }); router.push(`/canvas/${canvasId}`); } finally { setIsCreatingWorkspace(false); } }; return (
Überblick über deine Credits und laufende Generierungen.