Genealogy as a feature (#175)
All checks were successful
continuous-integration/drone/push Build is passing
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:
165
geneit_app/src/routes/family/genealogy/FamilyMemberTreeRoute.tsx
Normal file
165
geneit_app/src/routes/family/genealogy/FamilyMemberTreeRoute.tsx
Normal file
@ -0,0 +1,165 @@
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import {
|
||||
Alert,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormLabel,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Paper,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Select,
|
||||
Tab,
|
||||
Tabs,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import {
|
||||
FamilyTreeNode,
|
||||
buildAscendingTree,
|
||||
buildDescendingTree,
|
||||
treeHeight,
|
||||
} from "../../../utils/family_tree";
|
||||
import { useFamily } from "../../../widgets/BaseFamilyRoute";
|
||||
import { BasicFamilyTree } from "../../../widgets/BasicFamilyTree";
|
||||
import { MemberItem } from "../../../widgets/MemberItem";
|
||||
import { RouterLink } from "../../../widgets/RouterLink";
|
||||
import { useGenealogy } from "../../../widgets/genealogy/BaseGenealogyRoute";
|
||||
import { SimpleFamilyTree } from "../../../widgets/simple_family_tree/SimpleFamilyTree";
|
||||
|
||||
enum CurrTab {
|
||||
BasicTree,
|
||||
SimpleTree,
|
||||
}
|
||||
|
||||
enum TreeMode {
|
||||
Ascending,
|
||||
Descending,
|
||||
}
|
||||
|
||||
export function FamilyMemberTreeRoute(): React.ReactElement {
|
||||
const { memberId } = useParams();
|
||||
|
||||
const genealogy = useGenealogy();
|
||||
const family = useFamily();
|
||||
|
||||
const [currTab, setCurrTab] = React.useState(CurrTab.SimpleTree);
|
||||
const [currMode, setCurrMode] = React.useState(TreeMode.Descending);
|
||||
|
||||
const member = genealogy.members.get(Number(memberId));
|
||||
|
||||
const memo: [FamilyTreeNode, number] | null = React.useMemo(() => {
|
||||
if (!member) return null;
|
||||
const tree =
|
||||
currMode === TreeMode.Ascending
|
||||
? buildAscendingTree(member.id, genealogy.members, genealogy.couples)
|
||||
: buildDescendingTree(member.id, genealogy.members, genealogy.couples);
|
||||
|
||||
return [tree, treeHeight(tree)];
|
||||
}, [member, currMode, genealogy.members, genealogy.couples]);
|
||||
|
||||
const [currDepth, setCurrDepth] = React.useState(0);
|
||||
|
||||
if (!member) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
L'arbre ne peut pas être constuit : le membre n'existe pas !
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
const [tree, maxDepth] = memo!;
|
||||
|
||||
if (currDepth === 0) setCurrDepth(maxDepth);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
flex: "1",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
marginBottom: "10px",
|
||||
}}
|
||||
>
|
||||
{/* parent bar */}
|
||||
<div style={{ display: "flex" }}>
|
||||
<MemberItem
|
||||
dense
|
||||
member={member}
|
||||
secondary={
|
||||
<RouterLink to={family.family.URL("genealogy/tree")}>
|
||||
<IconButton>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</RouterLink>
|
||||
}
|
||||
/>
|
||||
<div style={{ flex: "10" }}></div>
|
||||
|
||||
<FormControl>
|
||||
<FormLabel>Arbre</FormLabel>
|
||||
<RadioGroup
|
||||
row
|
||||
value={currMode}
|
||||
onChange={(_e, v) => {
|
||||
setCurrDepth(0);
|
||||
setCurrMode(Number(v));
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value={TreeMode.Descending}
|
||||
control={<Radio />}
|
||||
label="Descendant"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value={TreeMode.Ascending}
|
||||
control={<Radio />}
|
||||
label="Ascendant"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
|
||||
<div style={{ flex: "1" }}></div>
|
||||
|
||||
<FormControl variant="standard" sx={{ m: 1, minWidth: 120 }}>
|
||||
<InputLabel>Profondeur</InputLabel>
|
||||
<Select
|
||||
value={currDepth}
|
||||
onChange={(v) => setCurrDepth(Number(v.target.value))}
|
||||
label="Profondeur"
|
||||
>
|
||||
{Array(maxDepth)
|
||||
.fill(0)
|
||||
.map((_v, index) => (
|
||||
<MenuItem key={index} value={index + 1}>
|
||||
{index + 1}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<div style={{ flex: "1" }}></div>
|
||||
|
||||
<Tabs
|
||||
value={currTab}
|
||||
onChange={(_e, v) => setCurrTab(v)}
|
||||
aria-label="basic tabs example"
|
||||
>
|
||||
<Tab tabIndex={CurrTab.BasicTree} label="Basique" />
|
||||
<Tab tabIndex={CurrTab.SimpleTree} label="Simple" />
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
{/* the tree itself */}
|
||||
<Paper style={{ flex: "1", display: "flex", flexDirection: "column" }}>
|
||||
{currTab === CurrTab.BasicTree ? (
|
||||
<BasicFamilyTree tree={tree!} depth={currDepth} />
|
||||
) : (
|
||||
<SimpleFamilyTree tree={tree!} depth={currDepth} />
|
||||
)}
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user