Genealogy as a feature (#175)
All checks were successful
continuous-integration/drone/push Build is passing

Start our journey into turning GeneIT as afully featured family intranet by making genealogy a feature that can be disabled by family admins

Reviewed-on: #175
This commit is contained in:
2024-05-16 19:15:15 +00:00
parent 0442538bd5
commit c8ee881b2c
34 changed files with 726 additions and 443 deletions

View File

@ -1,26 +1,19 @@
import DownloadIcon from "@mui/icons-material/Download";
import UploadIcon from "@mui/icons-material/Upload";
import {
Alert,
Box,
Button,
CardActions,
CardContent,
Checkbox,
FormControlLabel,
Switch,
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";
@ -55,7 +48,6 @@ export function FamilySettingsRoute(): React.ReactElement {
return (
<>
<FamilySettingsCard />
<FamilyExportCard />
<div style={{ textAlign: "center", marginTop: "50px" }}>
<Button
size="small"
@ -76,8 +68,8 @@ function FamilySettingsCard(): React.ReactElement {
const family = useFamily();
const [newName, setNewName] = React.useState(family.family.name);
const [disableCouplePhotos, setDisableCouplePhotos] = React.useState(
family.family.disable_couple_photos
const [enableGenealogy, setEnableGenealogy] = React.useState(
family.family.enable_genealogy
);
const canEdit = family.family.is_admin;
@ -93,7 +85,7 @@ function FamilySettingsCard(): React.ReactElement {
await FamilyApi.UpdateFamily({
id: family.family.family_id,
name: newName,
disable_couple_photos: disableCouplePhotos,
enable_genealogy: enableGenealogy,
});
family.reloadFamilyInfo();
@ -144,18 +136,17 @@ function FamilySettingsCard(): React.ReactElement {
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>
<FormControlLabel
disabled={!canEdit}
control={
<Switch
checked={enableGenealogy}
onChange={(_e, c) => setEnableGenealogy(c)}
/>
}
label="Activer le module de généalogie"
/>
</Box>
</CardContent>
<CardActions>
@ -170,109 +161,3 @@ function FamilySettingsCard(): React.ReactElement {
</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>&nbsp;</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>
);
}