diff --git a/src/components/commuters/CommuterCalendar.vue b/src/components/commuters/CommuterCalendar.vue index b4c9b15..c0300a7 100644 --- a/src/components/commuters/CommuterCalendar.vue +++ b/src/components/commuters/CommuterCalendar.vue @@ -90,9 +90,9 @@ import { useProjectStore } from '@/stores/useProjectStore'; import CommuterBtn from '@c/commuters/CommuterBtn.vue'; import CommuterProjectList from '@c/commuters/CommuterProjectList.vue'; import BackBtn from '@c/button/BackBtn.vue'; -import flatpickr from 'flatpickr'; -import monthSelectPlugin from 'flatpickr/dist/plugins/monthSelect/index'; -import 'flatpickr/dist/plugins/monthSelect/style.css'; +import { useDatePicker } from '@/stores/useDatePicker'; + +const datePickerStore = useDatePicker(); const baseUrl = $api.defaults.baseURL.replace(/api\/$/, ''); const user = ref({}); @@ -115,7 +115,6 @@ const commuters = ref([]); const monthlyCommuters = ref([]); const calendarDatepicker = ref(null); -let fpInstance = null; // 출퇴근 컴포넌트 이벤트 핸들러 const handleWorkTimeUpdate = () => { @@ -390,7 +389,6 @@ const selectedDateCommuters = computed(() => { commuter.COMMUTDAY === eventDate.value ); }); - onMounted(async () => { await fetchData(); await userStore.userInfo(); @@ -407,65 +405,13 @@ onMounted(async () => { checkedInProject.value = storedProject; } - nextTick(() => { - // 달력 데이트피커를 위한 input 요소 동적 생성 - const datePickerInput = document.createElement('input'); - datePickerInput.type = 'text'; - datePickerInput.style.display = 'none'; - document.body.appendChild(datePickerInput); - calendarDatepicker.value = datePickerInput; - - // Flatpickr 초기화 (달 선택) - fpInstance = flatpickr(calendarDatepicker.value, { - dateFormat: "Y-m", - plugins: [ - new monthSelectPlugin({ - shorthand: true, - dateFormat: "Y-m", - altFormat: "F Y" - }) - ], - onOpen: function() { - document.querySelector('.flatpickr-input').style.visibility = 'hidden'; - }, - onChange: function(selectedDatesArr, dateStr) { - // 선택한 달의 첫날로 달력을 이동 - fullCalendarRef.value.getApi().gotoDate(dateStr + "-01"); - const [year, month] = dateStr.split("-"); - lastRemainingYear.value = parseInt(year, 10); - lastRemainingMonth.value = month; - loadCalendarData(lastRemainingYear.value, lastRemainingMonth.value); - }, - onClose: function() { - calendarDatepicker.value.style.display = "none"; - } - }); - - // FullCalendar 년월월(.fc-toolbar-title) 클릭 시 데이트피커 열기 - const titleEl = document.querySelector('.fc-toolbar-title'); - if (titleEl) { - titleEl.style.cursor = 'pointer'; - titleEl.addEventListener('click', () => { - const rect = titleEl.getBoundingClientRect(); - const dpEl = calendarDatepicker.value; - - dpEl.style.display = 'block'; - dpEl.style.position = 'fixed'; - dpEl.style.top = `${rect.bottom + window.scrollY}px`; - dpEl.style.left = `${rect.left + window.scrollX}px`; - dpEl.style.transform = 'translate(-50%, -50%)'; - dpEl.style.zIndex = '9999'; - dpEl.style.border = 'none'; - dpEl.style.outline = 'none'; - dpEl.style.backgroundColor = 'transparent'; - // 제목의 중앙 아래에 위치하도록 계산 - // 또는 CSS transform 사용 - // dpEl.style.setProperty('--left-position', `${rect.left + window.scrollX}px`); - // dpEl.style.transform = 'translateX(-50%)'; - fpInstance.open(); - }); + datePickerStore.initDatePicker( + fullCalendarRef, + async (year, month, options) => { + // 데이터 다시 불러오기 + await fetchData(); } - }); + ); }); diff --git a/src/stores/useDatePicker.js b/src/stores/useDatePicker.js new file mode 100644 index 0000000..46eef0f --- /dev/null +++ b/src/stores/useDatePicker.js @@ -0,0 +1,95 @@ +/* + 작성자 : 박지윤 + 작성일 : 2025-03-25 + 수정자 : + 수정일 : + 설명 : 달력 데이트 피커 +*/ + +import { ref } from 'vue'; +import flatpickr from 'flatpickr'; +import monthSelectPlugin from 'flatpickr/dist/plugins/monthSelect/index'; +import 'flatpickr/dist/flatpickr.min.css'; +import 'flatpickr/dist/plugins/monthSelect/style.css'; + +export function useDatePicker() { + let fpInstance = null; + const calendarDatepicker = ref(null); + + const initDatePicker = (fullCalendarRef, onDateChange, options = {}) => { + // input 요소 동적 생성 + const datePickerInput = document.createElement('input'); + datePickerInput.type = 'text'; + datePickerInput.style.display = 'none'; + document.body.appendChild(datePickerInput); + calendarDatepicker.value = datePickerInput; + + // Flatpickr 초기화 + fpInstance = flatpickr(calendarDatepicker.value, { + dateFormat: "Y-m", + plugins: [ + new monthSelectPlugin({ + shorthand: true, + dateFormat: "Y-m", + altFormat: "F Y" + }) + ], + onOpen: function() { + document.querySelector('.flatpickr-input').style.visibility = 'hidden'; + }, + onChange: function(selectedDatesArr, dateStr) { + // 선택한 달의 첫날로 달력을 이동 + if (fullCalendarRef.value) { + fullCalendarRef.value.getApi().gotoDate(dateStr + "-01"); + } + + const [year, month] = dateStr.split("-"); + + // onDateChange가 함수인 경우에만 호출 + if (typeof onDateChange === 'function') { + onDateChange(parseInt(year, 10), month, options); + } + }, + onClose: function() { + if (calendarDatepicker.value) { + calendarDatepicker.value.style.display = "none"; + } + }, + ...options + }); + + // FullCalendar 년월월(.fc-toolbar-title) 클릭 시 데이트피커 열기 + const titleEl = document.querySelector('.fc-toolbar-title'); + if (titleEl) { + titleEl.style.cursor = 'pointer'; + titleEl.addEventListener('click', () => { + const rect = titleEl.getBoundingClientRect(); + const dpEl = calendarDatepicker.value; + + dpEl.style.display = 'block'; + dpEl.style.position = 'fixed'; + dpEl.style.top = `${rect.bottom + window.scrollY}px`; + dpEl.style.left = `${rect.left + window.scrollX}px`; + dpEl.style.transform = 'translate(-50%, -50%)'; + dpEl.style.zIndex = '9999'; + dpEl.style.border = 'none'; + dpEl.style.outline = 'none'; + dpEl.style.backgroundColor = 'transparent'; + + fpInstance.open(); + }); + } + }; + + const closeDatePicker = () => { + if (fpInstance) { + fpInstance.close(); + } + }; + + return { + initDatePicker, + closeDatePicker, + calendarDatepicker + }; +}