All checks were successful
continuous-integration/drone/push Build is passing
Add an option in family settings to disable couple photos from Web UI Reviewed-on: #5
279 lines
7.7 KiB
TypeScript
279 lines
7.7 KiB
TypeScript
import DownloadIcon from "@mui/icons-material/Download";
|
|
import UploadIcon from "@mui/icons-material/Upload";
|
|
import {
|
|
Alert,
|
|
Box,
|
|
Button,
|
|
CardActions,
|
|
CardContent,
|
|
Checkbox,
|
|
FormControlLabel,
|
|
TextField,
|
|
Tooltip,
|
|
Typography,
|
|
} from "@mui/material";
|
|
import React from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { DataApi } from "../../api/DataApi";
|
|
import { FamilyApi } from "../../api/FamilyApi";
|
|
import { ServerApi } from "../../api/ServerApi";
|
|
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider";
|
|
import { useConfirm } from "../../hooks/context_providers/ConfirmDialogProvider";
|
|
import { useLoadingMessage } from "../../hooks/context_providers/LoadingMessageProvider";
|
|
import { downloadBlob, selectFileToUpload } from "../../utils/files_utils";
|
|
import { useFamily } from "../../widgets/BaseFamilyRoute";
|
|
import { FamilyCard } from "../../widgets/FamilyCard";
|
|
import { formatDate } from "../../widgets/TimeWidget";
|
|
|
|
export function FamilySettingsRoute(): React.ReactElement {
|
|
const alert = useAlert();
|
|
const confirm = useConfirm();
|
|
const navigate = useNavigate();
|
|
|
|
const family = useFamily();
|
|
|
|
const deleteFamily = async () => {
|
|
try {
|
|
if (
|
|
!(await confirm(
|
|
"Voulez-vous vraiment supprimer cette famille, et toute les données qui s'y rattachent ? Cette opération est absolument irréversible !"
|
|
))
|
|
)
|
|
return;
|
|
|
|
await FamilyApi.DeleteFamily(family.family);
|
|
|
|
await alert("La famille a été supprimée avec succès !");
|
|
|
|
navigate("/");
|
|
} catch (e) {
|
|
console.error(e);
|
|
alert("Echec de la suppression de la famille !");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<FamilySettingsCard />
|
|
<FamilyExportCard />
|
|
<div style={{ textAlign: "center", marginTop: "50px" }}>
|
|
<Button
|
|
size="small"
|
|
color="error"
|
|
onClick={deleteFamily}
|
|
disabled={!family.family.is_admin}
|
|
>
|
|
Supprimer la famille
|
|
</Button>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function FamilySettingsCard(): React.ReactElement {
|
|
const alert = useAlert();
|
|
|
|
const family = useFamily();
|
|
|
|
const [newName, setNewName] = React.useState(family.family.name);
|
|
const [disableCouplePhotos, setDisableCouplePhotos] = React.useState(
|
|
family.family.disable_couple_photos
|
|
);
|
|
|
|
const canEdit = family.family.is_admin;
|
|
|
|
const [error, setError] = React.useState<string>();
|
|
const [success, setSuccess] = React.useState<string>();
|
|
|
|
const updateFamily = async () => {
|
|
try {
|
|
setError(undefined);
|
|
setSuccess(undefined);
|
|
|
|
await FamilyApi.UpdateFamily({
|
|
id: family.family.family_id,
|
|
name: newName,
|
|
disable_couple_photos: disableCouplePhotos,
|
|
});
|
|
|
|
family.reloadFamilyInfo();
|
|
|
|
alert("Les paramètres de la famille ont été mis à jour avec succès !");
|
|
} catch (e) {
|
|
console.error(e);
|
|
setError("Echec de la mise à jour des paramètres de la famille !");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<FamilyCard error={error} success={success}>
|
|
<CardContent>
|
|
<Typography gutterBottom variant="h5" component="div">
|
|
Paramètres de la famille
|
|
</Typography>
|
|
|
|
<Box
|
|
component="form"
|
|
sx={{
|
|
"& .MuiTextField-root": { my: 1 },
|
|
}}
|
|
noValidate
|
|
autoComplete="off"
|
|
>
|
|
<TextField
|
|
disabled
|
|
fullWidth
|
|
label="Identifiant"
|
|
value={family.family.family_id}
|
|
/>
|
|
|
|
<TextField
|
|
disabled
|
|
fullWidth
|
|
label="Création de la famille"
|
|
value={formatDate(family.family.time_create)}
|
|
/>
|
|
|
|
<TextField
|
|
fullWidth
|
|
label="Nom de la famille"
|
|
value={newName}
|
|
disabled={!canEdit}
|
|
onChange={(e) => setNewName(e.target.value)}
|
|
inputProps={{
|
|
maxLength: ServerApi.Config.constraints.family_name_len.max,
|
|
}}
|
|
/>
|
|
<Tooltip title="Les photos de couple ne sont pas utilisées en pratique dans les arbres généalogiques. Il est possible de masquer les formulaires d'édition de photos de couple pour limiter le risque de confusion.">
|
|
<FormControlLabel
|
|
disabled={!canEdit}
|
|
control={
|
|
<Checkbox
|
|
checked={disableCouplePhotos}
|
|
onChange={(_e, c) => setDisableCouplePhotos(c)}
|
|
/>
|
|
}
|
|
label="Désactiver les photos de couple"
|
|
/>
|
|
</Tooltip>
|
|
</Box>
|
|
</CardContent>
|
|
<CardActions>
|
|
<Button
|
|
onClick={updateFamily}
|
|
disabled={!canEdit}
|
|
style={{ marginLeft: "auto" }}
|
|
>
|
|
Enregistrer
|
|
</Button>
|
|
</CardActions>
|
|
</FamilyCard>
|
|
);
|
|
}
|
|
|
|
function FamilyExportCard(): React.ReactElement {
|
|
const loading = useLoadingMessage();
|
|
const confirm = useConfirm();
|
|
const alert = useAlert();
|
|
|
|
const family = useFamily();
|
|
|
|
const [error, setError] = React.useState<string>();
|
|
const [success, setSuccess] = React.useState<string>();
|
|
|
|
const exportData = async () => {
|
|
loading.show("Export des données");
|
|
try {
|
|
setError(undefined);
|
|
setSuccess(undefined);
|
|
|
|
const blob = await DataApi.ExportData(family.familyId);
|
|
downloadBlob(blob, `Export-${new Date().getTime()}.zip`);
|
|
|
|
setSuccess("Export des données effectué avec succès !");
|
|
} catch (e) {
|
|
console.error(e);
|
|
setError("Echec de l'export des données de la famille !");
|
|
}
|
|
loading.hide();
|
|
};
|
|
|
|
const importData = async () => {
|
|
try {
|
|
if (
|
|
!(await confirm(
|
|
"Attention ! Cette opération a pour effet d'effacer toutes les données existantes en base ! Voulez-vous vraiment poursuivre l'opération ?"
|
|
))
|
|
)
|
|
return;
|
|
|
|
const file = await selectFileToUpload({
|
|
allowedTypes: ["application/zip"],
|
|
});
|
|
if (file === null) return;
|
|
|
|
setError(undefined);
|
|
setSuccess(undefined);
|
|
|
|
loading.show("Restauration des données de la famille en cours...");
|
|
|
|
await DataApi.ImportData(family.familyId, file);
|
|
|
|
family.reloadFamilyInfo();
|
|
|
|
alert("Import des données de la famille effectué avec succès !");
|
|
} catch (e) {
|
|
console.error(e);
|
|
setError(`Echec de l'import des données de la famille ! (${e})`);
|
|
}
|
|
|
|
loading.hide();
|
|
};
|
|
|
|
return (
|
|
<FamilyCard error={error} success={success}>
|
|
<CardContent>
|
|
<Typography gutterBottom variant="h5" component="div">
|
|
Export / import des données de la famille
|
|
</Typography>
|
|
<p>
|
|
Vous pouvez, à des fins de sauvegardes ou de transfert, exporter et
|
|
importer l'ensemble des données des membres et des couples de cette
|
|
famille, sous format ZIP.
|
|
</p>
|
|
|
|
<Alert severity="warning">
|
|
Attention ! La restauration des données de la famille provoque
|
|
préalablement l'effacement de toutes les données enregistrées dans la
|
|
famille ! Par ailleurs, la restauration n'est pas réversible !
|
|
</Alert>
|
|
|
|
<p> </p>
|
|
|
|
<Button
|
|
startIcon={<DownloadIcon />}
|
|
variant="outlined"
|
|
fullWidth
|
|
onClick={exportData}
|
|
size={"large"}
|
|
style={{ marginBottom: "10px" }}
|
|
>
|
|
Exporter les données de la famille
|
|
</Button>
|
|
|
|
<Button
|
|
startIcon={<UploadIcon />}
|
|
variant="outlined"
|
|
color="warning"
|
|
fullWidth
|
|
onClick={importData}
|
|
disabled={!family.family.is_admin}
|
|
size={"large"}
|
|
>
|
|
Importer les données de la famille
|
|
</Button>
|
|
</CardContent>
|
|
</FamilyCard>
|
|
);
|
|
}
|