Add an accommodations reservations module #188
@ -45,6 +45,10 @@ export class AccommodationsList {
|
|||||||
return this.list.filter(predicate);
|
return this.list.filter(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get openToReservationList(): Accommodation[] {
|
||||||
|
return this.filter((a) => a.open_to_reservations);
|
||||||
|
}
|
||||||
|
|
||||||
get(id: number): Accommodation | undefined {
|
get(id: number): Accommodation | undefined {
|
||||||
return this.map.get(id);
|
return this.map.get(id);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { APIClient } from "../ApiClient";
|
import { APIClient } from "../ApiClient";
|
||||||
import { Family } from "../FamilyApi";
|
import { Family } from "../FamilyApi";
|
||||||
import moment from "moment";
|
|
||||||
|
|
||||||
export interface AccommodationReservation {
|
export interface AccommodationReservation {
|
||||||
id: number;
|
id: number;
|
||||||
@ -56,6 +55,12 @@ export class AccommodationsReservationsList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UpdateAccommodationReservation {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
accommodation_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class AccommodationsReservationsApi {
|
export class AccommodationsReservationsApi {
|
||||||
/**
|
/**
|
||||||
* Get the entire list of accommodations of a family
|
* Get the entire list of accommodations of a family
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
import { UpdateAccommodationReservation } from "../../api/accommodations/AccommodationsReservationsApi";
|
||||||
|
import { useAccommodations } from "../../widgets/accommodations/BaseAccommodationsRoute";
|
||||||
|
import { PropSelect } from "../../widgets/forms/PropSelect";
|
||||||
|
|
||||||
|
export function UpdateReservationDialog(p: {
|
||||||
|
open: boolean;
|
||||||
|
create: boolean;
|
||||||
|
reservation?: UpdateAccommodationReservation;
|
||||||
|
onClose: () => void;
|
||||||
|
onSubmitted: (c: UpdateAccommodationReservation) => void;
|
||||||
|
}): React.ReactElement {
|
||||||
|
const accommodations = useAccommodations();
|
||||||
|
|
||||||
|
const [reservation, setReservation] = React.useState<
|
||||||
|
UpdateAccommodationReservation | undefined
|
||||||
|
>();
|
||||||
|
|
||||||
|
const clearForm = () => {
|
||||||
|
setReservation(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancel = () => {
|
||||||
|
clearForm();
|
||||||
|
p.onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
clearForm();
|
||||||
|
p.onSubmitted(reservation!);
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!reservation) setReservation(p.reservation);
|
||||||
|
}, [p.open, p.reservation]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={p.open} onClose={cancel}>
|
||||||
|
<DialogTitle>
|
||||||
|
{p.create ? "Création" : "Mise à jour"} d'une réservation
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent style={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<PropSelect
|
||||||
|
editing={p.create}
|
||||||
|
label="Logement ciblé"
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setReservation((a) => {
|
||||||
|
return {
|
||||||
|
...a!,
|
||||||
|
accommodation_id: Number(v),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
options={accommodations.accommodations.openToReservationList.map(
|
||||||
|
(a) => {
|
||||||
|
return { label: a.name, value: a.id.toString() };
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
value={reservation?.accommodation_id?.toString()}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* TODO : la suite */}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={cancel}>Annuler</Button>
|
||||||
|
<Button
|
||||||
|
onClick={submit}
|
||||||
|
disabled={
|
||||||
|
(reservation?.accommodation_id ?? -1) > 0 &&
|
||||||
|
(reservation?.start ?? -1) > 0 &&
|
||||||
|
(reservation?.end ?? -1) > (reservation?.start ?? 0)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{p.create ? "Créer" : "Mettre à jour"}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
import React, { PropsWithChildren } from "react";
|
||||||
|
import { UpdateAccommodationReservation } from "../../../api/accommodations/AccommodationsReservationsApi";
|
||||||
|
import { UpdateReservationDialog } from "../../../dialogs/accommodations/UpdateReservationDialog";
|
||||||
|
|
||||||
|
type DialogContext = (
|
||||||
|
reservation: UpdateAccommodationReservation,
|
||||||
|
create: boolean
|
||||||
|
) => Promise<UpdateAccommodationReservation | undefined>;
|
||||||
|
|
||||||
|
const DialogContextK = React.createContext<DialogContext | null>(null);
|
||||||
|
|
||||||
|
export function UpdateReservationDialogProvider(
|
||||||
|
p: PropsWithChildren
|
||||||
|
): React.ReactElement {
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
|
const [reservation, setReservation] = React.useState<
|
||||||
|
UpdateAccommodationReservation | undefined
|
||||||
|
>(undefined);
|
||||||
|
const [create, setCreate] = React.useState(false);
|
||||||
|
|
||||||
|
const cb = React.useRef<
|
||||||
|
null | ((a: UpdateAccommodationReservation | undefined) => void)
|
||||||
|
>(null);
|
||||||
|
|
||||||
|
const handleClose = (res?: UpdateAccommodationReservation) => {
|
||||||
|
setOpen(false);
|
||||||
|
|
||||||
|
if (cb.current !== null) cb.current(res);
|
||||||
|
cb.current = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hook: DialogContext = (accommodation, create) => {
|
||||||
|
setReservation(accommodation);
|
||||||
|
setCreate(create);
|
||||||
|
setOpen(true);
|
||||||
|
|
||||||
|
return new Promise((res) => {
|
||||||
|
cb.current = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DialogContextK.Provider value={hook}>
|
||||||
|
{p.children}
|
||||||
|
</DialogContextK.Provider>
|
||||||
|
|
||||||
|
{open && (
|
||||||
|
<UpdateReservationDialog
|
||||||
|
open={open}
|
||||||
|
reservation={reservation}
|
||||||
|
create={create}
|
||||||
|
onClose={handleClose}
|
||||||
|
onSubmitted={handleClose}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateAccommodationReservation(): DialogContext {
|
||||||
|
return React.useContext(DialogContextK)!;
|
||||||
|
}
|
@ -17,6 +17,7 @@ import {
|
|||||||
AccommodationsReservationsApi,
|
AccommodationsReservationsApi,
|
||||||
AccommodationsReservationsList,
|
AccommodationsReservationsList,
|
||||||
} from "../../../api/accommodations/AccommodationsReservationsApi";
|
} from "../../../api/accommodations/AccommodationsReservationsApi";
|
||||||
|
import { useUpdateAccommodationReservation } from "../../../hooks/context_providers/accommodations/UpdateReservationDialogProvider";
|
||||||
import { AsyncWidget } from "../../../widgets/AsyncWidget";
|
import { AsyncWidget } from "../../../widgets/AsyncWidget";
|
||||||
import { useFamily } from "../../../widgets/BaseFamilyRoute";
|
import { useFamily } from "../../../widgets/BaseFamilyRoute";
|
||||||
import { FamilyPageTitle } from "../../../widgets/FamilyPageTitle";
|
import { FamilyPageTitle } from "../../../widgets/FamilyPageTitle";
|
||||||
@ -27,6 +28,7 @@ export function AccommodationsReservationsRoute(): React.ReactElement {
|
|||||||
|
|
||||||
const family = useFamily();
|
const family = useFamily();
|
||||||
const accommodations = useAccommodations();
|
const accommodations = useAccommodations();
|
||||||
|
const updateReservation = useUpdateAccommodationReservation();
|
||||||
|
|
||||||
const [reservations, setReservations] = React.useState<
|
const [reservations, setReservations] = React.useState<
|
||||||
AccommodationsReservationsList | undefined
|
AccommodationsReservationsList | undefined
|
||||||
@ -57,7 +59,17 @@ export function AccommodationsReservationsRoute(): React.ReactElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onSelect = (d: DateSelectArg) => {
|
const onSelect = (d: DateSelectArg) => {
|
||||||
|
// TODO : render this functional
|
||||||
|
// TODO : handle busy case
|
||||||
console.info(d);
|
console.info(d);
|
||||||
|
updateReservation(
|
||||||
|
{
|
||||||
|
accommodation_id: -1,
|
||||||
|
start: Math.floor(d.start.getDate() / 1000),
|
||||||
|
end: Math.floor(d.end.getDate() / 1000),
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -5,10 +5,11 @@ import {
|
|||||||
AccommodationsList,
|
AccommodationsList,
|
||||||
} from "../../api/accommodations/AccommodationListApi";
|
} from "../../api/accommodations/AccommodationListApi";
|
||||||
import { CreateAccommodationCalendarURLDialogProvider } from "../../hooks/context_providers/accommodations/CreateAccommodationCalendarURLDialogProvider";
|
import { CreateAccommodationCalendarURLDialogProvider } from "../../hooks/context_providers/accommodations/CreateAccommodationCalendarURLDialogProvider";
|
||||||
|
import { InstallCalendarDialogProvider } from "../../hooks/context_providers/accommodations/InstallCalendarDialogProvider";
|
||||||
import { UpdateAccommodationDialogProvider } from "../../hooks/context_providers/accommodations/UpdateAccommodationDialogProvider";
|
import { UpdateAccommodationDialogProvider } from "../../hooks/context_providers/accommodations/UpdateAccommodationDialogProvider";
|
||||||
|
import { UpdateReservationDialogProvider } from "../../hooks/context_providers/accommodations/UpdateReservationDialogProvider";
|
||||||
import { AsyncWidget } from "../AsyncWidget";
|
import { AsyncWidget } from "../AsyncWidget";
|
||||||
import { useFamily } from "../BaseFamilyRoute";
|
import { useFamily } from "../BaseFamilyRoute";
|
||||||
import { InstallCalendarDialogProvider } from "../../hooks/context_providers/accommodations/InstallCalendarDialogProvider";
|
|
||||||
|
|
||||||
interface AccommodationsContext {
|
interface AccommodationsContext {
|
||||||
accommodations: AccommodationsList;
|
accommodations: AccommodationsList;
|
||||||
@ -65,7 +66,9 @@ export function BaseAccommodationsRoute(): React.ReactElement {
|
|||||||
<UpdateAccommodationDialogProvider>
|
<UpdateAccommodationDialogProvider>
|
||||||
<CreateAccommodationCalendarURLDialogProvider>
|
<CreateAccommodationCalendarURLDialogProvider>
|
||||||
<InstallCalendarDialogProvider>
|
<InstallCalendarDialogProvider>
|
||||||
<Outlet />
|
<UpdateReservationDialogProvider>
|
||||||
|
<Outlet />
|
||||||
|
</UpdateReservationDialogProvider>
|
||||||
</InstallCalendarDialogProvider>
|
</InstallCalendarDialogProvider>
|
||||||
</CreateAccommodationCalendarURLDialogProvider>
|
</CreateAccommodationCalendarURLDialogProvider>
|
||||||
</UpdateAccommodationDialogProvider>
|
</UpdateAccommodationDialogProvider>
|
||||||
|
Loading…
Reference in New Issue
Block a user