법인 회원 초대 대응
This commit is contained in:
@@ -70,6 +70,13 @@
|
||||
<img th:src="@{/img/icon/icon_login_join.png}" alt="">
|
||||
<a th:href="@{/signup}">회원가입</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>|</span>
|
||||
</li>
|
||||
<li class="icon_join">
|
||||
<img th:src="@{/img/icon/icon_login_join.png}" alt="">
|
||||
<a th:href="@{/signup/invitation-code}">초대를 받으셨나요?</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="login_list m-only">
|
||||
@@ -89,6 +96,12 @@
|
||||
<li class="icon_join">
|
||||
<a th:href="@{/signup}">회원가입</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>|</span>
|
||||
</li>
|
||||
<li class="icon_join">
|
||||
<a th:href="@{/signup/invitation-code}">초대를 받으셨나요?</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div th:if="${param.logout}" class="alert alert-info mt-3">
|
||||
|
||||
@@ -9,6 +9,21 @@
|
||||
<h2 class="title">내 정보 관리</h2>
|
||||
</div>
|
||||
|
||||
<!-- 초대 알림 배너 -->
|
||||
<div th:if="${hasPendingInvitation}" class="invitation_alert_banner" style="background-color: #f0f8ff; border: 1px solid #2196F3; border-radius: 4px; padding: 15px 20px; margin: 20px 0;">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between;">
|
||||
<div>
|
||||
<strong style="color: #1976D2;">법인 회원 초대가 대기 중입니다</strong>
|
||||
<p style="margin: 5px 0 0 0; color: #666;">기관에서 귀하를 법인 회원으로 초대했습니다. 초대를 수락하면 해당 기관의 법인 회원으로 전환됩니다.</p>
|
||||
</div>
|
||||
<div>
|
||||
<a th:href="@{/signup/decision(invitation=${invitationToken})}" class="common_btn_type_1 blue" style="white-space: nowrap;">
|
||||
<span>초대 확인</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner i_cs h_inner8">
|
||||
<form id="updateForm" method="post" th:action="@{/mypage/update}" th:object="${user}">
|
||||
<div class="terms_box user_top">
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout/kbank_base_layout}">
|
||||
<body>
|
||||
<section layout:fragment="contentFragment" class="content">
|
||||
<div class="content_wrap">
|
||||
<div class="sub_title2">
|
||||
<h2 class="title add2">초대 코드 입력</h2>
|
||||
</div>
|
||||
<div class="inner i_cs9 h_inner9">
|
||||
<div class="form_type">
|
||||
<div class="con_title">
|
||||
<p>법인 기관으로부터 받으신 8자리 초대 코드를 입력해 주세요.</p>
|
||||
</div>
|
||||
|
||||
<form id="invitationCodeForm" method="post" th:action="@{/signup/invitation-code}">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
|
||||
<div class="form_type_box">
|
||||
<div class="info1 form_top">
|
||||
<p class="title">
|
||||
<span>초대 코드</span>
|
||||
</p>
|
||||
<div class="info_line info_add">
|
||||
<div class="info_box1 add add2">
|
||||
<!-- <input type="text"-->
|
||||
<!-- id="invitationCode"-->
|
||||
<!-- name="invitationCode"-->
|
||||
<!-- class="common_input_type_1 h_inp"-->
|
||||
<!-- placeholder="8자리 초대 코드를 입력해 주세요"-->
|
||||
<!-- maxlength="8"-->
|
||||
<!-- pattern="[A-Z0-9]{8}"-->
|
||||
<!-- title="8자리 영문 대문자와 숫자로 입력해주세요"-->
|
||||
<!-- required-->
|
||||
<!-- style="text-transform: uppercase;">-->
|
||||
<input type="text"
|
||||
id="invitationCode"
|
||||
name="invitationCode"
|
||||
class="common_input_type_1 h_inp"
|
||||
placeholder="8자리 초대 코드를 입력해 주세요"
|
||||
maxlength="8"
|
||||
required
|
||||
style="text-transform: uppercase;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info_txt" style="margin-top: 25px;">
|
||||
<p>※ 초대 코드는 이메일로 전달받으실 수 있습니다.</p>
|
||||
<p>※ 초대 코드는 대소문자를 구분하지 않으며, 8자리 영문자와 숫자로 구성되어 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 에러 메시지 표시 영역 -->
|
||||
<div th:if="${error}" class="error_message" style="color: #d32f2f; margin: 25px 0 15px 0; padding: 10px; background-color: #ffebee; border-radius: 4px;">
|
||||
<p th:text="${error}"></p>
|
||||
</div>
|
||||
|
||||
<!-- 브루트포스 방지: 시도 횟수 표시 -->
|
||||
<div th:if="${attemptsRemaining != null and attemptsRemaining <= 3}"
|
||||
class="warning_message"
|
||||
style="color: #f57c00; margin: 25px 0 15px 0; padding: 10px; background-color: #fff3e0; border-radius: 4px;">
|
||||
<p>남은 시도 횟수: <strong th:text="${attemptsRemaining}"></strong>회</p>
|
||||
<p>5회 실패 시 15분간 입력이 제한됩니다.</p>
|
||||
</div>
|
||||
|
||||
<!-- 브루트포스 방지: 계정 잠금 메시지 -->
|
||||
<div th:if="${lockoutTime != null}"
|
||||
class="error_message"
|
||||
style="color: #d32f2f; margin: 25px 0 15px 0; padding: 10px; background-color: #ffebee; border-radius: 4px;">
|
||||
<p>잘못된 초대 코드를 5회 입력하셨습니다.</p>
|
||||
<p th:text="${lockoutTime} + ' 후에 다시 시도해 주세요.'"></p>
|
||||
</div>
|
||||
|
||||
<div class="btn_login">
|
||||
<button type="submit" class="common_btn_type_1 h_btn" th:disabled="${lockoutTime != null}" style="width: 100%; border: none; cursor: pointer;">
|
||||
<span>확인</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="login_list pc-only" style="margin-top: 20px;">
|
||||
<ul>
|
||||
<li>
|
||||
<a th:href="@{/login}">로그인 페이지로 돌아가기</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>|</span>
|
||||
</li>
|
||||
<li>
|
||||
<a th:href="@{/signup}">회원가입</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="login_list m-only" style="margin-top: 20px;">
|
||||
<ul>
|
||||
<li>
|
||||
<a th:href="@{/login}">로그인 페이지로 돌아가기</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>|</span>
|
||||
</li>
|
||||
<li>
|
||||
<a th:href="@{/signup}">회원가입</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// 초대 코드 입력 필드를 대문자로 자동 변환
|
||||
$('#invitationCode').on('input', function() {
|
||||
this.value = this.value.toUpperCase();
|
||||
});
|
||||
|
||||
// 성공 메시지가 있으면 표시
|
||||
var successMsg = [[${success}]];
|
||||
if (successMsg) {
|
||||
customPopups.showAlert(successMsg);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
</body>
|
||||
</html>
|
||||
@@ -18,7 +18,7 @@
|
||||
<p class="tit_txt">
|
||||
<span th:text="${userName}"></span>님 안녕하세요.<br><br>
|
||||
<span th:text="${orgName}"></span>에서 귀하를 Kbank API Portal 법인회원으로 초대하였습니다.<br>
|
||||
<br> Kbank와 함께 금융서비스를 손쉽게 개발해 보세요.<br><br>
|
||||
<br> 광주은행과 함께 금융서비스를 손쉽게 개발해 보세요.<br><br>
|
||||
로그인 하여 법인회원 전환을 진행하세요.<br>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -67,9 +67,10 @@
|
||||
<td th:text="${user.maskedEmailAddr}">이메일 아이디</td>
|
||||
<td>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>초대 대기 중</td>
|
||||
<td>
|
||||
<div class="btn_wrap btn_set">
|
||||
<a href="#none" class="common_btn_type_4 resend_invitation"><span>재발송</span></a>
|
||||
<a href="#none" class="common_btn_type_4 cancel_invitation"><span>초대취소</span></a>
|
||||
</div>
|
||||
</td>
|
||||
@@ -103,8 +104,10 @@
|
||||
<div class="contents">
|
||||
<p class="con_txt2">추가할 이용자 e-mail 주소를 입력해 주세요.</p>
|
||||
<div class="inp_box">
|
||||
<input type="text" class="common_input_type_1 w_input" id="new_user_email"
|
||||
placeholder="이용자 e-mail 주소">
|
||||
<input type="email" class="common_input_type_1 w_input" id="new_user_email"
|
||||
placeholder="이용자 e-mail 주소"
|
||||
pattern="[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}"
|
||||
title="올바른 이메일 형식을 입력해주세요 (예: user@example.com)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -208,6 +211,13 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 이메일 형식 검증
|
||||
const emailPattern = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/;
|
||||
if (!emailPattern.test(email)) {
|
||||
customPopups.showAlert('올바른 이메일 형식을 입력해주세요. (예: user@example.com)');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/users/invite',
|
||||
type: 'POST',
|
||||
@@ -292,6 +302,7 @@
|
||||
const activateButtons = document.querySelectorAll('.activate_user');
|
||||
const inactivateButtons = document.querySelectorAll('.inactivate_user');
|
||||
const cancelInvitationButtons = document.querySelectorAll('.cancel_invitation');
|
||||
const resendInvitationButtons = document.querySelectorAll('.resend_invitation');
|
||||
|
||||
activateButtons.forEach(button => {
|
||||
button.addEventListener('click', handleUserStatusChange);
|
||||
@@ -305,6 +316,10 @@
|
||||
button.addEventListener('click', handleCancelInvitation);
|
||||
});
|
||||
|
||||
resendInvitationButtons.forEach(button => {
|
||||
button.addEventListener('click', handleResendInvitation);
|
||||
});
|
||||
|
||||
function handleUserStatusChange(event) {
|
||||
const row = event.target.closest('tr');
|
||||
const userId = row.querySelector('a').getAttribute('href').split('=')[1];
|
||||
@@ -361,6 +376,38 @@
|
||||
});
|
||||
}
|
||||
|
||||
function handleResendInvitation(event) {
|
||||
const row = event.target.closest('tr');
|
||||
const userId = row.querySelector('td[data-id]').getAttribute('data-id');
|
||||
const userName = row.querySelector('td:nth-child(3)').textContent;
|
||||
|
||||
customPopups.showConfirm(`${userName}에게 초대를 재발송하시겠습니까?`, function (selection) {
|
||||
if (selection) {
|
||||
$.ajax({
|
||||
url: '/users/resend-invitation',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({id: userId})
|
||||
}).done(function (response) {
|
||||
customPopups.showAlert(response.msg, function () {
|
||||
location.reload(); // Reload the page to reflect changes
|
||||
});
|
||||
}).fail(function (jqXHR, textStatus, errorThrown) {
|
||||
let errorMessage;
|
||||
try {
|
||||
const errorResponse = JSON.parse(jqXHR.responseText);
|
||||
errorMessage = errorResponse.msg || '초대 재발송 중 오류가 발생했습니다';
|
||||
} catch (e) {
|
||||
errorMessage = '초대 재발송 중 오류가 발생했습니다: ' + errorThrown;
|
||||
}
|
||||
customPopups.showAlert(errorMessage);
|
||||
}).always(function () {
|
||||
$('#customConfirm').hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
Reference in New Issue
Block a user