Files
Aislo/B01_Dashboard/logic/B01_Dashboard_Logic_Pages.ts
T

75 lines
2.8 KiB
TypeScript

/* =============================================================================
* B01_Dashboard_Logic_Pages.ts
* 대시보드 세부 페이지 계산(549-1) — 화면 · fetch 없음 · Node 로 바로 시험.
* 배지 글(역할 · 상태) · 보관함 남은 날 · 가입 요청 수.
* ========================================================================== */
export type BadgeTone = "accent" | "neutral" | "success" | "warning" | "danger";
const DAY_MS = 86_400_000;
/** 역할 → 한글 */
export function roleText(role: string | null | undefined): string {
if (role === "SYSTEM_ADMIN") return "시스템 관리자";
if (role === "ADMIN") return "회사 관리자";
if (role === "USER") return "일반 사용자";
return role ?? "-";
}
/** 상태 → 한글 · 배지 색 (모르는 값은 그대로 · 회색) */
export function statusBadgeOf(status: string | null | undefined): {
text: string;
tone: BadgeTone;
} {
switch ((status ?? "").toUpperCase()) {
case "ACTIVE":
return { text: "활성", tone: "success" };
case "INACTIVE":
return { text: "비활성", tone: "neutral" };
case "PENDING":
return { text: "대기", tone: "warning" };
case "APPROVED":
return { text: "승인", tone: "success" };
case "REJECTED":
return { text: "거절", tone: "danger" };
default:
return { text: status || "-", tone: "neutral" };
}
}
/** 남은 날 — 만료 시각까지 올림 일수 · 지난 것 0 · 만료 없음 null */
export function daysLeft(
expiresAt: string | null | undefined,
now: number = Date.now(),
): number | null {
if (!expiresAt) return null;
const at = new Date(expiresAt).getTime();
if (Number.isNaN(at)) return null;
return Math.max(0, Math.ceil((at - now) / DAY_MS));
}
/** 막대 채움 0~100 — 남은 날 ÷ 보관 기간 */
export function leftPercent(left: number | null, retentionDays: number): number {
if (left === null || retentionDays <= 0) return 0;
return Math.max(0, Math.min(100, Math.round((left / retentionDays) * 100)));
}
/** 7 일 안 만료 = 강조 */
export const EXPIRY_WARN_DAYS = 7;
export const isExpiringSoon = (left: number | null): boolean =>
left !== null && left <= EXPIRY_WARN_DAYS;
/** 가입 요청 중 처리할 것(대기) 수 — 상태 값이 없으면 대기로 봄 */
export function pendingCount(requests: { status?: string | null }[]): number {
return requests.filter((r) => !r.status || r.status.toUpperCase() === "PENDING").length;
}
/** 바이트 → 글 */
export function bytesText(bytes: number): string {
const gb = bytes / 1024 / 1024 / 1024;
if (gb >= 1) return `${gb.toFixed(2)} GB`;
const mb = bytes / 1024 / 1024;
if (mb >= 1) return `${mb.toFixed(1)} MB`;
return `${Math.max(1, Math.round(bytes / 1024))} KB`;
}