feat: widget — room display mode toggle (by room / by category)
This commit is contained in:
@@ -20,13 +20,25 @@ const publicWidget: FastifyPluginAsync = async (fastify) => {
|
||||
|
||||
const { rows: rooms } = await db.query(
|
||||
`SELECT id, number, name, type, floor, max_guests, base_rate, amenities, description, photos,
|
||||
allow_hourly, hourly_rate, extra_place, child_policy, status
|
||||
allow_hourly, hourly_rate, extra_place, child_policy, status, category_id
|
||||
FROM rooms
|
||||
WHERE hotel_id = $1 AND status != 'inactive'
|
||||
ORDER BY sort_order, number`,
|
||||
[hotel.id],
|
||||
)
|
||||
|
||||
const { rows: categories } = await db.query(
|
||||
`SELECT rc.id, rc.name, rc.description, rc.amenities, rc.photos,
|
||||
COALESCE(MIN(r.base_rate), 0) AS min_price,
|
||||
COALESCE(MAX(r.max_guests), 2) AS max_guests
|
||||
FROM room_categories rc
|
||||
LEFT JOIN rooms r ON r.category_id = rc.id AND r.status != 'inactive'
|
||||
WHERE rc.hotel_id = $1
|
||||
GROUP BY rc.id, rc.name, rc.description, rc.amenities, rc.photos, rc.sort_order
|
||||
ORDER BY rc.sort_order, rc.name`,
|
||||
[hotel.id],
|
||||
)
|
||||
|
||||
// Check if YooKassa gateway is configured for booking-widget
|
||||
const gateway = await getGatewayForModule(hotel.id, 'booking-widget')
|
||||
|
||||
@@ -47,9 +59,19 @@ const publicWidget: FastifyPluginAsync = async (fastify) => {
|
||||
amenities: r.amenities ?? [],
|
||||
description: r.description ?? '',
|
||||
photos: r.photos ?? [],
|
||||
categoryId: r.category_id ?? null,
|
||||
allowHourly: r.allow_hourly,
|
||||
hourlyRate: r.hourly_rate ? Number(r.hourly_rate) : null,
|
||||
})),
|
||||
categories: categories.map(c => ({
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
description: c.description ?? '',
|
||||
amenities: c.amenities ?? [],
|
||||
photos: c.photos ?? [],
|
||||
minPrice: Number(c.min_price),
|
||||
maxGuests: Number(c.max_guests),
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -74,7 +96,7 @@ const publicWidget: FastifyPluginAsync = async (fastify) => {
|
||||
const occupiedIds = new Set(occupied.map((r: any) => r.room_id))
|
||||
|
||||
const { rows: rooms } = await db.query(
|
||||
`SELECT id, number, name, type, floor, max_guests, base_rate, amenities, description, photos
|
||||
`SELECT id, number, name, type, floor, max_guests, base_rate, amenities, description, photos, category_id
|
||||
FROM rooms WHERE hotel_id = $1 AND status = 'available'
|
||||
ORDER BY sort_order, number`,
|
||||
[hotel.id],
|
||||
@@ -93,6 +115,7 @@ const publicWidget: FastifyPluginAsync = async (fastify) => {
|
||||
amenities: r.amenities ?? [],
|
||||
description: r.description ?? '',
|
||||
photos: r.photos ?? [],
|
||||
categoryId: r.category_id ?? null,
|
||||
}))
|
||||
}
|
||||
)
|
||||
@@ -101,7 +124,7 @@ const publicWidget: FastifyPluginAsync = async (fastify) => {
|
||||
// Create an online booking (no auth)
|
||||
fastify.post<SlugParam & {
|
||||
Body: {
|
||||
roomId: string; checkIn: string; checkOut: string
|
||||
roomId?: string; categoryId?: string; checkIn: string; checkOut: string
|
||||
guestName: string; guestEmail?: string; guestPhone?: string
|
||||
adults?: number; children?: number
|
||||
totalAmount: number; notes?: string
|
||||
@@ -111,14 +134,35 @@ const publicWidget: FastifyPluginAsync = async (fastify) => {
|
||||
const hotel = await getHotelId(req.params.slug)
|
||||
if (!hotel) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const { roomId, checkIn, checkOut, guestName, guestEmail, guestPhone,
|
||||
let { roomId, categoryId, checkIn, checkOut, guestName, guestEmail, guestPhone,
|
||||
adults = 1, children = 0, totalAmount, notes, services } = req.body
|
||||
|
||||
if (!roomId || !checkIn || !checkOut || !guestName || !totalAmount) {
|
||||
if (!checkIn || !checkOut || !guestName || !totalAmount) {
|
||||
return reply.code(400).send({ error: 'Missing required fields' })
|
||||
}
|
||||
if (!roomId && !categoryId) {
|
||||
return reply.code(400).send({ error: 'roomId or categoryId required' })
|
||||
}
|
||||
|
||||
// Check availability
|
||||
// If categoryId given, find first available room in category
|
||||
if (categoryId && !roomId) {
|
||||
const { rows: available } = await db.query(
|
||||
`SELECT id FROM rooms
|
||||
WHERE hotel_id = $1 AND category_id = $2 AND status = 'available'
|
||||
AND id NOT IN (
|
||||
SELECT room_id FROM bookings
|
||||
WHERE hotel_id = $1
|
||||
AND status NOT IN ('cancelled','no_show','checked_out')
|
||||
AND check_in < $4 AND check_out > $3
|
||||
)
|
||||
ORDER BY sort_order, number LIMIT 1`,
|
||||
[hotel.id, categoryId, checkIn, checkOut],
|
||||
)
|
||||
if (!available[0]) return reply.code(409).send({ error: 'No rooms available in this category for selected dates' })
|
||||
roomId = available[0].id
|
||||
}
|
||||
|
||||
// Check availability for specific room
|
||||
const { rows: conflict } = await db.query(
|
||||
`SELECT id FROM bookings
|
||||
WHERE hotel_id = $1 AND room_id = $2
|
||||
|
||||
Reference in New Issue
Block a user