first commit 2

This commit is contained in:
hmw1001
2026-06-11 18:47:38 +09:00
parent c768729ce6
commit 6f534e33a6
11095 changed files with 1595758 additions and 0 deletions
@@ -0,0 +1,95 @@
/**
* 파일명: contact-form-handler.js
* 설명: 홈페이지 메인의 상담 신청 폼을 처리하고 팝업을 제어하는 스크립트
*/
// 💡 [핵심 수정] jQuery를 사용하여 팝업 열기/닫기 기능 구현
$(function() {
const $modal = $('#contact-modal');
// '문의' 링크 클릭 시 팝업 열기
$('#open-contact-modal').on('click', function(e) {
e.preventDefault();
$modal.addClass('active');
});
// 닫기 버튼 클릭 시 팝업 닫기
$modal.on('click', '.modal-close', function(e) {
e.preventDefault();
$modal.removeClass('active');
});
// 팝업 배경 클릭 시 닫기
$modal.on('click', function(e) {
if ($(e.target).is($modal)) {
$modal.removeClass('active');
}
});
});
document.addEventListener('DOMContentLoaded', function() {
const contactForm = document.getElementById('contactForm');
const formMessages = document.getElementById('form-messages');
const submitButton = document.getElementById('contact-submit-btn');
if (contactForm && formMessages && submitButton) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault(); // 기본 폼 전송을 막습니다.
const originalButtonText = submitButton.textContent;
submitButton.disabled = true;
submitButton.textContent = '전송 중...';
formMessages.style.display = 'none';
formMessages.className = 'form-message-area'; // CSS 클래스 초기화
const formData = new FormData(contactForm);
const variables = {
contact_name: formData.get('contact_name'),
contact_hp: formData.get('contact_hp'),
contact_email: formData.get('contact_email'),
// textarea의 줄바꿈을 HTML <br> 태그로 변환하여 메일에 반영합니다.
contact_message: formData.get('contact_message').replace(/\n/g, '<br>')
};
// [추가] 메일 발송 에이전트(universalMailer) 로드 여부 확인
if (!window.universalMailer) {
alert('메일 발송 모듈(Agent)이 로드되지 않았습니다.\n페이지를 새로고침 하거나 관리자에게 문의하세요.');
submitButton.disabled = false;
submitButton.textContent = originalButtonText;
return;
}
// 💡 universalMailer 객체를 사용하여 메일 발송
window.universalMailer.send({
template_code: 'contact_inquiry', // 관리자에서 생성할 템플릿 코드
to_email : variables.contact_email,
// [추가] 참조 이메일 설정
// 'ADMIN_EMAIL' 키워드를 사용하면 서버(ajax_universal_send.php)에서
// 실제 관리자 이메일 주소(config.php의 cf_admin_email)로 자동 치환합니다.
cc_email: ['ADMIN_EMAIL'],
variables: variables,
onSuccess: function(response) {
alert(response.message || '상담 신청이 성공적으로 접수되었습니다. 빠른 시일 내에 연락드리겠습니다.');
contactForm.reset(); // 폼 초기화
// 성공 시 팝업 닫기
const contactModal = document.getElementById('contact-modal');
if (contactModal) {
// 모달의 닫기 버튼을 클릭하는 방식으로 닫습니다.
const closeButton = contactModal.querySelector('.modal-close');
if (closeButton) closeButton.click();
}
},
onError: function(errorMessage) {
formMessages.textContent = errorMessage || '오류가 발생했습니다. 잠시 후 다시 시도해주세요.';
formMessages.classList.add('error');
formMessages.style.display = 'block';
},
onComplete: function() {
submitButton.disabled = false;
submitButton.textContent = originalButtonText;
}
});
});
}
});
@@ -0,0 +1,59 @@
<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
// 📌 [핵심] 이 파일 하나만 include 하면 HTML, CSS, JS가 모두 로드되도록 구성합니다.
// 1. CSS 로드
// 현재 스킨 폴더의 style.css를 불러옵니다.
// 💡 [핵심 수정] 현재 스킨의 URL을 변수로 정의
$contact_skin_url = G5_THEME_URL.'/skin/contact/basic';
// 1. CSS 로드
add_stylesheet('<link rel="stylesheet" href="'.$contact_skin_url.'/style.css">', 0);
// 2. JS 로드
add_javascript('<script src="'.$contact_skin_url.'/universal-mailer.js"></script>', 10);
add_javascript('<script src="'.$contact_skin_url.'/contact-form-handler.js"></script>', 11);
?>
<!-- 3. HTML 구조 (문의하기 팝업 모달) -->
<div id="contact-modal" class="modal-overlay">
<div class="modal-content">
<button type="button" class="modal-close">&times;</button>
<div class="section-header">
<span class="subtitle">Contact Us</span>
<h2>공간의 가능성을 열어보세요.</h2>
<p>성진미도어의 전문가와 상담하고, 당신의 공간에 꼭 맞는 솔루션을 찾아보세요.</p>
</div>
<div class="contact-wrapper">
<div class="contact-info">
<h3>Information</h3>
<div class="info-item">
<strong>본사 및 전시장</strong>
<p>충청남도 아산시 음봉면 월산로 128-130</p>
</div>
<div class="info-item">
<strong>대표 연락처</strong>
<p>T. 041-532-0555 / H. 010-5434-4126</p>
</div>
<!-- <div class="info-item">
<strong>청주 전시장</strong>
<p>T. 043-235-2352 / H. 010-2066-4126</p>
</div> -->
<div class="info-item">
<strong>운영시간</strong>
<p>평일 09:00 - 18:00 (주말 및 공휴일 휴무)</p>
</div>
</div>
<form name="contactForm" id="contactForm" class="contact-form" method="post">
<h3>상담 신청</h3>
<div id="form-messages" class="form-message-area"></div> <!-- 💡 메시지 표시 영역 -->
<input type="text" name="contact_name" placeholder="이름" required>
<input type="tel" name="contact_hp" placeholder="연락처" required>
<input type="email" name="contact_email" placeholder="이메일" required>
<textarea name="contact_message" placeholder="문의 내용을 입력해주세요." rows="5" required></textarea>
<button type="submit" id="contact-submit-btn" class="cta-button">상담 신청하기</button>
</form>
</div>
</div>
</div>
@@ -0,0 +1,112 @@
/* --- 문의하기 팝업(모달) 스타일 --- */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999; /* 💡 [핵심 수정] z-index 값을 매우 높게 설정 */
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.modal-overlay.active {
opacity: 1;
visibility: visible;
}
.modal-content {
background-color: #fff;
padding: 40px;
border-radius: 12px;
box-shadow: 0 5px 20px rgba(0,0,0,0.2);
width: 90%;
max-width: 960px; /* 팝업 최대 너비 */
max-height: 90vh; /* 팝업 최대 높이 */
overflow-y: auto; /* 내용이 길면 스크롤 */
position: relative;
transform: scale(0.9);
transition: transform 0.3s ease;
}
.modal-overlay.active .modal-content {
transform: scale(1);
}
.modal-close {
position: absolute;
top: 15px;
right: 20px;
background: none;
border: none;
font-size: 28px;
font-weight: bold;
color: #888;
cursor: pointer;
line-height: 1;
padding: 0;
}
.modal-close:hover {
color: #333;
}
/* --- 문의 폼 메시지 영역 --- */
.form-message-area {
padding: 15px;
margin-bottom: 20px;
border-radius: 8px;
font-weight: 500;
display: none; /* 평소에는 숨김 */
text-align: center;
}
.form-message-area.success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
display: block;
}
.form-message-area.error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
display: block;
}
/* --- 컨텐츠 내부 스타일 (기존 CSS에서 가져옴) --- */
.contact-wrapper { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; }
.contact-info h3, .contact-form h3 { font-size: 28px; font-weight: 900; color: #2c3e50; margin-bottom: 32px; }
.info-item { margin-bottom: 24px; }
.info-item strong { display: block; font-size: 16px; font-weight: 700; color: #34495e; margin-bottom: 4px; }
.info-item p { font-size: 18px; color: #333; }
.contact-form input, .contact-form textarea { width: 100%; padding: 16px; border: 1px solid #ddd; border-radius: 8px; margin-bottom: 16px; font-size: 16px; font-family: 'Noto Sans KR', sans-serif; }
.contact-form input:focus, .contact-form textarea:focus { outline: none; border-color: #2c3e50; box-shadow: 0 0 0 3px rgba(44, 62, 80, 0.1); }
.contact-form .cta-button { width: 100%; font-size: 16px; cursor: pointer; background-color: #2c3e50; color: #ffffff; border: 2px solid #2c3e50; padding: 16px 32px; border-radius: 8px; font-weight: 700; transition: all 0.3s ease; }
.contact-form .cta-button:hover { background-color: #34495e; border-color: #34495e; color: #ffffff; }
/* 반응형 스타일 */
@media (max-width: 992px) {
.contact-wrapper {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.contact-wrapper {
padding: 0;
gap: 30px;
}
.modal-content {
padding: 20px;
width: 95%;
}
.contact-info h3, .contact-form h3 {
font-size: 24px;
margin-bottom: 20px;
}
}
@@ -0,0 +1,90 @@
/**
* 파일명: universal-mailer.js
* 설명: 사이트 전체에서 사용할 수 있는 범용 메일 발송 클라이언트
*/
(function(window) {
'use strict';
function UniversalMailer() {}
/**
* AJAX를 통해 지정된 템플릿으로 이메일을 발송합니다.
* @param {object} options - 메일 발송 옵션 객체
* @param {string} options.template_code - 사용할 메일 템플릿의 고유 코드
* @param {object} options.variables - 템플릿에 치환될 변수 객체 (예: {name: "홍길동"})
* @param {string|string[]} [options.to_email] - 수신자 이메일. (문자열 또는 배열)
* @param {string|string[]} [options.cc_email] - 참조 이메일. (문자열 또는 배열)
* @param {string|string[]} [options.bcc_email] - 숨은 참조 이메일. (문자열 또는 배열)
* @param {function} [options.onSuccess] - 발송 성공 시 실행될 콜백 함수
* @param {function} [options.onError] - 발송 실패 시 실행될 콜백 함수
* @param {function} [options.onComplete] - 성공/실패와 관계없이 마지막에 실행될 콜백 함수
*/
UniversalMailer.prototype.send = function(options) {
const formData = new FormData();
formData.append('template_code', options.template_code);
// 수신자 처리 (배열 또는 문자열)
if (options.to_email) {
if (Array.isArray(options.to_email)) {
options.to_email.forEach(email => formData.append('to_email[]', email));
} else {
formData.append('to_email', options.to_email);
}
}
// 참조자 처리 (배열 또는 문자열)
if (options.cc_email) {
if (Array.isArray(options.cc_email)) {
options.cc_email.forEach(email => formData.append('cc_email[]', email));
} else {
formData.append('cc_email', options.cc_email);
}
}
// 숨은 참조자 처리 (배열 또는 문자열)
if (options.bcc_email) {
if (Array.isArray(options.bcc_email)) {
options.bcc_email.forEach(email => formData.append('bcc_email[]', email));
} else {
formData.append('bcc_email', options.bcc_email);
}
}
if (options.variables) {
for (const key in options.variables) {
formData.append(`variables[${key}]`, options.variables[key]);
}
}
// GnuBoard의 g5_url 변수를 사용하여 AJAX 요청 URL을 생성합니다.
const ajax_url = (typeof g5_url !== 'undefined' ? g5_url : '') + '/adm/mail_manage/ajax_universal_send.php';
fetch(ajax_url, {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) throw new Error('서버와의 통신에 실패했습니다.');
return response.json();
})
.then(data => {
if (data.success) {
if (typeof options.onSuccess === 'function') options.onSuccess(data);
} else {
throw new Error(data.message || '알 수 없는 오류가 발생했습니다.');
}
})
.catch(error => {
if (typeof options.onError === 'function') options.onError(error.message);
})
.finally(() => {
if (typeof options.onComplete === 'function') options.onComplete();
});
};
// mailer 객체를 window 전역 객체에 등록하여 어디서든 접근 가능하게 합니다.
window.universalMailer = new UniversalMailer();
})(window);