"use client"; // ============================================================ // AI Assistant — "Lynk AI", a creative conversational copilot. // · Empty state : warm greeting, capability cards, prompt chips // · Active chat : message thread with a typing indicator and a // simulated, keyword-aware assistant reply // · Composer : auto-suggesting prompt row + send / new chat // All responses are canned + client-side so it demos with no API. // ============================================================ import { useEffect, useRef, useState } from "react"; import { user } from "./account-data"; import { Avatar, Btn, Icon, Pill, useToast } from "./ui"; type Msg = { id: number; from: "me" | "ai"; text: string }; const CAPABILITIES = [ { icon: "leads", tone: "var(--orange)", title: "Qualify leads", desc: "Score and summarise new leads, draft the first outreach." }, { icon: "estimates", tone: "var(--blue)", title: "Build estimates", desc: "Turn scope notes into a clean, line-itemed proposal." }, { icon: "schedule", tone: "var(--green)", title: "Plan the week", desc: "Suggest a crew schedule around weather and priorities." }, { icon: "leaderboard", tone: "var(--purple)", title: "Analyse pipeline", desc: "Spot stalled deals and where revenue is leaking." }, ]; const PROMPTS = [ { icon: "leads", text: "Summarise my new leads from this week" }, { icon: "estimates", text: "Draft an estimate for a 28-square asphalt reroof" }, { icon: "storm", text: "Which territories were hit by the last storm?" }, { icon: "pipeline", text: "Show deals stuck in the pipeline over 14 days" }, ]; let msgSeq = 1; export function AiAssistant() { const toast = useToast(); const [messages, setMessages] = useState([]); const [draft, setDraft] = useState(""); const [typing, setTyping] = useState(false); const scrollRef = useRef(null); const timer = useRef | null>(null); const started = messages.length > 0; useEffect(() => { scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" }); }, [messages, typing]); useEffect(() => () => { if (timer.current) clearTimeout(timer.current); }, []); function send(text: string) { const body = text.trim(); if (!body || typing) return; setMessages((m) => [...m, { id: msgSeq++, from: "me", text: body }]); setDraft(""); setTyping(true); timer.current = setTimeout(() => { setMessages((m) => [...m, { id: msgSeq++, from: "ai", text: replyFor(body) }]); setTyping(false); }, 1100); } function reset() { if (timer.current) clearTimeout(timer.current); setMessages([]); setDraft(""); setTyping(false); } return (
LynkedUp Pro

Lynk AI Beta

Opus 4.8 {started && New chat}
{!started ? (

{greeting()}, {user.firstName}.

I'm your roofing copilot. Ask me to summarise leads, draft estimates, plan crews or dig into your pipeline.

{CAPABILITIES.map((c) => ( ))}
Try asking
{PROMPTS.map((p) => ( ))}
) : (
{messages.map((m) => (
{m.from === "ai" ? : }
{m.text.split("\n").map((line, i) =>

{line}

)} {m.from === "ai" && (
)}
))} {typing && (
)}
)}
{started && (
{PROMPTS.slice(0, 3).map((p) => ( ))}
)}