fix: align access console status actions

This commit is contained in:
unknown
2026-07-22 19:04:54 +09:00
parent e01beea64c
commit ed972a318d
2 changed files with 40 additions and 10 deletions

View File

@@ -21,7 +21,7 @@ function accessBadge(record: AccessRecord): { className: string; label: string }
} }
const status = record.status ?? 'APPROVED'; const status = record.status ?? 'APPROVED';
if (status === 'APPROVED') { if (status === 'APPROVED') {
return { className: 'amber', label: '입장대기' }; return { className: STATUS_CLASS.APPROVED, label: STATUS_LABEL.APPROVED };
} }
return { className: STATUS_CLASS[status], label: STATUS_LABEL[status] }; return { className: STATUS_CLASS[status], label: STATUS_LABEL[status] };
} }
@@ -146,7 +146,7 @@ export const AccessConsolePage: React.FC = () => {
<span className="badge badge-gray"></span> <span className="badge badge-gray"></span>
) : ( ) : (
<span className="status-cell"> <span className="status-cell">
<span className="badge badge-amber"></span> <span className={`badge badge-${STATUS_CLASS.APPROVED}`}>{STATUS_LABEL.APPROVED}</span>
<button <button
className="btn-success" className="btn-success"
disabled={busy} disabled={busy}
@@ -207,7 +207,7 @@ export const AccessConsolePage: React.FC = () => {
})()} })()}
</td> </td>
<td> <td>
{r.inside && hasEnteredToday(r) && ( {r.inside && hasEnteredToday(r) ? (
<button <button
className="btn-danger" className="btn-danger"
disabled={busy} disabled={busy}
@@ -216,6 +216,17 @@ export const AccessConsolePage: React.FC = () => {
forceCheckOut(r.visitRequestId); forceCheckOut(r.visitRequestId);
}} }}
></button> ></button>
) : r.status === 'APPROVED' && !hasExitedToday(r) ? (
<button
className="btn-success"
disabled={busy}
onClick={(e) => {
e.stopPropagation();
forceCheckIn(r.visitRequestId);
}}
></button>
) : (
'-'
)} )}
</td> </td>
</tr> </tr>

View File

@@ -5,6 +5,7 @@ import { formatVisitRange } from '../status';
import { Dialog } from '../components/Dialog'; import { Dialog } from '../components/Dialog';
type SortKey = 'visitorName' | 'company' | 'zoneName' | 'purpose' | 'visitFrom'; type SortKey = 'visitorName' | 'company' | 'zoneName' | 'purpose' | 'visitFrom';
type BusyAction = 'approve' | 'reject';
const COLUMNS: { key: SortKey; label: string }[] = [ const COLUMNS: { key: SortKey; label: string }[] = [
{ key: 'visitorName', label: '방문자' }, { key: 'visitorName', label: '방문자' },
@@ -18,7 +19,7 @@ export const ApprovalQueuePage: React.FC = () => {
const [items, setItems] = useState<VisitRequestView[]>([]); const [items, setItems] = useState<VisitRequestView[]>([]);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [busyId, setBusyId] = useState<number | null>(null); const [busyAction, setBusyAction] = useState<{ id: number; action: BusyAction } | null>(null);
const [sortKey, setSortKey] = useState<SortKey | null>(null); const [sortKey, setSortKey] = useState<SortKey | null>(null);
const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc'); const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc');
const [rejectingId, setRejectingId] = useState<number | null>(null); const [rejectingId, setRejectingId] = useState<number | null>(null);
@@ -56,14 +57,14 @@ export const ApprovalQueuePage: React.FC = () => {
const approve = async (id: number) => { const approve = async (id: number) => {
setError(null); setError(null);
setBusyId(id); setBusyAction({ id, action: 'approve' });
try { try {
await approveRequest(id); await approveRequest(id);
load(); load();
} catch (e) { } catch (e) {
setError(e instanceof Error ? e.message : '처리 실패'); setError(e instanceof Error ? e.message : '처리 실패');
} finally { } finally {
setBusyId(null); setBusyAction(null);
} }
}; };
@@ -72,14 +73,14 @@ export const ApprovalQueuePage: React.FC = () => {
setRejectingId(null); setRejectingId(null);
if (id == null) return; if (id == null) return;
setError(null); setError(null);
setBusyId(id); setBusyAction({ id, action: 'reject' });
try { try {
await rejectRequest(id, comment); await rejectRequest(id, comment);
load(); load();
} catch (e) { } catch (e) {
setError(e instanceof Error ? e.message : '처리 실패'); setError(e instanceof Error ? e.message : '처리 실패');
} finally { } finally {
setBusyId(null); setBusyAction(null);
} }
}; };
@@ -119,8 +120,26 @@ export const ApprovalQueuePage: React.FC = () => {
<td>{r.purpose}</td> <td>{r.purpose}</td>
<td>{formatVisitRange(r.visitFrom, r.visitTo)}</td> <td>{formatVisitRange(r.visitFrom, r.visitTo)}</td>
<td className="action-cell"> <td className="action-cell">
<button className="btn-success" disabled={busyId === r.id} onClick={() => approve(r.id)}></button> <button
<button className="btn-danger" disabled={busyId === r.id} onClick={() => setRejectingId(r.id)}></button> className="btn-success"
disabled={busyAction?.id === r.id && busyAction.action === 'approve'}
onClick={() => {
if (busyAction?.id === r.id) return;
approve(r.id);
}}
>
{busyAction?.id === r.id && busyAction.action === 'approve' ? '처리 중...' : '승인'}
</button>
<button
className="btn-danger"
disabled={busyAction?.id === r.id && busyAction.action === 'reject'}
onClick={() => {
if (busyAction?.id === r.id) return;
setRejectingId(r.id);
}}
>
{busyAction?.id === r.id && busyAction.action === 'reject' ? '처리 중...' : '반려'}
</button>
</td> </td>
</tr> </tr>
))} ))}