회원가입 디자인 적용
This commit is contained in:
@@ -10558,6 +10558,754 @@ select.form-control {
|
||||
}
|
||||
}
|
||||
|
||||
.org-page-title-banner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
background: linear-gradient(to right, #E8F4FD 0%, #F0F8FF 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 64px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.org-page-title-banner::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h100v100H0z' fill='%23ffffff' opacity='0.03'/%3E%3C/svg%3E");
|
||||
background-size: 50px 50px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.org-page-title-banner .title-image {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 220px;
|
||||
width: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
.org-page-title-banner h1 {
|
||||
position: relative;
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
color: #1A1A2E;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-page-title-banner {
|
||||
height: 120px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.org-page-title-banner .title-image {
|
||||
height: 120px;
|
||||
}
|
||||
.org-page-title-banner h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-register-page {
|
||||
min-height: 100vh;
|
||||
padding: 0;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-register-page {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.org-register-container {
|
||||
max-width: 1066px;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px 64px;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-register-container {
|
||||
padding: 0 24px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-register-title {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
color: #1A1A2E;
|
||||
text-align: center;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-register-title {
|
||||
font-size: 32px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24px 32px;
|
||||
background: linear-gradient(135deg, #4B9BFF 0%, #2E7FF7 100%);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.org-section-header h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #FFFFFF;
|
||||
margin: 0;
|
||||
}
|
||||
.org-section-header .required-badge {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: #FFFFFF;
|
||||
padding: 4px 16px;
|
||||
border-radius: 50px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.org-section-header .required-badge::before {
|
||||
content: "*";
|
||||
color: #FFD93D;
|
||||
font-weight: 700;
|
||||
}
|
||||
.org-section-header--agreement {
|
||||
background: none;
|
||||
padding: 0 0 16px 0;
|
||||
border-radius: 0;
|
||||
border-bottom: 2px solid #212529;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.org-section-header--agreement h3 {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #212529;
|
||||
margin: 0;
|
||||
}
|
||||
.org-section-header--agreement .required-badge {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-section-header {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
.org-section-header h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.org-section-header--agreement {
|
||||
padding: 0 0 8px 0;
|
||||
}
|
||||
.org-section-header--agreement h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-info-notice {
|
||||
background: linear-gradient(135deg, #EFF6FF 0%, #F0F9FF 100%);
|
||||
padding: 24px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.org-info-notice ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.org-info-notice ul li {
|
||||
position: relative;
|
||||
padding-left: 24px;
|
||||
color: #64748B;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.org-info-notice ul li::before {
|
||||
content: "•";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #4B9BFF;
|
||||
font-weight: 700;
|
||||
}
|
||||
.org-info-notice ul li + li {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.org-form-group {
|
||||
margin-bottom: 40px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 24px;
|
||||
}
|
||||
.org-form-group:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-form-group {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1A1A2E;
|
||||
min-width: 180px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
.org-form-label .required {
|
||||
color: #FF6B6B;
|
||||
font-weight: 700;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-form-label {
|
||||
min-width: auto;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.org-form-input-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.org-form-input {
|
||||
width: 100%;
|
||||
padding: 16px 24px;
|
||||
border: 2px solid #E2E8F0;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
color: #1A1A2E;
|
||||
transition: all 0.3s ease;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
.org-form-input:focus {
|
||||
outline: none;
|
||||
border-color: #4B9BFF;
|
||||
box-shadow: 0 0 0 3px rgba(75, 155, 255, 0.1);
|
||||
}
|
||||
.org-form-input:disabled {
|
||||
background: #F8FAFC;
|
||||
color: #94A3B8;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.org-form-input.is-invalid {
|
||||
border-color: #FF6B6B;
|
||||
}
|
||||
.org-form-input.is-valid {
|
||||
border-color: #6BCF7F;
|
||||
}
|
||||
.org-form-input::placeholder {
|
||||
color: #94A3B8;
|
||||
}
|
||||
|
||||
.org-compound-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.org-compound-input .org-form-input,
|
||||
.org-compound-input .org-form-select {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.org-compound-input .phone-number {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
.org-compound-input .separator {
|
||||
color: #64748B;
|
||||
font-weight: 600;
|
||||
user-select: none;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-compound-input {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.org-compound-input .org-form-input,
|
||||
.org-compound-input .org-form-select {
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-form-select {
|
||||
width: 100%;
|
||||
padding: 16px 24px;
|
||||
border: 2px solid #E2E8F0;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
color: #1A1A2E;
|
||||
background: #FFFFFF;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748B' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 24px center;
|
||||
padding-right: 48px;
|
||||
}
|
||||
.org-form-select:focus {
|
||||
outline: none;
|
||||
border-color: #4B9BFF;
|
||||
box-shadow: 0 0 0 3px rgba(75, 155, 255, 0.1);
|
||||
}
|
||||
.org-form-select:disabled {
|
||||
background-color: #F8FAFC;
|
||||
color: #94A3B8;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.org-input-button-group {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
.org-input-button-group .org-form-input {
|
||||
flex: 1;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-input-button-group {
|
||||
flex-direction: column;
|
||||
}
|
||||
.org-input-button-group .org-form-input {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
.org-auth-input-group {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.org-auth-input-group .org-form-input {
|
||||
padding-right: 100px;
|
||||
}
|
||||
|
||||
.org-timer {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #FF6B6B;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.org-btn {
|
||||
padding: 16px 40px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.org-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.org-btn:not(:disabled):hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(75, 155, 255, 0.1);
|
||||
}
|
||||
.org-btn:not(:disabled):active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.org-btn-primary {
|
||||
background: linear-gradient(135deg, #4B9BFF 0%, #2E7FF7 100%);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.org-btn-primary:not(:disabled):hover {
|
||||
background: linear-gradient(135deg, #2E7FF7 0%, #4B9BFF 100%);
|
||||
}
|
||||
|
||||
.org-btn-secondary {
|
||||
background: #FFFFFF;
|
||||
color: #64748B;
|
||||
border: 2px solid #E2E8F0;
|
||||
}
|
||||
.org-btn-secondary:not(:disabled):hover {
|
||||
border-color: #4B9BFF;
|
||||
color: #4B9BFF;
|
||||
}
|
||||
|
||||
.org-btn-check, .org-file-label {
|
||||
padding: 16px 24px;
|
||||
background: #FFFFFF;
|
||||
color: #4B9BFF;
|
||||
border: 2px solid #4B9BFF;
|
||||
}
|
||||
.org-btn-check:not(:disabled):hover, .org-file-label:not(:disabled):hover {
|
||||
background: #4B9BFF;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.org-file-upload {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-file-upload {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.org-file-display {
|
||||
flex: 1;
|
||||
padding: 16px 24px;
|
||||
border: 2px dashed #E2E8F0;
|
||||
border-radius: 8px;
|
||||
background: #F8FAFC;
|
||||
color: #94A3B8;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.org-file-display.has-file {
|
||||
border-style: solid;
|
||||
border-color: #6BCF7F;
|
||||
background: rgba(107, 207, 127, 0.05);
|
||||
color: #1A1A2E;
|
||||
}
|
||||
|
||||
.org-file-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.org-file-label input[type=file] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.org-file-remove {
|
||||
padding: 16px;
|
||||
background: #FF6B6B;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.org-file-remove:hover {
|
||||
background: #ff3838;
|
||||
}
|
||||
|
||||
.org-file-notice {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, #FFF7ED 0%, #FFFBEB 100%);
|
||||
border-radius: 6px;
|
||||
}
|
||||
.org-file-notice p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #64748B;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.org-file-notice p + p {
|
||||
margin-top: 4px;
|
||||
}
|
||||
.org-file-notice p::before {
|
||||
content: "• ";
|
||||
color: #FFD93D;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.org-action-buttons {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
justify-content: center;
|
||||
margin-top: 64px;
|
||||
padding-top: 48px;
|
||||
border-top: 1px solid #E2E8F0;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-action-buttons {
|
||||
flex-direction: column;
|
||||
margin-top: 40px;
|
||||
padding-top: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.org-validation-message {
|
||||
margin-top: 8px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.org-validation-message.success {
|
||||
background: rgba(107, 207, 127, 0.1);
|
||||
color: #6BCF7F;
|
||||
}
|
||||
.org-validation-message.error {
|
||||
background: rgba(255, 107, 107, 0.1);
|
||||
color: #FF6B6B;
|
||||
}
|
||||
|
||||
.org-loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(26, 26, 46, 0.7);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
.org-loading-overlay.active {
|
||||
display: flex;
|
||||
}
|
||||
.org-loading-overlay .spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.2);
|
||||
border-top-color: #FFFFFF;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.org-compound-input .org-form-select,
|
||||
.org-compound-input .org-form-input {
|
||||
font-size: 14px;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
}
|
||||
.agreement-form {
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #DDDDDD;
|
||||
border-radius: 12px;
|
||||
padding: 30px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
margin-bottom: 90px;
|
||||
}
|
||||
|
||||
.agreement-all-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.agreement-divider {
|
||||
height: 1px;
|
||||
background: #DDDDDD;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.agreement-items-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.agreement-item-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 4px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.agreement-checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.agreement-checkbox-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.agreement-checkbox-input:checked + .agreement-checkbox-custom {
|
||||
background-image: url("/img/checkbox-checked.png");
|
||||
}
|
||||
.agreement-checkbox-input:focus + .agreement-checkbox-custom {
|
||||
box-shadow: 0 0 0 3px rgba(140, 149, 159, 0.1);
|
||||
}
|
||||
|
||||
.agreement-checkbox-custom {
|
||||
position: relative;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
min-width: 26px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background-image: url("/img/checkbox-unchecked.png");
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.agreement-checkbox-text {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #515961;
|
||||
line-height: 100.02%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.agreement-checkbox-text.agreement-all-text {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.agreement-required {
|
||||
color: #0049B4;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.agreement-title {
|
||||
color: #515961;
|
||||
}
|
||||
|
||||
.agreement-toggle-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
min-width: 22px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #64748B;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
padding: 8px 4px 10px 7px;
|
||||
}
|
||||
.agreement-toggle-icon i {
|
||||
font-size: 12px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.agreement-toggle-icon:hover {
|
||||
color: #4B9BFF;
|
||||
}
|
||||
.agreement-toggle-icon.active {
|
||||
color: #4B9BFF;
|
||||
}
|
||||
.agreement-toggle-icon.active i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.agreement-content {
|
||||
margin-top: 16px;
|
||||
background: #EDF9FE;
|
||||
}
|
||||
|
||||
.agreement-scroll {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 24px;
|
||||
}
|
||||
.agreement-scroll::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
.agreement-scroll::-webkit-scrollbar-track {
|
||||
background: #E2E8F0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.agreement-scroll::-webkit-scrollbar-thumb {
|
||||
background: #94A3B8;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.agreement-scroll::-webkit-scrollbar-thumb:hover {
|
||||
background: #64748B;
|
||||
}
|
||||
.agreement-scroll div {
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
color: #64748B;
|
||||
}
|
||||
.agreement-scroll div h1, .agreement-scroll div h2, .agreement-scroll div h3, .agreement-scroll div h4, .agreement-scroll div h5, .agreement-scroll div h6 {
|
||||
color: #1A1A2E;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.agreement-scroll div p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.agreement-scroll div ul, .agreement-scroll div ol {
|
||||
margin-left: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.agreement-scroll div table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.agreement-scroll div table th, .agreement-scroll div table td {
|
||||
border: 1px solid #E2E8F0;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
.agreement-scroll div table th {
|
||||
background: #EFF6FF;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.agreement-form {
|
||||
padding: 20px 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
.agreement-all-section {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.agreement-items-list {
|
||||
gap: 16px;
|
||||
}
|
||||
.agreement-item-row {
|
||||
height: auto;
|
||||
min-height: 28px;
|
||||
}
|
||||
.agreement-checkbox-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
.agreement-checkbox-text.agreement-all-text {
|
||||
font-size: 16px;
|
||||
}
|
||||
.agreement-scroll {
|
||||
max-height: 250px;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
.user-management-container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 808 B |
Binary file not shown.
|
After Width: | Height: | Size: 990 B |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -13,6 +13,8 @@ $accent-orange: #FF6B6B; // Orange accent
|
||||
$accent-green: #6BCF7F; // Green accent
|
||||
$accent-purple: #A78BFA; // Purple accent
|
||||
|
||||
$main-bg: #EDF9FE;
|
||||
|
||||
// Neutral colors
|
||||
$text-dark: #1A1A2E; // Main text color
|
||||
$text-gray: #64748B; // Secondary text
|
||||
@@ -25,6 +27,7 @@ $black: #000000; // Pure black
|
||||
$gray-800: #1F2937; // Dark gray
|
||||
$gray-900: #111827; // Darker gray
|
||||
|
||||
|
||||
// Gradients
|
||||
$gradient-primary: linear-gradient(135deg, $primary-blue 0%, $secondary-blue 100%);
|
||||
$gradient-accent: linear-gradient(135deg, $accent-cyan 0%, $primary-blue 100%);
|
||||
@@ -118,4 +121,4 @@ $button-padding-y: 16px;
|
||||
$card-padding: 32px;
|
||||
$input-padding-x: 16px;
|
||||
$input-padding-y: 12px;
|
||||
$input-height: 48px;
|
||||
$input-height: 48px;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
@import 'pages/apikey-detail';
|
||||
@import 'pages/notice';
|
||||
@import 'pages/inquiry';
|
||||
@import 'pages/org-register';
|
||||
@import 'pages/user-management';
|
||||
|
||||
// 6. Themes
|
||||
|
||||
@@ -0,0 +1,857 @@
|
||||
// Organization Registration Page Styles
|
||||
// Modern design for corporate registration flow
|
||||
|
||||
@import '../abstracts/variables';
|
||||
@import '../abstracts/mixins';
|
||||
|
||||
// Page Title Banner
|
||||
.org-page-title-banner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
background: linear-gradient(to right, #E8F4FD 0%, #F0F8FF 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: $spacing-4xl;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h100v100H0z' fill='%23ffffff' opacity='0.03'/%3E%3C/svg%3E");
|
||||
background-size: 50px 50px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.title-image {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 220px;
|
||||
width: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
h1 {
|
||||
position: relative;
|
||||
font-size: $font-size-3xl;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $text-dark;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
height: 120px;
|
||||
margin-bottom: $spacing-xl;
|
||||
|
||||
.title-image {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: $font-size-xl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main Registration Container
|
||||
.org-register-page {
|
||||
min-height: 100vh;
|
||||
padding: 0;
|
||||
|
||||
@include respond-to('sm') {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.org-register-container {
|
||||
max-width: 1066px;
|
||||
margin: 0 auto;
|
||||
padding: 0 $spacing-lg $spacing-4xl;
|
||||
|
||||
@include respond-to('sm') {
|
||||
padding: 0 $spacing-lg $spacing-xl;
|
||||
}
|
||||
}
|
||||
|
||||
// Header
|
||||
.org-register-title {
|
||||
font-size: $font-size-3xl;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $text-dark;
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-3xl;
|
||||
|
||||
@include respond-to('sm') {
|
||||
font-size: $font-size-2xl;
|
||||
margin-bottom: $spacing-xl;
|
||||
}
|
||||
}
|
||||
|
||||
// Section Headers
|
||||
.org-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: $spacing-lg $spacing-xl;
|
||||
background: linear-gradient(135deg, $primary-blue 0%, $secondary-blue 100%);
|
||||
border-radius: $border-radius-md;
|
||||
margin-bottom: $spacing-xl;
|
||||
|
||||
h3 {
|
||||
font-size: $font-size-lg;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $white;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.required-badge {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: $white;
|
||||
padding: $spacing-xs $spacing-md;
|
||||
border-radius: $border-radius-full;
|
||||
font-size: $font-size-sm;
|
||||
font-weight: $font-weight-medium;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: $spacing-xs;
|
||||
|
||||
&::before {
|
||||
content: '*';
|
||||
color: $accent-yellow;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
}
|
||||
|
||||
// Agreement variant - Simple text with underline (Figma design)
|
||||
&--agreement {
|
||||
background: none;
|
||||
padding: 0 0 $spacing-md 0;
|
||||
border-radius: 0;
|
||||
border-bottom: 2px solid #212529;
|
||||
margin-bottom: $spacing-xl;
|
||||
|
||||
h3 {
|
||||
font-size: 22px;
|
||||
font-weight: $font-weight-bold;
|
||||
color: #212529;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.required-badge {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
padding: $spacing-md $spacing-lg;
|
||||
|
||||
h3 {
|
||||
font-size: $font-size-md;
|
||||
}
|
||||
|
||||
&--agreement {
|
||||
padding: 0 0 $spacing-sm 0;
|
||||
|
||||
h3 {
|
||||
font-size: $font-size-md;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Info Notice
|
||||
.org-info-notice {
|
||||
background: linear-gradient(135deg, #EFF6FF 0%, #F0F9FF 100%);
|
||||
padding: $spacing-lg;
|
||||
border-radius: $border-radius-md;
|
||||
margin-bottom: $spacing-xl;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
padding-left: $spacing-lg;
|
||||
color: $text-gray;
|
||||
font-size: $font-size-sm;
|
||||
line-height: 1.6;
|
||||
|
||||
&::before {
|
||||
content: '•';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: $primary-blue;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
& + li {
|
||||
margin-top: $spacing-sm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Form Groups
|
||||
.org-form-group {
|
||||
margin-bottom: $spacing-2xl;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: $spacing-lg;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
}
|
||||
}
|
||||
|
||||
.org-form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-sm;
|
||||
font-size: $font-size-base;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $text-dark;
|
||||
min-width: 180px;
|
||||
padding-top: $spacing-md;
|
||||
|
||||
.required {
|
||||
color: $accent-orange;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
min-width: auto;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.org-form-input-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-sm;
|
||||
}
|
||||
|
||||
// Input Fields
|
||||
.org-form-input {
|
||||
width: 100%;
|
||||
padding: $spacing-md $spacing-lg;
|
||||
border: 2px solid $border-gray;
|
||||
border-radius: $border-radius-md;
|
||||
font-size: $font-size-base;
|
||||
color: $text-dark;
|
||||
transition: $transition-base;
|
||||
background: $white;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: $primary-blue;
|
||||
box-shadow: 0 0 0 3px rgba(75, 155, 255, 0.1);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: $gray-bg;
|
||||
color: $text-light;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.is-invalid {
|
||||
border-color: $accent-orange;
|
||||
}
|
||||
|
||||
&.is-valid {
|
||||
border-color: $accent-green;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
|
||||
// Compound Inputs (e.g., phone number, email)
|
||||
.org-compound-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-sm;
|
||||
|
||||
.org-form-input,
|
||||
.org-form-select {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
// Equal width for phone number inputs
|
||||
.phone-number {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: $text-gray;
|
||||
font-weight: $font-weight-semibold;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
flex-wrap: wrap;
|
||||
|
||||
.org-form-input,
|
||||
.org-form-select {
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select Dropdown
|
||||
.org-form-select {
|
||||
width: 100%;
|
||||
padding: $spacing-md $spacing-lg;
|
||||
border: 2px solid $border-gray;
|
||||
border-radius: $border-radius-md;
|
||||
font-size: $font-size-base;
|
||||
color: $text-dark;
|
||||
background: $white;
|
||||
cursor: pointer;
|
||||
transition: $transition-base;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748B' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right $spacing-lg center;
|
||||
padding-right: $spacing-3xl;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: $primary-blue;
|
||||
box-shadow: 0 0 0 3px rgba(75, 155, 255, 0.1);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: $gray-bg;
|
||||
color: $text-light;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// Button with Input
|
||||
.org-input-button-group {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
|
||||
.org-form-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@include respond-to('sm') {
|
||||
flex-direction: column;
|
||||
|
||||
.org-form-input {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auth Input Group (for authentication number with timer)
|
||||
.org-auth-input-group {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.org-form-input {
|
||||
padding-right: 100px; // Make space for timer
|
||||
}
|
||||
}
|
||||
|
||||
.org-timer {
|
||||
position: absolute;
|
||||
right: $spacing-lg;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: $font-size-sm;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $accent-orange;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
// Buttons
|
||||
.org-btn {
|
||||
padding: $spacing-md $spacing-2xl;
|
||||
border-radius: $border-radius-md;
|
||||
font-size: $font-size-base;
|
||||
font-weight: $font-weight-semibold;
|
||||
cursor: pointer;
|
||||
transition: $transition-base;
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $spacing-sm;
|
||||
white-space: nowrap;
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:not(:disabled):hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
&:not(:disabled):active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.org-btn-primary {
|
||||
background: linear-gradient(135deg, $primary-blue 0%, $secondary-blue 100%);
|
||||
color: $white;
|
||||
|
||||
&:not(:disabled):hover {
|
||||
background: linear-gradient(135deg, $secondary-blue 0%, $primary-blue 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.org-btn-secondary {
|
||||
background: $white;
|
||||
color: $text-gray;
|
||||
border: 2px solid $border-gray;
|
||||
|
||||
&:not(:disabled):hover {
|
||||
border-color: $primary-blue;
|
||||
color: $primary-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.org-btn-check {
|
||||
padding: $spacing-md $spacing-lg;
|
||||
background: $white;
|
||||
color: $primary-blue;
|
||||
border: 2px solid $primary-blue;
|
||||
|
||||
&:not(:disabled):hover {
|
||||
background: $primary-blue;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
// File Upload
|
||||
.org-file-upload {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-md;
|
||||
|
||||
@include respond-to('sm') {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.org-file-display {
|
||||
flex: 1;
|
||||
padding: $spacing-md $spacing-lg;
|
||||
border: 2px dashed $border-gray;
|
||||
border-radius: $border-radius-md;
|
||||
background: $gray-bg;
|
||||
color: $text-light;
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&.has-file {
|
||||
border-style: solid;
|
||||
border-color: $accent-green;
|
||||
background: rgba(107, 207, 127, 0.05);
|
||||
color: $text-dark;
|
||||
}
|
||||
}
|
||||
|
||||
.org-file-label {
|
||||
@extend .org-btn-check;
|
||||
cursor: pointer;
|
||||
|
||||
input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.org-file-remove {
|
||||
padding: $spacing-md;
|
||||
background: $accent-orange;
|
||||
color: $white;
|
||||
border: none;
|
||||
border-radius: $border-radius-md;
|
||||
cursor: pointer;
|
||||
transition: $transition-base;
|
||||
|
||||
&:hover {
|
||||
background: darken($accent-orange, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
// File Upload Notice
|
||||
.org-file-notice {
|
||||
margin-top: $spacing-md;
|
||||
padding: $spacing-md;
|
||||
background: linear-gradient(135deg, #FFF7ED 0%, #FFFBEB 100%);
|
||||
border-radius: $border-radius-sm;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: $font-size-sm;
|
||||
color: $text-gray;
|
||||
line-height: 1.5;
|
||||
|
||||
& + p {
|
||||
margin-top: $spacing-xs;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '• ';
|
||||
color: $accent-yellow;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Action Buttons
|
||||
.org-action-buttons {
|
||||
display: flex;
|
||||
gap: $spacing-lg;
|
||||
justify-content: center;
|
||||
margin-top: $spacing-4xl;
|
||||
padding-top: $spacing-3xl;
|
||||
border-top: 1px solid $border-gray;
|
||||
|
||||
@include respond-to('sm') {
|
||||
flex-direction: column;
|
||||
margin-top: $spacing-2xl;
|
||||
padding-top: $spacing-xl;
|
||||
}
|
||||
}
|
||||
|
||||
// Validation Messages
|
||||
.org-validation-message {
|
||||
margin-top: $spacing-sm;
|
||||
padding: $spacing-sm $spacing-md;
|
||||
border-radius: $border-radius-sm;
|
||||
font-size: $font-size-sm;
|
||||
|
||||
&.success {
|
||||
background: rgba(107, 207, 127, 0.1);
|
||||
color: $accent-green;
|
||||
}
|
||||
|
||||
&.error {
|
||||
background: rgba(255, 107, 107, 0.1);
|
||||
color: $accent-orange;
|
||||
}
|
||||
}
|
||||
|
||||
// Loading Overlay
|
||||
.org-loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(26, 26, 46, 0.7);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
|
||||
&.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.2);
|
||||
border-top-color: $white;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive Adjustments
|
||||
@include respond-to('sm') {
|
||||
.org-compound-input {
|
||||
.org-form-select,
|
||||
.org-form-input {
|
||||
font-size: $font-size-sm;
|
||||
padding: $spacing-sm $spacing-md;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Agreement Form - Figma Design
|
||||
.agreement-form {
|
||||
background: $white;
|
||||
border: 1px solid #DDDDDD;
|
||||
border-radius: 12px;
|
||||
padding: 30px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
margin-bottom: 90px;
|
||||
}
|
||||
|
||||
// Agree All Section
|
||||
.agreement-all-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
// Divider
|
||||
.agreement-divider {
|
||||
height: 1px;
|
||||
background: #DDDDDD;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// Agreement Items List
|
||||
.agreement-items-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
// Agreement Item Row
|
||||
.agreement-item-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 4px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
// Checkbox Label
|
||||
.agreement-checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
// Checkbox Input (hidden)
|
||||
.agreement-checkbox-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
&:checked + .agreement-checkbox-custom {
|
||||
background-image: url('/img/checkbox-checked.png');
|
||||
}
|
||||
|
||||
&:focus + .agreement-checkbox-custom {
|
||||
box-shadow: 0 0 0 3px rgba(140, 149, 159, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
// Checkbox Custom Style (Circle Design)
|
||||
.agreement-checkbox-custom {
|
||||
position: relative;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
min-width: 26px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background-image: url('/img/checkbox-unchecked.png');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
transition: $transition-base;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Checkbox Text
|
||||
.agreement-checkbox-text {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #515961;
|
||||
line-height: 100.02%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
&.agreement-all-text {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #212529;
|
||||
}
|
||||
}
|
||||
|
||||
// Agreement Required Badge
|
||||
.agreement-required {
|
||||
color: #0049B4;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
// Agreement Title
|
||||
.agreement-title {
|
||||
color: #515961;
|
||||
}
|
||||
|
||||
// Toggle Icon
|
||||
.agreement-toggle-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
min-width: 22px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: $text-gray;
|
||||
cursor: pointer;
|
||||
transition: $transition-base;
|
||||
padding: 8px 4px 10px 7px;
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $primary-blue;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $primary-blue;
|
||||
|
||||
i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Agreement Content
|
||||
.agreement-content {
|
||||
margin-top: $spacing-md;
|
||||
background: $main-bg;
|
||||
}
|
||||
|
||||
.agreement-scroll {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: $spacing-lg;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: $border-gray;
|
||||
border-radius: $border-radius-sm;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: $text-light;
|
||||
border-radius: $border-radius-sm;
|
||||
|
||||
&:hover {
|
||||
background: $text-gray;
|
||||
}
|
||||
}
|
||||
|
||||
// Style agreement content
|
||||
div {
|
||||
font-size: $font-size-sm;
|
||||
line-height: 1.8;
|
||||
color: $text-gray;
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: $text-dark;
|
||||
margin-top: $spacing-lg;
|
||||
margin-bottom: $spacing-md;
|
||||
font-weight: $font-weight-semibold;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin-left: $spacing-lg;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: $spacing-md;
|
||||
|
||||
th, td {
|
||||
border: 1px solid $border-gray;
|
||||
padding: $spacing-sm;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background: $light-bg;
|
||||
font-weight: $font-weight-semibold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@include respond-to('sm') {
|
||||
.agreement-form {
|
||||
padding: 20px 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.agreement-all-section {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.agreement-items-list {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.agreement-item-row {
|
||||
height: auto;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.agreement-checkbox-text {
|
||||
font-size: $font-size-sm;
|
||||
|
||||
&.agreement-all-text {
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
}
|
||||
|
||||
.agreement-scroll {
|
||||
max-height: 250px;
|
||||
padding: $spacing-md;
|
||||
}
|
||||
}
|
||||
+89
-102
@@ -1,102 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_base_layout}"
|
||||
xmlns:hx-on="http://www.w3.org/1999/xhtml">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_base_layout}">
|
||||
<body>
|
||||
<th:block th:fragment="commonUserInfo">
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">이메일 아이디</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" id="userId" class="common_input_type_1 w_inp"
|
||||
<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">
|
||||
<input type="text" id="userId" class="org-form-input"
|
||||
th:classappend="${isInvited ? 'input-readonly' : ''}"
|
||||
maxlength="30"
|
||||
th:value="${emailId}"
|
||||
th:readonly="${isInvited}"
|
||||
th:placeholder="#{portalUser.Register.email}">
|
||||
<span class="special_t">@</span>
|
||||
<input type="text" id="domain" class="common_input_type_1 w_inp2"
|
||||
<span class="separator">@</span>
|
||||
<input type="text" id="domain" class="org-form-input"
|
||||
th:classappend="${isInvited ? 'input-readonly' : ''}"
|
||||
maxlength="50"
|
||||
th:value="${domain}"
|
||||
th:readonly="${isInvited}"
|
||||
th:placeholder="#{portalUser.Register.domain}">
|
||||
<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>
|
||||
<div class="btn_check">
|
||||
<a class="common_btn_type_2 cbt btn_check_email"
|
||||
th:classappend="${isInvited ? 'hidden' : ''}"
|
||||
th:hx-post="@{/check_id}"
|
||||
hx-include="#csrf, #loginId, [name='registrationType']"
|
||||
hx-target="#email-validation"
|
||||
hx-swap="none">
|
||||
<span>중복체크</span>
|
||||
</a>
|
||||
</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"/>
|
||||
<button type="button" class="org-btn org-btn-check btn_check_email"
|
||||
th:classappend="${isInvited ? 'hidden' : ''}">
|
||||
중복체크
|
||||
</button>
|
||||
<div id="email-validation" class="org-validation-message"></div>
|
||||
</div>
|
||||
<div id="email-validation"></div>
|
||||
</div>
|
||||
</th:block>
|
||||
</body>
|
||||
<th:block>
|
||||
<script th:fragment="commonUserInfoScript">
|
||||
<script th:fragment="commonUserInfoScript" th:inline="javascript">
|
||||
// 이메일 조합 함수
|
||||
function combineEmail() {
|
||||
let emailId = document.getElementById('userId').value;
|
||||
let domain = document.getElementById('domain').value;
|
||||
let emailId = $('#userId').val();
|
||||
let domain = $('#domain').val();
|
||||
let combined = emailId + '@' + domain;
|
||||
let loginIdInput = document.getElementById('loginId');
|
||||
if (loginIdInput) {
|
||||
loginIdInput.value = combined;
|
||||
}
|
||||
$('#loginId').val(combined);
|
||||
}
|
||||
|
||||
function handleEmailValidationResponse(response) {
|
||||
const individualConversionForm = document.getElementById('individualConversionForm');
|
||||
const emailChangeForm = document.getElementById('emailChangeForm');
|
||||
const newUserForm = document.getElementById('newUserForm');
|
||||
const userIdInput = document.getElementById('userId');
|
||||
const domainInput = document.getElementById('domain');
|
||||
const checkButton = document.querySelector('.btn_check_email');
|
||||
const loginIdInput = document.getElementById('loginId');
|
||||
const scenarioInput = document.getElementById('registrationScenario');
|
||||
const individualConversionForm = $('#individualConversionForm');
|
||||
const emailChangeForm = $('#emailChangeForm');
|
||||
const newUserForm = $('#newUserForm, #newUserFields');
|
||||
const userIdInput = $('#userId');
|
||||
const domainInput = $('#domain');
|
||||
const checkButton = $('.btn_check_email');
|
||||
const loginIdInput = $('#loginId');
|
||||
const scenarioInput = $('#registrationScenario');
|
||||
|
||||
if (response && response.showPopup) {
|
||||
switch (response.popupType) {
|
||||
case "validEmail":
|
||||
case "newUser":
|
||||
// 시나리오 값 설정
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'new';
|
||||
// hidden input이 form의 일부인지 확인
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
scenarioInput.val('new');
|
||||
|
||||
customPopups.showAlert(response.message);
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
checkButton.hide();
|
||||
|
||||
if (userIdInput && domainInput && loginIdInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
userIdInput.prop('disabled', true);
|
||||
domainInput.prop('disabled', true);
|
||||
userIdInput.css('backgroundColor', '#e0e0e0');
|
||||
domainInput.css('backgroundColor', '#e0e0e0');
|
||||
|
||||
const combinedEmail = `${userIdInput.value.trim()}@${domainInput.value.trim()}`;
|
||||
loginIdInput.value = combinedEmail;
|
||||
}
|
||||
const combinedEmail = `${userIdInput.val().trim()}@${domainInput.val().trim()}`;
|
||||
loginIdInput.val(combinedEmail);
|
||||
|
||||
if (newUserForm) newUserForm.style.display = 'block';
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'none';
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'none';
|
||||
newUserForm.show();
|
||||
individualConversionForm.hide();
|
||||
emailChangeForm.hide();
|
||||
break;
|
||||
|
||||
case "conversionOrChange":
|
||||
@@ -104,51 +85,33 @@
|
||||
response.message,
|
||||
function () {
|
||||
// "이메일 유지" 선택 시 동작
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'retain';
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
scenarioInput.val('retain');
|
||||
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'block';
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'none';
|
||||
if (newUserForm) newUserForm.style.display = 'none';
|
||||
individualConversionForm.show();
|
||||
emailChangeForm.hide();
|
||||
newUserForm.hide();
|
||||
|
||||
if (userIdInput && domainInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
}
|
||||
userIdInput.prop('disabled', true);
|
||||
domainInput.prop('disabled', true);
|
||||
userIdInput.css('backgroundColor', '#e0e0e0');
|
||||
domainInput.css('backgroundColor', '#e0e0e0');
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
checkButton.hide();
|
||||
},
|
||||
function () {
|
||||
// "이메일 전환" 선택 시 동작
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'change';
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
scenarioInput.val('change');
|
||||
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'block';
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'none';
|
||||
if (newUserForm) newUserForm.style.display = 'none';
|
||||
emailChangeForm.show();
|
||||
individualConversionForm.hide();
|
||||
newUserForm.hide();
|
||||
|
||||
if (userIdInput && domainInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
}
|
||||
userIdInput.prop('disabled', true);
|
||||
domainInput.prop('disabled', true);
|
||||
userIdInput.css('backgroundColor', '#e0e0e0');
|
||||
domainInput.css('backgroundColor', '#e0e0e0');
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
checkButton.hide();
|
||||
}
|
||||
);
|
||||
break;
|
||||
@@ -169,11 +132,35 @@
|
||||
}
|
||||
|
||||
// 이메일 입력 필드에 이벤트 리스너 추가
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let userIdInput = document.getElementById("userId");
|
||||
let domainInput = document.getElementById("domain");
|
||||
if (userIdInput) userIdInput.addEventListener("input", combineEmail);
|
||||
if (domainInput) domainInput.addEventListener("input", combineEmail);
|
||||
$(document).ready(function () {
|
||||
$('#userId, #domain').on('input', combineEmail);
|
||||
|
||||
// 이메일 중복 체크 버튼 클릭
|
||||
$('.btn_check_email').on('click', function () {
|
||||
const loginId = $('#loginId').val();
|
||||
const registrationType = $('input[name="registrationType"]').val();
|
||||
|
||||
if (!loginId || loginId.indexOf('@') === -1) {
|
||||
customPopups.showAlert('이메일 주소를 올바르게 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: /*[[@{/check_id}]]*/ '/check_id',
|
||||
type: 'POST',
|
||||
data: {
|
||||
loginId: loginId,
|
||||
registrationType: registrationType,
|
||||
_csrf: $('input[name="_csrf"]').val()
|
||||
},
|
||||
success: function (response) {
|
||||
handleEmailValidationResponse(response);
|
||||
},
|
||||
error: function () {
|
||||
customPopups.showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
+181
-183
@@ -5,127 +5,94 @@
|
||||
<th:block th:fragment="newUserForm">
|
||||
<div id="newUserFields">
|
||||
<!-- 성명 -->
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">성명</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" th:field="*{userName}" id="userName" class="common_input_type_1"
|
||||
th:placeholder="#{portalUser.Register.userName}">
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label">
|
||||
<span class="required">*</span>
|
||||
성명
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" th:field="*{userName}" id="userName" class="org-form-input"
|
||||
th:placeholder="#{portalUser.Register.userName}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 휴대폰 번호 입력 -->
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">휴대폰 번호</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<span class="input">
|
||||
<div class="custom_select ct_sc h_inp2" id="phoneMobile">
|
||||
<div class="select_selected">선택</div>
|
||||
<ul class="common_selecttype select_items select_hide ct_sc2">
|
||||
<li>010</li>
|
||||
<li>011</li>
|
||||
<li>017</li>
|
||||
<li>016</li>
|
||||
<li>018</li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
<span class="dash">-</span>
|
||||
<span class="input">
|
||||
<input type="text" id="cellPhone1" maxlength="4" class="common_input_type_1 w_inp3"
|
||||
th:placeholder="#{portal.Register.phone1}">
|
||||
</span>
|
||||
<span class="dash">-</span>
|
||||
<span class="input">
|
||||
<input type="text" id="cellPhone2" maxlength="4" class="common_input_type_1 w_inp3"
|
||||
th:placeholder="#{portal.Register.phone2}">
|
||||
</span>
|
||||
<input type="hidden" th:field="*{mobileNumber}" id="mobileNumber">
|
||||
</div>
|
||||
<div class="btn_check">
|
||||
<a class="common_btn_type_2 cbt btn_auth"
|
||||
th:hx-post="@{/auth/request_auth_number}"
|
||||
hx-include="#csrf, #mobileNumber"
|
||||
hx-target="#authNumberContainer"
|
||||
hx-swap="none">
|
||||
<span>인증번호 받기</span>
|
||||
</a>
|
||||
<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="org-btn org-btn-check btn_auth">
|
||||
인증번호 받기
|
||||
</button>
|
||||
<div id="mobile-validation" class="org-validation-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mobile-validation"></div>
|
||||
|
||||
<!-- 인증번호 입력 -->
|
||||
<div class="info1 pt28" id="authNumberContainer">
|
||||
<p class="title">
|
||||
<span class="dot">인증번호 입력</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<div class="certify_box">
|
||||
<input type="text" th:field="*{authNumber}" id="authNumber" maxlength="6" pattern="[0-9]*"
|
||||
inputmode="numeric" class="common_input_type_1 w_input" th:placeholder="#{ncrdRegister.validate.authNumber}" required>
|
||||
<span class="certify_time" id="certify_time">03:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn_check">
|
||||
<a class="common_btn_type_2 cbt btn_verify_auth"
|
||||
th:hx-post="@{/auth/verify_auth_number}"
|
||||
hx-include="#mobileNumber,#authNumber"
|
||||
hx-target="#authNumber-validation"
|
||||
hx-swap="none">
|
||||
<span>인증번호 확인</span>
|
||||
</a>
|
||||
<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="org-btn org-btn-check btn_verify_auth">
|
||||
인증번호 확인
|
||||
</button>
|
||||
<div id="authNumber-validation" class="org-validation-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="authNumber-validation"></div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">비밀번호</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="password" name="password" id="password" class="common_input_type_1 w_input"
|
||||
th:placeholder="#{portalUser.Register.pass}"
|
||||
th:hx-post="@{/check_password}"
|
||||
hx-trigger="blur"
|
||||
hx-include="#mobileNumber, #loginId"
|
||||
hx-target="#password-validation"
|
||||
hx-swap="innerHTML">
|
||||
<input type="hidden" name="isPasswordValid" id="isPasswordValid"/>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></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 id="password-validation" class="validation-message"></div>
|
||||
|
||||
<!-- 비밀번호 확인 -->
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">비밀번호 확인</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="password" name="password2" id="password2" class="common_input_type_1 w_input"
|
||||
th:placeholder="#{portalUser.Register.passConfirm}"
|
||||
th:hx-post="@{/check_password_match}"
|
||||
hx-trigger="blur"
|
||||
hx-target="#password-match-validation"
|
||||
hx-include="#password"
|
||||
hx-swap="innerHTML">
|
||||
<input type="hidden" name="isPasswordMatch" id="isPasswordMatch"/>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></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 id="password-match-validation" class="validation-message"></div>
|
||||
|
||||
</div>
|
||||
</th:block>
|
||||
@@ -134,16 +101,16 @@
|
||||
<script th:fragment="newUserScript">
|
||||
// 휴대폰 번호 조합 함수
|
||||
function combineMobileNumber() {
|
||||
let mobileElement = document.querySelector('#phoneMobile .select_selected');
|
||||
if (!mobileElement) {
|
||||
console.error('Mobile element not found');
|
||||
let mobileSelect = document.getElementById('phoneMobile');
|
||||
if (!mobileSelect) {
|
||||
console.error('Mobile select element not found');
|
||||
return null;
|
||||
}
|
||||
let prefix = mobileElement.textContent.trim();
|
||||
let prefix = mobileSelect.value;
|
||||
let middle = document.getElementById('cellPhone1').value.trim();
|
||||
let last = document.getElementById('cellPhone2').value.trim();
|
||||
|
||||
if (prefix === '선택' || !middle || !last) {
|
||||
if (!prefix || !middle || !last) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -159,7 +126,6 @@
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
activateSelect();
|
||||
let countdownInterval;
|
||||
let isAuthVerified = false;
|
||||
|
||||
@@ -182,11 +148,9 @@
|
||||
combineMobileNumber();
|
||||
});
|
||||
|
||||
// select_selected 변경 감지
|
||||
$('#phoneMobile .select_items li').on('click', function () {
|
||||
setTimeout(() => {
|
||||
combineMobileNumber();
|
||||
}, 100);
|
||||
// select 변경 감지
|
||||
$('#phoneMobile').on('change', function () {
|
||||
combineMobileNumber();
|
||||
});
|
||||
|
||||
// 인증번호 입력 제한
|
||||
@@ -215,8 +179,10 @@
|
||||
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 {
|
||||
@@ -256,7 +222,8 @@
|
||||
}
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
document.querySelectorAll('#phoneMobile .select_selected, #cellPhone1, #cellPhone2')
|
||||
document.getElementById('phoneMobile').addEventListener('change', combineMobileNumber);
|
||||
document.querySelectorAll('#cellPhone1, #cellPhone2')
|
||||
.forEach(el => el.addEventListener('input', combineMobileNumber));
|
||||
|
||||
let authNumberInput = document.getElementById("authNumber");
|
||||
@@ -275,76 +242,107 @@
|
||||
}
|
||||
|
||||
// 인증번호 요청 버튼 이벤트 리스너
|
||||
let authButton = document.querySelector(".btn_auth");
|
||||
if (authButton) {
|
||||
authButton.addEventListener("click", function (event) {
|
||||
let mobileNumber = combineMobileNumber();
|
||||
if (!mobileNumber) {
|
||||
event.preventDefault(); // htmx 요청 중지
|
||||
customPopups.showAlert("휴대폰 번호를 올바르게 입력해주세요.");
|
||||
return;
|
||||
}
|
||||
document.getElementById('mobileNumber').value = mobileNumber;
|
||||
// htmx 요청이 자동으로 실행됨
|
||||
});
|
||||
}
|
||||
|
||||
// 인증번호 확인 버튼 이벤트 리스너
|
||||
let verifyAuthButton = document.querySelector(".btn_verify_auth");
|
||||
if (verifyAuthButton) {
|
||||
verifyAuthButton.addEventListener("click", function () {
|
||||
let authNumber = document.getElementById('authNumber').value;
|
||||
if (authNumber.length !== 6) {
|
||||
customPopups.showAlert("6자리 인증번호를 입력해주세요.");
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// HTMX 이벤트 리스너
|
||||
document.body.addEventListener('htmx:afterSwap', function (event) {
|
||||
let targetId = event.detail.target ? event.detail.target.id : null;
|
||||
if (targetId && ['password-validation', 'password-match-validation', 'authNumberContainer', 'authNumber-validation', 'email-validation'].includes(targetId)) {
|
||||
let response;
|
||||
try {
|
||||
response = typeof event.detail.xhr.response === 'string'
|
||||
? JSON.parse(event.detail.xhr.response)
|
||||
: event.detail.xhr.response;
|
||||
} catch (e) {
|
||||
console.error('Failed to parse response as JSON:', event.detail.xhr.response);
|
||||
customPopups.showAlert("서버에서 예상치 못한 응답을 받았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (targetId) {
|
||||
case 'email-validation':
|
||||
// handleEmailValidationResponse(response);
|
||||
break;
|
||||
case 'password-validation':
|
||||
case 'password-match-validation':
|
||||
let targetElement = document.getElementById(targetId);
|
||||
targetElement.className = 'validation-message ' + (response.valid ? 'success' : 'error');
|
||||
targetElement.textContent = response.message;
|
||||
|
||||
// 유효성 상태 저장
|
||||
if (targetId === 'password-validation') {
|
||||
document.getElementById('isPasswordValid').value = response.valid;
|
||||
} else if (targetId === 'password-match-validation') {
|
||||
document.getElementById('isPasswordMatch').value = response.valid;
|
||||
}
|
||||
break;
|
||||
case 'authNumberContainer':
|
||||
handleAuthNumberRequest(response);
|
||||
break;
|
||||
case 'authNumber-validation':
|
||||
handleAuthNumberVerification(response);
|
||||
break;
|
||||
}
|
||||
$('.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("처리 중 오류가 발생했습니다. 다시 시도해주세요.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.body.addEventListener('htmx:responseError', function (event) {
|
||||
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>
|
||||
|
||||
+273
-284
@@ -1,287 +1,274 @@
|
||||
<!doctype html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:hx-on="http://www.w3.org/1999/xhtml">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<body>
|
||||
<th:block th:fragment="orgInfoForm">
|
||||
<div class="form_type">
|
||||
<div class="info1">
|
||||
<p class="title">
|
||||
<span class="dot">사업자등록번호</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1 w_inp5 business-number" id="compRegNo1" maxlength="3"
|
||||
th:placeholder="#{portalOrg.Register.compRegNo1}" required>
|
||||
<span class="dash">-</span>
|
||||
<input type="text" class="common_input_type_1 w_inp6 business-number" id="compRegNo2" maxlength="2"
|
||||
th:placeholder="#{portalOrg.Register.compRegNo2}" required>
|
||||
<span class="dash">-</span>
|
||||
<input type="text" class="common_input_type_1 w_inp7 business-number" id="compRegNo3" maxlength="5"
|
||||
th:placeholder="#{portalOrg.Register.compRegNo3}" required>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
<input type="hidden" id="compRegNo" th:field="*{compRegNo}" hx-trigger="change delay:1s"/>
|
||||
<!-- Business Registration Number -->
|
||||
<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">
|
||||
<input type="text" class="org-form-input business-number" id="compRegNo1" maxlength="3"
|
||||
placeholder="000" required>
|
||||
<span class="separator">-</span>
|
||||
<input type="text" class="org-form-input business-number" id="compRegNo2" maxlength="2"
|
||||
placeholder="00" required>
|
||||
<span class="separator">-</span>
|
||||
<input type="text" class="org-form-input business-number" id="compRegNo3" maxlength="5"
|
||||
placeholder="00000" required>
|
||||
</div>
|
||||
<input type="hidden" id="compRegNo" th:field="*{compRegNo}"/>
|
||||
<div id="compRegNo-validation" class="org-validation-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">법인등록번호</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1 w_inp8 corp-reg-no" id="corpRegNo1" maxlength="6"
|
||||
th:placeholder="#{portalOrg.Register.corpRegNo1}" required>
|
||||
<span class="dash">-</span>
|
||||
<input type="text" class="common_input_type_1 w_inp9 corp-reg-no" id="corpRegNo2" maxlength="7"
|
||||
th:placeholder="#{portalOrg.Register.corpRegNo2}" required>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
<input type="hidden" id="corpRegNo" th:field="*{corpRegNo}" hx-trigger="change delay:1s"/>
|
||||
<!-- Corporate Registration Number -->
|
||||
<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">
|
||||
<input type="text" class="org-form-input corp-reg-no" id="corpRegNo1" maxlength="6"
|
||||
placeholder="000000" required>
|
||||
<span class="separator">-</span>
|
||||
<input type="text" class="org-form-input corp-reg-no" id="corpRegNo2" maxlength="7"
|
||||
placeholder="0000000" required>
|
||||
</div>
|
||||
<input type="hidden" id="corpRegNo" th:field="*{corpRegNo}"/>
|
||||
<div id="corpRegNo-validation" class="org-validation-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">법인명</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1" id="orgName" th:field="*{orgName}"
|
||||
th:placeholder="#{portalOrg.Register.orgName}"
|
||||
th:classappend="${#fields.hasErrors('orgName')}? 'is-invalid'" required>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
<div th:if="${#fields.hasErrors('orgName')}" class="invalid-feedback">
|
||||
<span th:errors="*{orgName}"></span>
|
||||
</div>
|
||||
<!-- Company Name -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label" for="orgName">
|
||||
<span class="required">*</span>
|
||||
법인명
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" class="org-form-input" id="orgName" th:field="*{orgName}"
|
||||
placeholder="법인명을 입력하세요"
|
||||
th:classappend="${#fields.hasErrors('orgName')}? 'is-invalid'" required>
|
||||
<div th:if="${#fields.hasErrors('orgName')}" class="org-validation-message error">
|
||||
<span th:errors="*{orgName}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">대표자 성명</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1" id="ceoName" th:field="*{ceoName}"
|
||||
th:placeholder="#{portalOrg.Register.ceoName}"
|
||||
th:classappend="${#fields.hasErrors('ceoName')}? 'is-invalid'" required>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
<div th:if="${#fields.hasErrors('ceoName')}" class="invalid-feedback">
|
||||
<span th:errors="*{ceoName}"></span>
|
||||
</div>
|
||||
<!-- CEO Name -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label" for="ceoName">
|
||||
<span class="required">*</span>
|
||||
대표자 성명
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" class="org-form-input" id="ceoName" th:field="*{ceoName}"
|
||||
placeholder="대표자 성명을 입력하세요"
|
||||
th:classappend="${#fields.hasErrors('ceoName')}? 'is-invalid'" required>
|
||||
<div th:if="${#fields.hasErrors('ceoName')}" class="org-validation-message error">
|
||||
<span th:errors="*{ceoName}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">사업장 소재지</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1" id="orgAddr" th:field="*{orgAddr}"
|
||||
th:placeholder="#{portalOrg.Register.orgAddr}"
|
||||
th:classappend="${#fields.hasErrors('orgAddr')}? 'is-invalid'" required>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
<div th:if="${#fields.hasErrors('orgAddr')}" class="invalid-feedback">
|
||||
<span th:errors="*{orgAddr}"></span>
|
||||
</div>
|
||||
<!-- Business Address -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label" for="orgAddr">
|
||||
<span class="required">*</span>
|
||||
사업장 소재지
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" class="org-form-input" id="orgAddr" th:field="*{orgAddr}"
|
||||
placeholder="사업장 소재지를 입력하세요"
|
||||
th:classappend="${#fields.hasErrors('orgAddr')}? 'is-invalid'" required>
|
||||
<div th:if="${#fields.hasErrors('orgAddr')}" class="org-validation-message error">
|
||||
<span th:errors="*{orgAddr}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">업태</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1 w_input" id="orgSectors" th:field="*{orgSectors}"
|
||||
th:placeholder="#{portalOrg.Register.orgSectors}">
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
</div>
|
||||
<!-- Business Type -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label" for="orgSectors">
|
||||
<span class="required">*</span>
|
||||
업태
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" class="org-form-input" id="orgSectors" th:field="*{orgSectors}"
|
||||
placeholder="업태를 입력하세요" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">업종</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1" id="orgIndustryType" th:field="*{orgIndustryType}"
|
||||
th:placeholder="#{portalOrg.Register.orgIndustryType}">
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
</div>
|
||||
<!-- Industry Type -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label" for="orgIndustryType">
|
||||
<span class="required">*</span>
|
||||
업종
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" class="org-form-input" id="orgIndustryType" th:field="*{orgIndustryType}"
|
||||
placeholder="업종을 입력하세요" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">회사 전화번호</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<span class="input">
|
||||
<div class="custom_select ct_sc h_inp2" id="orgAreaCode">
|
||||
<div class="select_selected active">선택</div>
|
||||
<ul class="common_selecttype select_hide select_items ct_sc2">
|
||||
<li>국번없음</li>
|
||||
<li>02</li>
|
||||
<li>031</li>
|
||||
<li>032</li>
|
||||
<li>033</li>
|
||||
<li>041</li>
|
||||
<li>042</li>
|
||||
<li>043</li>
|
||||
<li>044</li>
|
||||
<li>051</li>
|
||||
<li>052</li>
|
||||
<li>053</li>
|
||||
<li>054</li>
|
||||
<li>055</li>
|
||||
<li>061</li>
|
||||
<li>062</li>
|
||||
<li>063</li>
|
||||
<li>064</li>
|
||||
<li>060</li>
|
||||
<li>070</li>
|
||||
<li>080</li>
|
||||
<li>010</li>
|
||||
<li>011</li>
|
||||
<li>016</li>
|
||||
<li>017</li>
|
||||
<li>018</li>
|
||||
<li>019</li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
<span class="dash">-</span>
|
||||
<span class="input">
|
||||
<input type="text" id="orgPhoneNumber1" class="common_input_type_1 w_inp3" maxlength="4"
|
||||
th:placeholder="#{portal.Register.phone1}">
|
||||
</span>
|
||||
<span class="dash">-</span>
|
||||
<span class="input">
|
||||
<input type="text" id="orgPhoneNumber2" class="common_input_type_1 w_inp3" maxlength="4"
|
||||
th:placeholder="#{portal.Register.phone2}">
|
||||
</span>
|
||||
</div>
|
||||
<input type="hidden" id="orgPhoneNumber" th:field="*{orgPhoneNumber}">
|
||||
<div class="btn_check pc-only"></div>
|
||||
<!-- Company Phone Number -->
|
||||
<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" id="orgAreaCode" required>
|
||||
<option value="">선택</option>
|
||||
<option value="국번없음">국번없음</option>
|
||||
<option value="02">02</option>
|
||||
<option value="031">031</option>
|
||||
<option value="032">032</option>
|
||||
<option value="033">033</option>
|
||||
<option value="041">041</option>
|
||||
<option value="042">042</option>
|
||||
<option value="043">043</option>
|
||||
<option value="044">044</option>
|
||||
<option value="051">051</option>
|
||||
<option value="052">052</option>
|
||||
<option value="053">053</option>
|
||||
<option value="054">054</option>
|
||||
<option value="055">055</option>
|
||||
<option value="061">061</option>
|
||||
<option value="062">062</option>
|
||||
<option value="063">063</option>
|
||||
<option value="064">064</option>
|
||||
<option value="070">070</option>
|
||||
<option value="080">080</option>
|
||||
<option value="010">010</option>
|
||||
<option value="011">011</option>
|
||||
<option value="016">016</option>
|
||||
<option value="017">017</option>
|
||||
<option value="018">018</option>
|
||||
<option value="019">019</option>
|
||||
</select>
|
||||
<span class="separator">-</span>
|
||||
<input type="text" id="orgPhoneNumber1" class="org-form-input" maxlength="4"
|
||||
placeholder="0000">
|
||||
<span class="separator">-</span>
|
||||
<input type="text" id="orgPhoneNumber2" class="org-form-input" maxlength="4"
|
||||
placeholder="0000">
|
||||
</div>
|
||||
<input type="hidden" id="orgPhoneNumber" th:field="*{orgPhoneNumber}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Name -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label" for="serviceName">
|
||||
<span class="required">*</span>
|
||||
서비스명
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" class="org-form-input" id="serviceName" th:field="*{serviceName}"
|
||||
placeholder="서비스명을 입력하세요"
|
||||
th:classappend="${#fields.hasErrors('serviceName')}? 'is-invalid'" required>
|
||||
<div th:if="${#fields.hasErrors('serviceName')}" class="org-validation-message error">
|
||||
<span th:errors="*{serviceName}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">서비스명</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" class="common_input_type_1" id="serviceName" th:field="*{serviceName}"
|
||||
th:placeholder="#{portalOrg.Register.serviceName}"
|
||||
th:classappend="${#fields.hasErrors('serviceName')}? 'is-invalid'" required>
|
||||
</div>
|
||||
<div class="btn_check pc-only"></div>
|
||||
<div th:if="${#fields.hasErrors('serviceName')}" class="invalid-feedback">
|
||||
<span th:errors="*{serviceName}"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Customer Service Phone Number -->
|
||||
<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" id="scAreaCode" required>
|
||||
<option value="">선택</option>
|
||||
<option value="국번없음">국번없음</option>
|
||||
<option value="02">02</option>
|
||||
<option value="031">031</option>
|
||||
<option value="032">032</option>
|
||||
<option value="033">033</option>
|
||||
<option value="041">041</option>
|
||||
<option value="042">042</option>
|
||||
<option value="043">043</option>
|
||||
<option value="044">044</option>
|
||||
<option value="051">051</option>
|
||||
<option value="052">052</option>
|
||||
<option value="053">053</option>
|
||||
<option value="054">054</option>
|
||||
<option value="055">055</option>
|
||||
<option value="061">061</option>
|
||||
<option value="062">062</option>
|
||||
<option value="063">063</option>
|
||||
<option value="064">064</option>
|
||||
<option value="070">070</option>
|
||||
<option value="080">080</option>
|
||||
<option value="010">010</option>
|
||||
<option value="011">011</option>
|
||||
<option value="016">016</option>
|
||||
<option value="017">017</option>
|
||||
<option value="018">018</option>
|
||||
<option value="019">019</option>
|
||||
</select>
|
||||
<span class="separator">-</span>
|
||||
<input type="text" id="scPhoneNumber1" class="org-form-input" maxlength="4"
|
||||
placeholder="0000">
|
||||
<span class="separator">-</span>
|
||||
<input type="text" id="scPhoneNumber2" class="org-form-input" maxlength="4"
|
||||
placeholder="0000">
|
||||
</div>
|
||||
<input type="hidden" id="scPhoneNumber" th:field="*{scPhoneNumber}">
|
||||
</div>
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">고객센터 전화번호</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<span class="input">
|
||||
<div class="custom_select ct_sc h_inp2" id="scAreaCode">
|
||||
<div class="select_selected active">선택</div>
|
||||
<ul class="common_selecttype select_hide select_items ct_sc2">
|
||||
<li>국번없음</li>
|
||||
<li>02</li>
|
||||
<li>031</li>
|
||||
<li>032</li>
|
||||
<li>033</li>
|
||||
<li>041</li>
|
||||
<li>042</li>
|
||||
<li>043</li>
|
||||
<li>044</li>
|
||||
<li>051</li>
|
||||
<li>052</li>
|
||||
<li>053</li>
|
||||
<li>054</li>
|
||||
<li>055</li>
|
||||
<li>061</li>
|
||||
<li>062</li>
|
||||
<li>063</li>
|
||||
<li>064</li>
|
||||
<li>060</li>
|
||||
<li>070</li>
|
||||
<li>080</li>
|
||||
<li>010</li>
|
||||
<li>011</li>
|
||||
<li>016</li>
|
||||
<li>017</li>
|
||||
<li>018</li>
|
||||
<li>019</li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
<span class="dash">-</span>
|
||||
<span class="input">
|
||||
<input type="text" id="scPhoneNumber1" class="common_input_type_1 w_inp3" maxlength="4"
|
||||
th:placeholder="#{portal.Register.phone1}">
|
||||
</span>
|
||||
<span class="dash">-</span>
|
||||
<span class="input">
|
||||
<input type="text" id="scPhoneNumber2" class="common_input_type_1 w_inp3" maxlength="4"
|
||||
th:placeholder="#{portal.Register.phone2}">
|
||||
</span>
|
||||
</div>
|
||||
<input type="hidden" id="scPhoneNumber" th:field="*{scPhoneNumber}">
|
||||
<div class="btn_check pc-only"></div>
|
||||
</div>
|
||||
|
||||
<!-- Business Registration Certificate Upload -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label">
|
||||
<span class="required">*</span>
|
||||
사업자 등록증
|
||||
</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<div class="org-file-upload">
|
||||
<input type="text" class="org-file-display" id="fileNameDisplay" readonly placeholder="첨부파일을 선택하세요">
|
||||
<input type="hidden" id="compRegFile" th:field="*{compRegFile}">
|
||||
<label class="org-file-label" for="files">
|
||||
<i class="fas fa-upload"></i> 파일선택
|
||||
<input type="file" id="files" name="files"
|
||||
accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.hwp,.gif,.jpg,.png">
|
||||
</label>
|
||||
<button type="button" class="org-file-remove" id="fileRemoveBtn" style="display: none;">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info1 pt28">
|
||||
<p class="title tit_add w_tit">
|
||||
<span class="dot">사업자 등록증</span>
|
||||
</p>
|
||||
<div class="info_line info_add">
|
||||
<div class="info_box1 info_add2">
|
||||
<div class="filebox">
|
||||
<input type="text" class="upload-name before" readonly="readonly" placeholder="첨부파일">
|
||||
<input type="hidden" id="compRegFile" th:field="*{compRegFile}">
|
||||
</div>
|
||||
<div class="btn_check">
|
||||
<div class="file_btn">
|
||||
<label for="files">파일선택</label>
|
||||
<input type="file" id="files" name="files" accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.hwp,.gif,.jpg,.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div th:if="${#fields.hasErrors('compRegFile')}" class="invalid-feedback">
|
||||
<span th:errors="*{compRegFile}"></span>
|
||||
</div>
|
||||
<div class="list-dot">
|
||||
<p>첨부파일은 10MB 이내로 등록해 주세요.</p>
|
||||
<p>문서파일과 이미지 파일만 등록 가능합니다. (pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)</p>
|
||||
</div>
|
||||
<div class="org-file-notice">
|
||||
<p>첨부파일은 10MB 이내로 등록해 주세요.</p>
|
||||
<p>문서파일과 이미지 파일만 등록 가능합니다. (pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)</p>
|
||||
</div>
|
||||
<div th:if="${#fields.hasErrors('compRegFile')}" class="org-validation-message error">
|
||||
<span th:errors="*{compRegFile}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:fragment="orgInfoScript">
|
||||
|
||||
function validatePhoneNumber(prefix) {
|
||||
const areaCode = document.getElementById(`${prefix}AreaCode`).value;
|
||||
const part1 = document.getElementById(`${prefix}PhoneNumber1`).value.trim();
|
||||
const part2 = document.getElementById(`${prefix}PhoneNumber2`).value.trim();
|
||||
|
||||
// 회사 전화번호 검증
|
||||
if (!part1 || !part2) {
|
||||
if (!areaCode || areaCode === '' || !part1 || !part2) {
|
||||
customPopups.showAlert(`${prefix === 'org' ? '회사' : '고객센터'} 전화번호를 모두 입력해주세요.`);
|
||||
return false;
|
||||
}
|
||||
@@ -289,7 +276,6 @@
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
activateSelect();
|
||||
|
||||
function checkAndSendData(parts, expectedLengths, hiddenInputId, url, paramName) {
|
||||
let isValid = true;
|
||||
@@ -305,26 +291,37 @@
|
||||
|
||||
if (isValid) {
|
||||
document.getElementById(hiddenInputId).value = fullValue;
|
||||
let values = {};
|
||||
values[paramName] = fullValue;
|
||||
|
||||
// CSRF 토큰을 정확하게 가져오기
|
||||
const csrfToken = document.querySelector('input[name="_csrf"]')?.value ||
|
||||
document.querySelector('meta[name="_csrf"]')?.content;
|
||||
document.querySelector('meta[name="_csrf"]')?.content;
|
||||
|
||||
htmx.ajax('POST', url, {
|
||||
values: values,
|
||||
// AJAX로 검증 요청
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
[paramName]: fullValue,
|
||||
_csrf: csrfToken
|
||||
},
|
||||
headers: {
|
||||
'X-XSRF-TOKEN': csrfToken,
|
||||
'X-Custom-Handler': 'registration-validation'
|
||||
},
|
||||
swap: 'none',
|
||||
target: '#' + hiddenInputId // 명시적 타겟 지정
|
||||
}).then(function() {
|
||||
// HTMX 이벤트가 제대로 발생하는지 확인
|
||||
console.log('HTMX request completed');
|
||||
}).catch(function(error) {
|
||||
console.error('HTMX request failed:', error);
|
||||
success: function(response) {
|
||||
const validationDiv = document.getElementById(hiddenInputId + '-validation');
|
||||
if (validationDiv) {
|
||||
if (response.valid) {
|
||||
validationDiv.className = 'org-validation-message success';
|
||||
validationDiv.textContent = response.message || '유효한 번호입니다.';
|
||||
} else {
|
||||
validationDiv.className = 'org-validation-message error';
|
||||
validationDiv.textContent = response.message || '유효하지 않은 번호입니다.';
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error('Validation request failed');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -346,10 +343,11 @@
|
||||
checkAndSendData(parts, [6, 7], 'corpRegNo', '/check-corp-reg-no', 'corpRegNo');
|
||||
}
|
||||
|
||||
// 파일 선택 관련 코드
|
||||
// File upload handling
|
||||
const fileInput = document.getElementById('files');
|
||||
const fileNameInput = document.querySelector('.upload-name');
|
||||
const fileNameDisplay = document.getElementById('fileNameDisplay');
|
||||
const compRegFileInput = document.getElementById('compRegFile');
|
||||
const fileRemoveBtn = document.getElementById('fileRemoveBtn');
|
||||
|
||||
fileInput.addEventListener('change', function() {
|
||||
const files = fileInput.files;
|
||||
@@ -378,22 +376,20 @@
|
||||
return;
|
||||
}
|
||||
|
||||
fileNameInput.value = fileNames.join(', ');
|
||||
fileNameInput.classList.remove('before');
|
||||
fileNameInput.classList.add('i_trash', 'after');
|
||||
fileNameDisplay.value = fileNames.join(', ');
|
||||
fileNameDisplay.classList.add('has-file');
|
||||
compRegFileInput.value = fileNames.join(', '); // hidden input에 파일 이름들 설정
|
||||
fileRemoveBtn.style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
||||
// 파일명 입력란 클릭 시 파일 제거
|
||||
fileNameInput.addEventListener('click', function() {
|
||||
if (fileNameInput.classList.contains('i_trash')) {
|
||||
fileInput.value = '';
|
||||
fileNameInput.value = '';
|
||||
compRegFileInput.value = ''; // hidden input 값도 제거
|
||||
fileNameInput.classList.remove('i_trash', 'after');
|
||||
fileNameInput.classList.add('before');
|
||||
}
|
||||
// File remove button
|
||||
fileRemoveBtn.addEventListener('click', function() {
|
||||
fileInput.value = '';
|
||||
fileNameDisplay.value = '';
|
||||
compRegFileInput.value = '';
|
||||
fileNameDisplay.classList.remove('has-file');
|
||||
fileRemoveBtn.style.display = 'none';
|
||||
});
|
||||
|
||||
function addListeners() {
|
||||
@@ -404,21 +400,15 @@
|
||||
document.getElementById('corpRegNo1').addEventListener('input', checkCorporateNumber);
|
||||
document.getElementById('corpRegNo2').addEventListener('input', checkCorporateNumber);
|
||||
|
||||
// 전화번호 조합 함수 추가
|
||||
// 전화번호 조합 함수
|
||||
function combinePhoneNumber(prefix) {
|
||||
const areaCode = document.querySelector(`#${prefix}AreaCode .select_selected`).textContent;
|
||||
const areaCode = document.getElementById(`${prefix}AreaCode`).value;
|
||||
const part1 = document.getElementById(`${prefix}PhoneNumber1`).value;
|
||||
const part2 = document.getElementById(`${prefix}PhoneNumber2`).value;
|
||||
|
||||
if (areaCode === '선택' || !part1 || !part2) return;
|
||||
if (!areaCode || areaCode === '' || !part1 || !part2) return;
|
||||
|
||||
let fullNumber = '';
|
||||
// 지역번호가 '없음'인 경우에도 접두어로 저장
|
||||
if (areaCode === '국번없음') {
|
||||
fullNumber = `국번없음-${part1}-${part2}`;
|
||||
} else {
|
||||
fullNumber = `${areaCode}-${part1}-${part2}`;
|
||||
}
|
||||
const fullNumber = `${areaCode}-${part1}-${part2}`;
|
||||
|
||||
// hidden input에 하이픈이 포함된 값 설정
|
||||
const hiddenInput = document.getElementById(`${prefix}PhoneNumber`);
|
||||
@@ -443,12 +433,11 @@
|
||||
});
|
||||
|
||||
// 지역번호 선택 시에도 전화번호 조합
|
||||
document.querySelector('#orgAreaCode').addEventListener('click', () => combinePhoneNumber('org'));
|
||||
document.querySelector('#scAreaCode').addEventListener('click', () => combinePhoneNumber('sc'));
|
||||
document.getElementById('orgAreaCode').addEventListener('change', () => combinePhoneNumber('org'));
|
||||
document.getElementById('scAreaCode').addEventListener('change', () => combinePhoneNumber('sc'));
|
||||
}
|
||||
|
||||
addListeners();
|
||||
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
+198
-161
@@ -1,181 +1,218 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.w3.org/1999/xhtml">
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<body>
|
||||
<th:block th:fragment="orgUserInfoForm">
|
||||
<div class="info1 pt28">
|
||||
<p class="title">
|
||||
<span class="dot">이메일 아이디</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1">
|
||||
<input type="text" id="userId" class="common_input_type_1 w_inp"
|
||||
th:placeholder="#{portalUser.Register.email}">
|
||||
<span class="special_t">@</span>
|
||||
<input type="text" id="domain" class="common_input_type_1 w_inp2"
|
||||
th:placeholder="#{portalUser.Register.domain}">
|
||||
<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>
|
||||
<div class="btn_check">
|
||||
<a class="common_btn_type_2 cbt btn_check_email"
|
||||
th:hx-post="@{/check_id}"
|
||||
hx-include="#csrf, #loginId, [name='registrationType']"
|
||||
hx-target="#email-validation"
|
||||
hx-swap="none">
|
||||
<span>중복체크</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="email-validation"></div>
|
||||
</div>
|
||||
<div id="dynamicFormContainer">
|
||||
<div id="individualConversionForm" style="display: none;">
|
||||
<div th:include="~{apps/register/components/individualConversionForm :: individualConversionForm}"></div>
|
||||
</div>
|
||||
<div id="emailChangeForm" style="display: none;">
|
||||
<div th:include="~{apps/register/components/emailChangeForm :: emailChangeForm}"></div>
|
||||
</div>
|
||||
<div id="newUserForm" style="display: none;">
|
||||
<div th:include="~{apps/register/components/newUserInfoForm :: newUserForm}"></div>
|
||||
</div>
|
||||
<!-- Email ID -->
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label">
|
||||
<span class="required">*</span>
|
||||
이메일 아이디
|
||||
</label>
|
||||
<div class="org-input-button-group">
|
||||
<div class="org-compound-input" style="flex: 1;">
|
||||
<input type="text" id="userId" class="org-form-input"
|
||||
placeholder="이메일 아이디">
|
||||
<span class="separator">@</span>
|
||||
<input type="text" id="domain" class="org-form-input"
|
||||
placeholder="도메인">
|
||||
</div>
|
||||
<button type="button" class="org-btn org-btn-check btn_check_email">
|
||||
중복체크
|
||||
</button>
|
||||
</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>
|
||||
|
||||
<!-- Dynamic Form Container -->
|
||||
<div id="dynamicFormContainer">
|
||||
<div id="individualConversionForm" style="display: none;">
|
||||
<div th:include="~{apps/register/components/individualConversionForm :: individualConversionForm}"></div>
|
||||
</div>
|
||||
<div id="emailChangeForm" style="display: none;">
|
||||
<div th:include="~{apps/register/components/emailChangeForm :: emailChangeForm}"></div>
|
||||
</div>
|
||||
<div id="newUserForm" style="display: none;">
|
||||
<div th:include="~{apps/register/components/newUserInfoForm :: newUserForm}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:fragment="orgUserInfoScript">
|
||||
// 이메일 조합 함수
|
||||
function combineEmail() {
|
||||
let emailId = document.getElementById('userId').value;
|
||||
let domain = document.getElementById('domain').value;
|
||||
let combined = emailId + '@' + domain;
|
||||
let loginIdInput = document.getElementById('loginId');
|
||||
if (loginIdInput) {
|
||||
loginIdInput.value = combined;
|
||||
<script th:fragment="orgUserInfoScript">
|
||||
// 이메일 조합 함수
|
||||
function combineEmail() {
|
||||
let emailId = document.getElementById('userId').value;
|
||||
let domain = document.getElementById('domain').value;
|
||||
let combined = emailId + '@' + domain;
|
||||
let loginIdInput = document.getElementById('loginId');
|
||||
if (loginIdInput) {
|
||||
loginIdInput.value = combined;
|
||||
}
|
||||
}
|
||||
|
||||
function handleEmailValidationResponse(response) {
|
||||
const individualConversionForm = document.getElementById('individualConversionForm');
|
||||
const emailChangeForm = document.getElementById('emailChangeForm');
|
||||
const newUserForm = document.getElementById('newUserForm');
|
||||
const userIdInput = document.getElementById('userId');
|
||||
const domainInput = document.getElementById('domain');
|
||||
const checkButton = document.querySelector('.btn_check_email');
|
||||
const loginIdInput = document.getElementById('loginId');
|
||||
const scenarioInput = document.getElementById('registrationScenario');
|
||||
|
||||
if (response && response.showPopup) {
|
||||
switch (response.popupType) {
|
||||
case "validEmail":
|
||||
case "newUser":
|
||||
// 시나리오 값 설정
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'new';
|
||||
// hidden input이 form의 일부인지 확인
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleEmailValidationResponse(response) {
|
||||
const individualConversionForm = document.getElementById('individualConversionForm');
|
||||
const emailChangeForm = document.getElementById('emailChangeForm');
|
||||
const newUserForm = document.getElementById('newUserForm');
|
||||
const userIdInput = document.getElementById('userId');
|
||||
const domainInput = document.getElementById('domain');
|
||||
const checkButton = document.querySelector('.btn_check_email');
|
||||
const loginIdInput = document.getElementById('loginId');
|
||||
const scenarioInput = document.getElementById('registrationScenario');
|
||||
customPopups.showAlert(response.message);
|
||||
|
||||
if (response && response.showPopup) {
|
||||
switch (response.popupType) {
|
||||
case "validEmail":
|
||||
case "newUser":
|
||||
// 시나리오 값 설정
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'new';
|
||||
// hidden input이 form의 일부인지 확인
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
|
||||
customPopups.showAlert(response.message);
|
||||
if (userIdInput && domainInput && loginIdInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
const combinedEmail = `${userIdInput.value.trim()}@${domainInput.value.trim()}`;
|
||||
loginIdInput.value = combinedEmail;
|
||||
}
|
||||
|
||||
if (userIdInput && domainInput && loginIdInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
if (newUserForm) newUserForm.style.display = 'block';
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'none';
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'none';
|
||||
break;
|
||||
|
||||
const combinedEmail = `${userIdInput.value.trim()}@${domainInput.value.trim()}`;
|
||||
loginIdInput.value = combinedEmail;
|
||||
}
|
||||
|
||||
if (newUserForm) newUserForm.style.display = 'block';
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'none';
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'none';
|
||||
break;
|
||||
|
||||
case "conversionOrChange":
|
||||
customPopups.showEmailValidationPopup(
|
||||
response.message,
|
||||
function () {
|
||||
// "이메일 유지" 선택 시 동작
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'retain';
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'block';
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'none';
|
||||
if (newUserForm) newUserForm.style.display = 'none';
|
||||
|
||||
if (userIdInput && domainInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
}
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
},
|
||||
function () {
|
||||
// "이메일 전환" 선택 시 동작
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'change';
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'block';
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'none';
|
||||
if (newUserForm) newUserForm.style.display = 'none';
|
||||
|
||||
if (userIdInput && domainInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
}
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case "error":
|
||||
customPopups.showAlert(response.message);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error('알 수 없는 팝업 유형:', response.popupType);
|
||||
break;
|
||||
case "conversionOrChange":
|
||||
customPopups.showEmailValidationPopup(
|
||||
response.message,
|
||||
function () {
|
||||
// "이메일 유지" 선택 시 동작
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'retain';
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
} else if (response && response.message) {
|
||||
customPopups.showAlert(response.message);
|
||||
} else {
|
||||
customPopups.showAlert('알 수 없는 오류가 발생했습니다.');
|
||||
}
|
||||
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'block';
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'none';
|
||||
if (newUserForm) newUserForm.style.display = 'none';
|
||||
|
||||
if (userIdInput && domainInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
}
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
},
|
||||
function () {
|
||||
// "이메일 전환" 선택 시 동작
|
||||
if (scenarioInput) {
|
||||
scenarioInput.value = 'change';
|
||||
if (!scenarioInput.form) {
|
||||
document.getElementById('registerForm').appendChild(scenarioInput);
|
||||
}
|
||||
}
|
||||
|
||||
if (emailChangeForm) emailChangeForm.style.display = 'block';
|
||||
if (individualConversionForm) individualConversionForm.style.display = 'none';
|
||||
if (newUserForm) newUserForm.style.display = 'none';
|
||||
|
||||
if (userIdInput && domainInput) {
|
||||
userIdInput.disabled = true;
|
||||
domainInput.disabled = true;
|
||||
userIdInput.style.backgroundColor = '#e0e0e0';
|
||||
domainInput.style.backgroundColor = '#e0e0e0';
|
||||
}
|
||||
|
||||
if (checkButton) {
|
||||
checkButton.style.display = 'none';
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case "error":
|
||||
customPopups.showAlert(response.message);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error('알 수 없는 팝업 유형:', response.popupType);
|
||||
break;
|
||||
}
|
||||
} else if (response && response.message) {
|
||||
customPopups.showAlert(response.message);
|
||||
} else {
|
||||
customPopups.showAlert('알 수 없는 오류가 발생했습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
// 이메일 입력 필드에 이벤트 리스너 추가
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let userIdInput = document.getElementById("userId");
|
||||
let domainInput = document.getElementById("domain");
|
||||
if (userIdInput) userIdInput.addEventListener("input", combineEmail);
|
||||
if (domainInput) domainInput.addEventListener("input", combineEmail);
|
||||
// Email check button click handler
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let userIdInput = document.getElementById("userId");
|
||||
let domainInput = document.getElementById("domain");
|
||||
const checkButton = document.querySelector('.btn_check_email');
|
||||
|
||||
if (userIdInput) userIdInput.addEventListener("input", combineEmail);
|
||||
if (domainInput) domainInput.addEventListener("input", combineEmail);
|
||||
|
||||
// Email check button with AJAX
|
||||
if (checkButton) {
|
||||
checkButton.addEventListener('click', function() {
|
||||
const loginId = document.getElementById('loginId').value;
|
||||
const registrationType = document.querySelector('input[name="registrationType"]').value;
|
||||
|
||||
if (!loginId || loginId.indexOf('@') === -1) {
|
||||
customPopups.showAlert('이메일 주소를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const csrfToken = document.querySelector('input[name="_csrf"]')?.value;
|
||||
|
||||
// Show loading
|
||||
document.getElementById('loadingOverlay')?.classList.add('active');
|
||||
|
||||
$.ajax({
|
||||
url: '/check_id',
|
||||
type: 'POST',
|
||||
data: {
|
||||
loginId: loginId,
|
||||
registrationType: registrationType,
|
||||
_csrf: csrfToken
|
||||
},
|
||||
success: function(response) {
|
||||
document.getElementById('loadingOverlay')?.classList.remove('active');
|
||||
handleEmailValidationResponse(response);
|
||||
},
|
||||
error: function() {
|
||||
document.getElementById('loadingOverlay')?.classList.remove('active');
|
||||
customPopups.showAlert('서버 오류가 발생했습니다. 다시 시도해주세요.');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</script>
|
||||
</th:block>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,501 +1,515 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout/kbank_base_layout}">
|
||||
layout:decorate="~{layout/kjbank_signup_layout}">
|
||||
<body>
|
||||
<section layout:fragment="contentFragment" class="content">
|
||||
<script th:src="@{/js/htmx.min.js}"></script>
|
||||
<div class="content_wrap">
|
||||
<div class="sub_title2">
|
||||
<h2 class="title add">법인회원가입</h2>
|
||||
</div>
|
||||
<div class="inner i_cs h_inner2">
|
||||
<!-- 약관동의 섹션 -->
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
<input type="hidden" name="registrationType" th:value="${registrationType}"/>
|
||||
<th:block
|
||||
th:replace="~{apps/register/userAgreementContent :: agreementContent(${termsOfUse}, ${privacyCollect})}"></th:block>
|
||||
|
||||
<form name="portalOrg" id="registerForm" role="form" th:action="@{/signup/portalOrg}"
|
||||
th:object="${portalOrg}" method="post">
|
||||
<!-- 법인 기본 정보 -->
|
||||
<div class="terms_box">
|
||||
<p>법인 기본 정보</p>
|
||||
<span class="dot">필수 입력</span>
|
||||
</div>
|
||||
<div class="form_type">
|
||||
<th:block th:replace="~{apps/register/components/orgBasicInfoForm :: orgInfoForm}"></th:block>
|
||||
</div>
|
||||
|
||||
<!-- 기본 관리자 정보 -->
|
||||
<div class="terms_box">
|
||||
<p>법인 관리자 정보</p>
|
||||
<span class="dot">필수 입력</span>
|
||||
</div>
|
||||
<div class="top_info mtb12">
|
||||
<ul>
|
||||
<li>법인관리자는 API 신청 및 이용자 초대 등 모든 권한을 보유합니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form_type" th:if="${registrationType == 'corporate'}">
|
||||
<th:block th:replace="~{apps/register/components/orgUserInfoForm :: orgUserInfoForm}"></th:block>
|
||||
</div>
|
||||
|
||||
<!-- 가입 버튼 -->
|
||||
<div class="form_type">
|
||||
<div class="btn_application">
|
||||
<a type="button" class="common_btn_type_1 gray" id="cancelButton"><span>취소</span></a>
|
||||
<div class="btn_gap"></div>
|
||||
<a type="button" class="common_btn_type_1 btn_register"><span>가입신청</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<section layout:fragment="title">
|
||||
<div class="org-page-title-banner">
|
||||
<img th:src="@{/img/user_register_title.png}" alt="법인회원가입" class="title-image">
|
||||
<h1>법인회원가입</h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
|
||||
|
||||
<div class="org-register-page">
|
||||
<!-- Page Title Banner -->
|
||||
|
||||
<div class="org-register-container">
|
||||
<!-- Hidden Fields -->
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
<input type="hidden" name="registrationType" th:value="${registrationType}"/>
|
||||
|
||||
<!-- Alert Container -->
|
||||
<div id="alertContainer"></div>
|
||||
|
||||
<!-- Agreement Section -->
|
||||
<th:block th:replace="~{apps/register/userAgreementContent :: agreementContent(${termsOfUse}, ${privacyCollect})}"></th:block>
|
||||
|
||||
<form name="portalOrg" id="registerForm" role="form" th:action="@{/signup/portalOrg}"
|
||||
th:object="${portalOrg}" method="post">
|
||||
|
||||
<!-- Corporate Basic Information Section -->
|
||||
<div class="org-section-header org-section-header--agreement">
|
||||
<h3>법인 기본 정보</h3>
|
||||
<span class="required-badge">필수 입력</span>
|
||||
</div>
|
||||
<th:block th:replace="~{apps/register/components/orgBasicInfoForm :: orgInfoForm}"></th:block>
|
||||
|
||||
<!-- Corporate Admin Information Section -->
|
||||
<div class="org-section-header" style="margin-top: 48px;">
|
||||
<h3>법인 관리자 정보</h3>
|
||||
<span class="required-badge">필수 입력</span>
|
||||
</div>
|
||||
|
||||
<div class="org-info-notice">
|
||||
<ul>
|
||||
<li>법인관리자는 API 신청 및 이용자 초대 등 모든 권한을 보유합니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div th:if="${registrationType == 'corporate'}">
|
||||
<th:block th:replace="~{apps/register/components/orgUserInfoForm :: orgUserInfoForm}"></th:block>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="org-action-buttons">
|
||||
<button type="button" class="org-btn org-btn-secondary" id="cancelButton">취소</button>
|
||||
<button type="button" class="org-btn org-btn-primary btn_register">가입신청</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div class="org-loading-overlay" id="loadingOverlay">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:if="${error}" th:inline="javascript">
|
||||
$(document).ready(function () {
|
||||
customPopups.showAlert([[${error}]]);
|
||||
<script th:if="${error}" th:inline="javascript">
|
||||
$(document).ready(function () {
|
||||
customPopups.showAlert([[${error}]]);
|
||||
});
|
||||
</script>
|
||||
<script th:replace="~{apps/register/userAgreementContent :: agreementScript}"></script>
|
||||
<script th:replace="~{apps/register/components/orgBasicInfoForm :: orgInfoScript}"></script>
|
||||
<script th:replace="~{apps/register/components/orgUserInfoForm :: orgUserInfoScript}"></script>
|
||||
<script th:replace="~{apps/register/components/emailChangeForm :: emailChangeScript}"></script>
|
||||
<script th:replace="~{apps/register/components/newUserInfoForm :: newUserScript}"></script>
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let form = document.getElementById('registerForm');
|
||||
let agreementForm = document.getElementById('agreementForm');
|
||||
let btn_register = document.querySelector('.btn_register');
|
||||
let isAuthVerified = false;
|
||||
|
||||
// registrationScenario를 hidden input에서 가져오도록 수정
|
||||
let registrationScenario = document.getElementById('registrationScenario')?.value || 'new';
|
||||
|
||||
// hidden input의 값이 변경되면 registrationScenario 변수도 업데이트
|
||||
const scenarioInput = document.getElementById('registrationScenario');
|
||||
if (scenarioInput) {
|
||||
scenarioInput.addEventListener('change', function () {
|
||||
registrationScenario = this.value;
|
||||
console.log('Registration Scenario Updated:', registrationScenario);
|
||||
});
|
||||
</script>
|
||||
<script th:replace="~{apps/register/userAgreementContent :: agreementScript}"></script>
|
||||
<script th:replace="~{apps/register/components/orgBasicInfoForm :: orgInfoScript}"></script>
|
||||
<script th:replace="~{apps/register/components/orgUserInfoForm :: orgUserInfoScript}"></script>
|
||||
<script th:replace="~{apps/register/components/emailChangeForm :: emailChangeScript}"></script>
|
||||
<script th:replace="~{apps/register/components/newUserInfoForm :: newUserScript}"></script>
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
activateSelect();
|
||||
let form = document.getElementById('registerForm');
|
||||
let agreementForm = document.getElementById('agreementForm');
|
||||
let btn_register = document.querySelector('.btn_register');
|
||||
let isAuthVerified = false;
|
||||
|
||||
// registrationScenario를 hidden input에서 가져오도록 수정
|
||||
let registrationScenario = document.getElementById('registrationScenario')?.value || 'new';
|
||||
|
||||
// hidden input의 값이 변경되면 registrationScenario 변수도 업데이트
|
||||
const scenarioInput = document.getElementById('registrationScenario');
|
||||
if (scenarioInput) {
|
||||
scenarioInput.addEventListener('change', function () {
|
||||
registrationScenario = this.value;
|
||||
console.log('Registration Scenario Updated:', registrationScenario);
|
||||
});
|
||||
|
||||
// MutationObserver를 사용하여 값 변경 감지
|
||||
const observer = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (mutation) {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'value') {
|
||||
registrationScenario = scenarioInput.value;
|
||||
console.log('Registration Scenario Updated (from mutation):', registrationScenario);
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe(scenarioInput, {attributes: true});
|
||||
// MutationObserver를 사용하여 값 변경 감지
|
||||
const observer = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (mutation) {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'value') {
|
||||
registrationScenario = scenarioInput.value;
|
||||
console.log('Registration Scenario Updated (from mutation):', registrationScenario);
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe(scenarioInput, {attributes: true});
|
||||
}
|
||||
|
||||
// 시나리오별 필수 필드 정의
|
||||
const requiredFieldsByScenario = {
|
||||
new: {
|
||||
user: ['loginId', 'userName', 'password', 'password2', 'mobileNumber', 'authNumber'],
|
||||
org: ['compRegNo', 'corpRegNo', 'orgName', 'ceoName', 'orgAddr', 'orgSectors', 'orgIndustryType', 'orgPhoneNumber', 'scPhoneNumber', 'serviceName', 'compRegFile', 'files']
|
||||
},
|
||||
retain: {
|
||||
user: ['loginId', 'passwordConfirmIndividual'],
|
||||
org: ['compRegNo', 'corpRegNo', 'orgName', 'ceoName', 'orgAddr', 'orgSectors', 'orgIndustryType', 'orgPhoneNumber', 'scPhoneNumber', 'serviceName', 'compRegFile', 'files']
|
||||
},
|
||||
change: {
|
||||
user: ['loginId', 'passwordConfirmEmailChange', 'newLoginId'],
|
||||
org: ['compRegNo', 'corpRegNo', 'orgName', 'ceoName', 'orgAddr', 'orgSectors', 'orgIndustryType', 'orgPhoneNumber', 'scPhoneNumber', 'serviceName', 'compRegFile', 'files']
|
||||
}
|
||||
};
|
||||
// 시나리오별 필수 필드 정의
|
||||
const requiredFieldsByScenario = {
|
||||
new: {
|
||||
user: ['loginId', 'userName', 'password', 'password2', 'mobileNumber', 'authNumber'],
|
||||
org: ['compRegNo', 'corpRegNo', 'orgName', 'ceoName', 'orgAddr', 'orgSectors', 'orgIndustryType', 'orgPhoneNumber', 'scPhoneNumber', 'serviceName', 'compRegFile', 'files']
|
||||
},
|
||||
retain: {
|
||||
user: ['loginId', 'passwordConfirmIndividual'],
|
||||
org: ['compRegNo', 'corpRegNo', 'orgName', 'ceoName', 'orgAddr', 'orgSectors', 'orgIndustryType', 'orgPhoneNumber', 'scPhoneNumber', 'serviceName', 'compRegFile', 'files']
|
||||
},
|
||||
change: {
|
||||
user: ['loginId', 'passwordConfirmEmailChange', 'newLoginId'],
|
||||
org: ['compRegNo', 'corpRegNo', 'orgName', 'ceoName', 'orgAddr', 'orgSectors', 'orgIndustryType', 'orgPhoneNumber', 'scPhoneNumber', 'serviceName', 'compRegFile', 'files']
|
||||
}
|
||||
};
|
||||
|
||||
// 이메일 유효성 검사 함수
|
||||
function isValidEmail(email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
// 이메일 유효성 검사 함수
|
||||
function isValidEmail(email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
function collectFormData() {
|
||||
const form = document.createElement('form');
|
||||
form.enctype = 'multipart/form-data';
|
||||
form.method = 'POST';
|
||||
form.action = '/signup/portalOrg';
|
||||
form.style.display = 'none';
|
||||
|
||||
const fields = requiredFieldsByScenario[registrationScenario];
|
||||
|
||||
if (!fields) {
|
||||
console.error('Unknown scenario');
|
||||
return form;
|
||||
}
|
||||
|
||||
// 시나리오 값 추가
|
||||
const scenarioInput = document.getElementById('registrationScenario');
|
||||
if (scenarioInput) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'registrationScenario';
|
||||
input.value = scenarioInput.value;
|
||||
form.appendChild(input);
|
||||
} else {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'registrationScenario';
|
||||
input.value = registrationScenario;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
// user와 org 필드를 따로 처리
|
||||
fields.user.forEach(fieldId => {
|
||||
const element = document.getElementById(fieldId);
|
||||
if (element) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = fieldId;
|
||||
input.value = element.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
});
|
||||
|
||||
fields.org.forEach(fieldId => {
|
||||
const element = document.getElementById(fieldId);
|
||||
if (element) {
|
||||
if (element.type === 'file') {
|
||||
const files = element.files;
|
||||
if (files.length > 0) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.name = fieldId;
|
||||
input.files = files;
|
||||
form.appendChild(input);
|
||||
}
|
||||
} else {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = fieldId;
|
||||
input.value = element.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function collectFormData() {
|
||||
const form = document.createElement('form');
|
||||
form.enctype = 'multipart/form-data';
|
||||
form.method = 'POST';
|
||||
form.action = '/signup/portalOrg';
|
||||
form.style.display = 'none';
|
||||
// Add confirmPassword manually based on the scenario
|
||||
if (registrationScenario === 'retain') {
|
||||
const passwordConfirmIndividual = document.getElementById('passwordConfirmIndividual');
|
||||
if (passwordConfirmIndividual) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'confirmPassword';
|
||||
input.value = passwordConfirmIndividual.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
} else if (registrationScenario === 'change') {
|
||||
const passwordConfirmEmailChange = document.getElementById('passwordConfirmEmailChange');
|
||||
if (passwordConfirmEmailChange) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'confirmPassword';
|
||||
input.value = passwordConfirmEmailChange.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
}
|
||||
|
||||
const fields = requiredFieldsByScenario[registrationScenario];
|
||||
// 공통 필드 추가
|
||||
if (document.getElementById('termsOfUse')) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'termsOfUse';
|
||||
input.value = document.getElementById('termsOfUse').checked;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
if (!fields) {
|
||||
console.error('Unknown scenario');
|
||||
return form;
|
||||
}
|
||||
if (document.getElementById('privacyCollect')) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'privacyCollect';
|
||||
input.value = document.getElementById('privacyCollect').checked;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
// 시나리오 값 추가
|
||||
const scenarioInput = document.getElementById('registrationScenario');
|
||||
if (scenarioInput) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'registrationScenario';
|
||||
input.value = scenarioInput.value;
|
||||
form.appendChild(input);
|
||||
} else {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'registrationScenario';
|
||||
input.value = registrationScenario;
|
||||
form.appendChild(input);
|
||||
}
|
||||
// 시스템 필드 추가
|
||||
const csrfToken = document.querySelector('input[name="_csrf"]');
|
||||
if (csrfToken) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = '_csrf';
|
||||
input.value = csrfToken.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
// user와 org 필드를 따로 처리
|
||||
fields.user.forEach(fieldId => {
|
||||
const element = document.getElementById(fieldId);
|
||||
if (element) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = fieldId;
|
||||
input.value = element.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
});
|
||||
const registrationType = document.querySelector('input[name="registrationType"]');
|
||||
if (registrationType) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'registrationType';
|
||||
input.value = registrationType.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
|
||||
fields.org.forEach(fieldId => {
|
||||
const element = document.getElementById(fieldId);
|
||||
if (element) {
|
||||
if (element.type === 'file') {
|
||||
const files = element.files;
|
||||
if (files.length > 0) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.name = fieldId;
|
||||
input.files = files;
|
||||
form.appendChild(input);
|
||||
}
|
||||
} else {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = fieldId;
|
||||
input.value = element.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('Collected Form Data for scenario:',
|
||||
document.getElementById('registrationScenario')?.value || registrationScenario);
|
||||
return form;
|
||||
}
|
||||
|
||||
// Add confirmPassword manually based on the scenario
|
||||
if (registrationScenario === 'retain') {
|
||||
const passwordConfirmIndividual = document.getElementById('passwordConfirmIndividual');
|
||||
if (passwordConfirmIndividual) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'confirmPassword';
|
||||
input.value = passwordConfirmIndividual.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
} else if (registrationScenario === 'change') {
|
||||
const passwordConfirmEmailChange = document.getElementById('passwordConfirmEmailChange');
|
||||
if (passwordConfirmEmailChange) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'confirmPassword';
|
||||
input.value = passwordConfirmEmailChange.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
}
|
||||
// 시나리오별 유효성 검사
|
||||
function validateFormByScenario() {
|
||||
|
||||
// 공통 필드 추가
|
||||
if (document.getElementById('termsOfUse')) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'termsOfUse';
|
||||
input.value = document.getElementById('termsOfUse').checked;
|
||||
form.appendChild(input);
|
||||
}
|
||||
const currentScenario = document.getElementById('registrationScenario')?.value || 'new';
|
||||
console.log('Registration Scenario:', currentScenario);
|
||||
|
||||
if (document.getElementById('privacyCollect')) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'privacyCollect';
|
||||
input.value = document.getElementById('privacyCollect').checked;
|
||||
form.appendChild(input);
|
||||
}
|
||||
if (!currentScenario) {
|
||||
console.log('Unknown scenario');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 시스템 필드 추가
|
||||
const csrfToken = document.querySelector('input[name="_csrf"]');
|
||||
if (csrfToken) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = '_csrf';
|
||||
input.value = csrfToken.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
switch (registrationScenario) {
|
||||
case 'new':
|
||||
const loginIdElement = document.getElementById('loginId');
|
||||
const userNameElement = document.getElementById('userName');
|
||||
|
||||
const registrationType = document.querySelector('input[name="registrationType"]');
|
||||
if (registrationType) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'registrationType';
|
||||
input.value = registrationType.value;
|
||||
form.appendChild(input);
|
||||
}
|
||||
const isEmailValid = loginIdElement ? isValidEmail(loginIdElement.value) : false;
|
||||
const hasUserName = userNameElement ? userNameElement.value.trim() !== '' : false;
|
||||
const isPasswordValid = document.getElementById('isPasswordValid').value.trim() === 'true';
|
||||
const isPasswordMatch = document.getElementById('isPasswordMatch').value.trim() === 'true';
|
||||
|
||||
console.log('Collected Form Data for scenario:',
|
||||
document.getElementById('registrationScenario')?.value || registrationScenario);
|
||||
return form;
|
||||
}
|
||||
console.log('New User Validation:', {
|
||||
email: loginIdElement?.value,
|
||||
isEmailValid,
|
||||
isPasswordValid,
|
||||
isPasswordMatch,
|
||||
userName: userNameElement?.value,
|
||||
hasUserName,
|
||||
isAuthVerified,
|
||||
requiredFields: currentScenario
|
||||
});
|
||||
return isEmailValid && isPasswordValid && isPasswordMatch && hasUserName && isAuthVerified;
|
||||
|
||||
// 시나리오별 유효성 검사
|
||||
function validateFormByScenario() {
|
||||
case 'retain':
|
||||
const passwordConfirmElement = document.getElementById('passwordConfirmIndividual');
|
||||
const hasPassword = passwordConfirmElement ? passwordConfirmElement.value.length >= 8 : false;
|
||||
const retainLoginIdElement = document.getElementById('loginId');
|
||||
|
||||
const currentScenario = document.getElementById('registrationScenario')?.value || 'new';
|
||||
console.log('Registration Scenario:', currentScenario);
|
||||
console.log('Retain User Validation:', {
|
||||
email: retainLoginIdElement?.value,
|
||||
isEmailValid: retainLoginIdElement ? isValidEmail(retainLoginIdElement.value) : false,
|
||||
passwordLength: passwordConfirmElement?.value.length,
|
||||
hasPassword,
|
||||
requiredFields: currentScenario
|
||||
});
|
||||
return retainLoginIdElement && isValidEmail(retainLoginIdElement.value) && hasPassword;
|
||||
|
||||
if (!currentScenario) {
|
||||
console.log('Unknown scenario');
|
||||
return false;
|
||||
}
|
||||
case 'change':
|
||||
const changeLoginIdElement = document.getElementById('loginId');
|
||||
const newLoginIdElement = document.getElementById('newLoginId');
|
||||
const changePasswordElement = document.getElementById('passwordConfirmEmailChange');
|
||||
const hasChangePassword = changePasswordElement ? changePasswordElement.value.length >= 8 : false;
|
||||
|
||||
switch (registrationScenario) {
|
||||
case 'new':
|
||||
const loginIdElement = document.getElementById('loginId');
|
||||
const userNameElement = document.getElementById('userName');
|
||||
console.log('Change Email Validation:', {
|
||||
currentEmail: changeLoginIdElement?.value,
|
||||
newEmail: newLoginIdElement?.value,
|
||||
hasPassword: hasChangePassword,
|
||||
requiredFields: currentScenario
|
||||
});
|
||||
return changeLoginIdElement && newLoginIdElement &&
|
||||
isValidEmail(changeLoginIdElement.value) &&
|
||||
hasChangePassword &&
|
||||
isValidEmail(newLoginIdElement.value);
|
||||
|
||||
const isEmailValid = loginIdElement ? isValidEmail(loginIdElement.value) : false;
|
||||
const hasUserName = userNameElement ? userNameElement.value.trim() !== '' : false;
|
||||
const isPasswordValid = document.getElementById('isPasswordValid').value.trim() === 'true';
|
||||
const isPasswordMatch = document.getElementById('isPasswordMatch').value.trim() === 'true';
|
||||
default:
|
||||
console.log('Unknown scenario');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('New User Validation:', {
|
||||
email: loginIdElement?.value,
|
||||
isEmailValid,
|
||||
isPasswordValid,
|
||||
isPasswordMatch,
|
||||
userName: userNameElement?.value,
|
||||
hasUserName,
|
||||
isAuthVerified,
|
||||
requiredFields: currentScenario
|
||||
});
|
||||
return isEmailValid && isPasswordValid && isPasswordMatch && hasUserName && isAuthVerified;
|
||||
// 공통 필드 유효성 검사
|
||||
function validateCommonFields() {
|
||||
|
||||
case 'retain':
|
||||
const passwordConfirmElement = document.getElementById('passwordConfirmIndividual');
|
||||
const hasPassword = passwordConfirmElement ? passwordConfirmElement.value.length >= 8 : false;
|
||||
const retainLoginIdElement = document.getElementById('loginId');
|
||||
if(!validatePhoneNumber('org') || !validatePhoneNumber('sc')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('Retain User Validation:', {
|
||||
email: retainLoginIdElement?.value,
|
||||
isEmailValid: retainLoginIdElement ? isValidEmail(retainLoginIdElement.value) : false,
|
||||
passwordLength: passwordConfirmElement?.value.length,
|
||||
hasPassword,
|
||||
requiredFields: currentScenario
|
||||
});
|
||||
return retainLoginIdElement && isValidEmail(retainLoginIdElement.value) && hasPassword;
|
||||
const validations = {
|
||||
termsOfUse: $('#termsOfUse').prop('checked'),
|
||||
privacyPolicy: $('#privacyCollect').prop('checked'),
|
||||
compRegNo: $('#compRegNo').val().trim() !== '',
|
||||
corpRegNo: $('#corpRegNo').val().trim() !== '',
|
||||
orgName: $('#orgName').val().trim() !== '',
|
||||
ceoName: $('#ceoName').val().trim() !== '',
|
||||
orgAddr: $('#orgAddr').val().trim() !== '',
|
||||
orgPhoneNumber: $('#orgPhoneNumber').val().trim() !== '',
|
||||
scPhoneNumber: $('#scPhoneNumber').val().trim() !== '',
|
||||
serviceName: $('#serviceName').val().trim() !== '',
|
||||
compRegFile: $('#compRegFile').val().trim() !== ''
|
||||
};
|
||||
|
||||
case 'change':
|
||||
const changeLoginIdElement = document.getElementById('loginId');
|
||||
const newLoginIdElement = document.getElementById('newLoginId');
|
||||
const changePasswordElement = document.getElementById('passwordConfirmEmailChange');
|
||||
const hasChangePassword = changePasswordElement ? changePasswordElement.value.length >= 8 : false;
|
||||
console.log('Common Fields Validation:', validations);
|
||||
return Object.values(validations).every(value => value === true);
|
||||
}
|
||||
|
||||
console.log('Change Email Validation:', {
|
||||
currentEmail: changeLoginIdElement?.value,
|
||||
newEmail: newLoginIdElement?.value,
|
||||
hasPassword: hasChangePassword,
|
||||
requiredFields: currentScenario
|
||||
});
|
||||
return changeLoginIdElement && newLoginIdElement &&
|
||||
isValidEmail(changeLoginIdElement.value) &&
|
||||
hasChangePassword &&
|
||||
isValidEmail(newLoginIdElement.value);
|
||||
// 전체 폼 유효성 검사
|
||||
function validateForm() {
|
||||
const scenarioValidation = validateFormByScenario();
|
||||
const commonValidation = validateCommonFields();
|
||||
|
||||
default:
|
||||
console.log('Unknown scenario');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.log('Form validation result:', {
|
||||
scenarioValidation,
|
||||
commonValidation,
|
||||
registrationScenario
|
||||
});
|
||||
|
||||
// 공통 필드 유효성 검사
|
||||
function validateCommonFields() {
|
||||
return scenarioValidation && commonValidation;
|
||||
}
|
||||
|
||||
if(!validatePhoneNumber('org') || !validatePhoneNumber('sc')) {
|
||||
return false;
|
||||
}
|
||||
let isSubmitting = false;
|
||||
|
||||
const validations = {
|
||||
termsOfUse: $('#termsOfUse').prop('checked'),
|
||||
privacyPolicy: $('#privacyCollect').prop('checked'),
|
||||
compRegNo: $('#compRegNo').val().trim() !== '',
|
||||
corpRegNo: $('#corpRegNo').val().trim() !== '',
|
||||
orgName: $('#orgName').val().trim() !== '',
|
||||
ceoName: $('#ceoName').val().trim() !== '',
|
||||
orgAddr: $('#orgAddr').val().trim() !== '',
|
||||
orgPhoneNumber: $('#orgPhoneNumber').val().trim() !== '',
|
||||
scPhoneNumber: $('#scPhoneNumber').val().trim() !== '',
|
||||
serviceName: $('#serviceName').val().trim() !== '',
|
||||
compRegFile: $('#compRegFile').val().trim() !== ''
|
||||
};
|
||||
// 등록 버튼 클릭 이벤트
|
||||
btn_register.addEventListener('click', function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
console.log('Common Fields Validation:', validations);
|
||||
return Object.values(validations).every(value => value === true);
|
||||
}
|
||||
// Prevent resubmission
|
||||
if (isSubmitting) {
|
||||
console.log('Form is already being submitted...');
|
||||
return;
|
||||
}
|
||||
|
||||
// 전체 폼 유효성 검사
|
||||
function validateForm() {
|
||||
const scenarioValidation = validateFormByScenario();
|
||||
const commonValidation = validateCommonFields();
|
||||
isSubmitting = true;
|
||||
btn_register.disabled = true;
|
||||
|
||||
console.log('Form validation result:', {
|
||||
scenarioValidation,
|
||||
commonValidation,
|
||||
registrationScenario
|
||||
});
|
||||
// Show loading overlay
|
||||
document.getElementById('loadingOverlay').classList.add('active');
|
||||
|
||||
return scenarioValidation && commonValidation;
|
||||
}
|
||||
try {
|
||||
form.classList.add('was-validated');
|
||||
if (agreementForm) {
|
||||
agreementForm.classList.add('was-validated');
|
||||
}
|
||||
|
||||
let isSubmitting = false;
|
||||
console.log('Validating form...');
|
||||
|
||||
// 등록 버튼 클릭 이벤트
|
||||
btn_register.addEventListener('click', function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (validateForm()) {
|
||||
console.log('Form validation passed, collecting form data...');
|
||||
const form = collectFormData();
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
} else {
|
||||
console.log('Form validation failed');
|
||||
|
||||
// Prevent resubmission
|
||||
if (isSubmitting) {
|
||||
console.log('Form is already being submitted...');
|
||||
return;
|
||||
}
|
||||
// 현재 상태 출력
|
||||
const scenarioValidation = validateFormByScenario();
|
||||
const commonValidation = validateCommonFields();
|
||||
|
||||
isSubmitting = true;
|
||||
btn_register.disabled = true;
|
||||
try {
|
||||
form.classList.add('was-validated');
|
||||
if (agreementForm) {
|
||||
agreementForm.classList.add('was-validated');
|
||||
}
|
||||
const isPasswordValid = document.getElementById('isPasswordValid')?.value.trim() === 'true';
|
||||
const isPasswordMatch = document.getElementById('isPasswordMatch')?.value.trim() === 'true';
|
||||
|
||||
console.log('Validating form...');
|
||||
console.log('Validation details:', {
|
||||
scenarioValidation,
|
||||
commonValidation,
|
||||
registrationScenario,
|
||||
isAuthVerified,
|
||||
isPasswordValid,
|
||||
isPasswordMatch
|
||||
});
|
||||
|
||||
if (validateForm()) {
|
||||
console.log('Form validation passed, collecting form data...');
|
||||
const form = collectFormData();
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
} else {
|
||||
console.log('Form validation failed');
|
||||
|
||||
// 현재 상태 출력
|
||||
const scenarioValidation = validateFormByScenario();
|
||||
const commonValidation = validateCommonFields();
|
||||
|
||||
const isPasswordValid = document.getElementById('isPasswordValid').value.trim() === 'true';
|
||||
const isPasswordMatch = document.getElementById('isPasswordMatch').value.trim() === 'true';
|
||||
|
||||
console.log('Validation details:', {
|
||||
scenarioValidation,
|
||||
commonValidation,
|
||||
registrationScenario,
|
||||
isAuthVerified,
|
||||
isPasswordValid,
|
||||
isPasswordMatch
|
||||
});
|
||||
|
||||
let errorMessage = '모든 필수 항목을 입력하고 약관에 동의해주세요.'
|
||||
if (!scenarioValidation) {
|
||||
customPopups.showAlert(errorMessage);
|
||||
}
|
||||
if (!commonValidation) {
|
||||
customPopups.showAlert(errorMessage);
|
||||
}
|
||||
customPopups.showAlert(errorMessage);
|
||||
// Reset submission state since validation failed
|
||||
isSubmitting = false;
|
||||
btn_register.disabled = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Form submission error:', error);
|
||||
// Reset submission state on error
|
||||
isSubmitting = false;
|
||||
btn_register.disabled = false;
|
||||
}
|
||||
let errorMessage = '모든 필수 항목을 입력하고 약관에 동의해주세요.'
|
||||
customPopups.showAlert(errorMessage);
|
||||
|
||||
// Reset submission state since validation failed
|
||||
isSubmitting = false;
|
||||
btn_register.disabled = false;
|
||||
document.getElementById('loadingOverlay').classList.remove('active');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Form submission error:', error);
|
||||
// Reset submission state on error
|
||||
isSubmitting = false;
|
||||
btn_register.disabled = false;
|
||||
document.getElementById('loadingOverlay').classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// 신규 이메일 중복 체크 응답 처리 함수
|
||||
function handleNewEmailValidationResponse(response) {
|
||||
if (response.valid) {
|
||||
customPopups.showAlert(response.message || '신규 이메일 정보입니다.');
|
||||
} else {
|
||||
customPopups.showAlert(response.message || '이미 사용 중인 이메일입니다.');
|
||||
}
|
||||
// 신규 이메일 중복 체크 응답 처리 함수
|
||||
function handleNewEmailValidationResponse(response) {
|
||||
if (response.valid) {
|
||||
customPopups.showAlert(response.message || '신규 이메일 정보입니다.');
|
||||
} else {
|
||||
customPopups.showAlert(response.message || '이미 사용 중인 이메일입니다.');
|
||||
}
|
||||
}
|
||||
|
||||
// HTMX 이벤트 리스너 - 모든 HTMX 응답을 중앙에서 처리
|
||||
document.body.addEventListener('htmx:afterRequest', function (event) {
|
||||
const targetId = event.detail.target.id;
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = JSON.parse(event.detail.xhr.response);
|
||||
} catch (e) {
|
||||
console.error('응답 JSON 파싱 실패:', e);
|
||||
customPopups.showAlert('서버 응답을 처리할 수 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 비밀번호 관련 검증은 컴포넌트의 로직을 따르도록 return
|
||||
if (targetId === 'password-validation' || targetId === 'password-match-validation') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 나머지 요청들에 대해서만 처리
|
||||
if (event.detail.xhr.getResponseHeader('X-Custom-Handler') === 'registration-validation') {
|
||||
if (response && response.message) {
|
||||
customPopups.showAlert(response.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 기존 응답 처리 로직
|
||||
if (targetId === 'email-validation') {
|
||||
handleEmailValidationResponse(response);
|
||||
} else if (targetId === 'new-email-validation') {
|
||||
handleNewEmailValidationResponse(response);
|
||||
}
|
||||
|
||||
// 사업자등록번호와 법인등록번호에 대한 커스텀 이벤트 디스패치
|
||||
if (targetId === 'compRegNo' || targetId === 'corpRegNo') {
|
||||
const customEvent = new CustomEvent('htmxResponse', {
|
||||
detail: {
|
||||
targetId: targetId,
|
||||
response: response
|
||||
}
|
||||
});
|
||||
document.dispatchEvent(customEvent);
|
||||
}
|
||||
});
|
||||
|
||||
// HTMX 이벤트 리스너 - 모든 HTMX 응답을 중앙에서 처리
|
||||
document.body.addEventListener('htmx:afterRequest', function (event) {
|
||||
const targetId = event.detail.target.id;
|
||||
let response;
|
||||
// 커스텀 이벤트 리스너
|
||||
document.addEventListener('htmxResponse', function (event) {
|
||||
const {targetId, response} = event.detail;
|
||||
|
||||
try {
|
||||
response = JSON.parse(event.detail.xhr.response);
|
||||
} catch (e) {
|
||||
console.error('응답 JSON 파싱 실패:', e);
|
||||
customPopups.showAlert('서버 응답을 처리할 수 없습니다.');
|
||||
return;
|
||||
}
|
||||
if (targetId === 'compRegNo') {
|
||||
customPopups.showAlert(response.message || (response.valid ? '유효한 사업자등록번호입니다.' : '유효하지 않은 사업자등록번호입니다.'));
|
||||
} else if (targetId === 'corpRegNo') {
|
||||
customPopups.showAlert(response.message || (response.valid ? '유효한 법인등록번호입니다.' : '유효하지 않은 법인등록번호입니다.'));
|
||||
}
|
||||
});
|
||||
|
||||
// 비밀번호 관련 검증은 컴포넌트의 로직을 따르도록 return
|
||||
if (targetId === 'password-validation' || targetId === 'password-match-validation') {
|
||||
return;
|
||||
}
|
||||
// 인증 완료 이벤트 리스너
|
||||
document.addEventListener('authVerified', function () {
|
||||
isAuthVerified = true;
|
||||
});
|
||||
|
||||
// 나머지 요청들에 대해서만 처리
|
||||
if (event.detail.xhr.getResponseHeader('X-Custom-Handler') === 'registration-validation') {
|
||||
if (response && response.message) {
|
||||
customPopups.showAlert(response.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 기존 응답 처리 로직
|
||||
if (targetId === 'email-validation') {
|
||||
handleEmailValidationResponse(response);
|
||||
} else if (targetId === 'new-email-validation') {
|
||||
handleNewEmailValidationResponse(response);
|
||||
}
|
||||
|
||||
// 사업자등록번호와 법인등록번호에 대한 커스텀 이벤트 디스패치
|
||||
if (targetId === 'compRegNo' || targetId === 'corpRegNo') {
|
||||
const customEvent = new CustomEvent('htmxResponse', {
|
||||
detail: {
|
||||
targetId: targetId,
|
||||
response: response
|
||||
}
|
||||
});
|
||||
document.dispatchEvent(customEvent);
|
||||
}
|
||||
});
|
||||
|
||||
// 커스텀 이벤트 리스너
|
||||
document.addEventListener('htmxResponse', function (event) {
|
||||
const {targetId, response} = event.detail;
|
||||
|
||||
if (targetId === 'compRegNo') {
|
||||
customPopups.showAlert(response.message || (response.valid ? '유효한 사업자등록번호입니다.' : '유효하지 않은 사업자등록번호입니다.'));
|
||||
} else if (targetId === 'corpRegNo') {
|
||||
customPopups.showAlert(response.message || (response.valid ? '유효한 법인등록번호입니다.' : '유효하지 않은 법인등록번호입니다.'));
|
||||
}
|
||||
});
|
||||
|
||||
// 인증 완료 이벤트 리스너
|
||||
document.addEventListener('authVerified', function () {
|
||||
isAuthVerified = true;
|
||||
});
|
||||
|
||||
// 취소 버튼 클릭 시
|
||||
document.getElementById('cancelButton').addEventListener('click', function () {
|
||||
location.href = '/login';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
// 취소 버튼 클릭 시
|
||||
document.getElementById('cancelButton').addEventListener('click', function () {
|
||||
location.href = '/login';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,53 +5,70 @@
|
||||
layout:decorate="~{layout/base_layout}">
|
||||
<body>
|
||||
<th:block th:fragment="agreementContent(termsOfUse, privacyCollect)">
|
||||
<div class="terms_box t_top">
|
||||
<p>약관 동의</p>
|
||||
<!-- Agreement Section Header -->
|
||||
<div class="org-section-header org-section-header--agreement">
|
||||
<h3>약관 동의</h3>
|
||||
<span class="required-badge">필수 동의</span>
|
||||
</div>
|
||||
<form id="agreementForm">
|
||||
<div class="total_wrap">
|
||||
<span class="inp_check b_tit">
|
||||
<input type='checkbox' value='selectall' id="agree_all"/>
|
||||
<label for="agree_all">전체동의</label>
|
||||
</span>
|
||||
<div class="total_type">
|
||||
<div class="suv_ck">
|
||||
<ul>
|
||||
<li>
|
||||
<span class="inp_check s_tit">
|
||||
<input type='checkbox' name='termsOfUse' id="termsOfUse" required/>
|
||||
<label for="termsOfUse">
|
||||
<span>[필수]</span>「API Portal」 서비스 이용약관
|
||||
</label>
|
||||
</span>
|
||||
<a class="toggle-btn" data-target="termsOfUseContent"></a>
|
||||
<div id="termsOfUseContent" class="txt_wrap scrollbar" style="display:none;">
|
||||
<div th:utext="${termsOfUse?.contents ?: '이용약관 내용을 불러올 수 없습니다.'}"></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form id="agreementForm" class="agreement-form">
|
||||
<!-- Agree All Checkbox -->
|
||||
<div class="agreement-all-section">
|
||||
<label class="agreement-checkbox-label">
|
||||
<input type="checkbox" id="agree_all" class="agreement-checkbox-input">
|
||||
<span class="agreement-checkbox-custom"></span>
|
||||
<span class="agreement-checkbox-text agreement-all-text">전체동의</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Divider -->
|
||||
<div class="agreement-divider"></div>
|
||||
|
||||
<!-- Individual Agreements -->
|
||||
<div class="agreement-items-list">
|
||||
<!-- Terms of Use -->
|
||||
<div class="agreement-item-row">
|
||||
<label class="agreement-checkbox-label">
|
||||
<input type="checkbox" name="termsOfUse" id="termsOfUse" class="agreement-checkbox-input" required>
|
||||
<span class="agreement-checkbox-custom"></span>
|
||||
<span class="agreement-checkbox-text">
|
||||
<span class="agreement-required">[필수]</span>
|
||||
<span class="agreement-title">이용약관 동의</span>
|
||||
</span>
|
||||
</label>
|
||||
<button type="button" class="agreement-toggle-icon" data-target="termsOfUseContent">
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="termsOfUseContent" class="agreement-content" style="display:none;">
|
||||
<div class="agreement-scroll">
|
||||
<div th:utext="${termsOfUse?.contents ?: '이용약관 내용을 불러올 수 없습니다.'}"></div>
|
||||
</div>
|
||||
<!-- 개인정보수집동의서 추가 -->
|
||||
<div class="suv_ck">
|
||||
<ul>
|
||||
<li>
|
||||
<span class="inp_check s_tit">
|
||||
<input type='checkbox' name='privacyCollect' id="privacyCollect" required/>
|
||||
<th:block th:switch="${registrationType}">
|
||||
<label for="privacyCollect" th:case="'personal'">
|
||||
<span>[필수]</span> Kbank API Portal 회원가입을 위한 개인정보 수집•이용 동의서 (개인회원용)
|
||||
</label>
|
||||
<label for="privacyCollect" th:case="'corporate'">
|
||||
<span>[필수]</span> Kbank API Portal 회원가입을 위한 개인정보 수집•이용 동의서 (법인회원용)
|
||||
</label>
|
||||
</th:block>
|
||||
</span>
|
||||
<a class="toggle-btn" data-target="privacyCollectContent"></a>
|
||||
<div id="privacyCollectContent" class="txt_wrap scrollbar" style="display:none;">
|
||||
<div th:utext="${privacyCollect?.contents ?: '개인정보수집동의서 내용을 불러올 수 없습니다.'}"></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Privacy Policy -->
|
||||
<div class="agreement-item-row">
|
||||
<label class="agreement-checkbox-label">
|
||||
<input type="checkbox" name="privacyCollect" id="privacyCollect" class="agreement-checkbox-input" required>
|
||||
<span class="agreement-checkbox-custom"></span>
|
||||
<th:block th:switch="${registrationType}">
|
||||
<span class="agreement-checkbox-text" th:case="'personal'">
|
||||
<span class="agreement-required">[필수]</span>
|
||||
<span class="agreement-title">개인정보 수집 및 이용 동의</span>
|
||||
</span>
|
||||
<span class="agreement-checkbox-text" th:case="'corporate'">
|
||||
<span class="agreement-required">[필수]</span>
|
||||
<span class="agreement-title">개인정보 수집 및 이용 동의</span>
|
||||
</span>
|
||||
</th:block>
|
||||
</label>
|
||||
<button type="button" class="agreement-toggle-icon" data-target="privacyCollectContent">
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="privacyCollectContent" class="agreement-content" style="display:none;">
|
||||
<div class="agreement-scroll">
|
||||
<div th:utext="${privacyCollect?.contents ?: '개인정보수집동의서 내용을 불러올 수 없습니다.'}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,49 +78,56 @@
|
||||
<script th:fragment="agreementScript">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const agreeAll = document.getElementById('agree_all');
|
||||
const agreementChecks = document.querySelectorAll('.inp_check.s_tit input[type="checkbox"]');
|
||||
const toggleBtns = document.querySelectorAll('.toggle-btn');
|
||||
const agreementChecks = document.querySelectorAll('.agreement-checkbox-input[required]');
|
||||
const toggleIcons = document.querySelectorAll('.agreement-toggle-icon');
|
||||
|
||||
// 전체 동의 체크박스 이벤트
|
||||
agreeAll.addEventListener('change', function () {
|
||||
agreementChecks.forEach(check => {
|
||||
check.checked = this.checked;
|
||||
if (agreeAll) {
|
||||
agreeAll.addEventListener('change', function () {
|
||||
agreementChecks.forEach(check => {
|
||||
check.checked = this.checked;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 개별 체크박스 이벤트
|
||||
agreementChecks.forEach(check => {
|
||||
check.addEventListener('change', function () {
|
||||
agreeAll.checked = Array.from(agreementChecks).every(c => c.checked);
|
||||
if (agreeAll) {
|
||||
agreeAll.checked = Array.from(agreementChecks).every(c => c.checked);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 토글 버튼 이벤트
|
||||
toggleBtns.forEach(btn => {
|
||||
btn.addEventListener('click', function (e) {
|
||||
// 토글 아이콘 이벤트
|
||||
toggleIcons.forEach(icon => {
|
||||
icon.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const targetId = this.getAttribute('data-target');
|
||||
const targetContent = document.getElementById(targetId);
|
||||
const parentSection = this.closest('.suv_ck');
|
||||
const parentRow = this.closest('.agreement-item-row');
|
||||
|
||||
// 현재 섹션이 이미 열려있는지 확인
|
||||
const isCurrentlyOpen = targetContent.style.display === 'block';
|
||||
|
||||
document.querySelectorAll('.txt_wrap').forEach(content => {
|
||||
// 모든 섹션 닫기
|
||||
document.querySelectorAll('.agreement-content').forEach(content => {
|
||||
content.style.display = 'none';
|
||||
});
|
||||
document.querySelectorAll('.toggle-btn').forEach(button => {
|
||||
document.querySelectorAll('.agreement-toggle-icon').forEach(button => {
|
||||
button.classList.remove('active');
|
||||
});
|
||||
document.querySelectorAll('.suv_ck').forEach(section => {
|
||||
section.classList.remove('active');
|
||||
document.querySelectorAll('.agreement-item-row').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
|
||||
// 현재 섹션이 닫혀있었다면 열기
|
||||
if (!isCurrentlyOpen) {
|
||||
targetContent.style.display = 'block';
|
||||
this.classList.add('active');
|
||||
parentSection.classList.add('active');
|
||||
if (parentRow) {
|
||||
parentRow.classList.add('active');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
targetContent.scrollIntoView({
|
||||
|
||||
@@ -1,65 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout/kbank_base_layout}">
|
||||
layout:decorate="~{layout/kjbank_signup_layout}">
|
||||
<body>
|
||||
<section layout:fragment="contentFragment" class="content">
|
||||
<script th:src="@{/js/htmx.min.js}"></script>
|
||||
<div class="content_wrap">
|
||||
<div class="sub_title2">
|
||||
<h2 class="title add" th:if="${!isInvited}">개인회원가입</h2>
|
||||
<h2 class="title add" th:if="${isInvited}">법인회원가입</h2>
|
||||
</div>
|
||||
<div class="inner i_cs h_inner2">
|
||||
<div class="top_info" th:if="${!isInvited}">
|
||||
<ul>
|
||||
<li>서비스 또는 API 사용을 원하실 경우 법인회원 승인 후 이용하실 수 있습니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 약관동의 섹션 -->
|
||||
<input type="hidden" id="csrf" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
<th:block th:replace="~{apps/register/userAgreementContent :: agreementContent(${termsOfUse}, ${privacyCollect})}"></th:block>
|
||||
<!-- 기본 정보 입력 섹션 -->
|
||||
<form name="portalUser" id="registerForm" role="form" th:action="@{/signup/portalUser}"
|
||||
th:object="${portalUser}" method="post">
|
||||
<!-- 법인 정보 섹션, 초대받은 경우에만 -->
|
||||
<div class="terms_box" th:if="${isInvited}">
|
||||
<p>법인 정보</p>
|
||||
</div>
|
||||
<section layout:fragment="title">
|
||||
<div class="org-page-title-banner">
|
||||
<img th:src="@{/img/user_register_title.png}" alt="개인회원가입" class="title-image">
|
||||
<h1 th:text="${!isInvited ? '개인회원가입' : '법인회원가입'}">개인회원가입</h1>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="form_type" th:if="${isInvited}">
|
||||
<div class="info1">
|
||||
<p class="title w_tit">
|
||||
<span>법인명</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1 w_inp4">
|
||||
<input type="text" name="companyName" class="common_input_type_1"
|
||||
th:classappend="${isInvited ? 'input-readonly' : ''}" th:value="${orgName}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end 법인 정보 섹션, 초대받은 경우에만 -->
|
||||
<div class="terms_box">
|
||||
<p>기본 정보</p>
|
||||
<span class="dot">필수 입력란입니다</span>
|
||||
</div>
|
||||
<div class="form_type" th:if="${registrationType == isInvited ? 'corporate' :'personal'}">
|
||||
<th:block th:replace="~{apps/register/components/commonUserInfoForm :: commonUserInfo}"></th:block>
|
||||
<th:block th:replace="~{apps/register/components/newUserInfoForm :: newUserForm}"></th:block>
|
||||
</div>
|
||||
<div class="form_type">
|
||||
<div class="btn_application">
|
||||
<a type="button" class="common_btn_type_1 gray" id="cancelButton"><span>취소</span></a>
|
||||
<div class="btn_gap"></div>
|
||||
<a type="button" class="common_btn_type_1 btn_register"><span>가입신청</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<section layout:fragment="contentFragment">
|
||||
<div class="org-register-page">
|
||||
<div class="org-register-container">
|
||||
<!-- Hidden Fields -->
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
<input type="hidden" name="registrationType" th:value="${registrationType}"/>
|
||||
|
||||
<!-- Alert Container -->
|
||||
<div id="alertContainer"></div>
|
||||
|
||||
<!-- Info Notice -->
|
||||
<div class="org-info-notice" th:if="${!isInvited}">
|
||||
<ul>
|
||||
<li>서비스 또는 API 사용을 원하실 경우 법인회원 승인 후 이용하실 수 있습니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Agreement Section -->
|
||||
<th:block th:replace="~{apps/register/userAgreementContent :: agreementContent(${termsOfUse}, ${privacyCollect})}"></th:block>
|
||||
|
||||
<form name="portalUser" id="registerForm" role="form" th:action="@{/signup/portalUser}"
|
||||
th:object="${portalUser}" method="post">
|
||||
|
||||
<!-- Corporate Information Section (invited users only) -->
|
||||
<div th:if="${isInvited}">
|
||||
<div class="org-section-header org-section-header--agreement">
|
||||
<h3>법인 정보</h3>
|
||||
</div>
|
||||
|
||||
<div class="org-form-group">
|
||||
<label class="org-form-label">법인명</label>
|
||||
<div class="org-form-input-wrapper">
|
||||
<input type="text" name="companyName" class="org-form-input" th:value="${orgName}" readonly>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Basic Information Section -->
|
||||
<div class="org-section-header org-section-header--agreement" th:style="${isInvited ? 'margin-top: 48px;' : ''}">
|
||||
<h3>기본 정보</h3>
|
||||
<span class="required-badge">필수 입력</span>
|
||||
</div>
|
||||
|
||||
<div th:if="${registrationType == (isInvited ? 'corporate' : 'personal')}">
|
||||
<th:block th:replace="~{apps/register/components/commonUserInfoForm :: commonUserInfo}"></th:block>
|
||||
<th:block th:replace="~{apps/register/components/newUserInfoForm :: newUserForm}"></th:block>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="org-action-buttons">
|
||||
<button type="button" class="org-btn org-btn-secondary" id="cancelButton">취소</button>
|
||||
<button type="button" class="org-btn org-btn-primary btn_register">가입신청</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div class="org-loading-overlay" id="loadingOverlay">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:if="${error}" th:inline="javascript">
|
||||
@@ -70,128 +81,119 @@
|
||||
<script th:replace="~{apps/register/userAgreementContent :: agreementScript}"></script>
|
||||
<script th:replace="~{apps/register/components/commonUserInfoForm :: commonUserInfoScript}"></script>
|
||||
<script th:replace="~{apps/register/components/newUserInfoForm :: newUserScript}"></script>
|
||||
<script>
|
||||
let form = document.getElementById('registerForm');
|
||||
let agreementForm = document.getElementById('agreementForm');
|
||||
let btn_register = document.querySelector('.btn_register');
|
||||
let isAuthVerified = false;
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let form = document.getElementById('registerForm');
|
||||
let agreementForm = document.getElementById('agreementForm');
|
||||
let btn_register = document.querySelector('.btn_register');
|
||||
let isAuthVerified = false;
|
||||
|
||||
// 인증 완료 이벤트 리스너
|
||||
document.addEventListener('authVerified', function() {
|
||||
isAuthVerified = true;
|
||||
});
|
||||
// 인증 완료 이벤트 리스너
|
||||
document.addEventListener('authVerified', function() {
|
||||
isAuthVerified = true;
|
||||
});
|
||||
|
||||
// 이메일 유효성 검사 함수
|
||||
function isValidEmail(email) {
|
||||
const safeEmailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
||||
return safeEmailRegex.test(email);
|
||||
}
|
||||
|
||||
// 폼 유효성 검사 함수
|
||||
function checkFormValidity() {
|
||||
return isValidEmail($('#loginId').val()) &&
|
||||
($('#password').val() === $('#password2').val()) &&
|
||||
($('#userName').val().trim() !== '') &&
|
||||
$('#termsOfUse').prop('checked') &&
|
||||
$('#privacyCollect').prop('checked') &&
|
||||
(combineMobileNumber('#mobileNumber') !== null) &&
|
||||
isAuthVerified; // 인증 여부 확인
|
||||
}
|
||||
|
||||
let isSubmitting = false;
|
||||
|
||||
// 등록 버튼 클릭 이벤트
|
||||
btn_register.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Prevent resubmission
|
||||
if (isSubmitting) {
|
||||
console.log('Form is already being submitted...');
|
||||
return;
|
||||
// 이메일 유효성 검사 함수
|
||||
function isValidEmail(email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
isSubmitting = true;
|
||||
btn_register.disabled = true;
|
||||
// 폼 유효성 검사 함수
|
||||
function checkFormValidity() {
|
||||
const loginIdElement = $('#loginId');
|
||||
const userNameElement = $('#userName');
|
||||
const termsOfUseElement = $('#termsOfUse');
|
||||
const privacyCollectElement = $('#privacyCollect');
|
||||
const mobileNumberElement = $('#mobileNumber');
|
||||
const isPasswordValid = $('#isPasswordValid').val() === 'true';
|
||||
const isPasswordMatch = $('#isPasswordMatch').val() === 'true';
|
||||
|
||||
form.classList.add('was-validated');
|
||||
agreementForm.classList.add('was-validated');
|
||||
return isValidEmail(loginIdElement.val()) &&
|
||||
isPasswordValid &&
|
||||
isPasswordMatch &&
|
||||
userNameElement.val().trim() !== '' &&
|
||||
termsOfUseElement.prop('checked') &&
|
||||
privacyCollectElement.prop('checked') &&
|
||||
mobileNumberElement.val().trim() !== '' &&
|
||||
isAuthVerified;
|
||||
}
|
||||
|
||||
if (checkFormValidity() && form.checkValidity() && agreementForm.checkValidity()) {
|
||||
// 약관 동의 폼의 데이터를 hidden input으로 추가
|
||||
let agreementFormData = new FormData(agreementForm);
|
||||
for (let pair of agreementFormData.entries()) {
|
||||
if (!form.querySelector('input[name="' + pair[0] + '"]')) {
|
||||
let input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = pair[0];
|
||||
input.value = pair[1];
|
||||
form.appendChild(input);
|
||||
}
|
||||
let isSubmitting = false;
|
||||
|
||||
// 등록 버튼 클릭 이벤트
|
||||
btn_register.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Prevent resubmission
|
||||
if (isSubmitting) {
|
||||
console.log('Form is already being submitted...');
|
||||
return;
|
||||
}
|
||||
|
||||
// 불필요한 hidden input 제거
|
||||
const unnecessaryFields = ['isPasswordValid', 'isPasswordMatch'];
|
||||
unnecessaryFields.forEach(fieldName => {
|
||||
const field = form.querySelector(`input[name="${fieldName}"]`);
|
||||
if (field) {
|
||||
field.remove();
|
||||
isSubmitting = true;
|
||||
btn_register.disabled = true;
|
||||
|
||||
// Show loading overlay
|
||||
document.getElementById('loadingOverlay').classList.add('active');
|
||||
|
||||
try {
|
||||
form.classList.add('was-validated');
|
||||
if (agreementForm) {
|
||||
agreementForm.classList.add('was-validated');
|
||||
}
|
||||
});
|
||||
|
||||
// authCompletedYn 값 설정
|
||||
const authCompletedField = document.createElement('input');
|
||||
authCompletedField.type = 'hidden';
|
||||
authCompletedField.name = 'authCompletedYn';
|
||||
authCompletedField.value = isAuthVerified ? 'Y' : 'N';
|
||||
form.appendChild(authCompletedField);
|
||||
if (checkFormValidity() && form.checkValidity() && (agreementForm ? agreementForm.checkValidity() : true)) {
|
||||
// 약관 동의 폼의 데이터를 hidden input으로 추가
|
||||
if (agreementForm) {
|
||||
let agreementFormData = new FormData(agreementForm);
|
||||
for (let pair of agreementFormData.entries()) {
|
||||
if (!form.querySelector('input[name="' + pair[0] + '"]')) {
|
||||
let input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = pair[0];
|
||||
input.value = pair[1];
|
||||
form.appendChild(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form.submit();
|
||||
} else {
|
||||
customPopups.showAlert('모든 필수 항목을 입력하고 약관에 동의해주세요.');
|
||||
isSubmitting = false;
|
||||
btn_register.disabled = false;
|
||||
}
|
||||
});
|
||||
// 불필요한 hidden input 제거
|
||||
const unnecessaryFields = ['isPasswordValid', 'isPasswordMatch'];
|
||||
unnecessaryFields.forEach(fieldName => {
|
||||
const field = form.querySelector(`input[name="${fieldName}"]`);
|
||||
if (field) {
|
||||
field.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// 취소버튼 클릭시
|
||||
document.getElementById('cancelButton').addEventListener('click', function() {
|
||||
location.href = '/login';
|
||||
});
|
||||
// authCompletedYn 값 설정
|
||||
const authCompletedField = document.createElement('input');
|
||||
authCompletedField.type = 'hidden';
|
||||
authCompletedField.name = 'authCompletedYn';
|
||||
authCompletedField.value = isAuthVerified ? 'Y' : 'N';
|
||||
form.appendChild(authCompletedField);
|
||||
|
||||
// HTMX 이벤트 리스너 - 모든 HTMX 응답을 중앙에서 처리
|
||||
document.body.addEventListener('htmx:afterRequest', function(event) {
|
||||
const targetId = event.detail.target.id;
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = JSON.parse(event.detail.xhr.response);
|
||||
} catch (e) {
|
||||
console.error('응답 JSON 파싱 실패:', e);
|
||||
customPopups.showAlert('서버 응답을 처리할 수 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 커스텀 헤더를 체크하여 등록 검증 요청 처리
|
||||
if (event.detail.xhr.getResponseHeader('X-Custom-Handler') === 'registration-validation') {
|
||||
if (response && response.message) {
|
||||
if (response.status === 'SUCCESS') {
|
||||
customPopups.showSuccess(response.message);
|
||||
form.submit();
|
||||
} else {
|
||||
customPopups.showAlert(response.message);
|
||||
customPopups.showAlert('모든 필수 항목을 입력하고 약관에 동의해주세요.');
|
||||
isSubmitting = false;
|
||||
btn_register.disabled = false;
|
||||
document.getElementById('loadingOverlay').classList.remove('active');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Form submission error:', error);
|
||||
isSubmitting = false;
|
||||
btn_register.disabled = false;
|
||||
document.getElementById('loadingOverlay').classList.remove('active');
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// 응답 처리 로직
|
||||
if (targetId === 'email-validation') {
|
||||
// commonUserInfoForm의 함수 호출
|
||||
handleEmailValidationResponse(response);
|
||||
} else if (targetId === 'password-validation' || targetId === 'password-match-validation') {
|
||||
// 비밀번호 검증은 컴포넌트에서 처리하도록 함
|
||||
return;
|
||||
}
|
||||
// 취소 버튼 클릭 시
|
||||
document.getElementById('cancelButton').addEventListener('click', function() {
|
||||
location.href = '/login';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head th:replace="fragment/kjbank/head :: headFragment">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:replace="fragment/kjbank/header_container :: headerFragment"></th:block>
|
||||
<th:block th:replace="fragment/kjbank/header_container :: headerScript"></th:block>
|
||||
<div class="loading-overlay" style="display: none;">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
<th:block layout:fragment="title">
|
||||
</th:block>
|
||||
<div class="container">
|
||||
<th:block layout:fragment="contentFragment">
|
||||
</th:block>
|
||||
</div>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
</th:block>
|
||||
|
||||
<footer th:replace="fragment/kjbank/footer :: footerFragment"></footer>
|
||||
<section th:replace="fragment/popup/customPopups :: customPopups"></section>
|
||||
<section layout:fragment="pagePopups"></section>
|
||||
<script th:src="@{/js/popup/custom-popups.js}"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user