feat: 순서변경 ▲/▼ 버튼 추가 (터치 지원) + 단가표 테이블 스크롤 수정
- ReorderButtons 공통 컴포넌트 신규 생성 (molecules) - 패턴B(리스트): RankManagement, TitleManagement, CategoryManagement - 패턴A(테이블): ProcessDetail, ProcessForm, ChecklistDetail - 패턴C(컴포넌트): DraggableSection, DraggableField, HierarchyTab - 모바일: GripVertical 숨김, ▲/▼ 버튼만 표시 - 데스크톱: GripVertical + ▲/▼ 버튼 모두 표시 - 단가표 단가정보 테이블 overflow-hidden → overflow-x-auto + min-w 적용
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
Edit,
|
||||
Unlink
|
||||
} from 'lucide-react';
|
||||
import { ReorderButtons } from '@/components/molecules';
|
||||
|
||||
// 입력방식 옵션 (ItemMasterDataManagement에서 사용하는 상수)
|
||||
const INPUT_TYPE_OPTIONS = [
|
||||
@@ -25,9 +26,11 @@ interface DraggableFieldProps {
|
||||
moveField: (dragFieldId: number, hoverFieldId: number) => void;
|
||||
onDelete: () => void;
|
||||
onEdit?: () => void;
|
||||
prevFieldId?: number;
|
||||
nextFieldId?: number;
|
||||
}
|
||||
|
||||
export function DraggableField({ field, index, moveField, onDelete, onEdit }: DraggableFieldProps) {
|
||||
export function DraggableField({ field, index, moveField, onDelete, onEdit, prevFieldId, nextFieldId }: DraggableFieldProps) {
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const handleDragStart = (e: React.DragEvent) => {
|
||||
@@ -79,7 +82,14 @@ export function DraggableField({ field, index, moveField, onDelete, onEdit }: Dr
|
||||
>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<GripVertical className="h-4 w-4 text-gray-400" />
|
||||
<GripVertical className="h-4 w-4 text-gray-400 hidden md:block" />
|
||||
<ReorderButtons
|
||||
onMoveUp={() => prevFieldId !== undefined && moveField(field.id, prevFieldId)}
|
||||
onMoveDown={() => nextFieldId !== undefined && moveField(field.id, nextFieldId)}
|
||||
isFirst={prevFieldId === undefined}
|
||||
isLast={nextFieldId === undefined}
|
||||
size="xs"
|
||||
/>
|
||||
<span className="text-sm">{field.field_name}</span>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{INPUT_TYPE_OPTIONS.find(t => t.value === field.field_type)?.label || field.field_type}
|
||||
|
||||
@@ -10,10 +10,12 @@ import {
|
||||
X,
|
||||
Unlink
|
||||
} from 'lucide-react';
|
||||
import { ReorderButtons } from '@/components/molecules';
|
||||
|
||||
interface DraggableSectionProps {
|
||||
section: ItemSection;
|
||||
index: number;
|
||||
totalSections: number;
|
||||
moveSection: (dragIndex: number, hoverIndex: number) => void;
|
||||
onDelete: () => void;
|
||||
onEditTitle: (id: number, title: string) => void;
|
||||
@@ -28,6 +30,7 @@ interface DraggableSectionProps {
|
||||
export function DraggableSection({
|
||||
section,
|
||||
index,
|
||||
totalSections,
|
||||
moveSection,
|
||||
onDelete,
|
||||
onEditTitle,
|
||||
@@ -87,7 +90,14 @@ export function DraggableSection({
|
||||
<div className="bg-blue-50 border-b p-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2 flex-1 min-w-0">
|
||||
<GripVertical className="h-4 w-4 text-gray-400" style={{ cursor: 'move' }} />
|
||||
<GripVertical className="h-4 w-4 text-gray-400 hidden md:block" style={{ cursor: 'move' }} />
|
||||
<ReorderButtons
|
||||
onMoveUp={() => moveSection(index, index - 1)}
|
||||
onMoveDown={() => moveSection(index, index + 1)}
|
||||
isFirst={index === 0}
|
||||
isLast={index === totalSections - 1}
|
||||
size="xs"
|
||||
/>
|
||||
<FileText className="h-4 w-4 text-blue-600" />
|
||||
{editingSectionId === section.id ? (
|
||||
<div className="flex items-center gap-2 flex-1">
|
||||
|
||||
@@ -380,6 +380,7 @@ export function HierarchyTab({
|
||||
key={`section-${section.id}-${index}`}
|
||||
section={section}
|
||||
index={index}
|
||||
totalSections={selectedPage.sections.length}
|
||||
moveSection={(dragIndex, hoverIndex) => {
|
||||
moveSection(dragIndex, hoverIndex);
|
||||
}}
|
||||
@@ -469,7 +470,7 @@ export function HierarchyTab({
|
||||
) : (
|
||||
section.fields
|
||||
.sort((a, b) => (a.order_no ?? 0) - (b.order_no ?? 0))
|
||||
.map((field, fieldIndex) => (
|
||||
.map((field, fieldIndex, sortedFields) => (
|
||||
<DraggableField
|
||||
key={`${section.id}-${field.id}-${fieldIndex}`}
|
||||
field={field}
|
||||
@@ -479,6 +480,8 @@ export function HierarchyTab({
|
||||
setConfirmAction({ type: 'unlinkField', pageId: String(selectedPage.id), sectionId: String(section.id), fieldId: String(field.id) });
|
||||
}}
|
||||
onEdit={() => handleEditField(String(section.id), field)}
|
||||
prevFieldId={fieldIndex > 0 ? sortedFields[fieldIndex - 1].id : undefined}
|
||||
nextFieldId={fieldIndex < sortedFields.length - 1 ? sortedFields[fieldIndex + 1].id : undefined}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user