회원 가입 스타일 수정

This commit is contained in:
현성필
2025-11-26 17:17:30 +09:00
parent e8f9212a13
commit d94760c160
10 changed files with 603 additions and 423 deletions
+87 -13
View File
@@ -11246,9 +11246,8 @@ input[type=checkbox]:checked + .custom-checkbox {
} }
.org-info-notice { .org-info-notice {
padding: 24px;
border-radius: 8px; border-radius: 8px;
margin-bottom: 32px; margin-bottom: 16px;
} }
.org-info-notice ul { .org-info-notice ul {
list-style: none; list-style: none;
@@ -11274,7 +11273,7 @@ input[type=checkbox]:checked + .custom-checkbox {
} }
.org-form-group { .org-form-group {
margin-bottom: 40px; margin-bottom: 8px;
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
gap: 24px; gap: 24px;
@@ -11299,10 +11298,17 @@ input[type=checkbox]:checked + .custom-checkbox {
min-width: 180px; min-width: 180px;
padding-top: 16px; padding-top: 16px;
} }
.org-form-label .required::before { .org-form-label .required-badge {
content: "* "; display: inline-flex;
color: #FF6B6B; align-items: center;
font-weight: 700; justify-content: center;
padding: 2px 8px;
background: #3BA4ED;
color: #FFFFFF;
font-size: 12px;
font-weight: 500;
border-radius: 4px;
line-height: 1.2;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.org-form-label { .org-form-label {
@@ -11317,6 +11323,41 @@ input[type=checkbox]:checked + .custom-checkbox {
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
} }
@media (max-width: 768px) {
.org-form-input-wrapper {
width: 100%;
}
}
.org-input-row {
display: flex;
align-items: center;
gap: 16px;
}
.org-input-row .org-form-input,
.org-input-row .org-compound-input,
.org-input-row .org-auth-input-group {
flex: 1;
min-width: 0;
}
.org-input-row .org-btn-check, .org-input-row .org-file-label {
flex-shrink: 0;
}
@media (max-width: 768px) {
.org-input-row {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.org-input-row .org-form-input,
.org-input-row .org-compound-input,
.org-input-row .org-auth-input-group {
width: 100%;
}
.org-input-row .org-btn-check, .org-input-row .org-file-label {
width: 100%;
}
}
.org-form-input { .org-form-input {
width: 100%; width: 100%;
@@ -11352,6 +11393,7 @@ input[type=checkbox]:checked + .custom-checkbox {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
width: 100%;
} }
.org-compound-input .org-form-input, .org-compound-input .org-form-input,
.org-compound-input .org-form-select { .org-compound-input .org-form-select {
@@ -11366,14 +11408,16 @@ input[type=checkbox]:checked + .custom-checkbox {
color: #64748B; color: #64748B;
font-weight: 600; font-weight: 600;
user-select: none; user-select: none;
flex-shrink: 0;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.org-compound-input { .org-compound-input {
flex-wrap: wrap; width: 100%;
} }
.org-compound-input .org-form-input, .org-compound-input .org-form-input,
.org-compound-input .org-form-select { .org-compound-input .org-form-select {
min-width: 80px; flex: 1;
min-width: 0;
} }
} }
@@ -11483,14 +11527,21 @@ input[type=checkbox]:checked + .custom-checkbox {
.org-btn-check, .org-file-label { .org-btn-check, .org-file-label {
padding: 16px 24px; padding: 16px 24px;
background: #FFFFFF; width: 172px;
color: #0049b4; background: #A4D6EA;
border: 2px solid #0049b4; color: #FFFFFF;
border: 2px solid #A4D6EA;
text-align: center;
justify-content: center;
} }
.org-btn-check:not(:disabled):hover, .org-file-label:not(:disabled):hover { .org-btn-check:not(:disabled):hover, .org-file-label:not(:disabled):hover {
background: #0049b4;
color: #FFFFFF; color: #FFFFFF;
} }
@media (max-width: 768px) {
.org-btn-check, .org-file-label {
width: 100%;
}
}
.org-file-upload { .org-file-upload {
display: flex; display: flex;
@@ -11525,6 +11576,9 @@ input[type=checkbox]:checked + .custom-checkbox {
.org-file-label { .org-file-label {
cursor: pointer; cursor: pointer;
background: #3BA4ED;
border-radius: 12px;
border: 2px solid #3BA4ED;
} }
.org-file-label input[type=file] { .org-file-label input[type=file] {
display: none; display: none;
@@ -11571,6 +11625,11 @@ input[type=checkbox]:checked + .custom-checkbox {
padding-top: 48px; padding-top: 48px;
border-top: 1px solid #E2E8F0; border-top: 1px solid #E2E8F0;
} }
.org-action-buttons .btn {
width: 220px;
text-align: center;
justify-content: center;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.org-action-buttons { .org-action-buttons {
flex-direction: column; flex-direction: column;
@@ -11624,11 +11683,26 @@ input[type=checkbox]:checked + .custom-checkbox {
} }
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.org-form-input {
width: 100%;
}
.org-compound-input {
width: 100%;
}
.org-compound-input .org-form-select, .org-compound-input .org-form-select,
.org-compound-input .org-form-input { .org-compound-input .org-form-input {
flex: 1;
min-width: 0;
width: auto;
font-size: 14px; font-size: 14px;
padding: 8px 16px; padding: 8px 16px;
} }
.org-auth-input-group {
width: 100%;
}
.org-auth-input-group .org-form-input {
width: 100%;
}
} }
.agreement-form { .agreement-form {
background: #FFFFFF; background: #FFFFFF;
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -112,9 +112,8 @@
// Info Notice // Info Notice
.org-info-notice { .org-info-notice {
padding: $spacing-lg;
border-radius: $border-radius-md; border-radius: $border-radius-md;
margin-bottom: $spacing-xl; margin-bottom: $spacing-md;
ul { ul {
list-style: none; list-style: none;
@@ -145,7 +144,7 @@
// Form Groups // Form Groups
.org-form-group { .org-form-group {
margin-bottom: $spacing-2xl; margin-bottom: $spacing-sm;
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
gap: $spacing-lg; gap: $spacing-lg;
@@ -170,12 +169,17 @@
min-width: 180px; min-width: 180px;
padding-top: $spacing-md; padding-top: $spacing-md;
.required { .required-badge {
&::before { display: inline-flex;
content: '* '; align-items: center;
color: $accent-orange; justify-content: center;
font-weight: $font-weight-bold; padding: 2px 8px;
} background: #3BA4ED;
color: $white;
font-size: 12px;
font-weight: $font-weight-medium;
border-radius: 4px;
line-height: 1.2;
} }
@include respond-to('sm') { @include respond-to('sm') {
@@ -189,6 +193,44 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: $spacing-sm; gap: $spacing-sm;
@include respond-to('sm') {
width: 100%;
}
}
// Inline layout for input + button on same row
.org-input-row {
display: flex;
align-items: center;
gap: $spacing-md;
.org-form-input,
.org-compound-input,
.org-auth-input-group {
flex: 1;
min-width: 0;
}
.org-btn-check {
flex-shrink: 0;
}
@include respond-to('sm') {
flex-direction: column;
align-items: stretch;
gap: $spacing-sm;
.org-form-input,
.org-compound-input,
.org-auth-input-group {
width: 100%;
}
.org-btn-check {
width: 100%;
}
}
} }
// Input Fields // Input Fields
@@ -232,6 +274,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: $spacing-sm; gap: $spacing-sm;
width: 100%;
.org-form-input, .org-form-input,
.org-form-select { .org-form-select {
@@ -249,14 +292,16 @@
color: $text-gray; color: $text-gray;
font-weight: $font-weight-semibold; font-weight: $font-weight-semibold;
user-select: none; user-select: none;
flex-shrink: 0;
} }
@include respond-to('sm') { @include respond-to('sm') {
flex-wrap: wrap; width: 100%;
.org-form-input, .org-form-input,
.org-form-select { .org-form-select {
min-width: 80px; flex: 1;
min-width: 0;
} }
} }
} }
@@ -380,14 +425,20 @@
.org-btn-check { .org-btn-check {
padding: $spacing-md $spacing-lg; padding: $spacing-md $spacing-lg;
background: $white; width: 172px;
color: $primary-blue; background: #A4D6EA;
border: 2px solid $primary-blue; color: $white;
border: 2px solid #A4D6EA;
text-align: center;
justify-content: center;
&:not(:disabled):hover { &:not(:disabled):hover {
background: $primary-blue;
color: $white; color: $white;
} }
@include respond-to('sm') {
width: 100%;
}
} }
// File Upload // File Upload
@@ -425,6 +476,9 @@
.org-file-label { .org-file-label {
@extend .org-btn-check; @extend .org-btn-check;
cursor: pointer; cursor: pointer;
background: #3BA4ED;
border-radius: 12px;
border: 2px solid #3BA4ED;
input[type="file"] { input[type="file"] {
display: none; display: none;
@@ -478,6 +532,12 @@
padding-top: $spacing-3xl; padding-top: $spacing-3xl;
border-top: 1px solid $border-gray; border-top: 1px solid $border-gray;
.btn {
width: 220px;
text-align: center;
justify-content: center;
}
@include respond-to('sm') { @include respond-to('sm') {
flex-direction: column; flex-direction: column;
margin-top: $spacing-2xl; margin-top: $spacing-2xl;
@@ -538,13 +598,30 @@
// Responsive Adjustments // Responsive Adjustments
@include respond-to('sm') { @include respond-to('sm') {
.org-form-input {
width: 100%;
}
.org-compound-input { .org-compound-input {
width: 100%;
.org-form-select, .org-form-select,
.org-form-input { .org-form-input {
flex: 1;
min-width: 0;
width: auto;
font-size: $font-size-sm; font-size: $font-size-sm;
padding: $spacing-sm $spacing-md; padding: $spacing-sm $spacing-md;
} }
} }
.org-auth-input-group {
width: 100%;
.org-form-input {
width: 100%;
}
}
} }
// Agreement Form - Figma Design // Agreement Form - Figma Design
@@ -5,32 +5,33 @@
<th:block th:fragment="commonUserInfo"> <th:block th:fragment="commonUserInfo">
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 이메일 아이디 <span class="required-badge">필수</span>
이메일 아이디
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<div class="org-compound-input"> <div class="org-input-row">
<input type="text" id="userId" class="org-form-input" <div class="org-compound-input">
th:classappend="${isInvited ? 'input-readonly' : ''}" <input type="text" id="userId" class="org-form-input"
maxlength="30" th:classappend="${isInvited ? 'input-readonly' : ''}"
th:value="${emailId}" maxlength="30"
th:readonly="${isInvited}" th:value="${emailId}"
th:placeholder="#{portalUser.Register.email}"> th:readonly="${isInvited}"
<span class="separator">@</span> th:placeholder="#{portalUser.Register.email}">
<input type="text" id="domain" class="org-form-input" <span class="separator">@</span>
th:classappend="${isInvited ? 'input-readonly' : ''}" <input type="text" id="domain" class="org-form-input"
maxlength="50" th:classappend="${isInvited ? 'input-readonly' : ''}"
th:value="${domain}" maxlength="50"
th:readonly="${isInvited}" th:value="${domain}"
th:placeholder="#{portalUser.Register.domain}"> th:readonly="${isInvited}"
th:placeholder="#{portalUser.Register.domain}">
</div>
<button type="button" class="btn org-btn-check btn_check_email"
th:classappend="${isInvited ? 'hidden' : ''}">
중복체크
</button>
</div> </div>
<input type="hidden" id="loginId" name="loginId" th:value="${loginId}"> <input type="hidden" id="loginId" name="loginId" th:value="${loginId}">
<input type="hidden" name="registrationType" th:value="${registrationType}"/> <input type="hidden" name="registrationType" th:value="${registrationType}"/>
<input type="hidden" id="registrationScenario" name="registrationScenario" value="new"/> <input type="hidden" id="registrationScenario" name="registrationScenario" value="new"/>
<button type="button" class="btn org-btn-check btn_check_email"
th:classappend="${isInvited ? 'hidden' : ''}">
중복체크
</button>
<div id="email-validation" class="org-validation-message"></div> <div id="email-validation" class="org-validation-message"></div>
</div> </div>
</div> </div>
@@ -3,348 +3,373 @@
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_base_layout}"> xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_base_layout}">
<body> <body>
<th:block th:fragment="newUserForm"> <th:block th:fragment="newUserForm">
<div id="newUserFields"> <div id="newUserFields">
<!-- 성명 --> <!-- 성명 -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 성명 <span class="required-badge">필수</span>
성명 </label>
</label> <div class="org-form-input-wrapper">
<div class="org-form-input-wrapper"> <input type="text" th:field="*{userName}" id="userName" class="org-form-input"
<input type="text" th:field="*{userName}" id="userName" class="org-form-input" th:placeholder="#{portalUser.Register.userName}">
th:placeholder="#{portalUser.Register.userName}"> <div id="userName-validation" class="org-validation-message"></div>
</div> </div>
</div>
<!-- 휴대폰 번호 입력 -->
<div class="org-form-group">
<label class="org-form-label">
<span class="required">*</span>
휴대폰 번호
</label>
<div class="org-form-input-wrapper">
<div class="org-compound-input">
<select class="org-form-select phone-number" id="phoneMobile">
<option value="">선택</option>
<option value="010">010</option>
<option value="011">011</option>
<option value="017">017</option>
<option value="016">016</option>
<option value="018">018</option>
</select>
<span class="separator">-</span>
<input type="text" id="cellPhone1" maxlength="4" class="org-form-input phone-number"
th:placeholder="#{portal.Register.phone1}">
<span class="separator">-</span>
<input type="text" id="cellPhone2" maxlength="4" class="org-form-input phone-number"
th:placeholder="#{portal.Register.phone2}">
</div>
<input type="hidden" th:field="*{mobileNumber}" id="mobileNumber">
<button type="button" class="btn org-btn-check btn_auth">
인증번호 받기
</button>
<div id="mobile-validation" class="org-validation-message"></div>
</div>
</div>
<!-- 인증번호 입력 -->
<div class="org-form-group" id="authNumberContainer" style="display: none;">
<label class="org-form-label">
<span class="required">*</span>
인증번호 입력
</label>
<div class="org-form-input-wrapper">
<div class="org-auth-input-group">
<input type="text" th:field="*{authNumber}" id="authNumber" maxlength="6" pattern="[0-9]*"
inputmode="numeric" class="org-form-input" th:placeholder="#{ncrdRegister.validate.authNumber}" required>
<span class="org-timer" id="certify_time">03:00</span>
</div>
<button type="button" class="btn org-btn-check btn_verify_auth">
인증번호 확인
</button>
<div id="authNumber-validation" class="org-validation-message"></div>
</div>
</div>
<!-- 비밀번호 -->
<div class="org-form-group">
<label class="org-form-label">
<span class="required">*</span>
비밀번호
</label>
<div class="org-form-input-wrapper">
<input type="password" name="password" id="password" class="org-form-input"
th:placeholder="#{portalUser.Register.pass}">
<input type="hidden" name="isPasswordValid" id="isPasswordValid"/>
<div id="password-validation" class="org-validation-message"></div>
</div>
</div>
<!-- 비밀번호 확인 -->
<div class="org-form-group">
<label class="org-form-label">
<span class="required">*</span>
비밀번호 확인
</label>
<div class="org-form-input-wrapper">
<input type="password" name="password2" id="password2" class="org-form-input"
th:placeholder="#{portalUser.Register.passConfirm}">
<input type="hidden" name="isPasswordMatch" id="isPasswordMatch"/>
<div id="password-match-validation" class="org-validation-message"></div>
</div>
</div>
</div> </div>
<!-- 휴대폰 번호 입력 -->
<div class="org-form-group">
<label class="org-form-label">
휴대폰 번호 <span class="required-badge">필수</span>
</label>
<div class="org-form-input-wrapper">
<div class="org-input-row">
<div class="org-compound-input">
<select class="org-form-select phone-number" id="phoneMobile">
<option value="">선택</option>
<option value="010">010</option>
<option value="011">011</option>
<option value="017">017</option>
<option value="016">016</option>
<option value="018">018</option>
</select>
<span class="separator">-</span>
<input type="text" id="cellPhone1" maxlength="4" class="org-form-input phone-number"
th:placeholder="#{portal.Register.phone1}">
<span class="separator">-</span>
<input type="text" id="cellPhone2" maxlength="4" class="org-form-input phone-number"
th:placeholder="#{portal.Register.phone2}">
</div>
<button type="button" class="btn org-btn-check btn_auth">
인증번호 받기
</button>
</div>
<input type="hidden" th:field="*{mobileNumber}" id="mobileNumber">
<div id="mobile-validation" class="org-validation-message"></div>
</div>
</div>
<!-- 인증번호 입력 -->
<div class="org-form-group" id="authNumberContainer" style="display: none;">
<label class="org-form-label">
인증번호 입력 <span class="required-badge">필수</span>
</label>
<div class="org-form-input-wrapper">
<div class="org-input-row">
<div class="org-auth-input-group">
<input type="text" th:field="*{authNumber}" id="authNumber" maxlength="6" pattern="[0-9]*"
inputmode="numeric" class="org-form-input" th:placeholder="#{ncrdRegister.validate.authNumber}" required>
<span class="org-timer" id="certify_time">03:00</span>
</div>
<button type="button" class="btn org-btn-check btn_verify_auth">
인증번호 확인
</button>
</div>
<div id="authNumber-validation" class="org-validation-message"></div>
</div>
</div>
<!-- 비밀번호 -->
<div class="org-form-group">
<label class="org-form-label">
비밀번호 <span class="required-badge">필수</span>
</label>
<div class="org-form-input-wrapper">
<input type="password" name="password" id="password" class="org-form-input"
th:placeholder="#{portalUser.Register.pass}">
<input type="hidden" name="isPasswordValid" id="isPasswordValid"/>
<div id="password-validation" class="org-validation-message"></div>
</div>
</div>
<!-- 비밀번호 확인 -->
<div class="org-form-group">
<label class="org-form-label">
비밀번호 확인 <span class="required-badge">필수</span>
</label>
<div class="org-form-input-wrapper">
<input type="password" name="password2" id="password2" class="org-form-input"
th:placeholder="#{portalUser.Register.passConfirm}">
<input type="hidden" name="isPasswordMatch" id="isPasswordMatch"/>
<div id="password-match-validation" class="org-validation-message"></div>
</div>
</div>
</div>
</th:block> </th:block>
</body> </body>
<th:block> <th:block>
<script th:fragment="newUserScript"> <script th:fragment="newUserScript">
// 휴대폰 번호 조합 함수 // 휴대폰 번호 조합 함수
function combineMobileNumber() { function combineMobileNumber() {
let mobileSelect = document.getElementById('phoneMobile'); let mobileSelect = document.getElementById('phoneMobile');
if (!mobileSelect) { if (!mobileSelect) {
console.error('Mobile select element not found'); console.error('Mobile select element not found');
return null; return null;
} }
let prefix = mobileSelect.value; let prefix = mobileSelect.value;
let middle = document.getElementById('cellPhone1').value.trim(); let middle = document.getElementById('cellPhone1').value.trim();
let last = document.getElementById('cellPhone2').value.trim(); let last = document.getElementById('cellPhone2').value.trim();
if (!prefix || !middle || !last) { if (!prefix || !middle || !last) {
return null; return null;
} }
// 형식화된 번호 (xxx-xxxx-xxxx) // 형식화된 번호 (xxx-xxxx-xxxx)
let formattedNumber = `${prefix}-${middle}-${last}`; let formattedNumber = `${prefix}-${middle}-${last}`;
// hidden input에 형식화된 번호 설정 // hidden input에 형식화된 번호 설정
let mobileNumberInput = document.getElementById('mobileNumber'); let mobileNumberInput = document.getElementById('mobileNumber');
if (mobileNumberInput) { if (mobileNumberInput) {
mobileNumberInput.value = formattedNumber; mobileNumberInput.value = formattedNumber;
}
return formattedNumber;
}
document.addEventListener('DOMContentLoaded', function() {
let countdownInterval;
let isAuthVerified = false;
// 휴대폰 번호 중간, 끝자리 입력 제한 및 형식화
$('#cellPhone1').on('input', function() {
let value = $(this).val().replace(/[^0-9]/g, '');
if (value.length > 4) {
value = value.slice(0, 4);
}
$(this).val(value);
combineMobileNumber();
});
$('#cellPhone2').on('input', function() {
let value = $(this).val().replace(/[^0-9]/g, '');
if (value.length > 4) {
value = value.slice(0, 4);
}
$(this).val(value);
combineMobileNumber();
});
// select 변경 감지
$('#phoneMobile').on('change', function() {
combineMobileNumber();
});
// 인증번호 입력 제한
$('#authNumber').on('input', function() {
$(this).val($(this).val().replace(/[^0-9]/g, ''));
});
// 인증번호 검증 결과 처리 함수
function handleAuthNumberVerification(response) {
customPopups.showAlert(response.message);
if (response.valid) {
let authNumberInput = document.getElementById('authNumber');
let verifyAuthButton = document.querySelector('.btn_verify_auth');
let timerElement = document.getElementById('certify_time');
if (authNumberInput) {
authNumberInput.readonly = true;
}
if (verifyAuthButton) {
verifyAuthButton.disabled = true;
}
clearInterval(countdownInterval);
if (timerElement) {
timerElement.textContent = '인증 완료';
}
isAuthVerified = true;
document.dispatchEvent(new Event('authVerified'));
}
}
// 인증번호 요청 후 처리 함수
function handleAuthNumberRequest(response) {
if (response.valid) {
let authButton = document.querySelector('.btn_auth');
let authContainer = document.getElementById('authNumberContainer');
if (authButton) {
authButton.disabled = true;
}
if (authContainer) {
authContainer.style.display = 'flex';
}
startAuthNumberTimer();
customPopups.showAlert(response.message || '인증번호가 발송되었습니다.');
} else {
customPopups.showAlert(response.message || '알 수 없는 오류가 발생했습니다.');
let authButton = document.querySelector('.btn_auth');
if (authButton) {
authButton.disabled = false;
}
}
}
// 인증번호 타이머 시작 함수
function startAuthNumberTimer() {
clearInterval(countdownInterval);
let remainingTime = 180; // 3분
let timerElement = document.getElementById('certify_time');
let authButton = document.querySelector('.btn_auth');
let verifyAuthButton = document.querySelector('.btn_verify_auth');
let authNumberInput = document.getElementById('authNumber');
function updateRemainingTime() {
if (remainingTime <= 0) {
clearInterval(countdownInterval);
if (timerElement) {
timerElement.textContent = '입력 시간이 초과되었습니다.';
} }
return formattedNumber; customPopups.showAlert('입력 시간이 초과되었습니다. 인증번호를 다시 발송해주세요.');
if (authButton) {
authButton.disabled = false;
}
if (verifyAuthButton) {
verifyAuthButton.disabled = true;
}
if (authNumberInput) {
authNumberInput.readOnly = true;
}
} else {
let minutes = Math.floor(remainingTime / 60);
let seconds = remainingTime % 60;
if (timerElement) {
timerElement.textContent = `남은 시간: ${minutes}:${seconds.toString().padStart(2, '0')}`;
}
remainingTime--;
}
} }
document.addEventListener('DOMContentLoaded', function () { updateRemainingTime();
let countdownInterval; countdownInterval = setInterval(updateRemainingTime, 1000);
let isAuthVerified = false; }
// 휴대폰 번호 중간, 끝자리 입력 제한 및 형식화 // 이벤트 리스너 등록
$('#cellPhone1').on('input', function () { document.getElementById('phoneMobile').addEventListener('change', combineMobileNumber);
let value = $(this).val().replace(/[^0-9]/g, ''); document.querySelectorAll('#cellPhone1, #cellPhone2').forEach(el => el.addEventListener('input', combineMobileNumber));
if (value.length > 4) {
value = value.slice(0, 4);
}
$(this).val(value);
combineMobileNumber();
});
$('#cellPhone2').on('input', function () { let authNumberInput = document.getElementById('authNumber');
let value = $(this).val().replace(/[^0-9]/g, ''); if (authNumberInput) {
if (value.length > 4) { authNumberInput.addEventListener('input', function() {
value = value.slice(0, 4); this.value = this.value.replace(/\D/g, '');
} this.classList.toggle('is-invalid', this.value.length !== 6);
$(this).val(value);
combineMobileNumber();
});
// select 변경 감지
$('#phoneMobile').on('change', function () {
combineMobileNumber();
});
// 인증번호 입력 제한
$('#authNumber').on('input', function () {
$(this).val($(this).val().replace(/[^0-9]/g, ''));
});
// 인증번호 검증 결과 처리 함수
function handleAuthNumberVerification(response) {
customPopups.showAlert(response.message);
if (response.valid) {
let authNumberInput = document.getElementById('authNumber');
let verifyAuthButton = document.querySelector(".btn_verify_auth");
let timerElement = document.getElementById('certify_time');
if (authNumberInput) authNumberInput.readonly = true;
if (verifyAuthButton) verifyAuthButton.disabled = true;
clearInterval(countdownInterval);
if (timerElement) timerElement.textContent = '인증 완료';
isAuthVerified = true;
document.dispatchEvent(new Event('authVerified'));
}
}
// 인증번호 요청 후 처리 함수
function handleAuthNumberRequest(response) {
if (response.valid) {
let authButton = document.querySelector(".btn_auth");
let authContainer = document.getElementById("authNumberContainer");
if (authButton) authButton.disabled = true;
if (authContainer) authContainer.style.display = 'flex';
startAuthNumberTimer();
customPopups.showAlert(response.message || "인증번호가 발송되었습니다.");
} else {
customPopups.showAlert(response.message || '알 수 없는 오류가 발생했습니다.');
let authButton = document.querySelector(".btn_auth");
if (authButton) authButton.disabled = false;
}
}
// 인증번호 타이머 시작 함수
function startAuthNumberTimer() {
clearInterval(countdownInterval);
let remainingTime = 180; // 3분
let timerElement = document.getElementById("certify_time");
let authButton = document.querySelector(".btn_auth");
let verifyAuthButton = document.querySelector(".btn_verify_auth");
let authNumberInput = document.getElementById('authNumber');
function updateRemainingTime() {
if (remainingTime <= 0) {
clearInterval(countdownInterval);
if (timerElement) timerElement.textContent = "입력 시간이 초과되었습니다.";
customPopups.showAlert("입력 시간이 초과되었습니다. 인증번호를 다시 발송해주세요.");
if (authButton) authButton.disabled = false;
if (verifyAuthButton) verifyAuthButton.disabled = true;
if (authNumberInput) authNumberInput.readOnly = true;
} else {
let minutes = Math.floor(remainingTime / 60);
let seconds = remainingTime % 60;
if (timerElement) timerElement.textContent = `남은 시간: ${minutes}:${seconds.toString().padStart(2, '0')}`;
remainingTime--;
}
}
updateRemainingTime();
countdownInterval = setInterval(updateRemainingTime, 1000);
}
// 이벤트 리스너 등록
document.getElementById('phoneMobile').addEventListener('change', combineMobileNumber);
document.querySelectorAll('#cellPhone1, #cellPhone2')
.forEach(el => el.addEventListener('input', combineMobileNumber));
let authNumberInput = document.getElementById("authNumber");
if (authNumberInput) {
authNumberInput.addEventListener("input", function () {
this.value = this.value.replace(/\D/g, '');
this.classList.toggle('is-invalid', this.value.length !== 6);
});
}
let userNameInput = document.getElementById("userName");
if (userNameInput) {
userNameInput.addEventListener("input", function () {
this.classList.toggle('is-invalid', this.value.trim().length === 0);
});
}
// 인증번호 요청 버튼 이벤트 리스너
$('.btn_auth').on('click', function () {
let mobileNumber = combineMobileNumber();
if (!mobileNumber) {
customPopups.showAlert("휴대폰 번호를 올바르게 입력해주세요.");
return;
}
$('#mobileNumber').val(mobileNumber);
$.ajax({
url: /*[[@{/auth/request_auth_number}]]*/ '/auth/request_auth_number',
type: 'POST',
data: {
mobileNumber: mobileNumber,
_csrf: $('input[name="_csrf"]').val()
},
success: function (response) {
handleAuthNumberRequest(response);
},
error: function () {
customPopups.showAlert("처리 중 오류가 발생했습니다. 다시 시도해주세요.");
}
});
});
// 인증번호 확인 버튼 이벤트 리스너
$('.btn_verify_auth').on('click', function () {
let authNumber = $('#authNumber').val();
if (authNumber.length !== 6) {
customPopups.showAlert("6자리 인증번호를 입력해주세요.");
return;
}
$.ajax({
url: /*[[@{/auth/verify_auth_number}]]*/ '/auth/verify_auth_number',
type: 'POST',
data: {
mobileNumber: $('#mobileNumber').val(),
authNumber: authNumber,
_csrf: $('input[name="_csrf"]').val()
},
success: function (response) {
handleAuthNumberVerification(response);
},
error: function () {
customPopups.showAlert("처리 중 오류가 발생했습니다. 다시 시도해주세요.");
}
});
});
// 비밀번호 검증
$('#password').on('blur', function () {
let password = $(this).val();
if (!password) return;
$.ajax({
url: /*[[@{/check_password}]]*/ '/check_password',
type: 'POST',
data: {
password: password,
mobileNumber: $('#mobileNumber').val(),
loginId: $('#loginId').val(),
_csrf: $('input[name="_csrf"]').val()
},
success: function (response) {
let targetElement = $('#password-validation');
targetElement.removeClass('success error');
targetElement.addClass(response.valid ? 'success' : 'error');
targetElement.text(response.message);
$('#isPasswordValid').val(response.valid);
},
error: function () {
customPopups.showAlert("처리 중 오류가 발생했습니다. 다시 시도해주세요.");
}
});
});
// 비밀번호 확인 검증
$('#password2').on('blur', function () {
let password2 = $(this).val();
if (!password2) return;
$.ajax({
url: /*[[@{/check_password_match}]]*/ '/check_password_match',
type: 'POST',
data: {
password: $('#password').val(),
password2: password2,
_csrf: $('input[name="_csrf"]').val()
},
success: function (response) {
let targetElement = $('#password-match-validation');
targetElement.removeClass('success error');
targetElement.addClass(response.valid ? 'success' : 'error');
targetElement.text(response.message);
$('#isPasswordMatch').val(response.valid);
},
error: function () {
customPopups.showAlert("처리 중 오류가 발생했습니다. 다시 시도해주세요.");
}
});
});
}); });
</script> }
let userNameInput = document.getElementById('userName');
if (userNameInput) {
userNameInput.addEventListener('input', function() {
this.classList.toggle('is-invalid', this.value.trim().length === 0);
});
}
// 인증번호 요청 버튼 이벤트 리스너
$('.btn_auth').on('click', function() {
let mobileNumber = combineMobileNumber();
if (!mobileNumber) {
customPopups.showAlert('휴대폰 번호를 올바르게 입력해주세요.');
return;
}
$('#mobileNumber').val(mobileNumber);
$.ajax({
url: /*[[@{/auth/request_auth_number}]]*/ '/auth/request_auth_number',
type: 'POST',
data: {
mobileNumber: mobileNumber,
_csrf: $('input[name="_csrf"]').val()
},
success: function(response) {
handleAuthNumberRequest(response);
},
error: function() {
customPopups.showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.');
}
});
});
// 인증번호 확인 버튼 이벤트 리스너
$('.btn_verify_auth').on('click', function() {
let authNumber = $('#authNumber').val();
if (authNumber.length !== 6) {
customPopups.showAlert('6자리 인증번호를 입력해주세요.');
return;
}
$.ajax({
url: /*[[@{/auth/verify_auth_number}]]*/ '/auth/verify_auth_number',
type: 'POST',
data: {
mobileNumber: $('#mobileNumber').val(),
authNumber: authNumber,
_csrf: $('input[name="_csrf"]').val()
},
success: function(response) {
handleAuthNumberVerification(response);
},
error: function() {
customPopups.showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.');
}
});
});
// 비밀번호 검증
$('#password').on('blur', function() {
let password = $(this).val();
if (!password) {
return;
}
$.ajax({
url: /*[[@{/check_password}]]*/ '/check_password',
type: 'POST',
data: {
password: password,
mobileNumber: $('#mobileNumber').val(),
loginId: $('#loginId').val(),
_csrf: $('input[name="_csrf"]').val()
},
success: function(response) {
let targetElement = $('#password-validation');
targetElement.removeClass('success error');
targetElement.addClass(response.valid ? 'success' : 'error');
targetElement.text(response.message);
$('#isPasswordValid').val(response.valid);
},
error: function() {
customPopups.showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.');
}
});
});
// 비밀번호 확인 검증
$('#password2').on('blur', function() {
let password2 = $(this).val();
if (!password2) {
return;
}
$.ajax({
url: /*[[@{/check_password_match}]]*/ '/check_password_match',
type: 'POST',
data: {
password: $('#password').val(),
password2: password2,
_csrf: $('input[name="_csrf"]').val()
},
success: function(response) {
let targetElement = $('#password-match-validation');
targetElement.removeClass('success error');
targetElement.addClass(response.valid ? 'success' : 'error');
targetElement.text(response.message);
$('#isPasswordMatch').val(response.valid);
},
error: function() {
customPopups.showAlert("처리 중 오류가 발생했습니다. 다시 시도해주세요.");
}
});
});
});
</script>
</th:block> </th:block>
</html> </html>
@@ -6,8 +6,7 @@
<!-- Business Registration Number --> <!-- Business Registration Number -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 사업자등록번호 <span class="required-badge">필수</span>
사업자등록번호
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<div class="org-compound-input"> <div class="org-compound-input">
@@ -28,8 +27,7 @@
<!-- Corporate Registration Number --> <!-- Corporate Registration Number -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 법인등록번호 <span class="required-badge">필수</span>
법인등록번호
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<div class="org-compound-input"> <div class="org-compound-input">
@@ -47,8 +45,7 @@
<!-- Company Name --> <!-- Company Name -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label" for="orgName"> <label class="org-form-label" for="orgName">
<span class="required">*</span> 법인명 <span class="required-badge">필수</span>
법인명
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<input type="text" class="org-form-input" id="orgName" th:field="*{orgName}" <input type="text" class="org-form-input" id="orgName" th:field="*{orgName}"
@@ -63,8 +60,7 @@
<!-- CEO Name --> <!-- CEO Name -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label" for="ceoName"> <label class="org-form-label" for="ceoName">
<span class="required">*</span> 대표자 성명 <span class="required-badge">필수</span>
대표자 성명
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<input type="text" class="org-form-input" id="ceoName" th:field="*{ceoName}" <input type="text" class="org-form-input" id="ceoName" th:field="*{ceoName}"
@@ -79,8 +75,7 @@
<!-- Business Address --> <!-- Business Address -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label" for="orgAddr"> <label class="org-form-label" for="orgAddr">
<span class="required">*</span> 사업장 소재지 <span class="required-badge">필수</span>
사업장 소재지
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<input type="text" class="org-form-input" id="orgAddr" th:field="*{orgAddr}" <input type="text" class="org-form-input" id="orgAddr" th:field="*{orgAddr}"
@@ -95,8 +90,7 @@
<!-- Business Type --> <!-- Business Type -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label" for="orgSectors"> <label class="org-form-label" for="orgSectors">
<span class="required">*</span> 업태 <span class="required-badge">필수</span>
업태
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<input type="text" class="org-form-input" id="orgSectors" th:field="*{orgSectors}" <input type="text" class="org-form-input" id="orgSectors" th:field="*{orgSectors}"
@@ -107,8 +101,7 @@
<!-- Industry Type --> <!-- Industry Type -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label" for="orgIndustryType"> <label class="org-form-label" for="orgIndustryType">
<span class="required">*</span> 업종 <span class="required-badge">필수</span>
업종
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<input type="text" class="org-form-input" id="orgIndustryType" th:field="*{orgIndustryType}" <input type="text" class="org-form-input" id="orgIndustryType" th:field="*{orgIndustryType}"
@@ -119,8 +112,7 @@
<!-- Company Phone Number --> <!-- Company Phone Number -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 회사 전화번호 <span class="required-badge">필수</span>
회사 전화번호
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<div class="org-compound-input"> <div class="org-compound-input">
@@ -167,8 +159,7 @@
<!-- Service Name --> <!-- Service Name -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label" for="serviceName"> <label class="org-form-label" for="serviceName">
<span class="required">*</span> 서비스명 <span class="required-badge">필수</span>
서비스명
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<input type="text" class="org-form-input" id="serviceName" th:field="*{serviceName}" <input type="text" class="org-form-input" id="serviceName" th:field="*{serviceName}"
@@ -183,8 +174,7 @@
<!-- Customer Service Phone Number --> <!-- Customer Service Phone Number -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 고객센터 전화번호 <span class="required-badge">필수</span>
고객센터 전화번호
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<div class="org-compound-input"> <div class="org-compound-input">
@@ -231,15 +221,23 @@
<!-- Business Registration Certificate Upload --> <!-- Business Registration Certificate Upload -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 사업자 등록증 <span class="required-badge">필수</span>
사업자 등록증
</label> </label>
<div class="org-form-input-wrapper"> <div class="org-form-input-wrapper">
<div class="org-file-upload"> <div class="org-file-upload">
<input type="text" class="org-file-display" id="fileNameDisplay" readonly placeholder="첨부파일을 선택하세요"> <input type="text" class="org-file-display" id="fileNameDisplay" readonly placeholder="첨부파일을 선택하세요">
<input type="hidden" id="compRegFile" th:field="*{compRegFile}"> <input type="hidden" id="compRegFile" th:field="*{compRegFile}">
<label class="org-file-label" for="files"> <label class="org-file-label" for="files">
<i class="fas fa-upload"></i> 파일선택 <svg width="24" height="22" viewBox="0 0 24 22" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="23.9494" height="22" fill="url(#pattern0_3001_1395)"/>
<defs>
<pattern id="pattern0_3001_1395" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_3001_1395" transform="matrix(0.0217391 0 0 0.0236654 0 -0.0443038)"/>
</pattern>
<image id="image0_3001_1395" width="46" height="46" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAACXBIWXMAABcSAAAXEgFnn9JSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeRJREFUeNrsme1tgzAQhiHqAGxQRiATlGxAJ6i7QTpByQTtBrBBRiCdADYInaB0AvcsnaUTNR82GPzDr2Q5ODh6cO7LJgwWiHMeQZfgZReGYRO4LAEMreD/dYeWuQodQ/vh4ypcBK8JYC4eBMczXHGpzCXojICdB0xIwtcugX9IWx65h8kns8nyMAOWQRfjZUbG84Epj+QeYevfA/eJKPRpK3LU3K4KG+AV30ZG8OEAtEgq1Llu0L5m/qYwFYafS4WpvBDTkyrBbF7XWG1GVqTWnJuSuanGP6m18oeBcboi3UZBi+nAH3aOsCKqNCbwe4P/QjuZwB8MQiTDqnANPUE7o/Mbmw0FzInTVGT8OuVIC5xTJbaWqUQK59WVjrPHxinfgi69RegrGfluP3DcJT2PZWzoUtejirE8uAe3BN5ORIR+CGtcAZelbaJKDphR3yU0RJDOCXAAKckqFphhI5kxoavIil/22BQrU77cZNg8V+mVBPlqzokJ5KgojGQ6f1tlN2MjcwKYcNITHgbJ1sL4bSurWJTy8QFaH8c9uAf34B7cg3twD74xOK0/4hWP3OYonlUnDdTEYvK9V642G0FT8KP222ryhm0vVUt2QnvBX6fMM5wBHwfLDjl11WKdP6o/AQYA6KS7NOFJR28AAAAASUVORK5CYII="/>
</defs>
</svg>
파일선택
<input type="file" id="files" name="files" <input type="file" id="files" name="files"
accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.hwp,.gif,.jpg,.png"> accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.hwp,.gif,.jpg,.png">
</label> </label>
@@ -5,25 +5,26 @@
<!-- Email ID --> <!-- Email ID -->
<div class="org-form-group"> <div class="org-form-group">
<label class="org-form-label"> <label class="org-form-label">
<span class="required">*</span> 이메일 아이디 <span class="required-badge">필수</span>
이메일 아이디
</label> </label>
<div class="org-input-button-group"> <div class="org-form-input-wrapper">
<div class="org-compound-input" style="flex: 1;"> <div class="org-input-row">
<input type="text" id="userId" class="org-form-input" <div class="org-compound-input">
placeholder="이메일 아이디"> <input type="text" id="userId" class="org-form-input"
<span class="separator">@</span> placeholder="이메일 아이디">
<input type="text" id="domain" class="org-form-input" <span class="separator">@</span>
placeholder="도메인"> <input type="text" id="domain" class="org-form-input"
placeholder="도메인">
</div>
<button type="button" class="btn org-btn-check btn_check_email">
중복체크
</button>
</div> </div>
<button type="button" class="btn org-btn-check btn_check_email"> <input type="hidden" id="loginId" name="loginId" th:value="${loginId}">
중복체크 <input type="hidden" name="registrationType" th:value="${registrationType}"/>
</button> <input type="hidden" id="registrationScenario" name="registrationScenario" value="new"/>
<div id="email-validation" class="org-validation-message"></div>
</div> </div>
<input type="hidden" id="loginId" name="loginId" th:value="${loginId}">
<input type="hidden" name="registrationType" th:value="${registrationType}"/>
<input type="hidden" id="registrationScenario" name="registrationScenario" value="new"/>
<div id="email-validation" class="org-validation-message"></div>
</div> </div>
<!-- Dynamic Form Container --> <!-- Dynamic Form Container -->
@@ -24,6 +24,10 @@
<!-- Alert Container --> <!-- Alert Container -->
<div id="alertContainer"></div> <div id="alertContainer"></div>
<div class="org-section-header" style="margin-top: 60px;margin-bottom: 60px;">
<h3>법인 회원 가입 후 서비스 또는 API 이용을 하실 수 있습니다.</h3>
</div>
<!-- Agreement Section --> <!-- Agreement Section -->
<th:block th:replace="~{apps/register/userAgreementContent :: agreementContent(${termsOfUse}, ${privacyCollect})}"></th:block> <th:block th:replace="~{apps/register/userAgreementContent :: agreementContent(${termsOfUse}, ${privacyCollect})}"></th:block>
@@ -38,7 +42,7 @@
<th:block th:replace="~{apps/register/components/orgBasicInfoForm :: orgInfoForm}"></th:block> <th:block th:replace="~{apps/register/components/orgBasicInfoForm :: orgInfoForm}"></th:block>
<!-- Corporate Admin Information Section --> <!-- Corporate Admin Information Section -->
<div class="org-section-header" style="margin-top: 48px;"> <div class="org-section-header org-section-header--agreement" style="margin-top: 48px;">
<h3>법인 관리자 정보</h3> <h3>법인 관리자 정보</h3>
<span class="required-badge">필수 입력</span> <span class="required-badge">필수 입력</span>
</div> </div>
@@ -49,9 +53,9 @@
</ul> </ul>
</div> </div>
<div th:if="${registrationType == 'corporate'}"> <th:block th:if="${registrationType == 'corporate'}">
<th:block th:replace="~{apps/register/components/orgUserInfoForm :: orgUserInfoForm}"></th:block> <th:block th:replace="~{apps/register/components/orgUserInfoForm :: orgUserInfoForm}"></th:block>
</div> </th:block>
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="org-action-buttons"> <div class="org-action-buttons">