관리자 사용자 목록: 게스트 삭제 예정 시각 표시

게스트는 사이트를 나가고 하루 지나면 자동 삭제된다. 목록과 상세에
마지막 접속 + 24시간을 보여 주고, 접속 중이거나 방에 자리가 있으면 삭제 보류로 표시한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-10-08 11:13:42 +09:00
parent 2fbd956cb5
commit f93ff4f656
5 changed files with 31 additions and 2 deletions

View File

@@ -30,6 +30,9 @@ function useLoad<T>(path: string): [T | null, () => void, string | null] {
}
const time = (ms: number) => (ms ? new Date(ms).toLocaleString('ko-KR', { dateStyle: 'short', timeStyle: 'short' }) : '-');
/** Idle guests are deleted a day after they leave the site (docs/05 §5). */
const guestDeletion = (u: { kind: string; deleteAt: number | null }) =>
u.kind !== 'guest' ? null : u.deleteAt ? `삭제 예정 ${time(u.deleteAt)}` : '사이트나 방에 남아 있어 삭제 보류';
export default function AdminApp() {
const nav = useNavigate();
@@ -454,6 +457,7 @@ function Users() {
<tr key={u.id} className="clickable" onClick={() => setOpen(u.id)} tabIndex={0} onKeyDown={(e) => e.key === 'Enter' && setOpen(u.id)}>
<td>
<strong>{u.nickname}</strong>
{guestDeletion(u) && <div className="muted small">{guestDeletion(u)}</div>}
</td>
<td className="wide-only small">{u.kind === 'member' ? `디스코드 ${u.discordName ?? ''} (${u.discordId})` : '게스트'}</td>
<td>{u.role === 'superadmin' ? '슈퍼어드민' : u.role === 'admin' ? '어드민' : '-'}</td>
@@ -498,6 +502,7 @@ function UserSheet({ id, onClose }: { id: string; onClose: () => void }) {
<br />
{d.user.discordId ? `디스코드 ID ${d.user.discordId}` : '게스트'} · 가입 {time(d.user.createdAt)} · 마지막 접속 {time(d.user.lastSeenAt)}
{d.user.activeRoom && <> · 지금 방 {formatRoomCode(d.user.activeRoom)}</>}
{guestDeletion(d.user) && <> · {guestDeletion(d.user)}</>}
</p>
<p className="small">{d.stats.length ? d.stats.map((s) => `${s.gameId} ${s.played}판 ${s.wins}승`).join(' · ') : '기록 없음'}</p>
<div className="row">