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.
119 lines
3.8 KiB
TypeScript
119 lines
3.8 KiB
TypeScript
// frontend/components/approvals/ApprovalCard.tsx — approve.jsx 이식
|
|
"use client";
|
|
import { Icon } from "@/components/Icon";
|
|
import type { IconName } from "@/components/icons/paths";
|
|
import type { ApprovalOut } from "@/lib/types";
|
|
|
|
type Props = {
|
|
saved: string;
|
|
pending: ApprovalOut[];
|
|
done: ApprovalOut[];
|
|
autoCountNight?: number;
|
|
log?: { time: string; text: string }[];
|
|
showLog?: boolean;
|
|
onApprove: (id: string) => void;
|
|
onUndo: (id: string) => void;
|
|
onApproveAll: () => void;
|
|
};
|
|
|
|
export function ApprovalCard({
|
|
saved,
|
|
pending,
|
|
done,
|
|
autoCountNight,
|
|
log,
|
|
showLog,
|
|
onApprove,
|
|
onUndo,
|
|
onApproveAll,
|
|
}: Props) {
|
|
return (
|
|
<section className="card appr sp2">
|
|
<div className="ch">
|
|
<div className="ico lime">
|
|
<Icon name="spark" />
|
|
</div>
|
|
<div className="htext">
|
|
<h3>아리 결재함</h3>
|
|
<div className="sub">확인만 하면 끝 · 오늘 {saved} 아껴드렸어요</div>
|
|
</div>
|
|
{pending.length > 0 ? (
|
|
<span className="count warm">대기 {pending.length}건</span>
|
|
) : (
|
|
<span className="count">모두 처리됨</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* 승인 대기 */}
|
|
{pending.length === 0 ? (
|
|
<div className="appr-empty">
|
|
<span className="ae-tick">
|
|
<Icon name="tick" w={3} />
|
|
</span>
|
|
결재할 게 없어요 — 아리가 알아서 하고 있어요. 아래에서 언제든 되돌릴 수 있어요.
|
|
</div>
|
|
) : (
|
|
<div className="appr-list">
|
|
{pending.map((it) => (
|
|
<div className="ap-row" key={it.id}>
|
|
<div className="ap-ic" style={{ ["--tone" as string]: `var(--${it.tone})` }}>
|
|
<Icon name={it.icon as IconName} />
|
|
</div>
|
|
<div className="ap-body">
|
|
<div className="ap-title">{it.title}</div>
|
|
<div className="ap-detail">{it.detail}</div>
|
|
</div>
|
|
<div className="ap-acts">
|
|
<button className="ap-ok" onClick={() => onApprove(it.id)}>
|
|
<Icon name="tick" w={3} />
|
|
{it.cta || "승인"}
|
|
</button>
|
|
<button className="ap-alt">{it.alt || "나중에"}</button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
{pending.length >= 2 && (
|
|
<button className="ap-all" onClick={onApproveAll}>
|
|
<Icon name="tick" w={3} />
|
|
모두 승인 ({pending.length}건)
|
|
</button>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* 자동 처리됨 (되돌리기) */}
|
|
{done.length > 0 && (
|
|
<div className="appr-done">
|
|
<div className="ad-label">처리됨 — 탭 한 번으로 되돌릴 수 있어요</div>
|
|
{done.map((it) => (
|
|
<div className="ad-row" key={it.id}>
|
|
<span className="ad-tick">
|
|
<Icon name="tick" w={3} />
|
|
</span>
|
|
<span className="ad-title">{it.title}</span>
|
|
<span className="ad-time">{it.time}</span>
|
|
<button className="ad-undo" onClick={() => onUndo(it.id)}>
|
|
<Icon name="swap" />
|
|
{it.undo_label || "되돌리기"}
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* 활동 로그(대시보드 위젯에서만 showLog=true) */}
|
|
{showLog && log && (
|
|
<div className="appr-log">
|
|
<div className="ad-label">밤사이 조용히 한 일 {autoCountNight}건</div>
|
|
{log.map((l, i) => (
|
|
<div className="al-row" key={i}>
|
|
<span className="al-time">{l.time}</span>
|
|
<span className="al-text">{l.text}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</section>
|
|
);
|
|
}
|