diff --git a/apps/pocketbase/pb_data/auxiliary.db b/apps/pocketbase/pb_data/auxiliary.db index e1b3286..515babc 100644 Binary files a/apps/pocketbase/pb_data/auxiliary.db and b/apps/pocketbase/pb_data/auxiliary.db differ diff --git a/apps/pocketbase/pb_data/data.db b/apps/pocketbase/pb_data/data.db index 293ae71..a58edb1 100644 Binary files a/apps/pocketbase/pb_data/data.db and b/apps/pocketbase/pb_data/data.db differ diff --git a/apps/pocketbase/pb_migrations/1756241295_updated_timeSlots.js b/apps/pocketbase/pb_migrations/1756241295_updated_timeSlots.js new file mode 100644 index 0000000..8b0b815 --- /dev/null +++ b/apps/pocketbase/pb_migrations/1756241295_updated_timeSlots.js @@ -0,0 +1,38 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_586073990") + + // update field + collection.fields.addAt(7, new Field({ + "hidden": false, + "id": "number3301820327", + "max": null, + "min": 1, + "name": "max_booking_capacity", + "onlyInt": false, + "presentable": false, + "required": true, + "system": false, + "type": "number" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_586073990") + + // update field + collection.fields.addAt(7, new Field({ + "hidden": false, + "id": "number3301820327", + "max": null, + "min": 1, + "name": "max_capacity", + "onlyInt": false, + "presentable": false, + "required": true, + "system": false, + "type": "number" + })) + + return app.save(collection) +}) diff --git a/apps/pocketbase/pb_migrations/1756241390_updated_bookingTypes.js b/apps/pocketbase/pb_migrations/1756241390_updated_bookingTypes.js new file mode 100644 index 0000000..00bd671 --- /dev/null +++ b/apps/pocketbase/pb_migrations/1756241390_updated_bookingTypes.js @@ -0,0 +1,66 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_43114331") + + // update field + collection.fields.addAt(9, new Field({ + "hidden": false, + "id": "number1421793101", + "max": null, + "min": null, + "name": "min_participants_capacity", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + })) + + // update field + collection.fields.addAt(10, new Field({ + "hidden": false, + "id": "number3301820327", + "max": null, + "min": null, + "name": "max_participants_capacity", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_43114331") + + // update field + collection.fields.addAt(9, new Field({ + "hidden": false, + "id": "number1421793101", + "max": null, + "min": null, + "name": "min_capacity", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + })) + + // update field + collection.fields.addAt(10, new Field({ + "hidden": false, + "id": "number3301820327", + "max": null, + "min": null, + "name": "max_capacity", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + })) + + return app.save(collection) +}) diff --git a/apps/pocketbase/pb_migrations/1756242359_updated_timeSlots.js b/apps/pocketbase/pb_migrations/1756242359_updated_timeSlots.js new file mode 100644 index 0000000..515f381 --- /dev/null +++ b/apps/pocketbase/pb_migrations/1756242359_updated_timeSlots.js @@ -0,0 +1,27 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_586073990") + + // remove field + collection.fields.removeById("number3301820327") + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_586073990") + + // add field + collection.fields.addAt(7, new Field({ + "hidden": false, + "id": "number3301820327", + "max": null, + "min": 1, + "name": "max_booking_capacity", + "onlyInt": false, + "presentable": false, + "required": true, + "system": false, + "type": "number" + })) + + return app.save(collection) +}) diff --git a/apps/pocketbase/pb_migrations/1756242388_updated_bookingTypes.js b/apps/pocketbase/pb_migrations/1756242388_updated_bookingTypes.js new file mode 100644 index 0000000..c51eac8 --- /dev/null +++ b/apps/pocketbase/pb_migrations/1756242388_updated_bookingTypes.js @@ -0,0 +1,27 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_43114331") + + // add field + collection.fields.addAt(12, new Field({ + "hidden": false, + "id": "number2396794873", + "max": null, + "min": null, + "name": "booking_capacity", + "onlyInt": false, + "presentable": false, + "required": true, + "system": false, + "type": "number" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_43114331") + + // remove field + collection.fields.removeById("number2396794873") + + return app.save(collection) +}) diff --git a/apps/pocketbase/pb_migrations/1756243147_updated_bookings.js b/apps/pocketbase/pb_migrations/1756243147_updated_bookings.js new file mode 100644 index 0000000..c839e41 --- /dev/null +++ b/apps/pocketbase/pb_migrations/1756243147_updated_bookings.js @@ -0,0 +1,22 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_986407980") + + // update collection data + unmarshal({ + "listRule": "", + "viewRule": "" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_986407980") + + // update collection data + unmarshal({ + "listRule": null, + "viewRule": null + }, collection) + + return app.save(collection) +}) diff --git a/apps/web/components/BookingForm.tsx b/apps/web/components/BookingForm.tsx index 4ce1370..98f2829 100644 --- a/apps/web/components/BookingForm.tsx +++ b/apps/web/components/BookingForm.tsx @@ -119,21 +119,58 @@ const BookingInterface = () => { } }; - const handleDateChange = (date: string) => { + const handleDateChange = async (date: string) => { setSelectedDate(date); setSelectedTimeSlot(''); // Get time slots for the selected date from availableSlotsByDate const slotsForDate = availableSlotsByDate[date] || []; - console.log(`Time slots for ${date}:`, slotsForDate); - // Convert to TimeSlot format for TimeSlotSelector - const formattedTimeSlots: TimeSlot[] = slotsForDate.map((slot, index) => ({ + // Get bookings for this date filtered by booking type IDs + let bookingOverlapCounts: { [key: string]: number } = {}; + try { + const bookings = await bookingApi.getBookingsForDate(date, [selectedBookingType]); + + // Count overlapping bookings for each time slot + slotsForDate.forEach(slot => { + const slotStart = new Date(slot.start_time); + const slotEnd = new Date(slot.end_time); + + const overlappingBookings = bookings.filter(booking => { + const bookingStart = new Date(booking.start_time); + const bookingEnd = new Date(booking.end_time); + + // Check if bookings overlap with time slot + return bookingStart < slotEnd && bookingEnd > slotStart; + }); + + const totalParticipants = overlappingBookings.reduce((sum, booking) => + sum + (booking.participants_count || 0), 0 + ); + + const key = `${slot.start_time}-${slot.end_time}`; + bookingOverlapCounts[key] = totalParticipants; + }); + + console.log('Booking overlap counts:', bookingOverlapCounts); + } catch (error) { + console.error('Error fetching bookings for date:', error); + } + + // Convert to TimeSlot format and filter out fully booked slots + const bookingTypeCapacity = selectedBookingTypeData?.booking_capacity || 8; + const availableTimeSlots = slotsForDate.filter(slot => { + const key = `${slot.start_time}-${slot.end_time}`; + const overlappingCount = bookingOverlapCounts[key] || 0; + return overlappingCount < bookingTypeCapacity; + }); + + const formattedTimeSlots: TimeSlot[] = availableTimeSlots.map((slot, index) => ({ id: `slot-${date}-${index}`, start_time: slot.start_time, end_time: slot.end_time, is_active: true, - max_capacity: 8, + booking_capacity: bookingTypeCapacity, booking_types: [selectedBookingType], is_reccuring: false, recurrence_pattern: undefined, diff --git a/apps/web/components/DateSelector.tsx b/apps/web/components/DateSelector.tsx index 5a4660e..f5ae5c1 100644 --- a/apps/web/components/DateSelector.tsx +++ b/apps/web/components/DateSelector.tsx @@ -35,11 +35,14 @@ const DateSelector: React.FC = ({ date.setDate(today.getDate() + i); const dateString = date.toISOString().split('T')[0] || ''; + // Create date object from the ISO string to avoid timezone issues + const displayDate = new Date(dateString + 'T12:00:00.000Z'); + days.push({ date: dateString, - day: date.getDate(), - month: date.toLocaleDateString('en', { month: 'short' }), - dayName: date.toLocaleDateString('en', { weekday: 'short' }), + day: parseInt(dateString.split('-')[2]), + month: displayDate.toLocaleDateString('en', { month: 'short', timeZone: 'UTC' }), + dayName: displayDate.toLocaleDateString('en', { weekday: 'short', timeZone: 'UTC' }), available: availableDates.includes(dateString) }); } diff --git a/apps/web/lib/pocketbase.ts b/apps/web/lib/pocketbase.ts index 63c28be..7c7233e 100644 --- a/apps/web/lib/pocketbase.ts +++ b/apps/web/lib/pocketbase.ts @@ -1,5 +1,5 @@ import PocketBase from 'pocketbase'; -import { BookingType, TimeSlot } from '@/types/bookings'; +import { BookingType, TimeSlot, Booking } from '@/types/bookings'; // Initialize PocketBase client export const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL || 'http://127.0.0.1:8090'); @@ -122,4 +122,26 @@ export const bookingApi = { return availableSlotsByDate; }, + + // Get all bookings for a specific date filtered by booking type IDs + async getBookingsForDate( + date: string, + bookingTypeIds: string[] + ): Promise { + try { + // Create filter for booking type IDs + const bookingTypeFilter = bookingTypeIds.map(id => `booking_type = "${id}"`).join(' || '); + + const bookings = await pb.collection('bookings').getFullList({ + filter: `status = "confirmed" && start_time ~ "${date}" && (${bookingTypeFilter})`, + sort: 'start_time' + }); + + console.log(`Bookings for ${date}:`, bookings); + return bookings; + } catch (error) { + console.error('Error fetching bookings for date:', error); + return []; + } + }, }; \ No newline at end of file diff --git a/apps/web/types/bookings.ts b/apps/web/types/bookings.ts index eb6fe27..974305e 100644 --- a/apps/web/types/bookings.ts +++ b/apps/web/types/bookings.ts @@ -9,7 +9,7 @@ export interface BaseRecord { export interface Resource extends BaseRecord { name: string; type: 'wheel' | 'workstation'; - capacity: number; + usage_capacity: number; is_active: boolean; } @@ -23,9 +23,10 @@ export interface BookingType extends BaseRecord { min_duration: number; price_per_person: number; resources: string; // relation to Resource - min_capacity: number; - max_capacity: number; + min_participants_capacity: number; + max_participants_capacity: number; is_active: boolean; + booking_capacity: number; } // Time Slot entity @@ -36,7 +37,6 @@ export interface TimeSlot extends BaseRecord { is_active: boolean; is_reccuring?: boolean; recurrence_pattern?: RecurrencePattern; - max_capacity: number; } // Recurrence pattern structure