254 lines
7.7 KiB
TypeScript
254 lines
7.7 KiB
TypeScript
import { Resource, CreateReservationRequest, Reservation } from '../types';
|
|
|
|
export class SimpleLibreBookingClient {
|
|
private baseUrl: string;
|
|
private sessionToken: string | null = null;
|
|
private userId: string | null = null;
|
|
|
|
constructor(baseUrl?: string) {
|
|
this.baseUrl = baseUrl || process.env.REACT_APP_LIBREBOOKING_API_URL || 'http://localhost:8080/Web';
|
|
}
|
|
|
|
async authenticate(username: string, password: string): Promise<boolean> {
|
|
try {
|
|
console.log('Attempting authentication with:', { username, baseUrl: this.baseUrl });
|
|
|
|
const response = await fetch(`${this.baseUrl}/Services/index.php/Authentication/Authenticate`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ username, password }),
|
|
});
|
|
|
|
console.log('Authentication response status:', response.status);
|
|
const data = await response.json();
|
|
console.log('Authentication response data:', data);
|
|
|
|
if (response.ok && data.isAuthenticated) {
|
|
this.sessionToken = data.sessionToken;
|
|
this.userId = data.userId?.toString();
|
|
console.log('Authentication successful:', { sessionToken: this.sessionToken, userId: this.userId });
|
|
return true;
|
|
} else {
|
|
console.log('Authentication failed:', { status: response.status, data });
|
|
return false;
|
|
}
|
|
} catch (error) {
|
|
console.error('Authentication error:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async getResources(): Promise<Resource[]> {
|
|
if (!this.sessionToken) {
|
|
const username = process.env.REACT_APP_LIBREBOOKING_USERNAME;
|
|
const password = process.env.REACT_APP_LIBREBOOKING_PASSWORD;
|
|
|
|
if (username && password) {
|
|
const authenticated = await this.authenticate(username, password);
|
|
if (!authenticated) {
|
|
throw new Error('Authentication failed');
|
|
}
|
|
}
|
|
}
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (this.sessionToken && this.userId) {
|
|
headers['X-Booked-SessionToken'] = this.sessionToken;
|
|
headers['X-Booked-UserId'] = this.userId;
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/Services/index.php/Resources/`, {
|
|
headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
console.log('Resources response:', data);
|
|
return data.resources || [];
|
|
}
|
|
|
|
async getResource(id: string): Promise<Resource | null> {
|
|
if (!this.sessionToken) {
|
|
const username = process.env.REACT_APP_LIBREBOOKING_USERNAME;
|
|
const password = process.env.REACT_APP_LIBREBOOKING_PASSWORD;
|
|
|
|
if (username && password) {
|
|
const authenticated = await this.authenticate(username, password);
|
|
if (!authenticated) {
|
|
throw new Error('Authentication failed');
|
|
}
|
|
}
|
|
}
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (this.sessionToken && this.userId) {
|
|
headers['X-Booked-SessionToken'] = this.sessionToken;
|
|
headers['X-Booked-UserId'] = this.userId;
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/Services/index.php/Resources/${id}`, {
|
|
headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
console.log('Resource response:', data);
|
|
return data || null;
|
|
}
|
|
|
|
async getReservations(resourceId?: string): Promise<Reservation[]> {
|
|
if (!this.sessionToken) {
|
|
const username = process.env.REACT_APP_LIBREBOOKING_USERNAME;
|
|
const password = process.env.REACT_APP_LIBREBOOKING_PASSWORD;
|
|
|
|
if (username && password) {
|
|
const authenticated = await this.authenticate(username, password);
|
|
if (!authenticated) {
|
|
throw new Error('Authentication failed');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use a wide date range to get all reservations
|
|
const today = new Date();
|
|
const threeMonthsAgo = new Date(today.getTime() - (90 * 24 * 60 * 60 * 1000));
|
|
const threeMonthsFromNow = new Date(today.getTime() + (90 * 24 * 60 * 60 * 1000));
|
|
|
|
const params = new URLSearchParams({
|
|
startDateTime: threeMonthsAgo.toISOString().split('.')[0] + 'Z',
|
|
endDateTime: threeMonthsFromNow.toISOString().split('.')[0] + 'Z',
|
|
});
|
|
|
|
if (resourceId) {
|
|
params.append('resourceId', resourceId);
|
|
}
|
|
|
|
const url = `${this.baseUrl}/Services/index.php/Reservations/?${params.toString()}`;
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (this.sessionToken && this.userId) {
|
|
headers['X-Booked-SessionToken'] = this.sessionToken;
|
|
headers['X-Booked-UserId'] = this.userId;
|
|
}
|
|
|
|
const response = await fetch(url, {
|
|
headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
console.log('API date range:', {
|
|
start: data.startDateTime,
|
|
end: data.endDateTime
|
|
});
|
|
console.log('Found reservations:', data.reservations.length);
|
|
return data.reservations || [];
|
|
}
|
|
|
|
async createReservation(data: CreateReservationRequest): Promise<Reservation> {
|
|
if (!this.sessionToken) {
|
|
const username = process.env.REACT_APP_LIBREBOOKING_USERNAME;
|
|
const password = process.env.REACT_APP_LIBREBOOKING_PASSWORD;
|
|
|
|
if (username && password) {
|
|
const authenticated = await this.authenticate(username, password);
|
|
if (!authenticated) {
|
|
throw new Error('Authentication failed');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use the exact field names expected by LibreBooking API
|
|
const requestData = {
|
|
resourceId: data.resourceId,
|
|
startDateTime: data.startDateTime,
|
|
endDateTime: data.endDateTime,
|
|
title: data.title,
|
|
description: data.description || '',
|
|
allowParticipation: false,
|
|
termsAccepted: true
|
|
};
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (this.sessionToken && this.userId) {
|
|
headers['X-Booked-SessionToken'] = this.sessionToken;
|
|
headers['X-Booked-UserId'] = this.userId;
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/Services/index.php/Reservations/`, {
|
|
method: 'POST',
|
|
headers,
|
|
body: JSON.stringify(requestData),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const reservation = await response.json();
|
|
return reservation;
|
|
}
|
|
|
|
async updateReservationStatus(id: string, status: 'confirmed' | 'cancelled'): Promise<Reservation> {
|
|
if (!this.sessionToken) {
|
|
const username = process.env.REACT_APP_LIBREBOOKING_USERNAME;
|
|
const password = process.env.REACT_APP_LIBREBOOKING_PASSWORD;
|
|
|
|
if (username && password) {
|
|
const authenticated = await this.authenticate(username, password);
|
|
if (!authenticated) {
|
|
throw new Error('Authentication failed');
|
|
}
|
|
}
|
|
}
|
|
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (this.sessionToken && this.userId) {
|
|
headers['X-Booked-SessionToken'] = this.sessionToken;
|
|
headers['X-Booked-UserId'] = this.userId;
|
|
}
|
|
|
|
const response = await fetch(`${this.baseUrl}/Services/index.php/Reservations/${id}`, {
|
|
method: 'PUT',
|
|
headers,
|
|
body: JSON.stringify({ status }),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const reservation = await response.json();
|
|
return reservation;
|
|
}
|
|
|
|
getUserId(): string | null {
|
|
return this.userId || null;
|
|
}
|
|
} |