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.

113 lines
4.3 KiB
JavaScript

/* 아리 — 결재함 (승인 큐) 위젯
아리가 미리 해둔 일 = 되돌리기만, 위험한 일 = 승인 대기.
dash-v2.jsx에서 <ApprovalCard I={I} autonomy={...} showLog={...} /> 로 사용. */
(function () {
const { useState, useEffect } = React;
const A = window.AriApprovals;
/* autonomy: "approve"(승인 우선) | "mixed"(혼합) | "auto"(완전 자율) */
function initStatus(autonomy) {
const m = {};
A.items.forEach((it) => {
if (autonomy === "auto") m[it.id] = "done";
else if (autonomy === "mixed") m[it.id] = it.risk === "low" ? "done" : "pending";
else m[it.id] = "pending";
});
return m;
}
function ApprovalCard({ I, autonomy, showLog }) {
const [st, setSt] = useState(() => initStatus(autonomy));
useEffect(() => { setSt(initStatus(autonomy)); }, [autonomy]);
const pending = A.items.filter((it) => st[it.id] === "pending");
const done = A.items.filter((it) => st[it.id] === "done");
const approve = (id) => setSt((s) => ({ ...s, [id]: "done" }));
const undo = (id) => setSt((s) => ({ ...s, [id]: "pending" }));
const approveAll = () => setSt((s) => {
const n = { ...s };
pending.forEach((it) => { n[it.id] = "done"; });
return n;
});
return (
<section className="card appr sp2">
<div className="ch">
<div className="ico lime"><I d="spark" /></div>
<div className="htext">
<h3>아리 결재함</h3>
<div className="sub">확인만 하면 · 오늘 {A.savedToday} 아껴드렸어요</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"><I d="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": `var(--${it.tone})` }}><I d={it.icon} /></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={() => approve(it.id)}>
<I d="tick" w="3" />{it.cta || "승인"}
</button>
<button className="ap-alt">{it.alt || "나중에"}</button>
</div>
</div>
))}
{pending.length >= 2 && (
<button className="ap-all" onClick={approveAll}>
<I d="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"><I d="tick" w="3" /></span>
<span className="ad-title">{it.title}</span>
<span className="ad-time">{it.time}</span>
<button className="ad-undo" onClick={() => undo(it.id)}>
<I d="swap" />{it.undoLabel || "되돌리기"}
</button>
</div>
))}
</div>
)}
{/* ----- 활동 로그 ----- */}
{showLog && (
<div className="appr-log">
<div className="ad-label">밤사이 조용히 {A.autoCountNight}</div>
{A.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>
);
}
window.ApprovalCard = ApprovalCard;
})();