"use client" import { useState, useRef, useEffect } from "react" import { Send, Bot, Sparkles, Lock, Loader2, RotateCcw, Copy, Check, Zap } from "lucide-react" import Link from "next/link" import type { Plan } from "@/types" interface Message { role: "user" | "assistant" content: string error?: boolean } const SUGGESTED = [ "Which tenants have overdue rent this month?", "Summarise my open maintenance requests", "How is my occupancy rate?", "Which leases are expiring in 60 days?", "What were my total expenses this quarter?", "Which property earns the most rent?", ] function CopyButton({ text }: { text: string }) { const [copied, setCopied] = useState(false) return ( ) } function MessageBubble({ msg }: { msg: Message }) { if (msg.role === "user") { return (

{msg.content}

) } return (

{msg.content}

{!msg.error && (
)}
) } interface AiChatProps { plan: Plan limit: number used: number } export function AiChat({ plan, limit, used }: AiChatProps) { const [messages, setMessages] = useState([]) const [input, setInput] = useState("") const [loading, setLoading] = useState(false) const [currentUsed, setCurrentUsed] = useState(used) const bottomRef = useRef(null) const inputRef = useRef(null) const isLocked = limit === 0 const isExhausted = !isLocked && currentUsed >= limit const usagePct = limit > 0 ? Math.min((currentUsed / limit) * 100, 100) : 0 useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }) }, [messages, loading]) async function send(question: string) { if (!question.trim() || loading || isLocked || isExhausted) return setMessages((prev) => [...prev, { role: "user", content: question }]) setInput("") setLoading(true) // Reset textarea height if (inputRef.current) { inputRef.current.style.height = "auto" } try { const res = await fetch("/api/ai/ask", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ question }), }) const data = await res.json() if (!res.ok) { setMessages((prev) => [...prev, { role: "assistant", content: data.error ?? "Something went wrong.", error: true }]) } else { setMessages((prev) => [...prev, { role: "assistant", content: data.answer }]) if (data.usage) setCurrentUsed(data.usage.used) } } catch { setMessages((prev) => [...prev, { role: "assistant", content: "Network error. Please try again.", error: true }]) } finally { setLoading(false) } } function handleKey(e: React.KeyboardEvent) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault() send(input) } } return (
{/* Header */}

AI Assistant

Powered by your live portfolio data

{!isLocked && (
{currentUsed} / {limit}
75 ? "bg-amber-500" : "bg-indigo-500"}`} style={{ width: `${usagePct}%` }} />
)} {messages.length > 0 && ( )}
{/* Locked state */} {isLocked ? (

AI requires Pro plan

Upgrade to unlock AI-powered insights about your properties, tenants, rent collection, and more.

Upgrade to Pro — 50 AI calls/mo Testing? Switch plan in Demo Data →
) : ( <> {/* Chat area */}
{messages.length === 0 ? (

How can I help?

I have full access to your live portfolio — properties, tenants, payments, maintenance, and leases.

Try asking

{SUGGESTED.map((q) => ( ))}
) : ( <> {messages.map((msg, i) => ( ))} {loading && (
Analysing your portfolio…
)}
)}
{/* Input */}
{isExhausted && (
Monthly limit reached. Upgrade for more calls →
)}