Sửa lỗi người nhận được liên kết chia sẻ không xem được nội dung Tour
This commit is contained in:
Vendored
+45
-36
@@ -157,6 +157,49 @@ AuthController = __decorate([
|
||||
(0, common_1.Controller)('auth'),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService, jwt_1.JwtService])
|
||||
], AuthController);
|
||||
let PublicTourController = class PublicTourController {
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
}
|
||||
async getPublicTourDetails(id) {
|
||||
const tour = await this.prisma.tour.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
participants: {
|
||||
include: {
|
||||
user: {
|
||||
select: { id: true, name: true, email: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
photos: true,
|
||||
legs: {
|
||||
orderBy: { sequence: 'asc' },
|
||||
include: {
|
||||
locations: {
|
||||
orderBy: { plannedStart: 'asc' },
|
||||
include: { _count: { select: { comments: true } } }
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!tour)
|
||||
throw new common_1.NotFoundException(`Không tìm thấy Tour`);
|
||||
return tour;
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
(0, common_1.Get)(':id/public'),
|
||||
__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], PublicTourController.prototype, "getPublicTourDetails", null);
|
||||
PublicTourController = __decorate([
|
||||
(0, common_1.Controller)('tours'),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], PublicTourController);
|
||||
let TourController = class TourController {
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
@@ -374,33 +417,6 @@ let TourController = class TourController {
|
||||
}
|
||||
});
|
||||
}
|
||||
async getPublicTourDetails(id) {
|
||||
const tour = await this.prisma.tour.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
participants: {
|
||||
include: {
|
||||
user: {
|
||||
select: { id: true, name: true, email: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
photos: true,
|
||||
legs: {
|
||||
orderBy: { sequence: 'asc' },
|
||||
include: {
|
||||
locations: {
|
||||
orderBy: { plannedStart: 'asc' },
|
||||
include: { _count: { select: { comments: true } } }
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!tour)
|
||||
throw new common_1.NotFoundException(`Không tìm thấy Tour`);
|
||||
return tour;
|
||||
}
|
||||
async getTourDetails(id) {
|
||||
const tour = await this.prisma.tour.findUnique({
|
||||
where: { id },
|
||||
@@ -677,13 +693,6 @@ __decorate([
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TourController.prototype, "getPublicTours", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)(':id/public'),
|
||||
__param(0, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TourController.prototype, "getPublicTourDetails", null);
|
||||
__decorate([
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard, rbac_middleware_1.TourRoleGuard),
|
||||
(0, common_1.Get)(':id'),
|
||||
@@ -1131,6 +1140,7 @@ __decorate([
|
||||
__metadata("design:returntype", Promise)
|
||||
], CommentController.prototype, "getComments", null);
|
||||
__decorate([
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, common_1.Post)(':locationId/comments'),
|
||||
__param(0, (0, common_1.Param)('locationId', common_1.ParseUUIDPipe)),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
@@ -1141,7 +1151,6 @@ __decorate([
|
||||
], CommentController.prototype, "addComment", null);
|
||||
CommentController = __decorate([
|
||||
(0, common_1.Controller)('locations'),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
|
||||
CommentGateway])
|
||||
], CommentController);
|
||||
@@ -1155,7 +1164,7 @@ AppModule = __decorate([
|
||||
signOptions: { expiresIn: '1d' },
|
||||
}),
|
||||
],
|
||||
controllers: [AppController, AuthController, TourController, UserController, RoutingController, LegController, LocationController, CommentController],
|
||||
controllers: [AppController, AuthController, PublicTourController, TourController, UserController, RoutingController, LegController, LocationController, CommentController],
|
||||
providers: [prisma_service_1.PrismaService, jwt_strategy_1.JwtStrategy, rbac_middleware_1.TourRoleGuard, jwt_auth_guard_1.JwtAuthGuard, admin_guard_1.AdminGuard, CommentGateway],
|
||||
exports: [prisma_service_1.PrismaService]
|
||||
})
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+37
-31
@@ -103,6 +103,40 @@ class AuthController {
|
||||
}
|
||||
}
|
||||
|
||||
@Controller('tours') // Controller mới để xử lý các tour công khai
|
||||
class PublicTourController {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
@Get(':id/public')
|
||||
async getPublicTourDetails(@Param('id', ParseUUIDPipe) id: string) {
|
||||
const tour = await this.prisma.tour.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
participants: {
|
||||
include: {
|
||||
user: {
|
||||
select: { id: true, name: true, email: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
photos: true,
|
||||
legs: {
|
||||
orderBy: { sequence: 'asc' },
|
||||
include: {
|
||||
locations: {
|
||||
orderBy: { plannedStart: 'asc' },
|
||||
include: { _count: { select: { comments: true } } }
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!tour) throw new NotFoundException(`Không tìm thấy Tour`);
|
||||
return tour;
|
||||
}
|
||||
}
|
||||
|
||||
@Controller('tours')
|
||||
class TourController {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
@@ -376,35 +410,6 @@ class TourController {
|
||||
});
|
||||
}
|
||||
|
||||
@Get(':id/public')
|
||||
async getPublicTourDetails(@Param('id', ParseUUIDPipe) id: string) {
|
||||
const tour = await this.prisma.tour.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
participants: {
|
||||
include: {
|
||||
user: {
|
||||
select: { id: true, name: true, email: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
photos: true,
|
||||
legs: {
|
||||
orderBy: { sequence: 'asc' },
|
||||
include: {
|
||||
locations: {
|
||||
orderBy: { plannedStart: 'asc' },
|
||||
include: { _count: { select: { comments: true } } }
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!tour) throw new NotFoundException(`Không tìm thấy Tour`);
|
||||
return tour;
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard, TourRoleGuard)
|
||||
@Get(':id')
|
||||
async getTourDetails(@Param('id', ParseUUIDPipe) id: string) {
|
||||
@@ -933,7 +938,6 @@ export class CommentGateway implements OnGatewayConnection {
|
||||
}
|
||||
|
||||
@Controller('locations')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
class CommentController {
|
||||
constructor(
|
||||
private prisma: PrismaService,
|
||||
@@ -941,6 +945,7 @@ class CommentController {
|
||||
) {}
|
||||
|
||||
@Get(':locationId/comments')
|
||||
// Cho phép khách xem bình luận mà không cần đăng nhập
|
||||
async getComments(@Param('locationId', ParseUUIDPipe) locationId: string) {
|
||||
return this.prisma.comment.findMany({
|
||||
where: { locationId },
|
||||
@@ -951,6 +956,7 @@ class CommentController {
|
||||
});
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post(':locationId/comments')
|
||||
async addComment(
|
||||
@Param('locationId', ParseUUIDPipe) locationId: string,
|
||||
@@ -990,7 +996,7 @@ class CommentController {
|
||||
signOptions: { expiresIn: '1d' },
|
||||
}) as any,
|
||||
],
|
||||
controllers: [AppController, AuthController, TourController, UserController, RoutingController, LegController, LocationController, CommentController],
|
||||
controllers: [AppController, AuthController, PublicTourController, TourController, UserController, RoutingController, LegController, LocationController, CommentController],
|
||||
providers: [PrismaService, JwtStrategy, TourRoleGuard, JwtAuthGuard, AdminGuard, CommentGateway],
|
||||
exports: [PrismaService]
|
||||
})
|
||||
|
||||
+86
-69
@@ -1,88 +1,105 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { LandingPage } from '@/pages/LandingPage';
|
||||
import { TourDetailPage } from '@/pages/TourDetailPage';
|
||||
import { ExploreMap } from '@/pages/ExploreMap';
|
||||
import { SignupPage } from '@/pages/SignupPage';
|
||||
import { useTourStore } from '@/store/useTourStore';
|
||||
import { LandingPage } from './pages/LandingPage';
|
||||
import { ExploreMap } from './pages/ExploreMap';
|
||||
import { TourDetailPage } from './pages/TourDetailPage';
|
||||
import { SignupPage } from './pages/SignupPage';
|
||||
import { useTourStore } from './store/useTourStore';
|
||||
|
||||
function App() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const viewTourId = params.get('viewTour');
|
||||
|
||||
const App = () => {
|
||||
type View = 'landing' | 'explore' | 'detail' | 'signup';
|
||||
const [view, setView] = useState<View>('landing');
|
||||
const [isInitialSetup, setIsInitialSetup] = useState(false);
|
||||
const [user, setUser] = useState<any>(null);
|
||||
const [isUserLoaded, setIsUserLoaded] = useState(false); // Trạng thái để biết user đã được load từ localStorage chưa
|
||||
const [currentPage, setCurrentPage] = useState<'landing' | 'explore' | 'tourDetail' | 'signup'>(viewTourId ? 'tourDetail' : 'landing');
|
||||
const [currentTourId, setCurrentTourId] = useState<string | null>(viewTourId);
|
||||
const [isPublicTourView, setIsPublicTourView] = useState(!!viewTourId);
|
||||
|
||||
// Lấy action từ store
|
||||
const fetchTour = useTourStore(state => state.fetchTour);
|
||||
const fetchPublicTourDetails = useTourStore(state => state.fetchPublicTourDetails);
|
||||
|
||||
useEffect(() => {
|
||||
// Khôi phục phiên đăng nhập từ localStorage
|
||||
const savedUser = localStorage.getItem('user');
|
||||
if (savedUser) {
|
||||
const parsedUser = JSON.parse(savedUser);
|
||||
setUser(parsedUser);
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const viewTourId = params.get('viewTour');
|
||||
|
||||
if (viewTourId) {
|
||||
// Không gọi replaceState ngay để tránh mất ID khi component re-render hoặc refresh
|
||||
} else {
|
||||
// Kiểm tra đăng nhập bình thường nếu không có tham số viewTour
|
||||
const token = localStorage.getItem('token');
|
||||
const storedUser = localStorage.getItem('user');
|
||||
if (token && storedUser) {
|
||||
try {
|
||||
setUser(JSON.parse(storedUser));
|
||||
setCurrentPage('explore'); // Chuyển đến bản đồ khám phá nếu đã đăng nhập
|
||||
} catch (e) {
|
||||
console.error("Lỗi khi phân tích dữ liệu người dùng từ localStorage", e);
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
setCurrentPage('landing'); // Quay về trang Landing nếu dữ liệu lỗi
|
||||
}
|
||||
} else {
|
||||
setCurrentPage('landing'); // Quay về trang Landing nếu chưa đăng nhập
|
||||
}
|
||||
}
|
||||
setIsUserLoaded(true); // Đánh dấu user đã được load
|
||||
}, []); // Chỉ chạy một lần khi component mount
|
||||
|
||||
// Kiểm tra xem hệ thống đã được cài đặt chưa
|
||||
fetch(`/api/v1/auth/status`)
|
||||
.then(res => res.ok ? res.json() : Promise.reject())
|
||||
.then(data => setIsInitialSetup(!!data.isInitialSetup))
|
||||
.catch(() => setIsInitialSetup(false));
|
||||
}, []); // Chạy một lần khi component mount
|
||||
|
||||
// Effect để xử lý chuyển hướng nếu user đã đăng nhập và đang ở trang landing
|
||||
useEffect(() => {
|
||||
if (isUserLoaded && user && view === 'landing') {
|
||||
setView('explore');
|
||||
}
|
||||
}, [isUserLoaded, user, view]);
|
||||
|
||||
const handleLoginSuccess = (userData: any) => {
|
||||
setUser(userData);
|
||||
const handleLoginSuccess = (loggedInUser: any) => {
|
||||
setUser(loggedInUser);
|
||||
setCurrentPage('explore');
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
localStorage.removeItem('user');
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
setUser(null);
|
||||
setView('landing');
|
||||
setCurrentPage('landing');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app-container">
|
||||
{view === 'landing' && (
|
||||
<LandingPage
|
||||
isInitialSetup={isInitialSetup}
|
||||
onContinue={() => setView('explore')}
|
||||
onGoToSignup={() => setView('signup')}
|
||||
onGoToMap={() => setView('explore')}
|
||||
onLoginSuccess={handleLoginSuccess}
|
||||
/>
|
||||
)}
|
||||
const handleViewTour = (tourId: string) => {
|
||||
setCurrentTourId(tourId);
|
||||
setIsPublicTourView(false); // Không phải chế độ công khai nếu đến từ bản đồ khám phá
|
||||
setCurrentPage('tourDetail');
|
||||
};
|
||||
|
||||
{view === 'signup' && (
|
||||
<SignupPage
|
||||
onBack={() => setView('landing')}
|
||||
onSuccess={() => setView('landing')}
|
||||
/>
|
||||
)}
|
||||
|
||||
{view === 'explore' && (
|
||||
<ExploreMap
|
||||
onBack={() => setView('landing')}
|
||||
onLogout={user ? handleLogout : undefined}
|
||||
user={user}
|
||||
onViewTour={(id) => {
|
||||
fetchTour(id);
|
||||
setView('detail');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
const handleBackFromTourDetail = () => {
|
||||
setCurrentTourId(null);
|
||||
setIsPublicTourView(false);
|
||||
// Quay về trang khám phá nếu đã đăng nhập, ngược lại quay về Landing
|
||||
if (user) {
|
||||
setCurrentPage('explore');
|
||||
} else {
|
||||
setCurrentPage('landing');
|
||||
}
|
||||
};
|
||||
|
||||
{view === 'detail' && (
|
||||
<TourDetailPage onBack={() => setView('explore')} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const handleBackFromSignup = () => {
|
||||
setCurrentPage('landing');
|
||||
};
|
||||
|
||||
const handleSignupSuccess = () => {
|
||||
setCurrentPage('landing'); // Quay về trang Landing sau khi đăng ký thành công
|
||||
};
|
||||
|
||||
if (currentPage === 'tourDetail') {
|
||||
return (
|
||||
<TourDetailPage
|
||||
tourId={currentTourId!} // tourId được đảm bảo không null ở đây
|
||||
onBack={handleBackFromTourDetail}
|
||||
isPublicView={isPublicTourView}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (currentPage === 'explore') {
|
||||
return <ExploreMap onBack={handleBackFromTourDetail} onLogout={handleLogout} user={user} onViewTour={handleViewTour} />;
|
||||
}
|
||||
|
||||
if (currentPage === 'signup') {
|
||||
return <SignupPage onBack={handleBackFromSignup} onSuccess={handleSignupSuccess} />;
|
||||
}
|
||||
|
||||
return <LandingPage onContinue={() => setCurrentPage('explore')} onGoToSignup={() => setCurrentPage('signup')} onGoToMap={() => setCurrentPage('explore')} onLoginSuccess={handleLoginSuccess} isInitialSetup={false} />;
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -26,8 +26,12 @@ export const CommentModal: React.FC<CommentModalProps> = ({ isOpen, onClose, loc
|
||||
const fetchComments = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
const headers: Record<string, string> = {};
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||||
|
||||
const res = await fetch(`/api/v1/locations/${locationId}/comments`, {
|
||||
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
|
||||
headers
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
|
||||
@@ -240,7 +240,7 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
|
||||
const canEdit = isPublicView ? false : ['OWNER', 'MANAGER'].includes(userRole || '');
|
||||
const canInvite = isPublicView ? false : ['OWNER', 'MANAGER', 'MEMBER'].includes(userRole || '');
|
||||
const isOwner = isPublicView ? false : userRole === 'OWNER';
|
||||
const canShare = ['OWNER', 'MANAGER', 'MEMBER'].includes(userRole || '');
|
||||
const canShare = isPublicView || ['OWNER', 'MANAGER', 'MEMBER'].includes(userRole || '');
|
||||
|
||||
useEffect(() => {
|
||||
if (isPublicView) {
|
||||
|
||||
@@ -28,6 +28,7 @@ interface TourState {
|
||||
setActiveLegId: (id: string | null) => void;
|
||||
setMapCenter: (pos: [number, number]) => void;
|
||||
fetchTour: (id: string) => Promise<void>;
|
||||
fetchPublicTourDetails: (tourId: string) => Promise<void>;
|
||||
fetchPublicTours: () => Promise<void>;
|
||||
createJoinRequest: (tourId: string, userId?: string) => Promise<any>;
|
||||
fetchJoinRequests: (tourId: string) => Promise<any[]>;
|
||||
@@ -47,10 +48,9 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
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}`, {
|
||||
const response = await fetch(`/api/v1/tours/${id}`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
@@ -75,11 +75,10 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
}
|
||||
},
|
||||
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`, {
|
||||
const response = await fetch(`/api/v1/tours/explore`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
@@ -89,9 +88,27 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
const data = await response.json();
|
||||
set({ publicTours: data });
|
||||
},
|
||||
fetchPublicTourDetails: async (tourId: string) => {
|
||||
try {
|
||||
// Reset state cũ trước khi tải dữ liệu mới
|
||||
set({ currentTour: null, legs: [], userRole: 'VIEWER_ONLY' });
|
||||
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/public`);
|
||||
if (!response.ok) throw new Error('Không thể tải tour công khai');
|
||||
const data = await response.json();
|
||||
const legs = data.legs || [];
|
||||
set({
|
||||
currentTour: data,
|
||||
legs,
|
||||
userRole: 'VIEWER_ONLY',
|
||||
activeLegId: legs.length > 0 ? legs[0].id : null
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error('Lỗi khi tải tour công khai:', err);
|
||||
}
|
||||
},
|
||||
createTour: async (tourData: any) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours`, {
|
||||
const response = await fetch(`/api/v1/tours`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -108,9 +125,8 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
return tour;
|
||||
},
|
||||
updateTourDetails: async (tourId: string, data: any) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const token = localStorage.getItem('token');
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -125,8 +141,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
}
|
||||
},
|
||||
updateTour: async (id: string, data: any) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${id}`, {
|
||||
const response = await fetch(`/api/v1/tours/${id}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -140,8 +155,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
get().fetchPublicTours();
|
||||
},
|
||||
deleteTour: async (id: string) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${id}`, {
|
||||
const response = await fetch(`/api/v1/tours/${id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||||
@@ -157,8 +171,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
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`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/legs`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -170,8 +183,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
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`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/legs/batch`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -183,8 +195,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
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}`, {
|
||||
const response = await fetch(`/api/v1/legs/${legId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -198,8 +209,7 @@ export const useTourStore = create<TourState>((set, 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}`, {
|
||||
const response = await fetch(`/api/v1/legs/${legId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||||
@@ -214,8 +224,7 @@ export const useTourStore = create<TourState>((set, 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`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/locations`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -228,8 +237,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
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}`, {
|
||||
const response = await fetch(`/api/v1/locations/${locationId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -243,8 +251,7 @@ export const useTourStore = create<TourState>((set, 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}`, {
|
||||
const response = await fetch(`/api/v1/locations/${locationId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||||
@@ -256,8 +263,7 @@ export const useTourStore = create<TourState>((set, 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`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/start-point`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -271,8 +277,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
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`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/end-point`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -284,8 +289,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
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}`, {
|
||||
const response = await fetch(`/api/v1/routing/optimize/${legId}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
const { locations, totalDistance } = await response.json();
|
||||
@@ -299,8 +303,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
}
|
||||
},
|
||||
removeMember: async (tourId: string, userId: string) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/members/${userId}`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/members/${userId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
||||
@@ -311,8 +314,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
if (currentTour) get().fetchTour(currentTour.id);
|
||||
},
|
||||
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`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/members`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -328,8 +330,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
if (currentTour) get().fetchTour(currentTour.id);
|
||||
},
|
||||
createJoinRequest: async (tourId: string, userId?: string) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/join-requests`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/join-requests`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -344,8 +345,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
return response.json();
|
||||
},
|
||||
fetchJoinRequests: async (tourId: string) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/join-requests`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/join-requests`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`
|
||||
}
|
||||
@@ -357,8 +357,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
return response.json();
|
||||
},
|
||||
acceptJoinRequest: async (tourId: string, requestId: string) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/join-requests/${requestId}/accept`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/join-requests/${requestId}/accept`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`
|
||||
@@ -372,8 +371,7 @@ export const useTourStore = create<TourState>((set, get) => ({
|
||||
if (currentTour) get().fetchTour(currentTour.id);
|
||||
},
|
||||
rejectJoinRequest: async (tourId: string, requestId: string) => {
|
||||
const API_BASE = `http://${window.location.hostname}:3001`;
|
||||
const response = await fetch(`${API_BASE}/api/v1/tours/${tourId}/join-requests/${requestId}/reject`, {
|
||||
const response = await fetch(`/api/v1/tours/${tourId}/join-requests/${requestId}/reject`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`
|
||||
|
||||
Reference in New Issue
Block a user