From b57187a6a30b5f8057361b5129a97ed822bfa61a Mon Sep 17 00:00:00 2001 From: Juan Franco <91078895+m1lestones@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:28:57 -0400 Subject: [PATCH 1/3] fix: copilot UI polish and error handling - Iris greets user by first name above prompt buttons - Panel anchors to bottom-right above bubble (no longer flies to top) - Bubble default position raised 48px from bottom edge - Replaced 'Draft an outreach email' with admin/AE-specific prompts - Fixed duplicate React keys in IrisMessage renderer - Copilot route now surfaces actual Anthropic error messages --- apps/web/src/app/api/copilot/route.ts | 6 ++++ apps/web/src/components/CoPilot.tsx | 51 ++++++++++++++++----------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/apps/web/src/app/api/copilot/route.ts b/apps/web/src/app/api/copilot/route.ts index 4ceea85..07f1dd2 100644 --- a/apps/web/src/app/api/copilot/route.ts +++ b/apps/web/src/app/api/copilot/route.ts @@ -136,6 +136,12 @@ ${signalsContext}`; }); const data = await res.json(); + if (!res.ok || data?.type === 'error') { + console.error('Anthropic API error:', JSON.stringify(data)); + return NextResponse.json({ + reply: `Iris error: ${data?.error?.message ?? data?.error?.type ?? 'Unknown error from Anthropic API'}`, + }); + } const reply = data?.content?.[0]?.text ?? 'No response.'; return NextResponse.json({ reply }); } diff --git a/apps/web/src/components/CoPilot.tsx b/apps/web/src/components/CoPilot.tsx index 00a81ee..a502542 100644 --- a/apps/web/src/components/CoPilot.tsx +++ b/apps/web/src/components/CoPilot.tsx @@ -13,6 +13,7 @@ function IrisMessage({ text }: { text: string }) { const lines = text.split('\n'); const nodes: React.ReactNode[] = []; let i = 0; + let k = 0; while (i < lines.length) { const line = lines[i] ?? ''; @@ -31,7 +32,7 @@ function IrisMessage({ text }: { text: string }) { i++; } nodes.push( -
+
{renderInline(line)}
); @@ -131,7 +132,7 @@ function defaultPos() { const isMobile = window.innerWidth < 768; return { x: window.innerWidth - BUBBLE_SIZE - (isMobile ? 16 : 24), - y: window.innerHeight - BUBBLE_SIZE - (isMobile ? 88 : 24), + y: window.innerHeight - BUBBLE_SIZE - (isMobile ? 96 : 48), }; } @@ -146,7 +147,7 @@ export default function CoPilot() { const [pulsing, setPulsing] = useState(false); const [hasUnread, setHasUnread] = useState(false); // null = not yet mounted (SSR safe) - const { userId, isAdmin } = useUser(); + const { userId, isAdmin, userName } = useUser(); const [pos, setPos] = useState<{ x: number; y: number } | null>(null); const bottomRef = useRef+ Hi {userName.split(' ')[0]}, what do you need? +
+ )} - {[ - 'Who should I call this week?', - 'Draft an outreach email for Ascension', - "What's urgent across my accounts?", - ].map((prompt) => ( + {(isAdmin + ? [ + 'Draft my weekly digest', + "What's urgent across all accounts?", + 'Which AEs need a follow-up this week?', + ] + : [ + 'Who should I call this week?', + 'Summarize my most important account', + "What's urgent across my accounts?", + ] + ).map((prompt) => (