- 초대 로직 변경: 이메일→휴대폰 기반 초대 전환 및 UI 업데이트
- 알림 수신 동의 추가: 초대/취소 시 알림 발송 옵션 탑재 - 관리자 기능 추가: 소속 제외 및 권한 조정 기능 구현
This commit is contained in:
@@ -11,6 +11,13 @@ spring:
|
||||
cachecontrol:
|
||||
max-age: 86400
|
||||
public: true
|
||||
# 정적자원 콘텐츠 해시 버전닝: 운영은 항상 ON (파라미터로 비활성화 불가).
|
||||
# 해시 URL + 장기 캐시(max-age 86400)로 배포 시 자동 캐시 무효화.
|
||||
chain:
|
||||
strategy:
|
||||
content:
|
||||
enabled: true
|
||||
paths: /**
|
||||
jpa:
|
||||
properties:
|
||||
hibernate:
|
||||
|
||||
@@ -33,6 +33,15 @@ spring:
|
||||
max-age: 0
|
||||
must-revalidate: true
|
||||
no-cache: true
|
||||
# 정적자원 콘텐츠 해시 버전닝: /css/main.css -> /css/main-<hash>.css 자동 치환.
|
||||
# 내용이 바뀌면 URL이 바뀌어 강제 새로고침 없이 캐시가 무효화됨.
|
||||
# 비-prod 는 app.resource-versioning.enabled 파라미터로 제어(기본 ON),
|
||||
# false 로 두면 버전닝을 꺼서 sourceMap 디버깅이 가능. (prod 는 application-prod.yml 에서 항상 ON)
|
||||
chain:
|
||||
strategy:
|
||||
content:
|
||||
enabled: ${app.resource-versioning.enabled:true}
|
||||
paths: /**
|
||||
|
||||
jta:
|
||||
enabled: true
|
||||
@@ -49,6 +58,14 @@ spring:
|
||||
cache: false
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
# 정적자원 해시 버전닝 토글 (prod 제외 전 프로파일에 적용).
|
||||
# false 로 변경 시 /css/main.css 가 해시 없이 그대로 서빙되어 sourceMap 디버깅 가능.
|
||||
# prod 는 application-prod.yml 에서 항상 ON 으로 고정되어 이 값을 무시함.
|
||||
app:
|
||||
resource-versioning:
|
||||
enabled: true
|
||||
|
||||
security:
|
||||
basic:
|
||||
enabled: false
|
||||
|
||||
@@ -5739,11 +5739,11 @@ select.form-control {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px 16px;
|
||||
height: 40px;
|
||||
padding: 0 8px;
|
||||
height: 30px;
|
||||
white-space: nowrap;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
color: #000000;
|
||||
border: none;
|
||||
@@ -5776,6 +5776,13 @@ select.form-control {
|
||||
.list-table-btn--secondary:hover {
|
||||
background-color: rgb(187.8846153846, 197.2807692308, 234.8653846154);
|
||||
}
|
||||
.list-table-btn--danger {
|
||||
background-color: #F8D7DA;
|
||||
color: #B02A37;
|
||||
}
|
||||
.list-table-btn--danger:hover {
|
||||
background-color: rgb(244.5521276596, 195.2978723404, 199.7755319149);
|
||||
}
|
||||
|
||||
.table-pagination {
|
||||
display: flex;
|
||||
@@ -16644,16 +16651,15 @@ input[type=checkbox]:checked + .custom-checkbox {
|
||||
|
||||
.user-current-badge {
|
||||
display: inline-flex;
|
||||
height: 40px;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
padding: 0 8px;
|
||||
background-color: rgba(167, 139, 250, 0.1);
|
||||
color: #A78BFA;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
min-width: 116px;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.user-current-badge {
|
||||
@@ -17383,6 +17389,16 @@ input[type=checkbox]:checked + .custom-checkbox {
|
||||
.dropdown-wrapper .dropdown-menu .dropdown-item + .dropdown-item {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.dropdown-wrapper .dropdown-menu .dropdown-item--danger {
|
||||
color: #B02A37;
|
||||
}
|
||||
.dropdown-wrapper .dropdown-menu .dropdown-item--danger:hover {
|
||||
background: #fdeaec;
|
||||
color: #B02A37;
|
||||
}
|
||||
.dropdown-wrapper .dropdown-menu .dropdown-item--danger:active {
|
||||
background: #f8d7da;
|
||||
}
|
||||
.dropdown-wrapper.open .dropdown-toggle {
|
||||
background: rgba(0, 73, 180, 0.1);
|
||||
color: #0049b4;
|
||||
@@ -17845,6 +17861,13 @@ body.commission-print-page .btn-primary:hover {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.terms-empty {
|
||||
padding: 32px 24px;
|
||||
text-align: center;
|
||||
color: #8c959f;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.terms-selector {
|
||||
padding: 24px;
|
||||
background: #F6F9FB;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -364,7 +364,7 @@ const customPopups = {
|
||||
/**
|
||||
* 사용자 초대 팝업 표시
|
||||
* @param {Object} options - 팝업 옵션
|
||||
* @param {Function} options.onConfirm - 확인 버튼 클릭 시 호출되는 콜백 (파라미터: email)
|
||||
* @param {Function} options.onConfirm - 확인 버튼 클릭 시 호출되는 콜백 (파라미터: mobile, notifyConsent)
|
||||
* @param {Function} options.onCancel - 취소 버튼 클릭 시 호출되는 콜백 (선택사항)
|
||||
*/
|
||||
showUserInvite: function (options) {
|
||||
@@ -374,7 +374,8 @@ const customPopups = {
|
||||
const onCancel = options.onCancel;
|
||||
|
||||
// 입력 필드 및 에러 초기화
|
||||
$('#userInviteEmailInput').val('').removeClass('error');
|
||||
$('#userInviteMobileInput').val('').removeClass('error');
|
||||
$('#userInviteNotifyConsent').prop('checked', false);
|
||||
$('#userInvitePopupError').removeClass('show').text('');
|
||||
|
||||
// 팝업 표시 (modal 구조 사용)
|
||||
@@ -389,28 +390,29 @@ const customPopups = {
|
||||
|
||||
// 입력 필드에 포커스
|
||||
setTimeout(function() {
|
||||
$('#userInviteEmailInput').focus();
|
||||
$('#userInviteMobileInput').focus();
|
||||
}, 350);
|
||||
|
||||
// 확인 버튼 이벤트 (기존 이벤트 제거 후 재등록)
|
||||
$('#userInvitePopupConfirmButton').off('click').on('click', function () {
|
||||
const email = $('#userInviteEmailInput').val().trim();
|
||||
const mobile = $('#userInviteMobileInput').val().trim();
|
||||
const notifyConsent = $('#userInviteNotifyConsent').is(':checked');
|
||||
|
||||
// 이메일 유효성 검사
|
||||
if (!email) {
|
||||
customPopups.showUserInviteError('이메일 주소를 입력해주세요.');
|
||||
// 휴대폰 번호 유효성 검사
|
||||
if (!mobile) {
|
||||
customPopups.showUserInviteError('휴대폰 번호를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 이메일 형식 검증
|
||||
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailPattern.test(email)) {
|
||||
customPopups.showUserInviteError('올바른 이메일 형식이 아닙니다.');
|
||||
// 휴대폰 번호 형식 검증 (하이픈 유무 모두 허용)
|
||||
const mobilePattern = /^01[016-9]-?\d{3,4}-?\d{4}$/;
|
||||
if (!mobilePattern.test(mobile)) {
|
||||
customPopups.showUserInviteError('올바른 휴대폰 번호 형식이 아닙니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof onConfirm === 'function') {
|
||||
onConfirm(email);
|
||||
onConfirm(mobile, notifyConsent);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -431,14 +433,14 @@ const customPopups = {
|
||||
});
|
||||
|
||||
// Enter 키 이벤트
|
||||
$('#userInviteEmailInput').off('keypress').on('keypress', function (e) {
|
||||
$('#userInviteMobileInput').off('keypress').on('keypress', function (e) {
|
||||
if (e.which === 13) {
|
||||
$('#userInvitePopupConfirmButton').click();
|
||||
}
|
||||
});
|
||||
|
||||
// 입력 시 에러 초기화
|
||||
$('#userInviteEmailInput').off('input').on('input', function () {
|
||||
$('#userInviteMobileInput').off('input').on('input', function () {
|
||||
customPopups.clearUserInviteError();
|
||||
});
|
||||
},
|
||||
@@ -460,14 +462,15 @@ const customPopups = {
|
||||
$('body').css('overflow', '');
|
||||
|
||||
// 입력 필드 초기화
|
||||
$('#userInviteEmailInput').val('').removeClass('error');
|
||||
$('#userInviteMobileInput').val('').removeClass('error');
|
||||
$('#userInviteNotifyConsent').prop('checked', false);
|
||||
$('#userInvitePopupError').removeClass('show').text('');
|
||||
|
||||
// 이벤트 리스너 제거
|
||||
$('#userInvitePopupConfirmButton').off('click');
|
||||
$('#userInvitePopupCancelButton').off('click');
|
||||
$('#userInvitePopupCloseButton').off('click');
|
||||
$('#userInviteEmailInput').off('keypress').off('input');
|
||||
$('#userInviteMobileInput').off('keypress').off('input');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -476,7 +479,7 @@ const customPopups = {
|
||||
*/
|
||||
showUserInviteError: function (message) {
|
||||
$('#userInvitePopupError').text(message).addClass('show');
|
||||
$('#userInviteEmailInput').addClass('error');
|
||||
$('#userInviteMobileInput').addClass('error');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -484,7 +487,96 @@ const customPopups = {
|
||||
*/
|
||||
clearUserInviteError: function () {
|
||||
$('#userInvitePopupError').removeClass('show');
|
||||
$('#userInviteEmailInput').removeClass('error');
|
||||
$('#userInviteMobileInput').removeClass('error');
|
||||
},
|
||||
|
||||
/**
|
||||
* 초대취소 팝업 표시 (알림 수신 동의 체크박스 포함)
|
||||
* @param {Object} options - 팝업 옵션
|
||||
* @param {string} options.target - 취소 대상 표시 문자열 (마스킹된 이메일/휴대폰)
|
||||
* @param {Function} options.onConfirm - 확인 버튼 클릭 시 호출되는 콜백 (파라미터: notifyConsent)
|
||||
* @param {Function} options.onCancel - 취소(닫기) 버튼 클릭 시 호출되는 콜백 (선택사항)
|
||||
*/
|
||||
showCancelInvitation: function (options) {
|
||||
options = options || {};
|
||||
|
||||
const target = options.target || '';
|
||||
const onConfirm = options.onConfirm;
|
||||
const onCancel = options.onCancel;
|
||||
|
||||
// 대상 정보 및 체크박스 초기화
|
||||
$('#cancelInvitationTarget').text(target);
|
||||
$('#cancelInvitationNotifyConsent').prop('checked', false);
|
||||
|
||||
// 팝업 표시 (modal 구조 사용)
|
||||
$('#cancelInvitationPopup').show();
|
||||
setTimeout(function() {
|
||||
$('#cancelInvitationModalBackdrop').addClass('show');
|
||||
$('#cancelInvitationModal').addClass('show');
|
||||
}, 10);
|
||||
|
||||
// Body 스크롤 방지
|
||||
$('body').css('overflow', 'hidden');
|
||||
|
||||
// 확인 버튼 이벤트 (기존 이벤트 제거 후 재등록)
|
||||
$('#cancelInvitationPopupConfirmButton').off('click').on('click', function () {
|
||||
const notifyConsent = $('#cancelInvitationNotifyConsent').is(':checked');
|
||||
if (typeof onConfirm === 'function') {
|
||||
onConfirm(notifyConsent);
|
||||
}
|
||||
});
|
||||
|
||||
// 닫기 버튼 이벤트
|
||||
$('#cancelInvitationPopupCancelButton').off('click').on('click', function () {
|
||||
customPopups.hideCancelInvitation();
|
||||
if (typeof onCancel === 'function') {
|
||||
onCancel();
|
||||
}
|
||||
});
|
||||
|
||||
// X 버튼 이벤트
|
||||
$('#cancelInvitationPopupCloseButton').off('click').on('click', function () {
|
||||
customPopups.hideCancelInvitation();
|
||||
if (typeof onCancel === 'function') {
|
||||
onCancel();
|
||||
}
|
||||
});
|
||||
|
||||
// Escape 키 이벤트
|
||||
$(document).off('keydown.cancelInvitation').on('keydown.cancelInvitation', function (e) {
|
||||
if (e.key === 'Escape') {
|
||||
customPopups.hideCancelInvitation();
|
||||
if (typeof onCancel === 'function') {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 초대취소 팝업 숨기기
|
||||
*/
|
||||
hideCancelInvitation: function () {
|
||||
// Modal 숨김 애니메이션
|
||||
$('#cancelInvitationModalBackdrop').removeClass('show');
|
||||
$('#cancelInvitationModal').removeClass('show');
|
||||
|
||||
// 애니메이션 완료 후 숨김
|
||||
setTimeout(function() {
|
||||
$('#cancelInvitationPopup').hide();
|
||||
}, 300);
|
||||
|
||||
// Body 스크롤 복원
|
||||
$('body').css('overflow', '');
|
||||
|
||||
// 체크박스 초기화
|
||||
$('#cancelInvitationNotifyConsent').prop('checked', false);
|
||||
|
||||
// 이벤트 리스너 제거
|
||||
$('#cancelInvitationPopupConfirmButton').off('click');
|
||||
$('#cancelInvitationPopupCancelButton').off('click');
|
||||
$('#cancelInvitationPopupCloseButton').off('click');
|
||||
$(document).off('keydown.cancelInvitation');
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -459,11 +459,11 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $spacing-sm $spacing-md;
|
||||
height: 40px;
|
||||
padding: 0 $spacing-sm;
|
||||
height: 30px;
|
||||
white-space: nowrap;
|
||||
border-radius: $border-radius-md;
|
||||
font-size: $font-size-base;
|
||||
border-radius: $border-radius-sm;
|
||||
font-size: 13px;
|
||||
font-weight: $font-weight-regular;
|
||||
color: #000000;
|
||||
border: none;
|
||||
@@ -504,6 +504,15 @@
|
||||
background-color: darken(#CDD4F0, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
&--danger {
|
||||
background-color: #F8D7DA;
|
||||
color: #B02A37;
|
||||
|
||||
&:hover {
|
||||
background-color: darken(#F8D7DA, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -130,6 +130,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Empty state (해당 약관이 아직 시드되지 않은 경우)
|
||||
.terms-empty {
|
||||
padding: $spacing-xl $spacing-lg;
|
||||
text-align: center;
|
||||
color: #8c959f;
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
|
||||
// Version Selector (Figma: 검색창 986-2208)
|
||||
.terms-selector {
|
||||
padding: $spacing-lg;
|
||||
|
||||
@@ -101,16 +101,15 @@
|
||||
// Current user badge (used in actions column)
|
||||
.user-current-badge {
|
||||
display: inline-flex;
|
||||
height: 40px;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
padding: 0 $spacing-sm;
|
||||
background-color: rgba($accent-purple, 0.1);
|
||||
color: $accent-purple;
|
||||
border-radius: $border-radius-sm;
|
||||
font-size: $font-size-sm;
|
||||
font-size: 13px;
|
||||
font-weight: $font-weight-medium;
|
||||
min-width: 116px;
|
||||
|
||||
// 모바일에서 숨김
|
||||
@media (max-width: $breakpoint-sm) {
|
||||
@@ -1058,6 +1057,19 @@
|
||||
& + .dropdown-item {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
&--danger {
|
||||
color: #B02A37;
|
||||
|
||||
&:hover {
|
||||
background: #fdeaec;
|
||||
color: #B02A37;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #f8d7da;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,16 @@
|
||||
<image id="image0_1130_6799" width="163" height="129" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"/>
|
||||
</defs>
|
||||
</svg>
|
||||
<h2 class="result-title">회원가입 신청이 완료되었습니다.</h2>
|
||||
<h2 class="result-title" th:text="${registrationType == 'corporate'} ? '법인 신청이 완료 되었습니다.' : '회원가입 신청이 완료되었습니다.'">회원가입 신청이 완료되었습니다.</h2>
|
||||
</div>
|
||||
|
||||
<!-- Info Box -->
|
||||
<div class="result-info-box">
|
||||
<p class="info-text">
|
||||
<p class="info-text" th:if="${registrationType == 'corporate'}">
|
||||
관리자의 확인 및 승인 이후<br>
|
||||
이용하실 수 있습니다.
|
||||
</p>
|
||||
<p class="info-text" th:unless="${registrationType == 'corporate'}">
|
||||
API Portal 서비스를 이용하기 위해서<br>
|
||||
<strong>이메일 인증</strong>을 완료해 주세요.
|
||||
</p>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="list-table-header">
|
||||
<div class="header-cell" style="width: 90px;">NO.</div>
|
||||
<div class="header-cell" style="width: 90px;">성명</div>
|
||||
<div class="header-cell" style="flex: 1; min-width: 180px;">이메일 아이디</div>
|
||||
<div class="header-cell" style="flex: 1; min-width: 180px;">이메일 / 휴대폰</div>
|
||||
<div class="header-cell" style="width: 120px;">권한</div>
|
||||
<div class="header-cell" style="width: 120px;">계정상태</div>
|
||||
<div class="header-cell" style="width: 320px;">설정</div>
|
||||
@@ -71,18 +71,24 @@
|
||||
th:data-user-email="${user.maskedEmailAddr}">
|
||||
관리자 권한부여
|
||||
</button>
|
||||
<button type="button" class="list-table-btn list-table-btn--default revoke_manager"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && user.roleCode.toString() == 'ROLE_CORP_MANAGER'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
이용자로 변경
|
||||
</button>
|
||||
<button type="button" class="list-table-btn list-table-btn--danger remove_from_org"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && (user.roleCode.toString() == 'ROLE_CORP_USER' || user.roleCode.toString() == 'ROLE_CORP_MANAGER')}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
소속 제외
|
||||
</button>
|
||||
<button type="button" class="list-table-btn list-table-btn--primary activate_user"
|
||||
th:if="${user.userStatus.toString() != 'ACTIVE'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
활성화
|
||||
</button>
|
||||
<button type="button" class="list-table-btn list-table-btn--primary inactivate_user"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
비활성화
|
||||
</button>
|
||||
<button type="button" class="list-table-btn list-table-btn--secondary cancel_invitation"
|
||||
th:if="${user.userStatus.toString() == 'PENDING'}"
|
||||
th:data-user-id="${user.id}"
|
||||
@@ -108,18 +114,24 @@
|
||||
th:data-user-email="${user.maskedEmailAddr}">
|
||||
관리자 권한부여
|
||||
</button>
|
||||
<button type="button" class="dropdown-item revoke_manager"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && user.roleCode.toString() == 'ROLE_CORP_MANAGER'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
이용자로 변경
|
||||
</button>
|
||||
<button type="button" class="dropdown-item dropdown-item--danger remove_from_org"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && (user.roleCode.toString() == 'ROLE_CORP_USER' || user.roleCode.toString() == 'ROLE_CORP_MANAGER')}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
소속 제외
|
||||
</button>
|
||||
<button type="button" class="dropdown-item activate_user"
|
||||
th:if="${user.userStatus.toString() != 'ACTIVE'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
활성화
|
||||
</button>
|
||||
<button type="button" class="dropdown-item inactivate_user"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
비활성화
|
||||
</button>
|
||||
<button type="button" class="dropdown-item cancel_invitation"
|
||||
th:if="${user.userStatus.toString() == 'PENDING'}"
|
||||
th:data-user-id="${user.id}"
|
||||
@@ -137,8 +149,8 @@
|
||||
<div class="list-table-row" th:each="user : ${pendingUsers}">
|
||||
<div class="row-cell" style="width: 90px;" data-label="NO">-</div>
|
||||
<div class="row-cell" style="width: 90px;" data-label="성명">-</div>
|
||||
<div class="row-cell" style="flex: 1; min-width: 180px;" data-label="이메일" th:text="${user.maskedEmailAddr}">
|
||||
pending@example.com
|
||||
<div class="row-cell" style="flex: 1; min-width: 180px;" data-label="휴대폰" th:text="${user.maskedMobileNumber}">
|
||||
010-****-****
|
||||
</div>
|
||||
<div class="row-cell" style="width: 120px;" data-label="권한">이용자</div>
|
||||
<div class="row-cell" style="width: 120px;" data-label="계정상태">초대중</div>
|
||||
@@ -147,7 +159,7 @@
|
||||
<div class="actions-desktop">
|
||||
<button type="button" class="list-table-btn list-table-btn--secondary cancel_invitation"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-email="${user.maskedEmailAddr}">
|
||||
th:data-user-email="${user.maskedMobileNumber}">
|
||||
초대취소
|
||||
</button>
|
||||
</div>
|
||||
@@ -164,7 +176,7 @@
|
||||
<div class="dropdown-menu">
|
||||
<button type="button" class="dropdown-item cancel_invitation"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-email="${user.maskedEmailAddr}">
|
||||
th:data-user-email="${user.maskedMobileNumber}">
|
||||
초대취소
|
||||
</button>
|
||||
</div>
|
||||
@@ -194,6 +206,8 @@
|
||||
<div th:replace="~{fragment/popup/userInvitePopup :: userInvitePopup}"></div>
|
||||
<!-- Change Role Modal -->
|
||||
<div th:replace="~{fragment/popup/changeRolePopup :: changeRolePopup}"></div>
|
||||
<!-- Cancel Invitation Modal -->
|
||||
<div th:replace="~{fragment/popup/cancelInvitationPopup :: cancelInvitationPopup}"></div>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
@@ -247,12 +261,12 @@
|
||||
// Function to open the user invite popup
|
||||
function openUserInvitePopup() {
|
||||
customPopups.showUserInvite({
|
||||
onConfirm: function(email) {
|
||||
onConfirm: function(mobile, notifyConsent) {
|
||||
$.ajax({
|
||||
url: '/users/invite',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({emailAddr: email})
|
||||
data: JSON.stringify({mobileNumber: mobile, notifyConsent: notifyConsent})
|
||||
}).done(function(response) {
|
||||
customPopups.hideUserInvite();
|
||||
customPopups.showAlert(response.msg, function() {
|
||||
@@ -315,6 +329,63 @@
|
||||
});
|
||||
});
|
||||
|
||||
// 관리자 -> 이용자 변경 (본인 제외)
|
||||
document.querySelectorAll('.revoke_manager').forEach(button => {
|
||||
button.addEventListener('click', function(event) {
|
||||
const btn = event.currentTarget;
|
||||
const userId = btn.dataset.userId;
|
||||
const userName = btn.dataset.userName;
|
||||
|
||||
customPopups.showConfirm(`<strong>${userName}</strong>님을 이용자로 변경하시겠습니까?`, function(selection) {
|
||||
if (!selection) return;
|
||||
$.ajax({
|
||||
url: '/users/revoke-manager',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({id: userId})
|
||||
}).done(function(response) {
|
||||
customPopups.showAlert(response.msg, function() {
|
||||
location.reload();
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
let msg;
|
||||
try { msg = JSON.parse(jqXHR.responseText).msg; } catch (e) {}
|
||||
customPopups.showAlert(msg || ('권한 변경 중 오류가 발생했습니다: ' + errorThrown));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 소속 제외 -> 개인이용자 전환 (경고)
|
||||
document.querySelectorAll('.remove_from_org').forEach(button => {
|
||||
button.addEventListener('click', function(event) {
|
||||
const btn = event.currentTarget;
|
||||
const userId = btn.dataset.userId;
|
||||
const userName = btn.dataset.userName;
|
||||
|
||||
customPopups.showConfirm(
|
||||
`<strong>${userName}</strong>님을 소속에서 제외하시겠습니까?<br>제외 시 기관의 모든 권한이 회수되며 <strong>개인이용자</strong>로 전환됩니다.`,
|
||||
function(selection) {
|
||||
if (!selection) return;
|
||||
$.ajax({
|
||||
url: '/users/remove-from-org',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({id: userId})
|
||||
}).done(function(response) {
|
||||
customPopups.showAlert(response.msg, function() {
|
||||
location.reload();
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
let msg;
|
||||
try { msg = JSON.parse(jqXHR.responseText).msg; } catch (e) {}
|
||||
customPopups.showAlert(msg || ('소속 제외 중 오류가 발생했습니다: ' + errorThrown));
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const activateButtons = document.querySelectorAll('.activate_user');
|
||||
const inactivateButtons = document.querySelectorAll('.inactivate_user');
|
||||
const cancelInvitationButtons = document.querySelectorAll('.cancel_invitation');
|
||||
@@ -363,21 +434,24 @@
|
||||
const userId = button.dataset.userId;
|
||||
const userEmail = button.dataset.userEmail;
|
||||
|
||||
customPopups.showConfirm(`${userEmail}에 대한 초대를 취소하시겠습니까?`, function(selection) {
|
||||
if (selection) {
|
||||
customPopups.showCancelInvitation({
|
||||
target: userEmail,
|
||||
onConfirm: function(notifyConsent) {
|
||||
$.ajax({
|
||||
url: '/users/cancel-invitation',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({id: userId})
|
||||
data: JSON.stringify({id: userId, notifyConsent: notifyConsent})
|
||||
}).done(function(response) {
|
||||
customPopups.hideCancelInvitation();
|
||||
customPopups.showAlert(response.msg, function() {
|
||||
location.reload(); // Reload the page to reflect changes
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
customPopups.showAlert('초대 취소 중 오류가 발생했습니다: ' + errorThrown);
|
||||
}).always(function() {
|
||||
$('#customConfirm').hide();
|
||||
customPopups.hideCancelInvitation();
|
||||
let msg;
|
||||
try { msg = JSON.parse(jqXHR.responseText).msg; } catch (e) {}
|
||||
customPopups.showAlert(msg || ('초대 취소 중 오류가 발생했습니다: ' + errorThrown));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
<div class="footer-links">
|
||||
<a th:href="@{/agreements/terms}" class="footer-link">이용약관</a>
|
||||
<span class="footer-separator">|</span>
|
||||
<a th:href="@{/agreements/terms(tab=privacy)}" class="footer-link">개인정보처리방침</a>
|
||||
<a href="https://www.jejubank.co.kr/hmpg/csct/secuCenr/ptctPlcy/procsPlcy/ctnt.do"
|
||||
target="_blank" rel="noopener noreferrer" class="footer-link">개인정보처리방침</a>
|
||||
</div>
|
||||
<p class="footer-copyright">Copyright © 2026 DJ Bank. All Rights Reserved.</p>
|
||||
</div>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<section layout:fragment="title">
|
||||
<div class="page-title-banner">
|
||||
<img th:src="@{/img/img_title_bg.png}" class="title-image">
|
||||
<h1 th:text="${agreementTitle}">이용 약관</h1>
|
||||
<h1 th:text="${isTermsOfUse ? '이용약관' : (isPrivacyCollect ? '개인정보수집동의서' : '알림 수신 동의서')}">이용 약관</h1>
|
||||
</div>
|
||||
</section>
|
||||
<section layout:fragment="contentFragment">
|
||||
<div class="terms-container">
|
||||
<!-- Title Bar -->
|
||||
<div class="common-title-bar">
|
||||
<h2 class="common-title" th:text="${isTermsOfUse ? '이용약관' : '개인정보처리방침'}">이용약관</h2>
|
||||
<h2 class="common-title" th:text="${isTermsOfUse ? '이용약관' : (isPrivacyCollect ? '개인정보수집동의서' : '알림 수신 동의서')}">이용약관</h2>
|
||||
</div>
|
||||
|
||||
<!-- Tab Navigation -->
|
||||
@@ -22,15 +22,20 @@
|
||||
th:classappend="${isTermsOfUse ? 'active' : ''}">
|
||||
이용약관
|
||||
</a>
|
||||
<a th:href="@{/agreements/terms(tab='privacy')}"
|
||||
<a th:href="@{/agreements/terms(tab='privacy-collect')}"
|
||||
class="tab-link"
|
||||
th:classappend="${isPrivacyPolicy ? 'active' : ''}">
|
||||
개인정보처리방침
|
||||
th:classappend="${isPrivacyCollect ? 'active' : ''}">
|
||||
개인정보수집동의서
|
||||
</a>
|
||||
<a th:href="@{/agreements/terms(tab='notification')}"
|
||||
class="tab-link"
|
||||
th:classappend="${isNotification ? 'active' : ''}">
|
||||
알림 수신 동의서
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Version Selector -->
|
||||
<div class="terms-selector">
|
||||
<div class="terms-selector" th:if="${selectedAgreement != null}">
|
||||
<form id="agreementForm" th:action="@{/agreements/terms}" method="get">
|
||||
<input type="hidden" name="tab" th:value="${currentTab}">
|
||||
<select name="publishedOn" id="publishedOnSelect" class="terms-select" onchange="this.form.submit()">
|
||||
@@ -45,19 +50,24 @@
|
||||
|
||||
<!-- Terms Content -->
|
||||
<div class="terms-content">
|
||||
<!-- Attachment Download -->
|
||||
<div class="terms-attachment" th:if="${selectedAgreement.attachedFileId != null}">
|
||||
<a th:href="@{/file/download(fileId=${selectedAgreement.attachedFileId}, fileSn=1)}"
|
||||
class="attachment-link">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
<polyline points="7 10 12 15 17 10"></polyline>
|
||||
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||
</svg>
|
||||
<span th:text="${selectedAgreement.attachedFileName} ?: '첨부파일 다운로드'">첨부파일 다운로드</span>
|
||||
</a>
|
||||
<th:block th:if="${selectedAgreement != null}">
|
||||
<!-- Attachment Download -->
|
||||
<div class="terms-attachment" th:if="${selectedAgreement.attachedFileId != null}">
|
||||
<a th:href="@{/file/download(fileId=${selectedAgreement.attachedFileId}, fileSn=1)}"
|
||||
class="attachment-link">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
<polyline points="7 10 12 15 17 10"></polyline>
|
||||
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||
</svg>
|
||||
<span th:text="${selectedAgreement.attachedFileName} ?: '첨부파일 다운로드'">첨부파일 다운로드</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="content-body editor-content" th:utext="${selectedAgreement.contents}"></div>
|
||||
</th:block>
|
||||
<div class="terms-empty" th:if="${selectedAgreement == null}">
|
||||
<p>등록된 약관이 없습니다.</p>
|
||||
</div>
|
||||
<div class="content-body editor-content" th:utext="${selectedAgreement.contents}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<!-- views/fragment/popup/cancelInvitationPopup.html -->
|
||||
<div th:fragment="cancelInvitationPopup" id="cancelInvitationPopup" style="display: none;">
|
||||
<!-- Modal Backdrop -->
|
||||
<div class="modal-backdrop" id="cancelInvitationModalBackdrop"></div>
|
||||
|
||||
<!-- Modal Wrapper -->
|
||||
<div class="modal" id="cancelInvitationModal">
|
||||
<div class="modal-dialog">
|
||||
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">초대취소</h3>
|
||||
<button type="button" class="modal-close" id="cancelInvitationPopupCloseButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
<p id="cancelInvitationPopupMessage" style="text-align: center; margin-bottom: 24px; color: #1A1A2E; font-size: 16px;">
|
||||
<strong id="cancelInvitationTarget" style="color: #4B9BFF;"></strong>에 대한<br>초대를 취소하시겠습니까?
|
||||
</p>
|
||||
|
||||
<!-- 알림 수신 동의 체크박스 -->
|
||||
<div class="pop_consent_group" style="margin-top: 16px;">
|
||||
<label class="pop_consent_label"
|
||||
style="display: flex; align-items: flex-start; gap: 8px; font-size: 13px; color: #475569; line-height: 1.5; cursor: pointer;">
|
||||
<input type="checkbox" id="cancelInvitationNotifyConsent" style="margin-top: 3px; flex-shrink: 0;">
|
||||
<span>
|
||||
초대 취소 사실을 수신자에게 알림 메시지로 전송하기 위해 수신자의
|
||||
<a th:href="@{/agreements/terms(tab='notification')}" target="_blank" rel="noopener noreferrer"
|
||||
style="color: #3ba4ed; text-decoration: underline;">알림 수신 동의서</a>
|
||||
동의가 필요합니다. 동의하지 않을 경우 초대 취소는 진행되나 메시지가 발송되지 않습니다.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary btn-submit" id="cancelInvitationPopupCancelButton">닫기</button>
|
||||
<button type="button" class="btn btn-primary btn-submit" id="cancelInvitationPopupConfirmButton">초대취소</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,17 +21,32 @@
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
<p id="userInvitePopupMessage" style="text-align: center; margin-bottom: 24px; color: #64748B;">
|
||||
추가할 이용자 e-mail 주소를 입력해 주세요.
|
||||
추가할 이용자 휴대폰 번호를 입력해 주세요.
|
||||
</p>
|
||||
|
||||
<!-- Email Input Field -->
|
||||
<!-- Mobile Input Field -->
|
||||
<div class="pop_input_group">
|
||||
<input type="email"
|
||||
id="userInviteEmailInput"
|
||||
<input type="tel"
|
||||
id="userInviteMobileInput"
|
||||
class="pop_input_field"
|
||||
placeholder="이용자 e-mail 주소">
|
||||
placeholder="휴대폰 번호 ('-' 없이 입력)"
|
||||
maxlength="13">
|
||||
<div id="userInvitePopupError" class="error-message"></div>
|
||||
</div>
|
||||
|
||||
<!-- 알림 수신 동의 체크박스 -->
|
||||
<div class="pop_consent_group" style="margin-top: 16px;">
|
||||
<label class="pop_consent_label"
|
||||
style="display: flex; align-items: flex-start; gap: 8px; font-size: 13px; color: #475569; line-height: 1.5; cursor: pointer;">
|
||||
<input type="checkbox" id="userInviteNotifyConsent" style="margin-top: 3px; flex-shrink: 0;">
|
||||
<span>
|
||||
입력한 휴대폰 번호로 초대 메시지를 보내기 위해 수신자의
|
||||
<a th:href="@{/agreements/terms(tab='notification')}" target="_blank" rel="noopener noreferrer"
|
||||
style="color: #3ba4ed; text-decoration: underline;">알림 수신 동의서</a>
|
||||
동의가 필요합니다. 동의하지 않을 경우 초대는 진행되나 메시지가 발송되지 않습니다.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
|
||||
Reference in New Issue
Block a user