"use client"; /** * V2ComponentsDemo * * V2 컴포넌트들을 테스트하고 미리볼 수 있는 데모 페이지 */ import React, { useState } from "react"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import { ArrowLeft, Code, Eye, Zap } from "lucide-react"; // V2 컴포넌트들 import { V2Input } from "./V2Input"; import { V2Select } from "./V2Select"; import { V2Date } from "./V2Date"; import { V2List } from "./V2List"; import { V2Layout } from "./V2Layout"; import { V2Group } from "./V2Group"; import { V2Media } from "./V2Media"; import { V2Biz } from "./V2Biz"; import { V2Hierarchy } from "./V2Hierarchy"; // 조건부 로직 import { V2FormProvider, useV2Form } from "./V2FormContext"; import { ConditionalConfigPanel } from "./ConditionalConfigPanel"; // 타입 import { HierarchyNode, ConditionalConfig } from "@/types/v2-components"; interface V2ComponentsDemoProps { onBack?: () => void; } export function V2ComponentsDemo({ onBack }: V2ComponentsDemoProps) { const [activeTab, setActiveTab] = useState("conditional"); // 데모용 상태 const [inputValues, setInputValues] = useState({ text: "", number: 50, password: "", slider: 30, color: "#3b82f6", }); const [selectValues, setSelectValues] = useState({ dropdown: "", radio: "", check: [] as string[], tag: [] as string[], toggle: "false", }); const [dateValues, setDateValues] = useState({ date: "", time: "", datetime: "", range: ["", ""] as [string, string], }); // 샘플 데이터 const sampleOptions = [ { value: "option1", label: "옵션 1" }, { value: "option2", label: "옵션 2" }, { value: "option3", label: "옵션 3" }, { value: "option4", label: "옵션 4" }, ]; const sampleTableData = [ { id: 1, name: "홍길동", email: "hong@test.com", status: "active", date: "2024-01-15" }, { id: 2, name: "김철수", email: "kim@test.com", status: "inactive", date: "2024-02-20" }, { id: 3, name: "이영희", email: "lee@test.com", status: "active", date: "2024-03-10" }, { id: 4, name: "박민수", email: "park@test.com", status: "pending", date: "2024-04-05" }, ]; const sampleHierarchyData: HierarchyNode[] = [ { id: "1", label: "본사", children: [ { id: "1-1", label: "영업부", children: [ { id: "1-1-1", label: "영업1팀" }, { id: "1-1-2", label: "영업2팀" }, ], }, { id: "1-2", label: "개발부", children: [ { id: "1-2-1", label: "프론트엔드팀" }, { id: "1-2-2", label: "백엔드팀" }, ], }, ], }, ]; return (
{/* 헤더 */}
{onBack && ( )}

V2 컴포넌트 테스트

10개의 통합 컴포넌트를 테스트합니다

Phase 1-3 완료
{/* 탭 컨텐츠 */}
조건부 Input Select Date List Layout Group Media Biz Hierarchy {/* 조건부 동작 데모 탭 */} {/* V2Input 탭 */} V2Input 통합 입력 컴포넌트 - text, number, password, slider, color, button
{/* Text Input */} setInputValues({ ...inputValues, text: String(v) })} /> {/* Number Input */} setInputValues({ ...inputValues, number: Number(v) })} /> {/* Password Input */} setInputValues({ ...inputValues, password: String(v) })} /> {/* Slider Input */} setInputValues({ ...inputValues, slider: Number(v) })} /> {/* Color Input */} setInputValues({ ...inputValues, color: String(v) })} /> {/* Button */}

현재 값:

                    {JSON.stringify(inputValues, null, 2)}
                  
{/* V2Select 탭 */} V2Select 통합 선택 컴포넌트 - dropdown, radio, check, tag, toggle, swap
{/* Dropdown */} setSelectValues({ ...selectValues, dropdown: String(v) })} /> {/* Radio */} setSelectValues({ ...selectValues, radio: String(v) })} /> {/* Checkbox */} setSelectValues({ ...selectValues, check: v as string[] })} /> {/* Tag */} setSelectValues({ ...selectValues, tag: v as string[] })} /> {/* Toggle */} setSelectValues({ ...selectValues, toggle: String(v) })} />

현재 값:

                    {JSON.stringify(selectValues, null, 2)}
                  
