✨ 주요 변경사항: - 프로젝트 이름: kumamoto-travel-planner → travel-planner - 버전 업그레이드: v1.0.0 → v2.0.0 - 멀티유저 시스템 구현 (JWT 인증) - PostgreSQL 마이그레이션 시스템 추가 - Docker 컨테이너 이름 변경 - UI 브랜딩 업데이트 (Travel Planner) - API 서버 및 인증 시스템 추가 - 여행 공유 기능 구현 - 템플릿 시스템 추가 🔧 기술 스택: - Frontend: React + TypeScript + Vite - Backend: Node.js + Express + JWT - Database: PostgreSQL + 마이그레이션 - Infrastructure: Docker + Docker Compose 🌟 새로운 기능: - 사용자 인증 및 권한 관리 - 다중 여행 계획 관리 - 여행 템플릿 시스템 - 공유 링크 및 댓글 시스템 - 관리자 대시보드
99 lines
2.7 KiB
TypeScript
99 lines
2.7 KiB
TypeScript
import { TravelPlan, BasePoint } from '../types'
|
|
|
|
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'
|
|
|
|
// 여행 계획 API
|
|
export const travelPlanAPI = {
|
|
// 여행 계획 조회
|
|
async get(): Promise<TravelPlan | null> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/travel-plans`)
|
|
if (!response.ok) throw new Error('Failed to fetch travel plan')
|
|
const data = await response.json()
|
|
|
|
if (!data) return null
|
|
|
|
// Date 객체로 변환
|
|
return {
|
|
...data,
|
|
startDate: new Date(data.startDate),
|
|
endDate: new Date(data.endDate),
|
|
schedule: data.schedule.map((day: any) => ({
|
|
...day,
|
|
date: new Date(day.date),
|
|
})),
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching travel plan:', error)
|
|
// API 서버가 없으면 null 반환 (기본 데이터 사용)
|
|
return null
|
|
}
|
|
},
|
|
|
|
// 여행 계획 저장
|
|
async save(travelPlan: TravelPlan): Promise<void> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/travel-plans`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(travelPlan),
|
|
})
|
|
|
|
if (!response.ok) throw new Error('Failed to save travel plan')
|
|
} catch (error) {
|
|
console.error('Error saving travel plan:', error)
|
|
// API 서버가 없으면 무시 (로컬 상태만 사용)
|
|
}
|
|
},
|
|
}
|
|
|
|
// 기본 포인트 API
|
|
export const basePointsAPI = {
|
|
// 모든 기본 포인트 조회
|
|
async getAll(): Promise<BasePoint[]> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/base-points`)
|
|
if (!response.ok) throw new Error('Failed to fetch base points')
|
|
return await response.json()
|
|
} catch (error) {
|
|
console.error('Error fetching base points:', error)
|
|
throw error
|
|
}
|
|
},
|
|
|
|
// 기본 포인트 추가
|
|
async create(basePoint: Omit<BasePoint, 'id'>): Promise<BasePoint> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/base-points`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(basePoint),
|
|
})
|
|
|
|
if (!response.ok) throw new Error('Failed to create base point')
|
|
return await response.json()
|
|
} catch (error) {
|
|
console.error('Error creating base point:', error)
|
|
throw error
|
|
}
|
|
},
|
|
|
|
// 기본 포인트 삭제
|
|
async delete(id: string): Promise<void> {
|
|
try {
|
|
const response = await fetch(`${API_URL}/api/base-points/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
|
|
if (!response.ok) throw new Error('Failed to delete base point')
|
|
} catch (error) {
|
|
console.error('Error deleting base point:', error)
|
|
throw error
|
|
}
|
|
},
|
|
}
|