// ======================================== // Contact 페이지 전용 JavaScript // ======================================== document.addEventListener('DOMContentLoaded', function() { initContactForm(); initModal(); initMap(); initFormValidation(); }); // 연락처 폼 초기화 function initContactForm() { const form = document.getElementById('contactForm'); if (form) { form.addEventListener('submit', handleFormSubmit); // 실시간 유효성 검사 const inputs = form.querySelectorAll('input, select, textarea'); inputs.forEach(input => { input.addEventListener('blur', validateField); input.addEventListener('input', clearFieldError); }); // 전화번호 자동 포맷팅 const phoneInput = document.getElementById('phone'); if (phoneInput) { phoneInput.addEventListener('input', formatPhoneNumber); } // 리셋 버튼 확인 const resetBtn = form.querySelector('button[type="reset"]'); if (resetBtn) { resetBtn.addEventListener('click', handleFormReset); } } } // 폼 제출 처리 async function handleFormSubmit(e) { e.preventDefault(); const form = e.target; const submitBtn = form.querySelector('button[type="submit"]'); // 유효성 검사 if (!validateForm(form)) { showNotification('입력 정보를 확인해 주세요.', 'error'); return; } // 제출 버튼 비활성화 const originalText = submitBtn.textContent; submitBtn.textContent = '전송 중...'; submitBtn.disabled = true; try { // 폼 데이터 수집 const formData = new FormData(form); const data = Object.fromEntries(formData); // 실제 서버 전송 (현재는 시뮬레이션) await submitContactForm(data); // 성공 메시지 showNotification('문의가 성공적으로 전송되었습니다. 빠른 시일 내에 연락드리겠습니다.', 'success'); form.reset(); } catch (error) { console.error('Form submission error:', error); showNotification('전송 중 오류가 발생했습니다. 다시 시도해 주세요.', 'error'); } finally { // 버튼 복원 submitBtn.textContent = originalText; submitBtn.disabled = false; } } // 서버 전송 시뮬레이션 async function submitContactForm(data) { // 실제 구현 시 서버 API 호출 return new Promise((resolve, reject) => { setTimeout(() => { // 90% 확률로 성공 if (Math.random() > 0.1) { resolve({ success: true, message: '전송 완료' }); } else { reject(new Error('서버 오류')); } }, 2000); }); } // 폼 리셋 처리 function handleFormReset(e) { const confirmed = confirm('입력한 내용이 모두 삭제됩니다. 계속하시겠습니까?'); if (!confirmed) { e.preventDefault(); } else { // 에러 메시지 제거 const errorElements = document.querySelectorAll('.field-error'); errorElements.forEach(el => el.remove()); // 필드 에러 스타일 제거 const fields = document.querySelectorAll('.form-group input, .form-group select, .form-group textarea'); fields.forEach(field => field.classList.remove('error')); } } // 폼 유효성 검사 function validateForm(form) { let isValid = true; // 필수 필드 검사 const requiredFields = form.querySelectorAll('[required]'); requiredFields.forEach(field => { if (!validateField({ target: field })) { isValid = false; } }); // 이메일 형식 검사 const emailField = form.querySelector('#email'); if (emailField && emailField.value && !isValidEmail(emailField.value)) { showFieldError(emailField, '올바른 이메일 형식을 입력해 주세요.'); isValid = false; } // 전화번호 형식 검사 const phoneField = form.querySelector('#phone'); if (phoneField && phoneField.value && !isValidPhone(phoneField.value)) { showFieldError(phoneField, '올바른 전화번호 형식을 입력해 주세요.'); isValid = false; } return isValid; } // 개별 필드 유효성 검사 function validateField(e) { const field = e.target; const value = field.value.trim(); // 기존 에러 메시지 제거 clearFieldError(e); // 필수 필드 검사 if (field.required && !value) { showFieldError(field, '필수 입력 항목입니다.'); return false; } // 이메일 형식 검사 if (field.type === 'email' && value && !isValidEmail(value)) { showFieldError(field, '올바른 이메일 형식을 입력해 주세요.'); return false; } // 전화번호 형식 검사 if (field.type === 'tel' && value && !isValidPhone(value)) { showFieldError(field, '올바른 전화번호 형식을 입력해 주세요.'); return false; } return true; } // 필드 에러 표시 function showFieldError(field, message) { field.classList.add('error'); const errorEl = document.createElement('div'); errorEl.className = 'field-error'; errorEl.textContent = message; errorEl.style.color = '#ef4444'; errorEl.style.fontSize = '0.875rem'; errorEl.style.marginTop = '0.25rem'; field.parentNode.appendChild(errorEl); } // 필드 에러 제거 function clearFieldError(e) { const field = e.target; field.classList.remove('error'); const errorEl = field.parentNode.querySelector('.field-error'); if (errorEl) { errorEl.remove(); } } // 이메일 유효성 검사 function isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } // 전화번호 유효성 검사 function isValidPhone(phone) { const phoneRegex = /^[0-9-+\s()]+$/; return phoneRegex.test(phone) && phone.replace(/[^0-9]/g, '').length >= 10; } // 전화번호 자동 포맷팅 function formatPhoneNumber(e) { let value = e.target.value.replace(/[^0-9]/g, ''); if (value.length >= 11) { // 01X-XXXX-XXXX 형태 value = value.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3'); } else if (value.length >= 7) { // 01X-XXX-XXXX 또는 01X-XXXX-XXX 형태 value = value.replace(/(\d{3})(\d{3,4})(\d{0,4})/, '$1-$2-$3'); } else if (value.length >= 3) { // 01X-XXX 형태 value = value.replace(/(\d{3})(\d{0,4})/, '$1-$2'); } e.target.value = value; } // 알림 메시지 표시 function showNotification(message, type = 'info') { // 기존 알림 제거 const existingNotification = document.querySelector('.notification'); if (existingNotification) { existingNotification.remove(); } // 새 알림 생성 const notification = document.createElement('div'); notification.className = `notification notification-${type}`; notification.innerHTML = ` ${message} `; // 스타일 설정 Object.assign(notification.style, { position: 'fixed', top: '20px', right: '20px', padding: '1rem 1.5rem', borderRadius: '8px', boxShadow: '0 4px 15px rgba(0, 0, 0, 0.15)', zIndex: '9999', maxWidth: '400px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '1rem' }); // 타입별 색상 const colors = { success: { bg: '#10b981', color: 'white' }, error: { bg: '#ef4444', color: 'white' }, info: { bg: '#3b82f6', color: 'white' } }; const color = colors[type] || colors.info; notification.style.backgroundColor = color.bg; notification.style.color = color.color; // 닫기 버튼 스타일 const closeBtn = notification.querySelector('.notification-close'); Object.assign(closeBtn.style, { background: 'none', border: 'none', color: 'inherit', fontSize: '1.5rem', cursor: 'pointer', padding: '0', lineHeight: '1' }); // 닫기 기능 closeBtn.addEventListener('click', () => notification.remove()); // DOM에 추가 document.body.appendChild(notification); // 5초 후 자동 제거 setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 5000); } // 모달 초기화 function initModal() { const modal = document.getElementById('privacyModal'); const privacyLink = document.querySelector('.privacy-link'); const closeBtn = modal?.querySelector('.modal-close'); if (privacyLink && modal) { privacyLink.addEventListener('click', function(e) { e.preventDefault(); modal.classList.add('active'); document.body.style.overflow = 'hidden'; }); } if (closeBtn && modal) { closeBtn.addEventListener('click', function() { modal.classList.remove('active'); document.body.style.overflow = ''; }); } if (modal) { modal.addEventListener('click', function(e) { if (e.target === modal) { modal.classList.remove('active'); document.body.style.overflow = ''; } }); } // ESC 키로 모달 닫기 document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && modal?.classList.contains('active')) { modal.classList.remove('active'); document.body.style.overflow = ''; } }); } // 지도 초기화 function initMap() { // HTML에 이미 정적으로 정보가 표시되어 있으므로 // JavaScript로 덮어쓸 필요가 없음 // 지도 기능은 외부 링크(네이버 지도, 구글 맵)를 통해 제공 console.log('Map links are ready'); } // 폼 유효성 검사 초기화 function initFormValidation() { // CSS로 에러 스타일 정의 const style = document.createElement('style'); style.textContent = ` .form-group input.error, .form-group select.error, .form-group textarea.error { border-color: #ef4444 !important; box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1) !important; } .field-error { animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: translateY(0); } } .notification { animation: slideIn 0.3s ease; } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } `; document.head.appendChild(style); }