Add an accommodations reservations module #188

Merged
pierre merged 81 commits from accomodation_module into master 2024-06-22 21:30:26 +00:00
2 changed files with 92 additions and 12 deletions
Showing only changes of commit f6d8d6b3d1 - Show all commits

View File

@ -144,4 +144,20 @@ export class AccommodationsReservationsApi {
uri: `/family/${r.family_id}/accommodations/reservation/${r.id}`, uri: `/family/${r.family_id}/accommodations/reservation/${r.id}`,
}); });
} }
/**
* Validate or reject a reservation request
*/
static async Validate(
r: AccommodationReservation,
accept: boolean
): Promise<void> {
await APIClient.exec({
method: "POST",
uri: `/family/${r.family_id}/accommodations/reservation/${r.id}/validate`,
jsonData: {
validate: accept,
},
});
}
} }

View File

@ -20,6 +20,8 @@ import {
FormGroup, FormGroup,
FormLabel, FormLabel,
IconButton, IconButton,
Menu,
MenuItem,
Popover, Popover,
Tooltip, Tooltip,
Typography, Typography,
@ -92,6 +94,9 @@ export function AccommodationsReservationsRoute(): React.ReactElement {
} }
>(); >();
const [validateResaAnchorEl, setValidateResaAnchorEl] =
React.useState<null | HTMLElement>(null);
const load = async () => { const load = async () => {
setReservations( setReservations(
await AccommodationsReservationsApi.FullListOfFamily(family.family) await AccommodationsReservationsApi.FullListOfFamily(family.family)
@ -174,8 +179,39 @@ export function AccommodationsReservationsRoute(): React.ReactElement {
}); });
}; };
const respondToResaRequest = async (
r: AccommodationReservation,
validate: boolean
) => {
try {
loadingMessage.show("Validation de la réservation en cours...");
setActiveEvent(undefined);
await AccommodationsReservationsApi.Validate(r, validate);
reload();
snackbar("La réservation a été mise à jour avec succès !");
} catch (e) {
console.error("Failed to respond to reservation request!", e);
alert(`Echec de l'enregistrement de la réponse à la réservation ! ${e}`);
} finally {
loadingMessage.hide();
}
};
const validateReservation = async (r: AccommodationReservation) => { const validateReservation = async (r: AccommodationReservation) => {
// TODO respondToResaRequest(r, true);
};
const rejectReservation = async (r: AccommodationReservation) => {
if (
!(await confirm(
"Voulez-vous vraiment rejeter cette demande de réservation ?"
))
)
return;
respondToResaRequest(r, false);
}; };
const changeReservation = async (r: AccommodationReservation) => { const changeReservation = async (r: AccommodationReservation) => {
@ -473,18 +509,46 @@ export function AccommodationsReservationsRoute(): React.ReactElement {
<CardActions disableSpacing> <CardActions disableSpacing>
{activeEvent?.accommodation.need_validation && {activeEvent?.accommodation.need_validation &&
family.family.is_admin && ( family.family.is_admin && (
<>
<Tooltip <Tooltip
title="Valider (ou rejeter) la réservation" title="Valider (ou rejeter) la réservation"
arrow arrow
> >
<IconButton <IconButton
onClick={() => onClick={(e) =>
validateReservation(activeEvent?.reservation) setValidateResaAnchorEl(e.currentTarget)
} }
> >
<RuleIcon /> <RuleIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Menu
anchorEl={validateResaAnchorEl}
open={!!validateResaAnchorEl && !!activeEvent}
onClose={() => setValidateResaAnchorEl(null)}
>
<MenuItem
disabled={
activeEvent.reservation.validated === true
}
onClick={() =>
validateReservation(activeEvent.reservation)
}
>
Valider
</MenuItem>
<MenuItem
disabled={
activeEvent.reservation.validated === false
}
onClick={() =>
rejectReservation(activeEvent.reservation)
}
>
Rejeter
</MenuItem>
</Menu>
</>
)} )}
{user.user.id === activeEvent?.reservation.user_id && ( {user.user.id === activeEvent?.reservation.user_id && (
<> <>