{/* V2Date 탭 */} V2Date 통합 날짜/시간 컴포넌트 - date, time, datetime, range
{/* Date */} setDateValues({ ...dateValues, date: String(v) })} /> {/* Time */} setDateValues({ ...dateValues, time: String(v) })} /> {/* DateTime */} setDateValues({ ...dateValues, datetime: String(v) })} /> {/* Range */} setDateValues({ ...dateValues, range: v as [string, string] })} />

현재 값:

                    {JSON.stringify(dateValues, null, 2)}
                  
{/* V2List 탭 */} V2List 통합 리스트 컴포넌트 - table, card, list console.log("Row clicked:", row)} /> {/* V2Layout 탭 */} V2Layout 통합 레이아웃 컴포넌트 - 12컬럼 그리드 시스템, split, flex {/* 12컬럼 그리드 시스템 */}

12컬럼 그리드 시스템

shadcn/Tailwind 표준 12컬럼 시스템. 자식 요소에 col-span-* 클래스로 너비 조절

{/* 12컬럼 전체 보기 */} {Array.from({ length: 12 }).map((_, i) => (
{i + 1}
))}
{/* col-span 예시 */}

col-span 활용 예시

col-span-12 (전체)
col-span-6 (절반)
col-span-6 (절반)
col-span-4 (1/3)
col-span-4 (1/3)
col-span-4 (1/3)
col-span-3 (1/4)
col-span-3 (1/4)
col-span-3 (1/4)
col-span-3 (1/4)
col-span-8 (2/3)
col-span-4 (1/3)
{/* Split Layout */}

Split Layout (리사이즈 가능)

왼쪽 패널
오른쪽 패널
{/* V2Group 탭 */} V2Group 통합 그룹 컴포넌트 - tabs, accordion, section, card-section {/* Tabs */} 탭 1 내용
}, { id: "tab2", title: "탭 2", content:
탭 2 내용
}, { id: "tab3", title: "탭 3", content:
탭 3 내용
}, ], }} /> {/* Accordion */}

이 내용은 접었다 펼 수 있습니다.

{/* Card Section */}

카드 스타일 섹션 내용입니다.

{/* V2Media 탭 */} V2Media 통합 미디어 컴포넌트 - file, image, video, audio
{/* File Upload */} {/* Image Upload */}
{/* V2Biz 탭 */} V2Biz 통합 비즈니스 컴포넌트 - numbering, category, flow 등 (플레이스홀더)
{/* V2Hierarchy 탭 */} V2Hierarchy 통합 계층 구조 컴포넌트 - tree, org, bom, cascading
{/* Tree View */}

트리 뷰

{/* Cascading Dropdowns */}

