/** * pop-card-list v1 -> v2 마이그레이션 함수 * * 기존 PopCardListConfig의 고정 레이아웃(헤더/이미지/필드/입력/담기/포장)을 * CardGridConfigV2 셀 배열로 변환하여 PopCardListV2Config를 생성한다. */ import type { PopCardListConfig, PopCardListV2Config, CardCellDefinitionV2, } from "../types"; export function migrateCardListConfig(old: PopCardListConfig): PopCardListV2Config { const cells: CardCellDefinitionV2[] = []; let nextRow = 1; // 1. 헤더 행 (코드 + 제목) if (old.cardTemplate?.header?.codeField || old.cardTemplate?.header?.titleField) { if (old.cardTemplate.header.codeField) { cells.push({ id: "h-code", row: nextRow, col: 1, rowSpan: 1, colSpan: 1, type: "text", columnName: old.cardTemplate.header.codeField, fontSize: "sm", textColor: "hsl(var(--muted-foreground))", }); } if (old.cardTemplate.header.titleField) { cells.push({ id: "h-title", row: nextRow, col: 2, rowSpan: 1, colSpan: old.cardTemplate.header.codeField ? 2 : 3, type: "text", columnName: old.cardTemplate.header.titleField, fontSize: "md", fontWeight: "bold", }); } nextRow++; } // 2. 이미지 (왼쪽, 본문 높이만큼 rowSpan) const bodyFieldCount = old.cardTemplate?.body?.fields?.length || 0; const bodyRowSpan = Math.max(1, bodyFieldCount); if (old.cardTemplate?.image?.enabled) { cells.push({ id: "img", row: nextRow, col: 1, rowSpan: bodyRowSpan, colSpan: 1, type: "image", columnName: old.cardTemplate.image.imageColumn || "", defaultImage: old.cardTemplate.image.defaultImage, }); } // 3. 본문 필드들 (이미지 오른쪽) const fieldStartCol = old.cardTemplate?.image?.enabled ? 2 : 1; const fieldColSpan = old.cardTemplate?.image?.enabled ? 2 : 3; const hasRightActions = !!(old.inputField?.enabled || old.cartAction); (old.cardTemplate?.body?.fields || []).forEach((field, i) => { cells.push({ id: `f-${i}`, row: nextRow + i, col: fieldStartCol, rowSpan: 1, colSpan: hasRightActions ? fieldColSpan - 1 : fieldColSpan, type: "field", columnName: field.columnName, label: field.label, valueType: field.valueType, formulaLeft: field.formulaLeft, formulaOperator: field.formulaOperator as CardCellDefinitionV2["formulaOperator"], formulaRight: field.formulaRight, formulaRightType: field.formulaRightType as CardCellDefinitionV2["formulaRightType"], unit: field.unit, textColor: field.textColor, }); }); // 4. 수량 입력 + 담기 버튼 (오른쪽 열) const rightCol = 3; if (old.inputField?.enabled) { cells.push({ id: "input", row: nextRow, col: rightCol, rowSpan: Math.ceil(bodyRowSpan / 2), colSpan: 1, type: "number-input", inputUnit: old.inputField.unit, limitColumn: old.inputField.limitColumn || old.inputField.maxColumn, }); } if (old.cartAction) { cells.push({ id: "cart", row: nextRow + Math.ceil(bodyRowSpan / 2), col: rightCol, rowSpan: Math.floor(bodyRowSpan / 2) || 1, colSpan: 1, type: "cart-button", cartLabel: old.cartAction.label, cartCancelLabel: old.cartAction.cancelLabel, cartIconType: old.cartAction.iconType, cartIconValue: old.cartAction.iconValue, }); } // 5. 포장 요약 (마지막 행, full-width) if (old.packageConfig?.enabled) { const summaryRow = nextRow + bodyRowSpan; cells.push({ id: "pkg", row: summaryRow, col: 1, rowSpan: 1, colSpan: 3, type: "package-summary", }); } // 그리드 크기 계산 const maxRow = cells.length > 0 ? Math.max(...cells.map((c) => c.row + c.rowSpan - 1)) : 1; const maxCol = 3; return { dataSource: old.dataSource, cardGrid: { rows: maxRow, cols: maxCol, colWidths: old.cardTemplate?.image?.enabled ? ["1fr", "2fr", "1fr"] : ["1fr", "2fr", "1fr"], gap: 2, showCellBorder: false, cells, }, scrollDirection: old.scrollDirection, cardSize: old.cardSize, gridColumns: old.gridColumns, gridRows: old.gridRows, cardGap: 8, overflow: { mode: "loadMore", visibleCount: 6, loadMoreCount: 6 }, cardClickAction: "none", responsiveDisplay: old.responsiveDisplay, inputField: old.inputField, packageConfig: old.packageConfig, cartAction: old.cartAction, cartListMode: old.cartListMode, saveMapping: old.saveMapping, }; }