/** * OXQuiz.js * * OX 퀴즈 기능을 구현한 모듈 * 사용자가 OX 퀴즈에 참여하고 결과를 확인하는 기능 제공 * * 주요 기능: * 1. OX 퀴즈 참여 및 결과 처리 * 2. 퀴즈 UI 업데이트 및 상태 관리 * 3. 알림 설정 관리 * 4. 모달 팝업을 통한 결과 안내 */ const OXQuiz = (function() { /** * 모듈 초기화 함수 * 이벤트 리스너 등록 및 알림 상태 조회 */ function init() { addEventListeners(); getNotificationStatus(); } /** * 이벤트 리스너 등록 함수 * 퀴즈 결과 확인, 답변 선택, 알림 설정 버튼에 이벤트 리스너 등록 */ function addEventListeners() { $('#quizResult').off('click').on('click', handleQuizResult); $('.qzSelect a').off('click').on('click', handleAnswerSelection); $('#notificationBtn').off('click').on('click', handleNotification); // 힌트 버튼에 이벤트 리스너 추가 $('#hintButton').off('click').on('click', function() { const hintUrl = screenInfo.quizInfoList[screenInfo.currentQuiz - 1].hintUrl; openExternalUrl(hintUrl); }); } /** * 답변 선택 처리 함수 * 사용자가 OX 중 하나를 선택했을 때 UI 업데이트 * @param {Event} e - 클릭 이벤트 객체 */ function handleAnswerSelection(e) { e.preventDefault(); // 현재 퀴즈가 이미 완료된 상태인지 확인 const currentQuiz = screenInfo.quizInfoList[screenInfo.currentQuiz - 1]; if (currentQuiz.userAnswer !== null) { showCustomAlert('이미 완료된 퀴즈입니다.'); return; } $('.qzSelect a').removeClass('on'); $(this).addClass('on'); } /** * 퀴즈 결과 확인 처리 함수 * 사용자가 선택한 답변을 서버에 전송하고 결과 처리 */ function handleQuizResult() { const $resultButton = $(this); // 버튼이 비활성화 상태면 함수 실행 중지 if ($resultButton.prop('disabled')) return; // 선택된 답변 확인 const selectedAnswer = $('.qzSelect a.on').data('answer'); if (!selectedAnswer) { showCustomAlert('OX 중 한 가지를 선택해 주세요.'); return; } // 중복 클릭 방지를 위한 버튼 비활성화 $resultButton.prop('disabled', true); // 서버에 퀴즈 참여 요청 전송 $.ajax({ url: '/sopmal/bnft/participate', method: 'POST', contentType: 'application/json', data: JSON.stringify({ bnfInnb: screenInfo.basicInfo.bnfInnb, // 혜택 고유 번호 bnfQuizInnb: screenInfo.quizInfoList[screenInfo.currentQuiz - 1].bnfQuizInnb, // 퀴즈 고유 번호 answCn: selectedAnswer // 선택한 답변(O/X) }), success: handleQuizResponse, error: function(xhr, status, error) { $resultButton.prop('disabled', false); handleQuizError(xhr, status, error); } }); } /** * 퀴즈 응답 처리 함수 * 서버로부터 받은 퀴즈 결과를 처리하고 UI 업데이트 * @param {Object} response - 서버 응답 객체 */ function handleQuizResponse(response) { if (response.success) { updateQuizState(response); showResultModal(response); } else { showCustomAlert(response.message || '퀴즈 참여에 실패했습니다.'); } } /** * 퀴즈 오류 처리 함수 * 서버 요청 중 발생한 오류를 처리하고 사용자에게 안내 * @param {Object} xhr - XMLHttpRequest 객체 * @param {string} status - 요청 상태 * @param {string} error - 오류 메시지 */ function handleQuizError(xhr, status, error) { console.error('퀴즈 참여 실패:', error); let errorMessage = '퀴즈 참여 중 오류가 발생했습니다. '; if (xhr.status === 404) { errorMessage += '퀴즈를 찾을 수 없습니다. 페이지를 새로고침 해주세요.'; } else if (xhr.status === 403) { errorMessage += '권한이 없습니다. 로그인 상태를 확인해주세요.'; } else { errorMessage += '잠시 후 다시 시도해주세요.'; } showCustomAlert(errorMessage); } /** * 결과 모달 표시 함수 * 퀴즈 결과에 따라 적절한 모달 팝업을 표시 * @param {Object} response - 서버 응답 객체 */ function showResultModal(response) { let modalId; // 보상 코드에 따른 모달 선택 (수정) if (response.rewardCodes && response.rewardCodes.includes('13030')) { modalId = 'modal-3'; // 모든 퀴즈 정답 } else if (response.isCorrect) { modalId = 'modal-1'; // 정답 } else { modalId = 'modal-2'; // 오답 } // 모달 내용 업데이트 const $modal = $(`#${modalId}`); const $content = $modal.find('.microModal__content'); // 퀴즈 번호와 정답 업데이트 $content.find('.sub_tit:first').html( `${screenInfo.currentQuiz}번째 퀴즈, 정답은 ${response.correctAnswer}입니다.` ); // 마일리지 금액 업데이트 (수정) if (response.rewardInfos && response.rewardInfos.length > 0) { // 모든 보상의 마일리지 합계 계산 const totalMileage = response.rewardInfos.reduce((total, reward) => { return total + (reward.mlgRwdAmt || 0); }, 0); if (totalMileage > 0) { $content.find('.sub_tit:eq(1)').html( `마일리지 ${totalMileage.toLocaleString()}원 획득` ); } } // 다음 퀴즈 안내 메시지 업데이트 const lastMessage = screenInfo.currentQuiz < screenInfo.quizCount ? `${screenInfo.currentQuiz + 1}번째 퀴즈도 내일 꼭! 도전하세요.` : '모든 퀴즈에 도전해 주셔서 감사합니다!'; $content.find('p:last').text(lastMessage); // 모달 표시 및 닫힐 때 UI 업데이트 MicroModal.show(modalId, { onClose: function() { updateQuizUI(); } }); } /** * 알림 설정 토글 함수 * 퀴즈 알림 신청/취소 처리 */ function handleNotification() { const $btn = $(this); const currentStatus = $btn.data('status') === 'on'; const newStatus = !currentStatus; // 알림 상태 변경 API 호출 $.ajax({ url: '/sopmal/bnft/updateoxquizNotificationStatus', method: 'POST', contentType: 'application/json', data: JSON.stringify({ bnfInnb: screenInfo.basicInfo.bnfInnb, // 혜택 고유 번호 agreAt: newStatus ? 'Y' : 'N' // 알림 동의 여부(Y/N) }), success: function(response) { if (response.success) { updateNotificationButton(response.notificationStatus); showCustomAlert(response.notificationStatus ? "알림 신청이 완료되었습니다." : "알림 신청이 해제되었습니다."); } else { showCustomAlert("알림 상태 변경에 실패했습니다.\n잠시 후 다시 시도해주세요."); } }, error: function(xhr, status, error) { console.error('알림 상태 변경 실패:', error); showCustomAlert('알림 상태 변경 중 오류가 발생했습니다.'); } }); } /** * 알림 상태 조회 함수 * 서버에서 현재 알림 설정 상태를 조회하여 UI 업데이트 */ function getNotificationStatus() { $.ajax({ url: '/sopmal/bnft/getoxquizNotificationStatus', method: 'POST', contentType: 'application/json', data: JSON.stringify({ bnfInnb: screenInfo.basicInfo.bnfInnb }), success: function(response) { updateNotificationButton(response.notificationStatus); }, error: function(xhr, status, error) { console.error('알림 상태 조회 실패:', error); } }); } /** * 알림 버튼 UI 업데이트 함수 * 알림 상태에 따라 버튼 스타일과 텍스트 변경 * @param {boolean} isNotificationOn - 알림 활성화 여부 */ function updateNotificationButton(isNotificationOn) { const $notificationBtn = $('#notificationBtn'); const $notificationText = $notificationBtn.find('#notificationText'); // 아이콘을 항상 업데이트 const iconClass = isNotificationOn ? 'ico_alarm2' : 'ico_alarm2'; $notificationBtn.find('i').remove(); // 기존 아이콘 제거 $notificationBtn.prepend(''); // 새로운 아이콘 추가 // 버튼 텍스트와 스타일 업데이트 if (isNotificationOn) { $notificationText.text('알림 신청 완료'); $notificationBtn .data('status', 'on') .removeClass('outline'); } else { $notificationText.text('알림 신청'); $notificationBtn .data('status', 'off') .addClass('outline'); } } /** * 퀴즈 상태 업데이트 함수 * 퀴즈 결과에 따라 내부 상태 데이터 업데이트 * @param {Object} quizResult - 퀴즈 결과 객체 */ function updateQuizState(quizResult) { screenInfo.quizInfoList[screenInfo.currentQuiz - 1].userAnswer = quizResult.userAnswer; screenInfo.quizInfoList[screenInfo.currentQuiz - 1].isCorrect = quizResult.isCorrect ? 'O' : 'X'; updateQuizUI(); } /** * 퀴즈 UI 업데이트 함수 * 현재 퀴즈 상태에 맞게 화면 요소 업데이트 */ function updateQuizUI() { // 퀴즈 스탬프 업데이트 $('.quizStamp li').each(function(index) { const quizInfo = screenInfo.quizInfoList[index]; $(this).removeClass('on fail location'); if (quizInfo.isCorrect === 'O') { $(this).addClass('on'); } else if (quizInfo.isCorrect === 'X') { $(this).addClass('on fail'); } if (index + 1 === screenInfo.currentQuiz) { $(this).addClass('location'); } }); // 현재 퀴즈 내용 업데이트 const currentQuiz = screenInfo.quizInfoList[screenInfo.currentQuiz - 1]; $('.quizBox .txt').text(currentQuiz.quizCn); // 선택 초기화 resetQuizSelection(); // OX 버튼 상태 업데이트 (추가) const $oxButtons = $('.qzSelect a'); if (currentQuiz.userAnswer !== null) { // 이미 완료된 퀴즈: OX 버튼 비활성화 및 스타일 변경 $oxButtons.addClass('disabled') .css({ 'opacity': '0.5', 'pointer-events': 'none', 'cursor': 'not-allowed' }); // 사용자가 선택한 답변 표시 $oxButtons.filter(`[data-answer="${currentQuiz.userAnswer}"]`).addClass('on'); } else { // 미완료 퀴즈: OX 버튼 활성화 $oxButtons.removeClass('disabled') .css({ 'opacity': '1', 'pointer-events': 'auto', 'cursor': 'pointer' }); } // 결과확인 버튼 상태 업데이트 const $resultButton = $('.bottomBtnControls button:last-child'); if (currentQuiz.userAnswer !== null) { $resultButton.text('도전완료') .prop('disabled', true) .removeClass('theme') .addClass('gray'); } else { $resultButton.text('결과확인') .prop('disabled', false) .removeClass('gray') .addClass('theme'); } // 힌트 버튼 이벤트 리스너 재설정 $('#hintButton').off('click').on('click', function() { const hintUrl = screenInfo.quizInfoList[screenInfo.currentQuiz - 1].hintUrl; openExternalUrl(hintUrl); }); } /** * 다음 퀴즈로 이동 함수 * 현재 퀴즈에서 다음 퀴즈로 이동 */ function moveToNextQuiz() { if (screenInfo.currentQuiz < screenInfo.quizCount) { screenInfo.currentQuiz++; updateQuizUI(); } else { showCustomAlert('모든 퀴즈를 완료하셨습니다!'); } } /** * 퀴즈 선택 초기화 함수 * OX 선택 상태를 초기화 */ function resetQuizSelection() { $('.qzSelect a').removeClass('on'); } /** * 힌트 모달 표시 함수 * 퀴즈 힌트를 모달 팝업으로 표시 * @param {string} hintUrl - 힌트 내용을 가져올 URL */ function showHintModal(hintUrl) { window.location.href = hintUrl; } /** * 힌트 페이지로 이동하는 함수 * 힌트 URL이 상대경로인지 절대경로인지 확인하고 적절히 처리 * @param {string} hintUrl - 힌트 URL */ function goToHintPage(hintUrl) { // URL이 http:// 또는 https://로 시작하지 않으면 절대 경로로 변환 if (hintUrl && !hintUrl.match(/^https?:\/\//i)) { // URL이 /로 시작하지 않으면 /를 추가 if (!hintUrl.startsWith('/')) { hintUrl = '/' + hintUrl; } } // 새 창으로 URL 열기 (웹뷰에서도 작동) window.open(hintUrl, '_blank'); } /** * 외부 URL을 여는 함수 * a 태그를 동적으로 생성하여 새 창에서 URL 열기 * @param {string} url - 열고자 하는 URL */ function openExternalUrl(url) { // URL이 http나 https로 시작하지 않으면 https 프로토콜 추가 if (url && !url.match(/^https?:\/\//i)) { url = 'https://' + url; } console.log('Opening URL:', url); // a 태그 동적 생성 const link = document.createElement('a'); link.href = url; link.target = '_blank'; link.rel = 'noopener noreferrer'; // DOM에 추가하고 클릭 이벤트 발생 document.body.appendChild(link); link.click(); // DOM에서 제거 setTimeout(() => { document.body.removeChild(link); }, 100); } // 공개 API 반환 return { init: init, openExternalUrl: openExternalUrl }; })(); // 문서 로드 완료 시 OXQuiz 모듈 초기화 $(document).ready(function() { OXQuiz.init(); });