Add an accommodations reservations module #188
@ -87,4 +87,32 @@ export class AccommodationListApi {
|
||||
})
|
||||
).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;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { CardContent, Typography, Alert, Button } from "@mui/material";
|
||||
import {
|
||||
CardContent,
|
||||
Typography,
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
CardActions,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import { useAlert } from "../../../hooks/context_providers/AlertDialogProvider";
|
||||
import { useConfirm } from "../../../hooks/context_providers/ConfirmDialogProvider";
|
||||
@ -7,9 +14,15 @@ import { useFamily } from "../../../widgets/BaseFamilyRoute";
|
||||
import { FamilyCard } from "../../../widgets/FamilyCard";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import { useUpdateAccommodation } from "../../../hooks/context_providers/accommodations/UpdateAccommodationDialogProvider";
|
||||
import { AccommodationListApi } from "../../../api/accommodations/AccommodationListApi";
|
||||
import {
|
||||
Accommodation,
|
||||
AccommodationListApi,
|
||||
} from "../../../api/accommodations/AccommodationListApi";
|
||||
import { useSnackbar } from "../../../hooks/context_providers/SnackbarProvider";
|
||||
import { useAccommodations } from "../../../widgets/accommodations/BaseAccommodationsRoute";
|
||||
import { TimeWidget } from "../../../widgets/TimeWidget";
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
|
||||
export function AccommodationsSettingsRoute(): React.ReactElement {
|
||||
return (
|
||||
@ -34,6 +47,8 @@ function AccommodationsListCard(): React.ReactElement {
|
||||
const updateAccommodation = useUpdateAccommodation();
|
||||
|
||||
const createAccommodation = async () => {
|
||||
setError(undefined);
|
||||
setSuccess(undefined);
|
||||
try {
|
||||
const accommodation = await updateAccommodation(
|
||||
{
|
||||
@ -51,11 +66,55 @@ function AccommodationsListCard(): React.ReactElement {
|
||||
await AccommodationListApi.Create(family.family, accommodation);
|
||||
|
||||
snackbar("Le logement a été créé avec succès !");
|
||||
|
||||
await accommodations.reloadAccommodationsList();
|
||||
} catch (e) {
|
||||
console.error("Failed to create accommodation!", e);
|
||||
alert(`Échec de la création du logement! ${e}`);
|
||||
setError(`Échec de la création du logement! ${e}`);
|
||||
} finally {
|
||||
loading.hide();
|
||||
}
|
||||
};
|
||||
|
||||
const requestUpdateAccommodation = async (a: Accommodation) => {
|
||||
setError(undefined);
|
||||
setSuccess(undefined);
|
||||
try {
|
||||
const update = await updateAccommodation(a, false);
|
||||
if (!update) return;
|
||||
|
||||
loading.show("Mise à jour du logement en cours...");
|
||||
|
||||
await AccommodationListApi.Update(a, update);
|
||||
|
||||
snackbar("Le logement a été créé avec succès !");
|
||||
await accommodations.reloadAccommodationsList();
|
||||
} catch (e) {
|
||||
console.error("Failed to update accommodation!", e);
|
||||
setError(`Échec de la mise à jour du logement! ${e}`);
|
||||
} finally {
|
||||
loading.hide();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteAccommodation = async (a: Accommodation) => {
|
||||
setError(undefined);
|
||||
setSuccess(undefined);
|
||||
try {
|
||||
if (
|
||||
!(await confirm(
|
||||
`Voulez-vous vraiment supprimer le logement '${a.name}' ? Cette opération est définitive !`
|
||||
))
|
||||
)
|
||||
return;
|
||||
loading.show("Suppression du logement en cours...");
|
||||
|
||||
await AccommodationListApi.Delete(a);
|
||||
|
||||
snackbar("Le logement a été supprimé avec succès !");
|
||||
await accommodations.reloadAccommodationsList();
|
||||
} catch (e) {
|
||||
console.error("Failed to delete accommodation!", e);
|
||||
setError(`Échec de la suppression du logement! ${e}`);
|
||||
} finally {
|
||||
loading.hide();
|
||||
}
|
||||
@ -67,18 +126,90 @@ function AccommodationsListCard(): React.ReactElement {
|
||||
<Typography gutterBottom variant="h5" component="div">
|
||||
Logements
|
||||
</Typography>
|
||||
|
||||
{/* Display the list of accommodations */}
|
||||
{accommodations.accommodations.isEmpty && (
|
||||
<div style={{ textAlign: "center", margin: "25px" }}>
|
||||
Aucun logement enregistré pour le moment !
|
||||
</div>
|
||||
)}
|
||||
{accommodations.accommodations.fullList.map((a) => (
|
||||
<AccommodationCard
|
||||
accommodation={a}
|
||||
onRequestUpdate={requestUpdateAccommodation}
|
||||
onRequestDelete={deleteAccommodation}
|
||||
/>
|
||||
))}
|
||||
|
||||
{family.family.is_admin && (
|
||||
<Button
|
||||
startIcon={<AddIcon />}
|
||||
variant="outlined"
|
||||
color="info"
|
||||
fullWidth
|
||||
onClick={createAccommodation}
|
||||
disabled={!family.family.is_admin}
|
||||
size={"large"}
|
||||
>
|
||||
Ajouter un nouveau logement
|
||||
</Button>
|
||||
)}
|
||||
</CardContent>
|
||||
</FamilyCard>
|
||||
);
|
||||
}
|
||||
|
||||
function AccommodationCard(p: {
|
||||
accommodation: Accommodation;
|
||||
onRequestUpdate: (a: Accommodation) => void;
|
||||
onRequestDelete: (a: Accommodation) => void;
|
||||
}): React.ReactElement {
|
||||
const family = useFamily();
|
||||
return (
|
||||
<Card sx={{ minWidth: 275, margin: "10px 0px" }} variant="outlined">
|
||||
<CardContent>
|
||||
<Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
|
||||
Mis à jour il y a <TimeWidget time={p.accommodation.time_update} />
|
||||
</Typography>
|
||||
<Typography variant="h5" component="div">
|
||||
{p.accommodation.name}
|
||||
</Typography>
|
||||
<Typography sx={{ mb: 1.5 }} color="text.secondary">
|
||||
{p.accommodation.description}
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
<BoolIcon checked={p.accommodation.open_to_reservations} /> Ouvert aux
|
||||
réservations
|
||||
<br />
|
||||
<BoolIcon checked={!p.accommodation.need_validation} /> Réservation
|
||||
sans validation d'un administrateur
|
||||
</Typography>
|
||||
</CardContent>
|
||||
{family.family.is_admin && (
|
||||
<CardActions>
|
||||
<span style={{ flex: 1 }}></span>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => p.onRequestUpdate(p.accommodation)}
|
||||
>
|
||||
Modifier
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => p.onRequestDelete(p.accommodation)}
|
||||
>
|
||||
Supprimer
|
||||
</Button>
|
||||
</CardActions>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function BoolIcon(p: { checked?: boolean }): React.ReactElement {
|
||||
return p.checked ? (
|
||||
<CheckIcon color="success" />
|
||||
) : (
|
||||
<CloseIcon color="error" />
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user