init commit
This commit is contained in:
144
apps/web/lib/pocketbase.ts
Normal file
144
apps/web/lib/pocketbase.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
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;
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user