/** * 밍글 스튜디오 - 예약 현황 캘린더 * Google Apps Script 프록시를 통해 캘린더 데이터를 가져와 표시 */ (function() { 'use strict'; var APPS_SCRIPT_URL = 'https://script.google.com/macros/s/AKfycbwoaoSmEskbJod4gR5NjLnpWSkhIDUYaGBYk0y1Q865TzaJ4gctSrTOWXxRnVa7J9AASA/exec'; var currentYear, currentMonth; var calTitle = document.getElementById('calTitle'); var calBody = document.getElementById('calBody'); var prevBtn = document.getElementById('prevMonth'); var nextBtn = document.getElementById('nextMonth'); function init() { var now = new Date(); currentYear = now.getFullYear(); currentMonth = now.getMonth() + 1; prevBtn.addEventListener('click', function() { changeMonth(-1); }); nextBtn.addEventListener('click', function() { changeMonth(1); }); renderCalendar(); } function changeMonth(delta) { currentMonth += delta; if (currentMonth > 12) { currentMonth = 1; currentYear++; } else if (currentMonth < 1) { currentMonth = 12; currentYear--; } renderCalendar(); } function renderCalendar() { updateTitle(); // 매번 새로 불러오기 buildGrid([]); showLoading(); fetchBookedDates(currentYear, currentMonth, function(dates) { buildGrid(dates); hideLoading(); }); } function showLoading() { calBody.classList.add('loading'); // 기존 오버레이 제거 var existing = calBody.querySelector('.cal-loading-overlay'); if (existing) existing.remove(); var lang = (window.i18n && window.i18n.currentLang) || 'ko'; var loadingTexts = { ko: '불러오는 중...', en: 'Loading...', ja: '読み込み中...', zh: '加载中...' }; var overlay = document.createElement('div'); overlay.className = 'cal-loading-overlay'; overlay.innerHTML = '
' + (loadingTexts[lang] || loadingTexts.ko) + ''; calBody.appendChild(overlay); } function hideLoading() { calBody.classList.remove('loading'); var overlay = calBody.querySelector('.cal-loading-overlay'); if (overlay) overlay.remove(); } // --- 제목 업데이트 --- function updateTitle() { var lang = (window.i18n && window.i18n.currentLang) || 'ko'; var monthNames = { ko: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'], en: ['January','February','March','April','May','June','July','August','September','October','November','December'], ja: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'], zh: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'] }; var names = monthNames[lang] || monthNames.ko; if (lang === 'en') { calTitle.textContent = names[currentMonth - 1] + ' ' + currentYear; } else if (lang === 'ja' || lang === 'zh') { calTitle.textContent = currentYear + '年 ' + names[currentMonth - 1]; } else { calTitle.textContent = currentYear + '년 ' + names[currentMonth - 1]; } } // --- API 호출 --- function fetchBookedDates(year, month, callback) { if (!APPS_SCRIPT_URL) { callback([]); return; } var url = APPS_SCRIPT_URL + '?year=' + year + '&month=' + month; fetch(url) .then(function(res) { return res.json(); }) .then(function(data) { callback(data.bookedDates || []); }) .catch(function() { callback([]); }); } // --- 그리드 렌더링 --- function buildGrid(bookedDates) { calBody.innerHTML = ''; var firstDay = new Date(currentYear, currentMonth - 1, 1).getDay(); var daysInMonth = new Date(currentYear, currentMonth, 0).getDate(); var today = new Date(); var todayStr = today.getFullYear() + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0'); var bookedSet = {}; for (var b = 0; b < bookedDates.length; b++) { bookedSet[bookedDates[b]] = true; } var fragment = document.createDocumentFragment(); for (var e = 0; e < firstDay; e++) { var emptyCell = document.createElement('div'); emptyCell.className = 'cal-cell empty'; fragment.appendChild(emptyCell); } for (var d = 1; d <= daysInMonth; d++) { var dateStr = currentYear + '-' + String(currentMonth).padStart(2, '0') + '-' + String(d).padStart(2, '0'); var cell = document.createElement('div'); cell.className = 'cal-cell'; var dayNum = document.createElement('span'); dayNum.className = 'day-num'; dayNum.textContent = d; var cellDate = new Date(currentYear, currentMonth - 1, d); var isPast = cellDate < new Date(today.getFullYear(), today.getMonth(), today.getDate()); if (dateStr === todayStr) { cell.classList.add('today'); } else if (isPast) { cell.classList.add('past'); } else if (bookedSet[dateStr]) { cell.classList.add('booked'); } else { cell.classList.add('available'); } cell.appendChild(dayNum); fragment.appendChild(cell); } calBody.appendChild(fragment); } document.addEventListener('langChanged', function() { updateTitle(); }); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();