From f289d4a4d67acb40da37d71b0f168ee9b0572963 Mon Sep 17 00:00:00 2001 From: debu-2 Date: Sun, 4 Oct 2026 00:44:58 +0530 Subject: [PATCH] right side --- frontend/src/components/AgAgentPanel.jsx | 279 ++++++++++++++--------- frontend/src/styles.css | 20 ++ 2 files changed, 195 insertions(+), 104 deletions(-) diff --git a/frontend/src/components/AgAgentPanel.jsx b/frontend/src/components/AgAgentPanel.jsx index 8927f0b..2833582 100644 --- a/frontend/src/components/AgAgentPanel.jsx +++ b/frontend/src/components/AgAgentPanel.jsx @@ -1,7 +1,6 @@ import { useState } from "react"; import { Calendar, - Check, ChevronDown, ChevronRight, FileSearch, @@ -18,12 +17,14 @@ import SenderAvatar from "./SenderAvatar"; import { inboxContext } from "../utils/inboxSignals"; const ICON = { size: 14, strokeWidth: 1.75 }; +const AGENDA_SLOTS = 3; +const ATTENTION_SLOTS = 2; const cards = [ - { key: "important", label: "Important emails", captionKey: "importantFromClients", captionSuffix: "from clients", icon: Mail, tone: "rose" }, - { key: "actionItems", label: "Action items", hint: "Need your response", icon: ListChecks, tone: "blue" }, - { key: "meetings", label: "Meetings mentioned", hint: "In your emails", icon: Calendar, tone: "green" }, - { key: "invoices", label: "Invoices & bills", hint: "This week", icon: Receipt, tone: "amber" }, + { key: "important", label: "Important emails", captionKey: "importantFromClients", captionSuffix: "from clients", emptyCaption: "No priority mail yet", icon: Mail, tone: "rose" }, + { key: "actionItems", label: "Action items", hint: "Need your response", emptyCaption: "Nothing pending", icon: ListChecks, tone: "blue" }, + { key: "meetings", label: "Meetings mentioned", hint: "In your emails", emptyCaption: "No meetings found", icon: Calendar, tone: "green" }, + { key: "invoices", label: "Invoices & bills", hint: "This week", emptyCaption: "No invoices detected", icon: Receipt, tone: "amber" }, ]; function greeting(name) { @@ -32,6 +33,70 @@ function greeting(name) { return `${period}, ${name}`; } +function statCaption(card, stats) { + const count = stats[card.key] || 0; + if (count === 0) return card.emptyCaption || card.hint; + if (card.captionKey && stats[card.captionKey] > 0) { + return `${stats[card.captionKey]} ${card.captionSuffix}`; + } + return card.hint; +} + +function padSlots(items, slots) { + const result = items.slice(0, slots).map((item) => ({ ...item, placeholder: false })); + while (result.length < slots) { + result.push({ placeholder: true, id: `slot-${result.length}` }); + } + return result; +} + +function AgendaPlaceholder({ index }) { + return ( +
  • 0}> +
  • + ); +} + +function AttentionPlaceholder({ index, showEmptyMessage }) { + return ( +
  • 0 && !showEmptyMessage}> + {showEmptyMessage && index === 0 ? ( + <> +
  • + ); +} + export default function AgAgentPanel({ account, emails, @@ -45,9 +110,8 @@ export default function AgAgentPanel({ const [agentQuery, setAgentQuery] = useState(""); const [panelOpen, setPanelOpen] = useState(true); const firstName = account?.first_name || "there"; - const activeCards = cards.filter((card) => (stats[card.key] || 0) > 0); - const hasContext = needsReply.length > 0 || today.length > 0 || deadlines.length > 0; - const hasSignals = activeCards.length > 0 || hasContext; + const agendaSlots = padSlots(today, AGENDA_SLOTS); + const attentionSlots = padSlots(needsReply, ATTENTION_SLOTS); function submitAgentQuery(event) { event.preventDefault(); @@ -80,138 +144,145 @@ export default function AgAgentPanel({ {panelOpen && (
    - {!insight && hasSignals && ( + {!insight && (
    {greeting(firstName)} Here's what needs your attention today.
    )} - {!insight && !hasSignals && ( -
    -

    You're all caught up.

    -

    No urgent messages or outstanding actions.

    - Inbox is quiet right now. -
    - )} - - {!insight && activeCards.length > 0 && ( + {!insight && (
    - {activeCards.map((card) => { + {cards.map((card) => { const Icon = card.icon; const count = stats[card.key] || 0; - const caption = card.captionKey && stats[card.captionKey] - ? `${stats[card.captionKey]} ${card.captionSuffix}` - : card.hint; + const isEmpty = count === 0; return ( ); })}
    )} - {!insight && focus && hasSignals &&

    {focus}

    } + {!insight && focus &&

    {focus}

    }
    -

    Quick actions

    -
    - - - - +

    Quick actions

    +
    + + + + +
    -
    - {!insight && today.length > 0 && ( -
    -
    -

    Today's agenda

    - -
    -
      - {today.map((item) => ( -
    • -
    • - ))} -
    -
    + {!insight && ( +
    +
    +

    Today's agenda

    + +
    +
      + {agendaSlots.map((item, index) => ( + item.placeholder ? ( + + ) : ( +
    • +
    • + ) + ))} +
    +
    )} - {!insight && needsReply.length > 0 && ( -
    -

    Needs attention

    -
      - {needsReply.slice(0, 3).map((item) => ( -
    • - -
    • - ))} -
    -
    + {!insight && ( +
    +

    Needs attention

    +
      + {attentionSlots.map((item, index) => ( + item.placeholder ? ( + + ) : ( +
    • + +
    • + ) + ))} +
    +
    )} {!insight && deadlines.length > 0 && ( -
    -

    Deadlines

    -
      - {deadlines.map((item) => ( -
    • - {item.label} - {item.due} -
    • - ))} -
    -
    +
    +

    Deadlines

    +
      + {deadlines.map((item) => ( +
    • + {item.label} + {item.due} +
    • + ))} +
    +
    )}
    - setAgentQuery(event.target.value)} - placeholder="Ask about your emails..." - /> - - + setAgentQuery(event.target.value)} + placeholder="Ask about your emails..." + /> + +
    )} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index d1e682b..392acf5 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -619,6 +619,10 @@ h1 em { color:var(--coral); font-style:normal; font-weight:500; } .agent-stat-blue { background:linear-gradient(180deg,#f3f7ff 0%,#eaf1ff 100%); border-color:#d5e2f8; color:#4d74c4; } .agent-stat-green { background:linear-gradient(180deg,#f1faf4 0%,#e8f5ed 100%); border-color:#cfe8d8; color:#3d8a5d; } .agent-stat-amber { background:linear-gradient(180deg,#f7f2ff 0%,#efe8ff 100%); border-color:#ddd0f5; color:#8b6fd4; } +.agent-stat-empty { opacity:.72; cursor:default; } +.agent-stat-empty:hover { transform:none; box-shadow:none; } +.agent-stat-empty strong { color:#b5b0ba; } +.agent-stat-empty small { color:#a39ea8; } .agent-quick { margin-top:var(--space-1); padding-top:var(--space-3); border-top:1px solid var(--border-subtle); } .agent-quick h3 { margin:0 0 10px; color:#7a7580; font-size:10px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; } .agent-quick div { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-2); } @@ -657,6 +661,22 @@ h1 em { color:var(--coral); font-style:normal; font-weight:500; } .agent-agenda-row time { display:block; color:#8d8792; font-size:10px; font-weight:600; } .agent-agenda-row strong { display:block; color:#2a2530; font-size:var(--text-meta); font-weight:600; line-height:1.3; } .agent-agenda-row small { display:block; color:#8d8792; font-size:10px; } +.agent-placeholder-row { border-style:dashed; background:#fafafa; pointer-events:none; } +.agent-placeholder-row .agent-agenda-bar.placeholder { background:#e4e0dc; min-height:36px; } +.agent-placeholder-row time,.agent-placeholder-row strong,.agent-placeholder-row small { color:#b8b3bc; } +.agent-placeholder-row strong { font-weight:500; } +.agent-placeholder-copy { min-width:0; display:grid; gap:5px; align-content:center; } +.agent-placeholder-line { display:block; height:8px; border-radius:var(--radius-pill); background:linear-gradient(90deg,#ece8e4 0%,#f4f1ee 100%); } +.agent-placeholder-line.wide { width:78%; } +.agent-placeholder-line.narrow { width:42%; } +.agent-attention-placeholder { padding:10px 0; display:grid; grid-template-columns:30px 1fr 24px; align-items:center; gap:var(--space-2); border-bottom:1px solid var(--border-subtle); pointer-events:none; } +.agent-attention-placeholder:last-child { border-bottom:0; } +.agent-placeholder-avatar { width:30px; height:30px; border-radius:50%; background:linear-gradient(180deg,#ece8e4 0%,#e2deda 100%); } +.agent-placeholder-avatar.muted { background:linear-gradient(180deg,#f0ece8 0%,#e8e4e0 100%); } +.agent-placeholder-label { color:#b8b3bc; font-size:var(--text-meta); font-weight:600; } +.agent-placeholder-copy small { color:#c5c0ba; font-size:10px; } +.agent-placeholder-age { width:20px; height:8px; border-radius:var(--radius-pill); background:#ece8e4; } +.agent-attention-block .agent-attention-list:has(.agent-attention-placeholder) .agent-attention-placeholder:first-child .agent-placeholder-line.wide { width:65%; } .agent-attention-name { color:#2a2530; font-size:var(--text-meta); font-weight:600; } .agent-attention-meta { color:#8d8792; font-size:10px; } .agent-attention-list button:hover .agent-attention-name { color:var(--coral); }