'use client'; import { useState, useTransition } from 'react'; import { FoxButton } from '@fox/core/components/fox-button'; import { FoxButtonGroup } from '@fox/core/components/fox-button-group'; 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 styles from './admin-member-row-actions.module.scss'; 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와 대조해 수행한다 — 화면 비활성은 안내일 뿐 신뢰 경계가 아니다. * * 시안의 연필·휴지통 아이콘 버튼이다. `FoxIconButton`의 default·sm이 시안 값과 그대로 맞는다 * (form/height/sm=28, form/radius/sm=4, 테두리 #b1b8be). 두 버튼의 4px 간격도 시안이 btn-group * 인스턴스라 `FoxButtonGroup`(gap/2=4)이 갖는다 — 여기서 직접 여백을 주지 않는다. * * 본인 계정 안내는 ``로 감싸 남긴다 — 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: ( ), }); } return ( } label="수정" onAction={() => setIsEditOpen(true)} /> } label={isDeleting ? '삭제 중' : '삭제'} disabled={isSelf || isDeleting} onAction={confirmDelete} /> {isEditOpen && ( setIsEditOpen(false)} /> )} ); }