'use client'; import { useActionState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Field } from '@/components/ui/field'; import { Input } from '@/components/ui/input'; import { Modal } from '@/components/ui/modal'; import { RadioGroup } from '@/components/ui/radio-group'; import type { StudentMember } from '@/lib/domain/student-member'; import { updateStudentActiveStatus, type UpdateStudentActiveStatusState, } from '../_actions'; interface StudentDetailModalProps { member: StudentMember; onClose: () => void; } const ACTIVE_STATUS_OPTIONS = [ { value: 'true', label: '활성' }, { value: 'false', label: '비활성' }, ]; const INITIAL_STATE: UpdateStudentActiveStatusState = { status: 'idle' }; const DETAIL_FORM_ID = 'student-active-status-form'; /** * 학생 회원 조회 팝업 — 사용여부를 제외한 모든 항목은 readOnly다. 데이터는 목록 행에서 이미 * 갖고 있는 member를 props로 그대로 받으므로 재조회하지 않는다. 저장(Server Action) 성공 시 * 자동으로 닫힌다. * * Modal이 내부적으로 portal을 쓸 수도 있어(구현 미확정 — components/ui/modal.tsx는 design * 레인 소관) 저장 버튼은 footer 슬롯에서 `form={DETAIL_FORM_ID}` 속성으로 폼과 연결한다. * 네이티브 HTML의 `form` 속성은 버튼이 실제 DOM상 form의 자손이 아니어도 같은 문서 안에서 * id만 일치하면 그 form을 제출한다 — footer가 body와 다른 DOM 위치에 렌더돼도 안전하다. */ export function StudentDetailModal({ member, onClose }: StudentDetailModalProps) { const [state, formAction, isPending] = useActionState( updateStudentActiveStatus, INITIAL_STATE ); useEffect(() => { if (state.status === 'success') { onClose(); } }, [state, onClose]); const gradeClassNumber = `${member.grade}학년 ${member.classNumber}반 ${member.studentNumber}번`; return ( } >

본 화면의 모든 항목은 조회 전용입니다. (단, 사용여부는 수정 가능)

{state.status === 'error' && (

{state.error}

)}

회원 가입일 : {member.joinedAt}

); }