98 lines
4.2 KiB
PHP
98 lines
4.2 KiB
PHP
<div class="card border-0 shadow-sm p-4 p-md-5 rounded-4 bg-light">
|
|
<form id="inquiryForm">
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label small fw-bold">성함 / 업체명</label>
|
|
<input type="text" id="title" name="title" class="form-control" placeholder="성함을 입력하세요">
|
|
<div class="error" data-error-for="title"></div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label small fw-bold">이메일</label>
|
|
<input type="email" id="email" name="email" class="form-control" placeholder="예) contact@domain.com">
|
|
<div class="error" data-error-for="email"></div>
|
|
</div>
|
|
<div class="col-12">
|
|
<label class="form-label small fw-bold">문의 내용</label>
|
|
<textarea id="content" name="content" class="form-control" rows="5"
|
|
placeholder="문의하실 내용을 상세히 적어주세요."></textarea>
|
|
<div class="error" data-error-for="content"></div>
|
|
</div>
|
|
<div class="col-12 mt-4">
|
|
<button type="submit" id="submit" class="btn btn-dark w-100 py-3 fw-bold">문의 접수하기</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<div class="error text-danger mb-2" data-error-for="_global"></div>
|
|
</div>
|
|
<script type="text/javascript">
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const form = document.getElementById('inquiryForm');
|
|
if (!form) return;
|
|
|
|
const setGlobalError = (msg) => {
|
|
const globalBox = document.querySelector(`[data-error-for="_global"]`);
|
|
if (globalBox) globalBox.textContent = msg;
|
|
else alert(msg);
|
|
};
|
|
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
// 에러 초기화
|
|
document.querySelectorAll('.error').forEach(el => el.textContent = '');
|
|
|
|
const formData = new FormData(form);
|
|
|
|
let res;
|
|
try {
|
|
res = await fetch('/ajax/inquiry/create', {
|
|
method: 'POST',
|
|
body: formData,
|
|
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
|
});
|
|
} catch (err) {
|
|
setGlobalError('네트워크 오류가 발생했습니다.');
|
|
return;
|
|
}
|
|
|
|
// ✅ JSON 응답인지 먼저 체크 (리다이렉트/HTML이면 여기서 차단)
|
|
const ct = (res.headers.get('content-type') || '').toLowerCase();
|
|
if (!ct.includes('application/json')) {
|
|
// 보통 세션만료/권한필터/리다이렉트/에러페이지가 이 케이스
|
|
setGlobalError('세션이 만료되었거나 서버가 JSON이 아닌 응답을 반환했습니다. 다시 시도/로그인 해주세요.');
|
|
return;
|
|
}
|
|
|
|
// JSON 파싱 (여기서 실패하면 서버가 JSON을 깨뜨린 것)
|
|
let data;
|
|
try {
|
|
data = await res.json();
|
|
} catch (err) {
|
|
setGlobalError('서버 JSON 파싱 실패(응답 형식 오류).');
|
|
return;
|
|
}
|
|
|
|
// ✅ 422: 필드별 에러 + 전역 메시지
|
|
if (res.status === 422 && data && data.errors) {
|
|
const globalMsg = data.message || '입력값을 확인해 주세요.';
|
|
setGlobalError(globalMsg);
|
|
|
|
Object.entries(data.errors).forEach(([field, msg]) => {
|
|
const box = document.querySelector(`[data-error-for="${field}"]`);
|
|
if (box) box.textContent = msg;
|
|
});
|
|
return;
|
|
}
|
|
|
|
// ✅ 성공은 "반드시 data.ok === true" 로만 인정
|
|
if (!res.ok || !data || data.ok !== true) {
|
|
setGlobalError((data && data.message) ? data.message : '처리 중 오류가 발생했습니다.');
|
|
return;
|
|
}
|
|
|
|
// ✅ 성공
|
|
alert(data.message || '문의가 접수되었습니다.');
|
|
form.reset();
|
|
});
|
|
});
|
|
</script> |