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.
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
// frontend/components/notify/TriageStream.tsx — 트리아지 스트림 (탭 + 이유 칩 + 액션)
|
|
"use client";
|
|
import { Icon } from "@/components/Icon";
|
|
import type { Notification, NotifyBucket, Triage } from "@/lib/types";
|
|
import { SrcIcon } from "./SrcIcon";
|
|
import { WhyChip } from "./WhyChip";
|
|
|
|
const NT_TABS: { id: NotifyBucket; label: string }[] = [
|
|
{ id: "now", label: "지금" },
|
|
{ id: "later", label: "나중에" },
|
|
{ id: "held", label: "아리가 처리" },
|
|
];
|
|
const NT_CAP: Record<NotifyBucket, string> = {
|
|
now: "직접 봐야 하는 알림만 남겼어요. 나머지는 아리가 들고 있을게요.",
|
|
later: "급하지 않은 알림은 묶어서 다이제스트 시간에 전달돼요.",
|
|
held: "아리가 이미 처리한 알림이에요. 전부 되돌릴 수 있어요.",
|
|
};
|
|
|
|
export function TriageStream({
|
|
triage,
|
|
tab,
|
|
setTab,
|
|
onLater,
|
|
onUndo,
|
|
}: {
|
|
triage: Triage;
|
|
tab: NotifyBucket;
|
|
setTab: (t: NotifyBucket) => void;
|
|
onLater: (it: Notification) => void;
|
|
onUndo: (it: Notification) => void;
|
|
}) {
|
|
const list = triage[tab];
|
|
const more =
|
|
tab === "later"
|
|
? triage.counts.later - triage.later.length
|
|
: tab === "held"
|
|
? triage.counts.held - triage.held.length
|
|
: 0;
|
|
|
|
return (
|
|
<section className="card sp2 r2">
|
|
<div className="ch">
|
|
<div className="ico">
|
|
<Icon name="bell" />
|
|
</div>
|
|
<div className="htext">
|
|
<h3>트리아지</h3>
|
|
<div className="sub">아리가 분류한 오늘의 알림</div>
|
|
</div>
|
|
</div>
|
|
<div className="nt-tabs">
|
|
{NT_TABS.map((t) => (
|
|
<button
|
|
key={t.id}
|
|
className={"nt-tab" + (tab === t.id ? " on" : "")}
|
|
onClick={() => setTab(t.id)}
|
|
>
|
|
{t.label}
|
|
<span className="n">{triage.counts[t.id]}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
<div className="nt-cap">{NT_CAP[tab]}</div>
|
|
<div className="nt-list">
|
|
{list.map((it) => (
|
|
<div className="nt-row" key={it.id}>
|
|
<SrcIcon src={it.src} />
|
|
<div className="nt-body">
|
|
<div className="nt-app">
|
|
<span>{it.app}</span>
|
|
<WhyChip why={it.why} tone={it.tone} />
|
|
</div>
|
|
<div className="nt-title">{it.title}</div>
|
|
<div className="nt-sum">{it.sum}</div>
|
|
{tab === "now" && (
|
|
<div className="nt-acts">
|
|
{it.act && <button className="nt-act">{it.act}</button>}
|
|
<button className="nt-act ghost" onClick={() => onLater(it)}>
|
|
나중에
|
|
</button>
|
|
</div>
|
|
)}
|
|
{tab === "held" && (
|
|
<div className="nt-acts">
|
|
<button className="nt-act ghost" onClick={() => onUndo(it)}>
|
|
되돌리기
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<span className="nt-time">{it.time}</span>
|
|
</div>
|
|
))}
|
|
{list.length === 0 && (
|
|
<div className="nt-empty">
|
|
<Icon name="tick" />
|
|
비어 있어요. 오늘은 조용한 날이네요.
|
|
</div>
|
|
)}
|
|
</div>
|
|
{more > 0 && <div className="nt-more">비슷한 알림 +{more}건 — 아리가 묶어뒀어요</div>}
|
|
</section>
|
|
);
|
|
}
|