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 { FoxIconButton } from '@fox/core/components/fox-icon-button';
import { FoxPencilSimpleIcon, FoxTrashIcon } from '@fox/core/icons';
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/button`이 아니라 `FoxIconButton`을
* 쓴다 — 아이콘은 스스로 크기를 갖지 않고 감싼 슬롯이 정하는데, 그 슬롯 크기를 실제로 정의하는
* 건 @fox 쪽뿐이다(components/ui는 Tailwind 제거 이후 무스타일이다).
*
* 본인 계정 안내는 `<span title>`로 감싸 남긴다 — FoxIconButton은 `label`을 `aria-label`로만
* 쓰고 네이티브 툴팁을 렌더하지 않으며, 비활성 버튼은 스스로 hover 이벤트를 받지 못한다.
*/
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">
<FoxIconButton
type="ghost"
size="sm"
icon={<FoxPencilSimpleIcon />}
label="수정"
onAction={() => setIsEditOpen(true)}
/>
<span title={isSelf ? SELF_DELETE_HINT : undefined}>
<FoxIconButton
type="ghost"
size="sm"
icon={<FoxTrashIcon />}
label={isDeleting ? '삭제 중' : '삭제'}
disabled={isSelf || isDeleting}
onAction={confirmDelete}
/>
</span>
{isEditOpen && (
<AdminMemberEditModal
member={member}
onClose={() => setIsEditOpen(false)}
/>
)}
</div>
);
}