Files
Aislo/B01_Dashboard/B01_Dashboard_UI_View_Trash.ts
T

113 lines
4.0 KiB
TypeScript

/* =============================================================================
* B01_Dashboard_UI_View_Trash.ts
* 휴지통(592) — 지운 프로젝트 표(이름 · 종류 · 회사 · 지운 사람 · 지운 시각 · 남은 날) + [되살리기] · [영구 삭제].
* 시스템 관리자 = 전부 · 영구 삭제까지 · 회사 관리자 = 자기 회사 것 되살리기만(서버가 거름).
* 남은 날이 다 되면 서버 정리 루프가 DB 행 · 폴더째 지움.
* ========================================================================== */
import { askConfirm } from "@ui/ui_template_modal";
import { showToast } from "@ui/ui_template_toast";
import { createButton } from "@ui/ui_template_elements";
import {
fetchTrashProjects,
purgeTrashProject,
restoreTrashProject,
type TrashProject,
} from "./B01_Dashboard_Api_Fetch";
import { formatDate, formatTime } from "./B01_Dashboard_UI_Common";
import { badge, dataTable, emptyState, nameCell, pageFrame } from "./B01_Dashboard_UI_PageKit";
import { kindBadge } from "./B01_Dashboard_UI_ProjectList_Parts";
import { el as h, loadPage } from "./B01_Dashboard_UI_View_Parts";
import type { ViewCtx } from "./B01_Dashboard_UI_Views";
const COLUMNS = [
{ label: "이름" },
{ label: "종류" },
{ label: "회사" },
{ label: "지운 사람" },
{ label: "지운 시각" },
{ label: "남은 날" },
{ label: "관리", align: "end" as const },
];
export function mountTrash(host: HTMLElement, ctx: ViewCtx): void {
const admin = ctx.role === "SYSTEM_ADMIN";
const run = (): void =>
loadPage(host, async (stage) => {
const rows = await fetchTrashProjects();
const frame = pageFrame(
stage,
"휴지통",
"지운 프로젝트는 7 일 동안 여기 있다가 자료째 영구 삭제됩니다. 그 전에 되살릴 수 있습니다.",
);
const act = async (
p: TrashProject,
ask: string,
call: (id: string) => Promise<unknown>,
done: string,
danger = false,
): Promise<void> => {
if (!(await askConfirm({ title: p.name, message: ask, danger }))) return;
try {
await call(p.id);
showToast(done, "success");
} catch (error) {
showToast(error instanceof Error ? error.message : "처리하지 못했습니다.", "error");
}
run();
};
const actions = (p: TrashProject): HTMLElement => {
const box = h("div", "b01-sys-tool");
box.style.justifyContent = "flex-end";
box.append(
createButton({
label: "되살리기",
variant: "ghost",
size: 28,
onClick: () =>
void act(
p,
"프로젝트를 되살려 목록에 다시 보이게 합니다.",
restoreTrashProject,
"되살렸습니다.",
),
}),
);
if (admin)
box.append(
createButton({
label: "영구 삭제",
variant: "danger-ghost",
size: 28,
onClick: () =>
void act(
p,
"DB 자료와 프로젝트 폴더를 지금 영구 삭제합니다. 되돌릴 수 없습니다.",
purgeTrashProject,
"영구 삭제했습니다.",
true,
),
}),
);
return box;
};
frame.body.append(
rows.length
? dataTable(
COLUMNS,
rows.map((p) => [
p.name,
kindBadge(p.project_kind),
p.company_name ?? "-",
nameCell(p.deleted_by_name ?? "-", p.deleted_by_email),
`${formatDate(p.deleted_at)} ${formatTime(p.deleted_at)}`.trim(),
badge(`${p.days_left} 일`, p.days_left <= 1 ? "danger" : "neutral"),
actions(p),
]),
)
: emptyState({ icon: "trash", text: "휴지통이 비어 있습니다." }),
);
});
run();
}