Add an accommodations reservations module (#188)
All checks were successful
continuous-integration/drone/push Build is passing

Add a new module to enable accommodations reservation

![](https://gitea.communiquons.org/attachments/de1f5b12-0a93-40f8-b29d-97665daa6fd5)

Reviewed-on: #188
This commit is contained in:
2024-06-22 21:30:26 +00:00
parent 8ecacbe622
commit 1a890844ef
54 changed files with 4230 additions and 33 deletions

View File

@ -88,10 +88,12 @@ export class Family implements FamilyAPI {
export class ExtendedFamilyInfo extends Family {
public disable_couple_photos: boolean;
public enable_genealogy: boolean;
public enable_accommodations: boolean;
constructor(p: any) {
super(p);
this.disable_couple_photos = p.disable_couple_photos;
this.enable_genealogy = p.enable_genealogy;
this.enable_accommodations = p.enable_accommodations;
}
}
@ -235,6 +237,7 @@ export class FamilyApi {
id: number;
name?: string;
enable_genealogy?: boolean;
enable_accommodations?: boolean;
disable_couple_photos?: boolean;
}): Promise<void> {
await APIClient.exec({
@ -243,6 +246,7 @@ export class FamilyApi {
jsonData: {
name: settings.name,
enable_genealogy: settings.enable_genealogy,
enable_accommodations: settings.enable_accommodations,
disable_couple_photos: settings.disable_couple_photos,
},
});

View File

@ -32,6 +32,9 @@ interface Constraints {
member_country: LenConstraint;
member_sex: LenConstraint;
member_note: LenConstraint;
accommodation_name_len: LenConstraint;
accommodation_description_len: LenConstraint;
accommodation_calendar_name_len: LenConstraint;
}
interface OIDCProvider {

View File

@ -0,0 +1,124 @@
import { APIClient } from "../ApiClient";
import { Family } from "../FamilyApi";
export interface Accommodation {
id: number;
family_id: number;
time_create: number;
time_update: number;
name: string;
need_validation: boolean;
description?: string;
color?: string;
open_to_reservations: boolean;
}
export class AccommodationsList {
private list: Accommodation[];
private map: Map<number, Accommodation>;
constructor(list: Accommodation[]) {
this.list = list;
this.map = new Map();
for (const m of list) {
this.map.set(m.id, m);
}
this.list.sort((a, b) =>
a.name.toLowerCase().localeCompare(b.name.toLocaleLowerCase())
);
}
public get isEmpty(): boolean {
return this.list.length === 0;
}
public get size(): number {
return this.list.length;
}
public get fullList(): Accommodation[] {
return this.list;
}
filter(predicate: (m: Accommodation) => boolean): Accommodation[] {
return this.list.filter(predicate);
}
get openToReservationList(): Accommodation[] {
return this.filter((a) => a.open_to_reservations);
}
get(id: number): Accommodation | undefined {
return this.map.get(id);
}
}
export interface UpdateAccommodation {
name: string;
need_validation: boolean;
description?: string;
color?: string;
open_to_reservations: boolean;
}
export class AccommodationListApi {
/**
* Get the list of accommodation of a family
*/
static async GetListOfFamily(family: Family): Promise<AccommodationsList> {
const data = (
await APIClient.exec({
method: "GET",
uri: `/family/${family.family_id}/accommodations/list/list`,
})
).data;
return new AccommodationsList(data);
}
/**
* Create a new accommodation
*/
static async Create(
family: Family,
accommodation: UpdateAccommodation
): Promise<Accommodation> {
return (
await APIClient.exec({
method: "POST",
uri: `/family/${family.family_id}/accommodations/list/create`,
jsonData: accommodation,
})
).data;
}
/**
* Update an accommodation
*/
static async Update(
accommodation: Accommodation,
update: UpdateAccommodation
): Promise<Accommodation> {
return (
await APIClient.exec({
method: "PUT",
uri: `/family/${accommodation.family_id}/accommodations/list/${accommodation.id}`,
jsonData: update,
})
).data;
}
/**
* Delete an accommodation
*/
static async Delete(accommodation: Accommodation): Promise<Accommodation> {
return (
await APIClient.exec({
method: "DELETE",
uri: `/family/${accommodation.family_id}/accommodations/list/${accommodation.id}`,
})
).data;
}
}

View File

@ -0,0 +1,69 @@
import { APIClient } from "../ApiClient";
import { Family } from "../FamilyApi";
export interface NewCalendarURL {
accommodation_id?: number;
name: string;
}
export interface AccommodationCalendarURL {
id: number;
family_id: number;
accommodation_id: number;
user_id: number;
name: string;
token: string;
time_create: number;
time_used: number;
}
export class AccommodationsCalendarURLApi {
/**
* Create a new accommodation calendar URL
*/
static async Create(
family: Family,
calendar: NewCalendarURL
): Promise<AccommodationCalendarURL> {
return (
await APIClient.exec({
method: "POST",
uri: `/family/${family.family_id}/accommodations/reservations_calendars/create`,
jsonData: calendar,
})
).data;
}
/**
* Get accommodation calendar URL route
*/
static CalendarURL(c: AccommodationCalendarURL): string {
return `${APIClient.backendURL()}/acccommodations_calendar/${c.token}`;
}
/**
* Get accommodations calendars list
*/
static async GetList(family: Family): Promise<AccommodationCalendarURL[]> {
return (
await APIClient.exec({
method: "GET",
uri: `/family/${family.family_id}/accommodations/reservations_calendars/list`,
})
).data;
}
/**
* Delete an accommodation calendar
*/
static async Delete(
calendar: AccommodationCalendarURL
): Promise<AccommodationCalendarURL> {
return (
await APIClient.exec({
method: "DELETE",
uri: `/family/${calendar.family_id}/accommodations/reservations_calendars/${calendar.id}`,
})
).data;
}
}

View File

@ -0,0 +1,175 @@
import { APIClient } from "../ApiClient";
import { Family } from "../FamilyApi";
import { Accommodation } from "./AccommodationListApi";
export enum ValidateResaResult {
Success,
Error,
Conflict,
}
export interface AccommodationReservation {
id: number;
family_id: number;
accommodation_id: number;
user_id: number;
time_create: number;
time_update: number;
reservation_start: number;
reservation_end: number;
validated?: boolean;
}
export class AccommodationsReservationsList {
private list: AccommodationReservation[];
private map: Map<number, AccommodationReservation>;
constructor(list: AccommodationReservation[]) {
this.list = list;
this.map = new Map();
for (const m of list) {
this.map.set(m.id, m);
}
this.list.sort((a, b) => a.reservation_start - b.reservation_start);
}
public get isEmpty(): boolean {
return this.list.length === 0;
}
public get size(): number {
return this.list.length;
}
public get fullList(): AccommodationReservation[] {
return this.list;
}
filter(
predicate: (m: AccommodationReservation) => boolean
): AccommodationReservation[] {
return this.list.filter(predicate);
}
forAccommodation(id: number): AccommodationReservation[] {
return this.filter((a) => a.accommodation_id === id);
}
get(id: number): AccommodationReservation | undefined {
return this.map.get(id);
}
}
export interface UpdateAccommodationReservation {
start: number;
end: number;
accommodation_id: number;
reservation_id?: number;
}
export class AccommodationsReservationsApi {
/**
* Create a new reservation
*/
static async Create(
family: Family,
reservation: UpdateAccommodationReservation
): Promise<AccommodationReservation> {
return (
await APIClient.exec({
method: "POST",
uri: `/family/${family.family_id}/accommodations/reservations/accommodation/${reservation.accommodation_id}/create`,
jsonData: {
start: reservation.start,
end: reservation.end,
},
})
).data;
}
/**
* Get the entire list of accommodations of a family
*/
static async FullListOfFamily(
family: Family
): Promise<AccommodationsReservationsList> {
const data = (
await APIClient.exec({
method: "GET",
uri: `/family/${family.family_id}/accommodations/reservations/full_list`,
})
).data;
return new AccommodationsReservationsList(data);
}
/**
* Get the reservations of a given time interval for an accommodation
*/
static async ReservationsForInterval(
family: Family,
accommodation: Accommodation,
start: number,
end: number
): Promise<AccommodationsReservationsList> {
const data = (
await APIClient.exec({
method: "GET",
uri: `/family/${family.family_id}/accommodations/reservations/accommodation/${accommodation.id}/for_interval?start=${start}&end=${end}`,
})
).data;
return new AccommodationsReservationsList(data);
}
/**
* Update a reservation
*/
static async Update(
family: Family,
r: UpdateAccommodationReservation
): Promise<void> {
await APIClient.exec({
method: "PATCH",
uri: `/family/${family.family_id}/accommodations/reservation/${r.reservation_id}`,
jsonData: {
start: r.start,
end: r.end,
},
});
}
/**
* Delete a reservation
*/
static async Delete(r: AccommodationReservation): Promise<void> {
await APIClient.exec({
method: "DELETE",
uri: `/family/${r.family_id}/accommodations/reservation/${r.id}`,
});
}
/**
* Validate or reject a reservation request
*/
static async Validate(
r: AccommodationReservation,
accept: boolean
): Promise<ValidateResaResult> {
const res = await APIClient.exec({
method: "POST",
uri: `/family/${r.family_id}/accommodations/reservation/${r.id}/validate`,
jsonData: {
validate: accept,
},
allowFail: true,
});
if (res.status >= 200 && res.status <= 299)
return ValidateResaResult.Success;
if (res.status === 409) return ValidateResaResult.Conflict;
return ValidateResaResult.Error;
}
}