fix booking page

This commit is contained in:
yotakii
2026-02-23 14:56:25 +03:00
parent 724bcc8f10
commit 921c587656

View File

@@ -33,26 +33,128 @@ const Booking = () => {
specialRequests: ''
});
const extractArray = (res, keys = []) => {
const d = res?.data;
const dd = d?.data;
// direct arrays
if (Array.isArray(d)) return d;
if (Array.isArray(dd)) return dd;
// common shapes
for (const k of keys) {
if (Array.isArray(dd?.[k])) return dd[k];
if (Array.isArray(d?.[k])) return d[k];
}
// fallback scan first array found
if (dd && typeof dd === 'object') {
for (const v of Object.values(dd)) {
if (Array.isArray(v)) return v;
}
}
if (d && typeof d === 'object') {
for (const v of Object.values(d)) {
if (Array.isArray(v)) return v;
}
}
return [];
};
const normalizeRoomOptions = (items = []) => {
return items
.filter(Boolean)
.map((r) => {
const id = r?._id || r?.id || '';
const name =
r?.name ||
r?.title ||
r?.roomName ||
r?.roomCategory?.name ||
'Room';
const roomNumber = r?.roomNumber || r?.number || '';
const price =
r?.basePrice ??
r?.price ??
r?.pricing?.basePrice ??
r?.roomCategory?.basePrice;
const statusRaw = String(r?.status || '').toLowerCase();
const isInactive =
statusRaw === 'inactive' ||
statusRaw === 'disabled' ||
statusRaw === 'draft';
return {
_id: id,
name,
roomNumber,
basePrice: price,
status: r?.status,
kind: 'room',
label:
roomNumber && price != null
? `${name} (#${roomNumber}) - $${price}/night`
: roomNumber
? `${name} (#${roomNumber})`
: price != null
? `${name} - $${price}/night`
: name,
_isInactive: isInactive
};
})
.filter((x) => x._id)
.filter((x) => !x._isInactive);
};
const normalizeCategoryOptions = (items = []) => {
return items
.filter(Boolean)
.map((c) => {
const id = c?._id || c?.id || '';
const name = c?.name || c?.title || c?.categoryName || 'Room Type';
const price = c?.basePrice ?? c?.price ?? c?.startingPrice;
return {
_id: id,
name,
basePrice: price,
kind: 'category',
label: price != null ? `${name} - from $${price}/night` : name
};
})
.filter((x) => x._id);
};
useEffect(() => {
let mounted = true;
const loadRooms = async () => {
try {
const res = await api.get('/api/rooms?limit=100');
// 1) Try actual rooms first
const roomsRes = await api.get('/api/rooms?limit=100');
const rawRooms = extractArray(roomsRes, ['rooms', 'items', 'data']);
const normalizedRooms = normalizeRoomOptions(rawRooms);
const rawRooms =
res?.data?.data?.rooms ||
res?.data?.data ||
res?.data?.rooms ||
[];
if (normalizedRooms.length > 0) {
if (mounted) setRooms(normalizedRooms);
return;
}
const fetched = (Array.isArray(rawRooms) ? rawRooms : []).filter((r) => {
const status = String(r?.status || '').toLowerCase();
return !status || status === 'active';
});
// 2) Fallback to room categories (the types shown on public rooms page)
const categoriesRes = await api.get('/api/room-categories');
const rawCategories = extractArray(categoriesRes, ['categories', 'roomCategories', 'items', 'data']);
const normalizedCategories = normalizeCategoryOptions(rawCategories);
if (mounted) setRooms(fetched);
if (mounted) {
setRooms(normalizedCategories);
if (normalizedCategories.length === 0) {
setMessage({ type: 'warning', text: 'No rooms available' });
}
}
} catch (e) {
console.error('Failed to load rooms/categories:', e);
if (mounted) setMessage({ type: 'error', text: 'Failed to load rooms' });
} finally {
if (mounted) setLoadingRooms(false);
@@ -65,11 +167,10 @@ const Booking = () => {
}, []);
const handleChange = (key) => (e) => {
setForm(prev => ({ ...prev, [key]: e.target.value }));
setForm((prev) => ({ ...prev, [key]: e.target.value }));
};
const validateBeforeSubmit = () => {
// check dates
if (form.checkInDate && form.checkOutDate) {
const inD = new Date(form.checkInDate);
const outD = new Date(form.checkOutDate);
@@ -81,10 +182,12 @@ const Booking = () => {
const adults = Number(form.adults);
const children = Number(form.children || 0);
if (!Number.isFinite(adults) || adults < 1) {
setMessage({ type: 'error', text: 'Adults must be at least 1' });
return false;
}
if (!Number.isFinite(children) || children < 0) {
setMessage({ type: 'error', text: 'Children cannot be negative' });
return false;
@@ -102,6 +205,9 @@ const Booking = () => {
setSubmitting(true);
try {
const selectedOption = rooms.find((r) => r._id === form.roomId);
// Keep original payload structure, but add category fallback fields safely
const payload = {
guestInfo: {
firstName: form.firstName.trim(),
@@ -109,7 +215,10 @@ const Booking = () => {
email: form.email.trim(),
phone: form.phone.trim()
},
roomId: form.roomId,
roomId: selectedOption?.kind === 'room' ? form.roomId : undefined,
roomCategoryId: selectedOption?.kind === 'category' ? form.roomId : undefined,
roomCategory: selectedOption?.name || undefined,
requestedRoomType: selectedOption?.name || undefined,
checkInDate: form.checkInDate,
checkOutDate: form.checkOutDate,
numberOfGuests: {
@@ -119,13 +228,14 @@ const Booking = () => {
specialRequests: form.specialRequests
};
// remove undefined keys
Object.keys(payload).forEach((k) => payload[k] === undefined && delete payload[k]);
const res = await api.post('/api/bookings/request', payload);
const booking = res?.data?.data?.booking || null;
const bookingNumber = booking?.bookingNumber || res?.data?.data?.bookingNumber || null;
const selectedRoom = rooms.find(r => String(r._id || r.id) === String(form.roomId));
const requestForConfirmation = {
fullName: `${form.firstName} ${form.lastName}`.trim(),
phone: form.phone,
@@ -134,15 +244,15 @@ const Booking = () => {
checkOutDate: form.checkOutDate,
adults: Number(form.adults),
children: Number(form.children || 0),
roomCategory: selectedRoom?.name || selectedRoom?.title || '',
roomCategory: selectedOption?.name || '',
message: form.specialRequests || '',
bookingNumber: bookingNumber || '',
autoOpenWhatsApp: true
};
navigate('/booking/confirmation', { state: { request: requestForConfirmation } });
} catch (error) {
console.error('Booking submit error:', error);
setMessage({
type: 'error',
text: error.response?.data?.message || 'Failed to submit booking request'
@@ -190,18 +300,16 @@ const Booking = () => {
onChange={handleChange('roomId')}
required
>
{rooms.length === 0 ? (
<MenuItem disabled value="">
No rooms available
</MenuItem>
) : (
{rooms.length > 0 ? (
rooms.map((r) => (
<MenuItem key={r._id || r.id} value={r._id || r.id}>
{(r.name || r.title || 'Room')}
{r.roomNumber ? ` (#${r.roomNumber})` : ''}
{(r.basePrice ?? r.price) != null ? ` - $${r.basePrice ?? r.price}/night` : ''}
<MenuItem key={r._id} value={r._id}>
{r.label || r.name}
</MenuItem>
))
) : (
<MenuItem value="" disabled>
No rooms available
</MenuItem>
)}
</TextField>
@@ -248,7 +356,7 @@ const Booking = () => {
rows={3}
/>
<Button type="submit" variant="contained" size="large" disabled={submitting}>
<Button type="submit" variant="contained" size="large" disabled={submitting || rooms.length === 0}>
{submitting ? 'Submitting...' : 'Submit Booking Request'}
</Button>
</Box>