File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
'use client';
import { useState, useTransition } from 'react';
import { Button } from '@/components/ui/button';
import { useFeedback } from '@/app/_hooks/use-feedback';
import type { AdminMember } from '@/lib/domain/admin-member';
import { deleteAdminMemberAction } from '../_actions';
import { AdminMemberEditModal } from './admin-member-edit-modal';
interface AdminMemberRowActionsProps {
member: AdminMember;
/** 현재 로그인한 본인의 행인가 — 삭제를 막는다. */
isSelf: boolean;
}
const SELF_DELETE_HINT = '현재 로그인한 본인 계정은 삭제할 수 없습니다.';
/**
* 목록 행의 "관리" 셀(시안 ADM_ADM_101 ⑤) — 수정 팝업 열림 상태만 소유하는 최말단 상호작용
* 경계다(테이블 전체를 클라이언트로 내리지 않기 위해 이 셀만 분리했다).
*
* 삭제는 시안대로 **확인 얼럿을 거친 뒤** 실행한다. 전역 얼럿(FeedbackProvider)의 actions 슬롯에
* 직접 버튼을 넣어 확인/취소를 구성한다.
*
* **본인 계정 삭제는 막는다**(시안 ⑤). 화면에서 버튼을 비활성으로 두되, 실제 차단은 Server
* Action이 세션의 adminId와 대조해 수행한다 — 화면 비활성은 안내일 뿐 신뢰 경계가 아니다.
*
* 시안은 연필·휴지통 아이콘 버튼을 지정하지만 `components/ui/icons/`에 두 아이콘이 아직 없다
* (신규 아이콘 추가는 공용 컴포넌트 신설이라 design 레인 소관). 로직 우선 단계라 텍스트
* 버튼으로 대체했고, 아이콘 부재는 별도로 보고한다.
*/
export function AdminMemberRowActions({
member,
isSelf,
}: AdminMemberRowActionsProps) {
const { showAlert, hideAlert, showToast } = useFeedback();
const [isEditOpen, setIsEditOpen] = useState(false);
const [isDeleting, startDeleting] = useTransition();
function runDelete() {
hideAlert();
startDeleting(async () => {
const result = await deleteAdminMemberAction(member.id);
if (result.status === 'error') {
showToast({
variant: 'danger',
message: result.message ?? '삭제하지 못했습니다.',
});
return;
}
showToast({ variant: 'success', message: '관리자를 삭제했습니다.' });
});
}
function confirmDelete() {
showAlert({
variant: 'danger',
title: '관리자를 삭제하시겠습니까?',
message: `${member.name}(${member.loginId}) 계정을 삭제합니다. 삭제 후에는 되돌릴 수 없습니다.`,
actions: (
<>
<Button type="button" variant="ghost" onClick={hideAlert}>
취소
</Button>
<Button type="button" variant="primary" onClick={runDelete}>
삭제
</Button>
</>
),
});
}
return (
<div className="flex items-center gap-1">
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => setIsEditOpen(true)}
>
수정
</Button>
<Button
type="button"
variant="ghost"
size="sm"
onClick={confirmDelete}
disabled={isSelf || isDeleting}
title={isSelf ? SELF_DELETE_HINT : undefined}
>
{isDeleting ? '삭제 중...' : '삭제'}
</Button>
{isEditOpen && (
<AdminMemberEditModal
member={member}
onClose={() => setIsEditOpen(false)}
/>
)}
</div>
);
}