144 lines
4.8 KiB
TypeScript
144 lines
4.8 KiB
TypeScript
import PocketBase from 'pocketbase';
|
|
import { BookingType, Resource, TimeSlot, Booking } from '@/types/booking';
|
|
|
|
// Initialize PocketBase client
|
|
export const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL || 'http://127.0.0.1:8090');
|
|
|
|
// Disable auto cancellation for SSR
|
|
pb.autoCancellation(false);
|
|
|
|
// API functions for booking system
|
|
|
|
export const bookingApi = {
|
|
// Get all active booking types
|
|
async getBookingTypes(): Promise<BookingType[]> {
|
|
try {
|
|
const records = await pb.collection('bookingTypes').getFullList<BookingType>({
|
|
sort: 'created',
|
|
expand: 'resources',
|
|
});
|
|
return records;
|
|
} catch (error) {
|
|
console.error('Error fetching booking types:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get available resources
|
|
async getResources(): Promise<Resource[]> {
|
|
try {
|
|
const records = await pb.collection('resources').getFullList<Resource>({
|
|
filter: 'is_active = true',
|
|
sort: 'type',
|
|
});
|
|
return records;
|
|
} catch (error) {
|
|
console.error('Error fetching resources:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get available time slots for a specific booking type and date range
|
|
async getAvailableTimeSlots(
|
|
bookingTypeId: string,
|
|
startDate: Date,
|
|
endDate: Date
|
|
): Promise<TimeSlot[]> {
|
|
try {
|
|
const startDateStr = startDate.toISOString().split('T')[0];
|
|
const endDateStr = endDate.toISOString().split('T')[0];
|
|
|
|
const records = await pb.collection('timeSlots').getFullList<TimeSlot>({
|
|
filter: `is_active = true && booking_types ~ "${bookingTypeId}" && start_time >= "${startDateStr}" && start_time <= "${endDateStr}"`,
|
|
sort: 'start_time',
|
|
});
|
|
return records;
|
|
} catch (error) {
|
|
console.error('Error fetching time slots:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Check if a time slot has availability
|
|
async checkTimeSlotAvailability(
|
|
timeSlotId: string,
|
|
startTime: string,
|
|
endTime: string,
|
|
participantsCount: number
|
|
): Promise<{ available: boolean; currentBookings: number }> {
|
|
try {
|
|
// Get existing confirmed bookings for this time slot
|
|
const existingBookings = await pb.collection('bookings').getFullList<Booking>({
|
|
filter: `status = "confirmed" && start_time >= "${startTime}" && end_time <= "${endTime}"`,
|
|
});
|
|
|
|
// Get the time slot to check max capacity
|
|
const timeSlot = await pb.collection('timeSlots').getOne<TimeSlot>(timeSlotId);
|
|
|
|
const currentBookings = existingBookings.reduce((sum, booking) =>
|
|
sum + (booking.participants_count || 0), 0
|
|
);
|
|
|
|
const availableSpots = timeSlot.max_capacity - currentBookings;
|
|
const available = availableSpots >= participantsCount;
|
|
|
|
return {
|
|
available,
|
|
currentBookings,
|
|
};
|
|
} catch (error) {
|
|
console.error('Error checking availability:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Create a new booking
|
|
async createBooking(bookingData: {
|
|
booking_type: string;
|
|
customer_name: string;
|
|
customer_email: string;
|
|
start_time: string;
|
|
end_time: string;
|
|
participants_count: number;
|
|
internal_notes?: string;
|
|
}): Promise<Booking> {
|
|
try {
|
|
const record = await pb.collection('bookings').create<Booking>({
|
|
...bookingData,
|
|
status: 'confirmed',
|
|
payment_status: 'not_required', // We'll handle payment logic later
|
|
payment_required: false,
|
|
});
|
|
return record;
|
|
} catch (error) {
|
|
console.error('Error creating booking:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get booking by cancellation token (for cancellation flow)
|
|
async getBookingByToken(token: string): Promise<Booking | null> {
|
|
try {
|
|
const records = await pb.collection('bookings').getFullList<Booking>({
|
|
filter: `cancellation_token = "${token}"`,
|
|
});
|
|
return records[0] || null;
|
|
} catch (error) {
|
|
console.error('Error fetching booking by token:', error);
|
|
return null;
|
|
}
|
|
},
|
|
|
|
// Cancel booking
|
|
async cancelBooking(bookingId: string): Promise<boolean> {
|
|
try {
|
|
await pb.collection('bookings').update(bookingId, {
|
|
status: 'cancelled',
|
|
});
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error cancelling booking:', error);
|
|
return false;
|
|
}
|
|
},
|
|
}; |