Files
taxbaik/src/TaxBaik.Web/Pages/Contact.cshtml
T
kjh2064 a7f9b94499
TaxBaik CI/CD / build-and-deploy (push) Failing after 2m21s
feat: add message content length validation
- Backend: MinMessageLength=10, MaxMessageLength=5000
- Frontend: Real-time character counter
- Frontend: Client-side validation before submission
- Frontend: Error messages for length violations
- Applied to both Submit and Update operations

Prevents empty or excessively long messages while maintaining
user-friendly feedback on character count.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-04 02:45:00 +09:00

226 lines
9.3 KiB
Plaintext

@page
@model TaxBaik.Web.Pages.ContactModel
@{
ViewData["Title"] = "상담 신청 | 백원숙 세무회계";
}
<div class="container py-5" style="max-width: 600px;">
<div class="d-flex align-items-center justify-content-between gap-3 mb-4">
<h1 class="fw-bold mb-0">상담 신청</h1>
<a href="/taxbaik" class="btn btn-outline-secondary btn-sm"
onclick="if (history.length > 1) { history.back(); return false; }">
뒤로가기
</a>
</div>
@if (TempData["Success"] != null)
{
<div id="contact-success" class="alert alert-success alert-dismissible fade show" role="alert" role="status" style="font-size: 1.05rem;">
<strong>✅ 성공!</strong> @TempData["Success"]
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<script>
// 성공 메시지를 3초 후 자동 숨김 (사용자 클릭 가능)
setTimeout(() => {
const alert = document.getElementById('contact-success');
if (alert) {
const bsAlert = new bootstrap.Alert(alert);
bsAlert.close();
}
}, 5000);
// 폼 자동 초기화
setTimeout(() => {
document.querySelector('form').reset();
document.getElementById('agree').checked = false;
}, 1000);
</script>
}
<form method="post" id="contactForm">
@Html.AntiForgeryToken()
<div asp-validation-summary="All" class="text-danger mb-3"></div>
<div class="mb-3">
<label for="name" class="form-label">이름 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name" name="Name" required />
</div>
<div class="mb-3">
<label for="phone" class="form-label">전화번호 <span class="text-danger">*</span></label>
<input type="tel" class="form-control" id="phone" name="Phone" placeholder="010-1234-5678" required maxlength="13" />
<small class="form-text text-muted">숫자만 입력하면 자동 포맷팅됩니다 (예: 01012345678 또는 010-1234-5678)</small>
<div id="phoneError" class="text-danger mt-2" style="display: none;">
10~11자리 숫자를 입력해주세요.
</div>
</div>
<div class="mb-3">
<label for="email" class="form-label">이메일</label>
<input type="email" class="form-control" id="email" name="Email" />
</div>
<div class="mb-3">
<label for="service" class="form-label">상담분야</label>
<select class="form-select" id="service" name="ServiceType">
<option value="기장">사업자 기장</option>
<option value="양도세">부동산 양도세</option>
<option value="종소세">종합소득세</option>
<option value="증여상속">증여상속세</option>
<option value="기타">기타</option>
</select>
</div>
<div class="mb-3">
<label for="message" class="form-label">문의내용 <span class="text-danger">*</span></label>
<textarea class="form-control" id="message" name="Message" rows="5" required minlength="10" maxlength="5000" placeholder="최소 10자, 최대 5000자까지 입력 가능합니다"></textarea>
<small class="form-text text-muted">
<span id="messageCount">0</span>/5000
</small>
<div id="messageError" class="text-danger mt-2" style="display: none;"></div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="agree" name="Agree" value="true" required />
<label class="form-check-label" for="agree">
개인정보 수집·이용에 동의합니다
</label>
</div>
<button type="submit" class="btn btn-primary btn-lg w-100">상담신청</button>
</form>
<script>
const phoneInput = document.getElementById('phone');
const phoneError = document.getElementById('phoneError');
const messageInput = document.getElementById('message');
const messageError = document.getElementById('messageError');
const messageCount = document.getElementById('messageCount');
const contactForm = document.getElementById('contactForm');
const MIN_MESSAGE_LENGTH = 10;
const MAX_MESSAGE_LENGTH = 5000;
// 한국 전화번호 정규식
const koreanPhoneRegex = /^(0(2|3[1-3]|4[1-4]|5[1-5]|6[1-4]|70|50[5-9]|[7-9](?:\d{1,2})?)\d{7,8}|0\d{9,10})$/;
// 실시간 전화번호 마스킹
phoneInput.addEventListener('input', (e) => {
let value = e.target.value.replace(/\D/g, ''); // 숫자만 추출
if (value.length > 11) {
value = value.substring(0, 11); // 최대 11자리
}
// 포맷팅
value = formatKoreanPhoneNumber(value);
e.target.value = value;
validatePhone();
});
// 한국 전화번호 포맷팅
function formatKoreanPhoneNumber(value) {
if (!value.startsWith('0')) return value;
let areaCode = '';
if (value.startsWith('02')) {
areaCode = '02';
} else if ((value.startsWith('070') ||
(value.startsWith('050') && value.length > 2 && value[3] >= '5' && value[3] <= '9')) ||
(value.length >= 3 && /^0[3-6]\d/.test(value))) {
areaCode = value.substring(0, 3);
} else if (value.length >= 3 && value.startsWith('01')) {
areaCode = value.substring(0, 3);
}
if (!areaCode) return value;
const restPart = value.substring(areaCode.length);
if (restPart.length === 7) {
return `${areaCode}-${restPart.substring(0, 3)}-${restPart.substring(3)}`;
} else if (restPart.length === 8) {
return `${areaCode}-${restPart.substring(0, 4)}-${restPart.substring(4)}`;
} else if (restPart.length > 0 && restPart.length < 7) {
return `${areaCode}-${restPart}`;
}
return value;
}
// 전화번호 검증
function validatePhone() {
const value = phoneInput.value.replace(/\D/g, '');
const isValid = koreanPhoneRegex.test(value);
if (!isValid && phoneInput.value.length > 0) {
phoneError.style.display = 'block';
phoneInput.classList.add('is-invalid');
} else {
phoneError.style.display = 'none';
phoneInput.classList.remove('is-invalid');
}
return isValid;
}
// 폼 제출 전 검증
contactForm.addEventListener('submit', (e) => {
if (!validatePhone()) {
e.preventDefault();
phoneInput.focus();
}
});
// 포커스 아웃 시 최종 검증
phoneInput.addEventListener('blur', validatePhone);
// 메시지 길이 실시간 표시
messageInput.addEventListener('input', (e) => {
const length = e.target.value.length;
messageCount.textContent = length;
validateMessage();
});
// 메시지 검증
function validateMessage() {
const value = messageInput.value.trim();
const isValid = value.length >= MIN_MESSAGE_LENGTH && value.length <= MAX_MESSAGE_LENGTH;
if (!isValid && messageInput.value.length > 0) {
messageError.style.display = 'block';
if (value.length < MIN_MESSAGE_LENGTH) {
messageError.textContent = `최소 ${MIN_MESSAGE_LENGTH}자 이상 입력해주세요. (현재: ${value.length}자)`;
} else if (value.length > MAX_MESSAGE_LENGTH) {
messageError.textContent = `최대 ${MAX_MESSAGE_LENGTH}자까지만 입력 가능합니다. (현재: ${value.length}자)`;
}
messageInput.classList.add('is-invalid');
} else {
messageError.style.display = 'none';
messageInput.classList.remove('is-invalid');
}
return isValid;
}
// 폼 제출 시 메시지 검증 포함
const originalSubmitHandler = contactForm.onsubmit;
contactForm.addEventListener('submit', (e) => {
if (!validatePhone() || !validateMessage()) {
e.preventDefault();
if (!validatePhone()) {
phoneInput.focus();
} else if (!validateMessage()) {
messageInput.focus();
}
}
});
</script>
<hr class="my-5" />
<h5 class="fw-bold mb-3">빠른 상담을 원하시나요?</h5>
<p>카카오톡 채널을 통해 더 빠르게 상담받을 수 있습니다.</p>
<div class="gap-2 d-flex flex-wrap">
<a href="http://pf.kakao.com/_xoxchTX" target="_blank" class="btn btn-warning">카카오톡 채널 문의</a>
<a href="tel:010-4122-8268" class="btn btn-outline-primary">전화 상담</a>
</div>
</div>