200 lines
6.4 KiB
Markdown
200 lines
6.4 KiB
Markdown
# [계획서] 카테고리 트리 대분류 추가 모달 - 연속 등록 모드 수정
|
|
|
|
> 관련 문서: [맥락노트](./CCA[맥락]-카테고리-연속등록모드.md) | [체크리스트](./CCA[체크]-카테고리-연속등록모드.md)
|
|
|
|
## 개요
|
|
|
|
기준정보 - 옵션설정 화면에서 트리 구조 카테고리(예: 품목정보 > 재고단위)의 "대분류 추가" 모달이 저장 후 닫히지 않는 버그를 수정합니다.
|
|
평면 목록용 추가 모달(`CategoryValueAddDialog.tsx`)과 동일한 연속 입력 패턴을 적용합니다.
|
|
|
|
---
|
|
|
|
## 현재 동작
|
|
|
|
- 대분류 추가 모달에서 값 입력 후 "추가" 클릭 시 **값은 정상 저장됨**
|
|
- 저장 후 **모달이 닫히지 않고** 폼만 초기화됨 (항상 연속 입력 상태)
|
|
- "연속 입력" 체크박스 UI가 **없음** → 사용자가 모드를 끌 수 없음
|
|
- 모달을 닫으려면 "닫기" 버튼 또는 외부 클릭을 해야 함
|
|
|
|
### 현재 코드 (CategoryValueManagerTree.tsx - handleAdd, 512~530행)
|
|
|
|
```tsx
|
|
if (response.success) {
|
|
toast.success("카테고리가 추가되었습니다");
|
|
// 폼 초기화 (모달은 닫지 않고 연속 입력)
|
|
setFormData((prev) => ({
|
|
...prev,
|
|
valueCode: "",
|
|
valueLabel: "",
|
|
description: "",
|
|
color: "",
|
|
}));
|
|
setTimeout(() => addNameRef.current?.focus(), 50);
|
|
await loadTree(true);
|
|
if (parentValue) {
|
|
setExpandedNodes((prev) => new Set([...prev, parentValue.valueId]));
|
|
}
|
|
}
|
|
```
|
|
|
|
### 현재 DialogFooter (809~821행)
|
|
|
|
```tsx
|
|
<DialogFooter className="gap-2 sm:gap-0">
|
|
<Button variant="outline" onClick={() => setIsAddModalOpen(false)} ...>
|
|
닫기
|
|
</Button>
|
|
<Button onClick={handleAdd} ...>
|
|
추가
|
|
</Button>
|
|
</DialogFooter>
|
|
```
|
|
|
|
---
|
|
|
|
## 변경 후 동작
|
|
|
|
### 1. 기본 동작: 저장 후 모달 닫힘
|
|
|
|
- "추가" 클릭 → 저장 성공 → 모달 닫힘 + 트리 새로고침
|
|
- `CategoryValueAddDialog.tsx`(평면 목록 추가 모달)와 동일한 기본 동작
|
|
|
|
### 2. 연속 입력 체크박스 추가
|
|
|
|
- DialogFooter 좌측에 "연속 입력" 체크박스 표시
|
|
- 기본값: 체크 해제 (OFF)
|
|
- 체크 시: 저장 후 폼만 초기화, 모달 유지, 이름 필드에 포커스
|
|
- 체크 해제 시: 저장 후 모달 닫힘
|
|
|
|
---
|
|
|
|
## 시각적 예시
|
|
|
|
| 상태 | 연속 입력 체크 | 추가 버튼 클릭 후 |
|
|
|------|---------------|-----------------|
|
|
| 기본 (체크 해제) | [ ] 연속 입력 | 저장 → 모달 닫힘 → 트리 갱신 |
|
|
| 연속 모드 (체크) | [x] 연속 입력 | 저장 → 폼 초기화 → 모달 유지 → 이름 필드 포커스 |
|
|
|
|
### 모달 하단 레이아웃 (ScreenModal.tsx 패턴)
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ [닫기] [추가] │ ← DialogFooter (버튼만)
|
|
├─────────────────────────────────────────┤
|
|
│ [x] 저장 후 계속 입력 (연속 등록 모드) │ ← border-t 구분선 아래 별도 영역
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 아키텍처
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A["사용자: '추가' 클릭"] --> B["handleAdd()"]
|
|
B --> C{"API 호출 성공?"}
|
|
C -- 실패 --> D["toast.error → 모달 유지"]
|
|
C -- 성공 --> E["toast.success + loadTree"]
|
|
E --> F{"continuousAdd?"}
|
|
F -- true --> G["폼 초기화 + 이름 필드 포커스\n모달 유지"]
|
|
F -- false --> H["폼 초기화 + 모달 닫힘"]
|
|
```
|
|
|
|
---
|
|
|
|
## 변경 대상 파일
|
|
|
|
| 파일 | 역할 | 변경 내용 |
|
|
|------|------|----------|
|
|
| `frontend/components/table-category/CategoryValueManagerTree.tsx` | 트리형 카테고리 값 관리 | 상태 추가, handleAdd 분기, DialogFooter UI |
|
|
|
|
- **변경 규모**: 약 20줄 내외 소규모 변경
|
|
- **참고 파일**: `frontend/components/table-category/CategoryValueAddDialog.tsx` (동일 패턴)
|
|
|
|
---
|
|
|
|
## 코드 설계
|
|
|
|
### 1. 상태 추가 (286행 근처, 모달 상태 선언부)
|
|
|
|
```tsx
|
|
const [continuousAdd, setContinuousAdd] = useState(false);
|
|
```
|
|
|
|
### 2. handleAdd 성공 분기 수정 (512~530행 대체)
|
|
|
|
```tsx
|
|
if (response.success) {
|
|
toast.success("카테고리가 추가되었습니다");
|
|
await loadTree(true);
|
|
if (parentValue) {
|
|
setExpandedNodes((prev) => new Set([...prev, parentValue.valueId]));
|
|
}
|
|
|
|
if (continuousAdd) {
|
|
setFormData((prev) => ({
|
|
...prev,
|
|
valueCode: "",
|
|
valueLabel: "",
|
|
description: "",
|
|
color: "",
|
|
}));
|
|
setTimeout(() => addNameRef.current?.focus(), 50);
|
|
} else {
|
|
setFormData({ valueCode: "", valueLabel: "", description: "", color: "", isActive: true });
|
|
setIsAddModalOpen(false);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. DialogFooter + 연속 등록 체크박스 수정 (809~821행 대체)
|
|
|
|
DialogFooter는 버튼만 유지하고, 그 아래에 `border-t` 구분선과 체크박스를 별도 영역으로 배치합니다.
|
|
`ScreenModal.tsx` (1287~1303행) 패턴 그대로입니다.
|
|
|
|
```tsx
|
|
<DialogFooter className="gap-2 sm:gap-0">
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => setIsAddModalOpen(false)}
|
|
className="h-9 flex-1 text-sm sm:flex-none"
|
|
>
|
|
닫기
|
|
</Button>
|
|
<Button onClick={handleAdd} className="h-9 flex-1 text-sm sm:flex-none">
|
|
추가
|
|
</Button>
|
|
</DialogFooter>
|
|
|
|
{/* 연속 등록 모드 체크박스 - ScreenModal.tsx 패턴 */}
|
|
<div className="border-t px-4 py-3">
|
|
<div className="flex items-center gap-2">
|
|
<Checkbox
|
|
id="tree-continuous-add"
|
|
checked={continuousAdd}
|
|
onCheckedChange={(checked) => setContinuousAdd(checked as boolean)}
|
|
/>
|
|
<Label htmlFor="tree-continuous-add" className="cursor-pointer text-sm font-normal select-none">
|
|
저장 후 계속 입력 (연속 등록 모드)
|
|
</Label>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## 예상 문제 및 대응
|
|
|
|
`CategoryValueAddDialog.tsx`와 동일한 패턴이므로 별도 예상 문제 없음.
|
|
|
|
---
|
|
|
|
## 설계 원칙
|
|
|
|
- `CategoryValueAddDialog.tsx`(같은 폴더, 같은 목적)의 패턴을 그대로 따름
|
|
- 기존 수정/삭제 모달 동작은 변경하지 않음
|
|
- 하위 추가(중분류/소분류) 모달도 동일한 `handleAdd`를 사용하므로 자동 적용
|
|
- `Checkbox` import는 이미 존재 (24행)하므로 추가 import 불필요
|
|
- `Label` import는 이미 존재 (53행)하므로 추가 import 불필요
|
|
- 체크박스 위치/라벨/className 모두 `ScreenModal.tsx` (1287~1303행)과 동일
|