feat: 품목관리 동적 렌더링 시스템 구현
- DynamicItemForm 컴포넌트 구조 생성 - DynamicField: 필드 타입별 렌더링 - DynamicSection: 섹션 단위 렌더링 - DynamicFormRenderer: 페이지 전체 렌더링 - 필드 타입별 컴포넌트 (TextField, NumberField, DropdownField, CheckboxField, DateField, FileField, CustomField) - 커스텀 훅 (useDynamicFormState, useFormStructure, useConditionalFields) - DataTable 공통 컴포넌트 (테이블, 페이지네이션, 검색, 탭필터, 통계카드) - ItemFormWrapper: Feature Flag 기반 폼 선택 - 타입 정의 및 문서화 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
75
src/components/items/DynamicItemForm/DynamicFormRenderer.tsx
Normal file
75
src/components/items/DynamicItemForm/DynamicFormRenderer.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* DynamicFormRenderer Component
|
||||
*
|
||||
* 전체 폼 구조를 렌더링하는 메인 렌더러
|
||||
* - 섹션 순서대로 렌더링
|
||||
* - 조건부 섹션/필드 처리
|
||||
*/
|
||||
|
||||
'use client';
|
||||
|
||||
import { DynamicSection } from './DynamicSection';
|
||||
import { useConditionalFields } from './hooks/useConditionalFields';
|
||||
import type { DynamicFormRendererProps, DynamicSection as DynamicSectionType } from './types';
|
||||
|
||||
export function DynamicFormRenderer({
|
||||
sections,
|
||||
conditionalSections,
|
||||
conditionalFields,
|
||||
values,
|
||||
errors,
|
||||
onChange,
|
||||
onBlur,
|
||||
disabled,
|
||||
}: DynamicFormRendererProps) {
|
||||
// 조건부 표시 로직
|
||||
const { isSectionVisible, isFieldVisible } = useConditionalFields({
|
||||
sections,
|
||||
conditionalSections,
|
||||
conditionalFields,
|
||||
values,
|
||||
});
|
||||
|
||||
// 섹션 순서대로 정렬
|
||||
const sortedSections = [...sections].sort((a, b) => a.order_no - b.order_no);
|
||||
|
||||
// 표시할 섹션만 필터링
|
||||
const visibleSections = sortedSections.filter((section) =>
|
||||
isSectionVisible(section.id)
|
||||
);
|
||||
|
||||
// 각 섹션의 표시할 필드만 필터링
|
||||
const sectionsWithVisibleFields: DynamicSectionType[] = visibleSections.map((section) => ({
|
||||
...section,
|
||||
fields: section.fields.filter((field) =>
|
||||
isFieldVisible(section.id, field.id)
|
||||
),
|
||||
}));
|
||||
|
||||
if (sectionsWithVisibleFields.length === 0) {
|
||||
return (
|
||||
<div className="p-8 text-center text-gray-500 border-2 border-dashed rounded-lg">
|
||||
<p>표시할 섹션이 없습니다.</p>
|
||||
<p className="text-sm mt-1">품목 유형을 선택하거나 필수 필드를 입력해주세요.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{sectionsWithVisibleFields.map((section) => (
|
||||
<DynamicSection
|
||||
key={section.id}
|
||||
section={section}
|
||||
values={values}
|
||||
errors={errors}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
disabled={disabled}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DynamicFormRenderer;
|
||||
Reference in New Issue
Block a user