Approve tool use
This commit is contained in:
172
src/services/reviewService.ts
Normal file
172
src/services/reviewService.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
import { supabase } from '@/lib/supabase';
|
||||
|
||||
const API_BASE_URL = 'https://karibeo.lesoluciones.net:8443/api';
|
||||
|
||||
export interface Review {
|
||||
id: string;
|
||||
itemId: string;
|
||||
userId: string;
|
||||
userName: string;
|
||||
userAvatar: string;
|
||||
rating: number;
|
||||
comment: string;
|
||||
images: string[];
|
||||
createdAt: string;
|
||||
helpful: number;
|
||||
isHelpful: boolean;
|
||||
replies: ReviewReply[];
|
||||
canReply: boolean;
|
||||
}
|
||||
|
||||
export interface ReviewReply {
|
||||
id: string;
|
||||
authorId: string;
|
||||
authorName: string;
|
||||
authorAvatar: string;
|
||||
content: string;
|
||||
createdAt: string;
|
||||
images?: string[];
|
||||
}
|
||||
|
||||
export interface ReviewStats {
|
||||
average: number;
|
||||
totalRatings: number;
|
||||
totalReviews: number;
|
||||
breakdown: {
|
||||
[key: number]: {
|
||||
count: number;
|
||||
percentage: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class ReviewService {
|
||||
private async getAuthToken(): Promise<string | null> {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
return session?.access_token || null;
|
||||
}
|
||||
|
||||
async getReviews(itemId?: string): Promise<Review[]> {
|
||||
const token = await this.getAuthToken();
|
||||
const url = itemId
|
||||
? `${API_BASE_URL}/reviews?item_id=${itemId}`
|
||||
: `${API_BASE_URL}/reviews`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch reviews');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.map((review: any) => ({
|
||||
id: review.id,
|
||||
itemId: review.item_id,
|
||||
userId: review.user_id,
|
||||
userName: review.user_name || 'Anonymous',
|
||||
userAvatar: review.user_avatar || '',
|
||||
rating: review.rating,
|
||||
comment: review.comment,
|
||||
images: review.images || [],
|
||||
createdAt: new Date(review.created_at).toLocaleString(),
|
||||
helpful: review.helpful_count || 0,
|
||||
isHelpful: review.is_helpful || false,
|
||||
replies: review.replies || [],
|
||||
canReply: true,
|
||||
}));
|
||||
}
|
||||
|
||||
async createReview(data: {
|
||||
itemId: string;
|
||||
rating: number;
|
||||
comment: string;
|
||||
images?: string[];
|
||||
}): Promise<Review> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/reviews`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
item_id: data.itemId,
|
||||
rating: data.rating,
|
||||
comment: data.comment,
|
||||
images: data.images || [],
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to create review');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async createReply(reviewId: string, content: string, images?: string[]): Promise<ReviewReply> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/reviews/${reviewId}/replies`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content,
|
||||
images: images || [],
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to create reply');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async markAsHelpful(reviewId: string): Promise<void> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/reviews/${reviewId}/helpful`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to mark review as helpful');
|
||||
}
|
||||
}
|
||||
|
||||
async getReviewStats(itemId?: string): Promise<ReviewStats> {
|
||||
const token = await this.getAuthToken();
|
||||
const url = itemId
|
||||
? `${API_BASE_URL}/reviews/stats?item_id=${itemId}`
|
||||
: `${API_BASE_URL}/reviews/stats`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch review stats');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
export const reviewService = new ReviewService();
|
||||
226
src/services/tourismService.ts
Normal file
226
src/services/tourismService.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
import { supabase } from '@/lib/supabase';
|
||||
|
||||
const API_BASE_URL = 'https://karibeo.lesoluciones.net:8443/api';
|
||||
|
||||
export interface TourismOffer {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
type: 'tour' | 'activity' | 'experience' | 'package';
|
||||
price: number;
|
||||
currency: string;
|
||||
duration: string;
|
||||
location: string;
|
||||
images: string[];
|
||||
availability: boolean;
|
||||
rating: number;
|
||||
reviewCount: number;
|
||||
includes: string[];
|
||||
excludes: string[];
|
||||
schedule: string;
|
||||
maxParticipants: number;
|
||||
minParticipants: number;
|
||||
category: string;
|
||||
tags: string[];
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface TourismCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
offerCount: number;
|
||||
}
|
||||
|
||||
export interface TourBooking {
|
||||
id: string;
|
||||
offerId: string;
|
||||
offerName: string;
|
||||
date: string;
|
||||
participants: number;
|
||||
totalPrice: number;
|
||||
status: 'pending' | 'confirmed' | 'cancelled' | 'completed';
|
||||
customerInfo: {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
};
|
||||
}
|
||||
|
||||
class TourismService {
|
||||
private async getAuthToken(): Promise<string | null> {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
return session?.access_token || null;
|
||||
}
|
||||
|
||||
async getTourismOffers(filters?: {
|
||||
type?: string;
|
||||
category?: string;
|
||||
minPrice?: number;
|
||||
maxPrice?: number;
|
||||
location?: string;
|
||||
}): Promise<TourismOffer[]> {
|
||||
const token = await this.getAuthToken();
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (filters) {
|
||||
if (filters.type) params.append('type', filters.type);
|
||||
if (filters.category) params.append('category', filters.category);
|
||||
if (filters.minPrice) params.append('min_price', filters.minPrice.toString());
|
||||
if (filters.maxPrice) params.append('max_price', filters.maxPrice.toString());
|
||||
if (filters.location) params.append('location', filters.location);
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/tourism/offers?${params}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch tourism offers');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async getTourismOffer(offerId: string): Promise<TourismOffer> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/tourism/offers/${offerId}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch tourism offer');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async createTourismOffer(data: Partial<TourismOffer>): Promise<TourismOffer> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/tourism/offers`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to create tourism offer');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async updateTourismOffer(offerId: string, data: Partial<TourismOffer>): Promise<TourismOffer> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/tourism/offers/${offerId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to update tourism offer');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async deleteTourismOffer(offerId: string): Promise<void> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/tourism/offers/${offerId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to delete tourism offer');
|
||||
}
|
||||
}
|
||||
|
||||
async getCategories(): Promise<TourismCategory[]> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/tourism/categories`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch categories');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async createTourBooking(data: {
|
||||
offerId: string;
|
||||
date: string;
|
||||
participants: number;
|
||||
customerInfo: {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
};
|
||||
}): Promise<TourBooking> {
|
||||
const token = await this.getAuthToken();
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/tourism/bookings`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to create booking');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async getTourBookings(status?: string): Promise<TourBooking[]> {
|
||||
const token = await this.getAuthToken();
|
||||
const url = status
|
||||
? `${API_BASE_URL}/tourism/bookings?status=${status}`
|
||||
: `${API_BASE_URL}/tourism/bookings`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch bookings');
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
export const tourismService = new TourismService();
|
||||
Reference in New Issue
Block a user