"use client" import { AnimatePresence, motion } from "motion/react" import { useEffect, useState } from "react" import { CheckIcon, CopyIcon, FileTextIcon, LoaderCircleIcon, MailIcon, RotateCcwIcon } from "lucide-react" import { cn } from "@/lib/utils" import type { DemoInfo } from "../demo-info" import type { AiAccess } from "../demos" import type { Quote } from "../schemas" import { readNdjson } from "./use-ai-chat" type Mode = "email" | "quote" type QuoteView = Quote & { number: string; date: Date } const steps: Record = { email: ["Anfrage verstehen", "Passende Infos heraussuchen", "Antwort formulieren"], quote: ["Anfrage analysieren", "Positionen ableiten", "Preise kalkulieren", "Angebot gestalten"], } const euro = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }) const day = new Intl.DateTimeFormat("de-DE", { dateStyle: "long" }) function quoteNumber(text: string, year: number) { let hash = 0 for (const char of text) hash = (hash * 31 + char.charCodeAt(0)) | 0 return `A-${year}-${(Math.abs(hash) % 9000) + 1000}` } export function AssistantDemo({ access, info }: { access: AiAccess; info: DemoInfo }) { const [inquiry, setInquiry] = useState(info.samples.inquiry) const [mode, setMode] = useState("email") const [email, setEmail] = useState("") const [quote, setQuote] = useState(null) const [pending, setPending] = useState(false) const [step, setStep] = useState(0) const [error, setError] = useState(null) const [copied, setCopied] = useState(false) useEffect(() => { if (!pending) return const timer = setInterval(() => setStep((s) => s + 1), 1600) return () => clearInterval(timer) }, [pending]) async function run(next: Mode) { setMode(next) setPending(true) setStep(0) setError(null) try { if (next === "email") { setEmail("") const response = await fetch("/api/ai/generate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ task: "email", access, inquiry }), }) await readNdjson(response, (event) => { if (event.type === "error") throw new Error(event.message) if (event.type === "text") setEmail((text) => text + event.text) }) } else { setQuote(null) const response = await fetch("/api/ai/generate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ task: "quote", access, inquiry }), }) const data = (await response.json().catch(() => null)) as { result?: Quote; error?: string } | null if (!response.ok || !data?.result) throw new Error(data?.error ?? "Die KI ist gerade nicht erreichbar.") const today = new Date() setQuote({ ...data.result, number: quoteNumber(inquiry, today.getFullYear()), date: today }) } } catch (cause) { setError(cause instanceof Error ? cause.message : "Die KI ist gerade nicht erreichbar.") } finally { setPending(false) } } async function copy(text: string) { await navigator.clipboard.writeText(text).catch(() => undefined) setCopied(true) setTimeout(() => setCopied(false), 1500) } const subjectLine = email.match(/^Betreff:\s*(.*)$/m) const subject = subjectLine?.[1]?.trim() ?? "" const body = subject ? email.replace(/^Betreff:.*\n?/m, "").replace(/^\n+/, "") : email const showLoader = pending && (mode === "quote" || !email) return (

Kundenanfrage

Eigene Anfrage einfügen oder das Beispiel nutzen.