- 📱 PWA 지원: 홈화면 추가 가능한 Progressive Web App - 🎨 M-Project 색상 스키마: 하늘색, 주황색, 회색, 흰색 일관된 디자인 - 📊 대시보드: 데스크톱 캘린더 뷰 + 모바일 일일 뷰 반응형 디자인 - 📥 분류 센터: Gmail 스타일 받은편지함으로 스마트 분류 시스템 - 🤖 AI 분류 제안: 키워드 기반 자동 분류 제안 및 일괄 처리 - 📷 업로드 모달: 데스크톱(파일 선택) + 모바일(카메라/갤러리) 최적화 - 🏷️ 3가지 분류: Todo(시작일), 캘린더(마감일), 체크리스트(무기한) - 📋 체크리스트: 진행률 표시 및 완료 토글 기능 - 🔄 시놀로지 연동 준비: 메일플러스 연동을 위한 구조 설계 - 📱 반응형 UI: 모든 페이지 모바일 최적화 완료
166 lines
4.1 KiB
JavaScript
166 lines
4.1 KiB
JavaScript
/**
|
|
* API 통신 유틸리티
|
|
*/
|
|
|
|
const API_BASE_URL = 'http://localhost:9000/api';
|
|
|
|
class ApiClient {
|
|
constructor() {
|
|
this.token = localStorage.getItem('authToken');
|
|
}
|
|
|
|
async request(endpoint, options = {}) {
|
|
const url = `${API_BASE_URL}${endpoint}`;
|
|
const config = {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...options.headers
|
|
},
|
|
...options
|
|
};
|
|
|
|
// 인증 토큰 추가
|
|
if (this.token) {
|
|
config.headers['Authorization'] = `Bearer ${this.token}`;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(url, config);
|
|
|
|
if (!response.ok) {
|
|
if (response.status === 401) {
|
|
// 토큰 만료 시 로그아웃
|
|
this.logout();
|
|
throw new Error('인증이 만료되었습니다. 다시 로그인해주세요.');
|
|
}
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const contentType = response.headers.get('content-type');
|
|
if (contentType && contentType.includes('application/json')) {
|
|
return await response.json();
|
|
}
|
|
return await response.text();
|
|
} catch (error) {
|
|
console.error('API 요청 실패:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// GET 요청
|
|
async get(endpoint) {
|
|
return this.request(endpoint, { method: 'GET' });
|
|
}
|
|
|
|
// POST 요청
|
|
async post(endpoint, data) {
|
|
return this.request(endpoint, {
|
|
method: 'POST',
|
|
body: JSON.stringify(data)
|
|
});
|
|
}
|
|
|
|
// PUT 요청
|
|
async put(endpoint, data) {
|
|
return this.request(endpoint, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data)
|
|
});
|
|
}
|
|
|
|
// DELETE 요청
|
|
async delete(endpoint) {
|
|
return this.request(endpoint, { method: 'DELETE' });
|
|
}
|
|
|
|
// 파일 업로드
|
|
async uploadFile(endpoint, formData) {
|
|
return this.request(endpoint, {
|
|
method: 'POST',
|
|
headers: {
|
|
// Content-Type을 설정하지 않음 (FormData가 자동으로 설정)
|
|
},
|
|
body: formData
|
|
});
|
|
}
|
|
|
|
// 토큰 설정
|
|
setToken(token) {
|
|
this.token = token;
|
|
localStorage.setItem('authToken', token);
|
|
}
|
|
|
|
// 로그아웃
|
|
logout() {
|
|
this.token = null;
|
|
localStorage.removeItem('authToken');
|
|
localStorage.removeItem('currentUser');
|
|
window.location.reload();
|
|
}
|
|
}
|
|
|
|
// 전역 API 클라이언트 인스턴스
|
|
const api = new ApiClient();
|
|
|
|
// 인증 관련 API
|
|
const AuthAPI = {
|
|
async login(username, password) {
|
|
const response = await api.post('/auth/login', {
|
|
username,
|
|
password
|
|
});
|
|
|
|
if (response.access_token) {
|
|
api.setToken(response.access_token);
|
|
localStorage.setItem('currentUser', JSON.stringify(response.user));
|
|
}
|
|
|
|
return response;
|
|
},
|
|
|
|
async logout() {
|
|
try {
|
|
await api.post('/auth/logout');
|
|
} catch (error) {
|
|
console.error('로그아웃 API 호출 실패:', error);
|
|
} finally {
|
|
api.logout();
|
|
}
|
|
},
|
|
|
|
async getCurrentUser() {
|
|
return api.get('/auth/me');
|
|
}
|
|
};
|
|
|
|
// Todo 관련 API
|
|
const TodoAPI = {
|
|
async getTodos(filter = 'all') {
|
|
const params = filter !== 'all' ? `?status=${filter}` : '';
|
|
return api.get(`/todos${params}`);
|
|
},
|
|
|
|
async createTodo(todoData) {
|
|
return api.post('/todos', todoData);
|
|
},
|
|
|
|
async updateTodo(id, todoData) {
|
|
return api.put(`/todos/${id}`, todoData);
|
|
},
|
|
|
|
async deleteTodo(id) {
|
|
return api.delete(`/todos/${id}`);
|
|
},
|
|
|
|
async uploadImage(imageFile) {
|
|
const formData = new FormData();
|
|
formData.append('image', imageFile);
|
|
return api.uploadFile('/todos/upload-image', formData);
|
|
}
|
|
};
|
|
|
|
// 전역으로 사용 가능하도록 export
|
|
window.api = api;
|
|
window.AuthAPI = AuthAPI;
|
|
window.TodoAPI = TodoAPI;
|