- 초대 로직 변경: 이메일→휴대폰 기반 초대 전환 및 UI 업데이트
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- 알림 수신 동의 추가: 초대/취소 시 알림 발송 옵션 탑재
- 관리자 기능 추가: 소속 제외 및 권한 조정 기능 구현
This commit is contained in:
Rinjae
2026-06-23 20:58:27 +09:00
parent 53468c3b83
commit 84d92fced9
26 changed files with 648 additions and 198 deletions
+31 -8
View File
@@ -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;
}
}
}
}