/** * PurstmpStamp.js * * 구매 스탬프 기능을 구현한 모듈 * 사용자가 스탬프를 적립하고 교환권을 발급받는 기능 제공 * * 주요 기능: * 1. 스탬프 카드 슬라이더 UI 구현 * 2. 스탬프 상태 확인 및 업데이트 * 3. 모달 팝업 관리 * 4. 스탬프 새로고침 기능 * 5. 이달의 선물 정보 표시 */ // 전역 변수 제거 - window.screenInfo 사용 // let screenInfo = null; // 이 줄 삭제 // 문서가 로드되면 초기화 함수 실행 document.addEventListener('DOMContentLoaded', function() { // window.screenInfo가 JSP에서 설정되었는지 확인 if (window.screenInfo) { init(); // JSP에서 데이터가 이미 설정된 경우 바로 초기화 } else { loadScreenData(); // Ajax로 데이터 로드 } }); /** * 화면 데이터 로드 함수 * Ajax로 서버에서 스탬프 정보를 가져옴 */ function loadScreenData() { // 로딩 표시 showLoading(); $.ajax({ url: '/sopmal/bnft/getStampData', method: 'POST', contentType: 'application/json', data: JSON.stringify({}), // 빈 객체 전송 (인증은 세션으로 처리) dataType: 'json', success: function(response) { try { if (response.success) { window.screenInfo = response.data; // stampList 데이터 추출 (BO 서버 응답 구조에 맞춰) if (window.screenInfo && window.screenInfo.stampList) { window.screenInfo = window.screenInfo.stampList; // couponList를 coupons로 매핑 (기존 코드와의 호환성 유지) if (window.screenInfo.couponList) { window.screenInfo.coupons = window.screenInfo.couponList; } } init(); // 데이터 로드 완료 후 초기화 } else { showError(response.message || '데이터를 불러오는데 실패했습니다.'); } } catch (error) { console.error('데이터 처리 중 오류:', error); showError('데이터 처리 중 오류가 발생했습니다.'); } }, error: function(xhr, status, error) { console.error('Ajax 오류:', error); showError('서버와의 통신 중 오류가 발생했습니다.'); }, complete: function() { hideLoading(); } }); } /** * 로딩 표시 함수 */ function showLoading() { $('.stampCardWrap').html('
로딩중...
'); } /** * 로딩 숨김 함수 */ function hideLoading() { $('.loading-spinner').remove(); } /** * 에러 표시 함수 */ function showError(message) { $('.stampCardWrap').html(`
${message}
`); } /** * 모듈 초기화 함수 * 필요한 모든 컴포넌트와 이벤트 리스너 초기화 */ function init() { if (!window.screenInfo) { console.error('screenInfo가 없습니다.'); return; } initStampCardSlider(); // 스탬프 카드 슬라이더 초기화 initModal(); // 모달 팝업 초기화 updateTotalStamps(); // 전체 스탬프 수 업데이트 checkStampStatus(); // 스탬프 상태 확인 updateRewardInfo(); // 이달의 선물 정보 업데이트 // 새로고침 버튼 클릭 이벤트 처리 // init() 함수가 여러 번 호출될 수 있으므로, 이벤트 중복 등록을 방지하기 위해 .off()를 추가합니다. $('.stampCardWrap').off('click.reply').on('click.reply', '.btn_reply', function(e) { e.preventDefault(); e.stopPropagation(); // 슬라이드 이벤트와 충돌 방지 var couponIndex = $(this).closest('.stampCard').data('coupon-index'); refreshStamps(couponIndex); }); } /** * 스탬프 상태 확인 함수 * 스탬프가 없거나 교환권이 모두 사용된 경우 UI 변경 */ function checkStampStatus() { if (!window.screenInfo) return; // 데이터가 없는 경우 또는 교환권이 모두 사용된 경우 if (!window.screenInfo.coupons || window.screenInfo.coupons.length === 0) { // 예시에 맞는 UI로 변경: 스탬프 카드 형태 유지하되 빈 상태 표시 $('.stampCardWrap').html(`

