From c8993f906dd272b7c01af3d8c7faa3d0320c0274 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Mon, 17 Jun 2024 21:23:51 +0200 Subject: [PATCH] WIP calendar integration --- .../AccommodationsReservationsApi.tsx | 75 ++++++++ .../AccommodationsReservationsRoute.tsx | 180 +++++++++++++++++- 2 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 geneit_app/src/api/accommodations/AccommodationsReservationsApi.tsx diff --git a/geneit_app/src/api/accommodations/AccommodationsReservationsApi.tsx b/geneit_app/src/api/accommodations/AccommodationsReservationsApi.tsx new file mode 100644 index 0000000..b5d469f --- /dev/null +++ b/geneit_app/src/api/accommodations/AccommodationsReservationsApi.tsx @@ -0,0 +1,75 @@ +import { APIClient } from "../ApiClient"; +import { Family } from "../FamilyApi"; +import moment from "moment"; + +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; + + 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 class AccommodationsReservationsApi { + /** + * Get the entire list of accommodations of a family + */ + static async FullListOfFamily( + family: Family + ): Promise { + const data = ( + await APIClient.exec({ + method: "GET", + uri: `/family/${family.family_id}/accommodations/reservations/full_list`, + }) + ).data; + + return new AccommodationsReservationsList(data); + } +} diff --git a/geneit_app/src/routes/family/accommodations/AccommodationsReservationsRoute.tsx b/geneit_app/src/routes/family/accommodations/AccommodationsReservationsRoute.tsx index 310e67e..036fd2f 100644 --- a/geneit_app/src/routes/family/accommodations/AccommodationsReservationsRoute.tsx +++ b/geneit_app/src/routes/family/accommodations/AccommodationsReservationsRoute.tsx @@ -1,3 +1,181 @@ +import React from "react"; +import { FamilyApi, FamilyUser } from "../../../api/FamilyApi"; +import { + AccommodationsReservationsApi, + AccommodationsReservationsList, +} from "../../../api/accommodations/AccommodationsReservationsApi"; +import { AsyncWidget } from "../../../widgets/AsyncWidget"; +import { useFamily } from "../../../widgets/BaseFamilyRoute"; +import { FamilyPageTitle } from "../../../widgets/FamilyPageTitle"; +import { + FormControl, + FormLabel, + FormGroup, + FormControlLabel, + Checkbox, + FormHelperText, +} from "@mui/material"; +import { useAccommodations } from "../../../widgets/accommodations/BaseAccommodationsRoute"; +import { + Calendar, + DateLocalizer, + Views, + momentLocalizer, +} from "react-big-calendar"; +import moment from "moment"; + +const localizer = momentLocalizer(moment); + export function AccommodationsReservationsRoute(): React.ReactElement { - return <>TODO; + const loadKey = React.useRef(1); + + const family = useFamily(); + const accommodations = useAccommodations(); + + const [reservations, setReservations] = React.useState< + AccommodationsReservationsList | undefined + >(); + const [users, setUsers] = React.useState(null); + + const [showValidated, setShowValidated] = React.useState(true); + const [showRejected, setShowRejected] = React.useState(true); + const [showPending, setShowPending] = React.useState(true); + + const [hiddenPeople, setHiddenPeople] = React.useState>( + new Set() + ); + const [hiddenAccommodations, setHiddenAccommodations] = React.useState< + Set + >(new Set()); + + const load = async () => { + setReservations( + await AccommodationsReservationsApi.FullListOfFamily(family.family) + ); + setUsers(await FamilyApi.GetUsersList(family.family.family_id)); + }; + + const reload = async () => { + loadKey.current += 1; + setUsers(null); + }; + + return ( + <> + + ( +
+
+ {/* Invitation status */} + + Status + + setShowValidated(v)} + /> + } + label="Validé" + /> + setShowRejected(v)} + /> + } + label="Rejetés" + /> + setShowPending(v)} + /> + } + label="En attente de validation" + /> + + + + {/* Accommodations */} + + Logements + + {accommodations.accommodations.fullList.map((a) => ( + { + if (v) hiddenAccommodations.delete(a.id); + else hiddenAccommodations.add(a.id); + setHiddenAccommodations( + new Set(hiddenAccommodations) + ); + }} + /> + } + label={a.name} + /> + ))} + + + + {/* People */} + + Personnes + + {users?.map((u) => ( + { + if (v) hiddenPeople.delete(u.user_id); + else hiddenPeople.add(u.user_id); + setHiddenPeople(new Set(hiddenPeople)); + }} + /> + } + label={u.user_name} + /> + ))} + + +
+ + {/* The calendar */} +
+ +
+
+ )} + /> + + ); }