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 { Field } from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { Select } from '@/components/ui/select';
import {
ADMIN_ROLE_OPTIONS,
DEFAULT_ADMIN_ROLE_CODE,
type AdminMember,
} from '@/lib/domain/admin-member';
import {
splitPhoneNumber,
type AdminMemberFormErrors,
} from '@/lib/domain/admin-member-form';
import { AdminMenuPicker } from './admin-menu-picker';
interface AdminMemberFormFieldsProps {
/** 수정 팝업의 기존 값. 등록 팝업은 넘기지 않는다(빈 폼). */
member?: AdminMember;
errors: AdminMemberFormErrors;
}
/**
* 등록·수정 팝업이 공유하는 입력 항목 — 휴대전화 번호 / 이메일 / 역할 선택 / 메뉴 선택.
* 두 시안(ADM_ADM_102_p ②③ / 103_p ②)에서 규칙이 같은 부분만 모았다. 서로 다른 부분
* (이름·ID의 편집 가능 여부, 비밀번호 입력 방식, 잠김여부)은 각 팝업이 직접 그린다.
*
* 휴대전화 번호는 시안대로 3칸으로 나눠 받고 Server Action이 하나로 합친다
* (`joinPhoneNumber`) — 칸을 나누는 것은 화면 표현이고, 저장 형식은 도메인이 정한다.
*/
export function AdminMemberFormFields({
member,
errors,
}: AdminMemberFormFieldsProps) {
const phoneParts = splitPhoneNumber(member?.phoneNumber ?? null);
return (
<>
<Field label="휴대전화 번호 *">
<div className="flex items-center gap-2">
<Input
type="tel"
name="phoneNumber1"
defaultValue={phoneParts[0]}
maxLength={3}
inputMode="numeric"
aria-label="휴대전화 번호 앞자리"
placeholder="010"
/>
<Input
type="tel"
name="phoneNumber2"
defaultValue={phoneParts[1]}
maxLength={4}
inputMode="numeric"
aria-label="휴대전화 번호 가운데자리"
placeholder="0000"
/>
<Input
type="tel"
name="phoneNumber3"
defaultValue={phoneParts[2]}
maxLength={4}
inputMode="numeric"
aria-label="휴대전화 번호 끝자리"
placeholder="0000"
/>
</div>
</Field>
<FieldError message={errors.phoneNumber} />
<Field label="이메일">
<Input
type="email"
name="email"
defaultValue={member?.email ?? ''}
placeholder="이메일을 입력하세요."
/>
</Field>
<FieldError message={errors.email} />
<Field label="역할 선택 *">
<Select
name="roleCode"
defaultValue={member?.roleCode ?? DEFAULT_ADMIN_ROLE_CODE}
>
{ADMIN_ROLE_OPTIONS.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</Select>
</Field>
<FieldError message={errors.roleCode} />
<Field label="메뉴 선택 *">
<AdminMenuPicker defaultValue={member?.menuCodes ?? []} />
</Field>
<FieldError message={errors.menuCodes} />
</>
);
}
/** 필드 하단 오류 문구. 값이 없으면 아무것도 그리지 않아 레이아웃을 차지하지 않는다. */
export function FieldError({ message }: { message?: string }) {
if (!message) {
return null;
}
return <p className="text-body-sm text-danger">{message}</p>;
}