import { create } from 'zustand'; interface TourState { currentTour: any; legs: any[]; publicTours: any[]; userRole: string | null; activeLegId: string | null; mapCenter: [number, number]; setTour: (tour: any) => void; updateLegs: (legs: any[]) => void; createTour: (tourData: any) => Promise; updateTour: (id: string, data: any) => Promise; deleteTour: (id: string) => Promise; addLeg: (tourId: string, data: any) => Promise; initializeLegs: (tourId: string, count: number) => Promise; updateLeg: (legId: string, data: any) => Promise; deleteLeg: (legId: string) => Promise; addLocation: (tourId: string, locationData: any) => Promise; updateLocation: (locationId: string, data: any) => Promise; deleteLocation: (locationId: string) => Promise; updateTourStartPoint: (tourId: string, data: any) => Promise; updateTourEndPoint: (tourId: string, data: any) => Promise; optimizeRouting: (legId: string) => Promise; addMember: (tourId: string, member: { userId: string; role?: string }) => Promise; setActiveLegId: (id: string | null) => void; setMapCenter: (pos: [number, number]) => void; fetchTour: (id: string) => Promise; fetchPublicTours: () => Promise; } export const useTourStore = create((set, get) => ({ currentTour: null, legs: [], publicTours: [], userRole: null, activeLegId: null, mapCenter: [10.7769, 106.7009], setTour: (tour) => set({ currentTour: tour }), updateLegs: (legs) => set({ legs }), setActiveLegId: (id) => set({ activeLegId: id }), setMapCenter: (pos) => set({ mapCenter: pos }), fetchTour: async (id: string) => { const API_BASE = `http://${window.location.hostname}:3001`; const token = localStorage.getItem('token'); try { const response = await fetch(`${API_BASE}/api/v1/tours/${id}`, { headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); // ...existing role detection... let role = 'VIEWER_ONLY'; if (token) { try { const payload = JSON.parse(atob(token.split('.')[1])); const currentUserId = payload.sub; const participant = data.participants?.find((p: any) => p.userId === currentUserId); if (participant) role = participant.role; } catch (e) { console.error("Lỗi khi xác định vai trò người dùng:", e); } } const legs = data.legs || []; set({ currentTour: data, legs, userRole: role, activeLegId: legs.length > 0 ? legs[0].id : null }); } catch (err: any) { console.error('Không thể tải tour:', err); // Không set null để tránh flash trắng; giữ nguyên state cũ nếu có } }, fetchPublicTours: async () => { const API_BASE = `http://${window.location.hostname}:3001`; const token = localStorage.getItem('token'); if (!token) return; const response = await fetch(`${API_BASE}/api/v1/tours/explore`, { headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) return; const data = await response.json(); set({ publicTours: data }); }, createTour: async (tourData: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(tourData), }); return await response.json(); }, updateTour: async (id: string, data: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Lỗi khi cập nhật Tour'); // Làm mới danh sách khám phá get().fetchPublicTours(); }, deleteTour: async (id: string) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }, }); if (!response.ok) { const data = await response.json(); throw new Error(data.message || 'Lỗi khi xóa Tour'); } // Reset tour hiện tại nếu đang xem đúng tour vừa xóa if (get().currentTour?.id === id) set({ currentTour: null }); get().fetchPublicTours(); }, addLeg: async (tourId: string, data: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/legs`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Lỗi khi thêm chặng'); get().fetchTour(tourId); }, initializeLegs: async (tourId: string, count: number) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/legs/batch`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify({ count }), }); if (!response.ok) throw new Error('Lỗi khi khởi tạo chặng'); await get().fetchTour(tourId); }, updateLeg: async (legId: string, data: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/legs/${legId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Lỗi khi cập nhật chặng'); const { currentTour } = get(); if (currentTour) get().fetchTour(currentTour.id); }, deleteLeg: async (legId: string) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/legs/${legId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }, }); const result = await response.json(); if (!response.ok) { throw new Error(result.message || 'Lỗi khi xóa chặng'); } const { currentTour } = get(); if (currentTour) get().fetchTour(currentTour.id); }, addLocation: async (tourId: string, locationData: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/locations`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(locationData), }); if (!response.ok) throw new Error('Lỗi khi thêm địa điểm'); // Làm mới dữ liệu tour hiện tại get().fetchTour(tourId); }, updateLocation: async (locationId: string, data: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/locations/${locationId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Lỗi khi cập nhật địa điểm'); const { currentTour } = get(); if (currentTour) get().fetchTour(currentTour.id); }, deleteLocation: async (locationId: string) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/locations/${locationId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }, }); if (!response.ok) throw new Error('Lỗi khi xóa địa điểm'); const { currentTour } = get(); if (currentTour) get().fetchTour(currentTour.id); }, updateTourStartPoint: async (tourId: string, data: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/start-point`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data), }); console.log(`[STORE] updateTourStartPoint API Status: ${response.status}`); if (!response.ok) throw new Error('Lỗi khi thiết lập điểm bắt đầu'); await get().fetchTour(tourId); }, updateTourEndPoint: async (tourId: string, data: any) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/end-point`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Lỗi khi thiết lập điểm kết thúc'); await get().fetchTour(tourId); }, optimizeRouting: async (legId: string) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/routing/optimize/${legId}`, { method: 'POST' }); const { locations, totalDistance } = await response.json(); const { currentTour } = get(); if (currentTour) { const updatedLegs = currentTour.legs.map((l: any) => l.id === legId ? { ...l, locations: locations, totalDistance: totalDistance } : l ); set({ currentTour: { ...currentTour, legs: updatedLegs }, legs: updatedLegs }); } }, addMember: async (tourId: string, member: { userId: string; role?: string }) => { const API_BASE = `http://${window.location.hostname}:3001`; const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/members`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(member), }); if (!response.ok) throw new Error('Lỗi khi thêm thành viên'); const { currentTour } = get(); if (currentTour) get().fetchTour(currentTour.id); }, }));