연쇄 드롭다운

); } export default V2ComponentsDemo; // ===== 조건부 동작 데모 컴포넌트 ===== /** * 조건부 동작을 시연하는 데모 컴포넌트 * * 시나리오: * 1. 계약 유형 선택 → 유형별 다른 필드 표시 * 2. VIP 여부 체크 → VIP 전용 필드 활성화 * 3. 국가 선택 → 해당 국가의 도시만 표시 (연쇄) */ function ConditionalDemo() { return ( ); } function ConditionalDemoContent() { const { formData, setValue, evaluateCondition } = useV2Form(); // 국가별 도시 데이터 const cityOptions: Record> = { korea: [ { value: "seoul", label: "서울" }, { value: "busan", label: "부산" }, { value: "incheon", label: "인천" }, { value: "daegu", label: "대구" }, ], japan: [ { value: "tokyo", label: "도쿄" }, { value: "osaka", label: "오사카" }, { value: "kyoto", label: "교토" }, ], usa: [ { value: "newyork", label: "뉴욕" }, { value: "la", label: "로스앤젤레스" }, { value: "chicago", label: "시카고" }, ], }; // 현재 선택된 국가의 도시 옵션 const currentCountry = formData.country as string; const availableCities = currentCountry ? cityOptions[currentCountry] || [] : []; // 조건부 설정 const showB2BFields: ConditionalConfig = { enabled: true, field: "contractType", operator: "=", value: "b2b", action: "show", }; const showB2CFields: ConditionalConfig = { enabled: true, field: "contractType", operator: "=", value: "b2c", action: "show", }; const showDiscountField: ConditionalConfig = { enabled: true, field: "isVip", operator: "=", value: true, action: "show", }; // 조건 평가 const b2bState = evaluateCondition("b2bFields", showB2BFields); const b2cState = evaluateCondition("b2cFields", showB2CFields); const discountState = evaluateCondition("discountRate", showDiscountField); return (
{/* 시나리오 1: 계약 유형에 따른 필드 표시 */} 시나리오 1: 계약 유형별 필드 표시 계약 유형을 선택하면 해당 유형에 맞는 입력 필드가 나타납니다 {/* 계약 유형 선택 */} setValue("contractType", v)} /> {/* B2B 전용 필드 */} {b2bState.visible && (

B2B 전용 입력 필드

setValue("companyName", v)} /> setValue("employeeCount", v)} />
)} {/* B2C 전용 필드 */} {b2cState.visible && (

B2C 전용 입력 필드

setValue("customerName", v)} /> setValue("phone", v)} />
)}
{/* 시나리오 2: VIP 여부에 따른 필드 활성화 */} 시나리오 2: 조건부 필드 활성화 VIP 고객 체크 시 할인율 입력 필드가 나타납니다
setValue("isVip", v === "true")} />
{/* VIP 전용 할인율 필드 */} {discountState.visible && (

VIP 전용 혜택 설정

setValue("discountRate", v)} />

현재 할인율: {formData.discountRate || 0}%

)}
{/* 시나리오 3: 연쇄 드롭다운 (국가 → 도시) */} 시나리오 3: 연쇄 드롭다운 국가를 선택하면 해당 국가의 도시만 표시됩니다
{/* 국가 선택 */} { setValue("country", v); setValue("city", ""); // 국가 변경 시 도시 초기화 }} /> {/* 도시 선택 (국가에 따라 옵션 변경) */} setValue("city", v)} />
{!currentCountry && (

국가를 먼저 선택해주세요

)}
{/* 조건부 설정 UI 데모 */} {/* 현재 폼 데이터 표시 (하단으로 이동) */} 현재 폼 데이터 실시간으로 변경되는 폼 데이터를 확인합니다
              {JSON.stringify(formData, null, 2)}
            
); } /** * 조건부 설정 UI 패널 데모 * * 비개발자도 UI로 조건부 설정을 할 수 있음을 보여주는 데모 */ function ConditionalConfigUIDemo({ formData }: { formData: Record }) { const [demoConfig, setDemoConfig] = useState(undefined); const { evaluateCondition } = useV2Form(); // 데모용 필드 목록 (현재 폼의 필드들) const availableFields = [ { id: "contractType", label: "계약 유형", type: "select", options: [ { value: "b2b", label: "B2B" }, { value: "b2c", label: "B2C" }, ]}, { id: "isVip", label: "VIP 여부", type: "checkbox" }, { id: "country", label: "국가", type: "select", options: [ { value: "korea", label: "대한민국" }, { value: "japan", label: "일본" }, { value: "usa", label: "미국" }, ]}, { id: "discountRate", label: "할인율", type: "number" }, { id: "employeeCount", label: "직원 수", type: "number" }, ]; // 현재 설정으로 조건 평가 const conditionResult = demoConfig ? evaluateCondition("demoField", demoConfig) : { visible: true, disabled: false }; return ( 조건부 설정 UI 데모 화면관리에서 비개발자도 이 UI로 조건부 표시를 설정할 수 있습니다
{/* 왼쪽: 설정 UI */}

설정 패널 (화면관리에 들어갈 UI)

{/* 오른쪽: 미리보기 */}

적용 결과 미리보기

{/* 조건 평가 결과 */}

현재 조건 평가 결과:

{conditionResult.visible ? "표시됨" : "숨겨짐"} {conditionResult.disabled ? "비활성화" : "활성화"}
{/* 대상 필드 미리보기 */}

대상 필드:

{conditionResult.visible ? ( ) : (
(조건에 의해 숨겨진 필드)
)}
{/* 생성된 JSON */}

생성된 설정 JSON:

                    {demoConfig ? JSON.stringify(demoConfig, null, 2) : "(설정 없음)"}
                  
{/* 안내 메시지 */}

위의 "조건부 표시" 스위치를 켜고 설정을 변경해보세요. 위 시나리오들의 필드 값을 변경하면 조건 평가 결과가 실시간으로 바뀝니다.

); }