# 모달창 생성 시 유의사항

## 개요

이 문서는 SAM 프로젝트에서 모달창을 구현할 때 발생할 수 있는 문제점과 해결 방법을 정리한 것입니다.

---

## 1. pointer-events 문제

### 문제 상황

모달 배경 클릭을 방지하면서 모달 내부만 클릭 가능하게 하려고 다음과 같은 구조를 사용했을 때:

```html
<!-- 문제가 발생하는 구조 -->
<div class="fixed inset-0 z-50">
    <div class="absolute inset-0 bg-black bg-opacity-50"></div>
    <div class="absolute inset-0 flex items-center justify-center pointer-events-none">
        <div class="bg-white rounded-xl pointer-events-auto">
            <!-- AJAX로 로드되는 내용 -->
        </div>
    </div>
</div>
```

**증상**: 모달은 표시되지만 내부의 버튼, 입력 필드 등 모든 요소가 클릭되지 않음 (마치 돌덩어리처럼 동작)

### 원인

- `pointer-events-none`이 부모에 있고 `pointer-events-auto`가 자식에 있는 구조
- AJAX로 로드된 내용이 `pointer-events-auto` div 안에 들어가도, 그 안의 요소들에 pointer-events가 제대로 상속되지 않을 수 있음
- 특히 동적으로 로드된 HTML에서 이 문제가 자주 발생

### 해결 방법

`pointer-events-none/auto` 구조를 사용하지 않고 단순화:

```html
<!-- 올바른 구조 -->
<div id="modal" class="hidden fixed inset-0 z-50 overflow-y-auto">
    <!-- 배경 오버레이 -->
    <div class="fixed inset-0 bg-black bg-opacity-50"></div>
    <!-- 모달 컨텐츠 wrapper -->
    <div class="flex min-h-full items-center justify-center p-4">
        <div id="modalContent" class="relative bg-white rounded-xl shadow-2xl w-full max-w-3xl">
            <!-- 내용 -->
        </div>
    </div>
</div>
```

---

## 2. AJAX로 로드된 HTML에서 함수 호출 문제

### 문제 상황

```html
<!-- AJAX로 로드된 HTML -->
<button onclick="closeModal()">닫기</button>
```

**증상**: `closeModal is not defined` 오류 발생

### 원인

- 함수가 `function closeModal() {}` 형태로 정의되면 호이스팅되지만, 모듈 스코프나 블록 스코프 안에 있을 수 있음
- AJAX로 로드된 HTML에서 전역 함수에 접근하지 못할 수 있음

### 해결 방법

**방법 1: window 객체에 명시적 등록**

```javascript
// 전역 스코프에 함수 등록
window.closeModal = function() {
    document.getElementById('modal').classList.add('hidden');
    document.body.style.overflow = '';
};
```

**방법 2: 이벤트 델리게이션 (권장)**

```html
<!-- HTML: data 속성 사용 -->
<button data-close-modal>닫기</button>
```

```javascript
// JavaScript: document 레벨에서 이벤트 감지
document.addEventListener('click', function(e) {
    const closeBtn = e.target.closest('[data-close-modal]');
    if (closeBtn) {
        e.preventDefault();
        window.closeModal();
    }
});
```

---

## 3. 배경 스크롤 방지

### 모달 열 때

```javascript
document.body.style.overflow = 'hidden';
```

### 모달 닫을 때

```javascript
document.body.style.overflow = '';
```

---

## 4. ESC 키로 모달 닫기

```javascript
document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') {
        window.closeModal();
    }
});
```

---

## 5. 완전한 모달 구현 예시

### HTML 구조

```html
<!-- 모달 -->
<div id="exampleModal" class="hidden fixed inset-0 z-50 overflow-y-auto">
    <!-- 배경 오버레이 -->
    <div class="fixed inset-0 bg-black bg-opacity-50 transition-opacity"></div>
    <!-- 모달 컨텐츠 wrapper -->
    <div class="flex min-h-full items-center justify-center p-4">
        <div id="exampleModalContent" class="relative bg-white rounded-xl shadow-2xl w-full max-w-3xl">
            <!-- 로딩 표시 또는 내용 -->
        </div>
    </div>
</div>
```

### JavaScript

```javascript
// 전역 함수 등록
window.openExampleModal = function(id) {
    const modal = document.getElementById('exampleModal');
    const content = document.getElementById('exampleModalContent');

    modal.classList.remove('hidden');
    document.body.style.overflow = 'hidden';

    // AJAX로 내용 로드
    fetch(`/api/example/${id}`)
        .then(response => response.text())
        .then(html => {
            content.innerHTML = html;
        });
};

window.closeExampleModal = function() {
    document.getElementById('exampleModal').classList.add('hidden');
    document.body.style.overflow = '';
};

// ESC 키 지원
document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') {
        window.closeExampleModal();
    }
});

// 이벤트 델리게이션 (닫기 버튼)
document.addEventListener('click', function(e) {
    if (e.target.closest('[data-close-modal]')) {
        e.preventDefault();
        window.closeExampleModal();
    }
});
```

### AJAX로 로드되는 부분 뷰

```html
<div class="p-6">
    <div class="flex justify-between items-center mb-4">
        <h2 class="text-xl font-bold">모달 제목</h2>
        <!-- data-close-modal 속성 사용 -->
        <button type="button" data-close-modal class="text-gray-400 hover:text-gray-600">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
            </svg>
        </button>
    </div>

    <!-- 내용 -->

    <div class="flex justify-end gap-3 mt-6">
        <button type="button" data-close-modal class="px-4 py-2 border rounded-lg">취소</button>
        <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg">확인</button>
    </div>
</div>
```

---

## 6. 체크리스트

모달 구현 시 다음 사항을 확인하세요:

- [ ] `pointer-events-none/auto` 구조를 사용하지 않음
- [ ] 함수를 `window` 객체에 등록했음
- [ ] 닫기 버튼에 `data-close-modal` 속성을 추가했음
- [ ] document 레벨 이벤트 델리게이션을 설정했음
- [ ] 모달 열 때 `body.style.overflow = 'hidden'` 설정
- [ ] 모달 닫을 때 `body.style.overflow = ''` 복원
- [ ] ESC 키 이벤트 리스너 등록
- [ ] z-index가 다른 요소들과 충돌하지 않음 (보통 z-50 사용)

---

## 관련 파일

- `/resources/views/sales/managers/index.blade.php` - 영업파트너 관리 모달 구현 예시
- `/resources/views/sales/managers/partials/show-modal.blade.php` - 상세 모달 부분 뷰
- `/resources/views/sales/managers/partials/edit-modal.blade.php` - 수정 모달 부분 뷰
