Files
Hotel-Booking/Frontend/src/services/api/bookingService.ts
Iliyan Angelov 44e11520c5 updates
2025-11-20 02:18:52 +02:00

340 lines
7.0 KiB
TypeScript

import apiClient from './apiClient';
// Types
export interface BookingData {
room_id: number;
check_in_date: string; // YYYY-MM-DD
check_out_date: string; // YYYY-MM-DD
guest_count: number;
notes?: string;
payment_method: 'cash' | 'stripe' | 'paypal';
total_price: number;
guest_info: {
full_name: string;
email: string;
phone: string;
};
services?: Array<{
service_id: number;
quantity: number;
}>;
}
export interface Booking {
id: number;
booking_number: string;
user_id: number;
room_id: number;
check_in_date: string;
check_out_date: string;
guest_count: number;
total_price: number;
original_price?: number;
discount_amount?: number;
promotion_code?: string;
status:
| 'pending'
| 'confirmed'
| 'cancelled'
| 'checked_in'
| 'checked_out';
payment_method: 'cash' | 'stripe' | 'paypal';
payment_status:
| 'unpaid'
| 'paid'
| 'refunded';
deposit_paid?: boolean;
requires_deposit?: boolean;
notes?: string;
guest_info?: {
full_name: string;
email: string;
phone: string;
};
room?: {
id: number;
room_number: string;
floor: number;
status: string;
room_type: {
id: number;
name: string;
base_price: number;
capacity: number;
images?: string[];
};
};
user?: {
id: number;
name: string;
full_name: string;
email: string;
phone?: string;
phone_number?: string;
};
payments?: Payment[];
payment_balance?: {
total_paid: number;
total_price: number;
remaining_balance: number;
is_fully_paid: boolean;
payment_percentage: number;
};
createdAt: string;
updatedAt: string;
}
export interface Payment {
id: number;
booking_id: number;
amount: number;
payment_method: string;
payment_type: 'full' | 'deposit' | 'remaining';
deposit_percentage?: number;
payment_status: 'pending' | 'completed' | 'failed' | 'refunded';
transaction_id?: string;
payment_date?: string;
notes?: string;
created_at: string;
updated_at: string;
}
export interface BookingResponse {
success: boolean;
data: {
booking: Booking;
};
message?: string;
}
export interface BookingsResponse {
success: boolean;
data: {
bookings: Booking[];
pagination?: {
page: number;
limit: number;
total: number;
totalPages: number;
};
};
message?: string;
}
export interface CheckBookingResponse {
success: boolean;
data: {
booking: Booking;
};
message?: string;
}
/**
* Create a new booking
* POST /api/bookings
*/
export const createBooking = async (
bookingData: BookingData
): Promise<BookingResponse> => {
const response = await apiClient.post<BookingResponse>(
'/bookings',
bookingData
);
return response.data;
};
/**
* Get all bookings of the current user
* GET /api/bookings/me
*/
export const getMyBookings = async ():
Promise<BookingsResponse> => {
const response = await apiClient.get<BookingsResponse>(
'/bookings/me'
);
return response.data;
};
/**
* Get booking by ID
* GET /api/bookings/:id
*/
export const getBookingById = async (
id: number
): Promise<BookingResponse> => {
const response = await apiClient.get<BookingResponse>(
`/bookings/${id}`
);
return response.data;
};
/**
* Cancel a booking
* PATCH /api/bookings/:id/cancel
*/
export const cancelBooking = async (
id: number
): Promise<BookingResponse> => {
const response = await apiClient.patch<BookingResponse>(
`/bookings/${id}/cancel`
);
return response.data;
};
/**
* Check booking by booking number
* GET /api/bookings/check/:bookingNumber
*/
export const checkBookingByNumber = async (
bookingNumber: string
): Promise<CheckBookingResponse> => {
const response =
await apiClient.get<CheckBookingResponse>(
`/bookings/check/${bookingNumber}`
);
return response.data;
};
/**
* Get all bookings (admin)
* GET /api/bookings
*/
export const getAllBookings = async (
params?: {
status?: string;
search?: string;
page?: number;
limit?: number;
}
): Promise<BookingsResponse> => {
const response = await apiClient.get<BookingsResponse>('/bookings', { params });
return response.data;
};
/**
* Update booking status (admin)
* PUT /api/bookings/:id
*/
export const updateBooking = async (
id: number,
data: Partial<Booking>
): Promise<BookingResponse> => {
const response = await apiClient.put<BookingResponse>(`/bookings/${id}`, data);
return response.data;
};
/**
* Check room availability (helper function)
* GET /api/rooms/available?roomId=...&from=...&to=...
*/
export const checkRoomAvailability = async (
roomId: number,
checkInDate: string,
checkOutDate: string
): Promise<{ available: boolean; message?: string }> => {
try {
const response = await apiClient.get(
'/rooms/available',
{
params: {
roomId,
from: checkInDate,
to: checkOutDate,
},
}
);
// Handle new response format when roomId is provided
if (response.data?.data?.available !== undefined) {
return {
available: response.data.data.available,
message: response.data.data.message,
};
}
// Fallback for old format
return {
available: true,
message: response.data?.message || 'Room is available',
};
} catch (error: any) {
if (error.response?.status === 409 || error.response?.status === 404) {
return {
available: false,
message:
error.response.data?.message ||
error.response.data?.detail ||
'Room already booked during this time',
};
}
throw error;
}
};
/**
* Notify payment (upload payment receipt)
* POST /api/notify/payment
*/
export const notifyPayment = async (
bookingId: number,
file?: File
): Promise<{ success: boolean; message?: string }> => {
const formData = new FormData();
formData.append('bookingId', bookingId.toString());
if (file) {
formData.append('receipt', file);
}
const response = await apiClient.post(
'/notify/payment',
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
}
);
return response.data;
};
/**
* Generate QR code URL for bank transfer
*/
export const generateQRCode = (
bookingNumber: string,
amount: number
): string => {
// Using VietQR API format
// Bank: Vietcombank (VCB)
// Account: 0123456789
const bankCode = 'VCB';
const accountNumber = '0123456789';
const accountName = 'KHACH SAN ABC';
const transferContent = bookingNumber;
// VietQR format
const qrUrl =
`https://img.vietqr.io/image/${bankCode}-` +
`${accountNumber}-compact2.jpg?` +
`amount=${amount}&` +
`addInfo=${encodeURIComponent(transferContent)}&` +
`accountName=${encodeURIComponent(accountName)}`;
return qrUrl;
};
export default {
createBooking,
getMyBookings,
getBookingById,
cancelBooking,
checkBookingByNumber,
checkRoomAvailability,
notifyPayment,
generateQRCode,
getAllBookings,
updateBooking,
};