-
+
{KIND_LABEL[it.kind] ?? it.kind}
-
{it.title}
+
{it.title}
- {it.summary &&
{it.summary}
}
+ {it.summary &&
{it.summary}
}
- {it.state === "OPEN" ? (
-
+ {it.state !== "OPEN" &&
{it.state.toLowerCase()}}
+
+ );
+}
+
+function Detail({ it, onError, onDone, onSnooze, onArchive }: {
+ it: UiInboxItem; onError: (m: string) => void; onDone: () => void; onSnooze: () => void; onArchive: () => void;
+}) {
+ return (
+ <>
+ {/* Item actions bar (works for every item, threaded or not) */}
+ {it.state === "OPEN" && (
+
Snooze
Done
Archive
- ) : (
-
{it.state.toLowerCase()}
)}
-
+
+ {it.threadId ? (
+ // A message/mail item → open the conversation to read + reply.
+
+
+
+ ) : (
+ // A non-threaded item (e.g. a system alert) → show its detail.
+
+
{it.title}
+ {it.summary &&
{it.summary}
}
+
+ )}
+ >
);
}
diff --git a/src/components/dashboard/mail.tsx b/src/components/dashboard/mail.tsx
index 8fd4c8e..500d4ce 100644
--- a/src/components/dashboard/mail.tsx
+++ b/src/components/dashboard/mail.tsx
@@ -1,16 +1,15 @@
"use client";
// ============================================================
-// Mail — a dedicated reader for app-to-app and email messages,
-// powered by IIOS via the be-crm data door (crm.mail.*). Distinct
-// from Messenger (chat) and from the work-item Inbox: this shows the
-// actual mail (subject + rendered body) and lets you read + reply +
-// compose. HTML bodies render inside a sandboxed iframe (no scripts).
+// Mail components used INSIDE the Inbox (not a separate tab).
+// The Inbox is the one unified surface — mentions, system messages
+// and mail all live there. These render the mail body + reply, and
+// compose a new message. HTML bodies render in a sandboxed iframe.
// ============================================================
import { type CSSProperties, useEffect, useState } from "react";
-import { Avatar, Btn, Field, Icon, Modal, PageHead, Pill, useToast } from "./ui";
-import { useMailThreads, useMailThread, useMailCompose, type MailThread, type MailPerson } from "@/lib/mail-api";
+import { Avatar, Btn, Field, Icon, Modal, Pill } from "./ui";
+import { useMailThread, useMailCompose, type MailPerson } from "@/lib/mail-api";
const timeOf = (iso?: string) => {
if (!iso) return "";
@@ -23,87 +22,9 @@ const inputStyle: CSSProperties = {
background: "var(--panel)", color: "var(--text)", fontSize: 14, outline: "none",
};
-export function Mail() {
- const list = useMailThreads();
- const toast = useToast();
- const [selected, setSelected] = useState
(null);
- const [newOpen, setNewOpen] = useState(false);
-
- useEffect(() => {
- if ((!selected || !list.threads.some((t) => t.threadId === selected)) && list.threads[0]) {
- setSelected(list.threads[0].threadId);
- }
- }, [list.threads, selected]);
-
- const current = list.threads.find((t) => t.threadId === selected) ?? null;
-
- return (
-
-
setNewOpen(true)}>New mail}
- />
- {!list.live && (
-
- Demo mode — running on mock data. It goes live once the Shell + be-crm are connected.
-
- )}
-
-
-
-
-
- {current ? (
- toast.push({ tone: "error", title: "Failed", desc: m })} />
- ) : (
-
-
Select or compose a message
-
- )}
-
-
-
- setNewOpen(false)}
- onSent={() => { setNewOpen(false); list.refetch(); toast.push({ tone: "success", title: "Sent" }); }}
- onError={(m) => toast.push({ tone: "error", title: "Couldn't send", desc: m })}
- />
-
- );
-}
-
-function ThreadRow({ t, active, onClick }: { t: MailThread; active: boolean; onClick: () => void }) {
- return (
-
- );
-}
-
-function Reader({ thread, onError }: { thread: MailThread; onError: (m: string) => void }) {
- const t = useMailThread(thread.threadId);
+/** Reader + reply for one mail thread. Used in the Inbox detail pane when an item has a threadId. */
+export function MailReader({ threadId, subject, onError }: { threadId: string; subject: string; onError: (m: string) => void }) {
+ const t = useMailThread(threadId);
const [draft, setDraft] = useState("");
const [sending, setSending] = useState(false);
@@ -117,29 +38,26 @@ function Reader({ thread, onError }: { thread: MailThread; onError: (m: string)
}
return (
- <>
-