function initSurveyFormModule(moduleId) { const moduleElement = document.getElementById(moduleId); if (!moduleElement || moduleElement.classList.contains('initialized')) return; // 설문 데이터 가져오기 const surveyData = JSON.parse(moduleElement.dataset.survey || '{}'); const { survey, questions, theme_color } = surveyData; // DOM 요소들 const questionsContainer = moduleElement.querySelector('#questionsContainer'); const progressFill = moduleElement.querySelector('#progressFill'); const progressText = moduleElement.querySelector('#progressText'); const currentQuestionSpan = moduleElement.querySelector('#currentQuestion'); const submitBtn = moduleElement.querySelector('#submitBtn'); const surveyForm = moduleElement.querySelector('#surveyForm'); const confirmModal = moduleElement.querySelector('.confirm-modal'); const modalOverlay = confirmModal.querySelector('.modal-overlay'); const modalClose = confirmModal.querySelector('.modal-close'); const btnCancel = confirmModal.querySelector('.btn-cancel'); const btnConfirm = confirmModal.querySelector('.btn-confirm'); // CSS 변수 설정 if (theme_color) { moduleElement.style.setProperty('--survey-primary', theme_color); moduleElement.style.setProperty('--survey-primary-light', theme_color + '20'); moduleElement.style.setProperty('--survey-primary-dark', theme_color + 'CC'); } // 질문 렌더링 function renderQuestions() { if (!questions || !questions.length) return; const questionsHTML = questions.map((question, index) => { const fieldName = `answer_${question.sq_id}`; const required = question.sq_required ? 'required' : ''; const requiredMark = question.sq_required ? '*' : ''; let inputHTML = ''; switch (question.sq_type) { case 'text': inputHTML = ` `; break; case 'textarea': inputHTML = ` `; break; case 'radio': if (question.sq_options && Array.isArray(question.sq_options)) { inputHTML = `
${question.sq_options.map((option, optionIndex) => `
`).join('')}
`; } break; case 'checkbox': if (question.sq_options && Array.isArray(question.sq_options)) { inputHTML = `
${question.sq_options.map((option, optionIndex) => `
`).join('')}
`; } break; case 'select': if (question.sq_options && Array.isArray(question.sq_options)) { inputHTML = ` `; } break; case 'rating': const scale = question.sq_options?.scale || 5; const labels = question.sq_options?.labels || []; inputHTML = `
${Array.from({ length: scale }, (_, i) => i + 1).map(value => `
${value}
${labels[value - 1] ? `
${escapeHtml(labels[value - 1])}
` : ''}
`).join('')}
`; break; case 'date': inputHTML = ` `; break; } return `
${index + 1}

${escapeHtml(question.sq_title)} ${requiredMark}

${question.sq_description ? `

${escapeHtml(question.sq_description)}

` : ''}
${inputHTML}
`; }).join(''); questionsContainer.innerHTML = questionsHTML; } // HTML 이스케이프 함수 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 진행률 업데이트 function updateProgress() { let answeredQuestions = 0; const totalQuestions = questions.length; questions.forEach((question, index) => { const questionContainer = questionsContainer.children[index]; if (!questionContainer) return; const inputs = questionContainer.querySelectorAll('input, textarea, select'); let hasAnswer = false; inputs.forEach(input => { if (input.type === 'radio' || input.type === 'checkbox') { if (input.checked) hasAnswer = true; } else if (input.value.trim() !== '') { hasAnswer = true; } }); if (hasAnswer) { answeredQuestions++; } }); const progress = Math.round((answeredQuestions / totalQuestions) * 100); progressFill.style.width = progress + '%'; progressText.textContent = progress + '%'; currentQuestionSpan.textContent = answeredQuestions; // 모든 필수 질문이 답변되었는지 확인 const requiredQuestions = questionsContainer.querySelectorAll('input[required], textarea[required], select[required]'); let allRequiredAnswered = true; requiredQuestions.forEach(input => { if (input.type === 'radio') { const radioGroup = questionsContainer.querySelectorAll(`input[name="${input.name}"]`); let radioChecked = false; radioGroup.forEach(radio => { if (radio.checked) radioChecked = true; }); if (!radioChecked) allRequiredAnswered = false; } else if (input.type === 'checkbox') { const checkboxGroup = questionsContainer.querySelectorAll(`input[name="${input.name}"]`); let checkboxChecked = false; checkboxGroup.forEach(checkbox => { if (checkbox.checked) checkboxChecked = true; }); if (!checkboxChecked) allRequiredAnswered = false; } else if (input.value.trim() === '') { allRequiredAnswered = false; } }); submitBtn.disabled = !allRequiredAnswered; } // 이벤트 리스너 바인딩 function bindEvents() { // 라디오/체크박스 스타일링 questionsContainer.addEventListener('click', (e) => { const radioItem = e.target.closest('.radio-item'); const checkboxItem = e.target.closest('.checkbox-item'); if (radioItem) { const input = radioItem.querySelector('input'); const groupName = input.name; // 라디오 버튼 그룹의 다른 선택 해제 questionsContainer.querySelectorAll(`input[name="${groupName}"]`).forEach(radio => { radio.closest('.radio-item').classList.remove('selected'); }); input.checked = true; radioItem.classList.add('selected'); updateProgress(); } if (checkboxItem) { const input = checkboxItem.querySelector('input'); input.checked = !input.checked; checkboxItem.classList.toggle('selected', input.checked); updateProgress(); } }); // 평점 클릭 이벤트 questionsContainer.addEventListener('click', (e) => { const ratingItem = e.target.closest('.rating-item'); if (ratingItem) { const value = ratingItem.dataset.value; const input = ratingItem.querySelector('input'); const container = ratingItem.closest('.rating-container'); // 같은 그룹의 다른 평점 해제 container.querySelectorAll('.rating-item').forEach(item => { item.classList.remove('selected'); }); // 현재 평점 선택 ratingItem.classList.add('selected'); input.checked = true; updateProgress(); } }); // 일반 입력 필드 이벤트 questionsContainer.addEventListener('input', updateProgress); questionsContainer.addEventListener('change', updateProgress); // 폼 제출 이벤트 surveyForm.addEventListener('submit', (e) => { e.preventDefault(); if (submitBtn.disabled) { showNotification('모든 필수 항목을 입력해주세요.', 'error'); return; } // 확인 모달 표시 showConfirmModal(); }); // 모달 이벤트 modalClose.addEventListener('click', hideConfirmModal); btnCancel.addEventListener('click', hideConfirmModal); modalOverlay.addEventListener('click', hideConfirmModal); btnConfirm.addEventListener('click', () => { hideConfirmModal(); submitSurvey(); }); // ESC 키로 모달 닫기 document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && confirmModal.classList.contains('show')) { hideConfirmModal(); } }); } // 확인 모달 표시 function showConfirmModal() { confirmModal.classList.add('show'); document.body.style.overflow = 'hidden'; } // 확인 모달 숨기기 function hideConfirmModal() { confirmModal.classList.remove('show'); document.body.style.overflow = ''; } // 설문 제출 function submitSurvey() { submitBtn.classList.add('loading'); submitBtn.innerHTML = '
제출 중...'; submitBtn.disabled = true; const formData = new FormData(surveyForm); formData.append('ajax', '1'); fetch(surveyForm.action, { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { showNotification('설문이 성공적으로 제출되었습니다!', 'success'); setTimeout(() => { window.location.href = data.redirect_url; }, 1500); } else { showNotification(data.errors ? data.errors.join('\n') : '제출 중 오류가 발생했습니다.', 'error'); submitBtn.classList.remove('loading'); submitBtn.innerHTML = ' 설문 제출하기'; submitBtn.disabled = false; } }) .catch(error => { console.error('Error:', error); showNotification('제출 중 오류가 발생했습니다.', 'error'); submitBtn.classList.remove('loading'); submitBtn.innerHTML = ' 설문 제출하기'; submitBtn.disabled = false; }); } // 알림 표시 function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `survey-notification survey-notification-${type}`; notification.innerHTML = `
${message}
`; // 스타일 추가 notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: ${type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#17a2b8'}; color: white; padding: 15px 20px; border-radius: 8px; box-shadow: 0 5px 15px rgba(0,0,0,0.2); z-index: 1060; animation: slideInRight 0.3s ease; max-width: 300px; word-wrap: break-word; `; document.body.appendChild(notification); setTimeout(() => { notification.style.animation = 'slideOutRight 0.3s ease'; setTimeout(() => { notification.remove(); }, 300); }, 5000); } // 스크롤 시 질문 하이라이트 function initScrollHighlight() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 모든 하이라이트 제거 questionsContainer.querySelectorAll('.question-container').forEach(q => { q.classList.remove('highlight'); }); // 현재 질문 하이라이트 entry.target.classList.add('highlight'); } }); }, { threshold: 0.5, rootMargin: '-20% 0px -20% 0px' }); questionsContainer.querySelectorAll('.question-container').forEach(question => { observer.observe(question); }); } // 질문 애니메이션 초기화 function initQuestionAnimations() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.animationPlayState = 'running'; } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); questionsContainer.querySelectorAll('.question-container').forEach(question => { question.style.opacity = '0'; question.style.animationPlayState = 'paused'; observer.observe(question); }); } // 초기화 function init() { renderQuestions(); bindEvents(); updateProgress(); initScrollHighlight(); initQuestionAnimations(); moduleElement.classList.add('initialized'); } // 모듈 초기화 실행 init(); } // 추가 CSS 애니메이션 (JavaScript로 동적 추가) const additionalStyles = ` @keyframes slideInRight { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slideOutRight { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } } .survey-notification .notification-content { display: flex; align-items: center; gap: 10px; } .survey-notification i { font-size: 1.2em; flex-shrink: 0; } `; // 스타일 추가 (한 번만) if (!document.getElementById('survey-form-module-styles')) { const styleSheet = document.createElement('style'); styleSheet.id = 'survey-form-module-styles'; styleSheet.textContent = additionalStyles; document.head.appendChild(styleSheet); }