오프라인 매장 구매시
자동으로 스탬프가 적립됩니다.

스탬프 10개 적립시 이달의 선물 교환권을 드려요.

`); } } /** * 스탬프 카드 슬라이더 초기화 함수 * 스탬프 카드 UI 생성 및 슬라이드 기능 구현 (중복 생성 방지) */ function initStampCardSlider() { if (!window.screenInfo || !window.screenInfo.coupons) { console.warn('쿠폰 데이터가 없습니다.'); return; } const $stampCardWrap = $('.stampCardWrap'); const couponCount = window.screenInfo.coupons.length; if (couponCount === 0) { return; } // ✨ 가장 중요한 부분: 이미 카드가 생성되었다면, 함수를 즉시 종료하여 다시 그리지 않습니다. if ($stampCardWrap.find('.stampCard').length > 0) { console.log('카드가 이미 존재하므로 재생성하지 않습니다.'); return; } let currentCouponIndex = 0; let startX, moveX; /** * 모든 쿠폰 카드를 미리 생성하는 함수 */ function createAllCouponCards() { // 이 함수는 최초 1회만 호출되므로, 이전처럼 .empty()를 호출할 필요가 없습니다. window.screenInfo.coupons.forEach((coupon, index) => { const $card = createCouponCard(coupon, index); $stampCardWrap.append($card); }); // 페이지네이션 생성 if (couponCount > 1) { const $pagination = $(''); for (let i = 0; i < couponCount; i++) { const $button = $(``); $pagination.append($button); } $stampCardWrap.append($pagination); } } /** * 쿠폰 카드 생성 함수 */ function createCouponCard(coupon, index) { // 교환권 완료 상태에 따른 메시지 결정 let giftMessage = ''; if (coupon.extiketStmpCnt === 10 && coupon.exchngAt === 'Y') { giftMessage = '✅ 교환권 발급 완료! 쿠폰함에서 확인하세요'; } else if (coupon.extiketStmpCnt === 10) { giftMessage = '🎁 교환권 발급 준비완료!'; } else { giftMessage = `스탬프 10개 적립시 이달의 선물 교환권을 드려요.`; } return $(` `); } /** * 스탬프 카드 표시 함수 (참조 코드 방식 적용) */ function showSlide(index) { $('.stampCard').hide(); $('.stampCard').eq(index).fadeIn(); $('.pagination button').removeClass('active'); $('.pagination button').eq(index).addClass('active'); } /** * 페이지네이션 생성 함수 */ function createPagination() { if (couponCount <= 1) return; const $pagination = $('.pagination'); if ($pagination.length === 0) { const $newPagination = $(''); for (let i = 0; i < couponCount; i++) { $newPagination.append(``); } $stampCardWrap.append($newPagination); } } /** * 다음 슬라이드 표시 */ function nextSlide() { currentCouponIndex = (currentCouponIndex + 1) % couponCount; showSlide(currentCouponIndex); } /** * 이전 슬라이드 표시 */ function previousSlide() { currentCouponIndex = (currentCouponIndex - 1 + couponCount) % couponCount; showSlide(currentCouponIndex); } // 페이지네이션 버튼 클릭 이벤트 $stampCardWrap.on('click', '.pagination button', function(e) { e.stopPropagation(); currentCouponIndex = $(this).data('index'); showSlide(currentCouponIndex); }); // 카드 클릭 이벤트 (참조 코드 방식) $stampCardWrap.on('click', function(e) { if (couponCount <= 1) return; // 새로고침 버튼 클릭인 경우 슬라이드 이벤트 무시 if ($(e.target).hasClass('btn_reply') || $(e.target).closest('.btn_reply').length > 0) { return; } const clickX = e.clientX; const wrapWidth = $stampCardWrap.width(); const halfWidth = wrapWidth / 2; if (clickX < halfWidth) { previousSlide(); } else { nextSlide(); } }); // 터치 이벤트 $stampCardWrap.on('touchstart', function(e) { startX = e.touches[0].clientX; }); $stampCardWrap.on('touchmove', function(e) { moveX = e.touches[0].clientX; }); $stampCardWrap.on('touchend', function(e) { if (couponCount <= 1) return; if (startX - moveX > 50) { nextSlide(); } else if (moveX - startX > 50) { previousSlide(); } }); // 슬라이더 초기화 if (couponCount > 0) { createAllCouponCards(); createPagination(); showSlide(currentCouponIndex); } } /** * 날짜 포맷 변환 함수 * 날짜 문자열을 YYYY.MM.DD 형식으로 변환 * * @param {string} dateString - 변환할 날짜 문자열 * @returns {string} 포맷된 날짜 문자열 */ function formatDate(dateString) { const date = new Date(dateString); return `${date.getFullYear()}.${(date.getMonth() + 1).toString().padStart(2, '0')}.${date.getDate().toString().padStart(2, '0')}`; } /** * 모달 초기화 함수 * MicroModal 라이브러리를 사용한 모달 팝업 초기화 */ function initModal() { MicroModal.init({ disableScroll: true, awaitCloseAnimation: true, }); // 모달 트리거 버튼 클릭 이벤트 $('.fullscreen-trigger').on('click', function(e) { e.preventDefault(); var modalId = $(this).attr('data-micromodal-trigger'); // 전역 openModal 함수 사용 if (typeof window.openModal === 'function') { window.openModal(modalId); } else { MicroModal.show(modalId); } }); // 모달 닫기 버튼 클릭 이벤트 $('#modal-close-btn').on('click', function(e) { e.preventDefault(); e.stopPropagation(); console.log('모달 닫기 버튼 클릭됨'); // 디버깅용 window.location.href = '/sopmal/bnft/bnftMain'; }); // 브라우저 뒤로가기 버튼 처리 window.addEventListener('popstate', function(event) { var modalId = window.location.hash.replace('#', ''); if (modalId) { // 전역 closeModal 함수 사용 if (typeof window.closeModal === 'function') { window.closeModal(modalId); } else { MicroModal.close(modalId); } } else { $('.microModal').each(function() { MicroModal.close($(this).attr('id')); }); } document.body.style.overflow = ''; }); // URL 해시가 있는 경우 해당 모달 열기 if (window.location.hash) { var modalId = window.location.hash.replace('#', ''); // 전역 openModal 함수 사용 if (typeof window.openModal === 'function') { window.openModal(modalId); } else { MicroModal.show(modalId); } } } /** * 토스트 메시지 표시 함수 * * @param {string} message - 표시할 메시지 */ function showToast(message) { const $toastPop = $('#modal_exchange_ticket_toast'); $toastPop.text(message); $toastPop.addClass('show'); setTimeout(() => { $toastPop.removeClass('show'); }, 2000); } /** * 스탬프 새로고침 함수 (토스트 제거) */ function refreshStamps(couponIndex) { if (!window.screenInfo || !window.screenInfo.coupons || !window.screenInfo.coupons[couponIndex]) { showToast('쿠폰 정보를 찾을 수 없습니다.'); return; } const coupon = window.screenInfo.coupons[couponIndex]; $.ajax({ url: '/sopmal/bnft/refreshStamps', method: 'POST', data: JSON.stringify({ bnfInnb: window.screenInfo.bnfInnb || '', strInnb: coupon.strInnb || '', bnfExtiketInnb: coupon.bnfExtiketInnb || '', mbrInnb: window.screenInfo.mbrInnb || '', mbrDvCd: window.screenInfo.mbrDvCd || '', sopmalCd: window.screenInfo.sopmalCd || '' }), contentType: 'application/json', success: function(response) { try { if (response && response.resBody && response.resBody.result) { const responseData = JSON.parse(response.resBody.result); if (responseData.success) { // ⚠️ 매장명이 null인 경우 기존 매장명 유지 if (!responseData.cardInfo.branchName) { responseData.cardInfo.branchName = coupon.storeName || coupon.branchName || '매장명 미확인'; } updateStampCard(couponIndex, responseData); // ❌ 토스트 제거: showToast('스탬프 정보가 새로고침되었습니다.'); } else { showToast(responseData.message || '스탬프 정보를 새로고침하는데 실패했습니다.'); } } else { showToast('응답 형식이 올바르지 않습니다.'); } } catch (error) { console.error('응답 처리 중 오류:', error); showToast('응답을 처리하는 동안 오류가 발생했습니다.'); } }, error: function(xhr, status, error) { console.error('새로고침 Ajax 오류:', error); showToast('스탬프 정보를 새로고침하는데 실패했습니다.'); } }); } /** * 스탬프 카드 업데이트 함수 - 카드 틀은 유지하고 내용만 업데이트 */ function updateStampCard(couponIndex, data) { // 데이터 업데이트 Object.assign(window.screenInfo.coupons[couponIndex], data.cardInfo); const coupon = window.screenInfo.coupons[couponIndex]; const $card = $(`.stampCard[data-coupon-index="${couponIndex}"]`); // 1. 스탬프 개수 및 시각적 표시 업데이트 const newStampCount = coupon.extiketStmpCnt || 0; $card.find('.cardCnt b').text(newStampCount); $card.find('.stampArea li').each((index, el) => { $(el).toggleClass('on', index < newStampCount); }); // 2. 지점명 업데이트 const branchName = coupon.branchName || coupon.storeName || '매장명 미확인'; $card.find('.shopName span').text(branchName); // 3. 유효기간 업데이트 if (coupon.stmpValidDt) { $card.find('.useDate').text(`유효기간 ${formatDate(coupon.stmpValidDt)} 까지`); } // 4. 교환권 상태 메시지 업데이트 let giftMessage = ''; if (coupon.extiketStmpCnt === 10 && coupon.exchngAt === 'Y') { giftMessage = '✅ 교환권 발급 완료! 쿠폰함에서 확인하세요'; } else if (coupon.extiketStmpCnt === 10) { giftMessage = '🎁 교환권 발급 준비완료!'; } else { giftMessage = `스탬프 10개 적립시 이달의 선물 교환권을 드려요.`; } $card.find('.giftInfo').html(giftMessage); // 5. 부드러운 업데이트 효과 (CSS 애니메이션 필요) $card.find('.stampArea').addClass('updated'); setTimeout(() => { $card.find('.stampArea').removeClass('updated'); }, 300); updateTotalStamps(); } /** * 전체 스탬프 수 업데이트 함수 * 화면에 표시된 전체 쿠폰 수 업데이트 */ function updateTotalStamps() { const totalCoupons = window.screenInfo.coupons.length; $('.card_title b').text(totalCoupons); window.screenInfo.totalStamps = totalCoupons; } /** * 이달의 선물 정보 업데이트 함수 * 서버에서 받은 purstmpScreenInfo 데이터로 UI 업데이트 */ function updateRewardInfo() { if (!window.screenInfo || !window.screenInfo.purstmpScreenInfo || !window.screenInfo.purstmpScreenInfo[0]) { console.warn('이달의 선물 정보가 없습니다.'); return; } const rewardInfo = window.screenInfo.purstmpScreenInfo[0]; // 이달의 선물 이름 설정 (cnSj) if (rewardInfo.cnSj) { $('#rewardName').text(rewardInfo.cnSj); } // 이달의 선물 이미지 설정 (imgFilCours) if (rewardInfo.imgFilCours) { const imageSrc = window.cdnUrl + rewardInfo.imgFilCours; $('#rewardImage').attr('src', imageSrc); } // 이벤트 설명 설정 (wordsCn) - HTML 형태로 삽입 if (rewardInfo.wordsCn) { $('#eventDescription').html(rewardInfo.wordsCn); } }