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 => { const response = await apiClient.post( '/bookings', bookingData ); return response.data; }; /** * Get all bookings of the current user * GET /api/bookings/me */ export const getMyBookings = async (): Promise => { const response = await apiClient.get( '/bookings/me' ); return response.data; }; /** * Get booking by ID * GET /api/bookings/:id */ export const getBookingById = async ( id: number ): Promise => { const response = await apiClient.get( `/bookings/${id}` ); return response.data; }; /** * Cancel a booking * PATCH /api/bookings/:id/cancel */ export const cancelBooking = async ( id: number ): Promise => { const response = await apiClient.patch( `/bookings/${id}/cancel` ); return response.data; }; /** * Check booking by booking number * GET /api/bookings/check/:bookingNumber */ export const checkBookingByNumber = async ( bookingNumber: string ): Promise => { const response = await apiClient.get( `/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 => { const response = await apiClient.get('/bookings', { params }); return response.data; }; /** * Update booking status (admin) * PUT /api/bookings/:id */ export const updateBooking = async ( id: number, data: Partial ): Promise => { const response = await apiClient.put(`/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, };