feat: ESLint 정리 및 전체 코드 품질 개선
- eslint.config.mjs 규칙 강화 및 정리 - 전역 unused import/변수 제거 (312개 파일) - next.config.ts, middleware, proxy route 개선 - CopyableCell molecule 추가 - 회계/결재/HR/생산/건설/품질/영업 등 전 도메인 lint 정리 - IntegratedListTemplateV2, DataTable, MobileCard 등 공통 컴포넌트 개선 - execute-server-action 에러 핸들링 보강
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import type { DynamicFieldRendererProps, ComputedConfig, DynamicFormData } from '../types';
|
||||
import type { DynamicFieldRendererProps, ComputedConfig } from '../types';
|
||||
|
||||
/**
|
||||
* 안전한 수식 평가기
|
||||
|
||||
@@ -30,7 +30,7 @@ function formatCurrency(num: number, precision: number): string {
|
||||
}
|
||||
|
||||
function parseCurrency(str: string): number {
|
||||
const cleaned = str.replace(/[^0-9.\-]/g, '');
|
||||
const cleaned = str.replace(/[^0-9.-]/g, '');
|
||||
const num = parseFloat(cleaned);
|
||||
return isNaN(num) ? 0 : num;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export function CurrencyField({
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const raw = e.target.value;
|
||||
// 숫자, 점, 마이너스만 허용
|
||||
const pattern = allowNegative ? /[^0-9.\-]/g : /[^0-9.]/g;
|
||||
const pattern = allowNegative ? /[^0-9.-]/g : /[^0-9.]/g;
|
||||
const cleaned = raw.replace(pattern, '');
|
||||
setInputValue(cleaned);
|
||||
}, [allowNegative]);
|
||||
|
||||
@@ -17,7 +17,6 @@ export function NumberField({
|
||||
disabled,
|
||||
}: DynamicFieldRendererProps) {
|
||||
const fieldKey = field.field_key || `field_${field.id}`;
|
||||
const stringValue = value !== null && value !== undefined ? String(value) : '';
|
||||
|
||||
// properties에서 단위, 정밀도 등 추출
|
||||
const unit = field.properties?.unit as string | undefined;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import type { ItemMaster } from '@/types/item';
|
||||
import { ITEM_TYPE_LABELS, PART_TYPE_LABELS, PART_USAGE_LABELS, PRODUCT_CATEGORY_LABELS } from '@/types/item';
|
||||
import { ITEM_TYPE_LABELS, PRODUCT_CATEGORY_LABELS } from '@/types/item';
|
||||
import { getItemTypeStyle } from '@/lib/utils/status-config';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { notFound } from 'next/navigation';
|
||||
import ItemDetailClient from '@/components/items/ItemDetailClient';
|
||||
import type { ItemMaster, ItemType, ProductCategory, PartType, PartUsage } from '@/types/item';
|
||||
@@ -151,7 +150,6 @@ interface ItemDetailViewProps {
|
||||
* 품목 상세 보기 컴포넌트
|
||||
*/
|
||||
export function ItemDetailView({ itemCode, itemType, itemId }: ItemDetailViewProps) {
|
||||
const router = useRouter();
|
||||
const [item, setItem] = useState<ItemMaster | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -55,7 +55,7 @@ export default function BendingDiagramSection({
|
||||
widthSumFieldKey,
|
||||
setValue,
|
||||
isSubmitting,
|
||||
existingBendingDiagram,
|
||||
existingBendingDiagram: _existingBendingDiagram,
|
||||
existingBendingDiagramFileName,
|
||||
existingBendingDiagramFileId,
|
||||
onDeleteExistingFile,
|
||||
|
||||
@@ -50,13 +50,13 @@ export default function ProductForm({
|
||||
setProductStatus,
|
||||
remarks,
|
||||
setRemarks,
|
||||
needsBOM,
|
||||
setNeedsBOM,
|
||||
specificationFile,
|
||||
setSpecificationFile,
|
||||
certificationFile,
|
||||
setCertificationFile,
|
||||
isSubmitting,
|
||||
needsBOM: _needsBOM,
|
||||
setNeedsBOM: _setNeedsBOM,
|
||||
specificationFile: _specificationFile,
|
||||
setSpecificationFile: _setSpecificationFile,
|
||||
certificationFile: _certificationFile,
|
||||
setCertificationFile: _setCertificationFile,
|
||||
isSubmitting: _isSubmitting,
|
||||
register,
|
||||
setValue,
|
||||
getValues,
|
||||
|
||||
@@ -18,8 +18,8 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { TableRow, TableCell } from '@/components/ui/table';
|
||||
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
import { Plus, Package, FileDown, Upload } from 'lucide-react';
|
||||
import { downloadExcelTemplate, parseExcelFile, type ExcelColumn, type TemplateColumn } from '@/lib/utils/excel-download';
|
||||
import { Plus, Package } from 'lucide-react';
|
||||
import { parseExcelFile, type ExcelColumn, type TemplateColumn } from '@/lib/utils/excel-download';
|
||||
import { useItemList } from '@/hooks/useItemList';
|
||||
import { handleApiError } from '@/lib/api/error-handler';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
@@ -80,16 +80,12 @@ export default function ItemListClient() {
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [itemToDelete, setItemToDelete] = useState<{ id: string; code: string; itemType: string } | null>(null);
|
||||
|
||||
// Materials 타입 (SM, RM, CS는 Material 테이블 사용)
|
||||
const MATERIAL_TYPES = ['SM', 'RM', 'CS'];
|
||||
|
||||
// API에서 품목 목록 및 테이블 컬럼 조회 (서버 사이드 검색/필터링)
|
||||
const {
|
||||
items,
|
||||
pagination,
|
||||
totalStats,
|
||||
isLoading,
|
||||
isSearching,
|
||||
refresh,
|
||||
search,
|
||||
} = useItemList();
|
||||
@@ -139,17 +135,6 @@ export default function ItemListClient() {
|
||||
router.push(`/production/screen-production/${encodeURIComponent(itemCode)}?mode=view&type=${itemType}&id=${itemId}`);
|
||||
};
|
||||
|
||||
const handleEdit = (itemCode: string, itemType: string, itemId: string) => {
|
||||
// itemType을 query param으로 전달 (Materials 조회를 위해)
|
||||
router.push(`/production/screen-production/${encodeURIComponent(itemCode)}?mode=edit&type=${itemType}&id=${itemId}`);
|
||||
};
|
||||
|
||||
// 삭제 확인 다이얼로그 열기
|
||||
const openDeleteDialog = (itemId: string, itemCode: string, itemType: string) => {
|
||||
setItemToDelete({ id: itemId, code: itemCode, itemType });
|
||||
setDeleteDialogOpen(true);
|
||||
};
|
||||
|
||||
// 삭제 실행
|
||||
const handleConfirmDelete = async () => {
|
||||
if (!itemToDelete) return;
|
||||
@@ -288,17 +273,6 @@ export default function ItemListClient() {
|
||||
{ header: '활성상태', key: 'isActive', type: 'boolean', sampleValue: 'Y', description: 'Y:활성/N:비활성', width: 10 },
|
||||
];
|
||||
|
||||
// 양식 다운로드
|
||||
const handleTemplateDownload = async () => {
|
||||
await downloadExcelTemplate({
|
||||
columns: templateColumns,
|
||||
filename: '품목등록_양식',
|
||||
sheetName: '품목등록',
|
||||
includeSampleRow: true,
|
||||
includeGuideRow: true,
|
||||
});
|
||||
};
|
||||
|
||||
// 파일 업로드 input ref
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@@ -400,11 +374,11 @@ export default function ItemListClient() {
|
||||
// 테이블 컬럼 (sortable: true로 정렬 가능)
|
||||
columns: [
|
||||
{ key: 'rowNumber', label: '번호', className: 'w-[60px] text-center' },
|
||||
{ key: 'itemCode', label: '품목코드', className: 'min-w-[120px]' },
|
||||
{ key: 'itemCode', label: '품목코드', className: 'min-w-[120px]', copyable: true },
|
||||
{ key: 'itemType', label: '품목유형', className: 'min-w-[100px]' },
|
||||
{ key: 'itemName', label: '품목명', className: 'min-w-[150px]' },
|
||||
{ key: 'specification', label: '규격', className: 'min-w-[100px]' },
|
||||
{ key: 'unit', label: '단위', className: 'min-w-[60px]' },
|
||||
{ key: 'itemName', label: '품목명', className: 'min-w-[150px]', copyable: true },
|
||||
{ key: 'specification', label: '규격', className: 'min-w-[100px]', copyable: true },
|
||||
{ key: 'unit', label: '단위', className: 'min-w-[60px]', copyable: true },
|
||||
{ key: 'isActive', label: '품목상태', className: 'min-w-[80px]' },
|
||||
],
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
Database,
|
||||
FileText,
|
||||
} from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ interface DraggableFieldProps {
|
||||
nextFieldId?: number;
|
||||
}
|
||||
|
||||
export function DraggableField({ field, index, moveField, onDelete, onEdit, prevFieldId, nextFieldId }: DraggableFieldProps) {
|
||||
export function DraggableField({ field, index: _index, moveField, onDelete, onEdit, prevFieldId, nextFieldId }: DraggableFieldProps) {
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const handleDragStart = (e: React.DragEvent) => {
|
||||
@@ -63,7 +63,7 @@ export function DraggableField({ field, index, moveField, onDelete, onEdit, prev
|
||||
if (data.id !== field.id) {
|
||||
moveField(data.id, field.id);
|
||||
}
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore - 다른 타입의 드래그 데이터
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@ export function DraggableSection({
|
||||
if (data.index !== index) {
|
||||
moveSection(data.index, index);
|
||||
}
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore - 다른 타입의 드래그 데이터
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import type { ItemPage, SectionTemplate, ItemMasterField, ItemSection, BOMItem } from '@/contexts/ItemMasterContext';
|
||||
import { FieldDialog, type InputType } from '../dialogs/FieldDialog';
|
||||
import type { ItemPage, SectionTemplate, ItemMasterField, ItemSection } from '@/contexts/ItemMasterContext';
|
||||
import { FieldDialog } from '../dialogs/FieldDialog';
|
||||
import { FieldDrawer } from '../dialogs/FieldDrawer';
|
||||
import { TabManagementDialogs } from '../dialogs/TabManagementDialogs';
|
||||
import { OptionDialog } from '../dialogs/OptionDialog';
|
||||
@@ -17,7 +17,6 @@ import { SectionTemplateDialog } from '../dialogs/SectionTemplateDialog';
|
||||
import { ImportSectionDialog } from '../dialogs/ImportSectionDialog';
|
||||
import { ImportFieldDialog } from '../dialogs/ImportFieldDialog';
|
||||
import type { CustomTab, AttributeSubTab } from '../hooks/useTabManagement';
|
||||
import type { OptionColumn } from '../types';
|
||||
import type { ConditionalFieldConfig } from '../components/ConditionalDisplayUI';
|
||||
import type { SectionUsageResponse, FieldUsageResponse } from '@/types/item-master-api';
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export function ColumnDialog({
|
||||
setColumnName,
|
||||
columnKey,
|
||||
setColumnKey,
|
||||
textboxColumns,
|
||||
textboxColumns: _textboxColumns,
|
||||
setTextboxColumns,
|
||||
}: ColumnDialogProps) {
|
||||
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||
|
||||
@@ -118,7 +118,7 @@ export function FieldDialog({
|
||||
setNewFieldConditionTargetType,
|
||||
newFieldConditionFields,
|
||||
setNewFieldConditionFields,
|
||||
newFieldConditionSections,
|
||||
newFieldConditionSections: _newFieldConditionSections,
|
||||
setNewFieldConditionSections,
|
||||
tempConditionValue,
|
||||
setTempConditionValue,
|
||||
|
||||
@@ -16,7 +16,7 @@ interface LoadTemplateDialogProps {
|
||||
handleLoadTemplate: () => void;
|
||||
}
|
||||
|
||||
const ITEM_TYPE_OPTIONS = [
|
||||
const _ITEM_TYPE_OPTIONS = [
|
||||
{ value: 'product', label: '제품' },
|
||||
{ value: 'part', label: '부품' },
|
||||
{ value: 'material', label: '자재' },
|
||||
|
||||
@@ -62,7 +62,7 @@ export function MasterFieldDialog({
|
||||
setNewMasterFieldInputType,
|
||||
newMasterFieldRequired,
|
||||
setNewMasterFieldRequired,
|
||||
newMasterFieldCategory,
|
||||
newMasterFieldCategory: _newMasterFieldCategory,
|
||||
setNewMasterFieldCategory,
|
||||
newMasterFieldDescription,
|
||||
setNewMasterFieldDescription,
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useState, useEffect, useRef } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { useItemMaster } from '@/contexts/ItemMasterContext';
|
||||
import type { MasterOption, OptionColumn } from '../types';
|
||||
import { attributeService } from '../services';
|
||||
|
||||
export interface UseAttributeManagementReturn {
|
||||
// 속성 옵션 상태
|
||||
@@ -189,7 +188,7 @@ export function useAttributeManagement(): UseAttributeManagementReturn {
|
||||
}
|
||||
}
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
}, [unitOptions, materialOptions, surfaceTreatmentOptions, customAttributeOptions]);
|
||||
|
||||
// 옵션 추가
|
||||
|
||||
@@ -44,8 +44,8 @@ export function useDeleteManagement({ itemPages }: UseDeleteManagementProps): Us
|
||||
// 페이지 삭제 핸들러
|
||||
const handleDeletePage = useCallback((pageId: number) => {
|
||||
const pageToDelete = itemPages.find(p => p.id === pageId);
|
||||
const sectionIds = pageToDelete?.sections.map(s => s.id) || [];
|
||||
const fieldIds = pageToDelete?.sections.flatMap(s => s.fields?.map(f => f.id) || []) || [];
|
||||
const _sectionIds = pageToDelete?.sections.map(s => s.id) || [];
|
||||
const _fieldIds = pageToDelete?.sections.flatMap(s => s.fields?.map(f => f.id) || []) || [];
|
||||
deleteItemPage(pageId);
|
||||
}, [itemPages, deleteItemPage]);
|
||||
|
||||
@@ -53,7 +53,7 @@ export function useDeleteManagement({ itemPages }: UseDeleteManagementProps): Us
|
||||
const handleDeleteSection = useCallback((pageId: number, sectionId: number) => {
|
||||
const page = itemPages.find(p => p.id === pageId);
|
||||
const sectionToDelete = page?.sections.find(s => s.id === sectionId);
|
||||
const fieldIds = sectionToDelete?.fields?.map(f => f.id) || [];
|
||||
const _fieldIds = sectionToDelete?.fields?.map(f => f.id) || [];
|
||||
deleteSection(Number(sectionId));
|
||||
}, [itemPages, deleteSection]);
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ export function useInitialDataLoading({
|
||||
}
|
||||
hasInitialLoadRun.current = true;
|
||||
loadInitialData();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
}, []);
|
||||
|
||||
return {
|
||||
|
||||
@@ -61,7 +61,7 @@ export interface UseMasterFieldManagementReturn {
|
||||
|
||||
export function useMasterFieldManagement(): UseMasterFieldManagementReturn {
|
||||
const {
|
||||
itemMasterFields,
|
||||
itemMasterFields: _itemMasterFields,
|
||||
addItemMasterField,
|
||||
updateItemMasterField,
|
||||
deleteItemMasterField,
|
||||
|
||||
@@ -80,7 +80,7 @@ export function usePageManagement(): UsePageManagementReturn {
|
||||
migrationDoneRef.current.add(page.id);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
}, [itemPages.length]); // itemPages 길이가 변경될 때만 체크
|
||||
|
||||
// 페이지 추가
|
||||
@@ -168,8 +168,8 @@ export function usePageManagement(): UsePageManagementReturn {
|
||||
// 2025-12-01: 페이지 삭제 시 섹션들은 독립 섹션으로 이동 (필드 연결 유지)
|
||||
const handleDeletePage = (pageId: number) => {
|
||||
const pageToDelete = itemPages.find(p => p.id === pageId);
|
||||
const sectionCount = pageToDelete?.sections.length || 0;
|
||||
const fieldCount = pageToDelete?.sections.flatMap(s => s.fields || []).length || 0;
|
||||
const _sectionCount = pageToDelete?.sections.length || 0;
|
||||
const _fieldCount = pageToDelete?.sections.flatMap(s => s.fields || []).length || 0;
|
||||
|
||||
deleteItemPage(pageId);
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { useItemMaster } from '@/contexts/ItemMasterContext';
|
||||
import type { ItemPage, ItemSection, SectionTemplate } from '@/contexts/ItemMasterContext';
|
||||
import { sectionService } from '../services';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
|
||||
// 입력 모드 타입: 'new'/'existing' 또는 'custom'/'template' 모두 지원
|
||||
@@ -172,7 +171,7 @@ export function useSectionManagement(): UseSectionManagementReturn {
|
||||
const handleDeleteSection = async (pageId: number, sectionId: number) => {
|
||||
const page = itemPages.find(p => p.id === pageId);
|
||||
const sectionToDelete = page?.sections.find(s => s.id === sectionId);
|
||||
const fieldIds = sectionToDelete?.fields?.map(f => f.id) || [];
|
||||
const _fieldIds = sectionToDelete?.fields?.map(f => f.id) || [];
|
||||
|
||||
try {
|
||||
await deleteSection(sectionId);
|
||||
|
||||
@@ -204,7 +204,7 @@ export function useTabManagement(): UseTabManagementReturn {
|
||||
if (isNumericKey && !currentFieldIds.has(activeAttributeTab)) {
|
||||
setActiveAttributeTab('units');
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
}, [itemMasterFields]);
|
||||
|
||||
// 메인 탭 핸들러
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { useItemMaster } from '@/contexts/ItemMasterContext';
|
||||
import { useErrorAlert } from '../contexts';
|
||||
import type { ItemPage, SectionTemplate, TemplateField, BOMItem, ItemMasterField } from '@/contexts/ItemMasterContext';
|
||||
import type { ItemPage, SectionTemplate, TemplateField, BOMItem } from '@/contexts/ItemMasterContext';
|
||||
import { templateService } from '../services';
|
||||
import { ApiError } from '@/lib/api/error-handler';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
@@ -91,18 +91,18 @@ export interface UseTemplateManagementReturn {
|
||||
export function useTemplateManagement(): UseTemplateManagementReturn {
|
||||
const {
|
||||
sectionTemplates,
|
||||
addSectionTemplate,
|
||||
updateSectionTemplate,
|
||||
deleteSectionTemplate,
|
||||
addSectionTemplate: _addSectionTemplate,
|
||||
updateSectionTemplate: _updateSectionTemplate,
|
||||
deleteSectionTemplate: _deleteSectionTemplate,
|
||||
addSectionToPage,
|
||||
addItemMasterField,
|
||||
itemMasterFields,
|
||||
tenantId,
|
||||
addItemMasterField: _addItemMasterField,
|
||||
itemMasterFields: _itemMasterFields,
|
||||
tenantId: _tenantId,
|
||||
// 2025-11-26: sectionsAsTemplates가 itemPages에서 파생되므로
|
||||
// 섹션 탭에서 수정/삭제 시 실제 섹션 API를 호출해야 함
|
||||
updateSection,
|
||||
deleteSection,
|
||||
itemPages,
|
||||
itemPages: _itemPages,
|
||||
// 2025-11-26: 섹션 탭에서 새 섹션 추가 시 독립 섹션으로 생성
|
||||
createIndependentSection,
|
||||
// 2025-11-27: entity_relationships 기반 필드 연결/해제
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
import type { ItemMasterField } from '@/contexts/ItemMasterContext';
|
||||
import type { ItemFieldType } from '@/types/item-master-api';
|
||||
import { fieldService, type SingleFieldValidation } from './fieldService';
|
||||
import { fieldService } from './fieldService';
|
||||
|
||||
// ===== Types =====
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ export function HierarchyTab({
|
||||
handleEditField,
|
||||
moveField,
|
||||
// 2025-11-26 추가: 섹션/필드 불러오기
|
||||
setIsImportSectionDialogOpen,
|
||||
setIsImportSectionDialogOpen: _setIsImportSectionDialogOpen,
|
||||
setIsImportFieldDialogOpen,
|
||||
setImportFieldTargetSectionId,
|
||||
// 2025-11-27 추가: BOM 항목 API 함수
|
||||
|
||||
@@ -47,8 +47,8 @@ export function MasterFieldTab({
|
||||
setIsMasterFieldDialogOpen,
|
||||
handleEditMasterField,
|
||||
handleDeleteMasterField,
|
||||
hasUnsavedChanges,
|
||||
pendingChanges
|
||||
hasUnsavedChanges: _hasUnsavedChanges,
|
||||
pendingChanges: _pendingChanges
|
||||
}: MasterFieldTabProps) {
|
||||
return (
|
||||
<Card>
|
||||
@@ -60,11 +60,11 @@ export function MasterFieldTab({
|
||||
<CardDescription>재사용 가능한 항목을 관리합니다. 섹션에 연결하여 사용할 수 있습니다.</CardDescription>
|
||||
</div>
|
||||
{/* 변경사항 배지 - 나중에 사용 예정으로 임시 숨김 */}
|
||||
{false && hasUnsavedChanges && pendingChanges.masterFields.length > 0 && (
|
||||
{/* {hasUnsavedChanges && pendingChanges.masterFields.length > 0 && (
|
||||
<Badge variant="destructive" className="animate-pulse">
|
||||
{pendingChanges.masterFields.length}개 변경
|
||||
</Badge>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
<Button onClick={() => setIsMasterFieldDialogOpen(true)}>
|
||||
<Plus className="h-4 w-4 mr-2" />항목 추가
|
||||
|
||||
@@ -63,8 +63,8 @@ export function SectionsTab({
|
||||
ITEM_TYPE_OPTIONS,
|
||||
INPUT_TYPE_OPTIONS,
|
||||
unitOptions = [],
|
||||
hasUnsavedChanges = false,
|
||||
pendingChanges = { sectionTemplates: [] },
|
||||
hasUnsavedChanges: _hasUnsavedChanges = false,
|
||||
pendingChanges: _pendingChanges = { sectionTemplates: [] },
|
||||
onCloneSection,
|
||||
setIsImportFieldDialogOpen,
|
||||
setImportFieldTargetSectionId,
|
||||
@@ -83,11 +83,11 @@ export function SectionsTab({
|
||||
<CardDescription className="truncate">재사용 가능한 섹션 템플릿을 관리합니다</CardDescription>
|
||||
</div>
|
||||
{/* 변경사항 배지 - 나중에 사용 예정으로 임시 숨김 */}
|
||||
{false && hasUnsavedChanges && pendingChanges.sectionTemplates.length > 0 && (
|
||||
{/* {hasUnsavedChanges && pendingChanges.sectionTemplates.length > 0 && (
|
||||
<Badge variant="destructive" className="animate-pulse">
|
||||
{pendingChanges.sectionTemplates.length}개 변경
|
||||
</Badge>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
<Button size="sm" className="shrink-0" onClick={() => setIsSectionTemplateDialogOpen(true)}>
|
||||
<Plus className="h-4 w-4 md:mr-2" /><span className="hidden md:inline">섹션추가</span>
|
||||
|
||||
Reference in New Issue
Block a user