You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.1 KiB
TypeScript

// frontend/components/mail/MailRow.tsx — 메일 목록 행 (아바타 + AI pill)
"use client";
import { Icon } from "@/components/Icon";
import type { EmailRow, MailAccount, Person } from "@/lib/types";
export function aiCount(m: EmailRow): number {
return m.ai ? m.ai.tasks.length + m.ai.events.length + (m.ai.replies.length ? 1 : 0) : 0;
}
export function MailRow({
m,
person,
account,
accColor,
on,
onClick,
onStar,
}: {
m: EmailRow;
person?: Person;
account?: MailAccount;
accColor?: string; // 계정별 구분 색(계정 tone 이 겹치므로 팔레트에서 배정)
on: boolean;
onClick: () => void;
onStar: (id: string) => void;
}) {
// 표시 이름: 연락처(person) > 백엔드 표시이름(from_name) > 원문(from). 메일주소 대신 이름.
const name = person?.name ?? (m.from_name || m.from);
// 아바타는 '어느 계정' 표시 — 계정 색 + 계정 이니셜(색 dot 대신 명확하게).
const accName = account?.name ?? m.account;
const accInitial = accName.slice(0, 1).toUpperCase();
const color = accColor ?? (account?.tone ? `var(--${account.tone})` : "var(--muted)");
const showPills = m.ai && (m.ai.priority === "높음" || aiCount(m) > 0);
return (
<div className={"mrow" + (on ? " on" : "") + (m.read ? "" : " unread")} onClick={onClick}>
<div className="mr-ava" style={{ background: color }} title={`${accName} · ${account?.email ?? ""}`}>
{accInitial}
</div>
<div className="mr-body">
<div className="mr-top">
<span className="mr-from">
<b>{name}</b>
</span>
<span className="mr-time">{m.time}</span>
</div>
<div className="mr-subj">{m.subject}</div>
<div className="mr-prev">{m.preview}</div>
{showPills && m.ai && (
<div className="mr-tags">
{m.ai.priority === "높음" && (
<span className="ai-pill prio">
<Icon name="flag" />
</span>
)}
{m.ai.tasks.length > 0 && (
<span className="ai-pill task">
<Icon name="check" /> {m.ai.tasks.length}
</span>
)}
{m.ai.events.length > 0 && (
<span className="ai-pill event">
<Icon name="cal" />
{m.ai.events.length}
</span>
)}
{m.ai.replies.length > 0 && (
<span className="ai-pill reply">
<Icon name="reply" />
</span>
)}
</div>
)}
</div>
<div className="mr-flags">
<button
className={"mr-star" + (m.starred ? " on" : "")}
onClick={(e) => {
e.stopPropagation();
onStar(m.id);
}}
aria-label="별표"
>
<Icon name="star" w={m.starred ? 0 : 1.9} fill={m.starred ? "currentColor" : "none"} />
</button>
{m.has_attach && (
<span className="mr-attach">
<Icon name="clip" />
</span>
)}
</div>
</div>
);
}