Files
brain_dogfood/static/js/AppService.js
T

134 lines
4.5 KiB
JavaScript

/**
* 앱의 전역 상태 및 데이터 관리 엔진 (State Management & Core Services)
*/
import { API } from './api.js';
import { UI } from './ui.js';
import { CalendarManager } from './components/CalendarManager.js';
import { HeatmapManager } from './components/HeatmapManager.js';
export const AppService = {
state: {
memosCache: [],
currentFilterGroup: 'all',
currentFilterCategory: null, // NEW: 카테고리 필터
currentFilterDate: null,
currentSearchQuery: '',
offset: 0,
limit: 20,
hasMore: true,
isLoading: false
},
/**
* 필터 상태 초기화 및 데이터 첫 페이지 로딩
*/
async refreshData(onUpdateSidebar) {
this.state.offset = 0;
this.state.memosCache = [];
this.state.hasMore = true;
this.state.isLoading = false;
// 히트맵 데이터 새로고침
if (HeatmapManager && HeatmapManager.refresh) {
HeatmapManager.refresh();
}
await this.loadMore(onUpdateSidebar, false);
},
/**
* 다음 페이지 데이터를 가져와 병합
*/
async loadMore(onUpdateSidebar, isAppend = true) {
if (this.state.isLoading || !this.state.hasMore) return;
this.state.isLoading = true;
try {
const filters = {
group: this.state.currentFilterGroup,
category: this.state.currentFilterCategory, // NEW
date: this.state.currentFilterDate,
query: this.state.currentSearchQuery,
offset: this.state.offset,
limit: this.state.limit
};
const newMemos = await API.fetchMemos(filters);
if (newMemos.length < this.state.limit) {
this.state.hasMore = false;
}
if (isAppend) {
this.state.memosCache = [...this.state.memosCache, ...newMemos];
} else {
this.state.memosCache = newMemos;
}
window.allMemosCache = this.state.memosCache;
this.state.offset += newMemos.length;
CalendarManager.updateMemoDates(this.state.memosCache);
if (onUpdateSidebar) {
onUpdateSidebar(this.state.memosCache, this.state.currentFilterGroup, this.state.currentFilterCategory);
}
UI.setHasMore(this.state.hasMore);
UI.renderMemos(newMemos, {}, window.memoEventHandlers, isAppend);
} catch (err) {
console.error('[AppService] loadMore failed:', err);
} finally {
this.state.isLoading = false;
}
},
/**
* 필터 상태를 변경하고 데이터 초기화 후 다시 로딩
*/
async setFilter({ group, category, date, query }, onUpdateSidebar) {
let changed = false;
// 1. 그룹 선택 처리
if (group !== undefined) {
// 그룹이 바뀌거나, 혹은 카테고리가 켜져있는 상태에서 그룹을 누르면 카테고리 해제
if (this.state.currentFilterGroup !== group || this.state.currentFilterCategory !== null) {
this.state.currentFilterGroup = group;
this.state.currentFilterCategory = null;
changed = true;
}
}
// 2. 카테고리 선택 처리
if (category !== undefined) {
if (this.state.currentFilterCategory === category) {
// 이미 선택된 카테고리 재클릭 시 해제 (Toggle)
this.state.currentFilterCategory = null;
} else {
this.state.currentFilterCategory = category;
}
this.state.currentFilterGroup = 'all'; // 카테고리 필터 적용/변경 시 그룹 초기화
changed = true;
}
if (date !== undefined && this.state.currentFilterDate !== date) {
this.state.currentFilterDate = date;
changed = true;
CalendarManager.setSelectedDate(date);
if (HeatmapManager.setSelectedDate) {
HeatmapManager.setSelectedDate(date);
}
}
if (query !== undefined && this.state.currentSearchQuery !== query) {
this.state.currentSearchQuery = query;
changed = true;
}
if (changed) {
await this.refreshData(onUpdateSidebar);
}
}
};