Connect frontend to real API — rooms, bookings, housekeeping, calendar
- src/lib/api.ts: central API client with JWT auto-refresh, snake_case→camelCase transform - src/contexts/AuthContext.tsx: real login via POST /api/auth/login - src/pages/RoomsPage.tsx: load rooms from API, create/update via API - src/pages/BookingsPage.tsx: load bookings + rooms from API - src/pages/HousekeepingPage.tsx: load today's tasks from API, update status via API - src/pages/CalendarPage.tsx: load rooms + bookings from API - src/types/index.ts: fix HousekeepingTask.priority to match DB (medium/urgent) - backend/src/routes/rooms.ts: update to use new column names (max_guests, base_rate) + all new fields - backend/src/routes/bookings.ts: update price_per_night→base_rate, add paid_amount to PATCH - backend/migrations/003_fix_constraints.sql: fix rooms.status values, add paid_amount, inquiry status, other source - public/robots.txt + index.html: noindex for SPA inner pages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -117,7 +117,7 @@ const bookings: FastifyPluginAsync = async (fastify) => {
|
||||
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const { rows } = await db.query(
|
||||
`SELECT b.*, r.number AS room_number, r.type AS room_type, r.price_per_night
|
||||
`SELECT b.*, r.number AS room_number, r.type AS room_type, r.base_rate
|
||||
FROM bookings b
|
||||
JOIN rooms r ON r.id = b.room_id
|
||||
WHERE b.id = $1 AND b.hotel_id = $2`,
|
||||
@@ -144,7 +144,7 @@ const bookings: FastifyPluginAsync = async (fastify) => {
|
||||
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const allowed = ['guest_name','guest_email','guest_phone','check_in','check_out',
|
||||
'adults','children','status','source','total_amount','notes']
|
||||
'adults','children','status','source','total_amount','paid_amount','notes']
|
||||
const updates: string[] = []
|
||||
const values: unknown[] = []
|
||||
let idx = 1
|
||||
|
||||
@@ -49,8 +49,12 @@ const rooms: FastifyPluginAsync = async (fastify) => {
|
||||
|
||||
// ── POST /api/hotels/:slug/rooms ───────────────────────────────────────────
|
||||
fastify.post<SlugParam & { Body: {
|
||||
number: string; type: string; floor?: number; capacity?: number
|
||||
price_per_night: number; amenities?: string[]; notes?: string
|
||||
number: string; type: string; floor?: number
|
||||
max_guests?: number; base_rate: number; amenities?: string[]
|
||||
name?: string; category_id?: string; bed_type?: string
|
||||
beds?: unknown; housekeeping_status?: string; sort_order?: number
|
||||
allow_hourly?: boolean; hourly_rate?: number; extra_place?: unknown
|
||||
child_policy?: unknown; description?: string; photos?: string[]
|
||||
} }>(
|
||||
'/api/hotels/:slug/rooms',
|
||||
{ onRequest: [fastify.authenticate] },
|
||||
@@ -65,11 +69,30 @@ const rooms: FastifyPluginAsync = async (fastify) => {
|
||||
const hotelId = await getHotelId(slug)
|
||||
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const { number, type, floor = 1, capacity = 2, price_per_night, amenities = [], notes } = request.body
|
||||
const {
|
||||
number, type, floor = 1, max_guests = 2, base_rate,
|
||||
amenities = [], name, category_id, bed_type = 'double',
|
||||
beds, housekeeping_status = 'clean', sort_order = 99,
|
||||
allow_hourly = false, hourly_rate, extra_place, child_policy,
|
||||
description, photos = [],
|
||||
} = request.body
|
||||
|
||||
const { rows } = await db.query(
|
||||
`INSERT INTO rooms (hotel_id, number, type, floor, capacity, price_per_night, amenities, notes)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *`,
|
||||
[hotelId, number, type, floor, capacity, price_per_night, amenities, notes ?? null],
|
||||
`INSERT INTO rooms
|
||||
(hotel_id, number, type, floor, max_guests, base_rate, amenities, name,
|
||||
category_id, bed_type, beds, housekeeping_status, sort_order,
|
||||
allow_hourly, hourly_rate, extra_place, child_policy, description, photos)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19)
|
||||
RETURNING *`,
|
||||
[
|
||||
hotelId, number, type, floor, max_guests, base_rate,
|
||||
amenities, name ?? null, category_id ?? null, bed_type,
|
||||
beds ? JSON.stringify(beds) : null, housekeeping_status, sort_order,
|
||||
allow_hourly, hourly_rate ?? null,
|
||||
extra_place ? JSON.stringify(extra_place) : null,
|
||||
child_policy ? JSON.stringify(child_policy) : null,
|
||||
description ?? null, photos,
|
||||
],
|
||||
)
|
||||
return reply.code(201).send(rows[0])
|
||||
},
|
||||
@@ -111,7 +134,12 @@ const rooms: FastifyPluginAsync = async (fastify) => {
|
||||
const hotelId = await getHotelId(slug)
|
||||
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const allowed = ['number', 'type', 'floor', 'capacity', 'price_per_night', 'status', 'amenities', 'notes']
|
||||
const allowed = [
|
||||
'number', 'type', 'floor', 'max_guests', 'base_rate', 'status',
|
||||
'amenities', 'name', 'category_id', 'bed_type', 'beds',
|
||||
'housekeeping_status', 'sort_order', 'allow_hourly', 'hourly_rate',
|
||||
'extra_place', 'child_policy', 'description', 'photos',
|
||||
]
|
||||
const updates: string[] = []
|
||||
const values: unknown[] = []
|
||||
let idx = 1
|
||||
@@ -119,11 +147,17 @@ const rooms: FastifyPluginAsync = async (fastify) => {
|
||||
for (const key of allowed) {
|
||||
if (request.body[key] !== undefined) {
|
||||
updates.push(`${key} = $${idx}`)
|
||||
values.push(request.body[key])
|
||||
const val = request.body[key]
|
||||
values.push(
|
||||
(key === 'beds' || key === 'extra_place' || key === 'child_policy') && val && typeof val === 'object'
|
||||
? JSON.stringify(val)
|
||||
: val,
|
||||
)
|
||||
idx++
|
||||
}
|
||||
}
|
||||
if (updates.length === 0) return reply.code(400).send({ error: 'Nothing to update' })
|
||||
updates.push(`updated_at = NOW()`)
|
||||
values.push(id, hotelId)
|
||||
|
||||
const { rows } = await db.query(
|
||||
|
||||
Reference in New Issue
Block a user